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 "FilterConfigCache.hxx"
21 
22 #include <vcl/graphicfilter.hxx>
23 #include <unotools/configmgr.hxx>
24 #include <tools/svlibrary.h>
25 #include <com/sun/star/uno/Any.h>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <com/sun/star/uno/Exception.hpp>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/configuration/theDefaultProvider.hpp>
33 #include <com/sun/star/container/XNameAccess.hpp>
34 
35 using namespace ::com::sun::star::lang          ;   // XMultiServiceFactory
36 using namespace ::com::sun::star::container     ;   // XNameAccess
37 using namespace ::com::sun::star::uno           ;   // Reference
38 using namespace ::com::sun::star::beans         ;   // PropertyValue
39 using namespace ::com::sun::star::configuration ;
40 
41 const char* FilterConfigCache::FilterConfigCacheEntry::InternalPixelFilterNameList[] =
42 {
43     IMP_BMP, IMP_GIF, IMP_PNG,IMP_JPEG, IMP_XBM, IMP_XPM,
44     EXP_BMP, EXP_JPEG, EXP_PNG, IMP_MOV, nullptr
45 };
46 
47 const char* FilterConfigCache::FilterConfigCacheEntry::InternalVectorFilterNameList[] =
48 {
49     IMP_SVMETAFILE, IMP_WMF, IMP_EMF, IMP_SVG, IMP_PDF,
50     EXP_SVMETAFILE, EXP_WMF, EXP_EMF, EXP_SVG, EXP_PDF, nullptr
51 };
52 
53 const char* FilterConfigCache::FilterConfigCacheEntry::ExternalPixelFilterNameList[] =
54 {
55     "egi", "icd", "ipd", "ipx", "ipb", "epb", "epg",
56     "epp", "ira", "era", "itg", "iti", "eti", "exp", nullptr
57 };
58 
CreateFilterName(const OUString & rUserDataEntry)59 void FilterConfigCache::FilterConfigCacheEntry::CreateFilterName( const OUString& rUserDataEntry )
60 {
61     bIsPixelFormat = bIsInternalFilter = false;
62     sFilterName = rUserDataEntry;
63     const char** pPtr;
64     for ( pPtr = InternalPixelFilterNameList; *pPtr && !bIsInternalFilter; pPtr++ )
65     {
66         if ( sFilterName.equalsIgnoreAsciiCaseAscii( *pPtr ) )
67         {
68             bIsInternalFilter = true;
69             bIsPixelFormat = true;
70         }
71     }
72     for ( pPtr = InternalVectorFilterNameList; *pPtr && !bIsInternalFilter; pPtr++ )
73     {
74         if ( sFilterName.equalsIgnoreAsciiCaseAscii( *pPtr ) )
75             bIsInternalFilter = true;
76     }
77     if ( !bIsInternalFilter )
78     {
79         for ( pPtr = ExternalPixelFilterNameList; *pPtr && !bIsPixelFormat; pPtr++ )
80         {
81             if ( sFilterName.equalsIgnoreAsciiCaseAscii( *pPtr ) )
82                 bIsPixelFormat = true;
83         }
84         sExternalFilterName = sFilterName;
85         sFilterName = SVLIBRARY("gie");
86     }
87 }
88 
GetShortName()89 OUString FilterConfigCache::FilterConfigCacheEntry::GetShortName()
90 {
91     OUString aShortName;
92     if ( !lExtensionList.empty() )
93     {
94         aShortName = lExtensionList[ 0 ];
95         if ( aShortName.startsWith( "*." ) )
96             aShortName = aShortName.replaceAt( 0, 2, "" );
97     }
98     return aShortName;
99 }
100 
101 /** helper to open the configuration root of the underlying
102     config package
103 
104     @param  sPackage
105             specify, which config package should be opened.
106             Must be one of "types" or "filters"
107 
108     @return A valid object if open was successful. The access on opened
109             data will be readonly. It returns NULL in case open failed.
110 
111     @throws It let pass RuntimeExceptions only.
112  */
openConfig(const char * sPackage)113 static Reference< XInterface > openConfig(const char* sPackage)
114 {
115     Reference< XComponentContext > xContext(
116         comphelper::getProcessComponentContext() );
117     Reference< XInterface >           xCfg;
118     try
119     {
120         // get access to config API (not to file!)
121         Reference< XMultiServiceFactory > xConfigProvider = theDefaultProvider::get( xContext );
122 
123         Sequence< Any > lParams(1);
124         PropertyValue   aParam    ;
125 
126         // define cfg path for open
127         aParam.Name = "nodepath";
128         if (rtl_str_compareIgnoreAsciiCase(sPackage, "types") == 0)
129             aParam.Value <<= OUString( "/org.openoffice.TypeDetection.Types/Types" );
130         if (rtl_str_compareIgnoreAsciiCase(sPackage, "filters") == 0)
131             aParam.Value <<= OUString( "/org.openoffice.TypeDetection.GraphicFilter/Filters" );
132         lParams[0] <<= aParam;
133 
134         // get access to file
135         xCfg = xConfigProvider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", lParams);
136     }
137     catch(const RuntimeException&)
138         { throw; }
139     catch(const Exception&)
140         { xCfg.clear(); }
141 
142     return xCfg;
143 }
144 
ImplInit()145 void FilterConfigCache::ImplInit()
146 {
147     OUString const STYPE                ( "Type"                );
148     OUString const SUINAME              ( "UIName"              );
149     OUString const SFLAGS               ( "Flags"               );
150     OUString const SMEDIATYPE           ( "MediaType"           );
151     OUString const SEXTENSIONS          ( "Extensions"          );
152     OUString const SFORMATNAME          ( "FormatName"          );
153     OUString const SREALFILTERNAME      ( "RealFilterName"      );
154 
155     // get access to config
156     Reference< XNameAccess > xTypeAccess  ( openConfig("types"  ), UNO_QUERY );
157     Reference< XNameAccess > xFilterAccess( openConfig("filters"), UNO_QUERY );
158 
159     if ( xTypeAccess.is() && xFilterAccess.is() )
160     {
161         const Sequence< OUString > lAllFilter = xFilterAccess->getElementNames();
162 
163         for ( const OUString& sInternalFilterName : lAllFilter )
164         {
165             Reference< XPropertySet > xFilterSet;
166             xFilterAccess->getByName( sInternalFilterName ) >>= xFilterSet;
167             if (!xFilterSet.is())
168                 continue;
169 
170             FilterConfigCacheEntry aEntry;
171 
172             aEntry.sInternalFilterName = sInternalFilterName;
173             xFilterSet->getPropertyValue(STYPE) >>= aEntry.sType;
174             xFilterSet->getPropertyValue(SUINAME) >>= aEntry.sUIName;
175             xFilterSet->getPropertyValue(SREALFILTERNAME) >>= aEntry.sFilterType;
176             Sequence< OUString > lFlags;
177             xFilterSet->getPropertyValue(SFLAGS) >>= lFlags;
178             if (lFlags.getLength()!=1 || lFlags[0].isEmpty())
179                 continue;
180             if (lFlags[0].equalsIgnoreAsciiCase("import"))
181                 aEntry.nFlags = 1;
182             else if (lFlags[0].equalsIgnoreAsciiCase("export"))
183                 aEntry.nFlags = 2;
184 
185             OUString sFormatName;
186             xFilterSet->getPropertyValue(SFORMATNAME) >>= sFormatName;
187             aEntry.CreateFilterName( sFormatName );
188 
189             Reference< XPropertySet > xTypeSet;
190             xTypeAccess->getByName( aEntry.sType ) >>= xTypeSet;
191             if (!xTypeSet.is())
192                 continue;
193 
194             xTypeSet->getPropertyValue(SMEDIATYPE) >>= aEntry.sMediaType;
195             css::uno::Sequence<OUString> tmp;
196             if (xTypeSet->getPropertyValue(SEXTENSIONS) >>= tmp)
197                 aEntry.lExtensionList = comphelper::sequenceToContainer<std::vector<OUString>>(tmp);
198 
199             // The first extension will be used
200             // to generate our internal FilterType ( BMP, WMF ... )
201             OUString aExtension( aEntry.GetShortName() );
202             if (aExtension.getLength() != 3)
203                 continue;
204 
205             if ( aEntry.nFlags & 1 )
206                 aImport.push_back( aEntry );
207             if ( aEntry.nFlags & 2 )
208                 aExport.push_back( aEntry );
209 
210             // bFilterEntryCreated!?
211             if (!( aEntry.nFlags & 3 ))
212                 continue; //? Entry was already inserted ... but following code will be suppressed?!
213         }
214     }
215 };
216 
217 const char* FilterConfigCache::InternalFilterListForSvxLight[] =
218 {
219     "bmp","1","SVBMP",
220     "bmp","2","SVBMP",
221     "dxf","1","idx",
222     "eps","1","ips",
223     "eps","2","eps",
224     "gif","1","SVIGIF",
225     "gif","2","egi",
226     "jpg","1","SVIJPEG",
227     "jpg","2","SVEJPEG",
228     "mov","1","SVMOV",
229     "mov","2","SVMOV",
230     "met","1","ime",
231     "png","1","SVIPNG",
232     "png","2","SVEPNG",
233     "pct","1","ipt",
234     "pct","2","ept",
235     "pcd","1","icd",
236     "psd","1","ipd",
237     "pcx","1","ipx",
238     "pbm","1","ipb",
239     "pgm","1","ipb",
240     "ppm","1","ipb",
241     "ras","1","ira",
242     "ras","2","era",
243     "svm","1","SVMETAFILE",
244     "svm","2","SVMETAFILE",
245     "tga","1","itg",
246     "tif","1","iti",
247     "tif","2","eti",
248     "emf","1","SVEMF",
249     "emf","2","SVEMF",
250     "wmf","1","SVWMF",
251     "wmf","2","SVWMF",
252     "xbm","1","SVIXBM",
253     "xpm","1","SVIXPM",
254     "xpm","2","exp",
255     "svg","1","SVISVG",
256     "svg","2","SVESVG",
257     nullptr
258 };
259 
ImplInitSmart()260 void FilterConfigCache::ImplInitSmart()
261 {
262     const char** pPtr;
263     for ( pPtr = InternalFilterListForSvxLight; *pPtr; pPtr++ )
264     {
265         FilterConfigCacheEntry  aEntry;
266 
267         OUString    sExtension( OUString::createFromAscii( *pPtr++ ) );
268 
269         aEntry.lExtensionList.push_back(sExtension);
270 
271         aEntry.sType = sExtension;
272         aEntry.sUIName = sExtension;
273 
274         OString sFlags( *pPtr++ );
275         aEntry.nFlags = sFlags.toInt32();
276 
277         OUString    sUserData( OUString::createFromAscii( *pPtr ) );
278         aEntry.CreateFilterName( sUserData );
279 
280         if ( aEntry.nFlags & 1 )
281             aImport.push_back( aEntry );
282         if ( aEntry.nFlags & 2 )
283             aExport.push_back( aEntry );
284     }
285 }
286 
FilterConfigCache(bool bConfig)287 FilterConfigCache::FilterConfigCache( bool bConfig )
288 {
289     if (bConfig)
290         bConfig = !utl::ConfigManager::IsFuzzing();
291     if (bConfig)
292         ImplInit();
293     else
294         ImplInitSmart();
295 }
296 
~FilterConfigCache()297 FilterConfigCache::~FilterConfigCache()
298 {
299 }
300 
GetImportFilterName(sal_uInt16 nFormat)301 OUString FilterConfigCache::GetImportFilterName( sal_uInt16 nFormat )
302 {
303     if( nFormat < aImport.size() )
304         return aImport[ nFormat ].sFilterName;
305     return OUString();
306 }
307 
GetImportFormatNumber(const OUString & rFormatName)308 sal_uInt16 FilterConfigCache::GetImportFormatNumber( const OUString& rFormatName )
309 {
310     sal_uInt16 nPos = 0;
311     for (auto const& elem : aImport)
312     {
313         if ( elem.sUIName.equalsIgnoreAsciiCase( rFormatName ) )
314             return nPos;
315         ++nPos;
316     }
317     return GRFILTER_FORMAT_NOTFOUND;
318 }
319 
320 /// get the index of the filter that matches this extension
GetImportFormatNumberForExtension(const OUString & rExt)321 sal_uInt16 FilterConfigCache::GetImportFormatNumberForExtension( const OUString& rExt )
322 {
323     sal_uInt16 nPos = 0;
324     for (auto const& elem : aImport)
325     {
326         for ( OUString const & s : elem.lExtensionList )
327         {
328             if ( s.equalsIgnoreAsciiCase( rExt ) )
329                 return nPos;
330         }
331         ++nPos;
332     }
333     return GRFILTER_FORMAT_NOTFOUND;
334 }
335 
GetImportFormatNumberForShortName(const OUString & rShortName)336 sal_uInt16 FilterConfigCache::GetImportFormatNumberForShortName( const OUString& rShortName )
337 {
338     sal_uInt16 nPos = 0;
339     for (auto & elem : aImport)
340     {
341         if ( elem.GetShortName().equalsIgnoreAsciiCase( rShortName ) )
342             return nPos;
343         ++nPos;
344     }
345     return GRFILTER_FORMAT_NOTFOUND;
346 }
347 
GetImportFormatNumberForTypeName(const OUString & rType)348 sal_uInt16 FilterConfigCache::GetImportFormatNumberForTypeName( const OUString& rType )
349 {
350     sal_uInt16 nPos = 0;
351     for (auto const& elem : aImport)
352     {
353         if ( elem.sType.equalsIgnoreAsciiCase( rType ) )
354             return nPos;
355         ++nPos;
356     }
357     return GRFILTER_FORMAT_NOTFOUND;
358 }
359 
GetImportFormatName(sal_uInt16 nFormat)360 OUString FilterConfigCache::GetImportFormatName( sal_uInt16 nFormat )
361 {
362     if( nFormat < aImport.size() )
363         return aImport[ nFormat ].sUIName;
364     return OUString();
365 }
366 
GetImportFormatMediaType(sal_uInt16 nFormat)367 OUString FilterConfigCache::GetImportFormatMediaType( sal_uInt16 nFormat )
368 {
369     if( nFormat < aImport.size() )
370         return aImport[ nFormat ].sMediaType;
371     return OUString();
372 }
373 
GetImportFormatShortName(sal_uInt16 nFormat)374 OUString FilterConfigCache::GetImportFormatShortName( sal_uInt16 nFormat )
375 {
376     if( nFormat < aImport.size() )
377         return aImport[ nFormat ].GetShortName();
378     return OUString();
379 }
380 
GetImportFormatExtension(sal_uInt16 nFormat,sal_Int32 nEntry)381 OUString FilterConfigCache::GetImportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry )
382 {
383     if ( (nFormat < aImport.size()) && (size_t(nEntry) < aImport[ nFormat ].lExtensionList.size()) )
384         return aImport[ nFormat ].lExtensionList[ nEntry ];
385     return OUString();
386 }
387 
GetImportFilterType(sal_uInt16 nFormat)388 OUString FilterConfigCache::GetImportFilterType( sal_uInt16 nFormat )
389 {
390     if( nFormat < aImport.size() )
391         return aImport[ nFormat ].sType;
392     return OUString();
393 }
394 
GetImportFilterTypeName(sal_uInt16 nFormat)395 OUString FilterConfigCache::GetImportFilterTypeName( sal_uInt16 nFormat )
396 {
397     if( nFormat < aImport.size() )
398         return aImport[ nFormat ].sFilterType;
399     return OUString();
400 }
401 
GetExternalFilterName(sal_uInt16 nFormat,bool bExport)402 OUString FilterConfigCache::GetExternalFilterName(sal_uInt16 nFormat, bool bExport)
403 {
404     if (bExport)
405     {
406         if (nFormat < aExport.size())
407             return aExport[nFormat].sExternalFilterName;
408     }
409     else
410     {
411         if (nFormat < aImport.size())
412             return aImport[nFormat].sExternalFilterName;
413     }
414     return OUString();
415 }
416 
GetImportWildcard(sal_uInt16 nFormat,sal_Int32 nEntry)417 OUString FilterConfigCache::GetImportWildcard(sal_uInt16 nFormat, sal_Int32 nEntry)
418 {
419     OUString aWildcard( GetImportFormatExtension( nFormat, nEntry ) );
420     if ( !aWildcard.isEmpty() )
421         aWildcard = aWildcard.replaceAt( 0, 0, "*." );
422     return aWildcard;
423 }
424 
IsImportInternalFilter(sal_uInt16 nFormat)425 bool FilterConfigCache::IsImportInternalFilter( sal_uInt16 nFormat )
426 {
427     return (nFormat < aImport.size()) && aImport[ nFormat ].bIsInternalFilter;
428 }
429 
GetExportFilterName(sal_uInt16 nFormat)430 OUString FilterConfigCache::GetExportFilterName( sal_uInt16 nFormat )
431 {
432     if( nFormat < aExport.size() )
433         return aExport[ nFormat ].sFilterName;
434     return OUString();
435 }
436 
GetExportFormatNumber(const OUString & rFormatName)437 sal_uInt16 FilterConfigCache::GetExportFormatNumber(const OUString& rFormatName)
438 {
439     sal_uInt16 nPos = 0;
440     for (auto const& elem : aExport)
441     {
442         if ( elem.sUIName.equalsIgnoreAsciiCase( rFormatName ) )
443             return nPos;
444         ++nPos;
445     }
446     return GRFILTER_FORMAT_NOTFOUND;
447 }
448 
GetExportFormatNumberForMediaType(const OUString & rMediaType)449 sal_uInt16 FilterConfigCache::GetExportFormatNumberForMediaType( const OUString& rMediaType )
450 {
451     sal_uInt16 nPos = 0;
452     for (auto const& elem : aExport)
453     {
454         if ( elem.sMediaType.equalsIgnoreAsciiCase( rMediaType ) )
455             return nPos;
456         ++nPos;
457     }
458     return GRFILTER_FORMAT_NOTFOUND;
459 }
460 
GetExportFormatNumberForShortName(const OUString & rShortName)461 sal_uInt16 FilterConfigCache::GetExportFormatNumberForShortName( const OUString& rShortName )
462 {
463     sal_uInt16 nPos = 0;
464     for (auto & elem : aExport)
465     {
466         if ( elem.GetShortName().equalsIgnoreAsciiCase( rShortName ) )
467             return nPos;
468         ++nPos;
469     }
470     return GRFILTER_FORMAT_NOTFOUND;
471 }
472 
GetExportFormatNumberForTypeName(const OUString & rType)473 sal_uInt16 FilterConfigCache::GetExportFormatNumberForTypeName( const OUString& rType )
474 {
475     sal_uInt16 nPos = 0;
476     for (auto const& elem : aExport)
477     {
478         if ( elem.sType.equalsIgnoreAsciiCase( rType ) )
479             return nPos;
480         ++nPos;
481     }
482     return GRFILTER_FORMAT_NOTFOUND;
483 }
484 
GetExportFormatName(sal_uInt16 nFormat)485 OUString FilterConfigCache::GetExportFormatName( sal_uInt16 nFormat )
486 {
487     if( nFormat < aExport.size() )
488         return aExport[ nFormat ].sUIName;
489     return OUString();
490 }
491 
GetExportFormatMediaType(sal_uInt16 nFormat)492 OUString FilterConfigCache::GetExportFormatMediaType( sal_uInt16 nFormat )
493 {
494     if( nFormat < aExport.size() )
495         return aExport[ nFormat ].sMediaType;
496     return OUString();
497 }
498 
GetExportFormatShortName(sal_uInt16 nFormat)499 OUString FilterConfigCache::GetExportFormatShortName( sal_uInt16 nFormat )
500 {
501     if( nFormat < aExport.size() )
502         return aExport[ nFormat ].GetShortName();
503     return OUString();
504 }
505 
GetExportFormatExtension(sal_uInt16 nFormat,sal_Int32 nEntry)506 OUString FilterConfigCache::GetExportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry )
507 {
508     if ( (nFormat < aExport.size()) && (size_t(nEntry) < aExport[ nFormat ].lExtensionList.size()) )
509         return aExport[ nFormat ].lExtensionList[ nEntry ];
510     return OUString();
511 }
512 
GetExportInternalFilterName(sal_uInt16 nFormat)513 OUString FilterConfigCache::GetExportInternalFilterName( sal_uInt16 nFormat )
514 {
515     if( nFormat < aExport.size() )
516         return aExport[ nFormat ].sInternalFilterName;
517     return OUString();
518 }
519 
GetExportWildcard(sal_uInt16 nFormat,sal_Int32 nEntry)520 OUString FilterConfigCache::GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry )
521 {
522     OUString aWildcard( GetExportFormatExtension( nFormat, nEntry ) );
523     if ( !aWildcard.isEmpty() )
524         aWildcard = aWildcard.replaceAt( 0, 0, "*." );
525     return aWildcard;
526 }
527 
IsExportInternalFilter(sal_uInt16 nFormat)528 bool FilterConfigCache::IsExportInternalFilter( sal_uInt16 nFormat )
529 {
530     return (nFormat < aExport.size()) && aExport[ nFormat ].bIsInternalFilter;
531 }
532 
IsExportPixelFormat(sal_uInt16 nFormat)533 bool FilterConfigCache::IsExportPixelFormat( sal_uInt16 nFormat )
534 {
535     return (nFormat < aExport.size()) && aExport[ nFormat ].bIsPixelFormat;
536 }
537 
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
539