Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
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/TempFile.hpp>
28 : #include <com/sun/star/io/XSeekable.hpp>
29 :
30 : #include <comphelper/processfactory.hxx>
31 : #include <comphelper/storagehelper.hxx>
32 : #include <cppuhelper/supportsservice.hxx>
33 : #include <osl/diagnose.h>
34 :
35 : #include "xfactory.hxx"
36 : #include "xstorage.hxx"
37 :
38 : using namespace ::com::sun::star;
39 :
40 : #if OSL_DEBUG_LEVEL > 0
41 : #define THROW_WHERE SAL_WHERE
42 : #else
43 : #define THROW_WHERE ""
44 : #endif
45 :
46 23807 : bool CheckPackageSignature_Impl( const uno::Reference< io::XInputStream >& xInputStream,
47 : const uno::Reference< io::XSeekable >& xSeekable )
48 : {
49 23807 : if ( !xInputStream.is() || !xSeekable.is() )
50 0 : throw uno::RuntimeException();
51 :
52 23807 : if ( xSeekable->getLength() )
53 : {
54 22962 : uno::Sequence< sal_Int8 > aData( 4 );
55 22962 : xSeekable->seek( 0 );
56 22962 : sal_Int32 nRead = xInputStream->readBytes( aData, 4 );
57 22962 : xSeekable->seek( 0 );
58 :
59 : // TODO/LATER: should the disk spanned files be supported?
60 : // 0x50, 0x4b, 0x07, 0x08
61 22962 : return ( nRead == 4 && aData[0] == 0x50 && aData[1] == 0x4b && aData[2] == 0x03 && aData[3] == 0x04 );
62 : }
63 : else
64 845 : return true; // allow to create a storage based on empty stream
65 : }
66 :
67 122 : uno::Sequence< OUString > SAL_CALL OStorageFactory::impl_staticGetSupportedServiceNames()
68 : {
69 122 : uno::Sequence< OUString > aRet(2);
70 122 : aRet[0] = "com.sun.star.embed.StorageFactory";
71 122 : aRet[1] = "com.sun.star.comp.embed.StorageFactory";
72 122 : return aRet;
73 : }
74 :
75 243 : OUString SAL_CALL OStorageFactory::impl_staticGetImplementationName()
76 : {
77 243 : return OUString("com.sun.star.comp.embed.StorageFactory");
78 : }
79 :
80 121 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::impl_staticCreateSelfInstance(
81 : const uno::Reference< lang::XMultiServiceFactory >& xServiceManager )
82 : {
83 121 : return uno::Reference< uno::XInterface >( *new OStorageFactory( comphelper::getComponentContext(xServiceManager) ) );
84 : }
85 :
86 3859 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstance()
87 : throw ( uno::Exception,
88 : uno::RuntimeException, std::exception )
89 : {
90 : // TODO: reimplement TempStream service to support XStream interface
91 : uno::Reference < io::XStream > xTempStream(
92 : io::TempFile::create(m_xContext),
93 3859 : uno::UNO_QUERY_THROW );
94 :
95 : return uno::Reference< uno::XInterface >(
96 : static_cast< OWeakObject* >( new OStorage( xTempStream,
97 : embed::ElementModes::READWRITE,
98 : uno::Sequence< beans::PropertyValue >(),
99 : m_xContext,
100 7718 : embed::StorageFormats::PACKAGE ) ),
101 7718 : uno::UNO_QUERY );
102 : }
103 :
104 23813 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstanceWithArguments(
105 : const uno::Sequence< uno::Any >& aArguments )
106 : throw ( uno::Exception,
107 : uno::RuntimeException, std::exception )
108 : {
109 : // The request for storage can be done with up to three arguments
110 :
111 : // The first argument specifies a source for the storage
112 : // it can be URL, XStream, XInputStream.
113 : // The second value is a mode the storage should be open in.
114 : // And the third value is a media descriptor.
115 :
116 23813 : sal_Int32 nArgNum = aArguments.getLength();
117 : OSL_ENSURE( nArgNum < 4, "Wrong parameter number" );
118 :
119 23813 : if ( !nArgNum )
120 0 : return createInstance();
121 :
122 : // first try to retrieve storage open mode if any
123 : // by default the storage will be open in readonly mode
124 23813 : sal_Int32 nStorageMode = embed::ElementModes::READ;
125 23813 : if ( nArgNum >= 2 )
126 : {
127 23813 : if( !( aArguments[1] >>= nStorageMode ) )
128 : {
129 : OSL_FAIL( "Wrong second argument!\n" );
130 0 : throw lang::IllegalArgumentException(); // TODO:
131 : }
132 : // it's always possible to read written storage in this implementation
133 23813 : nStorageMode |= embed::ElementModes::READ;
134 : }
135 :
136 23813 : if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE
137 735 : && ( nStorageMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE )
138 0 : throw lang::IllegalArgumentException(); // TODO:
139 :
140 : // retrieve storage source stream
141 23813 : OUString aURL;
142 47626 : uno::Reference< io::XStream > xStream;
143 47626 : uno::Reference< io::XInputStream > xInputStream;
144 :
145 23813 : if ( aArguments[0] >>= aURL )
146 : {
147 120 : if ( aURL.isEmpty() )
148 : {
149 : OSL_FAIL( "Empty URL is provided!\n" );
150 0 : throw lang::IllegalArgumentException(); // TODO:
151 : }
152 :
153 120 : if ( aURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:") )
154 : {
155 : OSL_FAIL( "Packages URL's are not valid for storages!\n" ); // ???
156 0 : throw lang::IllegalArgumentException(); // TODO:
157 : }
158 :
159 : uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
160 : ucb::SimpleFileAccess::create(
161 120 : m_xContext ) );
162 :
163 120 : if ( nStorageMode & embed::ElementModes::WRITE )
164 94 : xStream = xTempAccess->openFileReadWrite( aURL );
165 : else
166 26 : xInputStream = xTempAccess->openFileRead( aURL );
167 : }
168 23693 : else if ( !( aArguments[0] >>= xStream ) && !( aArguments[0] >>= xInputStream ) )
169 : {
170 : OSL_FAIL( "Wrong first argument!\n" );
171 0 : throw uno::Exception(); // TODO: Illegal argument
172 : }
173 :
174 : // retrieve mediadescriptor and set storage properties
175 47614 : uno::Sequence< beans::PropertyValue > aDescr;
176 47614 : uno::Sequence< beans::PropertyValue > aPropsToSet;
177 :
178 23807 : sal_Int32 nStorageType = embed::StorageFormats::PACKAGE;
179 :
180 23807 : if ( nArgNum >= 3 )
181 : {
182 16984 : if( aArguments[2] >>= aDescr )
183 : {
184 16984 : if ( !aURL.isEmpty() )
185 : {
186 11 : aPropsToSet.realloc(1);
187 11 : aPropsToSet[0].Name = "URL";
188 11 : aPropsToSet[0].Value <<= aURL;
189 : }
190 :
191 34612 : for ( sal_Int32 nInd = 0, nNumArgs = 1; nInd < aDescr.getLength(); nInd++ )
192 : {
193 35256 : if ( aDescr[nInd].Name == "InteractionHandler"
194 17628 : || aDescr[nInd].Name == "Password"
195 17628 : || aDescr[nInd].Name == "RepairPackage"
196 34612 : || aDescr[nInd].Name == "StatusIndicator" )
197 : // || aDescr[nInd].Name == "Unpacked" ) // TODO:
198 : {
199 644 : aPropsToSet.realloc( ++nNumArgs );
200 644 : aPropsToSet[nNumArgs-1].Name = aDescr[nInd].Name;
201 644 : aPropsToSet[nNumArgs-1].Value = aDescr[nInd].Value;
202 : }
203 16984 : else if ( aDescr[nInd].Name == "StorageFormat" )
204 : {
205 16984 : OUString aFormatName;
206 16984 : sal_Int32 nFormatID = 0;
207 16984 : if ( aDescr[nInd].Value >>= aFormatName )
208 : {
209 16984 : if ( aFormatName == PACKAGE_STORAGE_FORMAT_STRING )
210 0 : nStorageType = embed::StorageFormats::PACKAGE;
211 16984 : else if ( aFormatName == ZIP_STORAGE_FORMAT_STRING )
212 11108 : nStorageType = embed::StorageFormats::ZIP;
213 5876 : else if ( aFormatName == OFOPXML_STORAGE_FORMAT_STRING )
214 5876 : nStorageType = embed::StorageFormats::OFOPXML;
215 : else
216 0 : throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 1 );
217 : }
218 0 : else if ( aDescr[nInd].Value >>= nFormatID )
219 : {
220 0 : if ( nFormatID != embed::StorageFormats::PACKAGE
221 0 : && nFormatID != embed::StorageFormats::ZIP
222 0 : && nFormatID != embed::StorageFormats::OFOPXML )
223 0 : throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 1 );
224 :
225 0 : nStorageType = nFormatID;
226 : }
227 : else
228 0 : throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 1 );
229 : }
230 : else
231 : OSL_FAIL( "Unacceptable property, will be ignored!\n" );
232 : }
233 : }
234 : else
235 : {
236 : OSL_FAIL( "Wrong third argument!\n" );
237 0 : throw uno::Exception(); // TODO: Illegal argument
238 : }
239 :
240 : }
241 :
242 : // create storage based on source
243 23807 : if ( xInputStream.is() )
244 : {
245 : // if xInputStream is set the storage should be open from it
246 19830 : if ( ( nStorageMode & embed::ElementModes::WRITE ) )
247 0 : throw uno::Exception(); // TODO: access denied
248 :
249 19830 : uno::Reference< io::XSeekable > xSeekable( xInputStream, uno::UNO_QUERY );
250 19830 : if ( !xSeekable.is() )
251 : {
252 : // TODO: wrap stream to let it be seekable
253 : OSL_FAIL( "Nonseekable streams are not supported for now!\n" );
254 : }
255 :
256 19830 : if ( !CheckPackageSignature_Impl( xInputStream, xSeekable ) )
257 5457 : throw io::IOException(); // TODO: this is not a package file
258 :
259 : return uno::Reference< uno::XInterface >(
260 28746 : static_cast< OWeakObject* >( new OStorage( xInputStream, nStorageMode, aPropsToSet, m_xContext, nStorageType ) ),
261 34203 : uno::UNO_QUERY );
262 : }
263 3977 : else if ( xStream.is() )
264 : {
265 15595 : if ( ( ( nStorageMode & embed::ElementModes::WRITE ) && !xStream->getOutputStream().is() )
266 15908 : || !xStream->getInputStream().is() )
267 0 : throw uno::Exception(); // TODO: access denied
268 :
269 3977 : uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
270 3977 : if ( !xSeekable.is() )
271 : {
272 : // TODO: wrap stream to let it be seekable
273 : OSL_FAIL( "Nonseekable streams are not supported for now!\n" );
274 : }
275 :
276 3977 : if ( !CheckPackageSignature_Impl( xStream->getInputStream(), xSeekable ) )
277 541 : throw io::IOException(); // TODO: this is not a package file
278 :
279 : return uno::Reference< uno::XInterface >(
280 6872 : static_cast< OWeakObject* >( new OStorage( xStream, nStorageMode, aPropsToSet, m_xContext, nStorageType ) ),
281 7413 : uno::UNO_QUERY );
282 : }
283 :
284 23813 : throw uno::Exception(); // general error during creation
285 : }
286 :
287 1 : OUString SAL_CALL OStorageFactory::getImplementationName()
288 : throw ( uno::RuntimeException, std::exception )
289 : {
290 1 : return impl_staticGetImplementationName();
291 : }
292 :
293 0 : sal_Bool SAL_CALL OStorageFactory::supportsService( const OUString& ServiceName )
294 : throw ( uno::RuntimeException, std::exception )
295 : {
296 0 : return cppu::supportsService(this, ServiceName);
297 : }
298 :
299 1 : uno::Sequence< OUString > SAL_CALL OStorageFactory::getSupportedServiceNames()
300 : throw ( uno::RuntimeException, std::exception )
301 : {
302 1 : return impl_staticGetSupportedServiceNames();
303 : }
304 :
305 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|