LibreOffice Module vcl (master)  1
transfer.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #ifdef _WIN32
21 #include <prewin.h>
22 #include <postwin.h>
23 #include <shlobj.h>
24 #endif
25 #include <osl/mutex.hxx>
26 #include <rtl/uri.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/urlobj.hxx>
31 #include <sot/exchange.hxx>
32 #include <sot/storage.hxx>
33 #include <vcl/bitmap.hxx>
34 #include <vcl/gdimtf.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/cvtgrf.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/window.hxx>
39 #include <comphelper/fileformat.h>
42 #include <comphelper/sequence.hxx>
43 #include <sot/filelist.hxx>
44 #include <cppuhelper/implbase.hxx>
45 
46 #include <comphelper/seqstream.hxx>
47 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
48 #include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
49 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
50 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
51 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
52 #include <com/sun/star/datatransfer/XTransferable2.hpp>
53 #include <com/sun/star/frame/Desktop.hpp>
54 
55 #include <svl/urlbmk.hxx>
56 #include <vcl/inetimg.hxx>
57 #include <vcl/wmf.hxx>
58 #include <vcl/imap.hxx>
59 #include <vcl/transfer.hxx>
60 #include <rtl/strbuf.hxx>
61 #include <cstdio>
62 #include <vcl/dibtools.hxx>
64 #include <vcl/pngwrite.hxx>
65 #include <vcl/graphicfilter.hxx>
66 #include <memory>
67 #include <utility>
68 #include <vcl/TypeSerializer.hxx>
69 
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::lang;
72 using namespace ::com::sun::star::frame;
73 using namespace ::com::sun::star::io;
74 using namespace ::com::sun::star::datatransfer;
76 using namespace ::com::sun::star::datatransfer::dnd;
77 
78 
79 #define TOD_SIG1 0x01234567
80 #define TOD_SIG2 0x89abcdef
81 
83 {
84  const sal_uInt32 nFirstPos = rOStm.Tell(), nViewAspect = rObjDesc.mnViewAspect;
85  const sal_uInt32 nSig1 = TOD_SIG1, nSig2 = TOD_SIG2;
86 
87  rOStm.SeekRel( 4 );
88  WriteSvGlobalName( rOStm, rObjDesc.maClassName );
89  rOStm.WriteUInt32( nViewAspect );
90  rOStm.WriteInt32( rObjDesc.maSize.Width() );
91  rOStm.WriteInt32( rObjDesc.maSize.Height() );
92  rOStm.WriteInt32( rObjDesc.maDragStartPos.X() );
93  rOStm.WriteInt32( rObjDesc.maDragStartPos.Y() );
94  rOStm.WriteUniOrByteString( rObjDesc.maTypeName, osl_getThreadTextEncoding() );
95  rOStm.WriteUniOrByteString( rObjDesc.maDisplayName, osl_getThreadTextEncoding() );
96  rOStm.WriteUInt32( nSig1 ).WriteUInt32( nSig2 );
97 
98  const sal_uInt32 nLastPos = rOStm.Tell();
99 
100  rOStm.Seek( nFirstPos );
101  rOStm.WriteUInt32( nLastPos - nFirstPos );
102  rOStm.Seek( nLastPos );
103 
104  return rOStm;
105 }
106 
107 
108 // the reading of the parameter is done using the special service css::datatransfer::MimeContentType,
109 // a similar approach should be implemented for creation of the mimetype string;
110 // for now the set of acceptable characters has to be hardcoded, in future it should be part of the service that creates the mimetype
111 
112 static OUString ImplGetParameterString( const TransferableObjectDescriptor& rObjDesc )
113 {
114  const OUString aClassName( rObjDesc.maClassName.GetHexName() );
115  OUString aParams;
116 
117  if( !aClassName.isEmpty() )
118  {
119  aParams += ";classname=\"" + aClassName + "\"";
120  }
121 
122  if( !rObjDesc.maTypeName.isEmpty() )
123  {
124  aParams += ";typename=\"" + rObjDesc.maTypeName + "\"";
125  }
126 
127  if( !rObjDesc.maDisplayName.isEmpty() )
128  {
129  // the display name might contain unacceptable characters, encode all of them
130  // this seems to be the only parameter currently that might contain such characters
131  sal_Bool pToAccept[128];
132  for (sal_Bool & rb : pToAccept)
133  rb = false;
134 
135  const char aQuotedParamChars[] =
136  "()<>@,;:/[]?=!#$&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~. ";
137 
138  for ( sal_Int32 nInd = 0; nInd < RTL_CONSTASCII_LENGTH(aQuotedParamChars); ++nInd )
139  {
140  sal_Unicode nChar = aQuotedParamChars[nInd];
141  if ( nChar < 128 )
142  pToAccept[nChar] = true;
143  }
144 
145  aParams += ";displayname=\""
146  + rtl::Uri::encode(
147  rObjDesc.maDisplayName, pToAccept, rtl_UriEncodeIgnoreEscapes,
148  RTL_TEXTENCODING_UTF8)
149  + "\"";
150  }
151 
152  aParams += ";viewaspect=\"" + OUString::number(rObjDesc.mnViewAspect)
153  + "\";width=\"" + OUString::number(rObjDesc.maSize.Width())
154  + "\";height=\"" + OUString::number(rObjDesc.maSize.Height())
155  + "\";posx=\"" + OUString::number(rObjDesc.maDragStartPos.X())
156  + "\";posy=\"" + OUString::number(rObjDesc.maDragStartPos.X()) + "\"";
157 
158  return aParams;
159 }
160 
161 
162 static void ImplSetParameterString( TransferableObjectDescriptor& rObjDesc, const DataFlavorEx& rFlavorEx )
163 {
165 
166  try
167  {
168  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
169 
170  Reference< XMimeContentType > xMimeType( xMimeFact->createMimeContentType( rFlavorEx.MimeType ) );
171 
172  if( xMimeType.is() )
173  {
174  static const OUStringLiteral aClassNameString( u"classname" );
175  static const OUStringLiteral aTypeNameString( u"typename" );
176  static const OUStringLiteral aDisplayNameString( u"displayname" );
177  static const OUStringLiteral aViewAspectString( u"viewaspect" );
178  static const OUStringLiteral aWidthString( u"width" );
179  static const OUStringLiteral aHeightString( u"height" );
180  static const OUStringLiteral aPosXString( u"posx" );
181  static const OUStringLiteral aPosYString( u"posy" );
182 
183  if( xMimeType->hasParameter( aClassNameString ) )
184  {
185  rObjDesc.maClassName.MakeId( xMimeType->getParameterValue( aClassNameString ) );
186  }
187 
188  if( xMimeType->hasParameter( aTypeNameString ) )
189  {
190  rObjDesc.maTypeName = xMimeType->getParameterValue( aTypeNameString );
191  }
192 
193  if( xMimeType->hasParameter( aDisplayNameString ) )
194  {
195  // the display name might contain unacceptable characters, in this case they should be encoded
196  // this seems to be the only parameter currently that might contain such characters
197  rObjDesc.maDisplayName = ::rtl::Uri::decode( xMimeType->getParameterValue( aDisplayNameString ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
198  }
199 
200  if( xMimeType->hasParameter( aViewAspectString ) )
201  {
202  rObjDesc.mnViewAspect = static_cast< sal_uInt16 >( xMimeType->getParameterValue( aViewAspectString ).toInt32() );
203  }
204 
205  if( xMimeType->hasParameter( aWidthString ) )
206  {
207  rObjDesc.maSize.setWidth( xMimeType->getParameterValue( aWidthString ).toInt32() );
208  }
209 
210  if( xMimeType->hasParameter( aHeightString ) )
211  {
212  rObjDesc.maSize.setHeight( xMimeType->getParameterValue( aHeightString ).toInt32() );
213  }
214 
215  if( xMimeType->hasParameter( aPosXString ) )
216  {
217  rObjDesc.maDragStartPos.setX( xMimeType->getParameterValue( aPosXString ).toInt32() );
218  }
219 
220  if( xMimeType->hasParameter( aPosYString ) )
221  {
222  rObjDesc.maDragStartPos.setY( xMimeType->getParameterValue( aPosYString ).toInt32() );
223  }
224  }
225  }
226  catch( const css::uno::Exception& )
227  {
228  }
229 }
230 
231 
233  mrParent( rTransferableHelper )
234 {
235 }
236 
237 
239 {
240 }
241 
242 
243 void SAL_CALL TransferableHelper::TerminateListener::disposing( const EventObject& )
244 {
245 }
246 
247 
249 {
250 }
251 
252 
254 {
255  mrParent.ImplFlush();
256 }
257 
259 {
260  return "com.sun.star.comp.svt.TransferableHelperTerminateListener";
261 }
262 
263 sal_Bool SAL_CALL TransferableHelper::TerminateListener::supportsService(const OUString& /*rServiceName*/)
264 {
265  return false;
266 }
267 
269 {
270  return {};
271 }
272 
274 {
275  css::uno::Reference<css::frame::XTerminateListener> listener;
276  {
277  const SolarMutexGuard aGuard;
278  std::swap(listener, mxTerminateListener);
279  }
280  if (listener.is()) {
281  Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
282  listener);
283  }
284 }
285 
286 Any SAL_CALL TransferableHelper::getTransferData( const DataFlavor& rFlavor )
287 {
288  return getTransferData2(rFlavor, OUString());
289 }
290 
291 Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, const OUString& rDestDoc )
292 {
293  if( !maAny.hasValue() || maFormats.empty() || ( maLastFormat != rFlavor.MimeType ) )
294  {
295  const SolarMutexGuard aGuard;
296 
297  maLastFormat = rFlavor.MimeType;
298  maAny = Any();
299 
300  try
301  {
302  DataFlavor aSubstFlavor;
303  bool bDone = false;
304 
305  // add formats if not already done
306  if (maFormats.empty())
308 
309  // check alien formats first and try to get a substitution format
310  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aSubstFlavor ) &&
311  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) )
312  {
313  GetData(aSubstFlavor, rDestDoc);
314  bDone = maAny.hasValue();
315  }
316  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor )
317  && TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor )
318  && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BITMAP, aSubstFlavor))
319  {
320  GetData(aSubstFlavor, rDestDoc);
321  bDone = true;
322  }
323  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
324  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
325  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
326  {
327  GetData(aSubstFlavor, rDestDoc);
328 
329  if( maAny.hasValue() )
330  {
332 
333  if( maAny >>= aSeq )
334  {
335  std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
336  GDIMetaFile aMtf;
337 
338  ReadGDIMetaFile( *pSrcStm, aMtf );
339  pSrcStm.reset();
340 
341  Graphic aGraphic( aMtf );
342  SvMemoryStream aDstStm( 65535, 65535 );
343 
344  if( GraphicConverter::Export( aDstStm, aGraphic, ConvertDataFormat::EMF ) == ERRCODE_NONE )
345  {
346  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
347  aDstStm.TellEnd() );
348  bDone = true;
349  }
350  }
351  }
352  }
353  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
354  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
355  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
356  {
357  GetData(aSubstFlavor, rDestDoc);
358 
359  if( maAny.hasValue() )
360  {
362 
363  if( maAny >>= aSeq )
364  {
365  std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
366  GDIMetaFile aMtf;
367 
368  ReadGDIMetaFile( *pSrcStm, aMtf );
369  pSrcStm.reset();
370 
371  SvMemoryStream aDstStm( 65535, 65535 );
372 
373  // taking wmf without file header
374  if ( ConvertGDIMetaFileToWMF( aMtf, aDstStm, nullptr, false ) )
375  {
376  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
377  aDstStm.TellEnd() );
378  bDone = true;
379  }
380  }
381  }
382  }
383 
384  // reset Any if substitute doesn't work
385  if( !bDone && maAny.hasValue() )
386  maAny = Any();
387 
388  // if any is not yet filled, use standard format
389  if( !maAny.hasValue() )
390  GetData(rFlavor, rDestDoc);
391  }
392  catch( const css::uno::Exception& )
393  {
394  }
395 
396  if( !maAny.hasValue() )
397  throw UnsupportedFlavorException();
398  }
399 
400  return maAny;
401 }
402 
404 {
405  // By default everything is complex, until proven otherwise
406  // in the respective document type transferable handler.
407  return true;
408 }
409 
410 Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
411 {
412  const SolarMutexGuard aGuard;
413 
414  try
415  {
416  if(maFormats.empty())
418  }
419  catch( const css::uno::Exception& )
420  {
421  }
422 
423  return comphelper::containerToSequence<DataFlavor>(maFormats);
424 }
425 
426 
427 sal_Bool SAL_CALL TransferableHelper::isDataFlavorSupported( const DataFlavor& rFlavor )
428 {
429  const SolarMutexGuard aGuard;
430 
431  try
432  {
433  if (maFormats.empty())
435  }
436  catch( const css::uno::Exception& )
437  {
438  }
439 
440  for (auto const& format : maFormats)
441  {
442  if( TransferableDataHelper::IsEqual( format, rFlavor ) )
443  {
444  return true;
445  }
446  }
447 
448  return false;
449 }
450 
451 
452 void SAL_CALL TransferableHelper::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
453 {
454  const SolarMutexGuard aGuard;
455 
456  try
457  {
458  if( mxTerminateListener.is() )
459  {
460  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
461  xDesktop->removeTerminateListener( mxTerminateListener );
462 
463  mxTerminateListener.clear();
464  }
465 
466  ObjectReleased();
467  }
468  catch( const css::uno::Exception& )
469  {
470  }
471 }
472 
473 
474 void SAL_CALL TransferableHelper::disposing( const EventObject& )
475 {
476 }
477 
478 
479 void SAL_CALL TransferableHelper::dragDropEnd( const DragSourceDropEvent& rDSDE )
480 {
481  const SolarMutexGuard aGuard;
482 
483  try
484  {
485  DragFinished( rDSDE.DropSuccess ? ( rDSDE.DropAction & ~DNDConstants::ACTION_DEFAULT ) : DNDConstants::ACTION_NONE );
486  ObjectReleased();
487  }
488  catch( const css::uno::Exception& )
489  {
490  }
491 }
492 
493 
494 void SAL_CALL TransferableHelper::dragEnter( const DragSourceDragEvent& )
495 {
496 }
497 
498 
499 void SAL_CALL TransferableHelper::dragExit( const DragSourceEvent& )
500 {
501 }
502 
503 
504 void SAL_CALL TransferableHelper::dragOver( const DragSourceDragEvent& )
505 {
506 }
507 
508 
509 void SAL_CALL TransferableHelper::dropActionChanged( const DragSourceDragEvent& )
510 {
511 }
512 
513 
515 {
516  sal_Int64 nRet;
517 
518  if( isUnoTunnelId<TransferableHelper>(rId) )
519  {
520  nRet = sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
521  }
522  else
523  nRet = 0;
524 
525  return nRet;
526 }
527 
528 
530 {
531  if( !mxClipboard.is() )
532  return;
533 
534  Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
535  SolarMutexReleaser aReleaser;
536 
537  try
538  {
539  if( xFlushableClipboard.is() )
540  xFlushableClipboard->flushClipboard();
541  }
542  catch( const css::uno::Exception& )
543  {
544  OSL_FAIL( "Could not flush clipboard" );
545  }
546 }
547 
548 
550 {
551  DataFlavor aFlavor;
552 
553  if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
554  AddFormat( aFlavor );
555 }
556 
557 
558 void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
559 {
560  bool bAdd = true;
561 
562  for (auto & format : maFormats)
563  {
564  if( TransferableDataHelper::IsEqual( format, rFlavor ) )
565  {
566  // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
567  if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
568  {
569  DataFlavor aObjDescFlavor;
570 
571  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
572  format.MimeType = aObjDescFlavor.MimeType;
573  format.MimeType += ::ImplGetParameterString(*mxObjDesc);
574  }
575 
576  bAdd = false;
577  break;
578  }
579  }
580 
581  if( !bAdd )
582  return;
583 
584  DataFlavorEx aFlavorEx;
585 
586  aFlavorEx.MimeType = rFlavor.MimeType;
587  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
588  aFlavorEx.DataType = rFlavor.DataType;
589  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
590 
591  if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
592  aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
593 
594  maFormats.push_back(aFlavorEx);
595 
596  if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
597  {
598  AddFormat( SotClipboardFormatId::PNG );
599  AddFormat( SotClipboardFormatId::BMP );
600  }
601  else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
602  {
603  AddFormat( SotClipboardFormatId::EMF );
604  AddFormat( SotClipboardFormatId::WMF );
605  }
606 }
607 
608 
610 {
611  DataFlavor aFlavor;
612 
613  if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
614  RemoveFormat( aFlavor );
615 }
616 
617 
618 void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
619 {
620  DataFlavorExVector::iterator aIter(maFormats.begin());
621 
622  while (aIter != maFormats.end())
623  {
624  if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
625  aIter = maFormats.erase(aIter);
626  else
627  ++aIter;
628  }
629 }
630 
631 
633 {
634  return std::any_of(maFormats.begin(), maFormats.end(),
635  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
636 }
637 
638 
640 {
641  maFormats.clear();
642  maAny.clear();
643 }
644 
645 
646 bool TransferableHelper::SetAny( const Any& rAny )
647 {
648  maAny = rAny;
649  return maAny.hasValue();
650 }
651 
652 
653 bool TransferableHelper::SetString( const OUString& rString, const DataFlavor& rFlavor )
654 {
655  DataFlavor aFileFlavor;
656 
657  if( !rString.isEmpty() &&
658  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::SIMPLE_FILE, aFileFlavor ) &&
659  TransferableDataHelper::IsEqual( aFileFlavor, rFlavor ) )
660  {
661  const OString aByteStr(OUStringToOString(rString, osl_getThreadTextEncoding()));
662  Sequence< sal_Int8 > aSeq( aByteStr.getLength() + 1 );
663 
664  memcpy( aSeq.getArray(), aByteStr.getStr(), aByteStr.getLength() );
665  aSeq[ aByteStr.getLength() ] = 0;
666  maAny <<= aSeq;
667  }
668  else
669  maAny <<= rString;
670 
671  return maAny.hasValue();
672 }
673 
674 
675 bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
676 {
677  if( !rBitmapEx.IsEmpty() )
678  {
679  SvMemoryStream aMemStm( 65535, 65535 );
680 
681  if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
682  {
683  // write a PNG
684  css::uno::Sequence<css::beans::PropertyValue> aFilterData;
685 
686 #ifdef IOS
687  // Use faster compression on slow devices
688  aFilterData.realloc(aFilterData.getLength() + 1);
689  aFilterData[aFilterData.getLength() - 1].Name = "Compression";
690 
691  // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
692  // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
693  // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
694  //
695  // Sure, the best would be to not have to re-encode the image at all, but have access to
696  // the original JPEG or PNG when there is a such.
697 
698  aFilterData[aFilterData.getLength() - 1].Value <<= 1;
699 #endif
700  vcl::PNGWriter aPNGWriter(rBitmapEx, &aFilterData);
701 
702  aPNGWriter.Write(aMemStm);
703  }
704  else
705  {
706  // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
707  WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
708  }
709 
710  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
711  }
712 
713  return maAny.hasValue();
714 }
715 
716 
718 {
719  if( rMtf.GetActionSize() )
720  {
721  SvMemoryStream aMemStm( 65535, 65535 );
722 
723  const_cast<GDIMetaFile&>(rMtf).Write( aMemStm );
724  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
725  }
726 
727  return maAny.hasValue();
728 }
729 
730 
732 {
733  if( rGraphic.GetType() != GraphicType::NONE )
734  {
735  SvMemoryStream aMemStm( 65535, 65535 );
736 
738  aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
739 
740  TypeSerializer aSerializer(aMemStm);
741  aSerializer.writeGraphic(rGraphic);
742 
743  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
744  }
745 
746  return maAny.hasValue();
747 }
748 
749 
751 {
752  SvMemoryStream aMemStm( 8192, 8192 );
753 
755  rIMap.Write( aMemStm );
756  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
757 
758  return maAny.hasValue();
759 }
760 
761 
763 {
764  PrepareOLE( rDesc );
765 
766  SvMemoryStream aMemStm( 1024, 1024 );
767 
768  WriteTransferableObjectDescriptor( aMemStm, rDesc );
769  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
770 
771  return maAny.hasValue();
772  }
773 
774 
776  const css::datatransfer::DataFlavor& rFlavor )
777 {
778  rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
779 
780  switch( SotExchange::GetFormat( rFlavor ) )
781  {
782  case SotClipboardFormatId::SOLK:
783  {
784  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
785  OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
786  OStringBuffer sOut;
787  sOut.append(sURL.getLength());
788  sOut.append('@').append(sURL);
789  sOut.append(sDesc.getLength());
790  sOut.append('@').append(sDesc);
791 
792  Sequence< sal_Int8 > aSeq(sOut.getLength());
793  memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
794  maAny <<= aSeq;
795  }
796  break;
797 
798  case SotClipboardFormatId::STRING:
799  maAny <<= rBmk.GetURL();
800  break;
801 
802  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
803  {
804  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
805  Sequence< sal_Int8 > aSeq( sURL.getLength() );
806  memcpy( aSeq.getArray(), sURL.getStr(), sURL.getLength() );
807  maAny <<= aSeq;
808  }
809  break;
810 
811  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
812  {
813  Sequence< sal_Int8 > aSeq( 2048 );
814 
815  memset( aSeq.getArray(), 0, 2048 );
816  strcpy( reinterpret_cast< char* >( aSeq.getArray() ), OUStringToOString(rBmk.GetURL(), eSysCSet).getStr() );
817  strcpy( reinterpret_cast< char* >( aSeq.getArray() ) + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr() );
818 
819  maAny <<= aSeq;
820  }
821  break;
822 
823 #ifdef _WIN32
824  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
825  {
826  Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTOR ) );
827  FILEGROUPDESCRIPTOR* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR*>(aSeq.getArray());
828  FILEDESCRIPTOR& rFDesc1 = pFDesc->fgd[ 0 ];
829 
830  pFDesc->cItems = 1;
831  memset( &rFDesc1, 0, sizeof( FILEDESCRIPTOR ) );
832  rFDesc1.dwFlags = FD_LINKUI;
833 
834  OStringBuffer aStr(OUStringToOString(
835  rBmk.GetDescription(), eSysCSet));
836  for( sal_Int32 nChar = 0; nChar < aStr.getLength(); ++nChar )
837  if( strchr( "\\/:*?\"<>|", aStr[nChar] ) )
838  aStr.remove(nChar--, 1);
839 
840  aStr.insert(0, "Shortcut to ");
841  aStr.append(".URL");
842  strcpy( rFDesc1.cFileName, aStr.getStr() );
843 
844  maAny <<= aSeq;
845  }
846  break;
847 
848  case SotClipboardFormatId::FILECONTENT:
849  {
850  maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
851  }
852  break;
853 #endif
854 
855  default:
856  break;
857  }
858 
859  return maAny.hasValue();
860 }
861 
862 
864  const css::datatransfer::DataFlavor& rFlavor )
865 {
866  SvMemoryStream aMemStm( 1024, 1024 );
867 
869  rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
870 
871  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
872 
873  return maAny.hasValue();
874 }
875 
876 
877 bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
878 {
879  tools::SvRef<SotTempStream> xStm( new SotTempStream( OUString() ) );
880 
881  xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
882 
883  if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
884  {
885  const sal_uInt32 nLen = xStm->TellEnd();
886  Sequence< sal_Int8 > aSeq( nLen );
887 
888  xStm->Seek( STREAM_SEEK_TO_BEGIN );
889  xStm->ReadBytes(aSeq.getArray(), nLen);
890 
891  if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
892  {
893  //JP 24.7.2001: as I know was this only for the writer application and this
894  // writes now UTF16 format into the stream
895  //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
896  // little / big endians! - Bug 88121
897  maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
898  }
899  else
900  maAny <<= aSeq;
901  }
902 
903  return maAny.hasValue();
904 }
905 
906 
907 bool TransferableHelper::WriteObject( tools::SvRef<SotTempStream>&, void*, sal_uInt32, const DataFlavor& )
908 {
909  OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
910  return false;
911 }
912 
913 
915 {
916 }
917 
918 
920 {
921 }
922 
923 
925 {
926  mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
927 
928  if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
929  AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
930 }
931 
932 void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
933 {
934  if( rClipboard.is() )
935  mxClipboard = rClipboard;
936 
937  if( !mxClipboard.is() || mxTerminateListener.is() )
938  return;
939 
940  try
941  {
942  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
943  pThis->mxTerminateListener = new TerminateListener( *pThis );
944  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
945  xDesktop->addTerminateListener( pThis->mxTerminateListener );
946 
947  mxClipboard->setContents( pThis, pThis );
948  }
949  catch( const css::uno::Exception& )
950  {
951  }
952 }
953 
955 {
956  DBG_ASSERT( pWindow, "Window pointer is NULL" );
957  Reference< XClipboard > xClipboard;
958 
959  if( pWindow )
960  xClipboard = pWindow->GetClipboard();
961 
962  CopyToClipboard(xClipboard);
963 }
964 
965 void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
966 {
967  if( !rSelection.is() || mxTerminateListener.is() )
968  return;
969 
970  try
971  {
972  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
973  pThis->mxTerminateListener = new TerminateListener( *pThis );
974  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
975  xDesktop->addTerminateListener( pThis->mxTerminateListener );
976 
977  rSelection->setContents( pThis, pThis );
978  }
979  catch( const css::uno::Exception& )
980  {
981  }
982 }
983 
985 {
987 }
988 
989 void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
990 
991 {
992  DBG_ASSERT( pWindow, "Window pointer is NULL" );
993  Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
994 
995  if( !xDragSource.is() )
996  return;
997 
998  /*
999  * #96792# release mouse before actually starting DnD.
1000  * This is necessary for the X11 DnD implementation to work.
1001  */
1002  if( pWindow->IsMouseCaptured() )
1003  pWindow->ReleaseMouse();
1004 
1005  const Point aPt( pWindow->GetPointerPosPixel() );
1006 
1007  // On macOS we are forced to execute 'startDrag' synchronously
1008  // contrary to the XDragSource interface specification because
1009  // we can receive drag events from the system only in the main
1010  // thread
1011 #if !defined(MACOSX)
1012  SolarMutexReleaser aReleaser;
1013 #endif
1014 
1015  try
1016  {
1017  DragGestureEvent aEvt;
1018  aEvt.DragAction = DNDConstants::ACTION_COPY;
1019  aEvt.DragOriginX = aPt.X();
1020  aEvt.DragOriginY = aPt.Y();
1021  aEvt.DragSource = xDragSource;
1022 
1023  xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
1024  }
1025  catch( const css::uno::Exception& )
1026  {
1027  }
1028 }
1029 
1031 {
1032  Reference< XClipboard > xSelection(GetSystemPrimarySelection());
1033 
1034  if( xSelection.is() )
1035  xSelection->setContents( nullptr, nullptr );
1036 }
1037 
1039 {
1040  static const UnoTunnelIdInit theTransferableHelperUnoTunnelId;
1041  return theTransferableHelperUnoTunnelId.getSeq();
1042 }
1043 
1044 namespace {
1045 
1046 class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
1047 {
1048 private:
1049  ::osl::Mutex& mrMutex;
1050  Reference< XClipboardNotifier > mxNotifier;
1052 
1053 protected:
1054  // XClipboardListener
1055  virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1056 
1057  // XEventListener
1058  virtual void SAL_CALL disposing( const EventObject& Source ) override;
1059 
1060 public:
1061  TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1062 
1064  bool isListening() const { return mpListener != nullptr; }
1065 
1067  void dispose();
1068 };
1069 
1070 }
1071 
1072 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1073  :mrMutex( _rMutex )
1074  ,mxNotifier( _rxClipboard, UNO_QUERY )
1075  ,mpListener( &_rListener )
1076 {
1077  osl_atomic_increment( &m_refCount );
1078  {
1079  if ( mxNotifier.is() )
1080  mxNotifier->addClipboardListener( this );
1081  else
1082  // born dead
1083  mpListener = nullptr;
1084  }
1085  osl_atomic_decrement( &m_refCount );
1086 }
1087 
1088 
1089 void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1090 {
1091  SolarMutexGuard aSolarGuard;
1092  // the SolarMutex here is necessary, since
1093  // - we cannot call mpListener without our own mutex locked
1094  // - Rebind respectively InitFormats (called by Rebind) will
1095  // try to lock the SolarMutex, too
1096  ::osl::MutexGuard aGuard( mrMutex );
1097  if( mpListener )
1098  mpListener->Rebind( event.Contents );
1099 }
1100 
1101 
1102 void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1103 {
1104  // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1105  dispose();
1106 }
1107 
1108 
1109 void TransferableClipboardNotifier::dispose()
1110 {
1111  ::osl::MutexGuard aGuard( mrMutex );
1112 
1113  Reference< XClipboardListener > xKeepMeAlive( this );
1114 
1115  if ( mxNotifier.is() )
1116  mxNotifier->removeClipboardListener( this );
1117  mxNotifier.clear();
1118 
1119  mpListener = nullptr;
1120 }
1121 
1123 {
1124  ::osl::Mutex maMutex;
1126 
1128  {
1129  }
1130 };
1131 
1133  : mxObjDesc(new TransferableObjectDescriptor)
1134  , mxImpl(new TransferableDataHelper_Impl)
1135 {
1136 }
1137 
1138 TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1139  : mxTransfer(rxTransferable)
1140  , mxObjDesc(new TransferableObjectDescriptor)
1141  , mxImpl(new TransferableDataHelper_Impl)
1142 {
1143  InitFormats();
1144 }
1145 
1147  : mxTransfer(rDataHelper.mxTransfer)
1148  , mxClipboard(rDataHelper.mxClipboard)
1149  , maFormats(rDataHelper.maFormats)
1150  , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1151  , mxImpl(new TransferableDataHelper_Impl)
1152 {
1153 }
1154 
1156  : mxTransfer(std::move(rDataHelper.mxTransfer))
1157  , mxClipboard(std::move(rDataHelper.mxClipboard))
1158  , maFormats(std::move(rDataHelper.maFormats))
1159  , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1160  , mxImpl(new TransferableDataHelper_Impl)
1161 {
1162 }
1163 
1165 {
1166  if ( this != &rDataHelper )
1167  {
1168  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1169 
1170  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1171 
1172  if (bWasClipboardListening)
1174 
1175  mxTransfer = rDataHelper.mxTransfer;
1176  maFormats = rDataHelper.maFormats;
1177  mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1178  mxClipboard = rDataHelper.mxClipboard;
1179 
1180  if (bWasClipboardListening)
1182  }
1183 
1184  return *this;
1185 }
1186 
1188 {
1189  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1190 
1191  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1192 
1193  if (bWasClipboardListening)
1195 
1196  mxTransfer = std::move(rDataHelper.mxTransfer);
1197  maFormats = std::move(rDataHelper.maFormats);
1198  mxObjDesc = std::move(rDataHelper.mxObjDesc);
1199  mxClipboard = std::move(rDataHelper.mxClipboard);
1200 
1201  if (bWasClipboardListening)
1203 
1204  return *this;
1205 }
1206 
1208 {
1210  {
1211  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1212  maFormats.clear();
1213  mxObjDesc.reset();
1214  }
1215 }
1216 
1217 void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1218  DataFlavorExVector& rDataFlavorExVector )
1219 {
1220  try
1221  {
1223  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1224  DataFlavorEx aFlavorEx;
1225  static const OUStringLiteral aCharsetStr( u"charset" );
1226 
1227 
1228  for (auto const& rFlavor : rDataFlavorSeq)
1229  {
1230  Reference< XMimeContentType > xMimeType;
1231 
1232  try
1233  {
1234  if( !rFlavor.MimeType.isEmpty() )
1235  xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1236  }
1237  catch( const css::uno::Exception& )
1238  {
1239  }
1240 
1241  aFlavorEx.MimeType = rFlavor.MimeType;
1242  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1243  aFlavorEx.DataType = rFlavor.DataType;
1244  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1245 
1246  rDataFlavorExVector.push_back( aFlavorEx );
1247 
1248  // add additional formats for special mime types
1249  if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1250  {
1251  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1252  {
1253  aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1254  rDataFlavorExVector.push_back( aFlavorEx );
1255  }
1256  }
1257  else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1258  {
1259  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1260  {
1261  aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1262  rDataFlavorExVector.push_back( aFlavorEx );
1263  }
1264  }
1265  else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1266  {
1267  // #104735# HTML_SIMPLE may also be inserted without comments
1268  aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1269  rDataFlavorExVector.push_back( aFlavorEx );
1270  }
1271  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1272  {
1273  // add, if it is a UTF-8 byte buffer
1274  if( xMimeType->hasParameter( aCharsetStr ) )
1275  {
1276  if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1277  xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1278  {
1279  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1280 
1281  }
1282  }
1283  }
1284  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1285  {
1286  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1287  }
1288  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1289  {
1290  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1291  }
1292  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1293 
1294  {
1295  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1296  }
1297  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1298  {
1299  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1300  }
1301  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1302  {
1303  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1304  }
1305  }
1306  }
1307  catch( const css::uno::Exception& )
1308  {
1309  }
1310 }
1311 
1313 {
1314  SolarMutexGuard aSolarGuard;
1315  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1316 
1317  maFormats.clear();
1319 
1320  if( !mxTransfer.is() )
1321  return;
1322 
1324 
1325  for (auto const& format : maFormats)
1326  {
1327  if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1328  {
1330  break;
1331  }
1332  }
1333 }
1334 
1335 
1337 {
1338  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1339  return std::any_of(maFormats.begin(), maFormats.end(),
1340  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1341 }
1342 
1343 bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1344 {
1345  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1346  for (auto const& format : maFormats)
1347  {
1348  if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1349  return true;
1350  }
1351 
1352  return false;
1353 }
1354 
1356 {
1357  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1358  return maFormats.size();
1359 }
1360 
1362 {
1363  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1364  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1365  return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1366 }
1367 
1368 DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1369 {
1370  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1371  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1372 
1373  DataFlavor aRet;
1374 
1375  if (nFormat < maFormats.size())
1376  aRet = maFormats[nFormat];
1377 
1378  return aRet;
1379 }
1380 
1381 
1382 Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1383 {
1384  Reference< XTransferable > xRet;
1385 
1386  if( mxTransfer.is() )
1387  {
1388  try
1389  {
1390  xRet = mxTransfer;
1391 
1392  // do a dummy call to check, if this interface is valid (nasty)
1393  xRet->getTransferDataFlavors();
1394 
1395  }
1396  catch( const css::uno::Exception& )
1397  {
1398  xRet.clear();
1399  }
1400  }
1401 
1402  return xRet;
1403 }
1404 
1405 
1406 Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1407 {
1408  Any aReturn;
1409 
1410  DataFlavor aFlavor;
1411  if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1412  aReturn = GetAny(aFlavor, rDestDoc);
1413 
1414  return aReturn;
1415 }
1416 
1417 Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1418 {
1419  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1420  Any aRet;
1421 
1422  try
1423  {
1424  if( mxTransfer.is() )
1425  {
1426  const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1427 
1428  Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1429 
1430  if( nRequestFormat != SotClipboardFormatId::NONE )
1431  {
1432  // try to get alien format first
1433  for (auto const& format : maFormats)
1434  {
1435  if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1436  {
1437 // tdf#133365: only release solar mutex on Windows
1438 #ifdef _WIN32
1439  // tdf#133527: first, make sure that we actually hold the mutex
1440  SolarMutexGuard g;
1441  // Our own thread may handle the nested IDataObject::GetData call,
1442  // and try to acquire solar mutex
1444 #endif // _WIN32
1445 
1446  if (xTransfer2.is())
1447  aRet = xTransfer2->getTransferData2(format, rDestDoc);
1448  else
1449  aRet = mxTransfer->getTransferData(format);
1450  }
1451 
1452  if( aRet.hasValue() )
1453  break;
1454  }
1455  }
1456 
1457  if( !aRet.hasValue() )
1458  {
1459 // tdf#133365: only release solar mutex on Windows
1460 #ifdef _WIN32
1461  // tdf#133527: first, make sure that we actually hold the mutex
1462  SolarMutexGuard g;
1463  // Our own thread may handle the nested IDataObject::GetData call,
1464  // and try to acquire solar mutex
1466 #endif // _WIN32
1467 
1468  if (xTransfer2.is())
1469  aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1470  else
1471  aRet = mxTransfer->getTransferData(rFlavor);
1472  }
1473  }
1474  }
1475  catch( const css::uno::Exception& )
1476  {
1477  }
1478 
1479  return aRet;
1480 }
1481 
1482 
1484 {
1485  DataFlavor aFlavor;
1486  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1487 }
1488 
1489 
1490 bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr )
1491 {
1492  Any aAny = GetAny(rFlavor, OUString());
1493  bool bRet = false;
1494 
1495  if( aAny.hasValue() )
1496  {
1497  OUString aOUString;
1499 
1500  if( aAny >>= aOUString )
1501  {
1502  rStr = aOUString;
1503  bRet = true;
1504  }
1505  else if( aAny >>= aSeq )
1506  {
1507 
1508  const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1509  sal_Int32 nLen = aSeq.getLength();
1510 
1511  //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1512  //DVO 2002-05-27: strip _all_ trailing zeros
1513  while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1514  --nLen;
1515 
1516  rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1517  bRet = true;
1518  }
1519  }
1520 
1521  return bRet;
1522 }
1523 
1524 
1526 {
1527  if(SotClipboardFormatId::BITMAP == nFormat)
1528  {
1529  // try to get PNG first
1530  DataFlavor aFlavor;
1531 
1532  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1533  {
1534  if(GetBitmapEx(aFlavor, rBmpEx))
1535  {
1536  return true;
1537  }
1538  }
1539 
1540  // then JPEG
1541  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1542  {
1543  if(GetBitmapEx(aFlavor, rBmpEx))
1544  {
1545  return true;
1546  }
1547  }
1548  }
1549 
1550  DataFlavor aFlavor;
1551  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1552 }
1553 
1554 
1555 bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx )
1556 {
1558  DataFlavor aSubstFlavor;
1559  bool bRet(GetSotStorageStream(rFlavor, xStm));
1560  bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1561  bool bSuppressJPEG(false);
1562 
1563  if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1564  {
1565  // when no direct success, try if PNG is available
1566  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1567  bSuppressJPEG = bRet;
1568  }
1569 
1570  if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1571  {
1572  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1573  bSuppressPNG = bRet;
1574  }
1575 
1576  if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1577  {
1578  // when no direct success, try if BMP is available
1579  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1580  bSuppressPNG = bRet;
1581  bSuppressJPEG = bRet;
1582  }
1583 
1584  if(bRet)
1585  {
1586  if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1587  {
1588  // it's a PNG, import to BitmapEx
1589  vcl::PngImageReader aPNGReader(*xStm);
1590  rBmpEx = aPNGReader.read();
1591  }
1592  else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1593  {
1594  // it's a JPEG, import to BitmapEx
1596  Graphic aGraphic;
1597  if (rFilter.ImportGraphic(aGraphic, "", *xStm) == ERRCODE_NONE)
1598  rBmpEx = aGraphic.GetBitmapEx();
1599  }
1600 
1601  if(rBmpEx.IsEmpty())
1602  {
1603  Bitmap aBitmap;
1604  AlphaMask aMask;
1605 
1606  // explicitly use Bitmap::Read with bFileHeader = sal_True
1607  // #i124085# keep DIBV5 for read from clipboard, but should not happen
1608  ReadDIBV5(aBitmap, aMask, *xStm);
1609 
1610  if(aMask.GetBitmap().IsEmpty())
1611  {
1612  rBmpEx = aBitmap;
1613  }
1614  else
1615  {
1616  rBmpEx = BitmapEx(aBitmap, aMask);
1617  }
1618  }
1619 
1620  bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1621 
1622  /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1623  problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1624  and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1625  Due to this reason the following code assumes that bitmaps with a logical size
1626  greater than 50 cm aren't having the correct mapmode set.
1627 
1628  The following code should be removed if DDBs and DIBs are supported via clipboard
1629  properly.
1630  */
1631  if(bRet)
1632  {
1633  const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1634 
1635  if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1636  {
1637  const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1638 
1639  // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1640  // the described 50 cm (which is 50000 100th mm)
1641  if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1642  {
1643  rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1644 
1645  // #i122388# also adapt size by applying the mew MapMode
1646  const Size aNewSize(OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
1647  rBmpEx.SetPrefSize(aNewSize);
1648  }
1649  }
1650  }
1651  }
1652 
1653  return bRet;
1654 }
1655 
1656 
1658 {
1659  DataFlavor aFlavor;
1660  return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1661  GetGDIMetaFile(aFlavor, rMtf) &&
1662  (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1663 }
1664 
1665 
1666 bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf )
1667 {
1669  DataFlavor aSubstFlavor;
1670  bool bRet = false;
1671 
1672  if( GetSotStorageStream( rFlavor, xStm ) )
1673  {
1674  ReadGDIMetaFile( *xStm, rMtf );
1675  bRet = ( xStm->GetError() == ERRCODE_NONE );
1676  }
1677 
1678  if( !bRet &&
1679  HasFormat( SotClipboardFormatId::EMF ) &&
1680  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1681  GetSotStorageStream( aSubstFlavor, xStm ) )
1682  {
1683  Graphic aGraphic;
1684 
1685  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1686  {
1687  rMtf = aGraphic.GetGDIMetaFile();
1688  bRet = true;
1689  }
1690  }
1691 
1692  if( !bRet &&
1693  HasFormat( SotClipboardFormatId::WMF ) &&
1694  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1695  GetSotStorageStream( aSubstFlavor, xStm ) )
1696  {
1697  Graphic aGraphic;
1698 
1699  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1700  {
1701  rMtf = aGraphic.GetGDIMetaFile();
1702  bRet = true;
1703  }
1704  }
1705 
1706  return bRet;
1707 }
1708 
1709 
1711 {
1712  if(SotClipboardFormatId::BITMAP == nFormat)
1713  {
1714  // try to get PNG first
1715  DataFlavor aFlavor;
1716 
1717  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1718  {
1719  if(GetGraphic(aFlavor, rGraphic))
1720  {
1721  return true;
1722  }
1723  }
1724  }
1725 
1726  DataFlavor aFlavor;
1727  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1728 }
1729 
1730 
1731 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic )
1732 {
1733  DataFlavor aFlavor;
1734  bool bRet = false;
1735 
1736  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1737  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1738  {
1739  // try to get PNG first
1740  BitmapEx aBmpEx;
1741 
1742  bRet = GetBitmapEx( aFlavor, aBmpEx );
1743  if( bRet )
1744  rGraphic = aBmpEx;
1745  }
1746  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1747  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1748  {
1749  Graphic aGraphic;
1751  if (GetSotStorageStream(rFlavor, xStm))
1752  {
1753  if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1754  {
1755  rGraphic = aGraphic;
1756  bRet = true;
1757  }
1758  }
1759  }
1760  else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1761  {
1762  BitmapEx aBitmapEx;
1763 
1764  bRet = GetBitmapEx(aFlavor, aBitmapEx);
1765  if (bRet)
1766  rGraphic = aBitmapEx;
1767  }
1768  else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1769  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1770  {
1771  BitmapEx aBmpEx;
1772 
1773  bRet = GetBitmapEx( aFlavor, aBmpEx );
1774  if( bRet )
1775  rGraphic = aBmpEx;
1776  }
1777  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1778  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1779  {
1780  GDIMetaFile aMtf;
1781 
1782  bRet = GetGDIMetaFile( aFlavor, aMtf );
1783  if( bRet )
1784  rGraphic = aMtf;
1785  }
1786  else
1787  {
1789 
1790  if( GetSotStorageStream( rFlavor, xStm ) )
1791  {
1792  TypeSerializer aSerializer(*xStm);
1793  aSerializer.readGraphic(rGraphic);
1794  bRet = ( xStm->GetError() == ERRCODE_NONE );
1795  }
1796  }
1797 
1798  return bRet;
1799 }
1800 
1801 
1803 {
1804  DataFlavor aFlavor;
1805  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1806 }
1807 
1808 
1809 bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap )
1810 {
1812  bool bRet = GetSotStorageStream( rFlavor, xStm );
1813 
1814  if( bRet )
1815  {
1816  rIMap.Read( *xStm );
1817  bRet = ( xStm->GetError() == ERRCODE_NONE );
1818  }
1819 
1820  return bRet;
1821 }
1822 
1823 
1825 {
1826  DataFlavor aFlavor;
1827  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1828 }
1829 
1830 
1832 {
1833  rDesc = *mxObjDesc;
1834  return true;
1835 }
1836 
1837 
1839 {
1840  DataFlavor aFlavor;
1841  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1842 }
1843 
1844 
1845 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk )
1846 {
1847  bool bRet = false;
1848  if( HasFormat( rFlavor ))
1849  {
1850  const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1851  switch( nFormat )
1852  {
1853  case SotClipboardFormatId::SOLK:
1854  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1855  {
1856  OUString aString;
1857  if( GetString( rFlavor, aString ) )
1858  {
1859  if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1860  {
1861  rBmk = INetBookmark( aString, aString );
1862  bRet = true;
1863  }
1864  else
1865  {
1866  OUString aURL, aDesc;
1867  sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1868 
1869  if( !nLen && aString[ 0 ] != '0' )
1870  {
1871  SAL_INFO( "svtools", "SOLK: 1. len=0" );
1872  }
1873  if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1874  {
1875  SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1876  }
1877  aURL = aString.copy( nStart + 1, nLen );
1878 
1879  aString = aString.replaceAt( 0, nStart + 1 + nLen, "" );
1880  nStart = aString.indexOf( '@' );
1881  nLen = aString.toInt32();
1882 
1883  if( !nLen && aString[ 0 ] != '0' )
1884  {
1885  SAL_INFO( "svtools", "SOLK: 2. len=0" );
1886  }
1887  if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1888  {
1889  SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1890  }
1891  aDesc = aString.copy( nStart+1, nLen );
1892 
1893  rBmk = INetBookmark( aURL, aDesc );
1894  bRet = true;
1895  }
1896  }
1897  }
1898  break;
1899 
1900  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1901  {
1902  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1903 
1904  if (2048 == aSeq.getLength())
1905  {
1906  const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1907  const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1908  rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1909  OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1910  bRet = true;
1911  }
1912  }
1913  break;
1914 
1915 #ifdef _WIN32
1916  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1917  {
1918  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1919 
1920  if (aSeq.getLength())
1921  {
1922  FILEGROUPDESCRIPTOR const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR const *>(aSeq.getConstArray());
1923 
1924  if( pFDesc->cItems )
1925  {
1926  OString aDesc( pFDesc->fgd[ 0 ].cFileName );
1927  rtl_TextEncoding eTextEncoding = osl_getThreadTextEncoding();
1928 
1929  if( ( aDesc.getLength() > 4 ) && aDesc.copy(aDesc.getLength() - 4).equalsIgnoreAsciiCase(".URL") )
1930  {
1931  std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( OStringToOUString(aDesc, eTextEncoding) ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1932  StreamMode::STD_READ ));
1933 
1934  if( !pStream || pStream->GetError() )
1935  {
1936  DataFlavor aFileContentFlavor;
1937 
1938  aSeq.realloc( 0 );
1939  pStream.reset();
1940 
1941  if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1942  {
1943  aSeq = GetSequence(aFileContentFlavor, OUString());
1944  if (aSeq.getLength())
1945  pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1946  }
1947  }
1948 
1949  if( pStream )
1950  {
1951  OString aLine;
1952  bool bSttFnd = false;
1953 
1954  while( pStream->ReadLine( aLine ) )
1955  {
1956  if (aLine.equalsIgnoreAsciiCase("[InternetShortcut]"))
1957  bSttFnd = true;
1958  else if (bSttFnd && aLine.copy(0, 4).equalsIgnoreAsciiCase("URL="))
1959  {
1960  rBmk = INetBookmark( OStringToOUString(aLine.subView(4), eTextEncoding),
1961  OStringToOUString(aDesc.subView(0, aDesc.getLength() - 4), eTextEncoding) );
1962  bRet = true;
1963  break;
1964  }
1965  }
1966  }
1967  }
1968  }
1969  }
1970  }
1971  break;
1972 #endif
1973  default: break;
1974  }
1975  }
1976  return bRet;
1977 }
1978 
1979 
1981  INetImage& rINtImg )
1982 {
1983  DataFlavor aFlavor;
1984  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1985 }
1986 
1987 
1989  const css::datatransfer::DataFlavor& rFlavor,
1990  INetImage& rINtImg )
1991 {
1993  bool bRet = GetSotStorageStream( rFlavor, xStm );
1994 
1995  if( bRet )
1996  bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
1997  return bRet;
1998 }
1999 
2000 
2002  FileList& rFileList )
2003 {
2004  DataFlavor aFlavor;
2005  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
2006 }
2007 
2008 
2010 {
2012  bool bRet = false;
2013 
2014  for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
2015  {
2016  if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
2017  {
2018  const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
2019 
2020  if( GetSotStorageStream( aFlavor, xStm ) )
2021  {
2022  if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2023  {
2024  OString aDiskString;
2025 
2026  while( xStm->ReadLine( aDiskString ) )
2027  if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2028  rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2029 
2030  bRet = true;
2031  }
2032  else
2033  bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2034  }
2035  }
2036  }
2037 
2038  return bRet;
2039 }
2040 
2041 
2042 Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc )
2043 {
2044  DataFlavor aFlavor;
2045  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2046  return Sequence<sal_Int8>();
2047 
2048  return GetSequence(aFlavor, rDestDoc);
2049 }
2050 
2051 Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc )
2052 {
2053  const Any aAny = GetAny(rFlavor, rDestDoc);
2054  Sequence<sal_Int8> aSeq;
2055  if (aAny.hasValue())
2056  aAny >>= aSeq;
2057 
2058  return aSeq;
2059 }
2060 
2061 
2063 {
2064  DataFlavor aFlavor;
2065  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2066 }
2067 
2068 
2069 bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotTempStream>& rxStream )
2070 {
2071  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2072 
2073  if (aSeq.hasElements())
2074  {
2075  rxStream = new SotTempStream( "" );
2076  rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2077  rxStream->Seek( 0 );
2078  }
2079 
2080  return aSeq.hasElements();
2081 }
2082 
2084 {
2085  DataFlavor aFlavor;
2086  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2087  return Reference<XInputStream>();
2088 
2089  return GetInputStream(aFlavor, rDestDoc);
2090 }
2091 
2092 Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc )
2093 {
2094  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2095 
2096  if (!aSeq.hasElements())
2097  return Reference<XInputStream>();
2098 
2100  return xStream;
2101 }
2102 
2103 void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2104 {
2105  mxTransfer = _rxNewContent;
2106  InitFormats();
2107 }
2108 
2110 {
2111  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2112 
2114 
2115  mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2116 
2117  return mxImpl->mxClipboardListener->isListening();
2118 }
2119 
2121 {
2122  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2123 
2124  if (mxImpl->mxClipboardListener.is())
2125  {
2126  mxImpl->mxClipboardListener->dispose();
2127  mxImpl->mxClipboardListener.clear();
2128  }
2129 }
2130 
2131 TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2132 {
2134 
2135  if( rClipboard.is() )
2136  {
2137  try
2138  {
2139  Reference< XTransferable > xTransferable( rClipboard->getContents() );
2140 
2141  if( xTransferable.is() )
2142  {
2143  aRet = TransferableDataHelper( xTransferable );
2144  // also copy the clipboard
2145  aRet.mxClipboard = rClipboard;
2146  }
2147  }
2148  catch( const css::uno::Exception& )
2149  {
2150  }
2151  }
2152 
2153  return aRet;
2154 }
2155 
2157 {
2158  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2159 
2160  Reference< XClipboard > xClipboard;
2161 
2162  if( pWindow )
2163  xClipboard = pWindow->GetClipboard();
2164 
2165  return CreateFromClipboard(xClipboard);
2166 }
2167 
2169 {
2170  Reference< XClipboard > xSelection(GetSystemPrimarySelection());
2172 
2173  if( xSelection.is() )
2174  {
2175  SolarMutexReleaser aReleaser;
2176 
2177  try
2178  {
2179  Reference< XTransferable > xTransferable( xSelection->getContents() );
2180 
2181  if( xTransferable.is() )
2182  {
2183  aRet = TransferableDataHelper( xTransferable );
2184  aRet.mxClipboard = xSelection;
2185  }
2186  }
2187  catch( const css::uno::Exception& )
2188  {
2189  }
2190  }
2191 
2192  return aRet;
2193 }
2194 
2195 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2196  const css::datatransfer::DataFlavor& rRequestFlavor )
2197 {
2199  bool bRet = false;
2200 
2201  try
2202  {
2203  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2204 
2205  Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2206  Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2207 
2208  if( xRequestType1.is() && xRequestType2.is() )
2209  {
2210  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2211  {
2212  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2213  {
2214  // special handling for text/plain media types
2215  static const OUStringLiteral aCharsetString( u"charset" );
2216 
2217  if( !xRequestType2->hasParameter( aCharsetString ) ||
2218  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2219  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2220  {
2221  bRet = true;
2222  }
2223  }
2224  else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2225  {
2226  // special handling for application/x-openoffice media types
2227  static const OUStringLiteral aFormatString( u"windows_formatname" );
2228 
2229  if( xRequestType1->hasParameter( aFormatString ) &&
2230  xRequestType2->hasParameter( aFormatString ) &&
2231  xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2232  {
2233  bRet = true;
2234  }
2235  }
2236  else
2237  bRet = true;
2238  }
2239  }
2240  }
2241  catch( const css::uno::Exception& )
2242  {
2243  bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2244  }
2245 
2246  return bRet;
2247 }
2248 
2249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic)
Definition: transfer.cxx:1710
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:243
bool SetINetImage(const INetImage &rINtImg, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:863
css::uno::Reference< css::datatransfer::dnd::XDragSource > GetDragSource()
Definition: mouse.cxx:718
Point GetPointerPosPixel()
Definition: mouse.cxx:549
VCL_DLLPRIVATE void ImplFlush()
Definition: transfer.cxx:529
URL aURL
void Write(SvStream &rOStm) const
Definition: imap.cxx:919
bool GetSotStorageStream(SotClipboardFormatId nFormat, tools::SvRef< SotTempStream > &rStreamRef)
Definition: transfer.cxx:2062
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
css::uno::Reference< css::frame::XTerminateListener > mxTerminateListener
Definition: transfer.hxx:170
css::uno::Any GetAny(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:1406
bool SetBitmapEx(const BitmapEx &rBitmap, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:675
void readGraphic(Graphic &rGraphic)
void setWidth(tools::Long nWidth)
SvStream & WriteInt32(sal_Int32 nInt32)
virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:427
const MapMode & GetPrefMapMode() const
Definition: bitmapex.hxx:89
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1466
virtual void SAL_CALL dragOver(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:504
virtual void AddSupportedFormats()=0
signed char sal_Int8
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetClipboard()
Definition: window.cxx:3418
OUString maLastFormat
Definition: transfer.hxx:168
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
void Rebind(const css::uno::Reference< css::datatransfer::XTransferable > &_rxNewData)
Definition: transfer.cxx:2103
::std::vector< DataFlavorEx > DataFlavorExVector
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: bitmapex.hxx:90
bool ConvertGDIMetaFileToWMF(const GDIMetaFile &rMTF, SvStream &rTargetStream, FilterConfigItem const *pConfigItem, bool bPlaceable)
Definition: wmf.cxx:69
bool SetTransferableObjectDescriptor(const TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:762
bool HasFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:632
DataFlavorExVector maFormats
Definition: transfer.hxx:282
#define STREAM_SEEK_TO_END
sal_uInt64 Seek(sal_uInt64 nPos)
Class to import and export graphic formats.
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1361
virtual void DragFinished(sal_Int8 nDropAction)
Definition: transfer.cxx:914
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk)
Definition: transfer.cxx:1838
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:403
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1336
static TransferableDataHelper CreateFromPrimarySelection()
Definition: transfer.cxx:2168
sal_uInt64 SeekRel(sal_Int64 nPos)
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:775
bool SetObject(void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:877
virtual sal_uInt64 TellEnd() override
void AddFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:549
constexpr tools::Long Width() const
SvStream & WriteTransferableObjectDescriptor(SvStream &rOStm, const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:82
virtual ~TerminateListener() override
Definition: transfer.cxx:238
sal_uInt16 sal_Unicode
virtual OUString SAL_CALL getImplementationName() override
Definition: transfer.cxx:258
ErrCode GetError() const
Reference< XInputStream > xStream
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
DataFlavorExVector maFormats
Definition: transfer.hxx:171
const Size & GetPrefSize() const
Definition: bitmapex.hxx:86
A helper class that calls Application::ReleaseSolarMutex() in its constructor and restores the mutex ...
Definition: svapp.hxx:1421
IntrinsicAnimationEventHandlerSharedPtr mpListener
SvStream & WriteUniOrByteString(const OUString &rStr, rtl_TextEncoding eDestCharSet)
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2156
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:340
SvStream & WriteUInt32(sal_uInt32 nUInt32)
virtual css::uno::Any SAL_CALL getTransferData2(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc) override
Definition: transfer.cxx:291
TransferableDataHelper & operator=(const TransferableDataHelper &rDataHelper)
Definition: transfer.cxx:1164
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: transfer.cxx:268
virtual bool WriteObject(tools::SvRef< SotTempStream > &rxOStm, void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:907
SotClipboardFormatId
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::unique_ptr< TransferableDataHelper_Impl > mxImpl
Definition: transfer.hxx:284
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:283
virtual void SAL_CALL dragEnter(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:494
virtual void SAL_CALL dropActionChanged(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:509
static void ImplSetParameterString(TransferableObjectDescriptor &rObjDesc, const DataFlavorEx &rFlavorEx)
Definition: transfer.cxx:162
static bool IsEqual(const css::datatransfer::DataFlavor &rInternalFlavor, const css::datatransfer::DataFlavor &rRequestFlavor)
Definition: transfer.cxx:2195
bool SetGraphic(const Graphic &rGraphic)
Definition: transfer.cxx:731
bool IsEmpty() const
Definition: BitmapEx.cxx:196
bool GetINetImage(SotClipboardFormatId nFormat, INetImage &rINtImg)
Definition: transfer.cxx:1980
void RemoveFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:609
#define SOFFICE_FILEFORMAT_50
#define DBG_ASSERT(sCon, aError)
css::datatransfer::DataFlavor GetFormatDataFlavor(sal_uInt32 nFormat) const
Definition: transfer.cxx:1368
int i
TerminateListener(TransferableHelper &rDropTargetHelper)
Definition: transfer.cxx:232
GraphicType GetType() const
Definition: graph.cxx:294
OUString GetHexName() const
#define STREAM_SEEK_TO_BEGIN
css::uno::Reference< css::datatransfer::XTransferable > GetXTransferable() const
Definition: transfer.cxx:1382
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:248
bool GetString(SotClipboardFormatId nFormat, OUString &rStr)
Definition: transfer.cxx:1483
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: transfer.cxx:1038
SvStream & ReadFileList(SvStream &rIStm, FileList &rFileList)
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
Definition: transfer.cxx:263
virtual void SAL_CALL notifyTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:253
#define TOD_SIG1
Definition: transfer.cxx:79
sal_uInt32 GetFormatCount() const
Definition: transfer.cxx:1355
float u
unsigned char sal_Bool
bool Write(SvStream &rStream)
Definition: pngwrite.cxx:707
const OUString & GetDescription() const
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:924
bool IsMouseCaptured() const
Definition: mouse.cxx:468
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:989
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1799
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
void CopyToClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
void SetVersion(sal_Int32 n)
void AppendFile(const OUString &rStr)
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:172
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
Definition: cvtgrf.cxx:34
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DragSourceEvent &dse) override
Definition: transfer.cxx:499
exports com.sun.star.chart2. data
virtual void SAL_CALL dragDropEnd(const css::datatransfer::dnd::DragSourceDropEvent &dsde) override
Definition: transfer.cxx:479
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap)
Definition: transfer.cxx:1802
virtual void SAL_CALL lostOwnership(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &xClipboard, const css::uno::Reference< css::datatransfer::XTransferable > &xTrans) override
Definition: transfer.cxx:452
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:229
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &rId) override
Definition: transfer.cxx:514
void ReleaseMouse()
Definition: mouse.cxx:457
#define TOD_SIG2
Definition: transfer.cxx:80
bool GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile &rMtf, size_t nMaxActions=0)
Return as GDI metafile.
Definition: transfer.cxx:1657
virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
Definition: transfer.cxx:410
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
Definition: cvtgrf.cxx:55
static SotClipboardFormatId RegisterFormat(const css::datatransfer::DataFlavor &rFlavor)
bool SetImageMap(const ImageMap &rIMap)
Definition: transfer.cxx:750
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:169
void CopyToPrimarySelection() const
Definition: transfer.cxx:984
static SotClipboardFormatId GetFormat(const css::datatransfer::DataFlavor &rFlavor)
static void FillDataFlavorExVector(const css::uno::Sequence< css::datatransfer::DataFlavor > &rDataFlavorSeq, DataFlavorExVector &rDataFlavorExVector)
Definition: transfer.cxx:1217
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
#define ERRCODE_NONE
Definition: errcode.hxx:196
constexpr tools::Long Height() const
void Read(SvStream &rIStm)
Definition: imap.cxx:955
#define DND_IMAGE_NONE
Definition: transfer.hxx:72
SvStream & ReadGDIMetaFile(SvStream &rIStm, GDIMetaFile &rGDIMetaFile, ImplMetaReadData *pData)
Definition: gdimtf.cxx:2642
#define SAL_INFO(area, stream)
virtual void ObjectReleased()
Definition: transfer.cxx:919
SvStream & WriteSvGlobalName(SvStream &rOStr, const SvGlobalName &rObj)
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp)
Definition: transfer.cxx:1525
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2083
void SetPrefSize(const Size &rPrefSize)
Definition: bitmapex.hxx:87
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList)
Definition: transfer.cxx:2001
bool IsEmpty() const
Definition: bitmap.hxx:547
sal_uInt64 Tell() const
size_t GetActionSize() const
Definition: gdimtf.cxx:180
Reference< XComponentContext > getProcessComponentContext()
const OUString & GetURL() const
Sequence< sal_Int8 > aSeq
css::uno::Reference< css::datatransfer::XTransferable > mxTransfer
Definition: transfer.hxx:280
css::uno::Any maAny
Definition: transfer.hxx:167
void setHeight(tools::Long nHeight)
static GraphicFilter & GetGraphicFilter()
bool GetTransferableObjectDescriptor(SotClipboardFormatId nFormat, TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:1824
void CopyToSelection(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
Definition: transfer.cxx:965
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:281
static TransferableDataHelper CreateFromClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard)
Definition: transfer.cxx:2131
SotClipboardFormatId mnSotId
void SetCompressMode(SvStreamCompressFlags nNewMode)
void dispose()
bool Read(SvStream &rIStm, SotClipboardFormatId nFormat)
Definition: inetimg.cxx:58
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1823
bool SetAny(const css::uno::Any &rAny)
Definition: transfer.cxx:646
const css::uno::Sequence< sal_Int8 > & getSeq() const
void writeGraphic(const Graphic &rGraphic)
static void ClearPrimarySelection()
Definition: transfer.cxx:1030
BaseContainerNodeSharedPtr & mrParent
bool SetString(const OUString &rString, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:653
aStr
void Write(SvStream &rOStm, SotClipboardFormatId nFormat) const
Definition: inetimg.cxx:28
static OUString ImplGetParameterString(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:112
css::uno::Sequence< sal_Int8 > GetSequence(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2042
bool MakeId(const OUString &rId)
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:286
rtl::Reference< TransferableClipboardNotifier > mxClipboardListener
Definition: transfer.cxx:1125
bool SetGDIMetaFile(const GDIMetaFile &rMtf)
Definition: transfer.cxx:717
Reference< XClipboard > GetSystemPrimarySelection()
Definition: transfer2.cxx:495
const void * GetData()
virtual bool GetData(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc)=0
#define DND_POINTER_NONE
Definition: transfer.hxx:71
static bool GetFormatDataFlavor(SotClipboardFormatId nFormat, css::datatransfer::DataFlavor &rFlavor)
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:474