Coverage Report

Created: 2026-05-16 09:25

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