android: Update app-specific/MIME type icons
[LibreOffice.git] / comphelper / source / misc / mimeconfighelper.cxx
blob7f402b6351ec9ce20d2763832f6c72e6f245a7df
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/PropertyValue.hpp>
21 #include <com/sun/star/configuration/theDefaultProvider.hpp>
22 #include <com/sun/star/container/XContainerQuery.hpp>
23 #include <com/sun/star/container/XNameAccess.hpp>
24 #include <com/sun/star/embed/VerbDescriptor.hpp>
25 #include <com/sun/star/document/XTypeDetection.hpp>
27 #include <osl/diagnose.h>
29 #include <comphelper/fileformat.h>
30 #include <comphelper/mimeconfighelper.hxx>
31 #include <comphelper/classids.hxx>
32 #include <comphelper/sequenceashashmap.hxx>
33 #include <comphelper/documentconstants.hxx>
34 #include <comphelper/propertysequence.hxx>
35 #include <rtl/ustrbuf.hxx>
36 #include <utility>
39 using namespace ::com::sun::star;
40 using namespace comphelper;
43 MimeConfigurationHelper::MimeConfigurationHelper( uno::Reference< uno::XComponentContext > xContext )
44 : m_xContext(std::move( xContext ))
46 if ( !m_xContext.is() )
47 throw uno::RuntimeException();
51 OUString MimeConfigurationHelper::GetStringClassIDRepresentation( const uno::Sequence< sal_Int8 >& aClassID )
53 OUStringBuffer aResult;
55 if ( aClassID.getLength() == 16 )
57 for ( sal_Int32 nInd = 0; nInd < aClassID.getLength(); nInd++ )
59 if ( nInd == 4 || nInd == 6 || nInd == 8 || nInd == 10 )
60 aResult.append("-");
62 sal_Int32 nDigit1 = static_cast<sal_Int32>( static_cast<sal_uInt8>(aClassID[nInd]) / 16 );
63 sal_Int32 nDigit2 = static_cast<sal_uInt8>(aClassID[nInd]) % 16;
64 aResult.append( OUString::number(nDigit1, 16) + OUString::number( nDigit2, 16 ) );
68 return aResult.makeStringAndClear();
72 static sal_uInt8 GetDigit_Impl( char aChar )
74 if ( aChar >= '0' && aChar <= '9' )
75 return aChar - '0';
76 else if ( aChar >= 'a' && aChar <= 'f' )
77 return aChar - 'a' + 10;
78 else if ( aChar >= 'A' && aChar <= 'F' )
79 return aChar - 'A' + 10;
80 else
81 return 16;
85 uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassIDRepresentation( std::u16string_view aClassID )
87 size_t nLength = aClassID.size();
88 if ( nLength == 36 )
90 OString aCharClassID = OUStringToOString( aClassID, RTL_TEXTENCODING_ASCII_US );
91 uno::Sequence< sal_Int8 > aResult( 16 );
92 auto pResult = aResult.getArray();
94 size_t nStrPointer = 0;
95 sal_Int32 nSeqInd = 0;
96 while( nSeqInd < 16 && nStrPointer + 1U < nLength )
98 sal_uInt8 nDigit1 = GetDigit_Impl( aCharClassID[nStrPointer++] );
99 sal_uInt8 nDigit2 = GetDigit_Impl( aCharClassID[nStrPointer++] );
101 if ( nDigit1 > 15 || nDigit2 > 15 )
102 break;
104 pResult[nSeqInd++] = static_cast<sal_Int8>( nDigit1 * 16 + nDigit2 );
106 if ( nStrPointer < nLength && aCharClassID[nStrPointer] == '-' )
107 nStrPointer++;
110 if ( nSeqInd == 16 && nStrPointer == nLength )
111 return aResult;
114 return uno::Sequence< sal_Int8 >();
118 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetConfigurationByPathImpl( const OUString& aPath )
120 uno::Reference< container::XNameAccess > xConfig;
124 if ( !m_xConfigProvider.is() )
125 m_xConfigProvider = configuration::theDefaultProvider::get( m_xContext );
127 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
129 {"nodepath", uno::Any(aPath)}
130 }));
131 xConfig.set( m_xConfigProvider->createInstanceWithArguments(
132 "com.sun.star.configuration.ConfigurationAccess",
133 aArgs ),
134 uno::UNO_QUERY );
136 catch( uno::Exception& )
139 return xConfig;
143 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetObjConfiguration()
145 std::unique_lock aGuard( m_aMutex );
147 if ( !m_xObjectConfig.is() )
148 m_xObjectConfig = GetConfigurationByPathImpl(
149 "/org.openoffice.Office.Embedding/Objects" );
151 return m_xObjectConfig;
155 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetVerbsConfiguration()
157 std::unique_lock aGuard( m_aMutex );
159 if ( !m_xVerbsConfig.is() )
160 m_xVerbsConfig = GetConfigurationByPathImpl(
161 "/org.openoffice.Office.Embedding/Verbs");
163 return m_xVerbsConfig;
167 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetMediaTypeConfiguration()
169 std::unique_lock aGuard( m_aMutex );
171 if ( !m_xMediaTypeConfig.is() )
172 m_xMediaTypeConfig = GetConfigurationByPathImpl(
173 "/org.openoffice.Office.Embedding/MimeTypeClassIDRelations");
175 return m_xMediaTypeConfig;
179 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetFilterFactory()
181 std::unique_lock aGuard( m_aMutex );
183 if ( !m_xFilterFactory.is() )
184 m_xFilterFactory.set(
185 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext),
186 uno::UNO_QUERY );
188 return m_xFilterFactory;
192 OUString MimeConfigurationHelper::GetDocServiceNameFromFilter( const OUString& aFilterName )
194 OUString aDocServiceName;
198 uno::Reference< container::XNameAccess > xFilterFactory(
199 GetFilterFactory(),
200 uno::UNO_SET_THROW );
202 uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName );
203 uno::Sequence< beans::PropertyValue > aFilterData;
204 if ( aFilterAnyData >>= aFilterData )
206 for ( const auto & prop : std::as_const(aFilterData) )
207 if ( prop.Name == "DocumentService" )
208 prop.Value >>= aDocServiceName;
211 catch( uno::Exception& )
214 return aDocServiceName;
218 OUString MimeConfigurationHelper::GetDocServiceNameFromMediaType( const OUString& aMediaType )
220 uno::Reference< container::XContainerQuery > xTypeCFG(
221 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_xContext),
222 uno::UNO_QUERY );
224 if ( xTypeCFG.is() )
228 // make query for all types matching the properties
229 uno::Sequence < beans::NamedValue > aSeq { { "MediaType", css::uno::Any(aMediaType) } };
231 uno::Reference < container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq );
232 while ( xEnum->hasMoreElements() )
234 uno::Sequence< beans::PropertyValue > aType;
235 if ( xEnum->nextElement() >>= aType )
237 for ( const auto & prop : std::as_const(aType) )
239 OUString aFilterName;
240 if ( prop.Name == "PreferredFilter"
241 && ( prop.Value >>= aFilterName ) && !aFilterName.isEmpty() )
243 OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName );
244 if ( !aDocumentName.isEmpty() )
245 return aDocumentName;
251 catch( uno::Exception& )
255 return OUString();
259 bool MimeConfigurationHelper::GetVerbByShortcut( const OUString& aVerbShortcut,
260 embed::VerbDescriptor& aDescriptor )
262 bool bResult = false;
264 uno::Reference< container::XNameAccess > xVerbsConfig = GetVerbsConfiguration();
265 uno::Reference< container::XNameAccess > xVerbsProps;
268 if ( xVerbsConfig.is() && ( xVerbsConfig->getByName( aVerbShortcut ) >>= xVerbsProps ) && xVerbsProps.is() )
270 embed::VerbDescriptor aTempDescr;
271 static constexpr OUStringLiteral sVerbID = u"VerbID";
272 static constexpr OUStringLiteral sVerbUIName = u"VerbUIName";
273 static constexpr OUStringLiteral sVerbFlags = u"VerbFlags";
274 static constexpr OUStringLiteral sVerbAttributes = u"VerbAttributes";
275 if ( ( xVerbsProps->getByName(sVerbID) >>= aTempDescr.VerbID )
276 && ( xVerbsProps->getByName(sVerbUIName) >>= aTempDescr.VerbName )
277 && ( xVerbsProps->getByName(sVerbFlags) >>= aTempDescr.VerbFlags )
278 && ( xVerbsProps->getByName(sVerbAttributes) >>= aTempDescr.VerbAttributes ) )
280 aDescriptor = aTempDescr;
281 bResult = true;
285 catch( uno::Exception& )
289 return bResult;
293 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjPropsFromConfigEntry(
294 const uno::Sequence< sal_Int8 >& aClassID,
295 const uno::Reference< container::XNameAccess >& xObjectProps )
297 uno::Sequence< beans::NamedValue > aResult;
299 if ( aClassID.getLength() == 16 )
303 const uno::Sequence< OUString > aObjPropNames = xObjectProps->getElementNames();
305 aResult.realloc( aObjPropNames.getLength() + 1 );
306 auto pResult = aResult.getArray();
307 pResult[0].Name = "ClassID";
308 pResult[0].Value <<= aClassID;
310 for ( sal_Int32 nInd = 0; nInd < aObjPropNames.getLength(); nInd++ )
312 pResult[nInd + 1].Name = aObjPropNames[nInd];
314 if ( aObjPropNames[nInd] == "ObjectVerbs" )
316 uno::Sequence< OUString > aVerbShortcuts;
317 if ( !(xObjectProps->getByName( aObjPropNames[nInd] ) >>= aVerbShortcuts) )
318 throw uno::RuntimeException();
319 uno::Sequence< embed::VerbDescriptor > aVerbDescriptors( aVerbShortcuts.getLength() );
320 auto aVerbDescriptorsRange = asNonConstRange(aVerbDescriptors);
321 for ( sal_Int32 nVerbI = 0; nVerbI < aVerbShortcuts.getLength(); nVerbI++ )
322 if ( !GetVerbByShortcut( aVerbShortcuts[nVerbI], aVerbDescriptorsRange[nVerbI] ) )
323 throw uno::RuntimeException();
325 pResult[nInd+1].Value <<= aVerbDescriptors;
327 else
328 pResult[nInd+1].Value = xObjectProps->getByName( aObjPropNames[nInd] );
331 catch( uno::Exception& )
333 aResult.realloc( 0 );
337 return aResult;
341 OUString MimeConfigurationHelper::GetExplicitlyRegisteredObjClassID( const OUString& aMediaType )
343 OUString aStringClassID;
345 uno::Reference< container::XNameAccess > xMediaTypeConfig = GetMediaTypeConfiguration();
348 if ( xMediaTypeConfig.is() )
349 xMediaTypeConfig->getByName( aMediaType ) >>= aStringClassID;
351 catch( uno::Exception& )
355 return aStringClassID;
360 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByStringClassID(
361 const OUString& aStringClassID )
363 uno::Sequence< beans::NamedValue > aObjProps;
365 uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID );
366 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
368 aObjProps = { { "ObjectFactory",
369 uno::Any(OUString("com.sun.star.embed.OOoSpecialEmbeddedObjectFactory")) },
370 { "ClassID", uno::Any(aClassID) } };
371 return aObjProps;
374 if ( aClassID.getLength() == 16 )
376 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
377 uno::Reference< container::XNameAccess > xObjectProps;
380 // TODO/LATER: allow to provide ClassID string in any format, only digits are counted
381 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
382 aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps );
384 catch( uno::Exception& )
389 return aObjProps;
393 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByClassID(
394 const uno::Sequence< sal_Int8 >& aClassID )
396 uno::Sequence< beans::NamedValue > aObjProps;
397 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
399 aObjProps = { { "ObjectFactory",
400 uno::Any(OUString("com.sun.star.embed.OOoSpecialEmbeddedObjectFactory")) },
401 { "ClassID", uno::Any(aClassID) } };
404 OUString aStringClassID = GetStringClassIDRepresentation( aClassID );
405 if ( !aStringClassID.isEmpty() )
407 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
408 uno::Reference< container::XNameAccess > xObjectProps;
411 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
412 aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps );
414 catch( uno::Exception& )
419 return aObjProps;
423 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByMediaType( const OUString& aMediaType )
425 uno::Sequence< beans::NamedValue > aObject =
426 GetObjectPropsByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) );
427 if ( aObject.hasElements() )
428 return aObject;
430 OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType );
431 if ( !aDocumentName.isEmpty() )
432 return GetObjectPropsByDocumentName( aDocumentName );
434 return uno::Sequence< beans::NamedValue >();
438 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByFilter( const OUString& aFilterName )
440 OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName );
441 if ( !aDocumentName.isEmpty() )
442 return GetObjectPropsByDocumentName( aDocumentName );
444 return uno::Sequence< beans::NamedValue >();
448 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByDocumentName( std::u16string_view aDocName )
450 if ( !aDocName.empty() )
452 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
453 if ( xObjConfig.is() )
457 const uno::Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
458 for ( const OUString & id : aClassIDs )
460 uno::Reference< container::XNameAccess > xObjectProps;
461 OUString aEntryDocName;
463 if ( ( xObjConfig->getByName( id ) >>= xObjectProps ) && xObjectProps.is()
464 && ( xObjectProps->getByName("ObjectDocumentServiceName") >>= aEntryDocName )
465 && aEntryDocName == aDocName )
467 return GetObjPropsFromConfigEntry( GetSequenceClassIDRepresentation( id ),
468 xObjectProps );
472 catch( uno::Exception& )
477 return uno::Sequence< beans::NamedValue >();
481 OUString MimeConfigurationHelper::GetFactoryNameByClassID( const uno::Sequence< sal_Int8 >& aClassID )
483 return GetFactoryNameByStringClassID( GetStringClassIDRepresentation( aClassID ) );
487 OUString MimeConfigurationHelper::GetFactoryNameByStringClassID( const OUString& aStringClassID )
489 OUString aResult;
491 if ( !aStringClassID.isEmpty() )
493 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
494 uno::Reference< container::XNameAccess > xObjectProps;
497 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
498 xObjectProps->getByName("ObjectFactory") >>= aResult;
500 catch( uno::Exception& )
502 uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID );
503 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
504 return "com.sun.star.embed.OOoSpecialEmbeddedObjectFactory";
508 return aResult;
512 OUString MimeConfigurationHelper::GetFactoryNameByDocumentName( std::u16string_view aDocName )
514 OUString aResult;
516 if ( !aDocName.empty() )
518 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
519 if ( xObjConfig.is() )
523 const uno::Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
524 for ( const OUString & id : aClassIDs )
526 uno::Reference< container::XNameAccess > xObjectProps;
527 OUString aEntryDocName;
529 if ( ( xObjConfig->getByName( id ) >>= xObjectProps ) && xObjectProps.is()
530 && ( xObjectProps->getByName( "ObjectDocumentServiceName" ) >>= aEntryDocName )
531 && aEntryDocName == aDocName )
533 xObjectProps->getByName("ObjectFactory") >>= aResult;
534 break;
538 catch( uno::Exception& )
543 return aResult;
547 OUString MimeConfigurationHelper::GetFactoryNameByMediaType( const OUString& aMediaType )
549 OUString aResult = GetFactoryNameByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) );
551 if ( aResult.isEmpty() )
553 OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType );
554 if ( !aDocumentName.isEmpty() )
555 aResult = GetFactoryNameByDocumentName( aDocumentName );
558 return aResult;
562 OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName(
563 uno::Sequence< beans::PropertyValue >& aMediaDescr,
564 bool bIgnoreType )
566 OUString aFilterName;
568 for ( const auto & prop : std::as_const(aMediaDescr) )
569 if ( prop.Name == "FilterName" )
570 prop.Value >>= aFilterName;
572 if ( aFilterName.isEmpty() )
574 // filter name is not specified, so type detection should be done
576 uno::Reference< document::XTypeDetection > xTypeDetection(
577 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_xContext),
578 uno::UNO_QUERY_THROW );
580 // typedetection can change the mode, add a stream and so on, thus a copy should be used
581 uno::Sequence< beans::PropertyValue > aTempMD( aMediaDescr );
583 // get TypeName
584 OUString aTypeName = xTypeDetection->queryTypeByDescriptor( aTempMD, true );
586 // get FilterName
587 for ( const auto & prop : std::as_const(aTempMD) )
588 if ( prop.Name == "FilterName" )
589 prop.Value >>= aFilterName;
591 if ( !aFilterName.isEmpty() )
593 sal_Int32 nOldLen = aMediaDescr.getLength();
594 aMediaDescr.realloc( nOldLen + 1 );
595 auto pMediaDescr = aMediaDescr.getArray();
596 pMediaDescr[nOldLen].Name = "FilterName";
597 pMediaDescr[ nOldLen ].Value <<= aFilterName;
600 else if ( !aTypeName.isEmpty() && !bIgnoreType )
602 uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY );
603 uno::Sequence< beans::PropertyValue > aTypes;
605 if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
607 for ( const auto & prop : std::as_const(aTypes) )
609 if ( prop.Name == "PreferredFilter" && ( prop.Value >>= aFilterName ) )
611 sal_Int32 nOldLen = aMediaDescr.getLength();
612 aMediaDescr.realloc( nOldLen + 1 );
613 auto pMediaDescr = aMediaDescr.getArray();
614 pMediaDescr[nOldLen].Name = "FilterName";
615 pMediaDescr[ nOldLen ].Value = prop.Value;
616 break;
623 return aFilterName;
626 OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName(
627 uno::Sequence< beans::PropertyValue >& aMediaDescr,
628 uno::Sequence< beans::NamedValue >& aObject )
630 OUString aDocName;
631 for ( const auto & nv : std::as_const(aObject) )
632 if ( nv.Name == "ObjectDocumentServiceName" )
634 nv.Value >>= aDocName;
635 break;
638 OSL_ENSURE( !aDocName.isEmpty(), "The name must exist at this point!" );
641 bool bNeedsAddition = true;
642 for ( sal_Int32 nMedInd = 0; nMedInd < aMediaDescr.getLength(); nMedInd++ )
643 if ( aMediaDescr[nMedInd].Name == "DocumentService" )
645 aMediaDescr.getArray()[nMedInd].Value <<= aDocName;
646 bNeedsAddition = false;
647 break;
650 if ( bNeedsAddition )
652 sal_Int32 nOldLen = aMediaDescr.getLength();
653 aMediaDescr.realloc( nOldLen + 1 );
654 auto pMediaDescr = aMediaDescr.getArray();
655 pMediaDescr[nOldLen].Name = "DocumentService";
656 pMediaDescr[nOldLen].Value <<= aDocName;
659 return UpdateMediaDescriptorWithFilterName( aMediaDescr, true );
662 #ifdef _WIN32
664 SfxFilterFlags MimeConfigurationHelper::GetFilterFlags( const OUString& aFilterName )
666 SfxFilterFlags nFlags = SfxFilterFlags::NONE;
669 if ( !aFilterName.isEmpty() )
671 uno::Reference< container::XNameAccess > xFilterFactory(
672 GetFilterFactory(),
673 uno::UNO_SET_THROW );
675 uno::Any aFilterAny = xFilterFactory->getByName( aFilterName );
676 uno::Sequence< beans::PropertyValue > aData;
677 if ( aFilterAny >>= aData )
679 SequenceAsHashMap aFilterHM( aData );
680 nFlags = static_cast<SfxFilterFlags>(aFilterHM.getUnpackedValueOrDefault( "Flags", sal_Int32(0) ));
683 } catch( uno::Exception& )
686 return nFlags;
689 bool MimeConfigurationHelper::AddFilterNameCheckOwnFile(
690 uno::Sequence< beans::PropertyValue >& aMediaDescr )
692 OUString aFilterName = UpdateMediaDescriptorWithFilterName( aMediaDescr, false );
693 if ( !aFilterName.isEmpty() )
695 SfxFilterFlags nFlags = GetFilterFlags( aFilterName );
696 // check the OWN flag
697 return bool(nFlags & SfxFilterFlags::OWN);
700 return false;
703 #endif
705 OUString MimeConfigurationHelper::GetDefaultFilterFromServiceName( const OUString& aServiceName, sal_Int32 nVersion )
707 OUString aResult;
709 if ( !aServiceName.isEmpty() && nVersion )
712 uno::Reference< container::XContainerQuery > xFilterQuery(
713 GetFilterFactory(),
714 uno::UNO_QUERY_THROW );
716 uno::Sequence< beans::NamedValue > aSearchRequest
718 { "DocumentService", css::uno::Any(aServiceName) },
719 { "FileFormatVersion", css::uno::Any(nVersion) }
722 uno::Reference< container::XEnumeration > xFilterEnum =
723 xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest );
725 // use the first filter that is found
726 if ( xFilterEnum.is() )
727 while ( xFilterEnum->hasMoreElements() )
729 uno::Sequence< beans::PropertyValue > aProps;
730 if ( xFilterEnum->nextElement() >>= aProps )
732 SfxFilterFlags nFlags = SfxFilterFlags::NONE;
733 OUString sName;
734 for (const auto & rPropVal : aProps)
736 if (rPropVal.Name == "Flags")
738 sal_Int32 nTmp(0);
739 if (rPropVal.Value >>= nTmp)
740 nFlags = static_cast<SfxFilterFlags>(nTmp);
742 else if (rPropVal.Name == "Name")
743 rPropVal.Value >>= sName;
746 // that should be import, export, own filter and not a template filter ( TemplatePath flag )
747 SfxFilterFlags const nRequired = SfxFilterFlags::OWN
748 // fdo#78159 for OOoXML, there is code to convert
749 // to ODF in OCommonEmbeddedObject::store*
750 // so accept it even though there's no export
751 | (SOFFICE_FILEFORMAT_60 == nVersion ? SfxFilterFlags::NONE : SfxFilterFlags::EXPORT)
752 | SfxFilterFlags::IMPORT;
753 if ( ( ( nFlags & nRequired ) == nRequired ) && !( nFlags & SfxFilterFlags::TEMPLATEPATH ) )
755 // if there are more than one filter the preferred one should be used
756 // if there is no preferred filter the first one will be used
757 if ( aResult.isEmpty() || ( nFlags & SfxFilterFlags::PREFERED ) )
758 aResult = sName;
759 if ( nFlags & SfxFilterFlags::PREFERED )
760 break; // the preferred filter was found
765 catch( uno::Exception& )
768 return aResult;
772 OUString MimeConfigurationHelper::GetExportFilterFromImportFilter( const OUString& aImportFilterName )
774 OUString aExportFilterName;
778 if ( !aImportFilterName.isEmpty() )
780 uno::Reference< container::XNameAccess > xFilterFactory(
781 GetFilterFactory(),
782 uno::UNO_SET_THROW );
784 uno::Any aImpFilterAny = xFilterFactory->getByName( aImportFilterName );
785 uno::Sequence< beans::PropertyValue > aImpData;
786 if ( aImpFilterAny >>= aImpData )
788 SequenceAsHashMap aImpFilterHM( aImpData );
789 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aImpFilterHM.getUnpackedValueOrDefault( "Flags", sal_Int32(0) ));
791 if ( !( nFlags & SfxFilterFlags::IMPORT ) )
793 OSL_FAIL( "This is no import filter!" );
794 throw uno::Exception("this is no import filter", nullptr);
797 if ( nFlags & SfxFilterFlags::EXPORT )
799 aExportFilterName = aImportFilterName;
801 else
803 OUString aDocumentServiceName = aImpFilterHM.getUnpackedValueOrDefault( "DocumentService", OUString() );
804 OUString aTypeName = aImpFilterHM.getUnpackedValueOrDefault( "Type", OUString() );
806 OSL_ENSURE( !aDocumentServiceName.isEmpty() && !aTypeName.isEmpty(), "Incomplete filter data!" );
807 if ( !(aDocumentServiceName.isEmpty() || aTypeName.isEmpty()) )
809 uno::Sequence< beans::NamedValue > aSearchRequest
811 { "Type", css::uno::Any(aTypeName) },
812 { "DocumentService", css::uno::Any(aDocumentServiceName) }
815 uno::Sequence< beans::PropertyValue > aExportFilterProps = SearchForFilter(
816 uno::Reference< container::XContainerQuery >( xFilterFactory, uno::UNO_QUERY_THROW ),
817 aSearchRequest,
818 SfxFilterFlags::EXPORT,
819 SfxFilterFlags::INTERNAL );
821 if ( aExportFilterProps.hasElements() )
823 SequenceAsHashMap aExpPropsHM( aExportFilterProps );
824 aExportFilterName = aExpPropsHM.getUnpackedValueOrDefault( "Name", OUString() );
831 catch( uno::Exception& )
834 return aExportFilterName;
838 // static
839 uno::Sequence< beans::PropertyValue > MimeConfigurationHelper::SearchForFilter(
840 const uno::Reference< container::XContainerQuery >& xFilterQuery,
841 const uno::Sequence< beans::NamedValue >& aSearchRequest,
842 SfxFilterFlags nMustFlags,
843 SfxFilterFlags nDontFlags )
845 uno::Sequence< beans::PropertyValue > aFilterProps;
846 uno::Reference< container::XEnumeration > xFilterEnum =
847 xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest );
849 // the first default filter will be taken,
850 // if there is no filter with flag default the first acceptable filter will be taken
851 if ( xFilterEnum.is() )
853 while ( xFilterEnum->hasMoreElements() )
855 uno::Sequence< beans::PropertyValue > aProps;
856 if ( xFilterEnum->nextElement() >>= aProps )
858 SequenceAsHashMap aPropsHM( aProps );
859 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aPropsHM.getUnpackedValueOrDefault("Flags",
860 sal_Int32(0) ));
861 if ( ( ( nFlags & nMustFlags ) == nMustFlags ) && !( nFlags & nDontFlags ) )
863 if ( ( nFlags & SfxFilterFlags::DEFAULT ) == SfxFilterFlags::DEFAULT )
865 aFilterProps = aProps;
866 break;
868 else if ( !aFilterProps.hasElements() )
869 aFilterProps = aProps;
875 return aFilterProps;
879 bool MimeConfigurationHelper::ClassIDsEqual( const uno::Sequence< sal_Int8 >& aClassID1, const uno::Sequence< sal_Int8 >& aClassID2 )
881 return aClassID1 == aClassID2;
885 uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3,
886 sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11,
887 sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 )
889 uno::Sequence< sal_Int8 > aResult{ /* [ 0] */ static_cast<sal_Int8>( n1 >> 24 ),
890 /* [ 1] */ static_cast<sal_Int8>( ( n1 << 8 ) >> 24 ),
891 /* [ 2] */ static_cast<sal_Int8>( ( n1 << 16 ) >> 24 ),
892 /* [ 3] */ static_cast<sal_Int8>( ( n1 << 24 ) >> 24 ),
893 /* [ 4] */ static_cast<sal_Int8>( n2 >> 8 ),
894 /* [ 5] */ static_cast<sal_Int8>( ( n2 << 8 ) >> 8 ),
895 /* [ 6] */ static_cast<sal_Int8>( n3 >> 8 ),
896 /* [ 7] */ static_cast<sal_Int8>( ( n3 << 8 ) >> 8 ),
897 /* [ 8] */ static_cast<sal_Int8>( b8 ),
898 /* [ 9] */ static_cast<sal_Int8>( b9 ),
899 /* [10] */ static_cast<sal_Int8>( b10 ),
900 /* [11] */ static_cast<sal_Int8>( b11 ),
901 /* [12] */ static_cast<sal_Int8>( b12 ),
902 /* [13] */ static_cast<sal_Int8>( b13 ),
903 /* [14] */ static_cast<sal_Int8>( b14 ),
904 /* [15] */ static_cast<sal_Int8>( b15 ) };
906 return aResult;
909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */