update credits
[LibreOffice.git] / comphelper / source / misc / mediadescriptor.cxx
blob586f6fcb1675d6e705b28c6c46fe2b4446944caa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/mediadescriptor.hxx>
21 #include <comphelper/namedvaluecollection.hxx>
22 #include <comphelper/stillreadwriteinteraction.hxx>
24 #include <com/sun/star/ucb/XContent.hpp>
25 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
26 #include <com/sun/star/task/XInteractionHandler.hpp>
27 #include <com/sun/star/io/XStream.hpp>
28 #include <com/sun/star/io/XActiveDataSink.hpp>
29 #include <com/sun/star/io/XSeekable.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include <com/sun/star/util/XURLTransformer.hpp>
33 #include <com/sun/star/ucb/InteractiveIOException.hpp>
34 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
35 #include <com/sun/star/ucb/CommandFailedException.hpp>
36 #include <com/sun/star/task/XInteractionAbort.hpp>
37 #include <com/sun/star/uri/UriReferenceFactory.hpp>
38 #include <com/sun/star/uri/XUriReference.hpp>
39 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <officecfg/Office/Common.hxx>
42 #include <ucbhelper/interceptedinteraction.hxx>
43 #include <ucbhelper/content.hxx>
44 #include <ucbhelper/commandenvironment.hxx>
45 #include <ucbhelper/activedatasink.hxx>
46 #include <comphelper/processfactory.hxx>
48 #include <rtl/ustrbuf.hxx>
51 namespace comphelper{
53 const OUString& MediaDescriptor::PROP_ABORTED()
55 static const OUString sProp("Aborted");
56 return sProp;
59 const OUString& MediaDescriptor::PROP_ASTEMPLATE()
61 static const OUString sProp("AsTemplate");
62 return sProp;
65 const OUString& MediaDescriptor::PROP_COMPONENTDATA()
67 static const OUString sProp("ComponentData");
68 return sProp;
71 const OUString& MediaDescriptor::PROP_DOCUMENTSERVICE()
73 static const OUString sProp("DocumentService");
74 return sProp;
77 const OUString& MediaDescriptor::PROP_ENCRYPTIONDATA()
79 static const OUString sProp("EncryptionData");
80 return sProp;
83 const OUString& MediaDescriptor::PROP_FILENAME()
85 static const OUString sProp("FileName");
86 return sProp;
89 const OUString& MediaDescriptor::PROP_FILTERNAME()
91 static const OUString sProp("FilterName");
92 return sProp;
95 const OUString& MediaDescriptor::PROP_FILTERPROVIDER()
97 static const OUString aProp("FilterProvider");
98 return aProp;
101 const OUString& MediaDescriptor::PROP_FILTEROPTIONS()
103 static const OUString sProp("FilterOptions");
104 return sProp;
107 const OUString& MediaDescriptor::PROP_FRAME()
109 static const OUString sProp("Frame");
110 return sProp;
113 const OUString& MediaDescriptor::PROP_FRAMENAME()
115 static const OUString sProp("FrameName");
116 return sProp;
119 const OUString& MediaDescriptor::PROP_HIDDEN()
121 static const OUString sProp("Hidden");
122 return sProp;
125 const OUString& MediaDescriptor::PROP_INPUTSTREAM()
127 static const OUString sProp("InputStream");
128 return sProp;
131 const OUString& MediaDescriptor::PROP_INTERACTIONHANDLER()
133 static const OUString sProp("InteractionHandler");
134 return sProp;
137 const OUString& MediaDescriptor::PROP_JUMPMARK()
139 static const OUString sProp("JumpMark");
140 return sProp;
143 const OUString& MediaDescriptor::PROP_MACROEXECUTIONMODE()
145 static const OUString sProp("MacroExecutionMode");
146 return sProp;
149 const OUString& MediaDescriptor::PROP_MEDIATYPE()
151 static const OUString sProp("MediaType");
152 return sProp;
155 const OUString& MediaDescriptor::PROP_MINIMIZED()
157 static const OUString sProp("Minimized");
158 return sProp;
161 const OUString& MediaDescriptor::PROP_NOAUTOSAVE()
163 static const OUString sProp("NoAutoSave");
164 return sProp;
167 const OUString& MediaDescriptor::PROP_OPENNEWVIEW()
169 static const OUString sProp("OpenNewView");
170 return sProp;
173 const OUString& MediaDescriptor::PROP_OUTPUTSTREAM()
175 static const OUString sProp("OutputStream");
176 return sProp;
179 const OUString& MediaDescriptor::PROP_POSTDATA()
181 static const OUString sProp("PostData");
182 return sProp;
185 const OUString& MediaDescriptor::PROP_PREVIEW()
187 static const OUString sProp("Preview");
188 return sProp;
191 const OUString& MediaDescriptor::PROP_READONLY()
193 static const OUString sProp("ReadOnly");
194 return sProp;
197 const OUString& MediaDescriptor::PROP_REFERRER()
199 static const OUString sProp("Referer");
200 return sProp;
203 const OUString& MediaDescriptor::PROP_STATUSINDICATOR()
205 static const OUString sProp("StatusIndicator");
206 return sProp;
209 const OUString& MediaDescriptor::PROP_STREAM()
211 static const OUString sProp("Stream");
212 return sProp;
215 const OUString& MediaDescriptor::PROP_STREAMFOROUTPUT()
217 static const OUString sProp("StreamForOutput");
218 return sProp;
221 const OUString& MediaDescriptor::PROP_TEMPLATENAME()
223 static const OUString sProp("TemplateName");
224 return sProp;
227 const OUString& MediaDescriptor::PROP_TYPENAME()
229 static const OUString sProp("TypeName");
230 return sProp;
233 const OUString& MediaDescriptor::PROP_UCBCONTENT()
235 static const OUString sProp("UCBContent");
236 return sProp;
239 const OUString& MediaDescriptor::PROP_UPDATEDOCMODE()
241 static const OUString sProp("UpdateDocMode");
242 return sProp;
245 const OUString& MediaDescriptor::PROP_URL()
247 static const OUString sProp("URL");
248 return sProp;
251 const OUString& MediaDescriptor::PROP_VERSION()
253 static const OUString sProp("Version");
254 return sProp;
257 const OUString& MediaDescriptor::PROP_DOCUMENTTITLE()
259 static const OUString sProp("DocumentTitle");
260 return sProp;
263 const OUString& MediaDescriptor::PROP_MODEL()
265 static const OUString sProp("Model");
266 return sProp;
269 const OUString& MediaDescriptor::PROP_PASSWORD()
271 static const OUString sProp("Password");
272 return sProp;
275 const OUString& MediaDescriptor::PROP_TITLE()
277 static const OUString sProp("Title");
278 return sProp;
281 const OUString& MediaDescriptor::PROP_SALVAGEDFILE()
283 static const OUString sProp("SalvagedFile");
284 return sProp;
287 const OUString& MediaDescriptor::PROP_VIEWONLY()
289 static const OUString sProp("ViewOnly");
290 return sProp;
293 const OUString& MediaDescriptor::PROP_DOCUMENTBASEURL()
295 static const OUString sProp("DocumentBaseURL");
296 return sProp;
299 const OUString& MediaDescriptor::PROP_DEEPDETECTION()
301 static const OUString aProp("DeepDetection");
302 return aProp;
305 MediaDescriptor::MediaDescriptor()
306 : SequenceAsHashMap()
310 MediaDescriptor::MediaDescriptor(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
311 : SequenceAsHashMap(lSource)
315 sal_Bool MediaDescriptor::isStreamReadOnly() const
317 static OUString CONTENTSCHEME_FILE( "file" );
318 static OUString CONTENTPROP_ISREADONLY( "IsReadOnly" );
319 static sal_Bool READONLY_FALLBACK = sal_False;
321 sal_Bool bReadOnly = READONLY_FALLBACK;
323 // check for explicit readonly state
324 const_iterator pIt = find(MediaDescriptor::PROP_READONLY());
325 if (pIt != end())
327 pIt->second >>= bReadOnly;
328 return bReadOnly;
331 // streams based on post data are readonly by definition
332 pIt = find(MediaDescriptor::PROP_POSTDATA());
333 if (pIt != end())
334 return sal_True;
336 // A XStream capsulate XInputStream and XOutputStream ...
337 // If it exists - the file must be open in read/write mode!
338 pIt = find(MediaDescriptor::PROP_STREAM());
339 if (pIt != end())
340 return sal_False;
342 // Only file system content provider is able to provide XStream
343 // so for this content impossibility to create XStream triggers
344 // switch to readonly mode.
347 css::uno::Reference< css::ucb::XContent > xContent = getUnpackedValueOrDefault(MediaDescriptor::PROP_UCBCONTENT(), css::uno::Reference< css::ucb::XContent >());
348 if (xContent.is())
350 css::uno::Reference< css::ucb::XContentIdentifier > xId(xContent->getIdentifier(), css::uno::UNO_QUERY);
351 OUString aScheme;
352 if (xId.is())
353 aScheme = xId->getContentProviderScheme();
355 if (aScheme.equalsIgnoreAsciiCase(CONTENTSCHEME_FILE))
356 bReadOnly = sal_True;
357 else
359 ::ucbhelper::Content aContent(xContent, css::uno::Reference< css::ucb::XCommandEnvironment >(), getProcessComponentContext());
360 aContent.getPropertyValue(CONTENTPROP_ISREADONLY) >>= bReadOnly;
364 catch(const css::uno::RuntimeException& )
365 { throw; }
366 catch(const css::uno::Exception&)
369 return bReadOnly;
372 // ----------------------------------------------------------------------------
374 css::uno::Any MediaDescriptor::getComponentDataEntry( const OUString& rName ) const
376 css::uno::Any aEntry;
377 SequenceAsHashMap::const_iterator aPropertyIter = find( PROP_COMPONENTDATA() );
378 if( aPropertyIter != end() )
379 return NamedValueCollection( aPropertyIter->second ).get( rName );
380 return css::uno::Any();
383 void MediaDescriptor::setComponentDataEntry( const OUString& rName, const css::uno::Any& rValue )
385 if( rValue.hasValue() )
387 // get or create the 'ComponentData' property entry
388 css::uno::Any& rCompDataAny = operator[]( PROP_COMPONENTDATA() );
389 // insert the value (retain sequence type, create NamedValue elements by default)
390 bool bHasNamedValues = !rCompDataAny.hasValue() || rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >();
391 bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >();
392 OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::setComponentDataEntry - incompatible 'ComponentData' property in media descriptor" );
393 if( bHasNamedValues || bHasPropValues )
395 // insert or overwrite the passed value
396 SequenceAsHashMap aCompDataMap( rCompDataAny );
397 aCompDataMap[ rName ] = rValue;
398 // write back the sequence (restore sequence with correct element type)
399 rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues );
402 else
404 // if an empty Any is passed, clear the entry
405 clearComponentDataEntry( rName );
409 void MediaDescriptor::clearComponentDataEntry( const OUString& rName )
411 SequenceAsHashMap::iterator aPropertyIter = find( PROP_COMPONENTDATA() );
412 if( aPropertyIter != end() )
414 css::uno::Any& rCompDataAny = aPropertyIter->second;
415 bool bHasNamedValues = rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >();
416 bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >();
417 OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::clearComponentDataEntry - incompatible 'ComponentData' property in media descriptor" );
418 if( bHasNamedValues || bHasPropValues )
420 // remove the value with the passed name
421 SequenceAsHashMap aCompDataMap( rCompDataAny );
422 aCompDataMap.erase( rName );
423 // write back the sequence, or remove it completely if it is empty
424 if( aCompDataMap.empty() )
425 erase( aPropertyIter );
426 else
427 rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues );
432 sal_Bool MediaDescriptor::addInputStream()
434 return impl_addInputStream( sal_True );
437 /*-----------------------------------------------*/
438 sal_Bool MediaDescriptor::addInputStreamOwnLock()
440 return impl_addInputStream(
441 officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get());
444 /*-----------------------------------------------*/
445 sal_Bool MediaDescriptor::impl_addInputStream( sal_Bool bLockFile )
447 // check for an already existing stream item first
448 const_iterator pIt = find(MediaDescriptor::PROP_INPUTSTREAM());
449 if (pIt != end())
450 return sal_True;
454 // No stream available - create a new one
455 // a) data comes as PostData ...
456 pIt = find(MediaDescriptor::PROP_POSTDATA());
457 if (pIt != end())
459 const css::uno::Any& rPostData = pIt->second;
460 css::uno::Reference< css::io::XInputStream > xPostData;
461 rPostData >>= xPostData;
463 return impl_openStreamWithPostData( xPostData );
466 // b) ... or we must get it from the given URL
467 OUString sURL = getUnpackedValueOrDefault(MediaDescriptor::PROP_URL(), OUString());
468 if (sURL.isEmpty())
469 throw css::uno::Exception( OUString( "Found no URL." ),
470 css::uno::Reference< css::uno::XInterface >());
472 // Parse URL! Only the main part has to be used further. E.g. a jumpmark can make trouble
473 OUString sNormalizedURL = impl_normalizeURL( sURL );
474 return impl_openStreamWithURL( sNormalizedURL, bLockFile );
476 #if OSL_DEBUG_LEVEL > 0
477 catch(const css::uno::Exception& ex)
479 OUStringBuffer sMsg(256);
480 sMsg.appendAscii("Invalid MediaDescriptor detected:\n");
481 sMsg.append (ex.Message );
482 OSL_FAIL(OUStringToOString(sMsg.makeStringAndClear(), RTL_TEXTENCODING_UTF8).getStr());
484 #else
485 catch(const css::uno::Exception&)
487 #endif
489 return sal_False;
492 sal_Bool MediaDescriptor::impl_openStreamWithPostData( const css::uno::Reference< css::io::XInputStream >& _rxPostData )
493 throw(::com::sun::star::uno::RuntimeException)
495 if ( !_rxPostData.is() )
496 throw css::lang::IllegalArgumentException( OUString( "Found invalid PostData." ),
497 css::uno::Reference< css::uno::XInterface >(), 1);
499 // PostData can't be used in read/write mode!
500 (*this)[MediaDescriptor::PROP_READONLY()] <<= sal_True;
502 // prepare the environment
503 css::uno::Reference< css::task::XInteractionHandler > xInteraction = getUnpackedValueOrDefault(
504 MediaDescriptor::PROP_INTERACTIONHANDLER(),
505 css::uno::Reference< css::task::XInteractionHandler >());
506 css::uno::Reference< css::ucb::XProgressHandler > xProgress;
507 ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
508 css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY);
510 // media type
511 OUString sMediaType = getUnpackedValueOrDefault(MediaDescriptor::PROP_MEDIATYPE(), OUString());
512 if (sMediaType.isEmpty())
514 sMediaType = "application/x-www-form-urlencoded";
515 (*this)[MediaDescriptor::PROP_MEDIATYPE()] <<= sMediaType;
518 // url
519 OUString sURL( getUnpackedValueOrDefault( PROP_URL(), OUString() ) );
521 css::uno::Reference< css::io::XInputStream > xResultStream;
524 // seek PostData stream to the beginning
525 css::uno::Reference< css::io::XSeekable > xSeek( _rxPostData, css::uno::UNO_QUERY );
526 if ( xSeek.is() )
527 xSeek->seek( 0 );
529 // a content for the URL
530 ::ucbhelper::Content aContent( sURL, xCommandEnv, getProcessComponentContext() );
532 // use post command
533 css::ucb::PostCommandArgument2 aPostArgument;
534 aPostArgument.Source = _rxPostData;
535 css::uno::Reference< css::io::XActiveDataSink > xSink( new ucbhelper::ActiveDataSink );
536 aPostArgument.Sink = xSink;
537 aPostArgument.MediaType = sMediaType;
538 aPostArgument.Referer = getUnpackedValueOrDefault( PROP_REFERRER(), OUString() );
540 OUString sCommandName( "post" );
541 aContent.executeCommand( sCommandName, css::uno::makeAny( aPostArgument ) );
543 // get result
544 xResultStream = xSink->getInputStream();
546 catch( const css::uno::Exception& )
550 // success?
551 if ( !xResultStream.is() )
553 OSL_FAIL( "no valid reply to the HTTP-Post" );
554 return sal_False;
557 (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xResultStream;
558 return sal_True;
561 /*-----------------------------------------------*/
562 sal_Bool MediaDescriptor::impl_openStreamWithURL( const OUString& sURL, sal_Bool bLockFile )
563 throw(::com::sun::star::uno::RuntimeException)
565 // prepare the environment
566 css::uno::Reference< css::task::XInteractionHandler > xOrgInteraction = getUnpackedValueOrDefault(
567 MediaDescriptor::PROP_INTERACTIONHANDLER(),
568 css::uno::Reference< css::task::XInteractionHandler >());
570 StillReadWriteInteraction* pInteraction = new StillReadWriteInteraction(xOrgInteraction);
571 css::uno::Reference< css::task::XInteractionHandler > xInteraction(static_cast< css::task::XInteractionHandler* >(pInteraction), css::uno::UNO_QUERY);
573 css::uno::Reference< css::ucb::XProgressHandler > xProgress;
574 ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
575 css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY);
577 // try to create the content
578 // no content -> no stream => return immediately with FALSE
579 ::ucbhelper::Content aContent;
580 css::uno::Reference< css::ucb::XContent > xContent;
583 aContent = ::ucbhelper::Content(sURL, xCommandEnv, getProcessComponentContext());
584 xContent = aContent.get();
586 catch(const css::uno::RuntimeException&)
587 { throw; }
588 catch(const css::ucb::ContentCreationException&)
589 { return sal_False; } // TODO error handling
590 catch(const css::uno::Exception&)
591 { return sal_False; } // TODO error handling
593 // try to open the file in read/write mode
594 // (if its allowed to do so).
595 // But handle errors in a "hidden mode". Because
596 // we try it readonly later - if read/write isnt an option.
597 css::uno::Reference< css::io::XStream > xStream ;
598 css::uno::Reference< css::io::XInputStream > xInputStream;
600 sal_Bool bReadOnly = sal_False;
601 sal_Bool bModeRequestedExplicitly = sal_False;
602 const_iterator pIt = find(MediaDescriptor::PROP_READONLY());
603 if (pIt != end())
605 pIt->second >>= bReadOnly;
606 bModeRequestedExplicitly = sal_True;
609 if ( !bReadOnly && bLockFile )
613 // TODO: use "special" still interaction to supress error messages
614 xStream = aContent.openWriteableStream();
615 if (xStream.is())
616 xInputStream = xStream->getInputStream();
618 catch(const css::uno::RuntimeException&)
619 { throw; }
620 catch(const css::uno::Exception&)
622 // ignore exception, if reason was problem reasoned on
623 // open it in WRITEABLE mode! Then we try it READONLY
624 // later a second time.
625 // All other errors must be handled as real error an
626 // break this method.
627 if (!pInteraction->wasWriteError() || bModeRequestedExplicitly)
628 return sal_False;
629 xStream.clear();
630 xInputStream.clear();
634 // If opening of the stream in read/write mode wasnt allowed
635 // or failed by an error - we must try it in readonly mode.
636 if (!xInputStream.is())
638 OUString aScheme;
642 css::uno::Reference< css::ucb::XContentIdentifier > xContId(
643 aContent.get().is() ? aContent.get()->getIdentifier() : 0 );
645 if ( xContId.is() )
646 aScheme = xContId->getContentProviderScheme();
648 // Only file system content provider is able to provide XStream
649 // so for this content impossibility to create XStream triggers
650 // switch to readonly mode in case of opening with locking on
651 if( bLockFile && aScheme.equalsIgnoreAsciiCase("file") )
652 bReadOnly = sal_True;
653 else
655 sal_Bool bRequestReadOnly = bReadOnly;
656 aContent.getPropertyValue( OUString( "IsReadOnly" ) ) >>= bReadOnly;
657 if ( bReadOnly && !bRequestReadOnly && bModeRequestedExplicitly )
658 return sal_False; // the document is explicitly requested with WRITEABLE mode
661 catch(const css::uno::RuntimeException&)
662 { throw; }
663 catch(const css::uno::Exception&)
664 { /* no error handling if IsReadOnly property does not exist for UCP */ }
666 if ( bReadOnly )
667 (*this)[MediaDescriptor::PROP_READONLY()] <<= bReadOnly;
669 pInteraction->resetInterceptions();
670 pInteraction->resetErrorStates();
673 // all the contents except file-URLs should be opened as usual
674 if ( bLockFile || !aScheme.equalsIgnoreAsciiCase("file") )
675 xInputStream = aContent.openStream();
676 else
677 xInputStream = aContent.openStreamNoLock();
679 catch(const css::uno::RuntimeException&)
680 { throw; }
681 catch(const css::uno::Exception&)
682 { return sal_False; }
685 // add streams to the descriptor
686 if (xContent.is())
687 (*this)[MediaDescriptor::PROP_UCBCONTENT()] <<= xContent;
688 if (xStream.is())
689 (*this)[MediaDescriptor::PROP_STREAM()] <<= xStream;
690 if (xInputStream.is())
691 (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xInputStream;
693 // At least we need an input stream. The r/w stream is optional ...
694 return xInputStream.is();
697 OUString MediaDescriptor::impl_normalizeURL(const OUString& sURL)
699 /* Remove Jumpmarks (fragments) of an URL only here.
700 They are not part of any URL and as a result may be
701 no ucb content can be created then.
702 On the other side arguments must exists ... because
703 they are part of an URL.
705 Do not use the URLTransformer service here. Because
706 it parses the URL in another way. It's main part isnt enough
707 and it's complete part contains the jumpmark (fragment) parameter ...
712 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
713 css::uno::Reference< css::uri::XUriReferenceFactory > xUriFactory = css::uri::UriReferenceFactory::create(xContext);;
714 css::uno::Reference< css::uri::XUriReference > xUriRef = xUriFactory->parse(sURL);
715 if (xUriRef.is())
717 xUriRef->clearFragment();
718 return xUriRef->getUriReference();
721 catch(const css::uno::RuntimeException&)
722 { throw; }
723 catch(const css::uno::Exception&)
726 // If an error ocurred ... return the original URL.
727 // It's a try .-)
728 return sURL;
731 } // namespace comphelper
733 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */