/* -*- 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/.
*/
// Our mathml #include <mathml/import.hxx>
// LO tools to use #include <com/sun/star/beans/PropertyAttribute.hpp> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/packages/WrongPasswordException.hpp> #include <com/sun/star/packages/zip/ZipIOException.hpp> #include <com/sun/star/task/XStatusIndicator.hpp> #include <com/sun/star/xml/sax/FastParser.hpp> #include <com/sun/star/xml/sax/InputSource.hpp> #include <com/sun/star/xml/sax/Parser.hpp> #include <com/sun/star/xml/sax/SAXParseException.hpp>
ErrCode SmMLImportWrapper::Import(SfxMedium& rMedium)
{ // Fetch context const uno::Reference<uno::XComponentContext>& xContext(
comphelper::getProcessComponentContext()); if (!xContext.is())
{
SAL_WARN("starmath", "Failed to fetch model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Check model if (!m_xModel.is())
{
SAL_WARN("starmath", "Failed to fetch model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Try to get an XStatusIndicator from the Medium
uno::Reference<task::XStatusIndicator> xStatusIndicator;
// Get model via uno
SmModel* pModel = m_xModel.get(); if (pModel == nullptr)
{
SAL_WARN("starmath", "Failed to fetch sm model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Get doc shell
m_pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell()); if (m_pDocShell == nullptr)
{
SAL_WARN("starmath", "Failed to fetch smdoc shell while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Check if it is an embed object bool bEmbedded = m_pDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
if (!bEmbedded)
{ // Extra check to ensure everything is fine if (m_pDocShell->GetMedium() != &rMedium)
{
SAL_WARN("starmath", "Given medium and doc shell medium differ while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Fetch the item set const SfxUnoAnyItem* pItem = rMedium.GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL); if (pItem != nullptr)
pItem->GetValue() >>= xStatusIndicator;
}
// Set base URI // needed for relative URLs; but it's OK to import e.g. MathML from the clipboard without one
SAL_INFO_IF(rMedium.GetBaseURL().isEmpty(), "starmath", "SmMLImportWrapper: no base URL");
xInfoSet->setPropertyValue(u"BaseURI"_ustr, Any(rMedium.GetBaseURL()));
// Fetch progress range
sal_Int32 nProgressRange(rMedium.IsStorage() ? 3 : 1); if (xStatusIndicator.is())
{
xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
xStatusIndicator->setValue(0);
}
// Get storage if (rMedium.IsStorage())
{ // TODO/LATER: handle the case of embedded links gracefully if (bEmbedded) // && !rMedium.GetStorage()->IsRoot() )
{
OUString aName(u"dummyObjName"_ustr); const SfxStringItem* pDocHierarchItem
= rMedium.GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME); if (pDocHierarchItem != nullptr)
aName = pDocHierarchItem->GetValue();
if (!aName.isEmpty())
xInfoSet->setPropertyValue(u"StreamRelPath"_ustr, Any(aName));
}
// Check if use OASIS ( new document format ) bool bOASIS = SotStorage::GetVersion(rMedium.GetStorage()) > SOFFICE_FILEFORMAT_60; if (xStatusIndicator.is())
xStatusIndicator->setValue(1);
// Error code in case of needed
ErrCode nWarn = ERRCODE_NONE;
// Read metadata // read a component from storage if (!bEmbedded)
{ if (bOASIS)
nWarn = ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"meta.xml", xContext,
xInfoSet,
u"com.sun.star.comp.Math.MLOasisMetaImporter", 6); else
nWarn
= ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"meta.xml", xContext,
xInfoSet, u"com.sun.star.comp.Math.XMLMetaImporter", 5);
}
// Check if successful if (nWarn != ERRCODE_NONE)
{ if (xStatusIndicator.is())
xStatusIndicator->end();
SAL_WARN("starmath", "Failed to read file"); return nWarn;
}
// Increase success indicator if (xStatusIndicator.is())
xStatusIndicator->setValue(2);
// Read settings // read a component from storage if (bOASIS)
nWarn = ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"settings.xml", xContext,
xInfoSet,
u"com.sun.star.comp.Math.MLOasisSettingsImporter", 6); else
nWarn
= ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"settings.xml", xContext,
xInfoSet, u"com.sun.star.comp.Math.XMLSettingsImporter", 5);
// Check if successful if (nWarn != ERRCODE_NONE)
{ if (xStatusIndicator.is())
xStatusIndicator->end();
SAL_WARN("starmath", "Failed to read file"); return nWarn;
}
// Increase success indicator if (xStatusIndicator.is())
xStatusIndicator->setValue(3);
// Read document // read a component from storage if (m_pDocShell->GetSmSyntaxVersion() == 5)
nWarn = ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"content.xml", xContext,
xInfoSet, u"com.sun.star.comp.Math.XMLImporter", 5); else
nWarn = ReadThroughComponentS(rMedium.GetStorage(), m_xModel, u"content.xml", xContext,
xInfoSet, u"com.sun.star.comp.Math.MLImporter", 6); // Check if successful if (nWarn != ERRCODE_NONE)
{ if (xStatusIndicator.is())
xStatusIndicator->end();
SAL_WARN("starmath", "Failed to read file"); return nWarn;
}
// Finish if (xStatusIndicator.is())
xStatusIndicator->end(); return ERRCODE_NONE;
} else
{ // Create input stream
Reference<io::XInputStream> xInputStream
= new utl::OInputStreamWrapper(rMedium.GetInStream());
// Increase success indicator if (xStatusIndicator.is())
xStatusIndicator->setValue(1);
// Read data // read a component from input stream
ErrCode nError = ERRCODE_NONE; if (m_pDocShell->GetSmSyntaxVersion() == 5)
nError = ReadThroughComponentIS(xInputStream, m_xModel, xContext, xInfoSet,
u"com.sun.star.comp.Math.XMLImporter", false, 5); else
nError = ReadThroughComponentIS(xInputStream, m_xModel, xContext, xInfoSet,
u"com.sun.star.comp.Math.MLImporter", false, 6);
// Finish if (xStatusIndicator.is())
xStatusIndicator->end();
// Declare any error if (nError != ERRCODE_NONE)
SAL_WARN("starmath", "Failed to read file");
return nError;
}
}
ErrCode SmMLImportWrapper::Import(std::u16string_view aSource)
{ // Fetch context const uno::Reference<uno::XComponentContext>& xContext(
comphelper::getProcessComponentContext()); if (!xContext.is())
{
SAL_WARN("starmath", "Failed to fetch model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Check model if (!m_xModel.is())
{
SAL_WARN("starmath", "Failed to fetch model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Get model via uno
SmModel* pModel = m_xModel.get(); if (pModel == nullptr)
{
SAL_WARN("starmath", "Failed to fetch sm model while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Get doc shell
m_pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell()); if (m_pDocShell == nullptr)
{
SAL_WARN("starmath", "Failed to fetch smdoc shell while file input"); return ERRCODE_SFX_DOLOADFAILED;
}
// Read data // read a component from text
ErrCode nError = ReadThroughComponentMS(aSource, uno::Reference<lang::XComponent>(m_xModel),
xContext, xInfoSet);
// Declare any error if (nError != ERRCODE_NONE)
{
SAL_WARN("starmath", "Failed to read file"); return nError;
}
return ERRCODE_NONE;
}
// read a component from input stream
ErrCode SmMLImportWrapper::ReadThroughComponentIS( const Reference<io::XInputStream>& xInputStream, const Reference<XComponent>& xModelComponent,
Reference<uno::XComponentContext> const& rxContext,
Reference<beans::XPropertySet> const& rPropSet, const char16_t* pFilterName, bool bEncrypted,
int_fast16_t nSyntaxVersion)
{ // Needs an input stream but checked by caller // Needs a context but checked by caller // Needs property set but checked by caller // Needs a filter name but checked by caller
if (nSyntaxVersion == 5)
{
SmXMLImport* pXMlImport = dynamic_cast<SmXMLImport*>(xFilter.get()); if (pXMlImport != nullptr && pXMlImport->GetSuccess()) return ERRCODE_NONE; else
{
SAL_WARN("starmath", "Filter failed on file input"); // However this can not be included since it's not public if (pXMlImport == nullptr) return ERRCODE_NONE; return ERRCODE_SFX_DOLOADFAILED;
}
}
m_pMlImport = dynamic_cast<SmMLImport*>(xFilter.get()); if (m_pMlImport != nullptr && m_pMlImport->getSuccess()) return ERRCODE_NONE; else
{
SAL_WARN("starmath", "Filter failed on file input"); return ERRCODE_SFX_DOLOADFAILED;
}
} catch (const xml::sax::SAXParseException& r)
{ // Sax parser sends wrapped exceptions, try to find the original one
xml::sax::SAXException aTmp;
xml::sax::SAXException aSaxEx = *static_cast<const xml::sax::SAXException*>(&r); while (aSaxEx.WrappedException >>= aTmp)
aSaxEx = aTmp;
packages::zip::ZipIOException aBrokenPackage; if (aSaxEx.WrappedException >>= aBrokenPackage)
{
SAL_WARN("starmath", "Failed to read file SAXParseException"); return ERRCODE_IO_BROKENPACKAGE;
}
// read a component from storage
ErrCode SmMLImportWrapper::ReadThroughComponentS(const uno::Reference<embed::XStorage>& xStorage, const Reference<XComponent>& xModelComponent, const char16_t* pStreamName,
Reference<uno::XComponentContext> const& rxContext,
Reference<beans::XPropertySet> const& rPropSet, const char16_t* pFilterName,
int_fast16_t nSyntaxVersion)
{ // Needs a storage but checked by caller // Needs a model but checked by caller // Needs a stream name but checked by caller // Needs a context but checked by caller // Needs a property set but checked by caller // Needs a filter name but checked by caller
// Get the input stream try
{ // Create the stream for the event read
uno::Reference<io::XStream> xEventsStream
= xStorage->openStreamElement(OUString(pStreamName), embed::ElementModes::READ);
// Determine if stream is encrypted or not
uno::Reference<beans::XPropertySet> xProps(xEventsStream, uno::UNO_QUERY);
Any aAny = xProps->getPropertyValue(u"Encrypted"_ustr); bool bEncrypted = false;
aAny >>= bEncrypted;
// Set base URL and open stream
rPropSet->setPropertyValue(u"StreamName"_ustr, Any(OUString(pStreamName)));
Reference<io::XInputStream> xStream = xEventsStream->getInputStream();
// read a component from text
ErrCode SmMLImportWrapper::ReadThroughComponentMS(
std::u16string_view aText, const css::uno::Reference<css::lang::XComponent>& xModelComponent,
css::uno::Reference<css::uno::XComponentContext> const& rxContext,
css::uno::Reference<css::beans::XPropertySet> const& rPropSet)
{ // Needs a storage but checked by caller // Needs a model but checked by caller // Needs a stream name but checked by caller // Needs a context but checked by caller // Needs a property set but checked by caller // Needs a filter name but checked by caller
// Get the input stream try
{ // Generate input memory stream
SvMemoryStream aMemoryStream;
aMemoryStream.WriteOString(OUStringToOString(aText, RTL_TEXTENCODING_UTF8));
uno::Reference<io::XInputStream> xStream(new utl::OInputStreamWrapper(aMemoryStream));
void SmMLImportContext::inheritStyle()
{ while ((m_pStyle = m_pStyle->getParentElement()) != nullptr)
{ if (m_pStyle->getParentElement()->getMlElementType() == SmMlElementType::MlMstyle
|| m_pStyle->getParentElement()->getMlElementType() == SmMlElementType::MlMath) break;
}
// Parent inheritation // Mathcolor, mathsize, dir and displaystyle are inherited from parent
SmMlElement* pParent = *m_pParent;
m_pElement->setAttribute(pParent->getAttribute(SmMlAttributeValueType::MlMathcolor));
m_pElement->setAttribute(pParent->getAttribute(SmMlAttributeValueType::MlMathsize));
m_pElement->setAttribute(pParent->getAttribute(SmMlAttributeValueType::MlDir));
m_pElement->setAttribute(pParent->getAttribute(SmMlAttributeValueType::MlDisplaystyle));
// Inherit operator dictionary overwrites if (m_pStyle != nullptr
&& (m_pElement->getMlElementType() == SmMlElementType::MlMo
|| m_pElement->getMlElementType() == SmMlElementType::MlMstyle
|| m_pElement->getMlElementType() == SmMlElementType::MlMath))
{ // TODO fetch operator dictionary first and then overwrite if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlAccent))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlAccent)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlFence))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlFence)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlLspace))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlLspace)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlMaxsize))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlMaxsize)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlMinsize))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlMinsize)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlMovablelimits))
m_pElement->setAttribute(
m_pStyle->getAttribute(SmMlAttributeValueType::MlMovablelimits)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlRspace))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlRspace)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlSeparator))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlSeparator)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlStretchy))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlStretchy)); if (m_pStyle->isAttributeSet(SmMlAttributeValueType::MlSymmetric))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlSymmetric));
if (m_pElement->getMlElementType() == SmMlElementType::MlMo)
{ // Set form based in position
SmMlAttribute aAttribute(SmMlAttributeValueType::MlForm);
SmMlForm aForm; if (m_pElement->getSubElementId() == 0)
aForm = { SmMlAttributeValueForm::MlPrefix }; else
aForm = { SmMlAttributeValueForm::MlInfix };
aAttribute.setMlForm(&aForm);
m_pElement->setAttribute(aAttribute);
}
}
// Inherit mathvariant if (m_pStyle && m_pStyle->isAttributeSet(SmMlAttributeValueType::MlMathvariant))
m_pElement->setAttribute(m_pStyle->getAttribute(SmMlAttributeValueType::MlMathvariant));
}
void SmMLImportContext::inheritStyleEnd()
{ // Mo: check it is the end: postfix if (m_pElement->getMlElementType() == SmMlElementType::MlMo)
{ if ((*m_pParent)->getSubElementsCount() == m_pElement->getSubElementId())
{ // Set form based in position
SmMlAttribute aAttribute(SmMlAttributeValueType::MlForm);
SmMlForm aForm = { SmMlAttributeValueForm::MlPosfix };
aAttribute.setMlForm(&aForm);
m_pElement->setAttribute(aAttribute);
}
}
// Inherit mathvariant if (!m_pStyle->isAttributeSet(SmMlAttributeValueType::MlMathvariant))
{
sal_Int32 nIndexUtf16 = 0; // Check if there is only one code point
m_pElement->getText().iterateCodePoints(&nIndexUtf16, 1); // Mathml says that 1 code point -> italic if (nIndexUtf16 == m_pElement->getText().getLength())
{
SmMlAttribute aAttribute(SmMlAttributeValueType::MlMathvariant);
SmMlMathvariant aMathvariant = { SmMlAttributeValueMathvariant::italic };
aAttribute.setMlMathvariant(&aMathvariant);
aAttribute.setSet(false);
m_pElement->setAttribute(aAttribute);
}
}
}
switch (nElement)
{ case XML_ELEMENT(OFFICE, XML_DOCUMENT):
{ if (m_pElementTree == nullptr)
m_pElementTree = new SmMlElement(SmMlElementType::NMlEmpty);
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(),
uno::UNO_QUERY_THROW);
pContext = new SmMLImportContext(*this, &m_pElementTree); break;
} case XML_ELEMENT(OFFICE, XML_DOCUMENT_META):
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(),
uno::UNO_QUERY_THROW);
pContext = new SvXMLMetaDocumentContext(*this, xDPS->getDocumentProperties()); break;
} case XML_ELEMENT(OFFICE, XML_DOCUMENT_SETTINGS):
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(),
uno::UNO_QUERY_THROW);
pContext = new XMLDocumentSettingsContext(*this); break;
} default:
declareMlError(); break;
} return pContext;
}
void SmMLImport::endDocument()
{
uno::Reference<frame::XModel> xModel = GetModel(); if (!xModel.is())
{
SAL_WARN("starmath", "Failed to set view settings because missing model");
SvXMLImport::endDocument(); return;
}
SmModel* pModel = comphelper::getFromUnoTunnel<SmModel>(xModel); if (!pModel)
{
SAL_WARN("starmath", "Failed to set view settings because missing sm model");
SvXMLImport::endDocument(); return;
}
SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell()); if (!pDocShell)
{
SAL_WARN("starmath", "Failed to set view settings because missing sm doc shell");
SvXMLImport::endDocument(); return;
}
// Check if there is element tree if (m_pElementTree == nullptr)
{
m_bSuccess = true;
SvXMLImport::endDocument(); return;
}
void SmMLImport::SetViewSettings(const Sequence<PropertyValue>& aViewProps)
{
uno::Reference<frame::XModel> xModel = GetModel(); if (!xModel.is())
{
SAL_WARN("starmath", "Failed to set view settings because missing model"); return;
}
SmModel* pModel = comphelper::getFromUnoTunnel<SmModel>(xModel); if (!pModel)
{
SAL_WARN("starmath", "Failed to set view settings because missing sm model"); return;
}
SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell()); if (!pDocShell)
{
SAL_WARN("starmath", "Failed to set view settings because missing sm doc shell"); return;
}
void SmMLImport::SetConfigurationSettings(const Sequence<PropertyValue>& aConfProps)
{
uno::Reference<frame::XModel> xModel = GetModel(); if (!xModel.is())
{
SAL_WARN("starmath", "Failed to set view settings because missing model"); return;
}
uno::Reference<XPropertySet> xProps(xModel, UNO_QUERY); if (!xProps.is())
{
SAL_WARN("starmath", "Failed to set view settings because missing model properties"); return;
}
Reference<XPropertySetInfo> xInfo(xProps->getPropertySetInfo()); if (!xInfo.is())
{
SAL_WARN("starmath", "Failed to set view settings because missing model properties information"); return;
}
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.