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 :
30 : #include "xfactory.hxx"
31 : #include "xstorage.hxx"
32 :
33 :
34 : using namespace ::com::sun::star;
35 :
36 : //-------------------------------------------------------------------------
37 1072 : sal_Bool CheckPackageSignature_Impl( const uno::Reference< io::XInputStream >& xInputStream,
38 : const uno::Reference< io::XSeekable >& xSeekable )
39 : {
40 1072 : if ( !xInputStream.is() || !xSeekable.is() )
41 0 : throw uno::RuntimeException();
42 :
43 1072 : if ( xSeekable->getLength() )
44 : {
45 1040 : uno::Sequence< sal_Int8 > aData( 4 );
46 1040 : xSeekable->seek( 0 );
47 1040 : sal_Int32 nRead = xInputStream->readBytes( aData, 4 );
48 1040 : xSeekable->seek( 0 );
49 :
50 : // TODO/LATER: should the disk spanned files be supported?
51 : // 0x50, 0x4b, 0x07, 0x08
52 1040 : return ( nRead == 4 && aData[0] == 0x50 && aData[1] == 0x4b && aData[2] == 0x03 && aData[3] == 0x04 );
53 : }
54 : else
55 32 : return sal_True; // allow to create a storage based on empty stream
56 : }
57 :
58 : //-------------------------------------------------------------------------
59 15 : uno::Sequence< ::rtl::OUString > SAL_CALL OStorageFactory::impl_staticGetSupportedServiceNames()
60 : {
61 15 : uno::Sequence< ::rtl::OUString > aRet(2);
62 15 : aRet[0] = "com.sun.star.embed.StorageFactory";
63 15 : aRet[1] = "com.sun.star.comp.embed.StorageFactory";
64 15 : return aRet;
65 : }
66 :
67 : //-------------------------------------------------------------------------
68 30 : OUString SAL_CALL OStorageFactory::impl_staticGetImplementationName()
69 : {
70 30 : return OUString("com.sun.star.comp.embed.StorageFactory");
71 : }
72 :
73 : //-------------------------------------------------------------------------
74 15 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::impl_staticCreateSelfInstance(
75 : const uno::Reference< lang::XMultiServiceFactory >& xServiceManager )
76 : {
77 15 : return uno::Reference< uno::XInterface >( *new OStorageFactory( xServiceManager ) );
78 : }
79 :
80 : //-------------------------------------------------------------------------
81 733 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstance()
82 : throw ( uno::Exception,
83 : uno::RuntimeException )
84 : {
85 : // TODO: reimplement TempStream service to support XStream interface
86 : uno::Reference < io::XStream > xTempStream(
87 : io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
88 733 : uno::UNO_QUERY_THROW );
89 :
90 : return uno::Reference< uno::XInterface >(
91 : static_cast< OWeakObject* >( new OStorage( xTempStream,
92 : embed::ElementModes::READWRITE,
93 : uno::Sequence< beans::PropertyValue >(),
94 : m_xFactory,
95 1132 : embed::StorageFormats::PACKAGE ) ),
96 1132 : uno::UNO_QUERY );
97 : }
98 :
99 : //-------------------------------------------------------------------------
100 1072 : uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstanceWithArguments(
101 : const uno::Sequence< uno::Any >& aArguments )
102 : throw ( uno::Exception,
103 : uno::RuntimeException )
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 1072 : sal_Int32 nArgNum = aArguments.getLength();
113 : OSL_ENSURE( nArgNum < 4, "Wrong parameter number" );
114 :
115 1072 : 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 1072 : sal_Int32 nStorageMode = embed::ElementModes::READ;
121 1072 : if ( nArgNum >= 2 )
122 : {
123 1072 : if( !( aArguments[1] >>= nStorageMode ) )
124 : {
125 : OSL_FAIL( "Wrong second argument!\n" );
126 0 : throw lang::IllegalArgumentException(); // TODO:
127 : }
128 : // it's allways possible to read written storage in this implementation
129 1072 : nStorageMode |= embed::ElementModes::READ;
130 : }
131 :
132 1072 : if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE
133 : && ( nStorageMode & embed::ElementModes::WRITE ) != embed::ElementModes::WRITE )
134 0 : throw lang::IllegalArgumentException(); // TODO:
135 :
136 : // retrieve storage source stream
137 1072 : ::rtl::OUString aURL;
138 1072 : uno::Reference< io::XStream > xStream;
139 1072 : uno::Reference< io::XInputStream > xInputStream;
140 :
141 1072 : 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.equalsIgnoreAsciiCase("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 : comphelper::getComponentContext(m_xFactory) ) );
158 :
159 0 : if ( nStorageMode & embed::ElementModes::WRITE )
160 0 : xStream = xTempAccess->openFileReadWrite( aURL );
161 : else
162 0 : xInputStream = xTempAccess->openFileRead( aURL );
163 : }
164 1072 : 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 1072 : uno::Sequence< beans::PropertyValue > aDescr;
172 1072 : uno::Sequence< beans::PropertyValue > aPropsToSet;
173 :
174 1072 : sal_Int32 nStorageType = embed::StorageFormats::PACKAGE;
175 :
176 1072 : if ( nArgNum >= 3 )
177 : {
178 765 : if( aArguments[2] >>= aDescr )
179 : {
180 765 : if ( !aURL.isEmpty() )
181 : {
182 0 : aPropsToSet.realloc(1);
183 0 : aPropsToSet[0].Name = "URL";
184 0 : aPropsToSet[0].Value <<= aURL;
185 : }
186 :
187 1556 : for ( sal_Int32 nInd = 0, nNumArgs = 1; nInd < aDescr.getLength(); nInd++ )
188 : {
189 3138 : if ( aDescr[nInd].Name == "InteractionHandler"
190 791 : || aDescr[nInd].Name == "Password"
191 791 : || aDescr[nInd].Name == "RepairPackage"
192 765 : || aDescr[nInd].Name == "StatusIndicator" )
193 : // || aDescr[nInd].Name == "Unpacked" ) // TODO:
194 : {
195 26 : aPropsToSet.realloc( ++nNumArgs );
196 26 : aPropsToSet[nNumArgs-1].Name = aDescr[nInd].Name;
197 26 : aPropsToSet[nNumArgs-1].Value = aDescr[nInd].Value;
198 : }
199 765 : else if ( aDescr[nInd].Name == "StorageFormat" )
200 : {
201 765 : ::rtl::OUString aFormatName;
202 765 : sal_Int32 nFormatID = 0;
203 765 : if ( aDescr[nInd].Value >>= aFormatName )
204 : {
205 765 : if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) )
206 0 : nStorageType = embed::StorageFormats::PACKAGE;
207 765 : else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) )
208 422 : nStorageType = embed::StorageFormats::ZIP;
209 343 : else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) )
210 343 : nStorageType = embed::StorageFormats::OFOPXML;
211 : else
212 0 : throw lang::IllegalArgumentException( OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 1 );
213 : }
214 0 : else if ( aDescr[nInd].Value >>= nFormatID )
215 : {
216 0 : if ( nFormatID != embed::StorageFormats::PACKAGE
217 : && nFormatID != embed::StorageFormats::ZIP
218 : && nFormatID != embed::StorageFormats::OFOPXML )
219 0 : throw lang::IllegalArgumentException( OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 1 );
220 :
221 0 : nStorageType = nFormatID;
222 : }
223 : else
224 0 : throw lang::IllegalArgumentException( OSL_LOG_PREFIX, 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 1072 : if ( xInputStream.is() )
240 : {
241 : // if xInputStream is set the storage should be open from it
242 737 : if ( ( nStorageMode & embed::ElementModes::WRITE ) )
243 0 : throw uno::Exception(); // TODO: access denied
244 :
245 737 : uno::Reference< io::XSeekable > xSeekable( xInputStream, uno::UNO_QUERY );
246 737 : 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 737 : if ( !CheckPackageSignature_Impl( xInputStream, xSeekable ) )
253 118 : throw io::IOException(); // TODO: this is not a package file
254 :
255 : return uno::Reference< uno::XInterface >(
256 1238 : static_cast< OWeakObject* >( new OStorage( xInputStream, nStorageMode, aPropsToSet, m_xFactory, nStorageType ) ),
257 1356 : uno::UNO_QUERY );
258 : }
259 335 : else if ( xStream.is() )
260 : {
261 1340 : if ( ( ( nStorageMode & embed::ElementModes::WRITE ) && !xStream->getOutputStream().is() )
262 1005 : || !xStream->getInputStream().is() )
263 0 : throw uno::Exception(); // TODO: access denied
264 :
265 335 : uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY );
266 335 : 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 335 : if ( !CheckPackageSignature_Impl( xStream->getInputStream(), xSeekable ) )
273 129 : throw io::IOException(); // TODO: this is not a package file
274 :
275 : return uno::Reference< uno::XInterface >(
276 412 : static_cast< OWeakObject* >( new OStorage( xStream, nStorageMode, aPropsToSet, m_xFactory, nStorageType ) ),
277 541 : uno::UNO_QUERY );
278 : }
279 :
280 0 : throw uno::Exception(); // general error during creation
281 : }
282 :
283 : //-------------------------------------------------------------------------
284 0 : ::rtl::OUString SAL_CALL OStorageFactory::getImplementationName()
285 : throw ( uno::RuntimeException )
286 : {
287 0 : return impl_staticGetImplementationName();
288 : }
289 :
290 : //-------------------------------------------------------------------------
291 0 : sal_Bool SAL_CALL OStorageFactory::supportsService( const ::rtl::OUString& ServiceName )
292 : throw ( uno::RuntimeException )
293 : {
294 0 : uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames();
295 :
296 0 : for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
297 0 : if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
298 0 : return sal_True;
299 :
300 0 : return sal_False;
301 : }
302 :
303 : //-------------------------------------------------------------------------
304 0 : uno::Sequence< ::rtl::OUString > SAL_CALL OStorageFactory::getSupportedServiceNames()
305 : throw ( uno::RuntimeException )
306 : {
307 0 : return impl_staticGetSupportedServiceNames();
308 : }
309 :
310 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|