1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/embed/ElementModes.hpp>
21 #include <com/sun/star/embed/XEncryptionProtectedSource2.hpp>
22 #include <com/sun/star/embed/XStorage.hpp>
23 #include <com/sun/star/embed/XTransactedObject.hpp>
24 #include <com/sun/star/embed/StorageFactory.hpp>
25 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
26 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
27 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/NamedValue.hpp>
31 #include <com/sun/star/beans/IllegalTypeException.hpp>
32 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
33 #include <com/sun/star/xml/crypto/XDigestContext.hpp>
34 #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp>
35 #include <com/sun/star/xml/crypto/DigestID.hpp>
39 #include <rtl/digest.h>
40 #include <osl/diagnose.h>
42 #include <ucbhelper/content.hxx>
44 #include <comphelper/fileformat.h>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/documentconstants.hxx>
48 #include <comphelper/storagehelper.hxx>
50 #include <boost/current_function.hpp>
52 using namespace ::com::sun::star
;
54 namespace comphelper
{
57 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetStorageFactory(
58 const uno::Reference
< uno::XComponentContext
>& rxContext
)
59 throw ( uno::Exception
)
61 uno::Reference
< uno::XComponentContext
> xContext
= rxContext
.is() ? rxContext
: ::comphelper::getProcessComponentContext();
63 return embed::StorageFactory::create( xContext
);
67 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetFileSystemStorageFactory(
68 const uno::Reference
< uno::XComponentContext
>& rxContext
)
69 throw ( uno::Exception
)
71 uno::Reference
< uno::XComponentContext
> xContext
= rxContext
.is() ? rxContext
: ::comphelper::getProcessComponentContext();
73 return embed::FileSystemStorageFactory::create(rxContext
);
77 uno::Reference
< embed::XStorage
> OStorageHelper::GetTemporaryStorage(
78 const uno::Reference
< uno::XComponentContext
>& rxContext
)
79 throw ( uno::Exception
)
81 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstance(),
83 if ( !xTempStorage
.is() )
84 throw uno::RuntimeException();
90 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL(
92 sal_Int32 nStorageMode
,
93 const uno::Reference
< uno::XComponentContext
>& rxContext
)
94 throw ( uno::Exception
)
96 uno::Sequence
< uno::Any
> aArgs( 2 );
98 aArgs
[1] <<= nStorageMode
;
100 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
102 if ( !xTempStorage
.is() )
103 throw uno::RuntimeException();
109 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL2(
110 const OUString
& aURL
,
111 sal_Int32 nStorageMode
,
112 const uno::Reference
< uno::XComponentContext
>& rxContext
)
113 throw ( uno::Exception
)
115 uno::Sequence
< uno::Any
> aArgs( 2 );
117 aArgs
[1] <<= nStorageMode
;
119 uno::Reference
< lang::XSingleServiceFactory
> xFact
;
121 ::ucbhelper::Content
aCntnt( aURL
,
122 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> (),
123 getProcessComponentContext() );
124 if (aCntnt
.isDocument()) {
125 xFact
= GetStorageFactory( rxContext
);
127 xFact
= GetFileSystemStorageFactory( rxContext
);
129 } catch (uno::Exception
&) { }
131 if (!xFact
.is()) throw uno::RuntimeException();
133 uno::Reference
< embed::XStorage
> xTempStorage(
134 xFact
->createInstanceWithArguments( aArgs
), uno::UNO_QUERY
);
135 if ( !xTempStorage
.is() )
136 throw uno::RuntimeException();
142 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromInputStream(
143 const uno::Reference
< io::XInputStream
>& xStream
,
144 const uno::Reference
< uno::XComponentContext
>& rxContext
)
145 throw ( uno::Exception
)
147 uno::Sequence
< uno::Any
> aArgs( 2 );
148 aArgs
[0] <<= xStream
;
149 aArgs
[1] <<= embed::ElementModes::READ
;
151 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
153 if ( !xTempStorage
.is() )
154 throw uno::RuntimeException();
160 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromStream(
161 const uno::Reference
< io::XStream
>& xStream
,
162 sal_Int32 nStorageMode
,
163 const uno::Reference
< uno::XComponentContext
>& rxContext
)
164 throw ( uno::Exception
)
166 uno::Sequence
< uno::Any
> aArgs( 2 );
167 aArgs
[0] <<= xStream
;
168 aArgs
[1] <<= nStorageMode
;
170 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
172 if ( !xTempStorage
.is() )
173 throw uno::RuntimeException();
179 void OStorageHelper::CopyInputToOutput(
180 const uno::Reference
< io::XInputStream
>& xInput
,
181 const uno::Reference
< io::XOutputStream
>& xOutput
)
182 throw ( uno::Exception
)
184 static const sal_Int32 nConstBufferSize
= 32000;
187 uno::Sequence
< sal_Int8
> aSequence ( nConstBufferSize
);
191 nRead
= xInput
->readBytes ( aSequence
, nConstBufferSize
);
192 if ( nRead
< nConstBufferSize
)
194 uno::Sequence
< sal_Int8
> aTempBuf ( aSequence
.getConstArray(), nRead
);
195 xOutput
->writeBytes ( aTempBuf
);
198 xOutput
->writeBytes ( aSequence
);
200 while ( nRead
== nConstBufferSize
);
204 uno::Reference
< io::XInputStream
> OStorageHelper::GetInputStreamFromURL(
205 const OUString
& aURL
,
206 const uno::Reference
< uno::XComponentContext
>& context
)
207 throw ( uno::Exception
)
209 uno::Reference
< io::XInputStream
> xInputStream
= ucb::SimpleFileAccess::create(context
)->openFileRead( aURL
);
210 if ( !xInputStream
.is() )
211 throw uno::RuntimeException();
217 void OStorageHelper::SetCommonStorageEncryptionData(
218 const uno::Reference
< embed::XStorage
>& xStorage
,
219 const uno::Sequence
< beans::NamedValue
>& aEncryptionData
)
220 throw ( uno::Exception
)
222 uno::Reference
< embed::XEncryptionProtectedSource2
> xEncrSet( xStorage
, uno::UNO_QUERY
);
223 if ( !xEncrSet
.is() )
224 throw io::IOException(); // TODO
226 xEncrSet
->setEncryptionData( aEncryptionData
);
230 sal_Int32
OStorageHelper::GetXStorageFormat(
231 const uno::Reference
< embed::XStorage
>& xStorage
)
232 throw ( uno::Exception
)
234 uno::Reference
< beans::XPropertySet
> xStorProps( xStorage
, uno::UNO_QUERY_THROW
);
237 xStorProps
->getPropertyValue("MediaType") >>= aMediaType
;
239 sal_Int32 nResult
= 0;
241 // TODO/LATER: the filter configuration could be used to detect it later, or batter a special service
243 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_ASCII
) ||
244 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII
) ||
245 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII
) ||
246 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_DRAW_ASCII
) ||
247 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII
) ||
248 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CALC_ASCII
) ||
249 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CHART_ASCII
) ||
250 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_MATH_ASCII
)
253 nResult
= SOFFICE_FILEFORMAT_60
;
256 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
) ||
257 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
) ||
258 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
) ||
259 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
) ||
260 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
) ||
261 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
) ||
262 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
) ||
263 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
) ||
264 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
) ||
265 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII
) ||
266 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII
) ||
267 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
) ||
268 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
) ||
269 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
) ||
270 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
) ||
271 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
) ||
272 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
) ||
273 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
276 nResult
= SOFFICE_FILEFORMAT_8
;
280 // the mediatype is not known
281 OUString
aMsg(BOOST_CURRENT_FUNCTION
);
283 aMsg
+= OUString::number(__LINE__
);
284 aMsg
+= ": unknown media type '";
287 throw beans::IllegalTypeException(aMsg
);
294 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromURL(
295 const OUString
& aFormat
,
296 const OUString
& aURL
,
297 sal_Int32 nStorageMode
,
298 const uno::Reference
< uno::XComponentContext
>& rxContext
,
299 bool bRepairStorage
)
300 throw ( uno::Exception
)
302 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
303 aProps
[0].Name
= "StorageFormat";
304 aProps
[0].Value
<<= aFormat
;
305 if ( bRepairStorage
)
308 aProps
[1].Name
= "RepairPackage";
309 aProps
[1].Value
<<= bRepairStorage
;
312 uno::Sequence
< uno::Any
> aArgs( 3 );
314 aArgs
[1] <<= nStorageMode
;
317 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
319 if ( !xTempStorage
.is() )
320 throw uno::RuntimeException();
326 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromInputStream(
327 const OUString
& aFormat
,
328 const uno::Reference
< io::XInputStream
>& xStream
,
329 const uno::Reference
< uno::XComponentContext
>& rxContext
,
330 bool bRepairStorage
)
331 throw ( uno::Exception
)
333 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
334 aProps
[0].Name
= "StorageFormat";
335 aProps
[0].Value
<<= aFormat
;
336 if ( bRepairStorage
)
339 aProps
[1].Name
= "RepairPackage";
340 aProps
[1].Value
<<= bRepairStorage
;
343 uno::Sequence
< uno::Any
> aArgs( 3 );
344 aArgs
[0] <<= xStream
;
345 aArgs
[1] <<= embed::ElementModes::READ
;
348 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
350 if ( !xTempStorage
.is() )
351 throw uno::RuntimeException();
357 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromStream(
358 const OUString
& aFormat
,
359 const uno::Reference
< io::XStream
>& xStream
,
360 sal_Int32 nStorageMode
,
361 const uno::Reference
< uno::XComponentContext
>& rxContext
,
362 bool bRepairStorage
)
363 throw ( uno::Exception
)
365 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
366 aProps
[0].Name
= "StorageFormat";
367 aProps
[0].Value
<<= aFormat
;
368 if ( bRepairStorage
)
371 aProps
[1].Name
= "RepairPackage";
372 aProps
[1].Value
<<= bRepairStorage
;
375 uno::Sequence
< uno::Any
> aArgs( 3 );
376 aArgs
[0] <<= xStream
;
377 aArgs
[1] <<= nStorageMode
;
380 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
382 if ( !xTempStorage
.is() )
383 throw uno::RuntimeException();
389 uno::Sequence
< beans::NamedValue
> OStorageHelper::CreatePackageEncryptionData( const OUString
& aPassword
)
391 // TODO/LATER: Should not the method be part of DocPasswordHelper?
392 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
393 if ( !aPassword
.isEmpty() )
395 sal_Int32 nSha1Ind
= 0;
396 // generate SHA256 start key
399 uno::Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
401 uno::Reference
< xml::crypto::XNSSInitializer
> xDigestContextSupplier
= xml::crypto::NSSInitializer::create(xContext
);
402 uno::Reference
< xml::crypto::XDigestContext
> xDigestContext( xDigestContextSupplier
->getDigestContext( xml::crypto::DigestID::SHA256
, uno::Sequence
< beans::NamedValue
>() ), uno::UNO_SET_THROW
);
404 OString
aUTF8Password( OUStringToOString( aPassword
, RTL_TEXTENCODING_UTF8
) );
405 xDigestContext
->updateDigest( uno::Sequence
< sal_Int8
>( reinterpret_cast< const sal_Int8
* >( aUTF8Password
.getStr() ), aUTF8Password
.getLength() ) );
406 uno::Sequence
< sal_Int8
> aDigest
= xDigestContext
->finalizeDigestAndDispose();
408 aEncryptionData
.realloc( ++nSha1Ind
);
409 aEncryptionData
[0].Name
= PACKAGE_ENCRYPTIONDATA_SHA256UTF8
;
410 aEncryptionData
[0].Value
<<= aDigest
;
412 catch ( uno::Exception
& )
414 OSL_ENSURE( false, "Can not create SHA256 digest!" );
417 // MS_1252 encoding was used for SO60 document format password encoding,
418 // this encoding supports only a minor subset of nonascii characters,
419 // but for compatibility reasons it has to be used for old document formats
420 aEncryptionData
.realloc( nSha1Ind
+ 2 );
421 aEncryptionData
[nSha1Ind
].Name
= PACKAGE_ENCRYPTIONDATA_SHA1UTF8
;
422 aEncryptionData
[nSha1Ind
+ 1].Name
= PACKAGE_ENCRYPTIONDATA_SHA1MS1252
;
424 rtl_TextEncoding pEncoding
[2] = { RTL_TEXTENCODING_UTF8
, RTL_TEXTENCODING_MS_1252
};
426 for ( sal_Int32 nInd
= 0; nInd
< 2; nInd
++ )
428 OString aByteStrPass
= OUStringToOString( aPassword
, pEncoding
[nInd
] );
430 sal_uInt8 pBuffer
[RTL_DIGEST_LENGTH_SHA1
];
431 rtlDigestError nError
= rtl_digest_SHA1( aByteStrPass
.getStr(),
432 aByteStrPass
.getLength(),
434 RTL_DIGEST_LENGTH_SHA1
);
436 if ( nError
!= rtl_Digest_E_None
)
438 aEncryptionData
.realloc( nSha1Ind
);
442 aEncryptionData
[nSha1Ind
+nInd
].Value
<<= uno::Sequence
< sal_Int8
>( reinterpret_cast<sal_Int8
*>(pBuffer
), RTL_DIGEST_LENGTH_SHA1
);
446 return aEncryptionData
;
450 bool OStorageHelper::IsValidZipEntryFileName( const OUString
& aName
, bool bSlashAllowed
)
452 return IsValidZipEntryFileName( aName
.getStr(), aName
.getLength(), bSlashAllowed
);
456 bool OStorageHelper::IsValidZipEntryFileName(
457 const sal_Unicode
*pChar
, sal_Int32 nLength
, bool bSlashAllowed
)
459 for ( sal_Int32 i
= 0; i
< nLength
; i
++ )
472 if ( !bSlashAllowed
)
476 if ( pChar
[i
] < 32 || (pChar
[i
] >= 0xD800 && pChar
[i
] <= 0xDFFF) )
484 bool OStorageHelper::PathHasSegment( const OUString
& aPath
, const OUString
& aSegment
)
486 bool bResult
= false;
487 const sal_Int32 nPathLen
= aPath
.getLength();
488 const sal_Int32 nSegLen
= aSegment
.getLength();
490 if ( !aSegment
.isEmpty() && nPathLen
>= nSegLen
)
492 OUString
aEndSegment( "/" );
493 aEndSegment
+= aSegment
;
495 OUString
aInternalSegment( aEndSegment
);
496 aInternalSegment
+= "/";
498 if ( aPath
.indexOf( aInternalSegment
) >= 0 )
501 if ( !bResult
&& !aPath
.compareTo( aSegment
, nSegLen
) )
503 if ( nPathLen
== nSegLen
|| aPath
[nSegLen
] == '/' )
507 if ( !bResult
&& nPathLen
> nSegLen
&& aPath
.copy( nPathLen
- nSegLen
- 1, nSegLen
+ 1 ) == aEndSegment
)
514 class LifecycleProxy::Impl
515 : public std::vector
< uno::Reference
< embed::XStorage
> > {};
516 LifecycleProxy::LifecycleProxy()
517 : m_xBadness( new Impl() ) { }
518 LifecycleProxy::~LifecycleProxy() { }
520 void LifecycleProxy::commitStorages()
522 for (Impl::reverse_iterator iter
= m_xBadness
->rbegin();
523 iter
!= m_xBadness
->rend(); ++iter
) // reverse order (outwards)
525 uno::Reference
<embed::XTransactedObject
> const xTransaction(*iter
,
527 if (xTransaction
.is())
529 xTransaction
->commit();
534 static void splitPath( std::vector
<OUString
> &rElems
,
535 const OUString
& rPath
)
537 for (sal_Int32 i
= 0; i
>= 0;)
538 rElems
.push_back( rPath
.getToken( 0, '/', i
) );
541 static uno::Reference
< embed::XStorage
> LookupStorageAtPath(
542 const uno::Reference
< embed::XStorage
> &xParentStorage
,
543 std::vector
<OUString
> &rElems
, sal_uInt32 nOpenMode
,
544 LifecycleProxy
&rNastiness
)
546 uno::Reference
< embed::XStorage
> xStorage( xParentStorage
);
547 rNastiness
.m_xBadness
->push_back( xStorage
);
548 for( size_t i
= 0; i
< rElems
.size() && xStorage
.is(); i
++ )
550 xStorage
= xStorage
->openStorageElement( rElems
[i
], nOpenMode
);
551 rNastiness
.m_xBadness
->push_back( xStorage
);
556 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageAtPath(
557 const uno::Reference
< embed::XStorage
> &xStorage
,
558 const OUString
& rPath
, sal_uInt32 nOpenMode
,
559 LifecycleProxy
&rNastiness
)
561 std::vector
<OUString
> aElems
;
562 splitPath( aElems
, rPath
);
563 return LookupStorageAtPath( xStorage
, aElems
, nOpenMode
, rNastiness
);
566 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPath(
567 const uno::Reference
< embed::XStorage
> &xParentStorage
,
568 const OUString
& rPath
, sal_uInt32 nOpenMode
,
569 LifecycleProxy
&rNastiness
)
571 std::vector
<OUString
> aElems
;
572 splitPath( aElems
, rPath
);
573 OUString
aName( aElems
.back() );
575 sal_uInt32 nStorageMode
= nOpenMode
& ~embed::ElementModes::TRUNCATE
;
576 uno::Reference
< embed::XStorage
> xStorage(
577 LookupStorageAtPath( xParentStorage
, aElems
, nStorageMode
, rNastiness
),
578 uno::UNO_QUERY_THROW
);
579 return xStorage
->openStreamElement( aName
, nOpenMode
);
582 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPackageURL(
583 uno::Reference
< embed::XStorage
> const& xParentStorage
,
584 const OUString
& rURL
, sal_uInt32
const nOpenMode
,
585 LifecycleProxy
& rNastiness
)
588 if (rURL
.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &path
))
590 return GetStreamAtPath(xParentStorage
, path
, nOpenMode
, rNastiness
);
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */