From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/win/dtrans/FmtFilter.cxx | 435 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 vcl/win/dtrans/FmtFilter.cxx (limited to 'vcl/win/dtrans/FmtFilter.cxx') diff --git a/vcl/win/dtrans/FmtFilter.cxx b/vcl/win/dtrans/FmtFilter.cxx new file mode 100644 index 000000000..27d051f7e --- /dev/null +++ b/vcl/win/dtrans/FmtFilter.cxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "FmtFilter.hxx" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace com::sun::star::uno; + +namespace { + +#pragma pack(2) +struct METAFILEHEADER +{ + DWORD key; + short hmf; + SMALL_RECT bbox; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#pragma pack() + +} + +// convert a windows metafile picture to a LibreOffice metafile picture + +Sequence< sal_Int8 > WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict ) +{ + OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) ); + + Sequence< sal_Int8 > mfpictStream; + METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) ); + HMETAFILE hMf = pMFPict->hMF; + sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, nullptr ); + + if ( nCount > 0 ) + { + mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) ); + + METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) ); + SMALL_RECT aRect = { 0, + 0, + static_cast< short >( pMFPict->xExt ), + static_cast< short >( pMFPict->yExt ) }; + USHORT nInch; + + switch( pMFPict->mm ) + { + case MM_TEXT: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::pt); + break; + + case MM_LOMETRIC: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm10); + break; + + case MM_HIMETRIC: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100); + break; + + case MM_LOENGLISH: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in100); + break; + + case MM_HIENGLISH: + case MM_ISOTROPIC: + case MM_ANISOTROPIC: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::in1000); + break; + + case MM_TWIPS: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::twip); + break; + + default: + nInch = o3tl::convert(1, o3tl::Length::in, o3tl::Length::master); + } + + pMFHeader->key = 0x9AC6CDD7L; + pMFHeader->hmf = 0; + pMFHeader->bbox = aRect; + pMFHeader->inch = nInch; + pMFHeader->reserved = 0; + pMFHeader->checksum = 0; + + char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) ); + + nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) ); + OSL_ASSERT( nCount > 0 ); + } + + return mfpictStream; +} + +// convert a windows enhanced metafile to a LibreOffice metafile + +Sequence< sal_Int8 > WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile ) +{ + Sequence< sal_Int8 > aRet; + UINT nSize = 0; + + if( hEnhMetaFile && + ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, nullptr ) ) != 0 ) ) + { + aRet.realloc( nSize ); + + if( GetEnhMetaFileBits( hEnhMetaFile, nSize, reinterpret_cast(aRet.getArray()) ) != nSize ) + aRet.realloc( 0 ); + } + + return aRet; +} + +// convert a LibreOffice metafile picture to a windows metafile picture + +HMETAFILEPICT OOMFPictToWinMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict ) +{ + HMETAFILEPICT hPict = nullptr; + HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), reinterpret_cast(aOOMetaFilePict.getConstArray()) ); + + if( hMtf ) + { + METAFILEPICT* pPict = static_cast(GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) )); + + pPict->mm = 8; + pPict->xExt = 0; + pPict->yExt = 0; + pPict->hMF = hMtf; + + GlobalUnlock( hPict ); + } + + return hPict; +} + +// convert a LibreOffice metafile picture to a windows enhanced metafile picture + +HENHMETAFILE OOMFPictToWinENHMFPict( Sequence< sal_Int8 > const & aOOMetaFilePict ) +{ + HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), reinterpret_cast(aOOMetaFilePict.getConstArray()) ); + + return hEnhMtf; +} + +// convert a windows device independent bitmap into a LibreOffice bitmap + +Sequence< sal_Int8 > WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB ) +{ + OSL_ENSURE(o3tl::make_unsigned(aWinDIB.getLength()) > sizeof(BITMAPINFOHEADER), "CF_DIBV5/CF_DIB too small (!)"); + Sequence< sal_Int8 > ooBmpStream; + + ooBmpStream.realloc(aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER)); + const BITMAPINFOHEADER* pBmpInfoHdr = reinterpret_cast< const BITMAPINFOHEADER* >(aWinDIB.getConstArray()); + BITMAPFILEHEADER* pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >(ooBmpStream.getArray()); + const DWORD nSizeInfoOrV5(pBmpInfoHdr->biSize > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER)); + DWORD nOffset(sizeof(BITMAPFILEHEADER) + nSizeInfoOrV5); + + memcpy(pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength()); + + if(pBmpInfoHdr->biBitCount <= 8) + { + nOffset += (pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : (1 << pBmpInfoHdr->biBitCount)) << 2; + } + else if((BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ((16 == pBmpInfoHdr->biBitCount ) || (32 == pBmpInfoHdr->biBitCount ))) + { + nOffset += 12; + } + + pBmpFileHdr->bfType = ('M' << 8) | 'B'; + pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER) + pBmpFileHdr->bfReserved1 = 0; + pBmpFileHdr->bfReserved2 = 0; + pBmpFileHdr->bfOffBits = nOffset; + + return ooBmpStream; +} + +// convert a LibreOffice bitmap into a windows device independent bitmap + +Sequence< sal_Int8 > OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp ) +{ + Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); + + memcpy( winDIBStream.getArray( ), + aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ), + aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); + + return winDIBStream; +} + +static std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment) +{ + std::ostringstream htmlHeader; + htmlHeader << "Version:1.0" << '\r' << '\n'; + htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n'; + htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n'; + htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n'; + htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n'; + return htmlHeader.str(); +} + +// the case of these tags has to match what we output in our filters +// both tags don't allow parameters +const std::string TAG_HTML(""); +const std::string TAG_END_HTML(""); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. #92840# +const std::string TAG_BODY(" TextHtmlToHTMLFormat(Sequence const & aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (aTextHtml.getLength() <= 0) + return Sequence(); + + // fill the buffer with dummy values to calc the exact length + std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0); + size_t lHtmlFormatHeader = dummyHtmlHeader.length(); + + std::string textHtml( + reinterpret_cast(aTextHtml.getConstArray()), + reinterpret_cast(aTextHtml.getConstArray()) + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '' Word 2000 does also so + std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind ? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. #92840# + std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1; + std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader; + + std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment); + htmlFormat += textHtml; + + Sequence byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + memset(byteSequence.getArray(), 0, byteSequence.getLength()); + + memcpy( + static_cast(byteSequence.getArray()), + static_cast(htmlFormat.c_str()), + htmlFormat.length()); + + return byteSequence; +} + +static std::wstring getFileExtension(const std::wstring& aFilename) +{ + std::wstring::size_type idx = aFilename.rfind(L"."); + if (idx != std::wstring::npos) + { + return std::wstring(aFilename, idx); + } + return std::wstring(); +} + +const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk"; + +static bool isShellLink(const std::wstring& aFilename) +{ + std::wstring ext = getFileExtension(aFilename); + return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0); +} + +/** Resolve a Windows Shell Link (lnk) file. If a resolution + is not possible simply return the provided name of the + lnk file. */ +static std::wstring getShellLinkTarget(const std::wstring& aLnkFile) +{ + OSL_ASSERT(isShellLink(aLnkFile)); + + std::wstring target = aLnkFile; + + try + { + sal::systools::COMReference pIShellLink; + pIShellLink.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER); + + sal::systools::COMReference pIPersistFile(pIShellLink, + sal::systools::COM_QUERY_THROW); + + HRESULT hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ); + if (FAILED(hr)) + return target; + + hr = pIShellLink->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI); + if (FAILED(hr)) + return target; + + wchar_t pathW[MAX_PATH]; + WIN32_FIND_DATAW wfd; + hr = pIShellLink->GetPath(pathW, MAX_PATH, &wfd, SLGP_RAWPATH); + if (FAILED(hr)) + return target; + + target = pathW; + } + catch(sal::systools::ComError& ex) + { + OSL_FAIL(ex.what()); + } + return target; +} + +typedef Sequence ByteSequence_t; + +/* Calculate the size required for turning a string list into + a double '\0' terminated string buffer */ +static size_t CalcSizeForStringListBuffer(const std::vector& fileList) +{ + if ( fileList.empty() ) + return 0; + + size_t size = 1; // one for the very final '\0' + for (auto const& elem : fileList) + { + size += elem.length() + 1; // length including terminating '\0' + } + return (size * sizeof(std::vector::value_type::value_type)); +} + +static ByteSequence_t FileListToByteSequence(const std::vector& fileList) +{ + ByteSequence_t bseq; + size_t size = CalcSizeForStringListBuffer(fileList); + + if (size > 0) + { + bseq.realloc(size); + wchar_t* p = reinterpret_cast(bseq.getArray()); + ZeroMemory(p, size); + + for (auto const& elem : fileList) + { + wcsncpy(p, elem.c_str(), elem.length()); + p += (elem.length() + 1); + } + } + return bseq; +} + +css::uno::Sequence CF_HDROPToFileList(HGLOBAL hGlobal) +{ + UINT nFiles = DragQueryFileW(static_cast(hGlobal), 0xFFFFFFFF, nullptr, 0); + std::vector files; + + for (UINT i = 0; i < nFiles; i++) + { + wchar_t buff[MAX_PATH]; + /*UINT size =*/ DragQueryFileW(static_cast(hGlobal), i, buff, MAX_PATH); + std::wstring filename = buff; + if (isShellLink(filename)) + filename = getShellLinkTarget(filename); + files.push_back(filename); + } + return FileListToByteSequence(files); +} + +// convert a windows bitmap handle into a LibreOffice bitmap + +Sequence< sal_Int8 > WinBITMAPToOOBMP( HBITMAP aHBMP ) +{ + Sequence< sal_Int8 > ooBmpStream; + + SIZE aBmpSize; + if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) ) + { + // fill bitmap info header + size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy; + Sequence< sal_Int8 > aBitmapStream( + sizeof(BITMAPINFO) + + nDataBytes + ); + PBITMAPINFOHEADER pBmp = reinterpret_cast(aBitmapStream.getArray()); + pBmp->biSize = sizeof( BITMAPINFOHEADER ); + pBmp->biWidth = aBmpSize.cx; + pBmp->biHeight = aBmpSize.cy; + pBmp->biPlanes = 1; + pBmp->biBitCount = 32; + pBmp->biCompression = BI_RGB; + pBmp->biSizeImage = static_cast(nDataBytes); + pBmp->biXPelsPerMeter = 1000; + pBmp->biYPelsPerMeter = 1000; + pBmp->biClrUsed = 0; + pBmp->biClrImportant = 0; + if( GetDIBits( nullptr, // DC, 0 is a default GC, basically that of the desktop + aHBMP, + 0, aBmpSize.cy, + aBitmapStream.getArray() + sizeof(BITMAPINFO), + reinterpret_cast(pBmp), + DIB_RGB_COLORS ) ) + { + ooBmpStream = WinDIBToOOBMP( aBitmapStream ); + } + } + + return ooBmpStream; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3