Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/desktop/source/lib/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 308 kB image not shown  

Quelle  init.cxx   Sprache: C

 
/* -*- Mode: C++; 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/.
 */


#include <sfx2/lokhelper.hxx>
#include <sal/types.h>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <config_buildconfig.h>
#include <config_cairo_rgba.h>
#include <config_features.h>
#include <editeng/unolingu.hxx>

#include <stdio.h>

#ifdef IOS
#include <sys/mman.h>
#include <sys/stat.h>
#include <unicode/udata.h>
#include <unicode/ucnv.h>
#include <premac.h>
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#include <postmac.h>
#endif

#undef HAVE_MALLOC_TRIM

#ifdef UNX
#  include <fcntl.h>
#endif
#ifdef LINUX
#if defined __GLIBC__
#  include <malloc.h>
#  define HAVE_MALLOC_TRIM
#endif
#endif

#ifdef ANDROID
#include <osl/detail/android-bootstrap.h>
#endif

#ifdef EMSCRIPTEN
#include <osl/detail/emscripten-bootstrap.h>
#endif

#include <algorithm>
#include <memory>
#include <iostream>
#include <string_view>

#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string.hpp>

#include <LibreOfficeKit/LibreOfficeKit.h>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>

#include <sal/log.hxx>
#include <utility>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/errinf.hxx>
#include <vcl/lok.hxx>
#include <o3tl/any.hxx>
#include <o3tl/unit_conversion.hxx>
#include <o3tl/string_view.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/thread.h>
#include <rtl/bootstrap.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/uri.hxx>
#include <svl/cryptosign.hxx>
#include <linguistic/misc.hxx>
#include <salhelper/timer.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <comphelper/random.hxx>
#include <comphelper/base64.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <comphelper/profilezone.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/threadpool.hxx>
#include <comphelper/types.hxx>
#include <comphelper/sequenceashashmap.hxx>

#include <com/sun/star/connection/XConnection.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/document/XTypeDetection.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/DispatchResultEvent.hpp>
#include <com/sun/star/frame/DispatchResultState.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/XDispatchResultListener.hpp>
#include <com/sun/star/frame/XSynchronousDispatch.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/util/thePathSettings.hpp>
#include <com/sun/star/util/PathSubstitution.hpp>
#include <com/sun/star/util/URLTransformer.hpp>
#include <com/sun/star/util/XFlushable.hpp>
#include <com/sun/star/configuration/theDefaultProvider.hpp>
#include <com/sun/star/configuration/Update.hpp>
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
#include <com/sun/star/datatransfer/XTransferable2.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/document/XRedlinesSupplier.hpp>
#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
#include <com/sun/star/bridge/BridgeFactory.hpp>
#include <com/sun/star/bridge/XBridgeFactory.hpp>
#include <com/sun/star/bridge/XBridge.hpp>
#include <com/sun/star/uno/XNamingService.hpp>

#include <com/sun/star/xml/crypto/SEInitializer.hpp>
#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
#include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
#include <com/sun/star/security/XCertificate.hpp>

#include <com/sun/star/linguistic2/DictionaryList.hpp>
#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
#include <com/sun/star/linguistic2/XSpellChecker.hpp>
#include <com/sun/star/linguistic2/XProofreader.hpp>
#include <com/sun/star/i18n/LocaleCalendar2.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>

#include <editeng/flstitem.hxx>
#ifdef IOS
#include <sfx2/app.hxx>
#endif
#include <sfx2/objsh.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/lokcomponenthelpers.hxx>
#include <sfx2/DocumentSigner.hxx>
#include <sfx2/sidebar/Sidebar.hxx>
#include <sfx2/lokunocmdlist.hxx>
#include <svl/numformat.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>
#include <svx/svdview.hxx>
#include <svx/svxids.hrc>
#include <svx/ucsubset.hxx>
#include <vcl/vclevent.hxx>
#include <vcl/GestureEventPan.hxx>
#include <vcl/svapp.hxx>
#include <unotools/resmgr.hxx>
#include <tools/fract.hxx>
#include <tools/json_writer.hxx>
#include <svtools/ctrltool.hxx>
#include <svtools/langtab.hxx>
#include <vcl/fontcharmap.hxx>
#ifdef IOS
#include <vcl/sysdata.hxx>
#endif
#include <vcl/virdev.hxx>
#include <vcl/ImageTree.hxx>
#include <vcl/ITiledRenderable.hxx>
#include <vcl/dialoghelper.hxx>
#ifdef _WIN32
#include <vcl/BitmapTools.hxx>
#endif
#include <unicode/uchar.h>
#include <unotools/securityoptions.hxx>
#include <unotools/confignode.hxx>
#include <unotools/syslocaleoptions.hxx>
#include <unotools/mediadescriptor.hxx>
#include <unotools/pathoptions.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/streamwrap.hxx>
#include <osl/module.hxx>
#include <comphelper/sequence.hxx>
#include <sfx2/sfxbasemodel.hxx>
#include <svl/undo.hxx>
#include <unotools/datetime.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <vcl/abstdlg.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <vcl/uitest/uiobject.hxx>
#include <vcl/jsdialog/executor.hxx>
#include <vcl/scheduler.hxx>

// Needed for getUndoManager()
#include <com/sun/star/document/XUndoManager.hpp>
#include <com/sun/star/document/XUndoManagerSupplier.hpp>
#include <com/sun/star/document/XLinkTargetSupplier.hpp>
#include <editeng/sizeitem.hxx>
#include <svx/rulritem.hxx>
#include <svx/pageitem.hxx>

#include <app.hxx>

#include "../app/cmdlineargs.hxx"
// We also need to hackily be able to start the main libreoffice thread:
#include "../app/sofficemain.h"
#include "../app/officeipcthread.hxx"
#include <lib/init.hxx>

#include "lokinteractionhandler.hxx"
#include "lokclipboard.hxx"
#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Impress.hxx>
#include <officecfg/Office/Linguistic.hxx>
#include <officecfg/Office/UI/ToolbarMode.hxx>
#include <unotools/optionsdlg.hxx>
#include <svl/ctloptions.hxx>
#include <svtools/colorcfg.hxx>
#include <svtools/miscopt.hxx>
#include <unotools/cmdoptions.hxx>
#include <unotools/lingucfg.hxx>
#include <unotools/moduleoptions.hxx>
#include <unotools/searchopt.hxx>
#include <unotools/useroptions.hxx>
#include <vcl/settings.hxx>

#include <officecfg/Setup.hxx>
#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
#include <svtools/acceleratorexecute.hxx>

#include <tools/hostfilter.hxx>

using namespace css;
using namespace vcl;
using namespace desktop;
using namespace utl;
using namespace bridge;
using namespace uno;
using namespace lang;

#ifdef UNX

static int urandom = -1;

extern "C" {
    int SAL_JNI_EXPORT lok_open_urandom()
    {
        return dup(urandom);
    }
};

#endif

using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageTool;


static LibLibreOffice_Impl *gImpl = nullptr;
static bool lok_preinit_2_called = false;
static bool gUseCompactFonts = false;
static std::weak_ptr< LibreOfficeKitClass > gOfficeClass;
static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass;

static void SetLastExceptionMsg(const OUString& s = OUString())
{
    SAL_WARN_IF(!s.isEmpty(), "lok""lok exception '" + s + "'");
    if (gImpl)
        gImpl->maLastExceptionMsg = s;
}

namespace {

struct ExtensionMap
{
    std::string_view extn;
    OUString filterName;
};

class TraceEventDumper : public AutoTimer
{
    static const int dumpTimeoutMS = 5000;

public:
    TraceEventDumper() : AutoTimer( "Trace Event dumper" )
    {
        SetTimeout(dumpTimeoutMS);
        Start();
    }

    virtual void Invoke() override
    {
        flushRecordings();
    }

    static void flushRecordings()
    {
        const css::uno::Sequence<OUString> aEvents =
            comphelper::TraceEvent::getRecordingAndClear();
        OStringBuffer aOutput;
        for (const auto &s : aEvents)
        {
            aOutput.append(OUStringToOString(s, RTL_TEXTENCODING_UTF8)
                + "\n");
        }
        if (aOutput.getLength() > 0)
        {
            OString aChunk = aOutput.makeStringAndClear();
            if (gImpl && gImpl->mpCallback)
                gImpl->mpCallback(LOK_CALLBACK_PROFILE_FRAME, aChunk.getStr(), gImpl->mpCallbackData);
        }
    }
};

TraceEventDumper *traceEventDumper = nullptr;

constexpr ExtensionMap aWriterExtensionMap[] =
{
    { "doc",   u"MS Word 97"_ustr },
    { "docm",  u"MS Word 2007 XML VBA"_ustr },
    { "docx",  u"Office Open XML Text"_ustr },
    { "fodt",  u"OpenDocument Text Flat XML"_ustr },
    { "html",  u"HTML (StarWriter)"_ustr },
    { "odt",   u"writer8"_ustr },
    { "ott",   u"writer8_template"_ustr },
    { "pdf",   u"writer_pdf_Export"_ustr },
    { "epub",  u"EPUB"_ustr },
    { "rtf",   u"Rich Text Format"_ustr },
    { "txt",   u"Text"_ustr },
    { "xhtml", u"XHTML Writer File"_ustr },
    { "png",   u"writer_png_Export"_ustr },
    { "xml",   u"writer_indexing_export"_ustr },
};

constexpr ExtensionMap aCalcExtensionMap[] =
{
    { "csv",   u"Text - txt - csv (StarCalc)"_ustr },
    { "fods",  u"OpenDocument Spreadsheet Flat XML"_ustr },
    { "html",  u"HTML (StarCalc)"_ustr },
    { "ods",   u"calc8"_ustr },
    { "ots",   u"calc8_template"_ustr },
    { "pdf",   u"calc_pdf_Export"_ustr },
    { "xhtml", u"XHTML Calc File"_ustr },
    { "xls",   u"MS Excel 97"_ustr },
    { "xlsm",  u"Calc MS Excel 2007 VBA XML"_ustr },
    { "xlsx",  u"Calc MS Excel 2007 XML"_ustr },
    { "png",   u"calc_png_Export"_ustr },
};

constexpr ExtensionMap aImpressExtensionMap[] =
{
    { "fodp",  u"OpenDocument Presentation Flat XML"_ustr },
    { "html",  u"impress_html_Export"_ustr },
    { "odg",   u"impress8_draw"_ustr },
    { "odp",   u"impress8"_ustr },
    { "otp",   u"impress8_template"_ustr },
    { "pdf",   u"impress_pdf_Export"_ustr },
    { "potm",  u"Impress MS PowerPoint 2007 XML Template"_ustr },
    { "pot",   u"MS PowerPoint 97 Vorlage"_ustr },
    { "pptm",  u"Impress MS PowerPoint 2007 XML VBA"_ustr },
    { "pptx",  u"Impress MS PowerPoint 2007 XML"_ustr },
    { "pps",   u"MS PowerPoint 97 Autoplay"_ustr },
    { "ppt",   u"MS PowerPoint 97"_ustr },
    { "svg",   u"impress_svg_Export"_ustr },
    { "xhtml", u"XHTML Impress File"_ustr },
    { "png",   u"impress_png_Export"_ustr },
    { "bmp",   u"impress_bmp_Export"_ustr },
    { "gif",   u"impress_gif_Export"_ustr },
    { "tif",   u"impress_tif_Export"_ustr },
    { "tiff",  u"impress_tif_Export"_ustr }, // tif and tiff are the same format: see https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types#tiff_tagged_image_file_format
};

constexpr ExtensionMap aDrawExtensionMap[] =
{
    { "fodg",  u"draw_ODG_FlatXML"_ustr },
    { "html",  u"draw_html_Export"_ustr },
    { "odg",   u"draw8"_ustr },
    { "pdf",   u"draw_pdf_Export"_ustr },
    { "svg",   u"draw_svg_Export"_ustr },
    { "xhtml", u"XHTML Draw File"_ustr },
    { "png",   u"draw_png_Export"_ustr },
};

OUString getUString(const char* pString)
{
    if (pString == nullptr)
        return OUString();

    return OStringToOUString(pString, RTL_TEXTENCODING_UTF8);
}

// Tolerate embedded \0s etc.
char *convertOString(const OString &rStr)
{
    char* pMemory = static_cast<char*>(malloc(rStr.getLength() + 1));
    assert(pMemory); // don't tolerate failed allocations.
    memcpy(pMemory, rStr.getStr(), rStr.getLength() + 1);
    return pMemory;
}

char *convertOUString(std::u16string_view aStr)
{
    return convertOString(OUStringToOString(aStr, RTL_TEXTENCODING_UTF8));
}

/// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
OUString getAbsoluteURL(const char* pURL)
{
    OUString aURL(getUString(pURL));
    if (aURL.isEmpty())
        return aURL;

    // convert relative paths to absolute ones
    OUString aWorkingDir;
    osl_getProcessWorkingDir(&aWorkingDir.pData);
    if (!aWorkingDir.endsWith("/"))
        aWorkingDir += "/";

    try
    {
        return rtl::Uri::convertRelToAbs(aWorkingDir, aURL);
    }
    catch (const rtl::MalformedUriException &)
    {
    }

    return OUString();
}

// unnamed namespace

std::vector<beans::PropertyValue> desktop::jsonToPropertyValuesVector(const char* pJSON)
{
    std::vector<beans::PropertyValue> aArguments;
    if (pJSON && pJSON[0] != '\0')
    {
        aArguments = comphelper::JsonToPropertyValues(pJSON);
    }
    return aArguments;
}

static void extractLinks(const uno::Reference< container::XNameAccess >& xLinks, bool subcontent, tools::JsonWriter& aJson)
{
    for (const OUString& aLink : xLinks->getElementNames())
    {
        uno::Any aAny;

        try
        {
            aAny = xLinks->getByName( aLink );
        }
        catch(const uno::Exception&)
        {
            // if the name of the target was invalid (like empty headings)
            // no object can be provided
            continue;
        }

        uno::Reference< beans::XPropertySet > xTarget;
        if( aAny >>= xTarget )
        {
            try
            {
                // get name to display
                aAny = xTarget->getPropertyValue(u"LinkDisplayName"_ustr);
                OUString aStrDisplayname;
                aAny >>= aStrDisplayname;

                if (subcontent)
                {
                    aJson.put(aStrDisplayname, aLink);
                }
                else
                {
                    uno::Reference<lang::XServiceInfo> xSI(xTarget, uno::UNO_QUERY_THROW);
                    if (xSI->supportsService(u"com.sun.star.document.LinkTarget"_ustr))
                    {
                        aJson.put(aStrDisplayname, aLink);
                        continue;
                    }
                    else
                    {
                        auto aNode = aJson.startNode(
                            OUStringToOString(aStrDisplayname, RTL_TEXTENCODING_UTF8));

                        uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
                        if( xLTS.is() )
                            extractLinks(xLTS->getLinks(), true, aJson);
                    }
                }
            }
            catch(...)
            {
                SAL_WARN("lok""extractLinks: Exception");
            }
        }
    }
}

static void unoAnyToJson(tools::JsonWriter& rJson, std::string_view pNodeName, const uno::Any& anyItem)
{
    auto aNode = rJson.startNode(pNodeName);
    OUString aType = anyItem.getValueTypeName();
    rJson.put("type", aType);

    if (aType == "string")
        rJson.put("value", anyItem.get<OUString>());
    else if (aType == "unsigned long")
        rJson.put("value", OString::number(anyItem.get<sal_uInt32>()));
    else if (aType == "long")
        rJson.put("value", OString::number(anyItem.get<sal_Int32>()));
    else if (aType == "[]any")
    {
        uno::Sequence<uno::Any> aSeq;
        if (anyItem >>= aSeq)
        {
            auto valueNode = rJson.startNode("value");

            for (auto i = 0; i < aSeq.getLength(); ++i)
            {
                unoAnyToJson(rJson, OString::number(i), aSeq[i]);
            }
        }
    }
}

static int lcl_getViewId(std::string_view payload);

namespace desktop {

RectangleAndPart RectangleAndPart::Create(const OString& rPayload)
{
    RectangleAndPart aRet;
    if (rPayload.startsWith("EMPTY")) // payload starts with "EMPTY"
    {
        aRet.m_aRectangle = tools::Rectangle(0, 0, SfxLokHelper::MaxTwips, SfxLokHelper::MaxTwips);
        if (comphelper::LibreOfficeKit::isPartInInvalidation())
        {
            int nSeparatorPos = rPayload.indexOf(',', 6);
            bool bHasMode = nSeparatorPos > 0;
            if (bHasMode)
            {
                aRet.m_nPart = o3tl::toInt32(rPayload.subView(6, nSeparatorPos - 6));
                assert(rPayload.getLength() > nSeparatorPos);
                aRet.m_nMode = o3tl::toInt32(rPayload.subView(nSeparatorPos + 1));
            }
            else
            {
                aRet.m_nPart = o3tl::toInt32(rPayload.subView(6));
                aRet.m_nMode = 0;
            }
        }

        return aRet;
    }

    // Read '<left>, <top>, <width>, <height>[, <part>, <mode>]'. C++ streams are simpler but slower.
    const char* pos = rPayload.getStr();
    const char* end = rPayload.getStr() + rPayload.getLength();
    tools::Long nLeft = rtl_str_toInt64_WithLength(pos, 10, end - pos);
    while (pos < end && *pos != ',')
        ++pos;
    if (pos < end)
        ++pos;
    assert(pos < end);
    tools::Long nTop = rtl_str_toInt64_WithLength(pos, 10, end - pos);
    while (pos < end && *pos != ',')
        ++pos;
    if (pos < end)
        ++pos;
    assert(pos < end);
    tools::Long nWidth = rtl_str_toInt64_WithLength(pos, 10, end - pos);
    while (pos < end && *pos != ',')
        ++pos;
    if (pos < end)
        ++pos;
    assert(pos < end);
    tools::Long nHeight = rtl_str_toInt64_WithLength(pos, 10, end - pos);
    tools::Long nPart = INT_MIN;
    tools::Long nMode = 0;
    if (comphelper::LibreOfficeKit::isPartInInvalidation())
    {
        while (pos < end && *pos != ',')
            ++pos;
        if (pos < end)
            ++pos;
        assert(pos < end);
        nPart = rtl_str_toInt64_WithLength(pos, 10, end - pos);

        while (pos < end && *pos != ',')
            ++pos;
        if (pos < end)
        {
            ++pos;
            assert(pos < end);
            nMode = rtl_str_toInt64_WithLength(pos, 10, end - pos);
        }
    }

    aRet.m_aRectangle = SanitizedRectangle(nLeft, nTop, nWidth, nHeight);
    aRet.m_nPart = nPart;
    aRet.m_nMode = nMode;
    return aRet;
}

tools::Rectangle RectangleAndPart::SanitizedRectangle(tools::Long nLeft, tools::Long nTop, tools::Long nWidth, tools::Long nHeight)
{
    if (nWidth <= 0 || nHeight <= 0)
        return tools::Rectangle();

    // The top-left corner starts at (0, 0).
    // Anything negative is invalid.
    if (nLeft < 0)
    {
        nWidth += nLeft;
        nLeft = 0;
    }

    if (nTop < 0)
    {
        nHeight += nTop;
        nTop = 0;
    }

    if (nWidth > 0 && nHeight > 0)
        return tools::Rectangle(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
    // Else set empty rect.
    return tools::Rectangle();
}

tools::Rectangle RectangleAndPart::SanitizedRectangle(const tools::Rectangle& rect)
{
    return SanitizedRectangle(rect.Left(), rect.Top(), rect.getOpenWidth(), rect.getOpenHeight());
}

const OString& CallbackFlushHandler::CallbackData::getPayload() const
{
    if(PayloadString.isEmpty())
    {
        // Do to-string conversion on demand, as many calls will get dropped without
        // needing the string.
        if(PayloadObject.which() == 1)
            PayloadString = getRectangleAndPart().toString();
    }
    return PayloadString;
}

void CallbackFlushHandler::CallbackData::updateRectangleAndPart(const RectangleAndPart& rRectAndPart)
{
    PayloadObject = rRectAndPart;
    PayloadString.clear(); // will be set on demand if needed
}

const RectangleAndPart& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
{
    // TODO: In case of unittests, they do not pass invalidations in binary but as text messages.
    // LO core should preferably always pass binary for performance.
    if(PayloadObject.which() != 1)
        PayloadObject = RectangleAndPart::Create(PayloadString);
    return boost::get<RectangleAndPart>(PayloadObject);
}

boost::property_tree::ptree& CallbackFlushHandler::CallbackData::setJson(const std::string& payload)
{
    boost::property_tree::ptree aTree;
    std::stringstream aStream(payload);
    boost::property_tree::read_json(aStream, aTree);

    // Let boost normalize the payload so it always matches the cache.
    setJson(aTree);

    // Return reference to the cached object.
    return boost::get<boost::property_tree::ptree>(PayloadObject);
}

void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree&&nbsp;rTree)
{
    std::stringstream aJSONStream;
    constexpr bool bPretty = false// Don't waste time and bloat logs.
    boost::property_tree::write_json(aJSONStream, rTree, bPretty);
    PayloadString = OString(o3tl::trim(aJSONStream.str()));

    PayloadObject = rTree;
}

const boost::property_tree::ptree& CallbackFlushHandler::CallbackData::getJson() const
{
    assert(PayloadObject.which() == 2);
    return boost::get<boost::property_tree::ptree>(PayloadObject);
}

int CallbackFlushHandler::CallbackData::getViewId() const
{
    if (isCached())
    {
        assert(PayloadObject.which() == 3);
        return boost::get<int>(PayloadObject);
    }
    return lcl_getViewId(getPayload());
}

bool CallbackFlushHandler::CallbackData::validate() const
{
    switch (PayloadObject.which())
    {
        // Not cached.
        case 0:
            return true;

        // RectangleAndPart.
        case 1:
            return getRectangleAndPart().toString().getStr() == getPayload();

        // Json.
        case 2:
        {
            std::stringstream aJSONStream;
            boost::property_tree::write_json(aJSONStream, getJson(), false);
            const std::string aExpected = boost::trim_copy(aJSONStream.str());
            return getPayload() == std::string_view(aExpected);
        }

        // View id.
        case 3:
            return getViewId() == lcl_getViewId( getPayload());

        default:
            assert(!"Unknown variant type; please add an entry to validate.");
    }

    return false;
}

// namespace desktop

static bool lcl_isViewCallbackType(const int type)
{
    switch (type)
    {
        case LOK_CALLBACK_CELL_VIEW_CURSOR:
        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
        case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
            return true;

        default:
            return false;
    }
}

static bool isUpdatedType(int type)
{
    switch (type)
    {
        case LOK_CALLBACK_TEXT_SELECTION:
        case LOK_CALLBACK_TEXT_SELECTION_START:
        case LOK_CALLBACK_TEXT_SELECTION_END:
            return true;
        default:
            return false;
    }
}

static bool isUpdatedTypePerViewId(int type)
{
    switch (type)
    {
        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
            return true;
        default:
            return false;
    }
}

static int lcl_getViewId(std::string_view payload)
{
    // this is a cheap way how to get the viewId from a JSON message; proper
    // parsing is terribly expensive, and we just need the viewId here
    size_t viewIdPos = payload.find("viewId");
    if (viewIdPos == std::string::npos)
        return 0;

    size_t numberPos = payload.find(":", viewIdPos + 6);
    if (numberPos == std::string::npos)
        return 0;

    for (++numberPos; numberPos < payload.length(); ++numberPos)
    {
        if (payload[numberPos] == ',' || payload[numberPos] == '}' || (payload[numberPos] >= '0' && payload[numberPos] <= '9'))
            break;
    }

    if (numberPos < payload.length() && payload[numberPos] >= '0' && payload[numberPos] <= '9')
        return o3tl::toInt32(payload.substr(numberPos));

    return 0;
}

// Wonder global state ...
static uno::Reference<css::uno::XComponentContext> xContext;
static uno::Reference<css::lang::XMultiServiceFactory> xSFactory;
static uno::Reference<css::lang::XMultiComponentFactory> xFactory;

namespace {

OUString lcl_getCurrentDocumentMimeType(const LibLODocument_Impl* pDocument)
{
    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(pDocument->mxComponent.get());
    if (!pBaseModel)
        return u""_ustr;

    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
    if (!pObjectShell)
        return u""_ustr;

    SfxMedium* pMedium = pObjectShell->GetMedium();
    if (!pMedium)
        return u""_ustr;

    auto pFilter = pMedium->GetFilter();
    if (!pFilter)
        return u""_ustr;

    return pFilter->GetMimeType();
}

// Gets an undo manager to enter and exit undo context. Needed by ToggleOrientation
css::uno::Reference< css::document::XUndoManager > getUndoManager( const css::uno::Reference< css::frame::XFrame >& rxFrame )
{
    const css::uno::Reference< css::frame::XController > xController = rxFrame->getController();
    if ( xController.is() )
    {
        const css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
        if ( xModel.is() )
        {
            const css::uno::Reference< css::document::XUndoManagerSupplier > xSuppUndo( xModel, css::uno::UNO_QUERY_THROW );
            return css::uno::Reference< css::document::XUndoManager >( xSuppUndo->getUndoManager(), css::uno::UNO_SET_THROW );
        }
    }

    return css::uno::Reference< css::document::XUndoManager > ();
}

// Adjusts page margins for Writer doc. Needed by ToggleOrientation
void ExecuteMarginLRChange(
    const tools::Long nPageLeftMargin,
    const tools::Long nPageRightMargin,
    SvxLongLRSpaceItem* pPageLRMarginItem)
{
    pPageLRMarginItem->SetLeft( nPageLeftMargin );
    pPageLRMarginItem->SetRight( nPageRightMargin );
    SfxViewShell* pViewSh = SfxViewShell::Current();
    if (!pViewSh)
        return;
    pViewSh->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_LRSPACE,
            SfxCallMode::RECORD, { pPageLRMarginItem });
}

// Adjusts page margins for Writer doc. Needed by ToggleOrientation
void ExecuteMarginULChange(
        const tools::Long nPageTopMargin,
        const tools::Long nPageBottomMargin,
        SvxLongULSpaceItem* pPageULMarginItem)
{
    pPageULMarginItem->SetUpper( nPageTopMargin );
    pPageULMarginItem->SetLower( nPageBottomMargin );
    SfxViewShell* pViewSh = SfxViewShell::Current();
    if (!pViewSh)
        return;
    pViewSh->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_ULSPACE,
            SfxCallMode::RECORD, { pPageULMarginItem });
}

// Main function which toggles page orientation of the Writer doc. Needed by ToggleOrientation
void ExecuteOrientationChange()
{
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
    if (!pViewFrm)
        return;

    std::unique_ptr<SvxPageItem> pPageItem(new SvxPageItem(SID_ATTR_PAGE));

    // 1mm in twips rounded
    // This should be in sync with MINBODY in sw/source/uibase/sidebar/PageMarginControl.hxx
    constexpr tools::Long MINBODY = o3tl::toTwips(1, o3tl::Length::mm);

    css::uno::Reference< css::document::XUndoManager > mxUndoManager(
                getUndoManager( pViewFrm->GetFrame().GetFrameInterface() ) );

    if ( mxUndoManager.is() )
        mxUndoManager->enterUndoContext( u""_ustr );

    SfxPoolItemHolder aResult;
    pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_SIZE, aResult);
    std::unique_ptr<SvxSizeItem> pPageSizeItem(static_cast<const SvxSizeItem*>(aResult.getItem())->Clone());

    pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_LRSPACE, aResult);
    std::unique_ptr<SvxLongLRSpaceItem> pPageLRMarginItem(static_cast<const SvxLongLRSpaceItem*>(aResult.getItem())->Clone());

    pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_ULSPACE, aResult);
    std::unique_ptr<SvxLongULSpaceItem> pPageULMarginItem(static_cast<const SvxLongULSpaceItem*>(aResult.getItem())->Clone());

    {
        bool bIsLandscape = false;
        if ( pPageSizeItem->GetSize().Width() > pPageSizeItem->GetSize().Height())
            bIsLandscape = true;

        // toggle page orientation
        pPageItem->SetLandscape(!bIsLandscape);


        // swap the width and height of the page size
        const tools::Long nRotatedWidth = pPageSizeItem->GetSize().Height();
        const tools::Long nRotatedHeight = pPageSizeItem->GetSize().Width();
        pPageSizeItem->SetSize(Size(nRotatedWidth, nRotatedHeight));


        // apply changed attributes
        if (SfxViewShell* pCurrent = SfxViewShell::Current())
        {
            pCurrent->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE,
                SfxCallMode::RECORD, { pPageSizeItem.get(), pPageItem.get() });
        }
    }


    // check, if margin values still fit to the changed page size.
    // if not, adjust margin values
    {
        const tools::Long nML = pPageLRMarginItem->GetLeft();
        const tools::Long nMR = pPageLRMarginItem->GetRight();
        const tools::Long nTmpPW = nML + nMR + MINBODY;

        const tools::Long nPW  = pPageSizeItem->GetSize().Width();

        if ( nTmpPW > nPW )
        {
            if ( nML <= nMR )
            {
                ExecuteMarginLRChange( pPageLRMarginItem->GetLeft(), nMR - (nTmpPW - nPW ), pPageLRMarginItem.get() );
            }
            else
            {
                ExecuteMarginLRChange( nML - (nTmpPW - nPW ), pPageLRMarginItem->GetRight(), pPageLRMarginItem.get() );
            }
        }

        const tools::Long nMT = pPageULMarginItem->GetUpper();
        const tools::Long nMB = pPageULMarginItem->GetLower();
        const tools::Long nTmpPH = nMT + nMB + MINBODY;

        const tools::Long nPH  = pPageSizeItem->GetSize().Height();

        if ( nTmpPH > nPH )
        {
            if ( nMT <= nMB )
            {
                ExecuteMarginULChange( pPageULMarginItem->GetUpper(), nMB - ( nTmpPH - nPH ), pPageULMarginItem.get() );
            }
            else
            {
                ExecuteMarginULChange( nMT - ( nTmpPH - nPH ), pPageULMarginItem->GetLower(), pPageULMarginItem.get() );
            }
        }
    }

    if ( mxUndoManager.is() )
        mxUndoManager->leaveUndoContext();
}

void hideSidebar()
{
    SfxViewShell* pViewShell = SfxViewShell::Current();
    SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
    if (pViewFrame)
        pViewFrame->SetChildWindow(SID_SIDEBAR, false , false );
    else
        SetLastExceptionMsg(u"No view shell or sidebar"_ustr);
}

css::uno::Sequence<css::lang::Locale> setLanguageToolConfig()
{
    css::uno::Sequence<css::lang::Locale> aLTLocales;

    const char* pEnabled = ::getenv("LANGUAGETOOL_ENABLED");
    const char* pBaseUrlString = ::getenv("LANGUAGETOOL_BASEURL");

    if (pEnabled && pBaseUrlString)
    {
        const char* pUsername = ::getenv("LANGUAGETOOL_USERNAME");
        const char* pApikey = ::getenv("LANGUAGETOOL_APIKEY");
        const char* pSSLVerification = ::getenv("LANGUAGETOOL_SSL_VERIFICATION");
        const char* pRestProtocol = ::getenv("LANGUAGETOOL_RESTPROTOCOL");

        OUString aEnabled = OStringToOUString(pEnabled, RTL_TEXTENCODING_UTF8);
        if (aEnabled != "true")
            return aLTLocales;
        OUString aBaseUrl = OStringToOUString(pBaseUrlString, RTL_TEXTENCODING_UTF8);
        try
        {
            using LanguageToolCfg = officecfg::Office::Linguistic::GrammarChecking::LanguageTool;
            auto batch(comphelper::ConfigurationChanges::create());

            LanguageToolCfg::BaseURL::set(aBaseUrl, batch);
            LanguageToolCfg::IsEnabled::set(true, batch);
            if (pSSLVerification)
            {
                OUString aSSLVerification = OStringToOUString(pSSLVerification, RTL_TEXTENCODING_UTF8);
                LanguageToolCfg::SSLCertVerify::set(aSSLVerification == "true", batch);
            }
            if (pRestProtocol)
            {
                OUString aRestProtocol = OStringToOUString(pRestProtocol, RTL_TEXTENCODING_UTF8);
                LanguageToolCfg::RestProtocol::set(aRestProtocol, batch);
            }
            if (pUsername && pApikey)
            {
                OUString aUsername = OStringToOUString(pUsername, RTL_TEXTENCODING_UTF8);
                OUString aApiKey = OStringToOUString(pApikey, RTL_TEXTENCODING_UTF8);
                LanguageToolCfg::Username::set(aUsername, batch);
                LanguageToolCfg::ApiKey::set(aApiKey, batch);
            }
            batch->commit();

            uno::Reference<linguistic2::XProofreader> xGC(
                xContext->getServiceManager()->createInstanceWithContext(u"org.openoffice.lingu.LanguageToolGrammarChecker"_ustr, xContext),
                uno::UNO_QUERY_THROW);
            uno::Reference<linguistic2::XSupportedLocales> xSuppLoc(xGC, uno::UNO_QUERY_THROW);

            css::uno::Reference<css::linguistic2::XLinguServiceManager2> xLangSrv =
                css::linguistic2::LinguServiceManager::create(xContext);
            if (xLangSrv.is())
            {
                css::uno::Reference<css::linguistic2::XSpellChecker> xSpell = xLangSrv->getSpellChecker();
                if (xSpell.is())
                {
                    Sequence<OUString> aEmpty;
                    Sequence<css::lang::Locale> aLocales = xSpell->getLocales();

                    for (int itLocale = 0; itLocale < aLocales.getLength(); itLocale++)
                    {
                        // turn off spell checker if LanguageTool supports the locale already
                        if (xSuppLoc->hasLocale(aLocales[itLocale]))
                            xLangSrv->setConfiguredServices(
                                SN_SPELLCHECKER, aLocales[itLocale], aEmpty);
                    }
                }
            }

            aLTLocales = xSuppLoc->getLocales();
        }
        catch(uno::Exception const& rException)
        {
            SAL_WARN("lok""Failed to set LanguageTool API settings: " << rException.Message);
        }
    }

    return aLTLocales;
}

}  // end anonymous namespace

// Could be anonymous in principle, but for the unit testing purposes, we
// declare it in init.hxx.
OUString desktop::extractParameter(OUString& rOptions, std::u16string_view rName)
{
    OUString aValue;

    OUString aNameEquals(OUString::Concat(rName) + "=");
    OUString aCommaNameEquals(OUString::Concat(",") + rName + "=");

    int nIndex = -1;
    if (rOptions.startsWith(aNameEquals))
    {
        size_t nLen = aNameEquals.getLength();
        int nComma = rOptions.indexOf(",", nLen);
        if (nComma >= 0)
        {
            aValue = rOptions.copy(nLen, nComma - nLen);
            rOptions = rOptions.copy(nComma + 1);
        }
        else
        {
            aValue = rOptions.copy(nLen);
            rOptions.clear();
        }
    }
    else if ((nIndex = rOptions.indexOf(aCommaNameEquals)) >= 0)
    {
        size_t nLen = aCommaNameEquals.getLength();
        int nComma = rOptions.indexOf(",", nIndex + nLen);
        if (nComma >= 0)
        {
            aValue = rOptions.copy(nIndex + nLen, nComma - nIndex - nLen);
            rOptions = OUString::Concat(rOptions.subView(0, nIndex)) + rOptions.subView(nComma);
        }
        else
        {
            aValue = rOptions.copy(nIndex + nLen);
            rOptions = rOptions.copy(0, nIndex);
        }
    }

    return aValue;
}

extern "C"
{

static void doc_destroy(LibreOfficeKitDocument* pThis);
static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* pUrl, const char* pFormat, const char* pFilterOptions);
static int doc_getDocumentType(LibreOfficeKitDocument* pThis);
static int doc_getParts(LibreOfficeKitDocument* pThis);
static char* doc_getPartPageRectangles(LibreOfficeKitDocument* pThis);
static int doc_getPart(LibreOfficeKitDocument* pThis);
static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
static void doc_selectPart(LibreOfficeKitDocument* pThis, int nPart, int nSelect);
static void doc_moveSelectedParts(LibreOfficeKitDocument* pThis, int nPosition, bool bDuplicate);
static char* doc_getPartName(LibreOfficeKitDocument* pThis, int nPart);
static void doc_setPartMode(LibreOfficeKitDocument* pThis, int nPartMode);
static int doc_getEditMode(LibreOfficeKitDocument* pThis);
static void doc_paintTile(LibreOfficeKitDocument* pThis,
                          unsigned char* pBuffer,
                          const int nCanvasWidth, const int nCanvasHeight,
                          const int nTilePosX, const int nTilePosY,
                          const int nTileWidth, const int nTileHeight);
static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
                              unsigned char* pBuffer,
                              const int nPart,
                              const int nMode,
                              const int nCanvasWidth, const int nCanvasHeight,
                              const int nTilePosX, const int nTilePosY,
                              const int nTileWidth, const int nTileHeight);
static int doc_getTileMode(LibreOfficeKitDocument* pThis);
static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
                                long* pWidth,
                                long* pHeight);
static void doc_getDataArea(LibreOfficeKitDocument* pThis,
                            long nTab,
                            long* pCol,
                            long* pRow);
static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
                                       const char* pArguments);

static void doc_registerCallback(LibreOfficeKitDocument* pThis,
                                LibreOfficeKitCallback pCallback,
                                void* pData);
static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
                             int nType,
                             int nCharCode,
                             int nKeyCode);
static void doc_setBlockedCommandList(LibreOfficeKitDocument* pThis,
                                int nViewId,
                                const char* blockedCommandList);

static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis,
                                            unsigned nWindowId,
                                            int nType,
                                            const char* pText);
static void doc_removeTextContext(LibreOfficeKitDocument* pThis,
                                  unsigned nLOKWindowId,
                                  int nCharBefore,
                                  int nCharAfter);
static void doc_sendDialogEvent(LibreOfficeKitDocument* pThis,
                               unsigned long long int nLOKWindowId,
                               const char* pArguments);
static void doc_postWindowKeyEvent(LibreOfficeKitDocument* pThis,
                                   unsigned nLOKWindowId,
                                   int nType,
                                   int nCharCode,
                                   int nKeyCode);
static void doc_postMouseEvent (LibreOfficeKitDocument* pThis,
                                int nType,
                                int nX,
                                int nY,
                                int nCount,
                                int nButtons,
                                int nModifier);
static void doc_postWindowMouseEvent (LibreOfficeKitDocument* pThis,
                                      unsigned nLOKWindowId,
                                      int nType,
                                      int nX,
                                      int nY,
                                      int nCount,
                                      int nButtons,
                                      int nModifier);
static void doc_postWindowGestureEvent(LibreOfficeKitDocument* pThis,
                                      unsigned nLOKWindowId,
                                      const char* pType,
                                      int nX,
                                      int nY,
                                      int nOffset);
static void doc_postUnoCommand(LibreOfficeKitDocument* pThis,
                               const char* pCommand,
                               const char* pArguments,
                               bool bNotifyWhenFinished);
static void doc_setWindowTextSelection(LibreOfficeKitDocument* pThis,
                                       unsigned nLOKWindowId,
                                       bool swap,
                                       int nX,
                                       int nY);
static void doc_setTextSelection (LibreOfficeKitDocument* pThis,
                                  int nType,
                                  int nX,
                                  int nY);
static char* doc_getTextSelection(LibreOfficeKitDocument* pThis,
                                  const char* pMimeType,
                                  char** pUsedMimeType);
static int doc_getSelectionType(LibreOfficeKitDocument* pThis);
static int doc_getSelectionTypeAndText(LibreOfficeKitDocument* pThis,
                                       const char* pMimeType,
                                       char** pText,
                                       char** pUsedMimeType);
static int doc_getClipboard (LibreOfficeKitDocument* pThis,
                             const char **pMimeTypes,
                             size_t      *pOutCount,
                             char      ***pOutMimeTypes,
                             size_t     **pOutSizes,
                             char      ***pOutStreams);
static int doc_setClipboard (LibreOfficeKitDocument* pThis,
                             const size_t   nInCount,
                             const char   **pInMimeTypes,
                             const size_t  *pInSizes,
                             const char   **pInStreams);
static bool doc_paste(LibreOfficeKitDocument* pThis,
                      const char* pMimeType,
                      const char* pData,
                      size_t nSize);
static void doc_setGraphicSelection (LibreOfficeKitDocument* pThis,
                                  int nType,
                                  int nX,
                                  int nY);
static void doc_resetSelection (LibreOfficeKitDocument* pThis);
static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCommand);
static void doc_setClientZoom(LibreOfficeKitDocument* pThis,
                                    int nTilePixelWidth,
                                    int nTilePixelHeight,
                                    int nTileTwipWidth,
                                    int nTileTwipHeight);
static void doc_setClientVisibleArea(LibreOfficeKitDocument* pThis, int nX, int nY, int nWidth, int nHeight);
static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int nLevelint nIndex, bool bHidden);
static int doc_createView(LibreOfficeKitDocument* pThis);
static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis, const char* pOptions);
static void doc_destroyView(LibreOfficeKitDocument* pThis, int nId);
static void doc_setView(LibreOfficeKitDocument* pThis, int nId);
static int doc_getView(LibreOfficeKitDocument* pThis);
static int doc_getViewsCount(LibreOfficeKitDocument* pThis);
static bool doc_getViewIds(LibreOfficeKitDocument* pThis, int* pArray, size_t nSize);
static void doc_setViewLanguage(LibreOfficeKitDocument* pThis, int nId, const char* language);
static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument* pThis,
                          const char *pFontName,
                          const char *pChar,
                          int* pFontWidth,
                          int* pFontHeight,
                          int pOrientation);
static unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
                          const char *pFontName,
                          const char *pChar,
                          int* pFontWidth,
                          int* pFontHeight);
static char* doc_getPartHash(LibreOfficeKitDocument* pThis, int nPart);

static void doc_paintWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
                            const int nX, const int nY,
                            const int nWidth, const int nHeight);

static void doc_paintWindowDPI(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
                               const int nX, const int nY,
                               const int nWidth, const int nHeight,
                               const double fDPIScale);

static void doc_paintWindowForView(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, unsigned char* pBuffer,
                                   const int nX, const int nY,
                                   const int nWidth, const int nHeight,
                                   const double fDPIScale, int viewId);

static void doc_postWindow(LibreOfficeKitDocument* pThis, unsigned
 nLOKWindowId, int nAction, const char* pData);

static char* doc_getPartInfo(LibreOfficeKitDocument* pThis, int nPart);

static bool doc_insertCertificate(LibreOfficeKitDocument* pThis,
                                  const unsigned char* pCertificateBinary,
                                  const int nCertificateBinarySize,
                                  const unsigned char* pPrivateKeyBinary,
                                  const int nPrivateKeyBinarySize);

static bool doc_addCertificate(LibreOfficeKitDocument* pThis,
                                 const unsigned char* pCertificateBinary,
                                 const int nCertificateBinarySize);

static int doc_getSignatureState(LibreOfficeKitDocument* pThis);

static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOutput);

static void doc_resizeWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
                             const int nWidth, const int nHeight);

static void doc_completeFunction(LibreOfficeKitDocument* pThis, const char*);


static void doc_sendFormFieldEvent(LibreOfficeKitDocument* pThis,
                                   const char* pArguments);

static bool doc_renderSearchResult(LibreOfficeKitDocument* pThis,
                                 const char* pSearchResult, unsigned char** pBitmapBuffer,
                                 int* pWidth, int* pHeight, size_t* pByteSize);

static void doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const char* pArguments);

static void doc_setViewTimezone(LibreOfficeKitDocument* pThis, int nId, const char* timezone);

static void doc_setViewReadOnly(LibreOfficeKitDocument* pThis, int nId, const bool readonly);

static void doc_setAllowChangeComments(LibreOfficeKitDocument* pThis, int nId, const bool allow);

static void doc_setAccessibilityState(LibreOfficeKitDocument* pThis, int nId, bool bEnabled);

static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument* pThis);

static int doc_getA11yCaretPosition(LibreOfficeKitDocument* pThis);

static char* doc_getPresentationInfo(LibreOfficeKitDocument* pThis);

static bool doc_createSlideRenderer(
    LibreOfficeKitDocument* pThis,
    const char* pSlideHash,
    int nSlideNumber, unsigned* nViewWidth, unsigned* nViewHeight,
    bool bRenderBackground, bool bRenderMasterPage);

static void doc_postSlideshowCleanup(LibreOfficeKitDocument* pThis);

static bool doc_renderNextSlideLayer(
    LibreOfficeKitDocument* pThis, unsigned char* pBuffer, bool* bIsBitmapLayer, double* pScale, char** pJsonMsg);

static void doc_setViewOption(LibreOfficeKitDocument* pDoc, const char* pOption, const char* pValue);

// extern "C"

namespace {
ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
{
    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
    return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
}

/*
 * Unfortunately clipboard creation using UNO is insanely baroque.
 * we also need to ensure that this works for the first view which
 * has no clear 'createView' called for it (unfortunately).
 */

rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis)
{
    ITiledRenderable* pDoc = getTiledRenderable(pThis);
    rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView());
    if (!pDoc)
    {
        return xClip;
    }

    SAL_INFO("lok""Set to clipboard for view " << xClip.get());
    // FIXME: using a hammer here - should not be necessary if all tests used createView.
    pDoc->setClipboard(uno::Reference<datatransfer::clipboard::XClipboard>(xClip->getXI(), UNO_QUERY));

    return xClip;
}

