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