2019-05-24 01:51:00 +03:00
/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2.0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
# include <sal/config.h>
# include "DataFlavorMapping.hxx"
# include "HtmlFmtFlt.hxx"
# include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
# include <com/sun/star/datatransfer/XMimeContentType.hpp>
# include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
# include <com/sun/star/lang/IllegalArgumentException.hpp>
# include <com/sun/star/uno/Sequence.hxx>
# include <comphelper/processfactory.hxx>
# include <rtl/ustring.hxx>
# include <sal/log.hxx>
# include <osl/endian.h>
# include <cassert>
# include <cstring>
# include <premac.h>
# include <UIKit/UIKit.h>
# include <MobileCoreServices/MobileCoreServices.h>
# include <postmac.h>
using namespace css : : datatransfer ;
using namespace css : : uno ;
using namespace css : : lang ;
using namespace cppu ;
namespace
{
/* Determine whether or not a DataFlavor is valid.
*/
bool isValidFlavor ( const DataFlavor & aFlavor )
{
size_t len = aFlavor . MimeType . getLength ( ) ;
Type dtype = aFlavor . DataType ;
return ( ( len > 0 )
& & ( ( dtype = = cppu : : UnoType < Sequence < sal_Int8 > > : : get ( ) )
| | ( dtype = = cppu : : UnoType < OUString > : : get ( ) ) ) ) ;
}
OUString NSStringToOUString ( const NSString * cfString )
{
assert ( cfString & & " Invalid parameter " ) ;
const char * utf8Str = [ cfString UTF8String ] ;
unsigned int len = rtl_str_getLength ( utf8Str ) ;
return OUString ( utf8Str , len , RTL_TEXTENCODING_UTF8 ) ;
}
NSString * OUStringToNSString ( const OUString & ustring )
{
OString utf8Str = OUStringToOString ( ustring , RTL_TEXTENCODING_UTF8 ) ;
return [ NSString stringWithCString : utf8Str . getStr ( ) encoding : NSUTF8StringEncoding ] ;
}
NSString * PBTYPE_PLAINTEXT = ( __bridge NSString * ) kUTTypePlainText ;
NSString * PBTYPE_RTF = ( __bridge NSString * ) kUTTypeRTF ;
NSString * PBTYPE_PNG = ( __bridge NSString * ) kUTTypePNG ;
NSString * PBTYPE_JPEG = ( __bridge NSString * ) kUTTypeJPEG ;
NSString * PBTYPE_HTML = ( __bridge NSString * ) kUTTypeHTML ;
NSString * PBTYPE_PDF = ( __bridge NSString * ) kUTTypePDF ;
NSString * PBTYPE_SESX
= @ " application/x-openoffice-embed-source-xml;windows_formatname= \" Star Embed Source (XML) \" " ;
NSString * PBTYPE_SLSDX = @ " application/ "
@ " x-openoffice-linksrcdescriptor-xml;windows_formatname= \" Star Link "
@ " Source Descriptor (XML) \" " ;
NSString * PBTYPE_LSX
= @ " application/x-openoffice-link-source-xml;windows_formatname= \" Star Link Source (XML) \" " ;
NSString * PBTYPE_EOX = @ " application/x-openoffice-embedded-obj-xml;windows_formatname= \" Star "
@ " Embedded Object (XML) \" " ;
NSString * PBTYPE_SVXB
= @ " application/x-openoffice-svbx;windows_formatname= \" SVXB (StarView Bitmap/Animation) \" " ;
NSString * PBTYPE_GDIMF = @ " application/x-openoffice-gdimetafile;windows_formatname= \" GDIMetaFile \" " ;
NSString * PBTYPE_SODX = @ " application/x-openoffice-objectdescriptor-xml;windows_formatname= \" Star "
@ " Object Descriptor (XML) \" " ;
NSString * PBTYPE_DUMMY_INTERNAL = @ " application/x-openoffice-internal " ;
const char * FLAVOR_SESX
= " application/x-openoffice-embed-source-xml;windows_formatname= \" Star Embed Source (XML) \" " ;
const char * FLAVOR_SLSDX = " application/ "
" x-openoffice-linksrcdescriptor-xml;windows_formatname= \" Star Link "
" Source Descriptor (XML) \" " ;
const char * FLAVOR_LSX
= " application/x-openoffice-link-source-xml;windows_formatname= \" Star Link Source (XML) \" " ;
const char * FLAVOR_EOX
= " application/x-openoffice-embedded-obj-xml;windows_formatname= \" Star Embedded Object (XML) \" " ;
const char * FLAVOR_SVXB
= " application/x-openoffice-svbx;windows_formatname= \" SVXB (StarView Bitmap/Animation) \" " ;
const char * FLAVOR_GDIMF
= " application/x-openoffice-gdimetafile;windows_formatname= \" GDIMetaFile \" " ;
const char * FLAVOR_SODX = " application/x-openoffice-objectdescriptor-xml;windows_formatname= \" Star "
" Object Descriptor (XML) \" " ;
const char * FLAVOR_DUMMY_INTERNAL = " application/x-openoffice-internal " ;
struct FlavorMap
{
NSString * SystemFlavor ;
const char * OOoFlavor ;
const char * HumanPresentableName ;
bool DataTypeOUString ; // sequence<byte> otherwise
} ;
static const FlavorMap flavorMap [ ]
= { { PBTYPE_PLAINTEXT , " text/plain;charset=utf-16 " , " Unicode Text (UTF-16) " , true } ,
{ PBTYPE_RTF , " text/rtf " , " Rich Text Format " , false } ,
{ PBTYPE_PNG , " image/png " , " Portable Network Graphics " , false } ,
{ PBTYPE_JPEG , " image/jpeg " , " Portable Network Graphics " , false } ,
// Nope, sorry. See comment in openOfficeToSystemFlavor() below.
// { PBTYPE_HTML, "text/html", "Plain HTML", false },
{ PBTYPE_PDF , " application/pdf " , " PDF File " , false } ,
{ PBTYPE_SESX , FLAVOR_SESX , " Star Embed Source (XML) " , false } ,
{ PBTYPE_SLSDX , FLAVOR_SLSDX , " Star Link Source Descriptor (XML) " , false } ,
{ PBTYPE_LSX , FLAVOR_LSX , " Star Link Source (XML) " , false } ,
{ PBTYPE_EOX , FLAVOR_EOX , " Star Embedded Object (XML) " , false } ,
{ PBTYPE_SVXB , FLAVOR_SVXB , " SVXB (StarView Bitmap/Animation " , false } ,
{ PBTYPE_GDIMF , FLAVOR_GDIMF , " GDIMetaFile " , false } ,
{ PBTYPE_SODX , FLAVOR_SODX , " Star Object Descriptor (XML) " , false } ,
{ PBTYPE_DUMMY_INTERNAL , FLAVOR_DUMMY_INTERNAL , " internal data " , false } } ;
# define SIZE_FLAVOR_MAP (sizeof(flavorMap) / sizeof(FlavorMap))
inline bool isByteSequenceType ( const Type & theType )
{
return ( theType = = cppu : : UnoType < Sequence < sal_Int8 > > : : get ( ) ) ;
}
inline bool isOUStringType ( const Type & theType )
{
return ( theType = = cppu : : UnoType < OUString > : : get ( ) ) ;
}
} // unnamed namespace
/* A base class for other data provider.
*/
class DataProviderBaseImpl : public DataProvider
{
public :
DataProviderBaseImpl ( const Any & data ) ;
DataProviderBaseImpl ( id data ) ;
virtual ~ DataProviderBaseImpl ( ) override ;
protected :
Any mData ;
//NSData* mSystemData;
id mSystemData ;
} ;
DataProviderBaseImpl : : DataProviderBaseImpl ( const Any & data )
: mData ( data )
, mSystemData ( nil )
{
}
DataProviderBaseImpl : : DataProviderBaseImpl ( id data )
: mSystemData ( data )
{
[ mSystemData retain ] ;
}
DataProviderBaseImpl : : ~ DataProviderBaseImpl ( )
{
if ( mSystemData )
{
[ mSystemData release ] ;
}
}
class UniDataProvider : public DataProviderBaseImpl
{
public :
UniDataProvider ( const Any & data ) ;
UniDataProvider ( NSData * data ) ;
NSData * getSystemData ( ) override ;
Any getOOoData ( ) override ;
} ;
UniDataProvider : : UniDataProvider ( const Any & data )
: DataProviderBaseImpl ( data )
{
}
UniDataProvider : : UniDataProvider ( NSData * data )
: DataProviderBaseImpl ( data )
{
}
NSData * UniDataProvider : : getSystemData ( )
{
OUString ustr ;
mData > > = ustr ;
OString strUtf8 ;
ustr . convertToString ( & strUtf8 , RTL_TEXTENCODING_UTF8 , OUSTRING_TO_OSTRING_CVTFLAGS ) ;
return [ NSData dataWithBytes : strUtf8 . getStr ( ) length : strUtf8 . getLength ( ) ] ;
}
Any UniDataProvider : : getOOoData ( )
{
Any oOOData ;
if ( mSystemData )
{
oOOData < < = OUString ( static_cast < const sal_Char * > ( [ mSystemData bytes ] ) ,
[ mSystemData length ] , RTL_TEXTENCODING_UTF8 ) ;
}
else
{
oOOData = mData ;
}
return oOOData ;
}
class ByteSequenceDataProvider : public DataProviderBaseImpl
{
public :
ByteSequenceDataProvider ( const Any & data ) ;
ByteSequenceDataProvider ( NSData * data ) ;
NSData * getSystemData ( ) override ;
Any getOOoData ( ) override ;
} ;
ByteSequenceDataProvider : : ByteSequenceDataProvider ( const Any & data )
: DataProviderBaseImpl ( data )
{
}
ByteSequenceDataProvider : : ByteSequenceDataProvider ( NSData * data )
: DataProviderBaseImpl ( data )
{
}
NSData * ByteSequenceDataProvider : : getSystemData ( )
{
Sequence < sal_Int8 > rawData ;
mData > > = rawData ;
return [ NSData dataWithBytes : rawData . getArray ( ) length : rawData . getLength ( ) ] ;
}
Any ByteSequenceDataProvider : : getOOoData ( )
{
Any oOOData ;
if ( mSystemData )
{
unsigned int flavorDataLength = [ mSystemData length ] ;
Sequence < sal_Int8 > byteSequence ;
byteSequence . realloc ( flavorDataLength ) ;
memcpy ( byteSequence . getArray ( ) , [ mSystemData bytes ] , flavorDataLength ) ;
oOOData < < = byteSequence ;
}
else
{
oOOData = mData ;
}
return oOOData ;
}
class HTMLFormatDataProvider : public DataProviderBaseImpl
{
public :
HTMLFormatDataProvider ( NSData * data ) ;
NSData * getSystemData ( ) override ;
Any getOOoData ( ) override ;
} ;
HTMLFormatDataProvider : : HTMLFormatDataProvider ( NSData * data )
: DataProviderBaseImpl ( data )
{
}
NSData * HTMLFormatDataProvider : : getSystemData ( )
{
Sequence < sal_Int8 > textHtmlData ;
mData > > = textHtmlData ;
Sequence < sal_Int8 > htmlFormatData = TextHtmlToHTMLFormat ( textHtmlData ) ;
return [ NSData dataWithBytes : htmlFormatData . getArray ( ) length : htmlFormatData . getLength ( ) ] ;
}
Any HTMLFormatDataProvider : : getOOoData ( )
{
Any oOOData ;
if ( mSystemData )
{
unsigned int flavorDataLength = [ mSystemData length ] ;
Sequence < sal_Int8 > unkHtmlData ;
unkHtmlData . realloc ( flavorDataLength ) ;
memcpy ( unkHtmlData . getArray ( ) , [ mSystemData bytes ] , flavorDataLength ) ;
Sequence < sal_Int8 > * pPlainHtml = & unkHtmlData ;
Sequence < sal_Int8 > plainHtml ;
if ( isHTMLFormat ( unkHtmlData ) )
{
plainHtml = HTMLFormatToTextHtml ( unkHtmlData ) ;
pPlainHtml = & plainHtml ;
}
oOOData < < = * pPlainHtml ;
}
else
{
oOOData = mData ;
}
return oOOData ;
}
DataFlavorMapper : : DataFlavorMapper ( )
{
Reference < XComponentContext > xContext = comphelper : : getProcessComponentContext ( ) ;
mrXMimeCntFactory = MimeContentTypeFactory : : create ( xContext ) ;
}
DataFlavorMapper : : ~ DataFlavorMapper ( )
{
// release potential NSStrings
for ( OfficeOnlyTypes : : iterator it = maOfficeOnlyTypes . begin ( ) ; it ! = maOfficeOnlyTypes . end ( ) ;
+ + it )
{
[ it - > second release ] ;
it - > second = nil ;
}
}
DataFlavor DataFlavorMapper : : systemToOpenOfficeFlavor ( const NSString * systemDataFlavor ) const
{
DataFlavor oOOFlavor ;
for ( size_t i = 0 ; i < SIZE_FLAVOR_MAP ; i + + )
{
if ( [ systemDataFlavor
caseInsensitiveCompare : const_cast < NSString * > ( flavorMap [ i ] . SystemFlavor ) ]
= = NSOrderedSame )
{
oOOFlavor . MimeType = OUString : : createFromAscii ( flavorMap [ i ] . OOoFlavor ) ;
oOOFlavor . HumanPresentableName
= OUString : : createFromAscii ( flavorMap [ i ] . HumanPresentableName ) ;
oOOFlavor . DataType = flavorMap [ i ] . DataTypeOUString
? cppu : : UnoType < OUString > : : get ( )
: cppu : : UnoType < Sequence < sal_Int8 > > : : get ( ) ;
return oOOFlavor ;
}
} // for
// look if this might be an internal type; if it comes in here it must have
// been through openOfficeToSystemFlavor before, so it should then be in the map
OUString aTryFlavor ( NSStringToOUString ( systemDataFlavor ) ) ;
if ( maOfficeOnlyTypes . find ( aTryFlavor ) ! = maOfficeOnlyTypes . end ( ) )
{
oOOFlavor . MimeType = aTryFlavor ;
oOOFlavor . HumanPresentableName . clear ( ) ;
oOOFlavor . DataType = cppu : : UnoType < Sequence < sal_Int8 > > : : get ( ) ;
}
return oOOFlavor ;
}
NSString * DataFlavorMapper : : openOfficeToSystemFlavor ( const DataFlavor & oOOFlavor ,
bool & rbInternal ) const
{
NSString * sysFlavor = nullptr ;
rbInternal = false ;
for ( size_t i = 0 ; i < SIZE_FLAVOR_MAP ; + + i )
{
if ( oOOFlavor . MimeType . startsWith ( OUString : : createFromAscii ( flavorMap [ i ] . OOoFlavor ) ) )
{
sysFlavor = flavorMap [ i ] . SystemFlavor ;
}
}
if ( ! sysFlavor )
{
// For some reason, if we allow text/html, we get an OSL_ENSURE failure in xmloff that
// apparently is a symptom of something being seriously wrong:
// xmloff/source/transform/OOo2Oasis.cxx:1925: duplicate doc handler
// Because is then followed a bit later by an assertion failure:
// Assertion failed: (!m_pFirst && !m_pLast && "There are still indices registered"), function ~SwIndexReg, file [...]/sw/source/core/bastyp/index.cxx, line 226
if ( oOOFlavor . MimeType = = " text/html " )
return nil ;
rbInternal = true ;
OfficeOnlyTypes : : const_iterator it = maOfficeOnlyTypes . find ( oOOFlavor . MimeType ) ;
if ( it = = maOfficeOnlyTypes . end ( ) )
sysFlavor = maOfficeOnlyTypes [ oOOFlavor . MimeType ]
= OUStringToNSString ( oOOFlavor . MimeType ) ;
else
sysFlavor = it - > second ;
}
return sysFlavor ;
}
NSString * DataFlavorMapper : : openOfficeImageToSystemFlavor ( UIPasteboard * pPasteboard )
{
if ( [ pPasteboard containsPasteboardTypes : @ [ PBTYPE_PNG ] ] )
return PBTYPE_PNG ;
else if ( [ pPasteboard containsPasteboardTypes : @ [ PBTYPE_JPEG ] ] )
return PBTYPE_JPEG ;
else if ( [ pPasteboard containsPasteboardTypes : @ [ PBTYPE_PDF ] ] )
return PBTYPE_PDF ;
return @ " " ;
}
DataProviderPtr_t
DataFlavorMapper : : getDataProvider ( const NSString * systemFlavor ,
Reference < XTransferable > const & rTransferable ) const
{
DataProviderPtr_t dp ;
try
{
DataFlavor oOOFlavor = systemToOpenOfficeFlavor ( systemFlavor ) ;
Any data = rTransferable - > getTransferData ( oOOFlavor ) ;
if ( isByteSequenceType ( data . getValueType ( ) ) )
{
2019-05-28 22:10:06 +03:00
dp = DataProviderPtr_t ( new ByteSequenceDataProvider ( data ) ) ;
2019-05-24 01:51:00 +03:00
}
else // Must be OUString type
{
SAL_WARN_IF ( ! isOUStringType ( data . getValueType ( ) ) , " vcl " , " must be OUString type " ) ;
dp = DataProviderPtr_t ( new UniDataProvider ( data ) ) ;
}
}
catch ( UnsupportedFlavorException & )
{
// Somebody violates the contract of the clipboard
// interface @see XTransferable
}
return dp ;
}
DataProviderPtr_t DataFlavorMapper : : getDataProvider ( const NSString * systemFlavor ,
NSData * systemData )
{
DataProviderPtr_t dp ;
if ( [ systemFlavor caseInsensitiveCompare : PBTYPE_PLAINTEXT ] = = NSOrderedSame )
{
dp = DataProviderPtr_t ( new UniDataProvider ( systemData ) ) ;
}
else if ( [ systemFlavor caseInsensitiveCompare : PBTYPE_HTML ] = = NSOrderedSame )
{
dp = DataProviderPtr_t ( new HTMLFormatDataProvider ( systemData ) ) ;
}
else
{
dp = DataProviderPtr_t ( new ByteSequenceDataProvider ( systemData ) ) ;
}
return dp ;
}
bool DataFlavorMapper : : isValidMimeContentType ( const OUString & contentType ) const
{
bool result = true ;
try
{
Reference < XMimeContentType > xCntType ( mrXMimeCntFactory - > createMimeContentType ( contentType ) ) ;
}
catch ( IllegalArgumentException & )
{
result = false ;
}
return result ;
}
NSArray * DataFlavorMapper : : flavorSequenceToTypesArray (
const css : : uno : : Sequence < css : : datatransfer : : DataFlavor > & flavors ) const
{
const sal_uInt32 nFlavors = flavors . getLength ( ) ;
NSMutableArray * array = [ [ NSMutableArray alloc ] initWithCapacity : 1 ] ;
bool bNeedDummyInternalFlavor ( false ) ;
for ( sal_uInt32 i = 0 ; i < nFlavors ; i + + )
{
if ( flavors [ i ] . MimeType . startsWith ( " image/bmp " ) )
{
[ array addObject : PBTYPE_PNG ] ;
}
else
{
const NSString * str = openOfficeToSystemFlavor ( flavors [ i ] , bNeedDummyInternalFlavor ) ;
if ( str ! = nil )
{
[ str retain ] ;
[ array addObject : str ] ;
}
}
}
// #i89462# #i90747#
// in case no system flavor was found to report
// report at least one so D&D between OOo targets works
if ( [ array count ] = = 0 | | bNeedDummyInternalFlavor )
{
[ array addObject : PBTYPE_DUMMY_INTERNAL ] ;
}
return [ array autorelease ] ;
}
css : : uno : : Sequence < css : : datatransfer : : DataFlavor >
DataFlavorMapper : : typesArrayToFlavorSequence ( NSArray * types ) const
{
int nFormats = [ types count ] ;
Sequence < DataFlavor > flavors ;
for ( int i = 0 ; i < nFormats ; i + + )
{
NSString * sysFormat = [ types objectAtIndex : i ] ;
DataFlavor oOOFlavor = systemToOpenOfficeFlavor ( sysFormat ) ;
if ( isValidFlavor ( oOOFlavor ) )
{
flavors . realloc ( flavors . getLength ( ) + 1 ) ;
flavors [ flavors . getLength ( ) - 1 ] = oOOFlavor ;
2019-05-29 11:36:50 +03:00
SAL_INFO ( " vcl.ios.clipboard " ,
" Mapped " < < [ sysFormat UTF8String ] < < " to " < < oOOFlavor . MimeType ) ;
2019-05-24 01:51:00 +03:00
}
}
return flavors ;
}
NSArray * DataFlavorMapper : : getAllSupportedPboardTypes ( )
{
NSMutableArray * array = [ [ NSMutableArray alloc ] initWithCapacity : SIZE_FLAVOR_MAP ] ;
for ( sal_uInt32 i = 0 ; i < SIZE_FLAVOR_MAP ; i + + )
{
[ array addObject : flavorMap [ i ] . SystemFlavor ] ;
}
return [ array autorelease ] ;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */