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

Quelle  XMLRedlineExport.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * 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 "XMLRedlineExport.hxx"
#include <o3tl/any.hxx>
#include <tools/debug.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/UnknownPropertyException.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>

#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/document/XRedlinesSupplier.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/text/XTextContent.hpp>
#include <com/sun/star/text/XTextSection.hpp>
#include <com/sun/star/util/DateTime.hpp>

#include <sax/tools/converter.hxx>

#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnamespace.hxx>
#include <xmloff/xmlexp.hxx>
#include <xmloff/xmluconv.hxx>
#include <unotools/securityoptions.hxx>
#include <comphelper/sequenceashashmap.hxx>


using namespace ::com::sun::star;
using namespace ::xmloff::token;

using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::beans::UnknownPropertyException;
using ::com::sun::star::document::XRedlinesSupplier;
using ::com::sun::star::container::XEnumerationAccess;
using ::com::sun::star::container::XEnumeration;
using ::com::sun::star::text::XText;
using ::com::sun::star::text::XTextContent;
using ::com::sun::star::text::XTextSection;
using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;


XMLRedlineExport::XMLRedlineExport(SvXMLExport& rExp)
:   sDeletion(GetXMLToken(XML_DELETION))
,   sFormatChange(GetXMLToken(XML_FORMAT_CHANGE))
,   sInsertion(GetXMLToken(XML_INSERTION))
,   rExport(rExp)
,   pCurrentChangesList(nullptr)
{
}


XMLRedlineExport::~XMLRedlineExport()
{
}


void XMLRedlineExport::ExportChange(
    const Reference<XPropertySet> & rPropSet,
    bool bAutoStyle)
{
    if (bAutoStyle)
    {
        // For the headers/footers, we have to collect the autostyles
        // here.  For the general case, however, it's better to collect
        // the autostyles by iterating over the global redline
        // list. So that's what we do: Here, we collect autostyles
        // only if we have no current list of changes. For the
        // main-document case, the autostyles are collected in
        // ExportChangesListAutoStyles().
        if (pCurrentChangesList != nullptr)
            ExportChangeAutoStyle(rPropSet);
    }
    else
    {
        ExportChangeInline(rPropSet);
    }
}


void XMLRedlineExport::ExportChangesList(bool bAutoStyles)
{
    if (bAutoStyles)
    {
        ExportChangesListAutoStyles();
    }
    else
    {
        ExportChangesListElements();
    }
}


void XMLRedlineExport::ExportChangesList(
    const Reference<XText> & rText,
    bool bAutoStyles)
{
    // in the header/footer case, auto styles are collected from the
    // inline change elements.
    if (bAutoStyles)
        return;

    // look for changes list for this XText
    ChangesMapType::iterator aFind = aChangeMap.find(rText);
    if (aFind == aChangeMap.end())
        return;

    ChangesVectorType& rChangesList = aFind->second;

    // export only if changes are found
    if (rChangesList.empty())
        return;

    // changes container element
    SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT,
                                XML_TRACKED_CHANGES,
                                truetrue);

    // iterate over changes list
    for (auto const& change : rChangesList)
    {
        ExportChangedRegion(change);
    }
    // else: changes list empty -> ignore
    // else: no changes list found -> empty
}

void XMLRedlineExport::SetCurrentXText(
    const Reference<XText> & rText)
{
    if (rText.is())
    {
        // look for appropriate list in map; use the found one, or create new
        ChangesMapType::iterator aIter = aChangeMap.find(rText);
        if (aIter == aChangeMap.end())
        {
            auto rv = aChangeMap.emplace(std::piecewise_construct, std::forward_as_tuple(rText), std::forward_as_tuple());
            pCurrentChangesList = &rv.first->second;
        }
        else
            pCurrentChangesList = &aIter->second;
    }
    else
    {
        // don't record changes
        SetCurrentXText();
    }
}

void XMLRedlineExport::SetCurrentXText()
{
    pCurrentChangesList = nullptr;
}


void XMLRedlineExport::ExportChangesListElements()
{
    // get redlines (aka tracked changes) from the model
    Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY);
    if (!xSupplier.is())
        return;

    Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines();

    // redline protection key
    Reference<XPropertySet> aDocPropertySet( rExport.GetModel(),
                                             uno::UNO_QUERY );
    // redlining enabled?
    bool bEnabled = *o3tl::doAccess<bool>(aDocPropertySet->getPropertyValue(
                                            u"RecordChanges"_ustr ));

    // only export if we have redlines or attributes
    if ( !(aEnumAccess->hasElements() || bEnabled) )
        return;


    // export only if we have changes, but tracking is not enabled
    if ( !bEnabled != !aEnumAccess->hasElements() )
    {
        rExport.AddAttribute(
            XML_NAMESPACE_TEXT, XML_TRACK_CHANGES,
            bEnabled ? XML_TRUE : XML_FALSE );
    }

    // changes container element
    SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT,
                                XML_TRACKED_CHANGES,
                                truetrue);

    // get enumeration and iterate over elements
    Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration();
    while (aEnum->hasMoreElements())
    {
        Any aAny = aEnum->nextElement();
        Reference<XPropertySet> xPropSet;
        aAny >>= xPropSet;

        DBG_ASSERT(xPropSet.is(),
                   "can't get XPropertySet; skipping Redline");
        if (xPropSet.is())
        {
            // export only if not in header or footer
            // (those must be exported with their XText)
            aAny = xPropSet->getPropertyValue(u"IsInHeaderFooter"_ustr);
            if (! *o3tl::doAccess<bool>(aAny))
            {
                // and finally, export change
                ExportChangedRegion(xPropSet);
            }
        }
        // else: no XPropertySet -> no export
    }
    // else: no redlines -> no export
    // else: no XRedlineSupplier -> no export
}

void XMLRedlineExport::ExportChangeAutoStyle(
    const Reference<XPropertySet> & rPropSet)
{
    // record change (if changes should be recorded)
    if (nullptr != pCurrentChangesList)
    {
        // put redline in list if it's collapsed or the redline start
        Any aIsStart = rPropSet->getPropertyValue(u"IsStart"_ustr);
        Any aIsCollapsed = rPropSet->getPropertyValue(u"IsCollapsed"_ustr);

        if ( *o3tl::doAccess<bool>(aIsStart) ||
             *o3tl::doAccess<bool>(aIsCollapsed) )
            pCurrentChangesList->push_back(rPropSet);
    }

    // get XText for export of redline auto styles
    Any aAny = rPropSet->getPropertyValue(u"RedlineText"_ustr);
    Reference<XText> xText;
    aAny >>= xText;
    if (xText.is())
    {
        // export the auto styles
        rExport.GetTextParagraphExport()->collectTextAutoStyles(xText);
    }

    SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
    if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
    {
        // See if the format redline has an autostyle for old direct formatting: if so, export that as
        // an autostyle.
        aAny = rPropSet->getPropertyValue(u"RedlineAutoFormat"_ustr);
        uno::Reference<beans::XPropertySet> xAutoFormat;
        aAny >>= xAutoFormat;
        if (xAutoFormat.is())
        {
            // Check for parent style when declaring the automatic style.
            rExport.GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT, xAutoFormat,
                    /*aAddStates=*/{},
                    /*bCheckParent=*/true);
        }
    }
}

void XMLRedlineExport::ExportChangesListAutoStyles()
{
    // get redlines (aka tracked changes) from the model
    Reference<XRedlinesSupplier> xSupplier(rExport.GetModel(), uno::UNO_QUERY);
    if (!xSupplier.is())
        return;

    Reference<XEnumerationAccess> aEnumAccess = xSupplier->getRedlines();

    // only export if we actually have redlines
    if (!aEnumAccess->hasElements())
        return;

    // get enumeration and iterate over elements
    Reference<XEnumeration> aEnum = aEnumAccess->createEnumeration();
    while (aEnum->hasMoreElements())
    {
        Any aAny = aEnum->nextElement();
        Reference<XPropertySet> xPropSet;
        aAny >>= xPropSet;

        DBG_ASSERT(xPropSet.is(),
                   "can't get XPropertySet; skipping Redline");
        if (xPropSet.is())
        {

            // export only if not in header or footer
            // (those must be exported with their XText)
            aAny = xPropSet->getPropertyValue(u"IsInHeaderFooter"_ustr);
            if (! *o3tl::doAccess<bool>(aAny))
            {
                ExportChangeAutoStyle(xPropSet);
            }
        }
    }
}

void XMLRedlineExport::ExportChangeInline(
    const Reference<XPropertySet> & rPropSet)
{
    // determine element name (depending on collapsed, start/end)
    enum XMLTokenEnum eElement = XML_TOKEN_INVALID;
    Any aAny = rPropSet->getPropertyValue(u"IsCollapsed"_ustr);
    bool bCollapsed = *o3tl::doAccess<bool>(aAny);
    if (bCollapsed)
    {
        eElement = XML_CHANGE;
    }
    else
    {
        aAny = rPropSet->getPropertyValue(u"IsStart"_ustr);
        const bool bStart = *o3tl::doAccess<bool>(aAny);
        eElement = bStart ? XML_CHANGE_START : XML_CHANGE_END;
    }

    if (XML_TOKEN_INVALID != eElement)
    {
        // we always need the ID
        rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID,
                             GetRedlineID(rPropSet));

        // export the element (no whitespace because we're in the text body)
        SvXMLElementExport aChangeElem(rExport, XML_NAMESPACE_TEXT,
                                       eElement, falsefalse);
    }
}


void XMLRedlineExport::ExportChangedRegion(
    const Reference<XPropertySet> & rPropSet)
{
    // Redline-ID
    rExport.AddAttributeIdLegacy(XML_NAMESPACE_TEXT, GetRedlineID(rPropSet));

    // merge-last-paragraph
    Any aAny = rPropSet->getPropertyValue(u"MergeLastPara"_ustr);
    if( ! *o3tl::doAccess<bool>(aAny) )
        rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_MERGE_LAST_PARAGRAPH,
                             XML_FALSE);

    // export change region element
    SvXMLElementExport aChangedRegion(rExport, XML_NAMESPACE_TEXT,
                                      XML_CHANGED_REGION, truetrue);


    // scope for (first) change element
    {
        aAny = rPropSet->getPropertyValue(u"RedlineType"_ustr);
        OUString sType;
        aAny >>= sType;

        SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
        if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
        {
            // See if the format redline has an autostyle for old direct formatting: if so, refer to the
            // already exported autostyle.
            aAny = rPropSet->getPropertyValue(u"RedlineAutoFormat"_ustr);
            uno::Reference<beans::XPropertySet> xAutoStyle;
            aAny >>= xAutoStyle;
            if (xAutoStyle.is())
            {
                bool bIsUICharStyle;
                bool bHasAutoStyle;
                OUString aParentName;
                uno::Reference<beans::XPropertySetInfo> xPropSetInfo = xAutoStyle->getPropertySetInfo();
                if (xPropSetInfo->hasPropertyByName("CharStyleName"))
                {
                    // Consider parent style when referring to the declared automatic style.
                    xAutoStyle->getPropertyValue("CharStyleName") >>= aParentName;
                }
                OUString sStyle = rExport.GetTextParagraphExport()->FindTextStyle(
                        xAutoStyle, bIsUICharStyle, bHasAutoStyle, /*pAddState=*/nullptr, &aParentName);
                if (!sStyle.isEmpty())
                {
                    rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_STYLE_NAME, rExport.EncodeStyleName(sStyle));
                }
            }
        }

        SvXMLElementExport aChange(rExport, XML_NAMESPACE_TEXT,
                                   ConvertTypeName(sType), truetrue);

        ExportChangeInfo(rPropSet);

        // get XText from the redline and export (if the XText exists)
        aAny = rPropSet->getPropertyValue(u"RedlineText"_ustr);
        Reference<XText> xText;
        aAny >>= xText;
        // Avoid double export for format-on-delete: no write on format, only on delete.
        if (xText.is() && sType == u"Delete")
        {
            rExport.GetTextParagraphExport()->exportText(xText);
            // default parameters: bProgress, bExportParagraph ???
        }
        // else: no text interface -> content is inline and will
        //       be exported there
    }

    // changed change? Hierarchical changes can only be two levels
    // deep. Here we check for the second level.
    aAny = rPropSet->getPropertyValue(u"RedlineSuccessorData"_ustr);
    Sequence<PropertyValue> aSuccessorData;
    aAny >>= aSuccessorData;

    // if we actually got a hierarchical change, make element and
    // process change info
    if (aSuccessorData.hasElements())
    {
        // Look up the type of the change. In practice this is always insert or delete, other types
        // can't have additional redlines on top of them.
        OUString sType;
        comphelper::SequenceAsHashMap aMap(aSuccessorData);
        auto it = aMap.find("RedlineType");
        if (it != aMap.end())
        {
            it->second >>= sType;
        }
        SvXMLElementExport aSecondChangeElem(
            rExport, XML_NAMESPACE_TEXT, ConvertTypeName(sType),
            truetrue);

        ExportChangeInfo(aSuccessorData);
        it = aMap.find("RedlineText");
        if (it != aMap.end())
        {
            // Delete has its own content outside the body text: export it here.
            uno::Reference<text::XText> xText;
            it->second >>= xText;
            if (xText.is())
            {
                rExport.GetTextParagraphExport()->exportText(xText);
            }
        }
    }
    // else: no hierarchical change
}


OUString const & XMLRedlineExport::ConvertTypeName(
    std::u16string_view sApiName)
{
    if (sApiName == u"Delete")
    {
        return sDeletion;
    }
    else if (sApiName == u"Insert")
    {
        return sInsertion;
    }
    else if (sApiName == u"Format")
    {
        return sFormatChange;
    }
    else
    {
        OSL_FAIL("unknown redline type");
        static constexpr OUString sUnknownChange(u"UnknownChange"_ustr);
        return sUnknownChange;
    }
}


/** Create a Redline-ID */
OUString XMLRedlineExport::GetRedlineID(
    const Reference<XPropertySet> & rPropSet)
{
    Any aAny = rPropSet->getPropertyValue(u"RedlineIdentifier"_ustr);
    OUString sTmp;
    aAny >>= sTmp;

    return "ct" + sTmp;
}


void XMLRedlineExport::ExportChangeInfo(
    const Reference<XPropertySet> & rPropSet)
{
    bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet(
            SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet(
                SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo);

    SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE,
                                   XML_CHANGE_INFO, truetrue);

    Any aAny = rPropSet->getPropertyValue(u"RedlineAuthor"_ustr);
    OUString sTmp;
    aAny >>= sTmp;
    if (!sTmp.isEmpty())
    {
        SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC,
                                          XML_CREATOR, true,
                                          false );
        rExport.Characters(bRemovePersonalInfo
                ? "Author" + OUString::number(rExport.GetInfoID(sTmp))
                : sTmp );
    }

    aAny = rPropSet->getPropertyValue(u"RedlineMovedID"_ustr);
    sal_uInt32 nTmp(0);
    aAny >>= nTmp;
    if (nTmp > 1)
    {
        SvXMLElementExport aCreatorElem(rExport, XML_NAMESPACE_LO_EXT, XML_MOVE_ID, truefalse);
        rExport.Characters( OUString::number( nTmp ) );
    }

    aAny = rPropSet->getPropertyValue(u"RedlineDateTime"_ustr);
    util::DateTime aDateTime;
    aAny >>= aDateTime;
    {
        OUStringBuffer sBuf;
        ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo
                ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true// Epoch time
                : aDateTime, nullptr, true);
        SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC,
                                          XML_DATE, true,
                                          false );
        rExport.Characters(sBuf.makeStringAndClear());
    }

    // comment as <text:p> sequence
    aAny = rPropSet->getPropertyValue(u"RedlineComment"_ustr);
    aAny >>= sTmp;
    WriteComment( sTmp );
}

// write RedlineSuccessorData
void XMLRedlineExport::ExportChangeInfo(
    const Sequence<PropertyValue> & rPropertyValues)
{
    OUString sComment;
    bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet(
            SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet(
                SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo);

    SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE,
                                   XML_CHANGE_INFO, truetrue);

    for(const PropertyValue& rVal : rPropertyValues)
    {
        if( rVal.Name == "RedlineAuthor" )
        {
            OUString sTmp;
            rVal.Value >>= sTmp;
            if (!sTmp.isEmpty())
            {
                SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC,
                                        XML_CREATOR, true,
                                        false );
                rExport.Characters(bRemovePersonalInfo
                                        ? "Author" + OUString::number(rExport.GetInfoID(sTmp))
                                        : sTmp );
            }
        }
        else if( rVal.Name == "RedlineComment" )
        {
            rVal.Value >>= sComment;
        }
        else if( rVal.Name == "RedlineDateTime" )
        {
            util::DateTime aDateTime;
            rVal.Value >>= aDateTime;
            OUStringBuffer sBuf;
            ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo
                                        ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true// Epoch time
                                        : aDateTime, nullptr, true);
            SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC,
                                          XML_DATE, true,
                                          false );
            rExport.Characters(sBuf.makeStringAndClear());
        }
        else if( rVal.Name == "RedlineType" )
        {
            // check if this has one of the expected types
            OUString sTmp;
            rVal.Value >>= sTmp;
            DBG_ASSERT(sTmp == "Insert" || sTmp == "Delete",
                       "hierarchical change must be insertion");
        }
        // else: unknown value -> ignore
    }

    // finally write comment paragraphs
    WriteComment( sComment );
}

void XMLRedlineExport::ExportStartOrEndRedline(
    const Reference<XPropertySet> & rPropSet,
    bool bStart)
{
    if( ! rPropSet.is() )
        return;

    // get appropriate (start or end) property
    Any aAny;
    try
    {
        aAny = rPropSet->getPropertyValue(bStart ? u"StartRedline"_ustr : u"EndRedline"_ustr);
    }
    catch(const UnknownPropertyException&)
    {
        // If we don't have the property, there's nothing to do.
        return;
    }

    Sequence<PropertyValue> aValues;
    aAny >>= aValues;

    // seek for redline properties
    bool bIsCollapsed = false;
    bool bIsStart = true;
    OUString sId;
    bool bIdOK = false// have we seen an ID?
    for (const auto& rValue : aValues)
    {
        if (rValue.Name == "RedlineIdentifier")
        {
            rValue.Value >>= sId;
            bIdOK = true;
        }
        else if (rValue.Name == "IsCollapsed")
        {
            bIsCollapsed = *o3tl::doAccess<bool>(rValue.Value);
        }
        else if (rValue.Name == "IsStart")
        {
            bIsStart = *o3tl::doAccess<bool>(rValue.Value);
        }
    }

    if( !bIdOK )
        return;

    SAL_WARN_IF( sId.isEmpty(), "xmloff""Redlines must have IDs" );

    // TODO: use GetRedlineID or eliminate that function
    rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID,
                         "ct" + sId);

    // export the element
    // (whitespace because we're not inside paragraphs)
    SvXMLElementExport aChangeElem(
        rExport, XML_NAMESPACE_TEXT,
        bIsCollapsed ? XML_CHANGE :
            ( bIsStart ? XML_CHANGE_START : XML_CHANGE_END ),
        truetrue);
}

void XMLRedlineExport::ExportStartOrEndRedline(
    const Reference<XTextContent> & rContent,
    bool bStart)
{
    Reference<XPropertySet> xPropSet(rContent, uno::UNO_QUERY);
    if (xPropSet.is())
    {
        ExportStartOrEndRedline(xPropSet, bStart);
    }
    else
    {
        OSL_FAIL("XPropertySet expected");
    }
}

void XMLRedlineExport::ExportStartOrEndRedline(
    const Reference<XTextSection> & rSection,
    bool bStart)
{
    Reference<XPropertySet> xPropSet(rSection, uno::UNO_QUERY);
    if (xPropSet.is())
    {
        ExportStartOrEndRedline(xPropSet, bStart);
    }
    else
    {
        OSL_FAIL("XPropertySet expected");
    }
}

void XMLRedlineExport::WriteComment(std::u16string_view rComment)
{
    if (rComment.empty())
        return;

    // iterate over all string-pieces separated by return (0x0a) and
    // put each inside a paragraph element.
    SvXMLTokenEnumerator aEnumerator(rComment, char(0x0a));
    std::u16string_view aSubString;
    while (aEnumerator.getNextToken(aSubString))
    {
        SvXMLElementExport aParagraph(
            rExport, XML_NAMESPACE_TEXT, XML_P, truefalse);
        rExport.Characters(OUString(aSubString));
    }
}

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

Messung V0.5
C=92 H=97 G=94

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© 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.