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