bump product version to 5.0.4.1
[LibreOffice.git] / comphelper / source / misc / storagehelper.cxx
blob91e3687a7ff891149caf111b2930470960b28829
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 <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>
37 #include <vector>
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(),
82 uno::UNO_QUERY );
83 if ( !xTempStorage.is() )
84 throw uno::RuntimeException();
86 return xTempStorage;
90 uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL(
91 const OUString& aURL,
92 sal_Int32 nStorageMode,
93 const uno::Reference< uno::XComponentContext >& rxContext )
94 throw ( uno::Exception )
96 uno::Sequence< uno::Any > aArgs( 2 );
97 aArgs[0] <<= aURL;
98 aArgs[1] <<= nStorageMode;
100 uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ),
101 uno::UNO_QUERY );
102 if ( !xTempStorage.is() )
103 throw uno::RuntimeException();
105 return xTempStorage;
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 );
116 aArgs[0] <<= aURL;
117 aArgs[1] <<= nStorageMode;
119 uno::Reference< lang::XSingleServiceFactory > xFact;
120 try {
121 ::ucbhelper::Content aCntnt( aURL,
122 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > (),
123 getProcessComponentContext() );
124 if (aCntnt.isDocument()) {
125 xFact = GetStorageFactory( rxContext );
126 } else {
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();
138 return xTempStorage;
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 ),
152 uno::UNO_QUERY );
153 if ( !xTempStorage.is() )
154 throw uno::RuntimeException();
156 return xTempStorage;
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 ),
171 uno::UNO_QUERY );
172 if ( !xTempStorage.is() )
173 throw uno::RuntimeException();
175 return xTempStorage;
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;
186 sal_Int32 nRead;
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 );
197 else
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();
213 return xInputStream;
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 );
236 OUString aMediaType;
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
242 if (
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;
255 else if (
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;
278 else
280 // the mediatype is not known
281 OUString aMsg(BOOST_CURRENT_FUNCTION);
282 aMsg += ":";
283 aMsg += OUString::number(__LINE__);
284 aMsg += ": unknown media type '";
285 aMsg += aMediaType;
286 aMsg += "'";
287 throw beans::IllegalTypeException(aMsg);
290 return nResult;
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 )
307 aProps.realloc( 2 );
308 aProps[1].Name = "RepairPackage";
309 aProps[1].Value <<= bRepairStorage;
312 uno::Sequence< uno::Any > aArgs( 3 );
313 aArgs[0] <<= aURL;
314 aArgs[1] <<= nStorageMode;
315 aArgs[2] <<= aProps;
317 uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ),
318 uno::UNO_QUERY );
319 if ( !xTempStorage.is() )
320 throw uno::RuntimeException();
322 return xTempStorage;
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 )
338 aProps.realloc( 2 );
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;
346 aArgs[2] <<= aProps;
348 uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ),
349 uno::UNO_QUERY );
350 if ( !xTempStorage.is() )
351 throw uno::RuntimeException();
353 return xTempStorage;
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 )
370 aProps.realloc( 2 );
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;
378 aArgs[2] <<= aProps;
380 uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ),
381 uno::UNO_QUERY );
382 if ( !xTempStorage.is() )
383 throw uno::RuntimeException();
385 return xTempStorage;
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(),
433 pBuffer,
434 RTL_DIGEST_LENGTH_SHA1 );
436 if ( nError != rtl_Digest_E_None )
438 aEncryptionData.realloc( nSha1Ind );
439 break;
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++ )
461 switch ( pChar[i] )
463 case '\\':
464 case '?':
465 case '<':
466 case '>':
467 case '\"':
468 case '|':
469 case ':':
470 return false;
471 case '/':
472 if ( !bSlashAllowed )
473 return false;
474 break;
475 default:
476 if ( pChar[i] < 32 || (pChar[i] >= 0xD800 && pChar[i] <= 0xDFFF) )
477 return false;
480 return true;
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 )
499 bResult = true;
501 if ( !bResult && !aPath.compareTo( aSegment, nSegLen ) )
503 if ( nPathLen == nSegLen || aPath[nSegLen] == '/' )
504 bResult = true;
507 if ( !bResult && nPathLen > nSegLen && aPath.copy( nPathLen - nSegLen - 1, nSegLen + 1 ) == aEndSegment )
508 bResult = true;
511 return bResult;
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,
526 uno::UNO_QUERY);
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 );
553 return 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() );
574 aElems.pop_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)
587 OUString path;
588 if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &path))
590 return GetStreamAtPath(xParentStorage, path, nOpenMode, rNastiness);
592 return 0;
597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */