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>
38 #include <rtl/digest.h>
40 #include <ucbhelper/content.hxx>
42 #include <comphelper/fileformat.h>
43 #include <comphelper/processfactory.hxx>
44 #include <comphelper/documentconstants.hxx>
46 #include <comphelper/storagehelper.hxx>
49 using namespace ::com::sun::star
;
51 namespace comphelper
{
53 // ----------------------------------------------------------------------
54 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetStorageFactory(
55 const uno::Reference
< uno::XComponentContext
>& rxContext
)
56 throw ( uno::Exception
)
58 uno::Reference
< uno::XComponentContext
> xContext
= rxContext
.is() ? rxContext
: ::comphelper::getProcessComponentContext();
60 return embed::StorageFactory::create( xContext
);
63 // ----------------------------------------------------------------------
64 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetFileSystemStorageFactory(
65 const uno::Reference
< uno::XComponentContext
>& rxContext
)
66 throw ( uno::Exception
)
68 uno::Reference
< uno::XComponentContext
> xContext
= rxContext
.is() ? rxContext
: ::comphelper::getProcessComponentContext();
70 return embed::FileSystemStorageFactory::create(rxContext
);
73 // ----------------------------------------------------------------------
74 uno::Reference
< embed::XStorage
> OStorageHelper::GetTemporaryStorage(
75 const uno::Reference
< uno::XComponentContext
>& rxContext
)
76 throw ( uno::Exception
)
78 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstance(),
80 if ( !xTempStorage
.is() )
81 throw uno::RuntimeException();
86 // ----------------------------------------------------------------------
87 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL(
89 sal_Int32 nStorageMode
,
90 const uno::Reference
< uno::XComponentContext
>& rxContext
)
91 throw ( uno::Exception
)
93 uno::Sequence
< uno::Any
> aArgs( 2 );
95 aArgs
[1] <<= nStorageMode
;
97 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
99 if ( !xTempStorage
.is() )
100 throw uno::RuntimeException();
105 // ----------------------------------------------------------------------
106 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL2(
107 const OUString
& aURL
,
108 sal_Int32 nStorageMode
,
109 const uno::Reference
< uno::XComponentContext
>& rxContext
)
110 throw ( uno::Exception
)
112 uno::Sequence
< uno::Any
> aArgs( 2 );
114 aArgs
[1] <<= nStorageMode
;
116 uno::Reference
< lang::XSingleServiceFactory
> xFact
;
118 ::ucbhelper::Content
aCntnt( aURL
,
119 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> (),
120 getProcessComponentContext() );
121 if (aCntnt
.isDocument()) {
122 xFact
= GetStorageFactory( rxContext
);
124 xFact
= GetFileSystemStorageFactory( rxContext
);
126 } catch (uno::Exception
&) { }
128 if (!xFact
.is()) throw uno::RuntimeException();
130 uno::Reference
< embed::XStorage
> xTempStorage(
131 xFact
->createInstanceWithArguments( aArgs
), uno::UNO_QUERY
);
132 if ( !xTempStorage
.is() )
133 throw uno::RuntimeException();
138 // ----------------------------------------------------------------------
139 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromInputStream(
140 const uno::Reference
< io::XInputStream
>& xStream
,
141 const uno::Reference
< uno::XComponentContext
>& rxContext
)
142 throw ( uno::Exception
)
144 uno::Sequence
< uno::Any
> aArgs( 2 );
145 aArgs
[0] <<= xStream
;
146 aArgs
[1] <<= embed::ElementModes::READ
;
148 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
150 if ( !xTempStorage
.is() )
151 throw uno::RuntimeException();
156 // ----------------------------------------------------------------------
157 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromStream(
158 const uno::Reference
< io::XStream
>& xStream
,
159 sal_Int32 nStorageMode
,
160 const uno::Reference
< uno::XComponentContext
>& rxContext
)
161 throw ( uno::Exception
)
163 uno::Sequence
< uno::Any
> aArgs( 2 );
164 aArgs
[0] <<= xStream
;
165 aArgs
[1] <<= nStorageMode
;
167 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
169 if ( !xTempStorage
.is() )
170 throw uno::RuntimeException();
175 // ----------------------------------------------------------------------
176 void OStorageHelper::CopyInputToOutput(
177 const uno::Reference
< io::XInputStream
>& xInput
,
178 const uno::Reference
< io::XOutputStream
>& xOutput
)
179 throw ( uno::Exception
)
181 static const sal_Int32 nConstBufferSize
= 32000;
184 uno::Sequence
< sal_Int8
> aSequence ( nConstBufferSize
);
188 nRead
= xInput
->readBytes ( aSequence
, nConstBufferSize
);
189 if ( nRead
< nConstBufferSize
)
191 uno::Sequence
< sal_Int8
> aTempBuf ( aSequence
.getConstArray(), nRead
);
192 xOutput
->writeBytes ( aTempBuf
);
195 xOutput
->writeBytes ( aSequence
);
197 while ( nRead
== nConstBufferSize
);
200 // ----------------------------------------------------------------------
201 uno::Reference
< io::XInputStream
> OStorageHelper::GetInputStreamFromURL(
202 const OUString
& aURL
,
203 const uno::Reference
< uno::XComponentContext
>& context
)
204 throw ( uno::Exception
)
206 uno::Reference
< io::XInputStream
> xInputStream
= ucb::SimpleFileAccess::create(context
)->openFileRead( aURL
);
207 if ( !xInputStream
.is() )
208 throw uno::RuntimeException();
213 // ----------------------------------------------------------------------
214 void OStorageHelper::SetCommonStorageEncryptionData(
215 const uno::Reference
< embed::XStorage
>& xStorage
,
216 const uno::Sequence
< beans::NamedValue
>& aEncryptionData
)
217 throw ( uno::Exception
)
219 uno::Reference
< embed::XEncryptionProtectedSource2
> xEncrSet( xStorage
, uno::UNO_QUERY
);
220 if ( !xEncrSet
.is() )
221 throw io::IOException(); // TODO
223 xEncrSet
->setEncryptionData( aEncryptionData
);
226 // ----------------------------------------------------------------------
227 sal_Int32
OStorageHelper::GetXStorageFormat(
228 const uno::Reference
< embed::XStorage
>& xStorage
)
229 throw ( uno::Exception
)
231 uno::Reference
< beans::XPropertySet
> xStorProps( xStorage
, uno::UNO_QUERY_THROW
);
234 xStorProps
->getPropertyValue( OUString( "MediaType" ) ) >>= aMediaType
;
236 sal_Int32 nResult
= 0;
238 // TODO/LATER: the filter configuration could be used to detect it later, or batter a special service
240 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_ASCII
) ||
241 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII
) ||
242 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII
) ||
243 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_DRAW_ASCII
) ||
244 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII
) ||
245 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CALC_ASCII
) ||
246 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CHART_ASCII
) ||
247 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_MATH_ASCII
)
250 nResult
= SOFFICE_FILEFORMAT_60
;
253 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
) ||
254 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
) ||
255 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
) ||
256 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
) ||
257 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
) ||
258 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
) ||
259 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
) ||
260 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
) ||
261 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
) ||
262 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII
) ||
263 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII
) ||
264 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
) ||
265 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
) ||
266 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
) ||
267 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
) ||
268 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
) ||
269 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
272 nResult
= SOFFICE_FILEFORMAT_8
;
276 // the mediatype is not known
277 throw beans::IllegalTypeException();
283 // ----------------------------------------------------------------------
284 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromURL(
285 const OUString
& aFormat
,
286 const OUString
& aURL
,
287 sal_Int32 nStorageMode
,
288 const uno::Reference
< uno::XComponentContext
>& rxContext
,
289 sal_Bool bRepairStorage
)
290 throw ( uno::Exception
)
292 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
293 aProps
[0].Name
= "StorageFormat";
294 aProps
[0].Value
<<= aFormat
;
295 if ( bRepairStorage
)
298 aProps
[1].Name
= "RepairPackage";
299 aProps
[1].Value
<<= bRepairStorage
;
302 uno::Sequence
< uno::Any
> aArgs( 3 );
304 aArgs
[1] <<= nStorageMode
;
307 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
309 if ( !xTempStorage
.is() )
310 throw uno::RuntimeException();
315 // ----------------------------------------------------------------------
316 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromInputStream(
317 const OUString
& aFormat
,
318 const uno::Reference
< io::XInputStream
>& xStream
,
319 const uno::Reference
< uno::XComponentContext
>& rxContext
,
320 sal_Bool bRepairStorage
)
321 throw ( uno::Exception
)
323 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
324 aProps
[0].Name
= "StorageFormat";
325 aProps
[0].Value
<<= aFormat
;
326 if ( bRepairStorage
)
329 aProps
[1].Name
= "RepairPackage";
330 aProps
[1].Value
<<= bRepairStorage
;
333 uno::Sequence
< uno::Any
> aArgs( 3 );
334 aArgs
[0] <<= xStream
;
335 aArgs
[1] <<= embed::ElementModes::READ
;
338 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
340 if ( !xTempStorage
.is() )
341 throw uno::RuntimeException();
346 // ----------------------------------------------------------------------
347 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromStream(
348 const OUString
& aFormat
,
349 const uno::Reference
< io::XStream
>& xStream
,
350 sal_Int32 nStorageMode
,
351 const uno::Reference
< uno::XComponentContext
>& rxContext
,
352 sal_Bool bRepairStorage
)
353 throw ( uno::Exception
)
355 uno::Sequence
< beans::PropertyValue
> aProps( 1 );
356 aProps
[0].Name
= "StorageFormat";
357 aProps
[0].Value
<<= aFormat
;
358 if ( bRepairStorage
)
361 aProps
[1].Name
= "RepairPackage";
362 aProps
[1].Value
<<= bRepairStorage
;
365 uno::Sequence
< uno::Any
> aArgs( 3 );
366 aArgs
[0] <<= xStream
;
367 aArgs
[1] <<= nStorageMode
;
370 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
372 if ( !xTempStorage
.is() )
373 throw uno::RuntimeException();
378 // ----------------------------------------------------------------------
379 uno::Sequence
< beans::NamedValue
> OStorageHelper::CreatePackageEncryptionData( const OUString
& aPassword
)
381 // TODO/LATER: Should not the method be part of DocPasswordHelper?
382 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
383 if ( !aPassword
.isEmpty() )
385 sal_Int32 nSha1Ind
= 0;
386 // generate SHA256 start key
389 uno::Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
391 uno::Reference
< xml::crypto::XNSSInitializer
> xDigestContextSupplier
= xml::crypto::NSSInitializer::create(xContext
);
392 uno::Reference
< xml::crypto::XDigestContext
> xDigestContext( xDigestContextSupplier
->getDigestContext( xml::crypto::DigestID::SHA256
, uno::Sequence
< beans::NamedValue
>() ), uno::UNO_SET_THROW
);
394 OString
aUTF8Password( OUStringToOString( aPassword
, RTL_TEXTENCODING_UTF8
) );
395 xDigestContext
->updateDigest( uno::Sequence
< sal_Int8
>( reinterpret_cast< const sal_Int8
* >( aUTF8Password
.getStr() ), aUTF8Password
.getLength() ) );
396 uno::Sequence
< sal_Int8
> aDigest
= xDigestContext
->finalizeDigestAndDispose();
398 aEncryptionData
.realloc( ++nSha1Ind
);
399 aEncryptionData
[0].Name
= PACKAGE_ENCRYPTIONDATA_SHA256UTF8
;
400 aEncryptionData
[0].Value
<<= aDigest
;
402 catch ( uno::Exception
& )
404 OSL_ENSURE( false, "Can not create SHA256 digest!" );
407 // MS_1252 encoding was used for SO60 document format password encoding,
408 // this encoding supports only a minor subset of nonascii characters,
409 // but for compatibility reasons it has to be used for old document formats
410 aEncryptionData
.realloc( nSha1Ind
+ 2 );
411 aEncryptionData
[nSha1Ind
].Name
= PACKAGE_ENCRYPTIONDATA_SHA1UTF8
;
412 aEncryptionData
[nSha1Ind
+ 1].Name
= PACKAGE_ENCRYPTIONDATA_SHA1MS1252
;
414 rtl_TextEncoding pEncoding
[2] = { RTL_TEXTENCODING_UTF8
, RTL_TEXTENCODING_MS_1252
};
416 for ( sal_Int32 nInd
= 0; nInd
< 2; nInd
++ )
418 OString aByteStrPass
= OUStringToOString( aPassword
, pEncoding
[nInd
] );
420 sal_uInt8 pBuffer
[RTL_DIGEST_LENGTH_SHA1
];
421 rtlDigestError nError
= rtl_digest_SHA1( aByteStrPass
.getStr(),
422 aByteStrPass
.getLength(),
424 RTL_DIGEST_LENGTH_SHA1
);
426 if ( nError
!= rtl_Digest_E_None
)
428 aEncryptionData
.realloc( nSha1Ind
);
432 aEncryptionData
[nSha1Ind
+nInd
].Value
<<= uno::Sequence
< sal_Int8
>( (sal_Int8
*)pBuffer
, RTL_DIGEST_LENGTH_SHA1
);
436 return aEncryptionData
;
439 // ----------------------------------------------------------------------
440 sal_Bool
OStorageHelper::IsValidZipEntryFileName( const OUString
& aName
, sal_Bool bSlashAllowed
)
442 return IsValidZipEntryFileName( aName
.getStr(), aName
.getLength(), bSlashAllowed
);
445 // ----------------------------------------------------------------------
446 sal_Bool
OStorageHelper::IsValidZipEntryFileName(
447 const sal_Unicode
*pChar
, sal_Int32 nLength
, sal_Bool bSlashAllowed
)
449 for ( sal_Int32 i
= 0; i
< nLength
; i
++ )
462 if ( !bSlashAllowed
)
466 if ( pChar
[i
] < 32 || (pChar
[i
] >= 0xD800 && pChar
[i
] <= 0xDFFF) )
473 // ----------------------------------------------------------------------
474 sal_Bool
OStorageHelper::PathHasSegment( const OUString
& aPath
, const OUString
& aSegment
)
476 sal_Bool bResult
= sal_False
;
477 const sal_Int32 nPathLen
= aPath
.getLength();
478 const sal_Int32 nSegLen
= aSegment
.getLength();
480 if ( !aSegment
.isEmpty() && nPathLen
>= nSegLen
)
482 OUString
aEndSegment( "/" );
483 aEndSegment
+= aSegment
;
485 OUString
aInternalSegment( aEndSegment
);
486 aInternalSegment
+= "/";
488 if ( aPath
.indexOf( aInternalSegment
) >= 0 )
491 if ( !bResult
&& !aPath
.compareTo( aSegment
, nSegLen
) )
493 if ( nPathLen
== nSegLen
|| aPath
.getStr()[nSegLen
] == (sal_Unicode
)'/' )
497 if ( !bResult
&& nPathLen
> nSegLen
&& aPath
.copy( nPathLen
- nSegLen
- 1, nSegLen
+ 1 ) == aEndSegment
)
504 class LifecycleProxy::Impl
505 : public std::vector
< uno::Reference
< embed::XStorage
> > {};
506 LifecycleProxy::LifecycleProxy()
507 : m_pBadness( new Impl() ) { }
508 LifecycleProxy::~LifecycleProxy() { }
510 void LifecycleProxy::commitStorages()
512 for (Impl::reverse_iterator iter
= m_pBadness
->rbegin();
513 iter
!= m_pBadness
->rend(); ++iter
) // reverse order (outwards)
515 uno::Reference
<embed::XTransactedObject
> const xTransaction(*iter
,
517 if (xTransaction
.is())
519 xTransaction
->commit();
524 static void splitPath( std::vector
<OUString
> &rElems
,
525 const OUString
& rPath
)
527 for (sal_Int32 i
= 0; i
>= 0;)
528 rElems
.push_back( rPath
.getToken( 0, '/', i
) );
531 static uno::Reference
< embed::XStorage
> LookupStorageAtPath(
532 const uno::Reference
< embed::XStorage
> &xParentStorage
,
533 std::vector
<OUString
> &rElems
, sal_uInt32 nOpenMode
,
534 LifecycleProxy
&rNastiness
)
536 uno::Reference
< embed::XStorage
> xStorage( xParentStorage
);
537 rNastiness
.m_pBadness
->push_back( xStorage
);
538 for( size_t i
= 0; i
< rElems
.size() && xStorage
.is(); i
++ )
540 xStorage
= xStorage
->openStorageElement( rElems
[i
], nOpenMode
);
541 rNastiness
.m_pBadness
->push_back( xStorage
);
546 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageAtPath(
547 const uno::Reference
< embed::XStorage
> &xStorage
,
548 const OUString
& rPath
, sal_uInt32 nOpenMode
,
549 LifecycleProxy
&rNastiness
)
551 std::vector
<OUString
> aElems
;
552 splitPath( aElems
, rPath
);
553 return LookupStorageAtPath( xStorage
, aElems
, nOpenMode
, rNastiness
);
556 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPath(
557 const uno::Reference
< embed::XStorage
> &xParentStorage
,
558 const OUString
& rPath
, sal_uInt32 nOpenMode
,
559 LifecycleProxy
&rNastiness
)
561 std::vector
<OUString
> aElems
;
562 splitPath( aElems
, rPath
);
563 OUString
aName( aElems
.back() );
565 sal_uInt32 nStorageMode
= nOpenMode
& ~embed::ElementModes::TRUNCATE
;
566 uno::Reference
< embed::XStorage
> xStorage(
567 LookupStorageAtPath( xParentStorage
, aElems
, nStorageMode
, rNastiness
),
568 uno::UNO_QUERY_THROW
);
569 return xStorage
->openStreamElement( aName
, nOpenMode
);
572 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPackageURL(
573 uno::Reference
< embed::XStorage
> const& xParentStorage
,
574 const OUString
& rURL
, sal_uInt32
const nOpenMode
,
575 LifecycleProxy
& rNastiness
)
577 static char const s_PkgScheme
[] = "vnd.sun.star.Package:";
578 if (0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
579 rURL
.getStr(), rURL
.getLength(),
580 s_PkgScheme
, SAL_N_ELEMENTS(s_PkgScheme
) - 1))
582 OUString
const path(rURL
.copy(SAL_N_ELEMENTS(s_PkgScheme
)-1));
583 return GetStreamAtPath(xParentStorage
, path
, nOpenMode
, rNastiness
);
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */