Line data Source code
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 "typedetection.hxx"
21 : #include "constant.hxx"
22 :
23 : #include <com/sun/star/document/XExtendedFilterDetection.hpp>
24 : #include <com/sun/star/util/URLTransformer.hpp>
25 : #include <com/sun/star/util/XURLTransformer.hpp>
26 :
27 : #include <com/sun/star/io/XInputStream.hpp>
28 : #include <com/sun/star/io/XSeekable.hpp>
29 : #include <com/sun/star/task/XInteractionHandler.hpp>
30 : #include <tools/wldcrd.hxx>
31 : #include <rtl/ustrbuf.hxx>
32 : #include <framework/interaction.hxx>
33 : #include <tools/urlobj.hxx>
34 : #include <unotools/localfilehelper.hxx>
35 : #include <comphelper/processfactory.hxx>
36 :
37 :
38 : namespace filter{
39 : namespace config{
40 :
41 5546 : TypeDetection::TypeDetection(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
42 : {
43 : BaseContainer::init(xSMGR ,
44 : TypeDetection::impl_getImplementationName() ,
45 : TypeDetection::impl_getSupportedServiceNames(),
46 5546 : FilterCache::E_TYPE );
47 5546 : }
48 :
49 :
50 :
51 11092 : TypeDetection::~TypeDetection()
52 : {
53 11092 : }
54 :
55 :
56 :
57 2597 : ::rtl::OUString SAL_CALL TypeDetection::queryTypeByURL(const ::rtl::OUString& sURL)
58 : throw (css::uno::RuntimeException)
59 : {
60 2597 : ::rtl::OUString sType;
61 :
62 : // SAFE ->
63 2597 : ::osl::ResettableMutexGuard aLock(m_aLock);
64 :
65 2597 : css::util::URL aURL;
66 2597 : aURL.Complete = sURL;
67 2597 : css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(comphelper::getComponentContext(m_xSMGR)));
68 2597 : xParser->parseStrict(aURL);
69 :
70 : // set std types as minimum requirement first!
71 : // Only in case no type was found for given URL,
72 : // use optional types too ...
73 2597 : FlatDetection lFlatTypes;
74 2597 : m_rCache->detectFlatForURL(aURL, lFlatTypes);
75 :
76 5012 : if (
77 2597 : (lFlatTypes.size() < 1 ) &&
78 2415 : (!m_rCache->isFillState(FilterCache::E_CONTAINS_TYPES))
79 : )
80 : {
81 0 : m_rCache->load(FilterCache::E_CONTAINS_TYPES);
82 0 : m_rCache->detectFlatForURL(aURL, lFlatTypes);
83 : }
84 :
85 : // first item is guaranteed as "preferred" one!
86 2597 : if (lFlatTypes.size() > 0)
87 : {
88 182 : const FlatDetectionInfo& aMatch = *(lFlatTypes.begin());
89 182 : sType = aMatch.sType;
90 : }
91 :
92 2597 : return sType;
93 : // <- SAFE
94 : }
95 :
96 : namespace {
97 :
98 : /**
99 : * Rank format types in order of complexity. More complex formats are
100 : * ranked higher so that they get tested sooner over simpler formats.
101 : *
102 : * Guidelines to determine how complex a format is (subject to change):
103 : *
104 : * 1) compressed text (XML, HTML, etc)
105 : * 2) binary
106 : * 3) non-compressed text
107 : * 3.1) structured text
108 : * 3.1.1) dialect of a structured text (e.g. docbook XML)
109 : * 3.1.2) generic structured text (e.g. generic XML)
110 : * 3.2) non-structured text
111 : *
112 : * In each category, rank them from strictly-structured to
113 : * loosely-structured.
114 : */
115 282 : int getFlatTypeRank(const rtl::OUString& rType)
116 : {
117 : // List formats from more complex to less complex.
118 : // TODO: Add more.
119 : static const char* ranks[] = {
120 : // Compressed XML
121 : "writer8_template",
122 : "writer8",
123 : "calc8_template",
124 : "calc8",
125 : "writer_OOXML_Text_Template",
126 : "writer_OOXML",
127 : "writer_MS_Word_2007_Template",
128 : "writer_MS_Word_2007",
129 : "Office Open XML Spreadsheet Template",
130 : "Office Open XML Spreadsheet",
131 : "MS Excel 2007 XML Template",
132 : "MS Excel 2007 XML",
133 :
134 : // Compressed text
135 : "pdf_Portable_Document_Format",
136 :
137 : // Binary
138 : "writer_T602_Document",
139 : "writer_WordPerfect_Document",
140 : "writer_MS_Works_Document",
141 : "writer_MS_Word_97_Vorlage",
142 : "writer_MS_Word_97",
143 : "writer_MS_Word_95_Vorlage",
144 : "writer_MS_Word_95",
145 : "writer_MS_WinWord_60",
146 : "writer_MS_WinWord_5",
147 : "MS Excel 2007 Binary",
148 : "calc_MS_Excel_97_VorlageTemplate",
149 : "calc_MS_Excel_97",
150 : "calc_MS_Excel_95_VorlageTemplate",
151 : "calc_MS_Excel_95",
152 : "calc_MS_Excel_5095_VorlageTemplate",
153 : "calc_MS_Excel_5095",
154 : "calc_MS_Excel_40_VorlageTemplate",
155 : "calc_MS_Excel_40",
156 : "calc_Pocket_Excel_File",
157 : "calc_Lotus",
158 : "calc_QPro",
159 : "calc_SYLK",
160 : "calc_DIF",
161 : "calc_dBase",
162 :
163 :
164 : // Non-compressed XML
165 : "writer_ODT_FlatXML",
166 : "calc_ODS_FlatXML",
167 : "calc_MS_Excel_2003_XML",
168 : "writer_MS_Word_2003_XML",
169 : "writer_DocBook_File",
170 : "XHTML_File",
171 :
172 : // Non-compressed text
173 : "writer_Rich_Text_Format",
174 : "generic_HTML",
175 : "generic_Text"
176 : };
177 :
178 282 : size_t n = SAL_N_ELEMENTS(ranks);
179 :
180 4028 : for (size_t i = 0; i < n; ++i)
181 : {
182 4028 : if (rType.equalsAscii(ranks[i]))
183 282 : return n - i - 1;
184 : }
185 :
186 : // Not ranked. Treat them equally. Unranked formats have higher priority
187 : // than the ranked internal ones since they may be defined externally.
188 0 : return n;
189 : }
190 :
191 : /**
192 : * Types with matching pattern first, then extension, then custom ranks by
193 : * types, then types that are supported by the document service come next.
194 : * Lastly, sort them alphabetically.
195 : */
196 : struct SortByPriority : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
197 : {
198 141 : bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
199 : {
200 141 : if (r1.bMatchByPattern != r2.bMatchByPattern)
201 0 : return r1.bMatchByPattern;
202 :
203 141 : if (r1.bMatchByExtension != r2.bMatchByExtension)
204 0 : return r1.bMatchByExtension;
205 :
206 141 : int rank1 = getFlatTypeRank(r1.sType);
207 141 : int rank2 = getFlatTypeRank(r2.sType);
208 :
209 141 : if (rank1 != rank2)
210 141 : return rank1 > rank2;
211 :
212 0 : if (r1.bPreselectedByDocumentService != r2.bPreselectedByDocumentService)
213 0 : return r1.bPreselectedByDocumentService;
214 :
215 : // All things being equal, sort them alphabetically.
216 0 : return r1.sType > r2.sType;
217 : }
218 : };
219 :
220 : struct EqualByName : public std::binary_function<FlatDetectionInfo, FlatDetectionInfo, bool>
221 : {
222 117 : bool operator() (const FlatDetectionInfo& r1, const FlatDetectionInfo& r2) const
223 : {
224 117 : return r1.sType == r2.sType;
225 : }
226 : };
227 :
228 : }
229 :
230 240 : ::rtl::OUString SAL_CALL TypeDetection::queryTypeByDescriptor(css::uno::Sequence< css::beans::PropertyValue >& lDescriptor,
231 : sal_Bool bAllowDeep )
232 : throw (css::uno::RuntimeException)
233 : {
234 : // make the descriptor more useable :-)
235 240 : ::comphelper::MediaDescriptor stlDescriptor(lDescriptor);
236 :
237 : // SAFE -> ----------------------------------
238 240 : ::osl::ResettableMutexGuard aLock(m_aLock);
239 :
240 : //*******************************************
241 : // parse given URL to split it into e.g. main and jump marks ...
242 240 : ::rtl::OUString sURL = stlDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString());
243 :
244 : #if OSL_DEBUG_LEVEL > 0
245 : if (stlDescriptor.find(::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FileName" ))) != stlDescriptor.end())
246 : OSL_FAIL("Detect using of deprecated and already unsupported MediaDescriptor property \"FileName\"!");
247 : #endif
248 :
249 240 : css::util::URL aURL;
250 240 : aURL.Complete = sURL;
251 240 : css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(comphelper::getComponentContext(m_xSMGR)));
252 240 : xParser->parseStrict(aURL);
253 :
254 : rtl::OUString aSelectedFilter = stlDescriptor.getUnpackedValueOrDefault(
255 240 : comphelper::MediaDescriptor::PROP_FILTERNAME(), rtl::OUString());
256 240 : if (!aSelectedFilter.isEmpty())
257 : {
258 : // Caller specified the filter type. Honor it. Just get the default
259 : // type for that filter, and bail out.
260 0 : if (impl_validateAndSetFilterOnDescriptor(stlDescriptor, aSelectedFilter))
261 0 : return stlDescriptor[comphelper::MediaDescriptor::PROP_TYPENAME()].get<rtl::OUString>();
262 : }
263 :
264 : // preselected type or document service? use it as first "flat" detected
265 : // type later!
266 240 : FlatDetection lFlatTypes;
267 240 : impl_getPreselection(aURL, stlDescriptor, lFlatTypes);
268 :
269 : //*******************************************
270 : // get all types, which match to the given descriptor
271 : // That can be true by: extensions/url pattern/mime type etcpp.
272 240 : m_rCache->detectFlatForURL(aURL, lFlatTypes);
273 :
274 240 : aLock.clear();
275 : // <- SAFE ----------------------------------
276 :
277 : // Properly prioritize all candidate types.
278 240 : lFlatTypes.sort(SortByPriority());
279 240 : lFlatTypes.unique(EqualByName());
280 :
281 240 : ::rtl::OUString sType ;
282 240 : ::rtl::OUString sLastChance;
283 :
284 : try
285 : {
286 : //*******************************************
287 : // verify every flat detected (or preselected!) type
288 : // by calling its registered deep detection service.
289 : // But break this loop if a type match to the given descriptor
290 : // by an URL pattern(!) or if deep detection isnt allowed from
291 : // outside (bAllowDeep=sal_False) or break the whole detection by
292 : // throwing an exception if creation of the might needed input
293 : // stream failed by e.g. an IO exception ...
294 240 : OUStringList lUsedDetectors;
295 240 : if (lFlatTypes.size()>0)
296 182 : sType = impl_detectTypeFlatAndDeep(stlDescriptor, lFlatTypes, bAllowDeep, lUsedDetectors, sLastChance);
297 :
298 : //*******************************************
299 : // if no flat detected (nor preselected!) type could be
300 : // verified and no error occurred during creation of
301 : // the might needed input stream, start detection
302 : // which uses all registered deep detection services.
303 240 : if (
304 240 : (sType.isEmpty()) &&
305 : (bAllowDeep )
306 : )
307 : {
308 58 : sType = impl_detectTypeDeepOnly(stlDescriptor, lUsedDetectors);
309 : }
310 :
311 : //*******************************************
312 : // flat detection failed
313 : // pure deep detection failed
314 : // => ask might existing InteractionHandler
315 : // means: ask user for it's decision
316 240 : if (sType.isEmpty())
317 3 : sType = impl_askUserForTypeAndFilterIfAllowed(stlDescriptor);
318 :
319 : //*******************************************
320 : // no real detected type - but a might valid one.
321 : // update descriptor and set last chance for return.
322 240 : if (sType.isEmpty() && !sLastChance.isEmpty())
323 : {
324 : OSL_FAIL("set first flat detected type without a registered deep detection service as \"last chance\" ... nevertheless some other deep detections said \"NO\". I TRY IT!");
325 0 : sType = sLastChance;
326 240 : }
327 : }
328 0 : catch(const css::uno::RuntimeException&)
329 0 : { throw; }
330 0 : catch(const css::uno::Exception&)
331 0 : { sType = ::rtl::OUString(); }
332 :
333 : //*******************************************
334 : // adapt media descriptor, so it contains the right values
335 : // for type/filter name/document service/ etcpp.
336 240 : impl_checkResultsAndAddBestFilter(stlDescriptor, sType); // Attention: sType is used as IN/OUT param here and will might be changed inside this method !!!
337 240 : impl_validateAndSetTypeOnDescriptor(stlDescriptor, sType);
338 :
339 240 : stlDescriptor >> lDescriptor;
340 240 : return sType;
341 : }
342 :
343 :
344 :
345 240 : void TypeDetection::impl_checkResultsAndAddBestFilter(::comphelper::MediaDescriptor& rDescriptor,
346 : ::rtl::OUString& sType )
347 : {
348 : // a)
349 : // Dont overwrite a might preselected filter!
350 : ::rtl::OUString sFilter = rDescriptor.getUnpackedValueOrDefault(
351 240 : ::comphelper::MediaDescriptor::PROP_FILTERNAME(),
352 480 : ::rtl::OUString());
353 240 : if (!sFilter.isEmpty())
354 : return;
355 :
356 : // b)
357 : // check a preselected document service too.
358 : // Then we have to search a suitable filter witin this module.
359 : ::rtl::OUString sDocumentService = rDescriptor.getUnpackedValueOrDefault(
360 240 : ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(),
361 480 : ::rtl::OUString());
362 240 : if (!sDocumentService.isEmpty())
363 : {
364 : try
365 : {
366 0 : ::rtl::OUString sRealType = sType;
367 :
368 : // SAFE ->
369 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
370 :
371 : // Attention: For executing next lines of code, We must be shure that
372 : // all filters already loaded :-(
373 : // That can disturb our "load on demand feature". But we have no other chance!
374 0 : m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
375 :
376 0 : CacheItem lIProps;
377 0 : lIProps[PROPNAME_DOCUMENTSERVICE] <<= sDocumentService;
378 0 : lIProps[PROPNAME_TYPE ] <<= sRealType;
379 0 : OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
380 :
381 0 : aLock.clear();
382 : // <- SAFE
383 :
384 0 : for (OUStringList::const_iterator pIt = lFilters.begin();
385 0 : pIt != lFilters.end(); ++pIt)
386 : {
387 : // SAFE ->
388 0 : aLock.reset();
389 : try
390 : {
391 0 : CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, *pIt);
392 0 : sal_Int32 nFlags = 0;
393 0 : aFilter[PROPNAME_FLAGS] >>= nFlags;
394 :
395 0 : if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
396 0 : sFilter = *pIt;
397 0 : if ((nFlags & FLAGVAL_PREFERRED) == FLAGVAL_PREFERRED)
398 0 : break;
399 : }
400 0 : catch(const css::uno::Exception&) {}
401 0 : aLock.clear();
402 : // <- SAFE
403 : }
404 :
405 0 : if (!sFilter.isEmpty())
406 : {
407 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sRealType;
408 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
409 0 : sType = sRealType;
410 : return;
411 0 : }
412 : }
413 0 : catch(const css::uno::Exception&)
414 : {}
415 : }
416 :
417 : // c)
418 : // We can use the preferred filter for the specified type.
419 : // Such preferred filter points:
420 : // - to the default filter of the preferred application
421 : // - or to any other filter if no preferred filter was set.
422 : // Note: It's an optimization only!
423 : // It's not guaranteed, that such preferred filter exists.
424 240 : sFilter = ::rtl::OUString();
425 : try
426 : {
427 : // SAFE ->
428 240 : ::osl::ResettableMutexGuard aLock(m_aLock);
429 :
430 240 : CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
431 237 : aType[PROPNAME_PREFERREDFILTER] >>= sFilter;
432 237 : CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
433 :
434 237 : aLock.clear();
435 : // <- SAFE
436 :
437 : // no exception => found valid type and filter => set it on the given descriptor
438 237 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ;
439 237 : rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
440 237 : return;
441 : }
442 3 : catch(const css::uno::Exception&)
443 : {}
444 :
445 : // d)
446 : // Search for any import(!) filter, which is registered for this type.
447 3 : sFilter = ::rtl::OUString();
448 : try
449 : {
450 : // SAFE ->
451 3 : ::osl::ResettableMutexGuard aLock(m_aLock);
452 :
453 : // Attention: For executing next lines of code, We must be shure that
454 : // all filters already loaded :-(
455 : // That can disturb our "load on demand feature". But we have no other chance!
456 3 : m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
457 :
458 3 : CacheItem lIProps;
459 3 : lIProps[PROPNAME_TYPE] <<= sType;
460 3 : OUStringList lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
461 :
462 3 : aLock.clear();
463 : // <- SAFE
464 :
465 3 : OUStringList::const_iterator pIt;
466 9 : for ( pIt = lFilters.begin();
467 6 : pIt != lFilters.end() ;
468 : ++pIt )
469 : {
470 0 : sFilter = *pIt;
471 :
472 : // SAFE ->
473 0 : aLock.reset();
474 : try
475 : {
476 0 : CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
477 0 : sal_Int32 nFlags = 0;
478 0 : aFilter[PROPNAME_FLAGS] >>= nFlags;
479 :
480 0 : if ((nFlags & FLAGVAL_IMPORT) == FLAGVAL_IMPORT)
481 0 : break;
482 : }
483 0 : catch(const css::uno::Exception&)
484 0 : { continue; }
485 0 : aLock.clear();
486 : // <- SAFE
487 :
488 0 : sFilter = ::rtl::OUString();
489 : }
490 :
491 3 : if (!sFilter.isEmpty())
492 : {
493 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ;
494 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
495 : return;
496 3 : }
497 : }
498 0 : catch(const css::uno::Exception&)
499 240 : {}
500 : }
501 :
502 :
503 :
504 0 : sal_Bool TypeDetection::impl_getPreselectionForType(const ::rtl::OUString& sPreSelType,
505 : const css::util::URL& aParsedURL ,
506 : FlatDetection& rFlatTypes )
507 : {
508 : // Can be used to supress execution of some parts of this method
509 : // if its already clear that detected type is valid or not.
510 : // Its neccessary to use shared code at the end, which update
511 : // all return parameters constistency!
512 0 : sal_Bool bBreakDetection = sal_False;
513 :
514 : // Further we must know if it matches by pattern
515 : // Every flat detected type by pattern wont be detected deep!
516 0 : sal_Bool bMatchByPattern = sal_False;
517 :
518 : // And we must know if a preselection must be preferred, because
519 : // it matches by it's extension too.
520 0 : sal_Bool bMatchByExtension = sal_False;
521 :
522 : // If we e.g. collect all filters of a factory (be a forced factory preselection)
523 : // we should preferr all filters of this factory, where the type match the given URL.
524 : // All other types (which sorrespond to filters of the same factory - but dont match
525 : // the URL) should be "used later" for detection and sorted at the end of our return vector
526 : // rFlatTypes!
527 : // => bPreferredPreselection = (matchByExtension || matchByURLPattern)
528 0 : sal_Bool bPreferredPreselection = sal_False;
529 :
530 : // validate type
531 0 : ::rtl::OUString sType(sPreSelType);
532 0 : CacheItem aType;
533 : try
534 : {
535 : // SAFE -> --------------------------
536 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
537 0 : aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
538 0 : aLock.clear();
539 : // <- SAFE --------------------------
540 : }
541 0 : catch(const css::container::NoSuchElementException&)
542 : {
543 0 : sType = ::rtl::OUString();
544 0 : bBreakDetection = sal_True;
545 : }
546 :
547 0 : if (!bBreakDetection)
548 : {
549 : // We cant check a preselected type for a given stream!
550 : // So we must believe, that it can work ...
551 0 : if ( aParsedURL.Complete == "private:stream" )
552 0 : bBreakDetection = sal_True;
553 : }
554 :
555 0 : if (!bBreakDetection)
556 : {
557 : // extract extension from URL .. to check it case-insensitive !
558 0 : INetURLObject aParser (aParsedURL.Main);
559 : ::rtl::OUString sExtension = aParser.getExtension(INetURLObject::LAST_SEGMENT ,
560 : sal_True ,
561 0 : INetURLObject::DECODE_WITH_CHARSET);
562 0 : sExtension = sExtension.toAsciiLowerCase();
563 :
564 : // otherwhise we must know, if it matches to the given URL realy.
565 : // especialy if it matches by its extension or pattern registration.
566 0 : OUStringList lExtensions(aType[PROPNAME_EXTENSIONS]);
567 0 : OUStringList lURLPattern(aType[PROPNAME_URLPATTERN]);
568 :
569 0 : for (OUStringList::const_iterator pIt = lExtensions.begin();
570 0 : pIt != lExtensions.end() ;
571 : ++pIt )
572 : {
573 0 : ::rtl::OUString sCheckExtension(pIt->toAsciiLowerCase());
574 0 : if (sCheckExtension.equals(sExtension))
575 : {
576 0 : bBreakDetection = sal_True;
577 0 : bMatchByExtension = sal_True;
578 0 : bPreferredPreselection = sal_True;
579 : break;
580 : }
581 0 : }
582 :
583 0 : if (!bBreakDetection)
584 : {
585 0 : for (OUStringList::const_iterator pIt = lURLPattern.begin();
586 0 : pIt != lURLPattern.end() ;
587 : ++pIt )
588 : {
589 0 : WildCard aCheck(*pIt);
590 0 : if (aCheck.Matches(aParsedURL.Main))
591 : {
592 0 : bBreakDetection = sal_True;
593 0 : bMatchByPattern = sal_True;
594 0 : bPreferredPreselection = sal_True;
595 : break;
596 : }
597 0 : }
598 0 : }
599 : }
600 :
601 : // if its a valid type - set it on all return values!
602 0 : if (!sType.isEmpty())
603 : {
604 0 : FlatDetectionInfo aInfo;
605 0 : aInfo.sType = sType;
606 0 : aInfo.bMatchByExtension = bMatchByExtension;
607 0 : aInfo.bMatchByPattern = bMatchByPattern;
608 :
609 0 : if (bPreferredPreselection)
610 0 : rFlatTypes.push_front(aInfo);
611 : else
612 0 : rFlatTypes.push_back(aInfo);
613 :
614 0 : return sal_True;
615 : }
616 :
617 : // not valid!
618 0 : return sal_False;
619 : }
620 :
621 :
622 :
623 0 : sal_Bool TypeDetection::impl_getPreselectionForFilter(const ::rtl::OUString& sPreSelFilter,
624 : const css::util::URL& aParsedURL ,
625 : FlatDetection& rFlatTypes )
626 : {
627 : // Can be used to supress execution of some parts of this method
628 : // if its already clear that detected filter is valid or not.
629 : // Its neccessary to use shared code at the end, which update
630 : // all return parameters constistency!
631 0 : sal_Bool bBreakDetection = sal_False;
632 :
633 : // validate filter
634 0 : ::rtl::OUString sFilter(sPreSelFilter);
635 0 : CacheItem aFilter;
636 : try
637 : {
638 : // SAFE -> --------------------------
639 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
640 0 : aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
641 0 : aLock.clear();
642 : // <- SAFE --------------------------
643 : }
644 0 : catch(const css::container::NoSuchElementException&)
645 : {
646 0 : sFilter = ::rtl::OUString();
647 0 : bBreakDetection = sal_True;
648 : }
649 :
650 0 : if (!bBreakDetection)
651 : {
652 : // get its type and check if it matches the given URL
653 0 : ::rtl::OUString sType;
654 0 : aFilter[PROPNAME_TYPE] >>= sType;
655 :
656 0 : bBreakDetection = impl_getPreselectionForType(sType, aParsedURL, rFlatTypes);
657 :
658 : // not a valid type? -> not a valid filter!
659 0 : if (!bBreakDetection)
660 0 : sFilter = ::rtl::OUString();
661 : }
662 :
663 0 : if (!sFilter.isEmpty())
664 0 : return sal_True;
665 : else
666 0 : return sal_False;
667 : }
668 :
669 :
670 :
671 0 : sal_Bool TypeDetection::impl_getPreselectionForDocumentService(const ::rtl::OUString& sPreSelDocumentService,
672 : const css::util::URL& aParsedURL ,
673 : FlatDetection& rFlatTypes )
674 : {
675 : // get all filters, which match to this doc service
676 0 : OUStringList lFilters;
677 : try
678 : {
679 : // SAFE -> --------------------------
680 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
681 :
682 : // Attention: For executing next lines of code, We must be shure that
683 : // all filters already loaded :-(
684 : // That can disturb our "load on demand feature". But we have no other chance!
685 0 : m_rCache->load(FilterCache::E_CONTAINS_FILTERS);
686 :
687 0 : CacheItem lIProps;
688 0 : lIProps[PROPNAME_DOCUMENTSERVICE] <<= sPreSelDocumentService;
689 0 : lFilters = m_rCache->getMatchingItemsByProps(FilterCache::E_FILTER, lIProps);
690 :
691 0 : aLock.clear();
692 : // <- SAFE --------------------------
693 : }
694 0 : catch(const css::container::NoSuchElementException&)
695 : {
696 0 : lFilters.clear();
697 : }
698 :
699 : // step over all filters, and check if its registered type
700 : // match the given URL.
701 : // But use temp. list of "preselected types" instead of incoming rFlatTypes list!
702 : // The reason behind: we must filter the getted results. And copying of stl entries
703 : // is an easier job then removing it .-)
704 0 : FlatDetection lPreselections;
705 0 : for (OUStringList::const_iterator pFilter = lFilters.begin();
706 0 : pFilter != lFilters.end() ;
707 : ++pFilter )
708 : {
709 0 : const ::rtl::OUString sFilter = *pFilter;
710 0 : impl_getPreselectionForFilter(sFilter, aParsedURL, lPreselections);
711 0 : }
712 :
713 : // We have to mark all retrieved preselection items as "preselected by document service".
714 : // Further we must ignore all preselected items, which does not match the URL!
715 0 : FlatDetection::iterator pIt;
716 0 : for ( pIt = lPreselections.begin();
717 0 : pIt != lPreselections.end() ;
718 : ++pIt )
719 : {
720 0 : FlatDetectionInfo& rInfo = *pIt;
721 0 : rInfo.bPreselectedByDocumentService = sal_True ;
722 0 : rFlatTypes.push_back(rInfo);
723 : }
724 :
725 0 : return sal_True;
726 : }
727 :
728 :
729 :
730 240 : void TypeDetection::impl_getPreselection(const css::util::URL& aParsedURL ,
731 : ::comphelper::MediaDescriptor& rDescriptor,
732 : FlatDetection& rFlatTypes )
733 : {
734 : // done to be shure, that only valid results leave this function!
735 240 : rFlatTypes.clear();
736 :
737 : /* #i55122#
738 : Sometimes we must detect files without or with real unknown extensions.
739 : If it does not work /which can happen of course .-)/, the user tried to preselect
740 : the right format. But some special dialogs (e.g. "Insert->Sheet From File")
741 : add it's own preselection too.
742 : So we have a combination of preselected values ...
743 :
744 : The we should preferr the most important one - set by the user.
745 : And the user normaly preselects a filter or type. The preslected
746 : document service cames from the dialog.
747 :
748 : Further it doesnt matter if the user preselected a filter or a document service.
749 : A filter selection is always more explicit then a document service selection.
750 : So it must be pereferred. An order between type and filter selection cant be discussed .-)
751 : */
752 :
753 240 : ::rtl::OUString sSelectedType = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_TYPENAME(), ::rtl::OUString());
754 240 : if (!sSelectedType.isEmpty())
755 0 : impl_getPreselectionForType(sSelectedType, aParsedURL, rFlatTypes);
756 :
757 240 : ::rtl::OUString sSelectedDoc = rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(), ::rtl::OUString());
758 240 : if (!sSelectedDoc.isEmpty())
759 0 : impl_getPreselectionForDocumentService(sSelectedDoc, aParsedURL, rFlatTypes);
760 240 : }
761 :
762 :
763 :
764 182 : ::rtl::OUString TypeDetection::impl_detectTypeFlatAndDeep( ::comphelper::MediaDescriptor& rDescriptor ,
765 : const FlatDetection& lFlatTypes ,
766 : sal_Bool bAllowDeep ,
767 : OUStringList& rUsedDetectors,
768 : ::rtl::OUString& rLastChance )
769 : {
770 : // reset it everytimes, so the outside code can distinguish between
771 : // a set and a not set value.
772 182 : rLastChance = ::rtl::OUString();
773 182 : rUsedDetectors.clear();
774 :
775 : // step over all possible types for this URL.
776 : // solutions:
777 : // a) no types => no detection
778 : // b) deep detection not allowed => return first valid type of list (because its the preferred or the first valid one)
779 : // or(!) match by URLPattern => in such case a deep detection will be supressed!
780 : // c) type has no detect service => safe the first occurred type without a detect service
781 : // as "last chance"(!). It will be used outside of this method
782 : // if no further type could be detected.
783 : // It must be the first one, because it can be a preferred type.
784 : // Our types list was sorted by such criteria!
785 : // d) detect service return a valid result => return its decision
786 : // e) detect service return an invalid result
787 : // or any needed information could not be
788 : // getted from the cache => ignore it, and continue with search
789 :
790 546 : for (FlatDetection::const_iterator pFlatIt = lFlatTypes.begin();
791 364 : pFlatIt != lFlatTypes.end() ;
792 : ++pFlatIt )
793 : {
794 182 : const FlatDetectionInfo& aFlatTypeInfo = *pFlatIt;
795 182 : ::rtl::OUString sFlatType = aFlatTypeInfo.sType;
796 :
797 182 : if (!impl_validateAndSetTypeOnDescriptor(rDescriptor, sFlatType))
798 0 : continue;
799 :
800 : // b)
801 182 : if (
802 : (!bAllowDeep ) ||
803 : (aFlatTypeInfo.bMatchByPattern)
804 : )
805 : {
806 0 : return sFlatType;
807 : }
808 :
809 : try
810 : {
811 : // SAFE -> ----------------------------------
812 182 : ::osl::ResettableMutexGuard aLock(m_aLock);
813 182 : CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sFlatType);
814 182 : aLock.clear();
815 :
816 182 : ::rtl::OUString sDetectService;
817 182 : aType[PROPNAME_DETECTSERVICE] >>= sDetectService;
818 :
819 : // c)
820 182 : if (sDetectService.isEmpty())
821 : {
822 : // flat detected types without any registered deep detection service and not
823 : // preselected by the user can be used as LAST CHANCE in case no other type could
824 : // be detected. Of course only the first type without deep detector can be used.
825 : // Further ones has to be ignored.
826 0 : if (rLastChance.isEmpty())
827 0 : rLastChance = sFlatType;
828 :
829 0 : continue;
830 : }
831 :
832 : // dont forget to add every real asked deep detection service here.
833 : // Such detectors will be ignored if may be "impl_detectTypeDeepOnly()"
834 : // must be called later!
835 182 : rUsedDetectors.push_back(sDetectService);
836 182 : ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
837 :
838 : // d)
839 182 : if (!sDeepType.isEmpty())
840 182 : return sDeepType;
841 : }
842 0 : catch(const css::container::NoSuchElementException&)
843 : {}
844 : // e)
845 182 : }
846 :
847 0 : return ::rtl::OUString();
848 : // <- SAFE ----------------------------------
849 : }
850 :
851 : //TO-DO: add a priority entry to filter config, e.g. defaulting to 50 and
852 : //flag externally that some filters are lower e.g. 25 and are catch-alls
853 : //to be tried last. Split up writer/calc/etc. filter detection to standalone
854 : //those problematic formats
855 : namespace
856 : {
857 7482 : bool sort_catchalls_to_end(const rtl::OUString& rA, const rtl::OUString& rB)
858 : {
859 7482 : if (rA == rB)
860 0 : return false;
861 7482 : if ( rA == "com.sun.star.text.FormatDetector" )
862 116 : return false;
863 7366 : if ( rB == "com.sun.star.text.FormatDetector" )
864 58 : return true;
865 7308 : return rA < rB;
866 : }
867 : }
868 :
869 58 : ::rtl::OUString TypeDetection::impl_detectTypeDeepOnly( ::comphelper::MediaDescriptor& rDescriptor ,
870 : const OUStringList& lOutsideUsedDetectors)
871 : {
872 : // We must know if a detect service was already used:
873 : // i) in a combined flat/deep detection scenario outside or
874 : // ii) in this method for a deep detection only.
875 : // Reason: Such deep detection services work differently in these two modes!
876 58 : OUStringList lInsideUsedDetectors;
877 58 : OUStringList::const_iterator pIt;
878 :
879 : // a)
880 : // The list of "already used detect services" correspond to the list
881 : // of preselected or flat detected types. But these detect services was called
882 : // to check these types explicitly and return black/white ... yes/no only.
883 : // Now they are called to return any possible result. But we should preferr
884 : // these already used detect services against all other ones!
885 174 : for ( pIt = lOutsideUsedDetectors.begin();
886 116 : pIt != lOutsideUsedDetectors.end() ;
887 : ++pIt )
888 : {
889 0 : const ::rtl::OUString& sDetectService = *pIt;
890 0 : ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
891 0 : if (!sDeepType.isEmpty())
892 0 : return sDeepType;
893 0 : lInsideUsedDetectors.push_back(sDetectService);
894 0 : }
895 :
896 : // SAFE -> ----------------------------------
897 58 : ::osl::ResettableMutexGuard aLock(m_aLock);
898 58 : OUStringList lDetectors = m_rCache->getItemNames(FilterCache::E_DETECTSERVICE);
899 58 : std::sort(lDetectors.begin(), lDetectors.end(), sort_catchalls_to_end);
900 58 : aLock.clear();
901 : // <- SAFE ----------------------------------
902 :
903 : // b)
904 : // Sometimes it would be nice to ask a special set of detect services before
905 : // any other detect service is asked. E.g. by using a preselection of a DocumentService.
906 : // That's needed to prevent us from asking the "wrong application module" and
907 : // opening the files into the "wrong application".
908 : ::rtl::OUString sPreselDocumentService = rDescriptor.getUnpackedValueOrDefault(
909 58 : ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(),
910 116 : ::rtl::OUString());
911 58 : if (!sPreselDocumentService.isEmpty())
912 : {
913 0 : for ( pIt = lDetectors.begin();
914 0 : pIt != lDetectors.end() ;
915 : ++pIt )
916 : {
917 0 : const ::rtl::OUString& sDetectService = *pIt;
918 :
919 0 : OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService);
920 0 : if (pAlreadyUsed != lInsideUsedDetectors.end())
921 0 : continue;
922 :
923 : // SAFE -> --------------------------------------------------------
924 0 : aLock.reset();
925 :
926 0 : CacheItem lIProps;
927 0 : lIProps[PROPNAME_DETECTSERVICE] <<= sDetectService;
928 0 : OUStringList lTypes = m_rCache->getMatchingItemsByProps(FilterCache::E_TYPE, lIProps);
929 :
930 0 : aLock.clear();
931 : // <- SAFE --------------------------------------------------------
932 :
933 0 : sal_Bool bMatchDetectorToDocumentService = sal_False;
934 0 : OUStringList::const_iterator pIt2;
935 0 : for ( pIt2 = lTypes.begin();
936 0 : pIt2 != lTypes.end() ;
937 : ++pIt2 )
938 : {
939 0 : const ::rtl::OUString& sType = *pIt2;
940 :
941 : try
942 : {
943 : // SAFE -> ----------------------------------------------------
944 0 : aLock.reset();
945 :
946 0 : CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
947 0 : ::rtl::OUString sFilter;
948 0 : aType[PROPNAME_PREFERREDFILTER] >>= sFilter;
949 0 : CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
950 0 : ::rtl::OUString sCheckDocumentService;
951 0 : aFilter[PROPNAME_DOCUMENTSERVICE] >>= sCheckDocumentService;
952 :
953 0 : aLock.clear();
954 : // <- SAFE
955 :
956 0 : if (sCheckDocumentService.equals(sPreselDocumentService))
957 : {
958 0 : bMatchDetectorToDocumentService = sal_True;
959 : break;
960 0 : }
961 : }
962 0 : catch(const css::uno::Exception&)
963 0 : { continue; }
964 : }
965 :
966 0 : if (bMatchDetectorToDocumentService)
967 : {
968 0 : ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
969 0 : if (!sDeepType.isEmpty())
970 0 : return sDeepType;
971 0 : lInsideUsedDetectors.push_back(sDetectService);
972 : }
973 0 : }
974 : }
975 :
976 : // c)
977 : // Last chance. No "used detectors", no "preselected detectors" ... ask any existing detect services
978 : // for this till know unknown format.
979 3519 : for ( pIt = lDetectors.begin();
980 2346 : pIt != lDetectors.end() ;
981 : ++pIt )
982 : {
983 1170 : const ::rtl::OUString& sDetectService = *pIt;
984 :
985 1170 : OUStringList::const_iterator pAlreadyUsed = ::std::find(lInsideUsedDetectors.begin(), lInsideUsedDetectors.end(), sDetectService);
986 1170 : if (pAlreadyUsed != lInsideUsedDetectors.end())
987 0 : continue;
988 :
989 1170 : ::rtl::OUString sDeepType = impl_askDetectService(sDetectService, rDescriptor);
990 1170 : if (!sDeepType.isEmpty())
991 55 : return sDeepType;
992 1170 : }
993 :
994 3 : return ::rtl::OUString();
995 : }
996 :
997 1592 : void TypeDetection::impl_seekStreamToZero(comphelper::MediaDescriptor& rDescriptor)
998 : {
999 : // try to seek to 0 ...
1000 : // But because XSeekable is an optional interface ... try it only .-)
1001 : css::uno::Reference< css::io::XInputStream > xStream = rDescriptor.getUnpackedValueOrDefault(
1002 1592 : ::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
1003 3184 : css::uno::Reference< css::io::XInputStream >());
1004 1592 : css::uno::Reference< css::io::XSeekable > xSeek(xStream, css::uno::UNO_QUERY);
1005 1592 : if (xSeek.is())
1006 : {
1007 : try
1008 : {
1009 1592 : xSeek->seek(0);
1010 : }
1011 0 : catch(const css::uno::RuntimeException&)
1012 : {
1013 0 : throw;
1014 : }
1015 0 : catch(const css::uno::Exception&)
1016 : {
1017 : }
1018 1592 : }
1019 1592 : }
1020 :
1021 1352 : ::rtl::OUString TypeDetection::impl_askDetectService(const ::rtl::OUString& sDetectService,
1022 : ::comphelper::MediaDescriptor& rDescriptor )
1023 : {
1024 : // Open the stream and add it to the media descriptor if this method is called for the first time.
1025 : // All following requests to this method will detect, that there already exists a stream .-)
1026 : // Attention: This method throws an exception if the stream could not be opened.
1027 : // It's important to break any further detection in such case.
1028 : // Catch it on the highest detection level only !!!
1029 1352 : impl_openStream(rDescriptor);
1030 :
1031 : // seek to 0 is an optional feature to be more robust against
1032 : // "simple implemented detect services" .-)
1033 1352 : impl_seekStreamToZero(rDescriptor);
1034 :
1035 1352 : css::uno::Reference< css::document::XExtendedFilterDetection > xDetector;
1036 1352 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR;
1037 :
1038 : // SAFE ->
1039 1352 : ::osl::ResettableMutexGuard aLock(m_aLock);
1040 1352 : xSMGR = m_xSMGR;
1041 1352 : aLock.clear();
1042 : // <- SAFE
1043 :
1044 : try
1045 : {
1046 : // Attention! If e.g. an office module was not installed sometimes we
1047 : // find a registered detect service, which is referred inside the
1048 : // configuration ... but not realy installed. On the other side we use
1049 : // third party components here, which can make trouble anyway. So we
1050 : // should handle errors during creation of such services more
1051 : // gracefully .-)
1052 : xDetector = css::uno::Reference< css::document::XExtendedFilterDetection >(
1053 1352 : xSMGR->createInstance(sDetectService),
1054 1352 : css::uno::UNO_QUERY_THROW);
1055 : }
1056 1112 : catch (...)
1057 : {
1058 : }
1059 :
1060 1352 : if ( ! xDetector.is())
1061 1112 : return ::rtl::OUString();
1062 :
1063 240 : ::rtl::OUString sDeepType;
1064 : try
1065 : {
1066 : // start deep detection
1067 : // Dont forget to convert stl descriptor to its uno representation.
1068 :
1069 : /* Attention!
1070 : You have to use an explicit instance of this uno sequence ...
1071 : Because its used as an in out parameter. And in case of a temp. used object
1072 : we will run into memory corruptions!
1073 : */
1074 240 : css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
1075 240 : rDescriptor >> lDescriptor;
1076 240 : sDeepType = xDetector->detect(lDescriptor);
1077 240 : rDescriptor << lDescriptor;
1078 : }
1079 0 : catch(const css::uno::Exception&)
1080 : {
1081 : // We should ignore errors here.
1082 : // Thrown exceptions mostly will end in crash recovery ...
1083 : // But might be we find another deep detection service which can detect the same
1084 : // document without a problem .-)
1085 0 : sDeepType = ::rtl::OUString();
1086 : }
1087 :
1088 : // seek to 0 is an optional feature to be more robust against
1089 : // "simple implemented detect services" .-)
1090 240 : impl_seekStreamToZero(rDescriptor);
1091 :
1092 : // analyze the results
1093 : // a) detect service returns "" => return "" too and remove TYPE/FILTER prop from descriptor
1094 : // b) returned type is unknown => return "" too and remove TYPE/FILTER prop from descriptor
1095 : // c) returned type is valid => check TYPE/FILTER props inside descriptor and return the type
1096 :
1097 : // this special helper checks for a valid type
1098 : // and set right values on the descriptor!
1099 240 : sal_Bool bValidType = impl_validateAndSetTypeOnDescriptor(rDescriptor, sDeepType);
1100 240 : if (bValidType)
1101 237 : return sDeepType;
1102 :
1103 3 : return ::rtl::OUString();
1104 : }
1105 :
1106 :
1107 :
1108 3 : ::rtl::OUString TypeDetection::impl_askUserForTypeAndFilterIfAllowed(::comphelper::MediaDescriptor& rDescriptor)
1109 : {
1110 : // SAFE ->
1111 3 : ::osl::ResettableMutexGuard aLock(m_aLock);
1112 3 : css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1113 3 : aLock.clear();
1114 : // <- SAFE
1115 :
1116 : css::uno::Reference< css::task::XInteractionHandler > xInteraction =
1117 3 : rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER(),
1118 6 : css::uno::Reference< css::task::XInteractionHandler >());
1119 :
1120 3 : if (!xInteraction.is())
1121 3 : return ::rtl::OUString();
1122 :
1123 : ::rtl::OUString sURL =
1124 0 : rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(),
1125 0 : ::rtl::OUString());
1126 :
1127 : css::uno::Reference< css::io::XInputStream > xStream =
1128 0 : rDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
1129 0 : css::uno::Reference< css::io::XInputStream >());
1130 :
1131 : // Dont distrub the user for "non existing files - means empty URLs" or
1132 : // if we was forced to detect a stream.
1133 : // Reason behind: We must be shure to ask user for "unknown contents" only ...
1134 : // and not for "missing files". Especialy if detection is done by a stream only
1135 : // we cant check if the stream points to an "existing content"!
1136 0 : if (
1137 0 : (sURL.isEmpty() ) || // "non existing file" ?
1138 0 : (!xStream.is() ) || // non existing file !
1139 0 : (sURL.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("private:stream"))) // not a good idea .-)
1140 : )
1141 0 : return ::rtl::OUString();
1142 :
1143 : try
1144 : {
1145 : // create a new request to ask user for it's decision about the usable filter
1146 0 : ::framework::RequestFilterSelect aRequest(sURL);
1147 0 : xInteraction->handle(aRequest.GetRequest());
1148 :
1149 : // "Cancel" pressed? => return with error
1150 0 : if (aRequest.isAbort())
1151 0 : return ::rtl::OUString();
1152 :
1153 : // "OK" pressed => verify the selected filter, get it's coressponding
1154 : // type and return it. (BTW: We must update the media descriptor here ...)
1155 : // The user selected explicitly a filter ... but normaly we are interested on
1156 : // a type here only. But we must be shure, that the selected filter is used
1157 : // too and no ambigous filter registration disturb us .-)
1158 :
1159 0 : ::rtl::OUString sFilter = aRequest.getFilter();
1160 0 : if (!impl_validateAndSetFilterOnDescriptor(rDescriptor, sFilter))
1161 0 : return ::rtl::OUString();
1162 :
1163 0 : ::rtl::OUString sType;
1164 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] >>= sType;
1165 0 : return sType;
1166 : }
1167 0 : catch(const css::uno::Exception&)
1168 : {}
1169 :
1170 0 : return ::rtl::OUString();
1171 : }
1172 :
1173 :
1174 :
1175 1352 : void TypeDetection::impl_openStream(::comphelper::MediaDescriptor& rDescriptor)
1176 : throw (css::uno::Exception)
1177 : {
1178 1352 : sal_Bool bSuccess = sal_False;
1179 1352 : ::rtl::OUString sURL = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString() );
1180 1352 : sal_Bool bRequestedReadOnly = rDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_READONLY(), sal_False );
1181 1352 : if ( !sURL.isEmpty() && ::utl::LocalFileHelper::IsLocalFile( INetURLObject( sURL ).GetMainURL( INetURLObject::NO_DECODE ) ) )
1182 : {
1183 : // OOo uses own file locking mechanics in case of local file
1184 1289 : bSuccess = rDescriptor.addInputStreamOwnLock();
1185 : }
1186 : else
1187 63 : bSuccess = rDescriptor.addInputStream();
1188 :
1189 1352 : if ( !bSuccess )
1190 0 : throw css::uno::Exception(_FILTER_CONFIG_FROM_ASCII_("Could not open stream."), static_cast< css::document::XTypeDetection* >(this));
1191 :
1192 1352 : if ( !bRequestedReadOnly )
1193 : {
1194 : // The MediaDescriptor implementation adds ReadOnly argument if the file can not be opened for writing
1195 : // this argument should be either removed or an additional argument should be added so that application
1196 : // can separate the case when the user explicitly requests readonly document.
1197 : // The current solution is to remove it here.
1198 1352 : rDescriptor.erase( ::comphelper::MediaDescriptor::PROP_READONLY() );
1199 1352 : }
1200 1352 : }
1201 :
1202 :
1203 :
1204 6 : void TypeDetection::impl_removeTypeFilterFromDescriptor(::comphelper::MediaDescriptor& rDescriptor)
1205 : {
1206 6 : ::comphelper::MediaDescriptor::iterator pItType = rDescriptor.find(::comphelper::MediaDescriptor::PROP_TYPENAME() );
1207 6 : ::comphelper::MediaDescriptor::iterator pItFilter = rDescriptor.find(::comphelper::MediaDescriptor::PROP_FILTERNAME());
1208 6 : if (pItType != rDescriptor.end())
1209 0 : rDescriptor.erase(pItType);
1210 6 : if (pItFilter != rDescriptor.end())
1211 0 : rDescriptor.erase(pItFilter);
1212 6 : }
1213 :
1214 :
1215 :
1216 662 : sal_Bool TypeDetection::impl_validateAndSetTypeOnDescriptor( ::comphelper::MediaDescriptor& rDescriptor,
1217 : const ::rtl::OUString& sType )
1218 : {
1219 : // SAFE ->
1220 662 : ::osl::ResettableMutexGuard aLock(m_aLock);
1221 662 : if (m_rCache->hasItem(FilterCache::E_TYPE, sType))
1222 : {
1223 656 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sType;
1224 656 : return sal_True;
1225 : }
1226 6 : aLock.clear();
1227 : // <- SAFE
1228 :
1229 : // remove all related informations from the descriptor
1230 6 : impl_removeTypeFilterFromDescriptor(rDescriptor);
1231 6 : return sal_False;
1232 : }
1233 :
1234 :
1235 :
1236 0 : sal_Bool TypeDetection::impl_validateAndSetFilterOnDescriptor( ::comphelper::MediaDescriptor& rDescriptor,
1237 : const ::rtl::OUString& sFilter )
1238 : {
1239 : try
1240 : {
1241 : // SAFE ->
1242 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
1243 :
1244 0 : CacheItem aFilter = m_rCache->getItem(FilterCache::E_FILTER, sFilter);
1245 0 : ::rtl::OUString sType;
1246 0 : aFilter[PROPNAME_TYPE] >>= sType;
1247 0 : CacheItem aType = m_rCache->getItem(FilterCache::E_TYPE, sType);
1248 :
1249 0 : aLock.clear();
1250 : // <- SAFE
1251 :
1252 : // found valid type and filter => set it on the given descriptor
1253 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= sType ;
1254 0 : rDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
1255 0 : return sal_True;
1256 : }
1257 0 : catch(const css::container::NoSuchElementException&){}
1258 :
1259 : // remove all related informations from the descriptor
1260 0 : impl_removeTypeFilterFromDescriptor(rDescriptor);
1261 0 : return sal_False;
1262 : }
1263 :
1264 :
1265 :
1266 5614 : ::rtl::OUString TypeDetection::impl_getImplementationName()
1267 : {
1268 5614 : return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.filter.config.TypeDetection" ));
1269 : }
1270 :
1271 :
1272 :
1273 5559 : css::uno::Sequence< ::rtl::OUString > TypeDetection::impl_getSupportedServiceNames()
1274 : {
1275 5559 : css::uno::Sequence< ::rtl::OUString > lServiceNames(1);
1276 5559 : lServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.TypeDetection" ));
1277 5559 : return lServiceNames;
1278 : }
1279 :
1280 :
1281 :
1282 5546 : css::uno::Reference< css::uno::XInterface > SAL_CALL TypeDetection::impl_createInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
1283 : {
1284 5546 : TypeDetection* pNew = new TypeDetection(xSMGR);
1285 5546 : return css::uno::Reference< css::uno::XInterface >(static_cast< css::document::XTypeDetection* >(pNew), css::uno::UNO_QUERY);
1286 : }
1287 :
1288 : } // namespace config
1289 : } // namespace filter
1290 :
1291 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|