const vcl::Font* FindFont(std::u16string_view rFontName)
{
    SfxObjectShell* pDocSh = SfxObjectShell::Current();
    if (!pDocSh)
        return nullptr;
    const SvxFontListItem* pFonts
        = static_cast<const SvxFontListItem*>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
    const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
    if (pList && !rFontName.empty())
        if (sal_Handle hMetric = pList->GetFirstFontMetric(rFontName))
            return &FontList::GetFontMetric(hMetric);
    return nullptr;
}

vcl::Font FindFont_FallbackToDefault(std::u16string_view rFontName)
{
    if (auto pFound = FindFont(rFontName))
        return *pFound;

    return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE, LANGUAGE_NONE,
                                        GetDefaultFontFlags::NONE);
}

int getDocumentType (LibreOfficeKitDocument* pThis)
{
    SetLastExceptionMsg();

    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);

    try
    {
        uno::Reference<lang::XServiceInfo> xDocument(pDocument->mxComponent, uno::UNO_QUERY_THROW);

        if (xDocument->supportsService(u"com.sun.star.sheet.SpreadsheetDocument"_ustr))
        {
            return LOK_DOCTYPE_SPREADSHEET;
        }
        else if (xDocument->supportsService(u"com.sun.star.presentation.PresentationDocument"_ustr))
        {
            return LOK_DOCTYPE_PRESENTATION;
        }
        else if (xDocument->supportsService(u"com.sun.star.drawing.DrawingDocument"_ustr))
        {
            return LOK_DOCTYPE_DRAWING;
        }
        else if (xDocument->supportsService(u"com.sun.star.text.TextDocument"_ustr) || xDocument->supportsService(u"com.sun.star.text.WebDocument"_ustr))
        {
            return LOK_DOCTYPE_TEXT;
        }
        else
        {
            SetLastExceptionMsg(u"unknown document type"_ustr);
        }
    }
    catch (const uno::Exception& exception)
    {
        SetLastExceptionMsg("exception: " + exception.Message);
    }
    return LOK_DOCTYPE_OTHER;
}

// anonymous namespace

LibLODocument_Impl::LibLODocument_Impl(uno::Reference <css::lang::XComponent> xComponent, int nDocumentId)
    : mxComponent(std::move(xComponent))
    , mnDocumentId(nDocumentId)
{
    assert(nDocumentId != -1 && "Cannot set mnDocumentId to -1");

    m_pDocumentClass = gDocumentClass.lock();
    if (!m_pDocumentClass)
    {
        m_pDocumentClass = std::make_shared<LibreOfficeKitDocumentClass>();

        m_pDocumentClass->nSize = sizeof(LibreOfficeKitDocumentClass);

        m_pDocumentClass->destroy = doc_destroy;
        m_pDocumentClass->saveAs = doc_saveAs;
        m_pDocumentClass->getDocumentType = doc_getDocumentType;
        m_pDocumentClass->getParts = doc_getParts;
        m_pDocumentClass->getPartPageRectangles = doc_getPartPageRectangles;
        m_pDocumentClass->getPart = doc_getPart;
        m_pDocumentClass->setPart = doc_setPart;
        m_pDocumentClass->selectPart = doc_selectPart;
        m_pDocumentClass->moveSelectedParts = doc_moveSelectedParts;
        m_pDocumentClass->getPartName = doc_getPartName;
        m_pDocumentClass->setPartMode = doc_setPartMode;
        m_pDocumentClass->getEditMode = doc_getEditMode;
        m_pDocumentClass->paintTile = doc_paintTile;
        m_pDocumentClass->paintPartTile = doc_paintPartTile;
        m_pDocumentClass->getTileMode = doc_getTileMode;
        m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
        m_pDocumentClass->getDataArea = doc_getDataArea;
        m_pDocumentClass->initializeForRendering = doc_initializeForRendering;
        m_pDocumentClass->registerCallback = doc_registerCallback;
        m_pDocumentClass->postKeyEvent = doc_postKeyEvent;
        m_pDocumentClass->postWindowExtTextInputEvent = doc_postWindowExtTextInputEvent;
        m_pDocumentClass->removeTextContext = doc_removeTextContext;
        m_pDocumentClass->postWindowKeyEvent = doc_postWindowKeyEvent;
        m_pDocumentClass->postMouseEvent = doc_postMouseEvent;
        m_pDocumentClass->postWindowMouseEvent = doc_postWindowMouseEvent;
        m_pDocumentClass->sendDialogEvent = doc_sendDialogEvent;
        m_pDocumentClass->postUnoCommand = doc_postUnoCommand;
        m_pDocumentClass->setTextSelection = doc_setTextSelection;
        m_pDocumentClass->setWindowTextSelection = doc_setWindowTextSelection;
        m_pDocumentClass->getTextSelection = doc_getTextSelection;
        m_pDocumentClass->getSelectionType = doc_getSelectionType;
        m_pDocumentClass->getSelectionTypeAndText = doc_getSelectionTypeAndText;
        m_pDocumentClass->getClipboard = doc_getClipboard;
        m_pDocumentClass->setClipboard = doc_setClipboard;
        m_pDocumentClass->paste = doc_paste;
        m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
        m_pDocumentClass->resetSelection = doc_resetSelection;
        m_pDocumentClass->getCommandValues = doc_getCommandValues;
        m_pDocumentClass->setClientZoom = doc_setClientZoom;
        m_pDocumentClass->setClientVisibleArea = doc_setClientVisibleArea;
        m_pDocumentClass->setOutlineState = doc_setOutlineState;

        m_pDocumentClass->createView = doc_createView;
        m_pDocumentClass->destroyView = doc_destroyView;
        m_pDocumentClass->setView = doc_setView;
        m_pDocumentClass->getView = doc_getView;
        m_pDocumentClass->getViewsCount = doc_getViewsCount;
        m_pDocumentClass->getViewIds = doc_getViewIds;

        m_pDocumentClass->renderFont = doc_renderFont;
        m_pDocumentClass->renderFontOrientation = doc_renderFontOrientation;
        m_pDocumentClass->getPartHash = doc_getPartHash;

        m_pDocumentClass->paintWindow = doc_paintWindow;
        m_pDocumentClass->paintWindowDPI = doc_paintWindowDPI;
        m_pDocumentClass->paintWindowForView = doc_paintWindowForView;
        m_pDocumentClass->postWindow = doc_postWindow;
        m_pDocumentClass->resizeWindow = doc_resizeWindow;

        m_pDocumentClass->setViewLanguage = doc_setViewLanguage;

        m_pDocumentClass->getPartInfo = doc_getPartInfo;

        m_pDocumentClass->insertCertificate = doc_insertCertificate;
        m_pDocumentClass->addCertificate = doc_addCertificate;
        m_pDocumentClass->getSignatureState = doc_getSignatureState;

        m_pDocumentClass->renderShapeSelection = doc_renderShapeSelection;
        m_pDocumentClass->postWindowGestureEvent = doc_postWindowGestureEvent;

        m_pDocumentClass->createViewWithOptions = doc_createViewWithOptions;
        m_pDocumentClass->completeFunction = doc_completeFunction;

        m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent;
        m_pDocumentClass->renderSearchResult = doc_renderSearchResult;

        m_pDocumentClass->setBlockedCommandList = doc_setBlockedCommandList;

        m_pDocumentClass->sendContentControlEvent = doc_sendContentControlEvent;

        m_pDocumentClass->setViewTimezone = doc_setViewTimezone;

        m_pDocumentClass->setAccessibilityState = doc_setAccessibilityState;

        m_pDocumentClass->getA11yFocusedParagraph = doc_getA11yFocusedParagraph;
        m_pDocumentClass->getA11yCaretPosition = doc_getA11yCaretPosition;

        m_pDocumentClass->setViewReadOnly = doc_setViewReadOnly;

        m_pDocumentClass->setAllowChangeComments = doc_setAllowChangeComments;

        m_pDocumentClass->getPresentationInfo = doc_getPresentationInfo;
        m_pDocumentClass->createSlideRenderer = doc_createSlideRenderer;
        m_pDocumentClass->postSlideshowCleanup = doc_postSlideshowCleanup;
        m_pDocumentClass->renderNextSlideLayer = doc_renderNextSlideLayer;
        m_pDocumentClass->setViewOption = doc_setViewOption;

        gDocumentClass = m_pDocumentClass;
    }
    pClass = m_pDocumentClass.get();

    forceSetClipboardForCurrentView(this);
}

LibLODocument_Impl::~LibLODocument_Impl()
{
    if (comphelper::LibreOfficeKit::isForkedChild())
    {
        // Touch the least memory possible, while trying to avoid leaking files.
        SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
        if (pBaseModel)
        {
            SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
            if (pObjectShell)
                pObjectShell->InternalCloseAndRemoveFiles();
        }
        return;
    }

    try
    {
        mxComponent->dispose();
    }
    catch (const css::lang::DisposedException&)
    {
        TOOLS_WARN_EXCEPTION("lok""failed to dispose document");
    }
}

static OUString getGenerator()
{
    OUString sGenerator(
        Translate::ExpandVariables(u"%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"_ustr));
    OUString os(u"$_OS"_ustr);
    ::rtl::Bootstrap::expandMacros(os);
    return sGenerator.replaceFirst("%1", os);
}

extern "C" {

// One of these is created per view to handle events cf. doc_registerCallback
CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData)
    : m_pDocument(pDocument),
      m_pCallback(pCallback),
      m_pFlushEvent(nullptr),
      m_pData(pData),
      m_nDisableCallbacks(0)
{
    // Add the states that are safe to skip duplicates on, even when
    // not consequent (i.e. do no emit them if unchanged from last).
    m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_MOUSE_POINTER, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_CELL_CURSOR, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_SET_PART, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_TABLE_SELECTED, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_TAB_STOP_LIST, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_RULER_UPDATE, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_VERTICAL_RULER_UPDATE, "NIL"_ostr);
    m_states.emplace(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE, "NIL"_ostr);

    if (char* pViewRenderState = pDocument->pClass->getCommandValues(pDocument, ".uno:ViewRenderState"))
    {
        m_aViewRenderState = pViewRenderState;
        free(pViewRenderState);
    }
}

void CallbackFlushHandler::stop()
{
    if (m_pFlushEvent)
    {
        Application::RemoveUserEvent(m_pFlushEvent);
        m_pFlushEvent = nullptr;
    }
}

CallbackFlushHandler::~CallbackFlushHandler()
{
    stop();
}

CallbackFlushHandler::queue_type2::iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::iterator pos)
{
    int delta = std::distance(m_queue1.begin(), pos);
    return m_queue2.begin() + delta;
}

CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::reverse_iterator pos)
{
    int delta = std::distance(m_queue1.rbegin(), pos);
    return m_queue2.rbegin() + delta;
}

void CallbackFlushHandler::setUpdatedType( int nType, bool value )
{
    assert(isUpdatedType(nType));
    if( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
        m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
    m_updatedTypes[ nType ] = value;
    if(value)
        scheduleFlush();
}

void CallbackFlushHandler::resetUpdatedType( int nType )
{
    setUpdatedType( nType, false );
}

void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
{
    assert(isUpdatedTypePerViewId(nType));
    std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
    if( types.size() <= o3tl::make_unsigned( nType ))
        types.resize( nType + 1 ); // new are default-constructed, i.e. 'set' is false
    types[ nType ] = PerViewIdData{ value, nSourceViewId };
    if(value)
        scheduleFlush();
}

void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType, int nViewId )
{
    assert(isUpdatedTypePerViewId(nType));
    bool allViewIds = false;
    // Handle specially messages that do not have viewId for backwards compatibility.
    if( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
        allViewIds = true;
    if( !allViewIds )
    {
        setUpdatedTypePerViewId( nType, nViewId, -1, false );
        return;
    }
    forauto& it : m_updatedTypesPerViewId )
    {
        std::vector<PerViewIdData>& types = it.second;
        if( types.size() >= o3tl::make_unsigned( nType ))
            types[ nType ].set = false;
    }
}

void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const OString& pPayload)
{
    CallbackData callbackData(pPayload);
    queue(nType, callbackData);
}

void CallbackFlushHandler::libreOfficeKitViewCallbackWithViewId(int nType, const OString& pPayload, int nViewId)
{
    CallbackData callbackData(pPayload, nViewId);
    queue(nType, callbackData);
}

void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart, int nMode)
{
    tools::Rectangle& rPaintedTiles = m_aPaintedTiles[nPart][nMode];
    if (rPaintedTiles.IsEmpty())
    {
        // We have not sent any tiles: don't send invalidations.
        return;
    }

    tools::Rectangle aRect;
    if (pRect)
    {
        // We got an invalidate: crop it against the bbox.
        aRect = *pRect;
        aRect.Intersection(rPaintedTiles);
        if (aRect.IsEmpty())
        {
            return;
        }
    }
    else
    {
        // EMPTY invalidation: reset the bbox.
        rPaintedTiles = tools::Rectangle();
        // nullptr pRect means: invalidate everything.
        aRect = RectangleAndPart::emptyAllRectangle;
    }

    // RectangleAndPart ctor doesn't store &aRect, so this is OK.
    CallbackData callbackData(&aRect, nPart, nMode);
    queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
}

void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType)
{
    assert(isUpdatedType( nType ));
    std::unique_lock<std::recursive_mutex> lock(m_mutex);
    SAL_INFO("lok""Updated: [" << nType << "]");
    setUpdatedType(nType, true);
}

void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
{
    assert(isUpdatedTypePerViewId( nType ));
    std::unique_lock<std::recursive_mutex> lock(m_mutex);
    SAL_INFO("lok""Updated: [" << nType << "]");
    setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true);
}

void CallbackFlushHandler::dumpState(rtl::OStringBuffer &rState)
{
    // NB. no locking
    rState.append("\n View:\t");
    rState.append(static_cast<sal_Int32>(m_viewId));
    rState.append("\n\tDisableCallbacks:\t");
    rState.append(static_cast<sal_Int32>(m_nDisableCallbacks));
    rState.append("\n\tStates:\n");
    for (const auto &i : m_states)
    {
        rState.append("\n\t\t");
        rState.append(static_cast<sal_Int32>(i.first));
        rState.append("\t");
        rState.append(i.second);
    }
}

void CallbackFlushHandler::libreOfficeKitViewAddPendingInvalidateTiles()
{
    // Invoke() will call flushPendingLOKInvalidateTiles(), so just make sure the timer is active.
    scheduleFlush();
}

void CallbackFlushHandler::queue(const int type, const OString& data)
{
    CallbackData callbackData(data);
    queue(type, callbackData);
}

void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
{
    comphelper::ProfileZone aZone("CallbackFlushHandler::queue");

    SAL_INFO("lok""Queue: [" << type << "]: [" << aCallbackData.getPayload() << "] on " << m_queue1.size() << " entries.");

    if (comphelper::LibreOfficeKit::isForkedChild())
    {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=99 G=95

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.30Angebot  Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können  ¤

*Eine klare Vorstellung vom Zielzustand






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.