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  const Bitmap aBitmap(rBitmapEx.GetBitmap());
706 
707  // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
708  WriteDIB(aBitmap, aMemStm, false, true);
709  }
710 
711  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
712  }
713 
714  return maAny.hasValue();
715 }
716 
717 
719 {
720  if( rMtf.GetActionSize() )
721  {
722  SvMemoryStream aMemStm( 65535, 65535 );
723 
724  const_cast<GDIMetaFile&>(rMtf).Write( aMemStm );
725  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
726  }
727 
728  return maAny.hasValue();
729 }
730 
731 
733 {
734  if( rGraphic.GetType() != GraphicType::NONE )
735  {
736  SvMemoryStream aMemStm( 65535, 65535 );
737 
739  aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
740  WriteGraphic( aMemStm, rGraphic );
741  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
742  }
743 
744  return maAny.hasValue();
745 }
746 
747 
749 {
750  SvMemoryStream aMemStm( 8192, 8192 );
751 
753  rIMap.Write( aMemStm );
754  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
755 
756  return maAny.hasValue();
757 }
758 
759 
761 {
762  PrepareOLE( rDesc );
763 
764  SvMemoryStream aMemStm( 1024, 1024 );
765 
766  WriteTransferableObjectDescriptor( aMemStm, rDesc );
767  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
768 
769  return maAny.hasValue();
770  }
771 
772 
774  const css::datatransfer::DataFlavor& rFlavor )
775 {
776  rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
777 
778  switch( SotExchange::GetFormat( rFlavor ) )
779  {
780  case SotClipboardFormatId::SOLK:
781  {
782  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
783  OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
784  OStringBuffer sOut;
785  sOut.append(sURL.getLength());
786  sOut.append('@').append(sURL);
787  sOut.append(sDesc.getLength());
788  sOut.append('@').append(sDesc);
789 
790  Sequence< sal_Int8 > aSeq(sOut.getLength());
791  memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
792  maAny <<= aSeq;
793  }
794  break;
795 
796  case SotClipboardFormatId::STRING:
797  maAny <<= rBmk.GetURL();
798  break;
799 
800  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
801  {
802  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
803  Sequence< sal_Int8 > aSeq( sURL.getLength() );
804  memcpy( aSeq.getArray(), sURL.getStr(), sURL.getLength() );
805  maAny <<= aSeq;
806  }
807  break;
808 
809  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
810  {
811  Sequence< sal_Int8 > aSeq( 2048 );
812 
813  memset( aSeq.getArray(), 0, 2048 );
814  strcpy( reinterpret_cast< char* >( aSeq.getArray() ), OUStringToOString(rBmk.GetURL(), eSysCSet).getStr() );
815  strcpy( reinterpret_cast< char* >( aSeq.getArray() ) + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr() );
816 
817  maAny <<= aSeq;
818  }
819  break;
820 
821 #ifdef _WIN32
822  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
823  {
824  Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTOR ) );
825  FILEGROUPDESCRIPTOR* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR*>(aSeq.getArray());
826  FILEDESCRIPTOR& rFDesc1 = pFDesc->fgd[ 0 ];
827 
828  pFDesc->cItems = 1;
829  memset( &rFDesc1, 0, sizeof( FILEDESCRIPTOR ) );
830  rFDesc1.dwFlags = FD_LINKUI;
831 
832  OStringBuffer aStr(OUStringToOString(
833  rBmk.GetDescription(), eSysCSet));
834  for( sal_Int32 nChar = 0; nChar < aStr.getLength(); ++nChar )
835  if( strchr( "\\/:*?\"<>|", aStr[nChar] ) )
836  aStr.remove(nChar--, 1);
837 
838  aStr.insert(0, "Shortcut to ");
839  aStr.append(".URL");
840  strcpy( rFDesc1.cFileName, aStr.getStr() );
841 
842  maAny <<= aSeq;
843  }
844  break;
845 
846  case SotClipboardFormatId::FILECONTENT:
847  {
848  OUString aStr( "[InternetShortcut]\x0aURL=" );
849  maAny <<= ( aStr += rBmk.GetURL() );
850  }
851  break;
852 #endif
853 
854  default:
855  break;
856  }
857 
858  return maAny.hasValue();
859 }
860 
861 
863  const css::datatransfer::DataFlavor& rFlavor )
864 {
865  SvMemoryStream aMemStm( 1024, 1024 );
866 
868  rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
869 
870  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
871 
872  return maAny.hasValue();
873 }
874 
875 
876 bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
877 {
878  tools::SvRef<SotStorageStream> xStm( new SotStorageStream( OUString() ) );
879 
880  xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
881 
882  if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
883  {
884  const sal_uInt32 nLen = xStm->TellEnd();
885  Sequence< sal_Int8 > aSeq( nLen );
886 
887  xStm->Seek( STREAM_SEEK_TO_BEGIN );
888  xStm->ReadBytes(aSeq.getArray(), nLen);
889 
890  if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
891  {
892  //JP 24.7.2001: as I know was this only for the writer application and this
893  // writes now UTF16 format into the stream
894  //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
895  // little / big endians! - Bug 88121
896  maAny <<= OUString( reinterpret_cast< const sal_Char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
897  }
898  else
899  maAny <<= aSeq;
900  }
901 
902  return maAny.hasValue();
903 }
904 
905 
906 bool TransferableHelper::WriteObject( tools::SvRef<SotStorageStream>&, void*, sal_uInt32, const DataFlavor& )
907 {
908  OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
909  return false;
910 }
911 
912 
914 {
915 }
916 
917 
919 {
920 }
921 
922 
924 {
925  mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
926 
927  if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
928  AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
929 }
930 
931 void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
932 {
933  if( rClipboard.is() )
934  mxClipboard = rClipboard;
935 
936  if( !(mxClipboard.is() && !mxTerminateListener.is()) )
937  return;
938 
939  try
940  {
941  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
942  pThis->mxTerminateListener = new TerminateListener( *pThis );
943  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
944  xDesktop->addTerminateListener( pThis->mxTerminateListener );
945 
946  mxClipboard->setContents( pThis, pThis );
947  }
948  catch( const css::uno::Exception& )
949  {
950  }
951 }
952 
954 {
955  DBG_ASSERT( pWindow, "Window pointer is NULL" );
956  Reference< XClipboard > xClipboard;
957 
958  if( pWindow )
959  xClipboard = pWindow->GetClipboard();
960 
961  CopyToClipboard(xClipboard);
962 }
963 
964 void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
965 {
966  if( !(rSelection.is() && !mxTerminateListener.is()) )
967  return;
968 
969  try
970  {
971  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
972  pThis->mxTerminateListener = new TerminateListener( *pThis );
973  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
974  xDesktop->addTerminateListener( pThis->mxTerminateListener );
975 
976  rSelection->setContents( pThis, pThis );
977  }
978  catch( const css::uno::Exception& )
979  {
980  }
981 }
982 
984 {
985  DBG_ASSERT( pWindow, "Window pointer is NULL" );
986  Reference< XClipboard > xSelection;
987 
988  if( pWindow )
989  xSelection = pWindow->GetPrimarySelection();
990 
991  CopyToSelection(xSelection);
992 }
993 
994 void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
995 
996 {
997  DBG_ASSERT( pWindow, "Window pointer is NULL" );
998  Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
999 
1000  if( !xDragSource.is() )
1001  return;
1002 
1003  /*
1004  * #96792# release mouse before actually starting DnD.
1005  * This is necessary for the X11 DnD implementation to work.
1006  */
1007  if( pWindow->IsMouseCaptured() )
1008  pWindow->ReleaseMouse();
1009 
1010  const Point aPt( pWindow->GetPointerPosPixel() );
1011 
1012  // On macOS we are forced to execute 'startDrag' synchronously
1013  // contrary to the XDragSource interface specification because
1014  // we can receive drag events from the system only in the main
1015  // thread
1016 #if !defined(MACOSX)
1017  SolarMutexReleaser aReleaser;
1018 #endif
1019 
1020  try
1021  {
1022  DragGestureEvent aEvt;
1023  aEvt.DragAction = DNDConstants::ACTION_COPY;
1024  aEvt.DragOriginX = aPt.X();
1025  aEvt.DragOriginY = aPt.Y();
1026  aEvt.DragSource = xDragSource;
1027 
1028  xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
1029  }
1030  catch( const css::uno::Exception& )
1031  {
1032  }
1033 }
1034 
1036 {
1037  DBG_ASSERT( pWindow, "Window pointer is NULL" );
1038  Reference< XClipboard > xSelection( pWindow->GetPrimarySelection() );
1039 
1040  if( xSelection.is() )
1041  xSelection->setContents( nullptr, nullptr );
1042 }
1043 
1044 namespace
1045 {
1046  class theTransferableHelperUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theTransferableHelperUnoTunnelId > {};
1047 }
1048 
1050 {
1051  return theTransferableHelperUnoTunnelId::get().getSeq();
1052 }
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 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1080  :mrMutex( _rMutex )
1081  ,mxNotifier( _rxClipboard, UNO_QUERY )
1082  ,mpListener( &_rListener )
1083 {
1084  osl_atomic_increment( &m_refCount );
1085  {
1086  if ( mxNotifier.is() )
1087  mxNotifier->addClipboardListener( this );
1088  else
1089  // born dead
1090  mpListener = nullptr;
1091  }
1092  osl_atomic_decrement( &m_refCount );
1093 }
1094 
1095 
1096 void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1097 {
1098  SolarMutexGuard aSolarGuard;
1099  // the SolarMutex here is necessary, since
1100  // - we cannot call mpListener without our own mutex locked
1101  // - Rebind respectively InitFormats (called by Rebind) will
1102  // try to lock the SolarMutex, too
1103  ::osl::MutexGuard aGuard( mrMutex );
1104  if( mpListener )
1105  mpListener->Rebind( event.Contents );
1106 }
1107 
1108 
1109 void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1110 {
1111  // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1112  dispose();
1113 }
1114 
1115 
1117 {
1118  ::osl::MutexGuard aGuard( mrMutex );
1119 
1120  Reference< XClipboardListener > xKeepMeAlive( this );
1121 
1122  if ( mxNotifier.is() )
1123  mxNotifier->removeClipboardListener( this );
1124  mxNotifier.clear();
1125 
1126  mpListener = nullptr;
1127 }
1128 
1130 {
1131  ::osl::Mutex maMutex;
1133 
1135  {
1136  }
1137 };
1138 
1140  : mxObjDesc(new TransferableObjectDescriptor)
1141  , mxImpl(new TransferableDataHelper_Impl)
1142 {
1143 }
1144 
1146  : mxTransfer(rxTransferable)
1147  , mxObjDesc(new TransferableObjectDescriptor)
1148  , mxImpl(new TransferableDataHelper_Impl)
1149 {
1150  InitFormats();
1151 }
1152 
1154  : mxTransfer(rDataHelper.mxTransfer)
1155  , mxClipboard(rDataHelper.mxClipboard)
1156  , maFormats(rDataHelper.maFormats)
1157  , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1158  , mxImpl(new TransferableDataHelper_Impl)
1159 {
1160 }
1161 
1163  : mxTransfer(std::move(rDataHelper.mxTransfer))
1164  , mxClipboard(std::move(rDataHelper.mxClipboard))
1165  , maFormats(std::move(rDataHelper.maFormats))
1166  , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1167  , mxImpl(new TransferableDataHelper_Impl)
1168 {
1169 }
1170 
1172 {
1173  if ( this != &rDataHelper )
1174  {
1175  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1176 
1177  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1178 
1179  if (bWasClipboardListening)
1181 
1182  mxTransfer = rDataHelper.mxTransfer;
1183  maFormats = rDataHelper.maFormats;
1184  mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1185  mxClipboard = rDataHelper.mxClipboard;
1186 
1187  if (bWasClipboardListening)
1189  }
1190 
1191  return *this;
1192 }
1193 
1195 {
1196  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1197 
1198  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1199 
1200  if (bWasClipboardListening)
1202 
1203  mxTransfer = std::move(rDataHelper.mxTransfer);
1204  maFormats = std::move(rDataHelper.maFormats);
1205  mxObjDesc = std::move(rDataHelper.mxObjDesc);
1206  mxClipboard = std::move(rDataHelper.mxClipboard);
1207 
1208  if (bWasClipboardListening)
1210 
1211  return *this;
1212 }
1213 
1215 {
1217  {
1218  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1219  maFormats.clear();
1220  mxObjDesc.reset();
1221  }
1222 }
1223 
1224 void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1225  DataFlavorExVector& rDataFlavorExVector )
1226 {
1227  try
1228  {
1230  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1231  DataFlavorEx aFlavorEx;
1232  const OUString aCharsetStr( "charset" );
1233 
1234 
1235  for (auto const& rFlavor : rDataFlavorSeq)
1236  {
1237  Reference< XMimeContentType > xMimeType;
1238 
1239  try
1240  {
1241  if( !rFlavor.MimeType.isEmpty() )
1242  xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1243  }
1244  catch( const css::uno::Exception& )
1245  {
1246  }
1247 
1248  aFlavorEx.MimeType = rFlavor.MimeType;
1249  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1250  aFlavorEx.DataType = rFlavor.DataType;
1251  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1252 
1253  rDataFlavorExVector.push_back( aFlavorEx );
1254 
1255  // add additional formats for special mime types
1256  if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId)
1257  {
1258  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1259  {
1260  aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1261  rDataFlavorExVector.push_back( aFlavorEx );
1262  }
1263  }
1264  else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1265  {
1266  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1267  {
1268  aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1269  rDataFlavorExVector.push_back( aFlavorEx );
1270  }
1271  }
1272  else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1273  {
1274  // #104735# HTML_SIMPLE may also be inserted without comments
1275  aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1276  rDataFlavorExVector.push_back( aFlavorEx );
1277  }
1278  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1279  {
1280  // add, if it is a UTF-8 byte buffer
1281  if( xMimeType->hasParameter( aCharsetStr ) )
1282  {
1283  if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1284  xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1285  {
1286  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1287 
1288  }
1289  }
1290  }
1291  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1292  {
1293  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1294  }
1295  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1296  {
1297  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1298  }
1299  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1300 
1301  {
1302  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1303  }
1304  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1305  {
1306  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1307  }
1308  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1309  {
1310  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1311  }
1312  }
1313  }
1314  catch( const css::uno::Exception& )
1315  {
1316  }
1317 }
1318 
1320 {
1321  SolarMutexGuard aSolarGuard;
1322  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1323 
1324  maFormats.clear();
1326 
1327  if( !mxTransfer.is() )
1328  return;
1329 
1331 
1332  for (auto const& format : maFormats)
1333  {
1334  if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1335  {
1337  break;
1338  }
1339  }
1340 }
1341 
1342 
1344 {
1345  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1346  return std::any_of(maFormats.begin(), maFormats.end(),
1347  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1348 }
1349 
1350 bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1351 {
1352  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1353  for (auto const& format : maFormats)
1354  {
1355  if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1356  return true;
1357  }
1358 
1359  return false;
1360 }
1361 
1363 {
1364  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1365  return maFormats.size();
1366 }
1367 
1369 {
1370  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1371  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1372  return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1373 }
1374 
1375 DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1376 {
1377  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1378  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1379 
1380  DataFlavor aRet;
1381 
1382  if (nFormat < maFormats.size())
1383  aRet = maFormats[nFormat];
1384 
1385  return aRet;
1386 }
1387 
1388 
1389 Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1390 {
1391  Reference< XTransferable > xRet;
1392 
1393  if( mxTransfer.is() )
1394  {
1395  try
1396  {
1397  xRet = mxTransfer;
1398 
1399  // do a dummy call to check, if this interface is valid (nasty)
1400  xRet->getTransferDataFlavors();
1401 
1402  }
1403  catch( const css::uno::Exception& )
1404  {
1405  xRet.clear();
1406  }
1407  }
1408 
1409  return xRet;
1410 }
1411 
1412 
1413 Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1414 {
1415  Any aReturn;
1416 
1417  DataFlavor aFlavor;
1418  if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1419  aReturn = GetAny(aFlavor, rDestDoc);
1420 
1421  return aReturn;
1422 }
1423 
1424 Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1425 {
1426  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1427  Any aRet;
1428 
1429  try
1430  {
1431  if( mxTransfer.is() )
1432  {
1433  const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1434 
1435  Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1436 
1437  if( nRequestFormat != SotClipboardFormatId::NONE )
1438  {
1439  // try to get alien format first
1440  for (auto const& format : maFormats)
1441  {
1442  if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1443  {
1444  if (xTransfer2.is())
1445  aRet = xTransfer2->getTransferData2(format, rDestDoc);
1446  else
1447  aRet = mxTransfer->getTransferData(format);
1448  }
1449 
1450  if( aRet.hasValue() )
1451  break;
1452  }
1453  }
1454 
1455  if( !aRet.hasValue() )
1456  {
1457  if (xTransfer2.is())
1458  aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1459  else
1460  aRet = mxTransfer->getTransferData(rFlavor);
1461  }
1462  }
1463  }
1464  catch( const css::uno::Exception& )
1465  {
1466  }
1467 
1468  return aRet;
1469 }
1470 
1471 
1473 {
1474  DataFlavor aFlavor;
1475  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1476 }
1477 
1478 
1479 bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr )
1480 {
1481  Any aAny = GetAny(rFlavor, OUString());
1482  bool bRet = false;
1483 
1484  if( aAny.hasValue() )
1485  {
1486  OUString aOUString;
1487  Sequence< sal_Int8 > aSeq;
1488 
1489  if( aAny >>= aOUString )
1490  {
1491  rStr = aOUString;
1492  bRet = true;
1493  }
1494  else if( aAny >>= aSeq )
1495  {
1496 
1497  const sal_Char* pChars = reinterpret_cast< const sal_Char* >( aSeq.getConstArray() );
1498  sal_Int32 nLen = aSeq.getLength();
1499 
1500  //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1501  //DVO 2002-05-27: strip _all_ trailing zeros
1502  while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1503  --nLen;
1504 
1505  rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1506  bRet = true;
1507  }
1508  }
1509 
1510  return bRet;
1511 }
1512 
1513 
1515 {
1516  if(SotClipboardFormatId::BITMAP == nFormat)
1517  {
1518  // try to get PNG first
1519  DataFlavor aFlavor;
1520 
1521  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1522  {
1523  if(GetBitmapEx(aFlavor, rBmpEx))
1524  {
1525  return true;
1526  }
1527  }
1528  }
1529 
1530  DataFlavor aFlavor;
1531  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1532 }
1533 
1534 
1535 bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx )
1536 {
1538  DataFlavor aSubstFlavor;
1539  bool bRet(GetSotStorageStream(rFlavor, xStm));
1540  bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1541  bool bSuppressJPEG(false);
1542 
1543  if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1544  {
1545  // when no direct success, try if PNG is available
1546  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1547  bSuppressJPEG = bRet;
1548  }
1549 
1550  if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1551  {
1552  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1553  bSuppressPNG = bRet;
1554  }
1555 
1556  if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1557  {
1558  // when no direct success, try if BMP is available
1559  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1560  bSuppressPNG = bRet;
1561  bSuppressJPEG = bRet;
1562  }
1563 
1564  if(bRet)
1565  {
1566  if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1567  {
1568  // it's a PNG, import to BitmapEx
1569  vcl::PNGReader aPNGReader(*xStm);
1570 
1571  rBmpEx = aPNGReader.Read();
1572  }
1573  else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1574  {
1575  // it's a JPEG, import to BitmapEx
1577  Graphic aGraphic;
1578  if (rFilter.ImportGraphic(aGraphic, "", *xStm) == ERRCODE_NONE)
1579  rBmpEx = aGraphic.GetBitmapEx();
1580  }
1581 
1582  if(rBmpEx.IsEmpty())
1583  {
1584  Bitmap aBitmap;
1585  AlphaMask aMask;
1586 
1587  // explicitly use Bitmap::Read with bFileHeader = sal_True
1588  // #i124085# keep DIBV5 for read from clipboard, but should not happen
1589  ReadDIBV5(aBitmap, aMask, *xStm);
1590 
1591  if(aMask.GetBitmap().IsEmpty())
1592  {
1593  rBmpEx = aBitmap;
1594  }
1595  else
1596  {
1597  rBmpEx = BitmapEx(aBitmap, aMask);
1598  }
1599  }
1600 
1601  bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1602 
1603  /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1604  problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1605  and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1606  Due to this reason the following code assumes that bitmaps with a logical size
1607  greater than 50 cm aren't having the correct mapmode set.
1608 
1609  The following code should be removed if DDBs and DIBs are supported via clipboard
1610  properly.
1611  */
1612  if(bRet)
1613  {
1614  const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1615 
1616  if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1617  {
1618  const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1619 
1620  // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1621  // the described 50 cm (which is 50000 100th mm)
1622  if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1623  {
1624  rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1625 
1626  // #i122388# also adapt size by applying the mew MapMode
1627  const Size aNewSize(OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
1628  rBmpEx.SetPrefSize(aNewSize);
1629  }
1630  }
1631  }
1632  }
1633 
1634  return bRet;
1635 }
1636 
1637 
1639 {
1640  DataFlavor aFlavor;
1641  return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1642  GetGDIMetaFile(aFlavor, rMtf) &&
1643  (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1644 }
1645 
1646 
1647 bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf )
1648 {
1650  DataFlavor aSubstFlavor;
1651  bool bRet = false;
1652 
1653  if( GetSotStorageStream( rFlavor, xStm ) )
1654  {
1655  ReadGDIMetaFile( *xStm, rMtf );
1656  bRet = ( xStm->GetError() == ERRCODE_NONE );
1657  }
1658 
1659  if( !bRet &&
1660  HasFormat( SotClipboardFormatId::EMF ) &&
1661  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1662  GetSotStorageStream( aSubstFlavor, xStm ) )
1663  {
1664  Graphic aGraphic;
1665 
1666  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1667  {
1668  rMtf = aGraphic.GetGDIMetaFile();
1669  bRet = true;
1670  }
1671  }
1672 
1673  if( !bRet &&
1674  HasFormat( SotClipboardFormatId::WMF ) &&
1675  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1676  GetSotStorageStream( aSubstFlavor, xStm ) )
1677  {
1678  Graphic aGraphic;
1679 
1680  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1681  {
1682  rMtf = aGraphic.GetGDIMetaFile();
1683  bRet = true;
1684  }
1685  }
1686 
1687  return bRet;
1688 }
1689 
1690 
1692 {
1693  if(SotClipboardFormatId::BITMAP == nFormat)
1694  {
1695  // try to get PNG first
1696  DataFlavor aFlavor;
1697 
1698  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1699  {
1700  if(GetGraphic(aFlavor, rGraphic))
1701  {
1702  return true;
1703  }
1704  }
1705  }
1706 
1707  DataFlavor aFlavor;
1708  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1709 }
1710 
1711 
1712 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic )
1713 {
1714  DataFlavor aFlavor;
1715  bool bRet = false;
1716 
1717  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1718  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1719  {
1720  // try to get PNG first
1721  BitmapEx aBmpEx;
1722 
1723  bRet = GetBitmapEx( aFlavor, aBmpEx );
1724  if( bRet )
1725  rGraphic = aBmpEx;
1726  }
1727  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1728  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1729  {
1730  Graphic aGraphic;
1732  if (GetSotStorageStream(rFlavor, xStm))
1733  {
1734  if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1735  {
1736  rGraphic = aGraphic;
1737  bRet = true;
1738  }
1739  }
1740  }
1741  else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1742  {
1743  BitmapEx aBitmapEx;
1744 
1745  bRet = GetBitmapEx(aFlavor, aBitmapEx);
1746  if (bRet)
1747  rGraphic = aBitmapEx;
1748  }
1749  else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1750  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1751  {
1752  BitmapEx aBmpEx;
1753 
1754  bRet = GetBitmapEx( aFlavor, aBmpEx );
1755  if( bRet )
1756  rGraphic = aBmpEx;
1757  }
1758  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1759  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1760  {
1761  GDIMetaFile aMtf;
1762 
1763  bRet = GetGDIMetaFile( aFlavor, aMtf );
1764  if( bRet )
1765  rGraphic = aMtf;
1766  }
1767  else
1768  {
1770 
1771  if( GetSotStorageStream( rFlavor, xStm ) )
1772  {
1773  ReadGraphic( *xStm, rGraphic );
1774  bRet = ( xStm->GetError() == ERRCODE_NONE );
1775  }
1776  }
1777 
1778  return bRet;
1779 }
1780 
1781 
1783 {
1784  DataFlavor aFlavor;
1785  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1786 }
1787 
1788 
1789 bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap )
1790 {
1792  bool bRet = GetSotStorageStream( rFlavor, xStm );
1793 
1794  if( bRet )
1795  {
1796  rIMap.Read( *xStm );
1797  bRet = ( xStm->GetError() == ERRCODE_NONE );
1798  }
1799 
1800  return bRet;
1801 }
1802 
1803 
1805 {
1806  DataFlavor aFlavor;
1807  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1808 }
1809 
1810 
1812 {
1813  rDesc = *mxObjDesc;
1814  return true;
1815 }
1816 
1817 
1819 {
1820  DataFlavor aFlavor;
1821  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1822 }
1823 
1824 
1825 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk )
1826 {
1827  bool bRet = false;
1828  if( HasFormat( rFlavor ))
1829  {
1830  const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1831  switch( nFormat )
1832  {
1833  case SotClipboardFormatId::SOLK:
1834  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1835  {
1836  OUString aString;
1837  if( GetString( rFlavor, aString ) )
1838  {
1839  if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1840  {
1841  rBmk = INetBookmark( aString, aString );
1842  bRet = true;
1843  }
1844  else
1845  {
1846  OUString aURL, aDesc;
1847  sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1848 
1849  if( !nLen && aString[ 0 ] != '0' )
1850  {
1851  SAL_INFO( "svtools", "SOLK: 1. len=0" );
1852  }
1853  if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1854  {
1855  SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1856  }
1857  aURL = aString.copy( nStart + 1, nLen );
1858 
1859  aString = aString.replaceAt( 0, nStart + 1 + nLen, "" );
1860  nStart = aString.indexOf( '@' );
1861  nLen = aString.toInt32();
1862 
1863  if( !nLen && aString[ 0 ] != '0' )
1864  {
1865  SAL_INFO( "svtools", "SOLK: 2. len=0" );
1866  }
1867  if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1868  {
1869  SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1870  }
1871  aDesc = aString.copy( nStart+1, nLen );
1872 
1873  rBmk = INetBookmark( aURL, aDesc );
1874  bRet = true;
1875  }
1876  }
1877  }
1878  break;
1879 
1880  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1881  {
1882  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1883 
1884  if (2048 == aSeq.getLength())
1885  {
1886  const sal_Char* p1 = reinterpret_cast< const sal_Char* >( aSeq.getConstArray() );
1887  const sal_Char* p2 = reinterpret_cast< const sal_Char* >( aSeq.getConstArray() ) + 1024;
1888  rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1889  OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1890  bRet = true;
1891  }
1892  }
1893  break;
1894 
1895 #ifdef _WIN32
1896  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1897  {
1898  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1899 
1900  if (aSeq.getLength())
1901  {
1902  FILEGROUPDESCRIPTOR const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR const *>(aSeq.getConstArray());
1903 
1904  if( pFDesc->cItems )
1905  {
1906  OString aDesc( pFDesc->fgd[ 0 ].cFileName );
1907  rtl_TextEncoding eTextEncoding = osl_getThreadTextEncoding();
1908 
1909  if( ( aDesc.getLength() > 4 ) && aDesc.copy(aDesc.getLength() - 4).equalsIgnoreAsciiCase(".URL") )
1910  {
1911  std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( OStringToOUString(aDesc, eTextEncoding) ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1912  StreamMode::STD_READ ));
1913 
1914  if( !pStream || pStream->GetError() )
1915  {
1916  DataFlavor aFileContentFlavor;
1917 
1918  aSeq.realloc( 0 );
1919  pStream.reset();
1920 
1921  if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1922  {
1923  aSeq = GetSequence(aFileContentFlavor, OUString());
1924  if (aSeq.getLength())
1925  pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1926  }
1927  }
1928 
1929  if( pStream )
1930  {
1931  OString aLine;
1932  bool bSttFnd = false;
1933 
1934  while( pStream->ReadLine( aLine ) )
1935  {
1936  if (aLine.equalsIgnoreAsciiCase("[InternetShortcut]"))
1937  bSttFnd = true;
1938  else if (bSttFnd && aLine.copy(0, 4).equalsIgnoreAsciiCase("URL="))
1939  {
1940  rBmk = INetBookmark( OStringToOUString(aLine.copy(4), eTextEncoding),
1941  OStringToOUString(aDesc.copy(0, aDesc.getLength() - 4), eTextEncoding) );
1942  bRet = true;
1943  break;
1944  }
1945  }
1946  }
1947  }
1948  }
1949  }
1950  }
1951  break;
1952 #endif
1953  default: break;
1954  }
1955  }
1956  return bRet;
1957 }
1958 
1959 
1961  INetImage& rINtImg )
1962 {
1963  DataFlavor aFlavor;
1964  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1965 }
1966 
1967 
1969  const css::datatransfer::DataFlavor& rFlavor,
1970  INetImage& rINtImg )
1971 {
1973  bool bRet = GetSotStorageStream( rFlavor, xStm );
1974 
1975  if( bRet )
1976  bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
1977  return bRet;
1978 }
1979 
1980 
1982  FileList& rFileList )
1983 {
1984  DataFlavor aFlavor;
1985  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
1986 }
1987 
1988 
1990 {
1992  bool bRet = false;
1993 
1994  for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
1995  {
1996  if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
1997  {
1998  const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
1999 
2000  if( GetSotStorageStream( aFlavor, xStm ) )
2001  {
2002  if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2003  {
2004  OString aDiskString;
2005 
2006  while( xStm->ReadLine( aDiskString ) )
2007  if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2008  rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2009 
2010  bRet = true;
2011  }
2012  else
2013  bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2014  }
2015  }
2016  }
2017 
2018  return bRet;
2019 }
2020 
2021 
2023 {
2024  DataFlavor aFlavor;
2025  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2026  return Sequence<sal_Int8>();
2027 
2028  return GetSequence(aFlavor, rDestDoc);
2029 }
2030 
2031 Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc )
2032 {
2033  const Any aAny = GetAny(rFlavor, rDestDoc);
2034  Sequence<sal_Int8> aSeq;
2035  if (aAny.hasValue())
2036  aAny >>= aSeq;
2037 
2038  return aSeq;
2039 }
2040 
2041 
2043 {
2044  DataFlavor aFlavor;
2045  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2046 }
2047 
2048 
2049 bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotStorageStream>& rxStream )
2050 {
2051  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2052 
2053  if (aSeq.hasElements())
2054  {
2055  rxStream = new SotStorageStream( "" );
2056  rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2057  rxStream->Seek( 0 );
2058  }
2059 
2060  return aSeq.hasElements();
2061 }
2062 
2064 {
2065  DataFlavor aFlavor;
2066  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2067  return Reference<XInputStream>();
2068 
2069  return GetInputStream(aFlavor, rDestDoc);
2070 }
2071 
2072 Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc )
2073 {
2074  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2075 
2076  if (!aSeq.hasElements())
2077  return Reference<XInputStream>();
2078 
2080  return xStream;
2081 }
2082 
2083 void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2084 {
2085  mxTransfer = _rxNewContent;
2086  InitFormats();
2087 }
2088 
2090 {
2091  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2092 
2094 
2095  mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2096 
2097  return mxImpl->mxClipboardListener->isListening();
2098 }
2099 
2101 {
2102  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2103 
2104  if (mxImpl->mxClipboardListener.is())
2105  {
2106  mxImpl->mxClipboardListener->dispose();
2107  mxImpl->mxClipboardListener.clear();
2108  }
2109 }
2110 
2111 
2113 {
2114  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2115 
2116  Reference< XClipboard > xClipboard;
2118 
2119  if( pWindow )
2120  xClipboard = pWindow->GetClipboard();
2121 
2122  if( xClipboard.is() )
2123  {
2124  try
2125  {
2126  Reference< XTransferable > xTransferable( xClipboard->getContents() );
2127 
2128  if( xTransferable.is() )
2129  {
2130  aRet = TransferableDataHelper( xTransferable );
2131  // also copy the clipboard
2132  aRet.mxClipboard = xClipboard;
2133  }
2134  }
2135  catch( const css::uno::Exception& )
2136  {
2137  }
2138  }
2139 
2140  return aRet;
2141 }
2142 
2143 
2145 {
2146  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2147 
2148  Reference< XClipboard > xSelection;
2150 
2151  if( pWindow )
2152  xSelection = pWindow->GetPrimarySelection();
2153 
2154  if( xSelection.is() )
2155  {
2156  SolarMutexReleaser aReleaser;
2157 
2158  try
2159  {
2160  Reference< XTransferable > xTransferable( xSelection->getContents() );
2161 
2162  if( xTransferable.is() )
2163  {
2164  aRet = TransferableDataHelper( xTransferable );
2165  aRet.mxClipboard = xSelection;
2166  }
2167  }
2168  catch( const css::uno::Exception& )
2169  {
2170  }
2171  }
2172 
2173  return aRet;
2174 }
2175 
2176 
2177 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2178  const css::datatransfer::DataFlavor& rRequestFlavor )
2179 {
2181  bool bRet = false;
2182 
2183  try
2184  {
2185  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2186 
2187  Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2188  Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2189 
2190  if( xRequestType1.is() && xRequestType2.is() )
2191  {
2192  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2193  {
2194  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2195  {
2196  // special handling for text/plain media types
2197  const OUString aCharsetString( "charset" );
2198 
2199  if( !xRequestType2->hasParameter( aCharsetString ) ||
2200  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2201  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2202  {
2203  bRet = true;
2204  }
2205  }
2206  else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2207  {
2208  // special handling for application/x-openoffice media types
2209  const OUString aFormatString( "windows_formatname" );
2210 
2211  if( xRequestType1->hasParameter( aFormatString ) &&
2212  xRequestType2->hasParameter( aFormatString ) &&
2213  xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2214  {
2215  bRet = true;
2216  }
2217  }
2218  else
2219  bRet = true;
2220  }
2221  }
2222  }
2223  catch( const css::uno::Exception& )
2224  {
2225  bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2226  }
2227 
2228  return bRet;
2229 }
2230 
2231 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic)
Definition: transfer.cxx:1691
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:862
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
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:1413
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:1674
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:3432
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:2083
::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:760
virtual void SAL_CALL disposing(const EventObject &Source) override
Definition: transfer.cxx:1109
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:906
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1368
virtual void DragFinished(sal_Int8 nDropAction)
Definition: transfer.cxx:913
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk)
Definition: transfer.cxx:1818
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:402
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1343
sal_uInt64 SeekRel(sal_Int64 nPos)
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:773
bool SetObject(void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:876
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
TransferableClipboardNotifier(const Reference< XClipboard > &_rxClipboard, TransferableDataHelper &_rListener,::osl::Mutex &_rMutex)
Definition: transfer.cxx:1079
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:1433
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetPrimarySelection()
Definition: window.cxx:3441
char sal_Char
SvStream & WriteUniOrByteString(const OUString &rStr, rtl_TextEncoding eDestCharSet)
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2112
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:1171
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
TransferableDataHelper * mpListener
Definition: transfer.cxx:1059
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:2177
Bitmap GetBitmap(const Color *pTransReplaceColor=nullptr) const
Definition: bitmapex.cxx:236
void dispose()
makes the instance non-functional
Definition: transfer.cxx:1116
bool SetGraphic(const Graphic &rGraphic)
Definition: transfer.cxx:732
bool IsEmpty() const
Definition: bitmapex.cxx:203
bool GetINetImage(SotClipboardFormatId nFormat, INetImage &rINtImg)
Definition: transfer.cxx:1960
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:1375
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:1389
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:247
bool GetString(SotClipboardFormatId nFormat, OUString &rStr)
Definition: transfer.cxx:1472
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: transfer.cxx:1049
SvStream & ReadFileList(SvStream &rIStm, FileList &rFileList)
virtual void SAL_CALL changedContents(const clipboard::ClipboardEvent &event) override
Definition: transfer.cxx:1096
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:1362
unsigned char sal_Bool
bool Write(SvStream &rStream)
Definition: pngwrite.cxx:708
Reference< XClipboardNotifier > mxNotifier
Definition: transfer.cxx:1058
const OUString & GetDescription() const
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:923
bool IsMouseCaptured() const
Definition: mouse.cxx:469
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:994
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1830
static void ClearSelection(vcl::Window *pWindow)
Definition: transfer.cxx:1035
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
std::shared_ptr< PresenterClockTimer::Listener > mpListener
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:2042
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap)
Definition: transfer.cxx:1782
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
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:1638
virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
Definition: transfer.cxx:409
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:748
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:1224
#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:2621
#define SAL_INFO(area, stream)
virtual void ObjectReleased()
Definition: transfer.cxx:918
SvStream & WriteSvGlobalName(SvStream &rOStr, const SvGlobalName &rObj)
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp)
Definition: transfer.cxx:1514
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2063
void SetPrefSize(const Size &rPrefSize)
Definition: bitmapex.hxx:87
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList)
Definition: transfer.cxx:1981
bool IsEmpty() const
Definition: bitmap.hxx:551
sal_uInt64 Tell() const
size_t GetActionSize() const
Definition: gdimtf.cxx:153
Reference< XComponentContext > getProcessComponentContext()
const OUString & GetURL() const
css::uno::Reference< css::datatransfer::XTransferable > mxTransfer
Definition: transfer.hxx:279
css::uno::Any maAny
Definition: transfer.hxx:166
bool isListening() const
determines whether we're currently listening
Definition: transfer.cxx:1072
static GraphicFilter & GetGraphicFilter()
bool GetTransferableObjectDescriptor(SotClipboardFormatId nFormat, TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:1804
void CopyToSelection(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:280
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:2022
bool MakeId(const OUString &rId)
static TransferableDataHelper CreateFromSelection(vcl::Window *pWindow)
Definition: transfer.cxx:2144
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:285
rtl::Reference< TransferableClipboardNotifier > mxClipboardListener
Definition: transfer.cxx:1132
long Y() const
bool SetGDIMetaFile(const GDIMetaFile &rMtf)
Definition: transfer.cxx:718
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