Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/ios/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 17 kB image not shown  

Quelle  DataFlavorMapping.cxx   Sprache: C

 
/* -*- 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_UTF8PLAINTEXT = (__bridge NSString*)kUTTypeUTF8PlainText;
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;

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)\"";
struct FlavorMap
{
    NSString* SystemFlavor;
    const char* OOoFlavor;
    const char* HumanPresentableName;
    bool DataTypeOUString; // sequence<byte> otherwise
};

// The SystemFlavor member is nil for the cases where there is no predefined pasteboard type UTI and
// we use the internal MIME type (media type) also on the pasteboard. That is OK, there dos not seem
// to be a requirement that the types are well-formed UTIs even on iOS. For an introduction to UTIs,
// see for instance
// https://alastairs-place.net/blog/2012/06/06/utis-are-better-than-you-think-and-heres-why/
//
// In those cases the MIME type might actually have parameters appended, separated by semicolons.
// At least the FLAVOR_SODX one must have at least a typename="%PRODUCTNAME %PRODUCTVERSION
// Spreadsheet" parameter (with macros expanded and translated) for LO to recognise it. See
// lcl_TestFormat() in sc/source/ui/view/cellsh.cxx.

static const FlavorMap flavorMap[]
    = { { PBTYPE_UTF8PLAINTEXT, "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""JPEG"false },
        { PBTYPE_HTML, "text/html""Plain HTML"false },
        { PBTYPE_PDF, "application/pdf""PDF File"false },
        { nil, FLAVOR_SESX, "Star Embed Source (XML)"false },
        { nil, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)"false },
        { nil, FLAVOR_LSX, "Star Link Source (XML)"false },
        { nil, FLAVOR_EOX, "Star Embedded Object (XML)"false },
        { nil, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation"false },
        { nil, FLAVOR_GDIMF, "GDIMetaFile"false },
        { nil, FLAVOR_SODX, "Star Object Descriptor (XML)"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 Utf8DataProvider : public DataProviderBaseImpl
{
public:
    Utf8DataProvider(const Any& data);
    Utf8DataProvider(NSData* data);

    NSData* getSystemData() override;
    Any getOOoData() override;
};

Utf8DataProvider::Utf8DataProvider(const Any& data)
    : DataProviderBaseImpl(data)
{
}

Utf8DataProvider::Utf8DataProvider(NSData* data)
    : DataProviderBaseImpl(data)
{
}

NSData* Utf8DataProvider::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 Utf8DataProvider::getOOoData()
{
    Any oOOData;

    if (mSystemData)
    {
        oOOData <<= OUString(static_cast<const 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 ((flavorMap[i].SystemFlavor == nil
             && ([systemDataFlavor
                     isEqualToString:[NSString stringWithUTF8String:flavorMap[i].OOoFlavor]]
                 ||
                 [systemDataFlavor hasPrefix:[[NSString stringWithUTF8String:flavorMap[i].OOoFlavor]
                                                 stringByAppendingString:@";"]]))
            || (flavorMap[i].SystemFlavor != nil &&
                [systemDataFlavor
                    isEqualToString:const_cast<NSString*>(flavorMap[i].SystemFlavor)]))
        {
            if (flavorMap[i].SystemFlavor == nil)
                oOOFlavor.MimeType = NSStringToOUString(systemDataFlavor);
            else
                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)))
        {
            if (flavorMap[i].SystemFlavor != nil)
                sysFlavor = flavorMap[i].SystemFlavor;
            else
                sysFlavor = OUStringToNSString(oOOFlavor.MimeType);

            // Flavor set, then break
            if (sysFlavor != nullptr)
                break;
        }
    }

    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 ~SwContentIndexReg, 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())
        {
            // tdf#161461 stop crashing by retaining NSString
            // OUStringToNSString() returns an autoreleased NSString so it
            // needs to be retained for the life of maOfficeOnlyTypes.
            sysFlavor = maOfficeOnlyTypes[oOOFlavor.MimeType] =
                [OUStringToNSString(oOOFlavor.MimeType) retain];
        }
        else
        {
            sysFlavor = it->second;
        }
    }

    return sysFlavor;
}

NSString* DataFlavorMapper::openOfficeImageToSystemFlavor()
{
    if ([[UIPasteboard generalPasteboard] containsPasteboardTypes:@[ PBTYPE_PNG ]])
        return PBTYPE_PNG;
    else if ([[UIPasteboard generalPasteboard] containsPasteboardTypes:@[ PBTYPE_JPEG ]])
        return PBTYPE_JPEG;
    else if ([[UIPasteboard generalPasteboard] 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()))
        {
            dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
        }
        else // Must be OUString type
        {
            SAL_WARN_IF(!isOUStringType(data.getValueType()), "vcl""must be OUString type");
            dp = DataProviderPtr_t(new Utf8DataProvider(data));
        }
    }
    catch (const UnsupportedFlavorException& e)
    {
        SAL_WARN("vcl.ios.clipboard",
                 "DataFlavorMapper::getDataProvider(): Exception: " << e.Message);
        // 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 (systemData == nil)
        return dp;

    if ([systemFlavor caseInsensitiveCompare:PBTYPE_UTF8PLAINTEXT] == NSOrderedSame)
    {
        dp = DataProviderPtr_t(new Utf8DataProvider(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 (const IllegalArgumentException& e)
    {
        SAL_WARN("vcl.ios.clipboard",
                 "DataFlavorMapper::isValidMimeContentType(): Exception: " << e.Message);
        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];
            }
        }
    }

    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.getArray()[flavors.getLength() - 1] = oOOFlavor;
            SAL_INFO("vcl.ios.clipboard",
                     "Mapped " << [sysFormat UTF8String] << " to " << oOOFlavor.MimeType);
        }
        else
        {
            SAL_INFO("vcl.ios.clipboard",
                     "Was not able to map " << [sysFormat UTF8String] << " to an internal flavour");
        }
    }

    return flavors;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.