1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
26
27 #include <osl/diagnose.h>
28
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
37
38 using namespace ::com::sun::star;
39 using namespace comphelper;
40
41
MimeConfigurationHelper(const uno::Reference<uno::XComponentContext> & rxContext)42 MimeConfigurationHelper::MimeConfigurationHelper( const uno::Reference< uno::XComponentContext >& rxContext )
43 : m_xContext( rxContext )
44 {
45 if ( !m_xContext.is() )
46 throw uno::RuntimeException();
47 }
48
49
GetStringClassIDRepresentation(const uno::Sequence<sal_Int8> & aClassID)50 OUString MimeConfigurationHelper::GetStringClassIDRepresentation( const uno::Sequence< sal_Int8 >& aClassID )
51 {
52 OUStringBuffer aResult;
53
54 if ( aClassID.getLength() == 16 )
55 {
56 for ( sal_Int32 nInd = 0; nInd < aClassID.getLength(); nInd++ )
57 {
58 if ( nInd == 4 || nInd == 6 || nInd == 8 || nInd == 10 )
59 aResult.append("-");
60
61 sal_Int32 nDigit1 = static_cast<sal_Int32>( static_cast<sal_uInt8>(aClassID[nInd]) / 16 );
62 sal_Int32 nDigit2 = static_cast<sal_uInt8>(aClassID[nInd]) % 16;
63 aResult.append( OUString::number(nDigit1, 16) + OUString::number( nDigit2, 16 ) );
64 }
65 }
66
67 return aResult.makeStringAndClear();
68 }
69
70
GetDigit_Impl(char aChar)71 static sal_uInt8 GetDigit_Impl( char aChar )
72 {
73 if ( aChar >= '0' && aChar <= '9' )
74 return aChar - '0';
75 else if ( aChar >= 'a' && aChar <= 'f' )
76 return aChar - 'a' + 10;
77 else if ( aChar >= 'A' && aChar <= 'F' )
78 return aChar - 'A' + 10;
79 else
80 return 16;
81 }
82
83
GetSequenceClassIDRepresentation(const OUString & aClassID)84 uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassIDRepresentation( const OUString& aClassID )
85 {
86 sal_Int32 nLength = aClassID.getLength();
87 if ( nLength == 36 )
88 {
89 OString aCharClassID = OUStringToOString( aClassID, RTL_TEXTENCODING_ASCII_US );
90 uno::Sequence< sal_Int8 > aResult( 16 );
91
92 sal_Int32 nStrPointer = 0;
93 sal_Int32 nSeqInd = 0;
94 while( nSeqInd < 16 && nStrPointer + 1 < nLength )
95 {
96 sal_uInt8 nDigit1 = GetDigit_Impl( aCharClassID[nStrPointer++] );
97 sal_uInt8 nDigit2 = GetDigit_Impl( aCharClassID[nStrPointer++] );
98
99 if ( nDigit1 > 15 || nDigit2 > 15 )
100 break;
101
102 aResult[nSeqInd++] = static_cast<sal_Int8>( nDigit1 * 16 + nDigit2 );
103
104 if ( nStrPointer < nLength && aCharClassID[nStrPointer] == '-' )
105 nStrPointer++;
106 }
107
108 if ( nSeqInd == 16 && nStrPointer == nLength )
109 return aResult;
110 }
111
112 return uno::Sequence< sal_Int8 >();
113 }
114
115
GetConfigurationByPath(const OUString & aPath)116 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetConfigurationByPath( const OUString& aPath )
117 {
118 osl::MutexGuard aGuard( m_aMutex );
119
120 uno::Reference< container::XNameAccess > xConfig;
121
122 try
123 {
124 if ( !m_xConfigProvider.is() )
125 m_xConfigProvider = configuration::theDefaultProvider::get( m_xContext );
126
127 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
128 {
129 {"nodepath", uno::Any(aPath)}
130 }));
131 xConfig.set( m_xConfigProvider->createInstanceWithArguments(
132 "com.sun.star.configuration.ConfigurationAccess",
133 aArgs ),
134 uno::UNO_QUERY );
135 }
136 catch( uno::Exception& )
137 {}
138
139 return xConfig;
140 }
141
142
GetObjConfiguration()143 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetObjConfiguration()
144 {
145 osl::MutexGuard aGuard( m_aMutex );
146
147 if ( !m_xObjectConfig.is() )
148 m_xObjectConfig = GetConfigurationByPath(
149 "/org.openoffice.Office.Embedding/Objects" );
150
151 return m_xObjectConfig;
152 }
153
154
GetVerbsConfiguration()155 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetVerbsConfiguration()
156 {
157 osl::MutexGuard aGuard( m_aMutex );
158
159 if ( !m_xVerbsConfig.is() )
160 m_xVerbsConfig = GetConfigurationByPath(
161 "/org.openoffice.Office.Embedding/Verbs");
162
163 return m_xVerbsConfig;
164 }
165
166
GetMediaTypeConfiguration()167 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetMediaTypeConfiguration()
168 {
169 osl::MutexGuard aGuard( m_aMutex );
170
171 if ( !m_xMediaTypeConfig.is() )
172 m_xMediaTypeConfig = GetConfigurationByPath(
173 "/org.openoffice.Office.Embedding/MimeTypeClassIDRelations");
174
175 return m_xMediaTypeConfig;
176 }
177
178
GetFilterFactory()179 uno::Reference< container::XNameAccess > MimeConfigurationHelper::GetFilterFactory()
180 {
181 osl::MutexGuard aGuard( m_aMutex );
182
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 );
187
188 return m_xFilterFactory;
189 }
190
191
GetDocServiceNameFromFilter(const OUString & aFilterName)192 OUString MimeConfigurationHelper::GetDocServiceNameFromFilter( const OUString& aFilterName )
193 {
194 OUString aDocServiceName;
195
196 try
197 {
198 uno::Reference< container::XNameAccess > xFilterFactory(
199 GetFilterFactory(),
200 uno::UNO_SET_THROW );
201
202 uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName );
203 uno::Sequence< beans::PropertyValue > aFilterData;
204 if ( aFilterAnyData >>= aFilterData )
205 {
206 for ( const auto & prop : std::as_const(aFilterData) )
207 if ( prop.Name == "DocumentService" )
208 prop.Value >>= aDocServiceName;
209 }
210 }
211 catch( uno::Exception& )
212 {}
213
214 return aDocServiceName;
215 }
216
217
GetDocServiceNameFromMediaType(const OUString & aMediaType)218 OUString MimeConfigurationHelper::GetDocServiceNameFromMediaType( const OUString& aMediaType )
219 {
220 uno::Reference< container::XContainerQuery > xTypeCFG(
221 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_xContext),
222 uno::UNO_QUERY );
223
224 if ( xTypeCFG.is() )
225 {
226 try
227 {
228 // make query for all types matching the properties
229 uno::Sequence < beans::NamedValue > aSeq { { "MediaType", css::uno::Any(aMediaType) } };
230
231 uno::Reference < container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq );
232 while ( xEnum->hasMoreElements() )
233 {
234 uno::Sequence< beans::PropertyValue > aType;
235 if ( xEnum->nextElement() >>= aType )
236 {
237 for ( const auto & prop : std::as_const(aType) )
238 {
239 OUString aFilterName;
240 if ( prop.Name == "PreferredFilter"
241 && ( prop.Value >>= aFilterName ) && !aFilterName.isEmpty() )
242 {
243 OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName );
244 if ( !aDocumentName.isEmpty() )
245 return aDocumentName;
246 }
247 }
248 }
249 }
250 }
251 catch( uno::Exception& )
252 {}
253 }
254
255 return OUString();
256 }
257
258
GetVerbByShortcut(const OUString & aVerbShortcut,embed::VerbDescriptor & aDescriptor)259 bool MimeConfigurationHelper::GetVerbByShortcut( const OUString& aVerbShortcut,
260 embed::VerbDescriptor& aDescriptor )
261 {
262 bool bResult = false;
263
264 uno::Reference< container::XNameAccess > xVerbsConfig = GetVerbsConfiguration();
265 uno::Reference< container::XNameAccess > xVerbsProps;
266 try
267 {
268 if ( xVerbsConfig.is() && ( xVerbsConfig->getByName( aVerbShortcut ) >>= xVerbsProps ) && xVerbsProps.is() )
269 {
270 embed::VerbDescriptor aTempDescr;
271 if ( ( xVerbsProps->getByName("VerbID") >>= aTempDescr.VerbID )
272 && ( xVerbsProps->getByName("VerbUIName") >>= aTempDescr.VerbName )
273 && ( xVerbsProps->getByName("VerbFlags") >>= aTempDescr.VerbFlags )
274 && ( xVerbsProps->getByName("VerbAttributes") >>= aTempDescr.VerbAttributes ) )
275 {
276 aDescriptor = aTempDescr;
277 bResult = true;
278 }
279 }
280 }
281 catch( uno::Exception& )
282 {
283 }
284
285 return bResult;
286 }
287
288
GetObjPropsFromConfigEntry(const uno::Sequence<sal_Int8> & aClassID,const uno::Reference<container::XNameAccess> & xObjectProps)289 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjPropsFromConfigEntry(
290 const uno::Sequence< sal_Int8 >& aClassID,
291 const uno::Reference< container::XNameAccess >& xObjectProps )
292 {
293 uno::Sequence< beans::NamedValue > aResult;
294
295 if ( aClassID.getLength() == 16 )
296 {
297 try
298 {
299 uno::Sequence< OUString > aObjPropNames = xObjectProps->getElementNames();
300
301 aResult.realloc( aObjPropNames.getLength() + 1 );
302 aResult[0].Name = "ClassID";
303 aResult[0].Value <<= aClassID;
304
305 for ( sal_Int32 nInd = 0; nInd < aObjPropNames.getLength(); nInd++ )
306 {
307 aResult[nInd + 1].Name = aObjPropNames[nInd];
308
309 if ( aObjPropNames[nInd] == "ObjectVerbs" )
310 {
311 uno::Sequence< OUString > aVerbShortcuts;
312 if ( !(xObjectProps->getByName( aObjPropNames[nInd] ) >>= aVerbShortcuts) )
313 throw uno::RuntimeException();
314 uno::Sequence< embed::VerbDescriptor > aVerbDescriptors( aVerbShortcuts.getLength() );
315 for ( sal_Int32 nVerbI = 0; nVerbI < aVerbShortcuts.getLength(); nVerbI++ )
316 if ( !GetVerbByShortcut( aVerbShortcuts[nVerbI], aVerbDescriptors[nVerbI] ) )
317 throw uno::RuntimeException();
318
319 aResult[nInd+1].Value <<= aVerbDescriptors;
320 }
321 else
322 aResult[nInd+1].Value = xObjectProps->getByName( aObjPropNames[nInd] );
323 }
324 }
325 catch( uno::Exception& )
326 {
327 aResult.realloc( 0 );
328 }
329 }
330
331 return aResult;
332 }
333
334
GetExplicitlyRegisteredObjClassID(const OUString & aMediaType)335 OUString MimeConfigurationHelper::GetExplicitlyRegisteredObjClassID( const OUString& aMediaType )
336 {
337 OUString aStringClassID;
338
339 uno::Reference< container::XNameAccess > xMediaTypeConfig = GetMediaTypeConfiguration();
340 try
341 {
342 if ( xMediaTypeConfig.is() )
343 xMediaTypeConfig->getByName( aMediaType ) >>= aStringClassID;
344 }
345 catch( uno::Exception& )
346 {
347 }
348
349 return aStringClassID;
350
351 }
352
353
GetObjectPropsByStringClassID(const OUString & aStringClassID)354 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByStringClassID(
355 const OUString& aStringClassID )
356 {
357 uno::Sequence< beans::NamedValue > aObjProps;
358
359 uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID );
360 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
361 {
362 aObjProps.realloc(2);
363 aObjProps[0].Name = "ObjectFactory";
364 aObjProps[0].Value <<= OUString( "com.sun.star.embed.OOoSpecialEmbeddedObjectFactory" );
365 aObjProps[1].Name = "ClassID";
366 aObjProps[1].Value <<= aClassID;
367 return aObjProps;
368 }
369
370 if ( aClassID.getLength() == 16 )
371 {
372 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
373 uno::Reference< container::XNameAccess > xObjectProps;
374 try
375 {
376 // TODO/LATER: allow to provide ClassID string in any format, only digits are counted
377 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
378 aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps );
379 }
380 catch( uno::Exception& )
381 {
382 }
383 }
384
385 return aObjProps;
386 }
387
388
GetObjectPropsByClassID(const uno::Sequence<sal_Int8> & aClassID)389 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByClassID(
390 const uno::Sequence< sal_Int8 >& aClassID )
391 {
392 uno::Sequence< beans::NamedValue > aObjProps;
393 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
394 {
395 aObjProps.realloc(2);
396 aObjProps[0].Name = "ObjectFactory";
397 aObjProps[0].Value <<= OUString( "com.sun.star.embed.OOoSpecialEmbeddedObjectFactory" );
398 aObjProps[1].Name = "ClassID";
399 aObjProps[1].Value <<= aClassID;
400 }
401
402 OUString aStringClassID = GetStringClassIDRepresentation( aClassID );
403 if ( !aStringClassID.isEmpty() )
404 {
405 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
406 uno::Reference< container::XNameAccess > xObjectProps;
407 try
408 {
409 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
410 aObjProps = GetObjPropsFromConfigEntry( aClassID, xObjectProps );
411 }
412 catch( uno::Exception& )
413 {
414 }
415 }
416
417 return aObjProps;
418 }
419
420
GetObjectPropsByMediaType(const OUString & aMediaType)421 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByMediaType( const OUString& aMediaType )
422 {
423 uno::Sequence< beans::NamedValue > aObject =
424 GetObjectPropsByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) );
425 if ( aObject.hasElements() )
426 return aObject;
427
428 OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType );
429 if ( !aDocumentName.isEmpty() )
430 return GetObjectPropsByDocumentName( aDocumentName );
431
432 return uno::Sequence< beans::NamedValue >();
433 }
434
435
GetObjectPropsByFilter(const OUString & aFilterName)436 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByFilter( const OUString& aFilterName )
437 {
438 OUString aDocumentName = GetDocServiceNameFromFilter( aFilterName );
439 if ( !aDocumentName.isEmpty() )
440 return GetObjectPropsByDocumentName( aDocumentName );
441
442 return uno::Sequence< beans::NamedValue >();
443 }
444
445
GetObjectPropsByDocumentName(std::u16string_view aDocName)446 uno::Sequence< beans::NamedValue > MimeConfigurationHelper::GetObjectPropsByDocumentName( std::u16string_view aDocName )
447 {
448 if ( !aDocName.empty() )
449 {
450 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
451 if ( xObjConfig.is() )
452 {
453 try
454 {
455 const uno::Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
456 for ( const OUString & id : aClassIDs )
457 {
458 uno::Reference< container::XNameAccess > xObjectProps;
459 OUString aEntryDocName;
460
461 if ( ( xObjConfig->getByName( id ) >>= xObjectProps ) && xObjectProps.is()
462 && ( xObjectProps->getByName("ObjectDocumentServiceName") >>= aEntryDocName )
463 && aEntryDocName == aDocName )
464 {
465 return GetObjPropsFromConfigEntry( GetSequenceClassIDRepresentation( id ),
466 xObjectProps );
467 }
468 }
469 }
470 catch( uno::Exception& )
471 {}
472 }
473 }
474
475 return uno::Sequence< beans::NamedValue >();
476 }
477
478
GetFactoryNameByClassID(const uno::Sequence<sal_Int8> & aClassID)479 OUString MimeConfigurationHelper::GetFactoryNameByClassID( const uno::Sequence< sal_Int8 >& aClassID )
480 {
481 return GetFactoryNameByStringClassID( GetStringClassIDRepresentation( aClassID ) );
482 }
483
484
GetFactoryNameByStringClassID(const OUString & aStringClassID)485 OUString MimeConfigurationHelper::GetFactoryNameByStringClassID( const OUString& aStringClassID )
486 {
487 OUString aResult;
488
489 if ( !aStringClassID.isEmpty() )
490 {
491 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
492 uno::Reference< container::XNameAccess > xObjectProps;
493 try
494 {
495 if ( xObjConfig.is() && ( xObjConfig->getByName( aStringClassID.toAsciiUpperCase() ) >>= xObjectProps ) && xObjectProps.is() )
496 xObjectProps->getByName("ObjectFactory") >>= aResult;
497 }
498 catch( uno::Exception& )
499 {
500 uno::Sequence< sal_Int8 > aClassID = GetSequenceClassIDRepresentation( aStringClassID );
501 if ( ClassIDsEqual( aClassID, GetSequenceClassID( SO3_DUMMY_CLASSID ) ) )
502 return "com.sun.star.embed.OOoSpecialEmbeddedObjectFactory";
503 }
504 }
505
506 return aResult;
507 }
508
509
GetFactoryNameByDocumentName(std::u16string_view aDocName)510 OUString MimeConfigurationHelper::GetFactoryNameByDocumentName( std::u16string_view aDocName )
511 {
512 OUString aResult;
513
514 if ( !aDocName.empty() )
515 {
516 uno::Reference< container::XNameAccess > xObjConfig = GetObjConfiguration();
517 if ( xObjConfig.is() )
518 {
519 try
520 {
521 const uno::Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
522 for ( const OUString & id : aClassIDs )
523 {
524 uno::Reference< container::XNameAccess > xObjectProps;
525 OUString aEntryDocName;
526
527 if ( ( xObjConfig->getByName( id ) >>= xObjectProps ) && xObjectProps.is()
528 && ( xObjectProps->getByName( "ObjectDocumentServiceName" ) >>= aEntryDocName )
529 && aEntryDocName == aDocName )
530 {
531 xObjectProps->getByName("ObjectFactory") >>= aResult;
532 break;
533 }
534 }
535 }
536 catch( uno::Exception& )
537 {}
538 }
539 }
540
541 return aResult;
542 }
543
544
GetFactoryNameByMediaType(const OUString & aMediaType)545 OUString MimeConfigurationHelper::GetFactoryNameByMediaType( const OUString& aMediaType )
546 {
547 OUString aResult = GetFactoryNameByStringClassID( GetExplicitlyRegisteredObjClassID( aMediaType ) );
548
549 if ( aResult.isEmpty() )
550 {
551 OUString aDocumentName = GetDocServiceNameFromMediaType( aMediaType );
552 if ( !aDocumentName.isEmpty() )
553 aResult = GetFactoryNameByDocumentName( aDocumentName );
554 }
555
556 return aResult;
557 }
558
559
UpdateMediaDescriptorWithFilterName(uno::Sequence<beans::PropertyValue> & aMediaDescr,bool bIgnoreType)560 OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName(
561 uno::Sequence< beans::PropertyValue >& aMediaDescr,
562 bool bIgnoreType )
563 {
564 OUString aFilterName;
565
566 for ( const auto & prop : std::as_const(aMediaDescr) )
567 if ( prop.Name == "FilterName" )
568 prop.Value >>= aFilterName;
569
570 if ( aFilterName.isEmpty() )
571 {
572 // filter name is not specified, so type detection should be done
573
574 uno::Reference< document::XTypeDetection > xTypeDetection(
575 m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_xContext),
576 uno::UNO_QUERY_THROW );
577
578 // typedetection can change the mode, add a stream and so on, thus a copy should be used
579 uno::Sequence< beans::PropertyValue > aTempMD( aMediaDescr );
580
581 // get TypeName
582 OUString aTypeName = xTypeDetection->queryTypeByDescriptor( aTempMD, true );
583
584 // get FilterName
585 for ( const auto & prop : std::as_const(aTempMD) )
586 if ( prop.Name == "FilterName" )
587 prop.Value >>= aFilterName;
588
589 if ( !aFilterName.isEmpty() )
590 {
591 sal_Int32 nOldLen = aMediaDescr.getLength();
592 aMediaDescr.realloc( nOldLen + 1 );
593 aMediaDescr[nOldLen].Name = "FilterName";
594 aMediaDescr[ nOldLen ].Value <<= aFilterName;
595
596 }
597 else if ( !aTypeName.isEmpty() && !bIgnoreType )
598 {
599 uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY );
600 uno::Sequence< beans::PropertyValue > aTypes;
601
602 if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
603 {
604 for ( const auto & prop : std::as_const(aTypes) )
605 {
606 if ( prop.Name == "PreferredFilter" && ( prop.Value >>= aFilterName ) )
607 {
608 sal_Int32 nOldLen = aMediaDescr.getLength();
609 aMediaDescr.realloc( nOldLen + 1 );
610 aMediaDescr[nOldLen].Name = "FilterName";
611 aMediaDescr[ nOldLen ].Value = prop.Value;
612 break;
613 }
614 }
615 }
616 }
617 }
618
619 return aFilterName;
620 }
621
UpdateMediaDescriptorWithFilterName(uno::Sequence<beans::PropertyValue> & aMediaDescr,uno::Sequence<beans::NamedValue> & aObject)622 OUString MimeConfigurationHelper::UpdateMediaDescriptorWithFilterName(
623 uno::Sequence< beans::PropertyValue >& aMediaDescr,
624 uno::Sequence< beans::NamedValue >& aObject )
625 {
626 OUString aDocName;
627 for ( const auto & nv : std::as_const(aObject) )
628 if ( nv.Name == "ObjectDocumentServiceName" )
629 {
630 nv.Value >>= aDocName;
631 break;
632 }
633
634 OSL_ENSURE( !aDocName.isEmpty(), "The name must exist at this point!" );
635
636
637 bool bNeedsAddition = true;
638 for ( sal_Int32 nMedInd = 0; nMedInd < aMediaDescr.getLength(); nMedInd++ )
639 if ( aMediaDescr[nMedInd].Name == "DocumentService" )
640 {
641 aMediaDescr[nMedInd].Value <<= aDocName;
642 bNeedsAddition = false;
643 break;
644 }
645
646 if ( bNeedsAddition )
647 {
648 sal_Int32 nOldLen = aMediaDescr.getLength();
649 aMediaDescr.realloc( nOldLen + 1 );
650 aMediaDescr[nOldLen].Name = "DocumentService";
651 aMediaDescr[nOldLen].Value <<= aDocName;
652 }
653
654 return UpdateMediaDescriptorWithFilterName( aMediaDescr, true );
655 }
656
657 #ifdef _WIN32
658
GetFilterFlags(const OUString & aFilterName)659 SfxFilterFlags MimeConfigurationHelper::GetFilterFlags( const OUString& aFilterName )
660 {
661 SfxFilterFlags nFlags = SfxFilterFlags::NONE;
662 try
663 {
664 if ( !aFilterName.isEmpty() )
665 {
666 uno::Reference< container::XNameAccess > xFilterFactory(
667 GetFilterFactory(),
668 uno::UNO_SET_THROW );
669
670 uno::Any aFilterAny = xFilterFactory->getByName( aFilterName );
671 uno::Sequence< beans::PropertyValue > aData;
672 if ( aFilterAny >>= aData )
673 {
674 SequenceAsHashMap aFilterHM( aData );
675 nFlags = static_cast<SfxFilterFlags>(aFilterHM.getUnpackedValueOrDefault( "Flags", sal_Int32(0) ));
676 }
677 }
678 } catch( uno::Exception& )
679 {}
680
681 return nFlags;
682 }
683
AddFilterNameCheckOwnFile(uno::Sequence<beans::PropertyValue> & aMediaDescr)684 bool MimeConfigurationHelper::AddFilterNameCheckOwnFile(
685 uno::Sequence< beans::PropertyValue >& aMediaDescr )
686 {
687 OUString aFilterName = UpdateMediaDescriptorWithFilterName( aMediaDescr, false );
688 if ( !aFilterName.isEmpty() )
689 {
690 SfxFilterFlags nFlags = GetFilterFlags( aFilterName );
691 // check the OWN flag
692 return bool(nFlags & SfxFilterFlags::OWN);
693 }
694
695 return false;
696 }
697
698 #endif
699
GetDefaultFilterFromServiceName(const OUString & aServiceName,sal_Int32 nVersion)700 OUString MimeConfigurationHelper::GetDefaultFilterFromServiceName( const OUString& aServiceName, sal_Int32 nVersion )
701 {
702 OUString aResult;
703
704 if ( !aServiceName.isEmpty() && nVersion )
705 try
706 {
707 uno::Reference< container::XContainerQuery > xFilterQuery(
708 GetFilterFactory(),
709 uno::UNO_QUERY_THROW );
710
711 uno::Sequence< beans::NamedValue > aSearchRequest
712 {
713 { "DocumentService", css::uno::Any(aServiceName) },
714 { "FileFormatVersion", css::uno::Any(nVersion) }
715 };
716
717 uno::Reference< container::XEnumeration > xFilterEnum =
718 xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest );
719
720 // use the first filter that is found
721 if ( xFilterEnum.is() )
722 while ( xFilterEnum->hasMoreElements() )
723 {
724 uno::Sequence< beans::PropertyValue > aProps;
725 if ( xFilterEnum->nextElement() >>= aProps )
726 {
727 SequenceAsHashMap aPropsHM( aProps );
728 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aPropsHM.getUnpackedValueOrDefault( "Flags", sal_Int32(0) ));
729
730 // that should be import, export, own filter and not a template filter ( TemplatePath flag )
731 SfxFilterFlags const nRequired = SfxFilterFlags::OWN
732 // fdo#78159 for OOoXML, there is code to convert
733 // to ODF in OCommonEmbeddedObject::store*
734 // so accept it even though there's no export
735 | (SOFFICE_FILEFORMAT_60 == nVersion ? SfxFilterFlags::NONE : SfxFilterFlags::EXPORT)
736 | SfxFilterFlags::IMPORT;
737 if ( ( ( nFlags & nRequired ) == nRequired ) && !( nFlags & SfxFilterFlags::TEMPLATEPATH ) )
738 {
739 // if there are more than one filter the preferred one should be used
740 // if there is no preferred filter the first one will be used
741 if ( aResult.isEmpty() || ( nFlags & SfxFilterFlags::PREFERED ) )
742 aResult = aPropsHM.getUnpackedValueOrDefault( "Name", OUString() );
743 if ( nFlags & SfxFilterFlags::PREFERED )
744 break; // the preferred filter was found
745 }
746 }
747 }
748 }
749 catch( uno::Exception& )
750 {}
751
752 return aResult;
753 }
754
755
GetExportFilterFromImportFilter(const OUString & aImportFilterName)756 OUString MimeConfigurationHelper::GetExportFilterFromImportFilter( const OUString& aImportFilterName )
757 {
758 OUString aExportFilterName;
759
760 try
761 {
762 if ( !aImportFilterName.isEmpty() )
763 {
764 uno::Reference< container::XNameAccess > xFilterFactory(
765 GetFilterFactory(),
766 uno::UNO_SET_THROW );
767
768 uno::Any aImpFilterAny = xFilterFactory->getByName( aImportFilterName );
769 uno::Sequence< beans::PropertyValue > aImpData;
770 if ( aImpFilterAny >>= aImpData )
771 {
772 SequenceAsHashMap aImpFilterHM( aImpData );
773 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aImpFilterHM.getUnpackedValueOrDefault( "Flags", sal_Int32(0) ));
774
775 if ( !( nFlags & SfxFilterFlags::IMPORT ) )
776 {
777 OSL_FAIL( "This is no import filter!" );
778 throw uno::Exception("this is no import filter", nullptr);
779 }
780
781 if ( nFlags & SfxFilterFlags::EXPORT )
782 {
783 aExportFilterName = aImportFilterName;
784 }
785 else
786 {
787 OUString aDocumentServiceName = aImpFilterHM.getUnpackedValueOrDefault( "DocumentService", OUString() );
788 OUString aTypeName = aImpFilterHM.getUnpackedValueOrDefault( "Type", OUString() );
789
790 OSL_ENSURE( !aDocumentServiceName.isEmpty() && !aTypeName.isEmpty(), "Incomplete filter data!" );
791 if ( !(aDocumentServiceName.isEmpty() || aTypeName.isEmpty()) )
792 {
793 uno::Sequence< beans::NamedValue > aSearchRequest
794 {
795 { "Type", css::uno::Any(aTypeName) },
796 { "DocumentService", css::uno::Any(aDocumentServiceName) }
797 };
798
799 uno::Sequence< beans::PropertyValue > aExportFilterProps = SearchForFilter(
800 uno::Reference< container::XContainerQuery >( xFilterFactory, uno::UNO_QUERY_THROW ),
801 aSearchRequest,
802 SfxFilterFlags::EXPORT,
803 SfxFilterFlags::INTERNAL );
804
805 if ( aExportFilterProps.hasElements() )
806 {
807 SequenceAsHashMap aExpPropsHM( aExportFilterProps );
808 aExportFilterName = aExpPropsHM.getUnpackedValueOrDefault( "Name", OUString() );
809 }
810 }
811 }
812 }
813 }
814 }
815 catch( uno::Exception& )
816 {}
817
818 return aExportFilterName;
819 }
820
821
822 // static
SearchForFilter(const uno::Reference<container::XContainerQuery> & xFilterQuery,const uno::Sequence<beans::NamedValue> & aSearchRequest,SfxFilterFlags nMustFlags,SfxFilterFlags nDontFlags)823 uno::Sequence< beans::PropertyValue > MimeConfigurationHelper::SearchForFilter(
824 const uno::Reference< container::XContainerQuery >& xFilterQuery,
825 const uno::Sequence< beans::NamedValue >& aSearchRequest,
826 SfxFilterFlags nMustFlags,
827 SfxFilterFlags nDontFlags )
828 {
829 uno::Sequence< beans::PropertyValue > aFilterProps;
830 uno::Reference< container::XEnumeration > xFilterEnum =
831 xFilterQuery->createSubSetEnumerationByProperties( aSearchRequest );
832
833 // the first default filter will be taken,
834 // if there is no filter with flag default the first acceptable filter will be taken
835 if ( xFilterEnum.is() )
836 {
837 while ( xFilterEnum->hasMoreElements() )
838 {
839 uno::Sequence< beans::PropertyValue > aProps;
840 if ( xFilterEnum->nextElement() >>= aProps )
841 {
842 SequenceAsHashMap aPropsHM( aProps );
843 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aPropsHM.getUnpackedValueOrDefault("Flags",
844 sal_Int32(0) ));
845 if ( ( ( nFlags & nMustFlags ) == nMustFlags ) && !( nFlags & nDontFlags ) )
846 {
847 if ( ( nFlags & SfxFilterFlags::DEFAULT ) == SfxFilterFlags::DEFAULT )
848 {
849 aFilterProps = aProps;
850 break;
851 }
852 else if ( !aFilterProps.hasElements() )
853 aFilterProps = aProps;
854 }
855 }
856 }
857 }
858
859 return aFilterProps;
860 }
861
862
ClassIDsEqual(const uno::Sequence<sal_Int8> & aClassID1,const uno::Sequence<sal_Int8> & aClassID2)863 bool MimeConfigurationHelper::ClassIDsEqual( const uno::Sequence< sal_Int8 >& aClassID1, const uno::Sequence< sal_Int8 >& aClassID2 )
864 {
865 return aClassID1 == aClassID2;
866 }
867
868
GetSequenceClassID(sal_uInt32 n1,sal_uInt16 n2,sal_uInt16 n3,sal_uInt8 b8,sal_uInt8 b9,sal_uInt8 b10,sal_uInt8 b11,sal_uInt8 b12,sal_uInt8 b13,sal_uInt8 b14,sal_uInt8 b15)869 uno::Sequence< sal_Int8 > MimeConfigurationHelper::GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3,
870 sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11,
871 sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 )
872 {
873 uno::Sequence< sal_Int8 > aResult( 16 );
874 aResult[0] = static_cast<sal_Int8>( n1 >> 24 );
875 aResult[1] = static_cast<sal_Int8>( ( n1 << 8 ) >> 24 );
876 aResult[2] = static_cast<sal_Int8>( ( n1 << 16 ) >> 24 );
877 aResult[3] = static_cast<sal_Int8>( ( n1 << 24 ) >> 24 );
878 aResult[4] = static_cast<sal_Int8>( n2 >> 8 );
879 aResult[5] = static_cast<sal_Int8>( ( n2 << 8 ) >> 8 );
880 aResult[6] = static_cast<sal_Int8>( n3 >> 8 );
881 aResult[7] = static_cast<sal_Int8>( ( n3 << 8 ) >> 8 );
882 aResult[8] = b8;
883 aResult[9] = b9;
884 aResult[10] = b10;
885 aResult[11] = b11;
886 aResult[12] = b12;
887 aResult[13] = b13;
888 aResult[14] = b14;
889 aResult[15] = b15;
890
891 return aResult;
892 }
893
894 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
895