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 <sal/config.h>
21 #include <sal/log.hxx>
23 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
24 #include <com/sun/star/embed/ElementModes.hpp>
25 #include <com/sun/star/embed/StorageFormats.hpp>
26 #include <com/sun/star/beans/PropertyValue.hpp>
27 #include <com/sun/star/io/IOException.hpp>
28 #include <com/sun/star/io/TempFile.hpp>
29 #include <com/sun/star/io/XSeekable.hpp>
31 #include <comphelper/propertyvalue.hxx>
32 #include <comphelper/storagehelper.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <cppuhelper/weak.hxx>
35 #include <osl/diagnose.h>
36 #include <unotools/tempfile.hxx>
38 #include "xfactory.hxx"
39 #include "xstorage.hxx"
41 using namespace ::com::sun::star
;
43 #if OSL_DEBUG_LEVEL > 0
44 #define THROW_WHERE SAL_WHERE
46 #define THROW_WHERE ""
49 static bool CheckPackageSignature_Impl( const uno::Reference
< io::XInputStream
>& xInputStream
,
50 const uno::Reference
< io::XSeekable
>& xSeekable
)
52 if ( !xInputStream
.is() || !xSeekable
.is() )
53 throw uno::RuntimeException();
55 if ( xSeekable
->getLength() )
57 uno::Sequence
< sal_Int8
> aData( 4 );
59 sal_Int32 nRead
= xInputStream
->readBytes( aData
, 4 );
62 // TODO/LATER: should the disk spanned files be supported?
63 // 0x50, 0x4b, 0x07, 0x08
64 return ( nRead
== 4 && aData
[0] == 0x50 && aData
[1] == 0x4b && aData
[2] == 0x03 && aData
[3] == 0x04 );
67 return true; // allow to create a storage based on empty stream
72 uno::Reference
< uno::XInterface
> SAL_CALL
OStorageFactory::createInstance()
74 // TODO: reimplement TempStream service to support XStream interface
75 uno::Reference
< io::XStream
> xTempStream(new utl::TempFileFastService
);
77 return cppu::getXWeak(new OStorage(xTempStream
, embed::ElementModes::READWRITE
,
78 uno::Sequence
<beans::PropertyValue
>(), m_xContext
,
79 embed::StorageFormats::PACKAGE
));
82 uno::Reference
< uno::XInterface
> SAL_CALL
OStorageFactory::createInstanceWithArguments(
83 const uno::Sequence
< uno::Any
>& aArguments
)
85 // The request for storage can be done with up to three arguments
87 // The first argument specifies a source for the storage
88 // it can be URL, XStream, XInputStream.
89 // The second value is a mode the storage should be open in.
90 // And the third value is a media descriptor.
92 sal_Int32 nArgNum
= aArguments
.getLength();
93 OSL_ENSURE( nArgNum
< 4, "Wrong parameter number" );
96 return createInstance();
98 // first try to retrieve storage open mode if any
99 // by default the storage will be open in readonly mode
100 sal_Int32 nStorageMode
= embed::ElementModes::READ
;
103 if( !( aArguments
[1] >>= nStorageMode
) )
105 OSL_FAIL( "Wrong second argument!" );
106 throw lang::IllegalArgumentException(); // TODO:
108 // it's always possible to read written storage in this implementation
109 nStorageMode
|= embed::ElementModes::READ
;
112 if ( ( nStorageMode
& embed::ElementModes::TRUNCATE
) == embed::ElementModes::TRUNCATE
113 && ( nStorageMode
& embed::ElementModes::WRITE
) != embed::ElementModes::WRITE
)
114 throw lang::IllegalArgumentException(); // TODO:
116 // retrieve storage source stream
118 uno::Reference
< io::XStream
> xStream
;
119 uno::Reference
< io::XInputStream
> xInputStream
;
121 if ( aArguments
[0] >>= aURL
)
123 if ( aURL
.isEmpty() )
125 OSL_FAIL( "Empty URL is provided!" );
126 throw lang::IllegalArgumentException(); // TODO:
129 if ( aURL
.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:") )
131 OSL_FAIL( "Packages URL's are not valid for storages!" ); // ???
132 throw lang::IllegalArgumentException(); // TODO:
135 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(
136 ucb::SimpleFileAccess::create(
139 if ( nStorageMode
& embed::ElementModes::WRITE
)
140 xStream
= xTempAccess
->openFileReadWrite( aURL
);
142 xInputStream
= xTempAccess
->openFileRead( aURL
);
144 else if ( !( aArguments
[0] >>= xStream
) && !( aArguments
[0] >>= xInputStream
) )
146 OSL_FAIL( "Wrong first argument!" );
147 throw uno::Exception(u
"wrong first arg"_ustr
, nullptr); // TODO: Illegal argument
150 // retrieve mediadescriptor and set storage properties
151 uno::Sequence
< beans::PropertyValue
> aDescr
;
152 uno::Sequence
< beans::PropertyValue
> aPropsToSet
;
154 sal_Int32 nStorageType
= embed::StorageFormats::PACKAGE
;
158 if( aArguments
[2] >>= aDescr
)
160 if ( !aURL
.isEmpty() )
162 aPropsToSet
= { comphelper::makePropertyValue(u
"URL"_ustr
, aURL
) };
165 sal_Int32 nNumArgs
= 1;
166 for (const auto& rProp
: aDescr
)
168 if ( rProp
.Name
== "InteractionHandler"
169 || rProp
.Name
== "Password"
170 || rProp
.Name
== "RepairPackage"
171 || rProp
.Name
== "StatusIndicator" )
173 aPropsToSet
.realloc( ++nNumArgs
);
174 auto pPropsToSet
= aPropsToSet
.getArray();
175 pPropsToSet
[nNumArgs
-1].Name
= rProp
.Name
;
176 pPropsToSet
[nNumArgs
-1].Value
= rProp
.Value
;
178 else if ( rProp
.Name
== "StorageFormat" )
180 OUString aFormatName
;
181 sal_Int32 nFormatID
= 0;
182 if ( rProp
.Value
>>= aFormatName
)
184 if ( aFormatName
== PACKAGE_STORAGE_FORMAT_STRING
)
185 nStorageType
= embed::StorageFormats::PACKAGE
;
186 else if ( aFormatName
== ZIP_STORAGE_FORMAT_STRING
)
187 nStorageType
= embed::StorageFormats::ZIP
;
188 else if ( aFormatName
== OFOPXML_STORAGE_FORMAT_STRING
)
189 nStorageType
= embed::StorageFormats::OFOPXML
;
191 throw lang::IllegalArgumentException( THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
193 else if ( rProp
.Value
>>= nFormatID
)
195 if ( nFormatID
!= embed::StorageFormats::PACKAGE
196 && nFormatID
!= embed::StorageFormats::ZIP
197 && nFormatID
!= embed::StorageFormats::OFOPXML
)
198 throw lang::IllegalArgumentException( THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
200 nStorageType
= nFormatID
;
203 throw lang::IllegalArgumentException( THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
205 else if (rProp
.Name
== "NoFileSync")
207 // Forward NoFileSync to the storage.
208 aPropsToSet
.realloc(++nNumArgs
);
209 auto pPropsToSet
= aPropsToSet
.getArray();
210 pPropsToSet
[nNumArgs
- 1].Name
= rProp
.Name
;
211 pPropsToSet
[nNumArgs
- 1].Value
= rProp
.Value
;
214 OSL_FAIL( "Unacceptable property, will be ignored!" );
219 OSL_FAIL( "Wrong third argument!" );
220 throw uno::Exception(u
"wrong 3rd arg"_ustr
, nullptr); // TODO: Illegal argument
225 // create storage based on source
226 if ( xInputStream
.is() )
228 // if xInputStream is set the storage should be open from it
229 if ( nStorageMode
& embed::ElementModes::WRITE
)
230 throw uno::Exception(u
"storagemode==write"_ustr
, nullptr); // TODO: access denied
232 uno::Reference
< io::XSeekable
> xSeekable( xInputStream
, uno::UNO_QUERY
);
233 if ( !xSeekable
.is() )
235 // TODO: wrap stream to let it be seekable
236 OSL_FAIL( "Nonseekable streams are not supported for now!" );
239 if ( !CheckPackageSignature_Impl( xInputStream
, xSeekable
) )
240 throw io::IOException(u
"package signature check failed, probably not a package file"_ustr
, nullptr); // TODO: this is not a package file
242 return cppu::getXWeak(
243 new OStorage(xInputStream
, nStorageMode
, aPropsToSet
, m_xContext
, nStorageType
));
245 else if ( xStream
.is() )
247 if ( ( ( nStorageMode
& embed::ElementModes::WRITE
) && !xStream
->getOutputStream().is() )
248 || !xStream
->getInputStream().is() )
249 throw uno::Exception(u
"access denied"_ustr
, nullptr); // TODO: access denied
251 uno::Reference
< io::XSeekable
> xSeekable( xStream
, uno::UNO_QUERY
);
252 if ( !xSeekable
.is() )
254 // TODO: wrap stream to let it be seekable
255 OSL_FAIL( "Nonseekable streams are not supported for now!" );
258 if ( !CheckPackageSignature_Impl( xStream
->getInputStream(), xSeekable
) )
259 throw io::IOException(); // TODO: this is not a package file
261 return cppu::getXWeak(
262 new OStorage(xStream
, nStorageMode
, aPropsToSet
, m_xContext
, nStorageType
));
265 throw uno::Exception(u
"no input stream or regular stream"_ustr
, nullptr); // general error during creation
268 OUString SAL_CALL
OStorageFactory::getImplementationName()
270 return u
"com.sun.star.comp.embed.StorageFactory"_ustr
;
273 sal_Bool SAL_CALL
OStorageFactory::supportsService( const OUString
& ServiceName
)
275 return cppu::supportsService(this, ServiceName
);
278 uno::Sequence
< OUString
> SAL_CALL
OStorageFactory::getSupportedServiceNames()
280 return { u
"com.sun.star.embed.StorageFactory"_ustr
,
281 u
"com.sun.star.comp.embed.StorageFactory"_ustr
};
285 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
286 package_OStorageFactory_get_implementation(
287 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
289 return cppu::acquire(new OStorageFactory(context
));
292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */