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/io/NotConnectedException.hpp>
21 : #include <com/sun/star/io/BufferSizeExceededException.hpp>
22 : #include <com/sun/star/uno/RuntimeException.hpp>
23 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 : #include <ucbhelper/content.hxx>
25 : #include <com/sun/star/uno/Reference.h>
26 : #include <com/sun/star/ucb/NameClash.hpp>
27 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
28 : #include <unotools/tempfile.hxx>
29 : #include <unotools/ucbstreamhelper.hxx>
30 : #include <com/sun/star/io/XInputStream.hpp>
31 : #include <com/sun/star/ucb/InsertCommandArgument.hpp>
32 : #include <com/sun/star/ucb/ResultSetException.hpp>
33 : #include <com/sun/star/uno/Sequence.h>
34 : #include <com/sun/star/sdbc/XResultSet.hpp>
35 : #include <com/sun/star/ucb/XContentAccess.hpp>
36 : #include <com/sun/star/sdbc/XRow.hpp>
37 : #include <com/sun/star/ucb/CommandAbortedException.hpp>
38 : #include <com/sun/star/datatransfer/DataFlavor.hpp>
39 : #include <com/sun/star/ucb/ContentInfo.hpp>
40 : #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
41 : #include <com/sun/star/beans/Property.hpp>
42 : #include <com/sun/star/packages/manifest/ManifestWriter.hpp>
43 : #include <com/sun/star/packages/manifest/ManifestReader.hpp>
44 : #include <com/sun/star/ucb/InteractiveIOException.hpp>
45 :
46 : #include <rtl/digest.h>
47 : #include <tools/ref.hxx>
48 : #include <tools/debug.hxx>
49 : #include <unotools/streamhelper.hxx>
50 : #include <unotools/streamwrap.hxx>
51 : #include <unotools/ucbhelper.hxx>
52 : #include <unotools/localfilehelper.hxx>
53 : #include <tools/urlobj.hxx>
54 : #include <comphelper/processfactory.hxx>
55 : #include <cppuhelper/implbase2.hxx>
56 : #include <ucbhelper/commandenvironment.hxx>
57 :
58 : #include "sot/stg.hxx"
59 : #include "sot/storinfo.hxx"
60 : #include <sot/storage.hxx>
61 : #include <sot/exchange.hxx>
62 : #include <sot/formats.hxx>
63 : #include <comphelper/classids.hxx>
64 :
65 : #include <vector>
66 :
67 : using namespace ::com::sun::star::lang;
68 : using namespace ::com::sun::star::beans;
69 : using namespace ::com::sun::star::uno;
70 : using namespace ::com::sun::star::ucb;
71 : using namespace ::com::sun::star::io;
72 : using namespace ::com::sun::star::sdbc;
73 : using namespace ::ucbhelper;
74 :
75 : #if OSL_DEBUG_LEVEL > 1
76 : #include <stdio.h>
77 : static int nOpenFiles=0;
78 : static int nOpenStreams=0;
79 : #endif
80 :
81 : typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base;
82 : class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
83 : {
84 : protected:
85 : ::osl::Mutex m_aMutex;
86 : OUString m_aURL;
87 : SvStream* m_pSvStream;
88 :
89 : public:
90 : FileStreamWrapper_Impl( const OUString& rName );
91 : virtual ~FileStreamWrapper_Impl();
92 :
93 : virtual void SAL_CALL seek( sal_Int64 _nLocation ) throw ( IllegalArgumentException, IOException, RuntimeException);
94 : virtual sal_Int64 SAL_CALL getPosition( ) throw ( IOException, RuntimeException);
95 : virtual sal_Int64 SAL_CALL getLength( ) throw ( IOException, RuntimeException);
96 : virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
97 : virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
98 : virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException);
99 : virtual sal_Int32 SAL_CALL available() throw( NotConnectedException, RuntimeException );
100 : virtual void SAL_CALL closeInput() throw( NotConnectedException, RuntimeException );
101 :
102 : protected:
103 : void checkConnected();
104 : void checkError();
105 : };
106 :
107 : //------------------------------------------------------------------
108 0 : FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString& rName )
109 : : m_aURL( rName )
110 0 : , m_pSvStream(0)
111 : {
112 : // if no URL is provided the stream is empty
113 0 : }
114 :
115 : //------------------------------------------------------------------
116 0 : FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
117 : {
118 0 : if ( m_pSvStream )
119 : {
120 0 : delete m_pSvStream;
121 : #if OSL_DEBUG_LEVEL > 1
122 : --nOpenFiles;
123 : #endif
124 : }
125 :
126 0 : if ( !m_aURL.isEmpty() )
127 0 : ::utl::UCBContentHelper::Kill( m_aURL );
128 0 : }
129 :
130 : //------------------------------------------------------------------------------
131 0 : sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
132 : throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
133 : {
134 0 : if ( m_aURL.isEmpty() )
135 : {
136 0 : aData.realloc( 0 );
137 0 : return 0;
138 : }
139 :
140 0 : checkConnected();
141 :
142 0 : if (nBytesToRead < 0)
143 0 : throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
144 :
145 0 : ::osl::MutexGuard aGuard( m_aMutex );
146 :
147 0 : aData.realloc(nBytesToRead);
148 :
149 0 : sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
150 0 : checkError();
151 :
152 : // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
153 0 : if (nRead < (sal_uInt32)nBytesToRead)
154 0 : aData.realloc( nRead );
155 :
156 0 : return nRead;
157 : }
158 :
159 : //------------------------------------------------------------------------------
160 0 : sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
161 : {
162 0 : if ( m_aURL.isEmpty() )
163 : {
164 0 : aData.realloc( 0 );
165 0 : return 0;
166 : }
167 :
168 0 : checkError();
169 :
170 0 : if (nMaxBytesToRead < 0)
171 0 : throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
172 :
173 0 : if (m_pSvStream->IsEof())
174 : {
175 0 : aData.realloc(0);
176 0 : return 0;
177 : }
178 : else
179 0 : return readBytes(aData, nMaxBytesToRead);
180 : }
181 :
182 : //------------------------------------------------------------------------------
183 0 : void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
184 : {
185 0 : if ( m_aURL.isEmpty() )
186 0 : return;
187 :
188 0 : ::osl::MutexGuard aGuard( m_aMutex );
189 0 : checkError();
190 :
191 0 : m_pSvStream->SeekRel(nBytesToSkip);
192 0 : checkError();
193 : }
194 :
195 : //------------------------------------------------------------------------------
196 0 : sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException )
197 : {
198 0 : if ( m_aURL.isEmpty() )
199 0 : return 0;
200 :
201 0 : ::osl::MutexGuard aGuard( m_aMutex );
202 0 : checkConnected();
203 :
204 0 : sal_uInt32 nPos = m_pSvStream->Tell();
205 0 : checkError();
206 :
207 0 : m_pSvStream->Seek(STREAM_SEEK_TO_END);
208 0 : checkError();
209 :
210 0 : sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
211 0 : m_pSvStream->Seek(nPos);
212 0 : checkError();
213 :
214 0 : return nAvailable;
215 : }
216 :
217 : //------------------------------------------------------------------------------
218 0 : void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException )
219 : {
220 0 : if ( m_aURL.isEmpty() )
221 0 : return;
222 :
223 0 : ::osl::MutexGuard aGuard( m_aMutex );
224 0 : checkConnected();
225 0 : DELETEZ( m_pSvStream );
226 : #if OSL_DEBUG_LEVEL > 1
227 : --nOpenFiles;
228 : #endif
229 0 : ::utl::UCBContentHelper::Kill( m_aURL );
230 0 : m_aURL = "";
231 : }
232 :
233 : //------------------------------------------------------------------------------
234 0 : void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
235 : {
236 0 : if ( m_aURL.isEmpty() )
237 0 : return;
238 :
239 0 : ::osl::MutexGuard aGuard( m_aMutex );
240 0 : checkConnected();
241 :
242 0 : m_pSvStream->Seek((sal_uInt32)_nLocation);
243 0 : checkError();
244 : }
245 :
246 : //------------------------------------------------------------------------------
247 0 : sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( ) throw (IOException, RuntimeException)
248 : {
249 0 : if ( m_aURL.isEmpty() )
250 0 : return 0;
251 :
252 0 : ::osl::MutexGuard aGuard( m_aMutex );
253 0 : checkConnected();
254 :
255 0 : sal_uInt32 nPos = m_pSvStream->Tell();
256 0 : checkError();
257 0 : return (sal_Int64)nPos;
258 : }
259 :
260 : //------------------------------------------------------------------------------
261 0 : sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( ) throw (IOException, RuntimeException)
262 : {
263 0 : if ( m_aURL.isEmpty() )
264 0 : return 0;
265 :
266 0 : ::osl::MutexGuard aGuard( m_aMutex );
267 0 : checkConnected();
268 :
269 0 : sal_uInt32 nCurrentPos = m_pSvStream->Tell();
270 0 : checkError();
271 :
272 0 : m_pSvStream->Seek(STREAM_SEEK_TO_END);
273 0 : sal_uInt32 nEndPos = m_pSvStream->Tell();
274 0 : m_pSvStream->Seek(nCurrentPos);
275 :
276 0 : checkError();
277 :
278 0 : return (sal_Int64)nEndPos;
279 : }
280 :
281 : //------------------------------------------------------------------------------
282 0 : void FileStreamWrapper_Impl::checkConnected()
283 : {
284 0 : if ( m_aURL.isEmpty() )
285 0 : throw NotConnectedException(OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
286 0 : if ( !m_pSvStream )
287 : {
288 0 : m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ );
289 : #if OSL_DEBUG_LEVEL > 1
290 : ++nOpenFiles;
291 : #endif
292 : }
293 0 : }
294 :
295 : //------------------------------------------------------------------------------
296 0 : void FileStreamWrapper_Impl::checkError()
297 : {
298 0 : checkConnected();
299 :
300 0 : if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
301 : // TODO: really evaluate the error
302 0 : throw NotConnectedException(OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
303 0 : }
304 :
305 0 : TYPEINIT1( UCBStorageStream, BaseStorageStream );
306 1970 : TYPEINIT1( UCBStorage, BaseStorage );
307 :
308 : #define COMMIT_RESULT_FAILURE 0
309 : #define COMMIT_RESULT_NOTHING_TO_DO 1
310 : #define COMMIT_RESULT_SUCCESS 2
311 :
312 : #define min( x, y ) (( x < y ) ? x : y)
313 :
314 0 : sal_Int32 GetFormatId_Impl( SvGlobalName aName )
315 : {
316 0 : if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
317 0 : return SOT_FORMATSTR_ID_STARWRITER_60;
318 0 : if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
319 0 : return SOT_FORMATSTR_ID_STARWRITERWEB_60;
320 0 : if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
321 0 : return SOT_FORMATSTR_ID_STARWRITERGLOB_60;
322 0 : if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
323 0 : return SOT_FORMATSTR_ID_STARDRAW_60;
324 0 : if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
325 0 : return SOT_FORMATSTR_ID_STARIMPRESS_60;
326 0 : if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
327 0 : return SOT_FORMATSTR_ID_STARCALC_60;
328 0 : if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
329 0 : return SOT_FORMATSTR_ID_STARCHART_60;
330 0 : if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
331 0 : return SOT_FORMATSTR_ID_STARMATH_60;
332 0 : if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
333 0 : aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
334 0 : aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
335 0 : aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
336 : // allowed, but not supported
337 0 : return 0;
338 : else
339 : {
340 : OSL_FAIL( "Unknown UCB storage format!" );
341 0 : return 0;
342 : }
343 : }
344 :
345 :
346 0 : SvGlobalName GetClassId_Impl( sal_Int32 nFormat )
347 : {
348 0 : switch ( nFormat )
349 : {
350 : case SOT_FORMATSTR_ID_STARWRITER_8 :
351 : case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE :
352 0 : return SvGlobalName( SO3_SW_CLASSID_60 );
353 : case SOT_FORMATSTR_ID_STARWRITERWEB_8 :
354 0 : return SvGlobalName( SO3_SWWEB_CLASSID_60 );
355 : case SOT_FORMATSTR_ID_STARWRITERGLOB_8 :
356 0 : return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
357 : case SOT_FORMATSTR_ID_STARDRAW_8 :
358 : case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE :
359 0 : return SvGlobalName( SO3_SDRAW_CLASSID_60 );
360 : case SOT_FORMATSTR_ID_STARIMPRESS_8 :
361 : case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE :
362 0 : return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
363 : case SOT_FORMATSTR_ID_STARCALC_8 :
364 : case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE :
365 0 : return SvGlobalName( SO3_SC_CLASSID_60 );
366 : case SOT_FORMATSTR_ID_STARCHART_8 :
367 : case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE :
368 0 : return SvGlobalName( SO3_SCH_CLASSID_60 );
369 : case SOT_FORMATSTR_ID_STARMATH_8 :
370 : case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE :
371 0 : return SvGlobalName( SO3_SM_CLASSID_60 );
372 : case SOT_FORMATSTR_ID_STARWRITER_60 :
373 0 : return SvGlobalName( SO3_SW_CLASSID_60 );
374 : case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
375 0 : return SvGlobalName( SO3_SWWEB_CLASSID_60 );
376 : case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
377 0 : return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
378 : case SOT_FORMATSTR_ID_STARDRAW_60 :
379 0 : return SvGlobalName( SO3_SDRAW_CLASSID_60 );
380 : case SOT_FORMATSTR_ID_STARIMPRESS_60 :
381 0 : return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
382 : case SOT_FORMATSTR_ID_STARCALC_60 :
383 0 : return SvGlobalName( SO3_SC_CLASSID_60 );
384 : case SOT_FORMATSTR_ID_STARCHART_60 :
385 0 : return SvGlobalName( SO3_SCH_CLASSID_60 );
386 : case SOT_FORMATSTR_ID_STARMATH_60 :
387 0 : return SvGlobalName( SO3_SM_CLASSID_60 );
388 : default :
389 0 : return SvGlobalName();
390 : }
391 : }
392 :
393 : // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
394 : // class, that uses the refcounted object as impl-class.
395 :
396 : enum RepresentModes {
397 : nonset,
398 : svstream,
399 : xinputstream
400 : };
401 :
402 : class UCBStorageStream_Impl : public SvRefBase, public SvStream
403 : {
404 : ~UCBStorageStream_Impl();
405 : public:
406 :
407 : virtual sal_uLong GetData( void* pData, sal_uLong nSize );
408 : virtual sal_uLong PutData( const void* pData, sal_uLong nSize );
409 : virtual sal_uLong SeekPos( sal_uLong nPos );
410 : virtual void SetSize( sal_uLong nSize );
411 : virtual void FlushData();
412 : virtual void ResetError();
413 :
414 : UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
415 :
416 : OUString m_aOriginalName;// the original name before accessing the stream
417 : OUString m_aName; // the actual name ( changed with a Rename command at the parent )
418 : OUString m_aURL; // the full path name to create the content
419 : OUString m_aContentType;
420 : OUString m_aOriginalContentType;
421 : OString m_aKey;
422 : ::ucbhelper::Content* m_pContent; // the content that provides the data
423 : Reference<XInputStream> m_rSource; // the stream covering the original data of the content
424 : SvStream* m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
425 : // for read/write streams it's a copy into a temporary file
426 : OUString m_aTempURL; // URL of this temporary stream
427 : RepresentModes m_nRepresentMode; // should it be used as XInputStream or as SvStream
428 : long m_nError;
429 : StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
430 : bool m_bSourceRead; // Source still contains useful information
431 : bool m_bModified; // only modified streams will be sent to the original content
432 : bool m_bCommited; // sending the streams is coordinated by the root storage of the package
433 : bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
434 : // this means that the root storage does an autocommit when its external
435 : // reference is destroyed
436 : bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
437 :
438 : UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool, const OString* pKey=0,
439 : bool bRepair = false, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() );
440 :
441 : void Free();
442 : bool Init();
443 : bool Clear();
444 : sal_Int16 Commit(); // if modified and commited: transfer an XInputStream to the content
445 : bool Revert(); // discard all changes
446 : BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
447 : sal_uLong GetSize();
448 :
449 : sal_uLong ReadSourceWriteTemporary( sal_uLong aLength ); // read aLength from source and copy to temporary,
450 : // no seeking is produced
451 : sal_uLong ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
452 :
453 : sal_uLong CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
454 : // but the writing is done at the end of temporary
455 : // pointer position is not changed
456 : using SvStream::SetError;
457 : void SetError( sal_uInt32 nError );
458 : void PrepareCachedForReopen( StreamMode nMode );
459 : };
460 :
461 0 : SV_DECL_IMPL_REF( UCBStorageStream_Impl );
462 :
463 : struct UCBStorageElement_Impl;
464 : typedef ::std::vector< UCBStorageElement_Impl* > UCBStorageElementList_Impl;
465 :
466 : class UCBStorage_Impl : public SvRefBase
467 : {
468 : ~UCBStorage_Impl();
469 : public:
470 : UCBStorage* m_pAntiImpl; // only valid if external references exists
471 :
472 : OUString m_aOriginalName;// the original name before accessing the storage
473 : OUString m_aName; // the actual name ( changed with a Rename command at the parent )
474 : OUString m_aURL; // the full path name to create the content
475 : OUString m_aContentType;
476 : OUString m_aOriginalContentType;
477 : ::ucbhelper::Content* m_pContent; // the content that provides the storage elements
478 : ::utl::TempFile* m_pTempFile; // temporary file, only for storages on stream
479 : SvStream* m_pSource; // original stream, only for storages on a stream
480 : long m_nError;
481 : StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
482 : bool m_bModified; // only modified elements will be sent to the original content
483 : bool m_bCommited; // sending the streams is coordinated by the root storage of the package
484 : bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
485 : // this means that the root storage does an autocommit when its external
486 : // reference is destroyed
487 : bool m_bIsRoot; // marks this storage as root storages that manages all oommits and reverts
488 : bool m_bDirty; // ???
489 : bool m_bIsLinked;
490 : bool m_bListCreated;
491 : sal_uLong m_nFormat;
492 : OUString m_aUserTypeName;
493 : SvGlobalName m_aClassId;
494 :
495 : UCBStorageElementList_Impl m_aChildrenList;
496 :
497 : bool m_bRepairPackage;
498 : Reference< XProgressHandler > m_xProgressHandler;
499 :
500 : UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
501 : bool, bool = false, Reference< XProgressHandler > = Reference< XProgressHandler >() );
502 : UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
503 : bool = false, Reference< XProgressHandler > = Reference< XProgressHandler >() );
504 : UCBStorage_Impl( SvStream&, UCBStorage*, bool );
505 : void Init();
506 : sal_Int16 Commit();
507 : bool Revert();
508 : bool Insert( ::ucbhelper::Content *pContent );
509 : UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
510 : UCBStorageStream_Impl* OpenStream( UCBStorageElement_Impl*, StreamMode, bool, const OString* pKey=0 );
511 : void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
512 : void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
513 : sal_Int32 GetObjectCount();
514 : void ReadContent();
515 : void CreateContent();
516 401 : ::ucbhelper::Content* GetContent()
517 401 : { if ( !m_pContent ) CreateContent(); return m_pContent; }
518 802 : UCBStorageElementList_Impl& GetChildrenList()
519 : {
520 802 : long nError = m_nError;
521 802 : ReadContent();
522 802 : if ( m_nMode & STREAM_WRITE )
523 : {
524 802 : m_nError = nError;
525 802 : if ( m_pAntiImpl )
526 : {
527 802 : m_pAntiImpl->ResetError();
528 802 : m_pAntiImpl->SetError( nError );
529 : }
530 : }
531 :
532 802 : return m_aChildrenList;
533 : }
534 :
535 : void SetError( long nError );
536 : };
537 :
538 0 : SV_DECL_IMPL_REF( UCBStorage_Impl );
539 :
540 : // this struct contains all necessary information on an element inside a UCBStorage
541 0 : struct UCBStorageElement_Impl
542 : {
543 : OUString m_aName; // the actual URL relative to the root "folder"
544 : OUString m_aOriginalName;// the original name in the content
545 : sal_uLong m_nSize;
546 : bool m_bIsFolder; // Only true when it is a UCBStorage !
547 : bool m_bIsStorage; // Also true when it is an OLEStorage !
548 : bool m_bIsRemoved; // element will be removed on commit
549 : bool m_bIsInserted; // element will be removed on revert
550 : UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
551 : UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
552 :
553 0 : UCBStorageElement_Impl( const OUString& rName,
554 : bool bIsFolder = false, sal_uLong nSize = 0 )
555 : : m_aName( rName )
556 : , m_aOriginalName( rName )
557 : , m_nSize( nSize )
558 : , m_bIsFolder( bIsFolder )
559 : , m_bIsStorage( bIsFolder )
560 : , m_bIsRemoved( false )
561 0 : , m_bIsInserted( false )
562 : {
563 0 : }
564 :
565 : ::ucbhelper::Content* GetContent();
566 : bool IsModified();
567 : OUString GetContentType();
568 : void SetContentType( const OUString& );
569 : OUString GetOriginalContentType();
570 0 : bool IsLoaded()
571 0 : { return m_xStream.Is() || m_xStorage.Is(); }
572 : };
573 :
574 0 : ::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
575 : {
576 0 : if ( m_xStream.Is() )
577 0 : return m_xStream->m_pContent;
578 0 : else if ( m_xStorage.Is() )
579 0 : return m_xStorage->GetContent();
580 : else
581 0 : return NULL;
582 : }
583 :
584 0 : OUString UCBStorageElement_Impl::GetContentType()
585 : {
586 0 : if ( m_xStream.Is() )
587 0 : return m_xStream->m_aContentType;
588 0 : else if ( m_xStorage.Is() )
589 0 : return m_xStorage->m_aContentType;
590 : else
591 : {
592 : OSL_FAIL("Element not loaded!");
593 0 : return OUString();
594 : }
595 : }
596 :
597 0 : void UCBStorageElement_Impl::SetContentType( const OUString& rType )
598 : {
599 0 : if ( m_xStream.Is() ) {
600 0 : m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
601 : }
602 0 : else if ( m_xStorage.Is() ) {
603 0 : m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
604 : }
605 : else {
606 : OSL_FAIL("Element not loaded!");
607 : }
608 0 : }
609 :
610 0 : OUString UCBStorageElement_Impl::GetOriginalContentType()
611 : {
612 0 : if ( m_xStream.Is() )
613 0 : return m_xStream->m_aOriginalContentType;
614 0 : else if ( m_xStorage.Is() )
615 0 : return m_xStorage->m_aOriginalContentType;
616 : else
617 0 : return OUString();
618 : }
619 :
620 0 : bool UCBStorageElement_Impl::IsModified()
621 : {
622 0 : bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
623 0 : if ( bModified )
624 : {
625 0 : if ( m_xStream.Is() )
626 0 : bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
627 0 : else if ( m_xStorage.Is() )
628 0 : bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
629 : }
630 :
631 0 : return bModified;
632 : }
633 :
634 0 : UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, const OString* pKey, bool bRepair, Reference< XProgressHandler > xProgress )
635 : : m_pAntiImpl( pStream )
636 : , m_aURL( rName )
637 : , m_pContent( NULL )
638 : , m_pStream( NULL )
639 : , m_nRepresentMode( nonset )
640 : , m_nError( 0 )
641 : , m_nMode( nMode )
642 0 : , m_bSourceRead( !( nMode & STREAM_TRUNC ) )
643 : , m_bModified( false )
644 : , m_bCommited( false )
645 : , m_bDirect( bDirect )
646 0 : , m_bIsOLEStorage( false )
647 : {
648 : // name is last segment in URL
649 0 : INetURLObject aObj( rName );
650 0 : m_aName = m_aOriginalName = aObj.GetLastName();
651 : try
652 : {
653 : // create the content
654 0 : Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
655 :
656 0 : OUString aTemp( rName );
657 :
658 0 : if ( bRepair )
659 : {
660 0 : xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
661 0 : xProgress );
662 0 : aTemp += OUString("?repairpackage");
663 : }
664 :
665 0 : m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
666 :
667 0 : if ( pKey )
668 : {
669 0 : m_aKey = *pKey;
670 :
671 : // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
672 : sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1];
673 0 : rtlDigestError nErr = rtl_digest_SHA1( pKey->getStr(), pKey->getLength(), aBuffer, RTL_DIGEST_LENGTH_SHA1 );
674 0 : if ( nErr == rtl_Digest_E_None )
675 : {
676 0 : sal_uInt8* pBuffer = aBuffer;
677 0 : ::com::sun::star::uno::Sequence < sal_Int8 > aSequ( (sal_Int8*) pBuffer, RTL_DIGEST_LENGTH_SHA1 );
678 0 : ::com::sun::star::uno::Any aAny;
679 0 : aAny <<= aSequ;
680 0 : m_pContent->setPropertyValue("EncryptionKey", aAny );
681 : }
682 0 : }
683 : }
684 0 : catch (const ContentCreationException&)
685 : {
686 : // content could not be created
687 0 : SetError( SVSTREAM_CANNOT_MAKE );
688 : }
689 0 : catch (const RuntimeException&)
690 : {
691 : // any other error - not specified
692 0 : SetError( ERRCODE_IO_GENERAL );
693 0 : }
694 0 : }
695 :
696 0 : UCBStorageStream_Impl::~UCBStorageStream_Impl()
697 : {
698 0 : if( m_rSource.is() )
699 0 : m_rSource.clear();
700 :
701 0 : if( m_pStream )
702 0 : delete m_pStream;
703 :
704 0 : if ( !m_aTempURL.isEmpty() )
705 0 : ::utl::UCBContentHelper::Kill( m_aTempURL );
706 :
707 0 : if( m_pContent )
708 0 : delete m_pContent;
709 0 : }
710 :
711 :
712 0 : bool UCBStorageStream_Impl::Init()
713 : {
714 0 : if( m_nRepresentMode == xinputstream )
715 : {
716 : OSL_FAIL( "XInputStream misuse!" );
717 0 : SetError( ERRCODE_IO_ACCESSDENIED );
718 0 : return false;
719 : }
720 :
721 0 : if( !m_pStream )
722 : {
723 : // no temporary stream was created
724 : // create one
725 :
726 0 : m_nRepresentMode = svstream; // can not be used as XInputStream
727 :
728 0 : if ( m_aTempURL.isEmpty() )
729 0 : m_aTempURL = ::utl::TempFile().GetURL();
730 :
731 0 : m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, STREAM_STD_READWRITE, true /* bFileExists */ );
732 : #if OSL_DEBUG_LEVEL > 1
733 : ++nOpenFiles;
734 : #endif
735 :
736 0 : if( !m_pStream )
737 : {
738 : OSL_FAIL( "Suspicious temporary stream creation!" );
739 0 : SetError( SVSTREAM_CANNOT_MAKE );
740 0 : return false;
741 : }
742 :
743 0 : SetError( m_pStream->GetError() );
744 : }
745 :
746 0 : if( m_bSourceRead && !m_rSource.is() )
747 : {
748 : // source file contain useful information and is not opened
749 : // open it from the point of noncopied data
750 :
751 : try
752 : {
753 0 : m_rSource = m_pContent->openStream();
754 : }
755 0 : catch (const Exception&)
756 : {
757 : // usually means that stream could not be opened
758 : }
759 :
760 0 : if( m_rSource.is() )
761 : {
762 0 : m_pStream->Seek( STREAM_SEEK_TO_END );
763 :
764 : try
765 : {
766 0 : m_rSource->skipBytes( m_pStream->Tell() );
767 : }
768 0 : catch (const BufferSizeExceededException&)
769 : {
770 : // the temporary stream already contain all the data
771 0 : m_bSourceRead = false;
772 : }
773 0 : catch (const Exception&)
774 : {
775 : // something is really wrong
776 0 : m_bSourceRead = false;
777 : OSL_FAIL( "Can not operate original stream!" );
778 0 : SetError( SVSTREAM_CANNOT_MAKE );
779 : }
780 :
781 0 : m_pStream->Seek( 0 );
782 : }
783 : else
784 : {
785 : // if the new file is edited than no source exist
786 0 : m_bSourceRead = false;
787 : //SetError( SVSTREAM_CANNOT_MAKE );
788 : }
789 : }
790 :
791 : DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
792 :
793 0 : return true;
794 : }
795 :
796 0 : sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary()
797 : {
798 : // read source stream till the end and copy all the data to
799 : // the current position of the temporary stream
800 :
801 0 : sal_uLong aResult = 0;
802 :
803 0 : if( m_bSourceRead )
804 : {
805 0 : Sequence<sal_Int8> aData(32000);
806 :
807 : try
808 : {
809 : sal_uLong aReaded;
810 0 : do
811 : {
812 0 : aReaded = m_rSource->readBytes( aData, 32000 );
813 0 : aResult += m_pStream->Write( aData.getArray(), aReaded );
814 : } while( aReaded == 32000 );
815 : }
816 0 : catch (const Exception &e)
817 : {
818 : OSL_FAIL( OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
819 : (void)e;
820 0 : }
821 : }
822 :
823 0 : m_bSourceRead = false;
824 :
825 0 : return aResult;
826 :
827 : }
828 :
829 0 : sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength )
830 : {
831 : // read aLength bite from the source stream and copy them to the current
832 : // position of the temporary stream
833 :
834 0 : sal_uLong aResult = 0;
835 :
836 0 : if( m_bSourceRead )
837 : {
838 0 : Sequence<sal_Int8> aData(32000);
839 :
840 : try
841 : {
842 :
843 0 : sal_uLong aReaded = 32000;
844 :
845 0 : for( sal_uLong pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 )
846 : {
847 0 : sal_uLong aToCopy = min( aLength - pInd, 32000 );
848 0 : aReaded = m_rSource->readBytes( aData, aToCopy );
849 0 : aResult += m_pStream->Write( aData.getArray(), aReaded );
850 : }
851 :
852 0 : if( aResult < aLength )
853 0 : m_bSourceRead = false;
854 : }
855 0 : catch( const Exception & e )
856 : {
857 : OSL_FAIL( OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
858 : (void)e;
859 0 : }
860 : }
861 :
862 0 : return aResult;
863 : }
864 :
865 0 : sal_uLong UCBStorageStream_Impl::CopySourceToTemporary()
866 : {
867 : // current position of the temporary stream is not changed
868 0 : sal_uLong aResult = 0;
869 :
870 0 : if( m_bSourceRead )
871 : {
872 0 : sal_uLong aPos = m_pStream->Tell();
873 0 : m_pStream->Seek( STREAM_SEEK_TO_END );
874 0 : aResult = ReadSourceWriteTemporary();
875 0 : m_pStream->Seek( aPos );
876 : }
877 :
878 0 : return aResult;
879 :
880 : }
881 :
882 : // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
883 : // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
884 0 : sal_uLong UCBStorageStream_Impl::GetData( void* pData, sal_uLong nSize )
885 : {
886 0 : sal_uLong aResult = 0;
887 :
888 0 : if( !Init() )
889 0 : return 0;
890 :
891 :
892 : // read data that is in temporary stream
893 0 : aResult = m_pStream->Read( pData, nSize );
894 0 : if( m_bSourceRead && aResult < nSize )
895 : {
896 : // read the tail of the data from original stream
897 : // copy this tail to the temporary stream
898 :
899 0 : sal_uLong aToRead = nSize - aResult;
900 0 : pData = (void*)( (char*)pData + aResult );
901 :
902 : try
903 : {
904 0 : Sequence<sal_Int8> aData( aToRead );
905 0 : sal_uLong aReaded = m_rSource->readBytes( aData, aToRead );
906 0 : aResult += m_pStream->Write( (void*)aData.getArray(), aReaded );
907 0 : memcpy( pData, aData.getArray(), aReaded );
908 : }
909 0 : catch (const Exception &e)
910 : {
911 : OSL_FAIL( OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
912 : (void)e;
913 : }
914 :
915 0 : if( aResult < nSize )
916 0 : m_bSourceRead = false;
917 : }
918 :
919 0 : return aResult;
920 : }
921 :
922 0 : sal_uLong UCBStorageStream_Impl::PutData( const void* pData, sal_uLong nSize )
923 : {
924 0 : if ( !(m_nMode & STREAM_WRITE) )
925 : {
926 0 : SetError( ERRCODE_IO_ACCESSDENIED );
927 0 : return 0; // ?mav?
928 : }
929 :
930 0 : if( !nSize || !Init() )
931 0 : return 0;
932 :
933 0 : sal_uLong aResult = m_pStream->Write( pData, nSize );
934 :
935 0 : m_bModified = aResult > 0;
936 :
937 0 : return aResult;
938 :
939 : }
940 :
941 0 : sal_uLong UCBStorageStream_Impl::SeekPos( sal_uLong nPos )
942 : {
943 0 : if( !Init() )
944 0 : return 0;
945 :
946 : sal_uLong aResult;
947 :
948 0 : if( nPos == STREAM_SEEK_TO_END )
949 : {
950 0 : m_pStream->Seek( STREAM_SEEK_TO_END );
951 0 : ReadSourceWriteTemporary();
952 0 : aResult = m_pStream->Tell();
953 : }
954 : else
955 : {
956 : // the problem is that even if nPos is larger the length
957 : // of the stream the stream pointer will be moved to this position
958 : // so we have to check if temporary stream does not contain required position
959 :
960 0 : if( m_pStream->Tell() > nPos
961 0 : || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
962 : {
963 : // no copiing is required
964 0 : aResult = m_pStream->Seek( nPos );
965 : }
966 : else
967 : {
968 : // the temp stream pointer points to the end now
969 0 : aResult = m_pStream->Tell();
970 :
971 0 : if( aResult < nPos )
972 : {
973 0 : if( m_bSourceRead )
974 : {
975 0 : aResult += ReadSourceWriteTemporary( nPos - aResult );
976 0 : if( aResult < nPos )
977 0 : m_bSourceRead = false;
978 :
979 : DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
980 : }
981 :
982 0 : if( (m_nMode & STREAM_WRITE) && !m_bSourceRead && aResult < nPos )
983 : {
984 : // it means that all the Source stream was copied already
985 : // but the required position still was not reached
986 : // for writable streams it should be done
987 0 : m_pStream->SetStreamSize( nPos );
988 0 : aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
989 : DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
990 : }
991 : }
992 : }
993 : }
994 :
995 0 : return aResult;
996 : }
997 :
998 0 : void UCBStorageStream_Impl::SetSize( sal_uLong nSize )
999 : {
1000 0 : if ( !(m_nMode & STREAM_WRITE) )
1001 : {
1002 0 : SetError( ERRCODE_IO_ACCESSDENIED );
1003 0 : return;
1004 : }
1005 :
1006 0 : if( !Init() )
1007 0 : return;
1008 :
1009 0 : m_bModified = true;
1010 :
1011 0 : if( m_bSourceRead )
1012 : {
1013 0 : sal_uLong aPos = m_pStream->Tell();
1014 0 : m_pStream->Seek( STREAM_SEEK_TO_END );
1015 0 : if( m_pStream->Tell() < nSize )
1016 0 : ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
1017 0 : m_pStream->Seek( aPos );
1018 : }
1019 :
1020 0 : m_pStream->SetStreamSize( nSize );
1021 0 : m_bSourceRead = false;
1022 : }
1023 :
1024 0 : void UCBStorageStream_Impl::FlushData()
1025 : {
1026 0 : if( m_pStream )
1027 : {
1028 0 : CopySourceToTemporary();
1029 0 : m_pStream->Flush();
1030 : }
1031 :
1032 0 : m_bCommited = true;
1033 0 : }
1034 :
1035 0 : void UCBStorageStream_Impl::SetError( sal_uInt32 nErr )
1036 : {
1037 0 : if ( !m_nError )
1038 : {
1039 0 : m_nError = nErr;
1040 0 : SvStream::SetError( nErr );
1041 0 : if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
1042 : }
1043 0 : }
1044 :
1045 0 : void UCBStorageStream_Impl::ResetError()
1046 : {
1047 0 : m_nError = 0;
1048 0 : SvStream::ResetError();
1049 0 : if ( m_pAntiImpl )
1050 0 : m_pAntiImpl->ResetError();
1051 0 : }
1052 :
1053 0 : sal_uLong UCBStorageStream_Impl::GetSize()
1054 : {
1055 0 : if( !Init() )
1056 0 : return 0;
1057 :
1058 0 : sal_uLong nPos = m_pStream->Tell();
1059 0 : m_pStream->Seek( STREAM_SEEK_TO_END );
1060 0 : ReadSourceWriteTemporary();
1061 0 : sal_uLong nRet = m_pStream->Tell();
1062 0 : m_pStream->Seek( nPos );
1063 :
1064 0 : return nRet;
1065 : }
1066 :
1067 0 : BaseStorage* UCBStorageStream_Impl::CreateStorage()
1068 : {
1069 : // create an OLEStorage on a SvStream ( = this )
1070 : // it gets the root attribute because otherwise it would probably not write before my root is commited
1071 0 : UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1072 0 : Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1073 :
1074 : // GetError() call cleares error code for OLE storages, must be changed in future
1075 0 : long nTmpErr = pStorage->GetError();
1076 0 : pStorage->SetError( nTmpErr );
1077 :
1078 0 : m_bIsOLEStorage = !nTmpErr;
1079 0 : return static_cast< BaseStorage* > ( pStorage );
1080 : }
1081 :
1082 0 : sal_Int16 UCBStorageStream_Impl::Commit()
1083 : {
1084 : // send stream to the original content
1085 : // the parent storage is responsible for the correct handling of deleted contents
1086 0 : if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1087 : {
1088 : // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1089 : // was commited as well ( if not opened in direct mode )
1090 :
1091 0 : if ( m_bModified )
1092 : {
1093 : try
1094 : {
1095 0 : CopySourceToTemporary();
1096 :
1097 : // release all stream handles
1098 0 : Free();
1099 :
1100 : // the temporary file does not exist only for truncated streams
1101 : DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & STREAM_TRUNC ), "No temporary file to read from!");
1102 0 : if ( m_aTempURL.isEmpty() && !( m_nMode & STREAM_TRUNC ) )
1103 0 : throw RuntimeException();
1104 :
1105 : // create wrapper to stream that is only used while reading inside package component
1106 0 : Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1107 :
1108 0 : Any aAny;
1109 0 : InsertCommandArgument aArg;
1110 0 : aArg.Data = xStream;
1111 0 : aArg.ReplaceExisting = true;
1112 0 : aAny <<= aArg;
1113 0 : m_pContent->executeCommand( OUString("insert"), aAny );
1114 :
1115 : // wrapper now controls lifetime of temporary file
1116 0 : m_aTempURL = "";
1117 :
1118 0 : INetURLObject aObj( m_aURL );
1119 0 : aObj.SetName( m_aName );
1120 0 : m_aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
1121 0 : m_bModified = false;
1122 0 : m_bSourceRead = true;
1123 : }
1124 0 : catch (const CommandAbortedException&)
1125 : {
1126 : // any command wasn't executed successfully - not specified
1127 0 : SetError( ERRCODE_IO_GENERAL );
1128 0 : return COMMIT_RESULT_FAILURE;
1129 : }
1130 0 : catch (const RuntimeException&)
1131 : {
1132 : // any other error - not specified
1133 0 : SetError( ERRCODE_IO_GENERAL );
1134 0 : return COMMIT_RESULT_FAILURE;
1135 : }
1136 0 : catch (const Exception&)
1137 : {
1138 : // any other error - not specified
1139 0 : SetError( ERRCODE_IO_GENERAL );
1140 0 : return COMMIT_RESULT_FAILURE;
1141 : }
1142 :
1143 0 : m_bCommited = false;
1144 0 : return COMMIT_RESULT_SUCCESS;
1145 : }
1146 : }
1147 :
1148 0 : return COMMIT_RESULT_NOTHING_TO_DO;
1149 : }
1150 :
1151 0 : bool UCBStorageStream_Impl::Revert()
1152 : {
1153 : // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1154 0 : if ( m_bCommited )
1155 : {
1156 : OSL_FAIL("Revert while commit is in progress!" );
1157 0 : return false; // ???
1158 : }
1159 :
1160 0 : Free();
1161 0 : if ( !m_aTempURL.isEmpty() )
1162 : {
1163 0 : ::utl::UCBContentHelper::Kill( m_aTempURL );
1164 0 : m_aTempURL = "";
1165 : }
1166 :
1167 0 : m_bSourceRead = false;
1168 : try
1169 : {
1170 0 : m_rSource = m_pContent->openStream();
1171 0 : if( m_rSource.is() )
1172 : {
1173 0 : if ( m_pAntiImpl && ( m_nMode & STREAM_TRUNC ) )
1174 : // stream is in use and should be truncated
1175 0 : m_bSourceRead = false;
1176 : else
1177 : {
1178 0 : m_nMode &= ~STREAM_TRUNC;
1179 0 : m_bSourceRead = true;
1180 : }
1181 : }
1182 : else
1183 0 : SetError( SVSTREAM_CANNOT_MAKE );
1184 : }
1185 0 : catch (const ContentCreationException&)
1186 : {
1187 0 : SetError( ERRCODE_IO_GENERAL );
1188 : }
1189 0 : catch (const RuntimeException&)
1190 : {
1191 0 : SetError( ERRCODE_IO_GENERAL );
1192 : }
1193 0 : catch (const Exception&)
1194 : {
1195 : }
1196 :
1197 0 : m_bModified = false;
1198 0 : m_aName = m_aOriginalName;
1199 0 : m_aContentType = m_aOriginalContentType;
1200 0 : return ( GetError() == ERRCODE_NONE );
1201 : }
1202 :
1203 0 : bool UCBStorageStream_Impl::Clear()
1204 : {
1205 0 : bool bRet = ( m_pAntiImpl == NULL );
1206 : DBG_ASSERT( bRet, "Removing used stream!" );
1207 0 : if( bRet )
1208 : {
1209 0 : Free();
1210 : }
1211 :
1212 0 : return bRet;
1213 : }
1214 :
1215 0 : void UCBStorageStream_Impl::Free()
1216 : {
1217 : #if OSL_DEBUG_LEVEL > 1
1218 : if ( m_pStream )
1219 : {
1220 : if ( !m_aTempURL.isEmpty() )
1221 : --nOpenFiles;
1222 : else
1223 : --nOpenStreams;
1224 : }
1225 : #endif
1226 :
1227 0 : m_nRepresentMode = nonset;
1228 0 : m_rSource.clear();
1229 0 : DELETEZ( m_pStream );
1230 0 : }
1231 :
1232 0 : void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1233 : {
1234 0 : bool isWritable = (( m_nMode & STREAM_WRITE ) != 0 );
1235 0 : if ( isWritable )
1236 : {
1237 : // once stream was writable, never reset to readonly
1238 0 : nMode |= STREAM_WRITE;
1239 : }
1240 :
1241 0 : m_nMode = nMode;
1242 0 : Free();
1243 :
1244 0 : if ( nMode & STREAM_TRUNC )
1245 : {
1246 0 : m_bSourceRead = 0; // usually it should be 0 already but just in case...
1247 :
1248 0 : if ( !m_aTempURL.isEmpty() )
1249 : {
1250 0 : ::utl::UCBContentHelper::Kill( m_aTempURL );
1251 0 : m_aTempURL = "";
1252 : }
1253 : }
1254 0 : }
1255 :
1256 0 : UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, const OString* pKey, bool bRepair, Reference< XProgressHandler > xProgress )
1257 : {
1258 : // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1259 : // to class UCBStorageStream !
1260 0 : pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey, bRepair, xProgress );
1261 0 : pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1262 0 : StorageBase::m_nMode = pImp->m_nMode;
1263 0 : }
1264 :
1265 0 : UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1266 0 : : pImp( pImpl )
1267 : {
1268 0 : pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1269 0 : pImp->m_pAntiImpl = this;
1270 0 : SetError( pImp->m_nError );
1271 0 : StorageBase::m_nMode = pImp->m_nMode;
1272 0 : }
1273 :
1274 0 : UCBStorageStream::~UCBStorageStream()
1275 : {
1276 0 : if ( pImp->m_nMode & STREAM_WRITE )
1277 0 : pImp->Flush();
1278 0 : pImp->m_pAntiImpl = NULL;
1279 0 : pImp->Free();
1280 0 : pImp->ReleaseRef();
1281 0 : }
1282 :
1283 0 : sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
1284 : {
1285 : //return pImp->m_pStream->Read( pData, nSize );
1286 0 : return pImp->GetData( pData, nSize );
1287 : }
1288 :
1289 0 : sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
1290 : {
1291 0 : return pImp->PutData( pData, nSize );
1292 : }
1293 :
1294 0 : sal_uLong UCBStorageStream::Seek( sal_uLong nPos )
1295 : {
1296 : //return pImp->m_pStream->Seek( nPos );
1297 0 : return pImp->Seek( nPos );
1298 : }
1299 :
1300 0 : sal_uLong UCBStorageStream::Tell()
1301 : {
1302 0 : if( !pImp->Init() )
1303 0 : return 0;
1304 0 : return pImp->m_pStream->Tell();
1305 : }
1306 :
1307 0 : void UCBStorageStream::Flush()
1308 : {
1309 : // streams are never really transacted, so flush also means commit !
1310 0 : Commit();
1311 0 : }
1312 :
1313 0 : bool UCBStorageStream::SetSize( sal_uLong nNewSize )
1314 : {
1315 0 : pImp->SetSize( nNewSize );
1316 0 : return !pImp->GetError();
1317 : }
1318 :
1319 0 : bool UCBStorageStream::Validate( bool bWrite ) const
1320 : {
1321 0 : return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
1322 : }
1323 :
1324 0 : bool UCBStorageStream::ValidateMode( StreamMode m ) const
1325 : {
1326 : // ???
1327 0 : if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
1328 0 : return true;
1329 0 : sal_uInt16 nCurMode = 0xFFFF;
1330 0 : if( ( m & 3 ) == STREAM_READ )
1331 : {
1332 : // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1333 0 : if( ( ( m & STREAM_SHARE_DENYWRITE )
1334 0 : && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
1335 0 : || ( ( m & STREAM_SHARE_DENYALL )
1336 0 : && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
1337 0 : return true;
1338 : }
1339 : else
1340 : {
1341 : // only SHARE_DENYALL allowed
1342 : // storages open in r/o mode are OK, since only
1343 : // the commit may fail
1344 0 : if( ( m & STREAM_SHARE_DENYALL )
1345 0 : && ( nCurMode & STREAM_SHARE_DENYALL ) )
1346 0 : return true;
1347 : }
1348 :
1349 0 : return true;
1350 : }
1351 :
1352 0 : const SvStream* UCBStorageStream::GetSvStream() const
1353 : {
1354 0 : if( !pImp->Init() )
1355 0 : return NULL;
1356 :
1357 0 : pImp->CopySourceToTemporary();
1358 0 : return pImp->m_pStream; // should not live longer then pImp!!!
1359 : }
1360 :
1361 0 : SvStream* UCBStorageStream::GetModifySvStream()
1362 : {
1363 0 : return (SvStream*)pImp;
1364 : }
1365 :
1366 0 : bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1367 : {
1368 : // ???
1369 0 : return ((BaseStorageStream*) this ) == &rStream;
1370 : }
1371 :
1372 0 : bool UCBStorageStream::Commit()
1373 : {
1374 : // mark this stream for sending it on root commit
1375 0 : pImp->FlushData();
1376 0 : return true;
1377 : }
1378 :
1379 0 : bool UCBStorageStream::Revert()
1380 : {
1381 0 : return pImp->Revert();
1382 : }
1383 :
1384 0 : bool UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1385 : {
1386 0 : if( !pImp->Init() )
1387 0 : return false;
1388 :
1389 0 : UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
1390 0 : if ( pStg )
1391 0 : pStg->pImp->m_aContentType = pImp->m_aContentType;
1392 :
1393 0 : pDestStm->SetSize( 0 );
1394 0 : Seek( STREAM_SEEK_TO_END );
1395 0 : sal_Int32 n = Tell();
1396 0 : if( n < 0 )
1397 0 : return false;
1398 :
1399 0 : if( pDestStm->SetSize( n ) && n )
1400 : {
1401 0 : sal_uInt8* p = new sal_uInt8[ 4096 ];
1402 0 : Seek( 0L );
1403 0 : pDestStm->Seek( 0L );
1404 0 : while( n )
1405 : {
1406 0 : sal_uInt32 nn = n;
1407 0 : if( nn > 4096 )
1408 0 : nn = 4096;
1409 0 : if( Read( p, nn ) != nn )
1410 0 : break;
1411 0 : if( pDestStm->Write( p, nn ) != nn )
1412 0 : break;
1413 0 : n -= nn;
1414 : }
1415 :
1416 0 : delete[] p;
1417 : }
1418 :
1419 0 : return true;
1420 : }
1421 :
1422 0 : bool UCBStorageStream::SetProperty( const OUString& rName, const ::com::sun::star::uno::Any& rValue )
1423 : {
1424 0 : if ( rName == "Title")
1425 0 : return false;
1426 :
1427 0 : if ( rName == "MediaType")
1428 : {
1429 0 : OUString aTmp;
1430 0 : rValue >>= aTmp;
1431 0 : pImp->m_aContentType = aTmp;
1432 : }
1433 :
1434 : try
1435 : {
1436 0 : if ( pImp->m_pContent )
1437 : {
1438 0 : pImp->m_pContent->setPropertyValue( rName, rValue );
1439 0 : return true;
1440 : }
1441 : }
1442 0 : catch (const Exception&)
1443 : {
1444 : }
1445 :
1446 0 : return false;
1447 : }
1448 :
1449 0 : sal_uLong UCBStorageStream::GetSize() const
1450 : {
1451 0 : return pImp->GetSize();
1452 : }
1453 :
1454 0 : UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1455 : {
1456 0 : OUString aURL = GetLinkedFile( rStrm );
1457 0 : if ( !aURL.isEmpty() )
1458 : {
1459 0 : StreamMode nMode = STREAM_READ;
1460 0 : if( rStrm.IsWritable() )
1461 0 : nMode = STREAM_READ | STREAM_WRITE;
1462 :
1463 0 : ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
1464 0 : pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, true );
1465 : }
1466 : else
1467 : {
1468 : // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1469 : // to class UCBStorage !
1470 0 : pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1471 : }
1472 :
1473 0 : pImp->AddRef();
1474 0 : pImp->Init();
1475 0 : StorageBase::m_nMode = pImp->m_nMode;
1476 0 : }
1477 :
1478 0 : UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1479 : {
1480 : // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1481 : // to class UCBStorage !
1482 0 : pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1483 0 : pImp->AddRef();
1484 0 : pImp->Init();
1485 0 : StorageBase::m_nMode = pImp->m_nMode;
1486 0 : }
1487 :
1488 0 : UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
1489 : {
1490 : // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1491 : // to class UCBStorage !
1492 0 : pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1493 0 : pImp->AddRef();
1494 0 : pImp->Init();
1495 0 : StorageBase::m_nMode = pImp->m_nMode;
1496 0 : }
1497 :
1498 401 : UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1499 : {
1500 : // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1501 : // to class UCBStorage !
1502 401 : pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1503 401 : pImp->AddRef();
1504 401 : pImp->Init();
1505 401 : StorageBase::m_nMode = pImp->m_nMode;
1506 401 : }
1507 :
1508 0 : UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1509 0 : : pImp( pImpl )
1510 : {
1511 0 : pImp->m_pAntiImpl = this;
1512 0 : SetError( pImp->m_nError );
1513 0 : pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1514 0 : StorageBase::m_nMode = pImp->m_nMode;
1515 0 : }
1516 :
1517 1203 : UCBStorage::~UCBStorage()
1518 : {
1519 401 : if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1520 : // DirectMode is simulated with an AutoCommit
1521 0 : Commit();
1522 :
1523 401 : pImp->m_pAntiImpl = NULL;
1524 401 : pImp->ReleaseRef();
1525 802 : }
1526 :
1527 0 : UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
1528 : : m_pAntiImpl( pStorage )
1529 0 : , m_pContent( new ::ucbhelper::Content( rContent ) )
1530 : , m_pTempFile( NULL )
1531 : , m_pSource( NULL )
1532 : //, m_pStream( NULL )
1533 : , m_nError( 0 )
1534 : , m_nMode( nMode )
1535 : , m_bModified( false )
1536 : , m_bCommited( false )
1537 : , m_bDirect( bDirect )
1538 : , m_bIsRoot( bIsRoot )
1539 : , m_bDirty( false )
1540 : , m_bIsLinked( true )
1541 : , m_bListCreated( false )
1542 : , m_nFormat( 0 )
1543 : , m_aClassId( SvGlobalName() )
1544 : , m_bRepairPackage( bIsRepair )
1545 0 : , m_xProgressHandler( xProgressHandler )
1546 : {
1547 0 : OUString aName( rName );
1548 0 : if( aName.isEmpty() )
1549 : {
1550 : // no name given = use temporary name!
1551 : DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1552 0 : m_pTempFile = new ::utl::TempFile;
1553 0 : m_pTempFile->EnableKillingFile( true );
1554 0 : m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1555 : }
1556 :
1557 0 : m_aURL = rName;
1558 0 : }
1559 :
1560 401 : UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
1561 : : m_pAntiImpl( pStorage )
1562 : , m_pContent( NULL )
1563 : , m_pTempFile( NULL )
1564 : , m_pSource( NULL )
1565 : //, m_pStream( NULL )
1566 : , m_nError( 0 )
1567 : , m_nMode( nMode )
1568 : , m_bModified( false )
1569 : , m_bCommited( false )
1570 : , m_bDirect( bDirect )
1571 : , m_bIsRoot( bIsRoot )
1572 : , m_bDirty( false )
1573 : , m_bIsLinked( false )
1574 : , m_bListCreated( false )
1575 : , m_nFormat( 0 )
1576 : , m_aClassId( SvGlobalName() )
1577 : , m_bRepairPackage( bIsRepair )
1578 401 : , m_xProgressHandler( xProgressHandler )
1579 : {
1580 401 : OUString aName( rName );
1581 401 : if( aName.isEmpty() )
1582 : {
1583 : // no name given = use temporary name!
1584 : DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1585 401 : m_pTempFile = new ::utl::TempFile;
1586 401 : m_pTempFile->EnableKillingFile( true );
1587 401 : m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1588 : }
1589 :
1590 401 : if ( m_bIsRoot )
1591 : {
1592 : // create the special package URL for the package content
1593 401 : OUString aTemp = OUString("vnd.sun.star.pkg://");
1594 401 : aTemp += OUString(INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1595 401 : m_aURL = aTemp;
1596 :
1597 401 : if ( m_nMode & STREAM_WRITE )
1598 : {
1599 : // the root storage opens the package, so make sure that there is any
1600 401 : SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READWRITE, m_pTempFile != 0 /* bFileExists */ );
1601 401 : delete pStream;
1602 401 : }
1603 : }
1604 : else
1605 : {
1606 : // substorages are opened like streams: the URL is a "child URL" of the root package URL
1607 0 : m_aURL = rName;
1608 0 : if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1609 0 : m_bIsLinked = true;
1610 401 : }
1611 401 : }
1612 :
1613 0 : UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1614 : : m_pAntiImpl( pStorage )
1615 : , m_pContent( NULL )
1616 0 : , m_pTempFile( new ::utl::TempFile )
1617 : , m_pSource( &rStream )
1618 : , m_nError( 0 )
1619 : , m_bModified( false )
1620 : , m_bCommited( false )
1621 : , m_bDirect( bDirect )
1622 : , m_bIsRoot( true )
1623 : , m_bDirty( false )
1624 : , m_bIsLinked( false )
1625 : , m_bListCreated( false )
1626 : , m_nFormat( 0 )
1627 : , m_aClassId( SvGlobalName() )
1628 0 : , m_bRepairPackage( false )
1629 : {
1630 : // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1631 : // which will be called in the storages' dtor
1632 0 : m_pTempFile->EnableKillingFile( true );
1633 : DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1634 :
1635 : // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1636 : // accessed readonly
1637 : // the root storage opens the package; create the special package URL for the package content
1638 0 : OUString aTemp = OUString("vnd.sun.star.pkg://");
1639 0 : aTemp += OUString(INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1640 0 : m_aURL = aTemp;
1641 :
1642 : // copy data into the temporary file
1643 0 : SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, true /* bFileExists */ );
1644 0 : if ( pStream )
1645 : {
1646 0 : rStream.Seek(0);
1647 0 : rStream >> *pStream;
1648 0 : pStream->Flush();
1649 0 : DELETEZ( pStream );
1650 : }
1651 :
1652 : // close stream and let content access the file
1653 0 : m_pSource->Seek(0);
1654 :
1655 : // check opening mode
1656 0 : m_nMode = STREAM_READ;
1657 0 : if( rStream.IsWritable() )
1658 0 : m_nMode = STREAM_READ | STREAM_WRITE;
1659 0 : }
1660 :
1661 401 : void UCBStorage_Impl::Init()
1662 : {
1663 : // name is last segment in URL
1664 401 : INetURLObject aObj( m_aURL );
1665 401 : if ( m_aName.isEmpty() )
1666 : // if the name was not already set to a temp name
1667 0 : m_aName = m_aOriginalName = aObj.GetLastName();
1668 :
1669 : // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
1670 401 : if ( !m_pContent && !( m_nMode & STORAGE_DISKSPANNED_MODE ) )
1671 401 : CreateContent();
1672 :
1673 401 : if ( m_nMode & STORAGE_DISKSPANNED_MODE )
1674 : {
1675 : // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
1676 : // disk spanned file
1677 0 : m_aContentType = m_aOriginalContentType = OUString( "application/vnd.sun.xml.impress" );
1678 : }
1679 401 : else if ( m_pContent )
1680 : {
1681 14 : if ( m_bIsLinked )
1682 : {
1683 0 : if( m_bIsRoot )
1684 : {
1685 0 : ReadContent();
1686 0 : if ( m_nError == ERRCODE_NONE )
1687 : {
1688 : // read the manifest.xml file
1689 0 : aObj.Append( OUString( "META-INF" ) );
1690 0 : aObj.Append( OUString( "manifest.xml" ) );
1691 :
1692 : // create input stream
1693 0 : SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
1694 : // no stream means no manifest.xml
1695 0 : if ( pStream )
1696 : {
1697 0 : if ( !pStream->GetError() )
1698 : {
1699 0 : ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1700 0 : com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xInputStream( pHelper );
1701 :
1702 : // create a manifest reader object that will read in the manifest from the stream
1703 : Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader =
1704 : ::com::sun::star::packages::manifest::ManifestReader::create(
1705 0 : ::comphelper::getProcessComponentContext() ) ;
1706 0 : Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1707 :
1708 : // cleanup
1709 0 : xReader = NULL;
1710 0 : xInputStream = NULL;
1711 0 : SetProps( aProps, OUString() );
1712 : }
1713 :
1714 0 : delete pStream;
1715 : }
1716 : }
1717 : }
1718 : else
1719 0 : ReadContent();
1720 : }
1721 : else
1722 : {
1723 : // get the manifest information from the package
1724 : try {
1725 14 : Any aAny = m_pContent->getPropertyValue("MediaType");
1726 28 : OUString aTmp;
1727 14 : if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1728 14 : m_aContentType = m_aOriginalContentType = aTmp;
1729 : }
1730 0 : catch (const Exception&)
1731 : {
1732 : DBG_ASSERT( false,
1733 : "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1734 : }
1735 : }
1736 : }
1737 :
1738 401 : if ( !m_aContentType.isEmpty() )
1739 : {
1740 : // get the clipboard format using the content type
1741 0 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
1742 0 : aDataFlavor.MimeType = m_aContentType;
1743 0 : m_nFormat = SotExchange::GetFormat( aDataFlavor );
1744 :
1745 : // get the ClassId using the clipboard format ( internal table )
1746 0 : m_aClassId = GetClassId_Impl( m_nFormat );
1747 :
1748 : // get human presentable name using the clipboard format
1749 0 : SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1750 0 : m_aUserTypeName = aDataFlavor.HumanPresentableName;
1751 :
1752 0 : if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1753 0 : ReadContent();
1754 401 : }
1755 401 : }
1756 :
1757 788 : void UCBStorage_Impl::CreateContent()
1758 : {
1759 : try
1760 : {
1761 : // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1762 788 : Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1763 :
1764 1576 : OUString aTemp( m_aURL );
1765 :
1766 788 : if ( m_bRepairPackage )
1767 : {
1768 0 : xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
1769 0 : m_xProgressHandler );
1770 0 : aTemp += OUString("?repairpackage");
1771 : }
1772 :
1773 2350 : m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
1774 : }
1775 1548 : catch (const ContentCreationException&)
1776 : {
1777 : // content could not be created
1778 774 : SetError( SVSTREAM_CANNOT_MAKE );
1779 : }
1780 0 : catch (const RuntimeException&)
1781 : {
1782 : // any other error - not specified
1783 0 : SetError( SVSTREAM_CANNOT_MAKE );
1784 : }
1785 788 : }
1786 :
1787 802 : void UCBStorage_Impl::ReadContent()
1788 : {
1789 802 : if ( m_bListCreated )
1790 1189 : return;
1791 :
1792 401 : m_bListCreated = true;
1793 :
1794 : // create cursor for access to children
1795 401 : Sequence< OUString > aProps(4);
1796 401 : OUString* pProps = aProps.getArray();
1797 401 : pProps[0] = OUString("Title");
1798 401 : pProps[1] = OUString("IsFolder");
1799 401 : pProps[2] = OUString("MediaType");
1800 401 : pProps[3] = OUString("Size");
1801 401 : ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS;
1802 :
1803 : try
1804 : {
1805 401 : GetContent();
1806 401 : if ( !m_pContent )
1807 387 : return;
1808 :
1809 14 : Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude );
1810 28 : Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
1811 28 : Reference< XRow > xRow( xResultSet, UNO_QUERY );
1812 14 : if ( xResultSet.is() )
1813 : {
1814 28 : while ( xResultSet->next() )
1815 : {
1816 : // insert all into the children list
1817 0 : OUString aTitle( xRow->getString(1) );
1818 0 : OUString aContentType;
1819 0 : if ( m_bIsLinked )
1820 : {
1821 : // unpacked storages have to deal with the meta-inf folder by themselves
1822 0 : if ( aTitle == "META-INF" )
1823 0 : continue;
1824 : }
1825 : else
1826 : {
1827 0 : aContentType = xRow->getString(3);
1828 : }
1829 :
1830 0 : bool bIsFolder( xRow->getBoolean(2) );
1831 0 : sal_Int64 nSize = xRow->getLong(4);
1832 0 : UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (sal_uLong) nSize );
1833 0 : m_aChildrenList.push_back( pElement );
1834 :
1835 0 : bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1836 0 : if ( bIsFolder )
1837 : {
1838 0 : if ( m_bIsLinked )
1839 0 : OpenStorage( pElement, m_nMode, m_bDirect );
1840 0 : if ( pElement->m_xStorage.Is() )
1841 0 : pElement->m_xStorage->Init();
1842 : }
1843 0 : else if ( bIsOfficeDocument )
1844 : {
1845 : // streams can be external OLE objects, so they are now folders, but storages!
1846 0 : OUString aName( m_aURL + OUString("/") + xRow->getString(1));
1847 :
1848 0 : Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1849 0 : if ( m_bRepairPackage )
1850 : {
1851 0 : xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
1852 0 : m_xProgressHandler );
1853 0 : aName += "?repairpackage";
1854 : }
1855 :
1856 0 : ::ucbhelper::Content aContent( aName, xComEnv, comphelper::getProcessComponentContext() );
1857 :
1858 0 : OUString aMediaType;
1859 0 : Any aAny = aContent.getPropertyValue("MediaType");
1860 0 : if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1861 0 : pElement->m_bIsStorage = true;
1862 0 : else if ( aMediaType.isEmpty() )
1863 : {
1864 : // older files didn't have that special content type, so they must be detected
1865 0 : OpenStream( pElement, STREAM_STD_READ, m_bDirect );
1866 0 : if ( Storage::IsStorageFile( pElement->m_xStream ) )
1867 0 : pElement->m_bIsStorage = true;
1868 : else
1869 0 : pElement->m_xStream->Free();
1870 0 : }
1871 : }
1872 0 : }
1873 14 : }
1874 : }
1875 0 : catch (const InteractiveIOException& r)
1876 : {
1877 0 : if ( r.Code != IOErrorCode_NOT_EXISTING )
1878 0 : SetError( ERRCODE_IO_GENERAL );
1879 : }
1880 0 : catch (const CommandAbortedException&)
1881 : {
1882 : // any command wasn't executed successfully - not specified
1883 0 : if ( !( m_nMode & STREAM_WRITE ) )
1884 : // if the folder was just inserted and not already commited, this is not an error!
1885 0 : SetError( ERRCODE_IO_GENERAL );
1886 : }
1887 0 : catch (const RuntimeException&)
1888 : {
1889 : // any other error - not specified
1890 0 : SetError( ERRCODE_IO_GENERAL );
1891 : }
1892 0 : catch (const ResultSetException&)
1893 : {
1894 : // means that the package file is broken
1895 0 : SetError( ERRCODE_IO_BROKENPACKAGE );
1896 : }
1897 0 : catch (const SQLException&)
1898 : {
1899 : // means that the file can be broken
1900 0 : SetError( ERRCODE_IO_WRONGFORMAT );
1901 : }
1902 0 : catch (const Exception&)
1903 : {
1904 : // any other error - not specified
1905 0 : SetError( ERRCODE_IO_GENERAL );
1906 14 : }
1907 : }
1908 :
1909 774 : void UCBStorage_Impl::SetError( long nError )
1910 : {
1911 774 : if ( !m_nError )
1912 : {
1913 387 : m_nError = nError;
1914 387 : if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1915 : }
1916 774 : }
1917 :
1918 0 : sal_Int32 UCBStorage_Impl::GetObjectCount()
1919 : {
1920 0 : sal_Int32 nCount = m_aChildrenList.size();
1921 0 : for ( size_t i = 0; i < m_aChildrenList.size(); ++i )
1922 : {
1923 0 : UCBStorageElement_Impl* pElement = m_aChildrenList[ i ];
1924 : DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
1925 0 : if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
1926 0 : nCount += pElement->m_xStorage->GetObjectCount();
1927 : }
1928 :
1929 0 : return nCount;
1930 : }
1931 :
1932 0 : OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1933 : {
1934 0 : bool bFound = false;
1935 0 : for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
1936 : {
1937 0 : const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
1938 0 : OUString aType;
1939 :
1940 0 : for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
1941 : {
1942 0 : const PropertyValue& rAny = rMyProps[nProps];
1943 0 : if ( rAny.Name == "FullPath" )
1944 : {
1945 0 : OUString aTmp;
1946 0 : if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1947 0 : bFound = true;
1948 0 : if ( !aType.isEmpty() )
1949 0 : break;
1950 : }
1951 0 : else if ( rAny.Name == "MediaType" )
1952 : {
1953 0 : if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1954 0 : break;
1955 : }
1956 : }
1957 :
1958 0 : if ( bFound )
1959 0 : return aType;
1960 0 : }
1961 :
1962 0 : return OUString();
1963 : }
1964 :
1965 0 : void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1966 : {
1967 0 : OUString aPath( rPath );
1968 0 : if ( !m_bIsRoot )
1969 0 : aPath += m_aName;
1970 0 : aPath += "/";
1971 :
1972 0 : m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1973 :
1974 0 : if ( m_bIsRoot )
1975 : // the "FullPath" of a child always starts without '/'
1976 0 : aPath = "";
1977 :
1978 0 : for ( size_t i = 0; i < m_aChildrenList.size(); ++i )
1979 : {
1980 0 : UCBStorageElement_Impl* pElement = m_aChildrenList[ i ];
1981 : DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
1982 0 : if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
1983 0 : pElement->m_xStorage->SetProps( rSequence, aPath );
1984 : else
1985 : {
1986 0 : OUString aElementPath( aPath );
1987 0 : aElementPath += pElement->m_aName;
1988 0 : pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1989 : }
1990 : }
1991 :
1992 0 : if ( !m_aContentType.isEmpty() )
1993 : {
1994 : // get the clipboard format using the content type
1995 0 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
1996 0 : aDataFlavor.MimeType = m_aContentType;
1997 0 : m_nFormat = SotExchange::GetFormat( aDataFlavor );
1998 :
1999 : // get the ClassId using the clipboard format ( internal table )
2000 0 : m_aClassId = GetClassId_Impl( m_nFormat );
2001 :
2002 : // get human presentable name using the clipboard format
2003 0 : SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
2004 0 : m_aUserTypeName = aDataFlavor.HumanPresentableName;
2005 0 : }
2006 0 : }
2007 :
2008 0 : void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
2009 : {
2010 : // first my own properties
2011 0 : Sequence < PropertyValue > aProps(2);
2012 :
2013 : // first property is the "FullPath" name
2014 : // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2015 0 : OUString aPath( rPath );
2016 0 : if ( !m_bIsRoot )
2017 0 : aPath += m_aName;
2018 0 : aPath += "/";
2019 0 : aProps[0].Name = OUString("MediaType");
2020 0 : aProps[0].Value <<= (OUString ) m_aContentType;
2021 0 : aProps[1].Name = OUString("FullPath");
2022 0 : aProps[1].Value <<= (OUString ) aPath;
2023 0 : rSequence[ nProps++ ] = aProps;
2024 :
2025 0 : if ( m_bIsRoot )
2026 : // the "FullPath" of a child always starts without '/'
2027 0 : aPath = "";
2028 :
2029 : // now the properties of my elements
2030 0 : for ( size_t i = 0; i < m_aChildrenList.size(); ++i )
2031 : {
2032 0 : UCBStorageElement_Impl* pElement = m_aChildrenList[ i ];
2033 : DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2034 0 : if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2035 : // storages add there properties by themselves ( see above )
2036 0 : pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
2037 : else
2038 : {
2039 : // properties of streams
2040 0 : OUString aElementPath( aPath );
2041 0 : aElementPath += pElement->m_aName;
2042 0 : aProps[0].Name = OUString("MediaType");
2043 0 : aProps[0].Value <<= (OUString ) pElement->GetContentType();
2044 0 : aProps[1].Name = OUString("FullPath");
2045 0 : aProps[1].Value <<= (OUString ) aElementPath;
2046 0 : rSequence[ nProps++ ] = aProps;
2047 : }
2048 0 : }
2049 0 : }
2050 :
2051 1203 : UCBStorage_Impl::~UCBStorage_Impl()
2052 : {
2053 : // first delete elements!
2054 401 : for ( size_t i = 0, n = m_aChildrenList.size(); i < n; ++i )
2055 0 : delete m_aChildrenList[ i ];
2056 401 : m_aChildrenList.clear();
2057 :
2058 401 : delete m_pContent;
2059 401 : delete m_pTempFile;
2060 802 : }
2061 :
2062 0 : bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
2063 : {
2064 : // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2065 : // it must be inserted with a title and a type
2066 0 : bool bRet = false;
2067 :
2068 : try
2069 : {
2070 0 : Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
2071 0 : sal_Int32 nCount = aInfo.getLength();
2072 0 : if ( nCount == 0 )
2073 0 : return false;
2074 :
2075 0 : for ( sal_Int32 i = 0; i < nCount; ++i )
2076 : {
2077 : // Simply look for the first KIND_FOLDER...
2078 0 : const ContentInfo & rCurr = aInfo[i];
2079 0 : if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
2080 : {
2081 : // Make sure the only required bootstrap property is "Title",
2082 0 : const Sequence< Property > & rProps = rCurr.Properties;
2083 0 : if ( rProps.getLength() != 1 )
2084 0 : continue;
2085 :
2086 0 : if ( rProps[ 0 ].Name != "Title" )
2087 0 : continue;
2088 :
2089 0 : Sequence < OUString > aNames(1);
2090 0 : OUString* pNames = aNames.getArray();
2091 0 : pNames[0] = OUString( "Title" );
2092 0 : Sequence < Any > aValues(1);
2093 0 : Any* pValues = aValues.getArray();
2094 0 : pValues[0] = makeAny( OUString( m_aName ) );
2095 :
2096 0 : Content aNewFolder;
2097 0 : if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
2098 0 : continue;
2099 :
2100 : // remove old content, create an "empty" new one and initialize it with the new inserted
2101 0 : DELETEZ( m_pContent );
2102 0 : m_pContent = new ::ucbhelper::Content( aNewFolder );
2103 0 : bRet = true;
2104 : }
2105 0 : }
2106 : }
2107 0 : catch (const CommandAbortedException&)
2108 : {
2109 : // any command wasn't executed successfully - not specified
2110 0 : SetError( ERRCODE_IO_GENERAL );
2111 : }
2112 0 : catch (const RuntimeException&)
2113 : {
2114 : // any other error - not specified
2115 0 : SetError( ERRCODE_IO_GENERAL );
2116 : }
2117 0 : catch (const Exception&)
2118 : {
2119 : // any other error - not specified
2120 0 : SetError( ERRCODE_IO_GENERAL );
2121 : }
2122 :
2123 0 : return bRet;
2124 : }
2125 :
2126 0 : sal_Int16 UCBStorage_Impl::Commit()
2127 : {
2128 : // send all changes to the package
2129 0 : sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
2130 :
2131 : // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2132 : // commit command has been sent
2133 0 : if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) )
2134 : {
2135 : try
2136 : {
2137 : // all errors will be caught in the "catch" statement outside the loop
2138 0 : for ( size_t i = 0; i < m_aChildrenList.size() && nRet; ++i )
2139 : {
2140 0 : UCBStorageElement_Impl* pElement = m_aChildrenList[ i ];
2141 0 : ::ucbhelper::Content* pContent = pElement->GetContent();
2142 0 : bool bDeleteContent = false;
2143 0 : if ( !pContent && pElement->IsModified() )
2144 : {
2145 : // if the element has never been opened, no content has been created until now
2146 0 : bDeleteContent = true; // remember to delete it later
2147 0 : OUString aName( m_aURL );
2148 0 : aName += "/";
2149 0 : aName += pElement->m_aOriginalName;
2150 0 : pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2151 : }
2152 :
2153 0 : if ( pElement->m_bIsRemoved )
2154 : {
2155 : // was it inserted, then removed (so there would be nothing to do!)
2156 0 : if ( !pElement->m_bIsInserted )
2157 : {
2158 : // first remove all open stream handles
2159 0 : if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() )
2160 : {
2161 0 : pContent->executeCommand( OUString("delete"), makeAny( sal_Bool( sal_True ) ) );
2162 0 : nRet = COMMIT_RESULT_SUCCESS;
2163 : }
2164 : else
2165 : // couldn't release stream because there are external references to it
2166 0 : nRet = COMMIT_RESULT_FAILURE;
2167 : }
2168 : }
2169 : else
2170 : {
2171 0 : sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2172 0 : if ( pElement->m_xStorage.Is() )
2173 : {
2174 : // element is a storage
2175 : // do a commit in the following cases:
2176 : // - if storage is already inserted, and changed
2177 : // - storage is not in a package
2178 : // - it's a new storage, try to insert and commit if successful inserted
2179 0 : if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
2180 : {
2181 0 : nLocalRet = pElement->m_xStorage->Commit();
2182 0 : pContent = pElement->GetContent();
2183 : }
2184 : }
2185 0 : else if ( pElement->m_xStream.Is() )
2186 : {
2187 : // element is a stream
2188 0 : nLocalRet = pElement->m_xStream->Commit();
2189 0 : if ( pElement->m_xStream->m_bIsOLEStorage )
2190 : {
2191 : // OLE storage should be stored encrytped, if the storage uses encryption
2192 0 : pElement->m_xStream->m_aContentType = OUString("application/vnd.sun.star.oleobject");
2193 0 : Any aValue;
2194 0 : aValue <<= (sal_Bool)sal_True;
2195 0 : pElement->m_xStream->m_pContent->setPropertyValue("Encrypted", aValue );
2196 : }
2197 :
2198 0 : pContent = pElement->GetContent();
2199 : }
2200 :
2201 0 : if ( pElement->m_aName != pElement->m_aOriginalName )
2202 : {
2203 : // name ( title ) of the element was changed
2204 0 : nLocalRet = COMMIT_RESULT_SUCCESS;
2205 0 : Any aAny;
2206 0 : aAny <<= (OUString) pElement->m_aName;
2207 0 : pContent->setPropertyValue("Title", aAny );
2208 : }
2209 :
2210 0 : if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() )
2211 : {
2212 : // mediatype of the element was changed
2213 0 : nLocalRet = COMMIT_RESULT_SUCCESS;
2214 0 : Any aAny;
2215 0 : aAny <<= (OUString) pElement->GetContentType();
2216 0 : pContent->setPropertyValue("MediaType", aAny );
2217 : }
2218 :
2219 0 : if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2220 0 : nRet = nLocalRet;
2221 : }
2222 :
2223 0 : if ( bDeleteContent )
2224 : // content was created inside the loop
2225 0 : delete pContent;
2226 :
2227 0 : if ( nRet == COMMIT_RESULT_FAILURE )
2228 0 : break;
2229 : }
2230 : }
2231 0 : catch (const ContentCreationException&)
2232 : {
2233 : // content could not be created
2234 0 : SetError( ERRCODE_IO_NOTEXISTS );
2235 0 : return COMMIT_RESULT_FAILURE;
2236 : }
2237 0 : catch (const CommandAbortedException&)
2238 : {
2239 : // any command wasn't executed successfully - not specified
2240 0 : SetError( ERRCODE_IO_GENERAL );
2241 0 : return COMMIT_RESULT_FAILURE;
2242 : }
2243 0 : catch (const RuntimeException&)
2244 : {
2245 : // any other error - not specified
2246 0 : SetError( ERRCODE_IO_GENERAL );
2247 0 : return COMMIT_RESULT_FAILURE;
2248 : }
2249 0 : catch (const Exception&)
2250 : {
2251 : // any other error - not specified
2252 0 : SetError( ERRCODE_IO_GENERAL );
2253 0 : return COMMIT_RESULT_FAILURE;
2254 : }
2255 :
2256 0 : if ( m_bIsRoot && m_pContent )
2257 : {
2258 : // the root storage must flush the root package content
2259 0 : if ( nRet == COMMIT_RESULT_SUCCESS )
2260 : {
2261 : try
2262 : {
2263 : // commit the media type to the JAR file
2264 : // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2265 0 : Any aType;
2266 0 : aType <<= (OUString) m_aContentType;
2267 0 : m_pContent->setPropertyValue("MediaType", aType );
2268 :
2269 0 : if ( m_bIsLinked )
2270 : {
2271 : // write a manifest file
2272 : // first create a subfolder "META-inf"
2273 0 : Content aNewSubFolder;
2274 0 : bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, OUString("META-INF"), aNewSubFolder );
2275 0 : if ( bRet )
2276 : {
2277 : // create a stream to write the manifest file - use a temp file
2278 0 : OUString aURL( aNewSubFolder.getURL() );
2279 0 : ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL );
2280 :
2281 : // get the stream from the temp file and create an output stream wrapper
2282 0 : SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE );
2283 0 : ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2284 0 : com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper );
2285 :
2286 : // create a manifest writer object that will fill the stream
2287 : Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter =
2288 : ::com::sun::star::packages::manifest::ManifestWriter::create(
2289 0 : ::comphelper::getProcessComponentContext() );
2290 0 : sal_Int32 nCount = GetObjectCount() + 1;
2291 0 : Sequence < Sequence < PropertyValue > > aProps( nCount );
2292 0 : sal_Int32 nProps = 0;
2293 0 : GetProps( nProps, aProps, OUString() );
2294 0 : xWriter->writeManifestSequence( xOutputStream, aProps );
2295 :
2296 : // move the stream to its desired location
2297 0 : Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2298 0 : xWriter = NULL;
2299 0 : xOutputStream = NULL;
2300 0 : DELETEZ( pTempFile );
2301 0 : aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, OUString("manifest.xml"), NameClash::OVERWRITE );
2302 0 : }
2303 : }
2304 : else
2305 : {
2306 : #if OSL_DEBUG_LEVEL > 1
2307 : fprintf ( stderr, "Files: %i\n", nOpenFiles );
2308 : fprintf ( stderr, "Streams: %i\n", nOpenStreams );
2309 : #endif
2310 : // force writing
2311 0 : Any aAny;
2312 0 : m_pContent->executeCommand( OUString("flush"), aAny );
2313 0 : if ( m_pSource != 0 )
2314 : {
2315 0 : SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ );
2316 0 : m_pSource->SetStreamSize(0);
2317 : // m_pSource->Seek(0);
2318 0 : *pStream >> *m_pSource;
2319 0 : DELETEZ( pStream );
2320 0 : m_pSource->Seek(0);
2321 0 : }
2322 0 : }
2323 : }
2324 0 : catch (const CommandAbortedException&)
2325 : {
2326 : // how to tell the content : forget all changes ?!
2327 : // or should we assume that the content does it by itself because he throwed an exception ?!
2328 : // any command wasn't executed successfully - not specified
2329 0 : SetError( ERRCODE_IO_GENERAL );
2330 0 : return COMMIT_RESULT_FAILURE;
2331 : }
2332 0 : catch (const RuntimeException&)
2333 : {
2334 : // how to tell the content : forget all changes ?!
2335 : // or should we assume that the content does it by itself because he throwed an exception ?!
2336 : // any other error - not specified
2337 0 : SetError( ERRCODE_IO_GENERAL );
2338 0 : return COMMIT_RESULT_FAILURE;
2339 : }
2340 0 : catch (const InteractiveIOException& r)
2341 : {
2342 0 : if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2343 0 : SetError( ERRCODE_IO_ACCESSDENIED );
2344 0 : else if ( r.Code == IOErrorCode_NOT_EXISTING )
2345 0 : SetError( ERRCODE_IO_NOTEXISTS );
2346 0 : else if ( r.Code == IOErrorCode_CANT_READ )
2347 0 : SetError( ERRCODE_IO_CANTREAD );
2348 0 : else if ( r.Code == IOErrorCode_CANT_WRITE )
2349 0 : SetError( ERRCODE_IO_CANTWRITE );
2350 : else
2351 0 : SetError( ERRCODE_IO_GENERAL );
2352 :
2353 0 : return COMMIT_RESULT_FAILURE;
2354 : }
2355 0 : catch (const Exception&)
2356 : {
2357 : // how to tell the content : forget all changes ?!
2358 : // or should we assume that the content does it by itself because he throwed an exception ?!
2359 : // any other error - not specified
2360 0 : SetError( ERRCODE_IO_GENERAL );
2361 0 : return COMMIT_RESULT_FAILURE;
2362 : }
2363 : }
2364 0 : else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2365 : {
2366 : // how to tell the content : forget all changes ?! Should we ?!
2367 0 : SetError( ERRCODE_IO_GENERAL );
2368 0 : return nRet;
2369 : }
2370 :
2371 : // after successful root commit all elements names and types are adjusted and all removed elements
2372 : // are also removed from the lists
2373 0 : for ( size_t i = 0; i < m_aChildrenList.size(); )
2374 : {
2375 0 : UCBStorageElement_Impl* pInnerElement = m_aChildrenList[ i ];
2376 0 : if ( pInnerElement->m_bIsRemoved )
2377 : {
2378 0 : UCBStorageElementList_Impl::iterator it = m_aChildrenList.begin();
2379 0 : ::std::advance( it, i );
2380 0 : delete *it;
2381 0 : m_aChildrenList.erase( it );
2382 : }
2383 : else
2384 : {
2385 0 : pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2386 0 : pInnerElement->m_bIsInserted = false;
2387 0 : ++i;
2388 : }
2389 : }
2390 : }
2391 :
2392 0 : m_bCommited = false;
2393 : }
2394 :
2395 0 : return nRet;
2396 : }
2397 :
2398 0 : bool UCBStorage_Impl::Revert()
2399 : {
2400 0 : for ( size_t i = 0; i < m_aChildrenList.size(); )
2401 : {
2402 0 : UCBStorageElement_Impl* pElement = m_aChildrenList[ i ];
2403 0 : pElement->m_bIsRemoved = false;
2404 0 : if ( pElement->m_bIsInserted )
2405 : {
2406 0 : UCBStorageElementList_Impl::iterator it = m_aChildrenList.begin();
2407 0 : ::std::advance( it, i );
2408 0 : delete *it;
2409 0 : m_aChildrenList.erase( it );
2410 : }
2411 : else
2412 : {
2413 0 : if ( pElement->m_xStream.Is() )
2414 : {
2415 0 : pElement->m_xStream->m_bCommited = false;
2416 0 : pElement->m_xStream->Revert();
2417 : }
2418 0 : else if ( pElement->m_xStorage.Is() )
2419 : {
2420 0 : pElement->m_xStorage->m_bCommited = false;
2421 0 : pElement->m_xStorage->Revert();
2422 : }
2423 :
2424 0 : pElement->m_aName = pElement->m_aOriginalName;
2425 0 : pElement->m_bIsRemoved = false;
2426 0 : ++i;
2427 : }
2428 : }
2429 0 : return true;
2430 : }
2431 :
2432 401 : const OUString& UCBStorage::GetName() const
2433 : {
2434 401 : return pImp->m_aName; // pImp->m_aURL ?!
2435 : }
2436 :
2437 401 : bool UCBStorage::IsRoot() const
2438 : {
2439 401 : return pImp->m_bIsRoot;
2440 : }
2441 :
2442 0 : void UCBStorage::SetDirty()
2443 : {
2444 0 : pImp->m_bDirty = true;
2445 0 : }
2446 :
2447 0 : void UCBStorage::SetClass( const SvGlobalName & rClass, sal_uLong nOriginalClipFormat, const OUString & rUserTypeName )
2448 : {
2449 0 : pImp->m_aClassId = rClass;
2450 0 : pImp->m_nFormat = nOriginalClipFormat;
2451 0 : pImp->m_aUserTypeName = rUserTypeName;
2452 :
2453 : // in UCB storages only the content type will be stored, all other information can be reconstructed
2454 : // ( see the UCBStorage_Impl::Init() method )
2455 0 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2456 0 : SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2457 0 : pImp->m_aContentType = aDataFlavor.MimeType;
2458 0 : }
2459 :
2460 0 : void UCBStorage::SetClassId( const ClsId& rClsId )
2461 : {
2462 0 : pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId );
2463 0 : if ( pImp->m_aClassId == SvGlobalName() )
2464 0 : return;
2465 :
2466 : // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2467 : // stored in one the substreams
2468 : // UCB storages store the content type information as content type in the manifest file and so this information must be
2469 : // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2470 : // the content type
2471 0 : pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2472 0 : if ( pImp->m_nFormat )
2473 : {
2474 0 : ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2475 0 : SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2476 0 : pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2477 0 : pImp->m_aContentType = aDataFlavor.MimeType;
2478 : }
2479 : }
2480 :
2481 0 : const ClsId& UCBStorage::GetClassId() const
2482 : {
2483 0 : return ( const ClsId& ) pImp->m_aClassId.GetCLSID();
2484 : }
2485 :
2486 0 : void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, sal_uLong /*nOriginalClipFormat*/, const OUString & /*rUserTypeName*/ )
2487 : {
2488 : // ???
2489 0 : }
2490 :
2491 0 : bool UCBStorage::ShouldConvert()
2492 : {
2493 : // ???
2494 0 : return false;
2495 : }
2496 :
2497 0 : SvGlobalName UCBStorage::GetClassName()
2498 : {
2499 0 : return pImp->m_aClassId;
2500 : }
2501 :
2502 0 : sal_uLong UCBStorage::GetFormat()
2503 : {
2504 0 : return pImp->m_nFormat;
2505 : }
2506 :
2507 0 : OUString UCBStorage::GetUserName()
2508 : {
2509 : OSL_FAIL("UserName is not implemented in UCB storages!" );
2510 0 : return pImp->m_aUserTypeName;
2511 : }
2512 :
2513 0 : void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2514 : {
2515 : // put information in childrenlist into StorageInfoList
2516 0 : for ( size_t i = 0; i < pImp->GetChildrenList().size(); ++i )
2517 : {
2518 0 : UCBStorageElement_Impl* pElement = pImp->GetChildrenList()[ i ];
2519 0 : if ( !pElement->m_bIsRemoved )
2520 : {
2521 : // problem: what about the size of a substorage ?!
2522 0 : sal_uLong nSize = pElement->m_nSize;
2523 0 : if ( pElement->m_xStream.Is() )
2524 0 : nSize = pElement->m_xStream->GetSize();
2525 0 : SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2526 0 : pList->push_back( aInfo );
2527 : }
2528 : }
2529 0 : }
2530 :
2531 0 : bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const OUString& rNew ) const
2532 : {
2533 : // insert stream or storage into the list or stream of the destination storage
2534 : // not into the content, this will be done on commit !
2535 : // be aware of name changes !
2536 0 : if ( !rElement.m_bIsStorage )
2537 : {
2538 : // copy the streams data
2539 : // the destination stream must not be open
2540 0 : BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2541 0 : BaseStorageStream* pStream = NULL;
2542 0 : bool bDeleteStream = false;
2543 :
2544 : // if stream is already open, it is allowed to copy it, so be aware of this
2545 0 : if ( rElement.m_xStream.Is() )
2546 0 : pStream = rElement.m_xStream->m_pAntiImpl;
2547 0 : if ( !pStream )
2548 : {
2549 0 : pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect );
2550 0 : bDeleteStream = true;
2551 : }
2552 :
2553 0 : pStream->CopyTo( pOtherStream );
2554 0 : SetError( pStream->GetError() );
2555 0 : if( pOtherStream->GetError() )
2556 0 : pDest->SetError( pOtherStream->GetError() );
2557 : else
2558 0 : pOtherStream->Commit();
2559 :
2560 0 : if ( bDeleteStream )
2561 0 : delete pStream;
2562 0 : delete pOtherStream;
2563 : }
2564 : else
2565 : {
2566 : // copy the storage content
2567 : // the destination storage must not be open
2568 0 : BaseStorage* pStorage = NULL;
2569 :
2570 : // if stream is already open, it is allowed to copy it, so be aware of this
2571 0 : bool bDeleteStorage = false;
2572 0 : if ( rElement.m_xStorage.Is() )
2573 0 : pStorage = rElement.m_xStorage->m_pAntiImpl;
2574 0 : if ( !pStorage )
2575 : {
2576 0 : pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2577 0 : bDeleteStorage = true;
2578 : }
2579 :
2580 0 : UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
2581 0 : UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );
2582 :
2583 0 : bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2584 : BaseStorage* pOtherStorage = bOpenUCBStorage ?
2585 0 : pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) :
2586 0 : pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2587 :
2588 : // For UCB storages, the class id and the format id may differ,
2589 : // do passing the class id is not sufficient.
2590 0 : if( bOpenUCBStorage )
2591 0 : pOtherStorage->SetClass( pStorage->GetClassName(),
2592 0 : pStorage->GetFormat(),
2593 0 : pUCBCopy->pImp->m_aUserTypeName );
2594 : else
2595 0 : pOtherStorage->SetClassId( pStorage->GetClassId() );
2596 0 : pStorage->CopyTo( pOtherStorage );
2597 0 : SetError( pStorage->GetError() );
2598 0 : if( pOtherStorage->GetError() )
2599 0 : pDest->SetError( pOtherStorage->GetError() );
2600 : else
2601 0 : pOtherStorage->Commit();
2602 :
2603 0 : if ( bDeleteStorage )
2604 0 : delete pStorage;
2605 0 : delete pOtherStorage;
2606 : }
2607 :
2608 0 : return Good() && pDest->Good();
2609 : }
2610 :
2611 802 : UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const OUString& rName ) const
2612 : {
2613 : DBG_ASSERT( !rName.isEmpty(), "Name is empty!" );
2614 802 : for ( size_t i = 0, n = pImp->GetChildrenList().size(); i < n; ++i )
2615 : {
2616 0 : UCBStorageElement_Impl* pElement = pImp->GetChildrenList()[ i ];
2617 0 : if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2618 0 : return pElement;
2619 : }
2620 802 : return NULL;
2621 : }
2622 :
2623 0 : bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2624 : {
2625 : DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
2626 0 : if ( pDestStg == ((BaseStorage*)this) )
2627 0 : return false;
2628 :
2629 : // perhaps it's also a problem if one storage is a parent of the other ?!
2630 : // or if not: could be optimized ?!
2631 :
2632 : // For UCB storages, the class id and the format id may differ,
2633 : // do passing the class id is not sufficient.
2634 0 : if( pDestStg->ISA( UCBStorage ) )
2635 : pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2636 0 : pImp->m_aUserTypeName );
2637 : else
2638 0 : pDestStg->SetClassId( GetClassId() );
2639 0 : pDestStg->SetDirty();
2640 :
2641 0 : bool bRet = true;
2642 0 : for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2643 : {
2644 0 : UCBStorageElement_Impl* pElement = pImp->GetChildrenList()[ i ];
2645 0 : if ( !pElement->m_bIsRemoved )
2646 0 : bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2647 : }
2648 :
2649 0 : if( !bRet )
2650 0 : SetError( pDestStg->GetError() );
2651 0 : return Good() && pDestStg->Good();
2652 : }
2653 :
2654 0 : bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2655 : {
2656 0 : if( rElemName.isEmpty() )
2657 0 : return false;
2658 :
2659 0 : if ( pDest == ((BaseStorage*) this) )
2660 : {
2661 : // can't double an element
2662 0 : return false;
2663 : }
2664 : else
2665 : {
2666 : // for copying no optimization is useful, because in every case the stream data must be copied
2667 0 : UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2668 0 : if ( pElement )
2669 0 : return CopyStorageElement_Impl( *pElement, pDest, rNew );
2670 : else
2671 : {
2672 0 : SetError( SVSTREAM_FILE_NOT_FOUND );
2673 0 : return false;
2674 : }
2675 : }
2676 : }
2677 :
2678 0 : bool UCBStorage::Commit()
2679 : {
2680 : // mark this storage for sending it on root commit
2681 0 : pImp->m_bCommited = true;
2682 0 : if ( pImp->m_bIsRoot )
2683 : // the root storage coordinates commiting by sending a Commit command to its content
2684 0 : return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2685 : else
2686 0 : return true;
2687 : }
2688 :
2689 0 : bool UCBStorage::Revert()
2690 : {
2691 0 : return pImp->Revert();
2692 : }
2693 :
2694 0 : BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect, const OString* pKey )
2695 : {
2696 0 : if( rEleName.isEmpty() )
2697 0 : return NULL;
2698 :
2699 : // try to find the storage element
2700 0 : UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2701 0 : if ( !pElement )
2702 : {
2703 : // element does not exist, check if creation is allowed
2704 0 : if( ( nMode & STREAM_NOCREATE ) )
2705 : {
2706 0 : SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2707 0 : OUString aName( pImp->m_aURL );
2708 0 : aName += "/";
2709 0 : aName += rEleName;
2710 0 : UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2711 0 : pStream->SetError( GetError() );
2712 0 : pStream->pImp->m_aName = rEleName;
2713 0 : return pStream;
2714 : }
2715 : else
2716 : {
2717 : // create a new UCBStorageElement and insert it into the list
2718 0 : pElement = new UCBStorageElement_Impl( rEleName );
2719 0 : pElement->m_bIsInserted = true;
2720 0 : pImp->m_aChildrenList.push_back( pElement );
2721 : }
2722 : }
2723 :
2724 0 : if ( pElement && !pElement->m_bIsFolder )
2725 : {
2726 : // check if stream is already created
2727 0 : if ( pElement->m_xStream.Is() )
2728 : {
2729 : // stream has already been created; if it has no external reference, it may be opened another time
2730 0 : if ( pElement->m_xStream->m_pAntiImpl )
2731 : {
2732 : OSL_FAIL("Stream is already open!" );
2733 0 : SetError( SVSTREAM_ACCESS_DENIED ); // ???
2734 0 : return NULL;
2735 : }
2736 : else
2737 : {
2738 : // check if stream is opened with the same keyword as before
2739 : // if not, generate a new stream because it could be encrypted vs. decrypted!
2740 0 : OString aKey;
2741 0 : if ( pKey )
2742 0 : aKey = *pKey;
2743 0 : if ( pElement->m_xStream->m_aKey == aKey )
2744 : {
2745 0 : pElement->m_xStream->PrepareCachedForReopen( nMode );
2746 :
2747 0 : return new UCBStorageStream( pElement->m_xStream );
2748 0 : }
2749 : }
2750 : }
2751 :
2752 : // stream is opened the first time
2753 0 : pImp->OpenStream( pElement, nMode, bDirect, pKey );
2754 :
2755 : // if name has been changed before creating the stream: set name!
2756 0 : pElement->m_xStream->m_aName = rEleName;
2757 0 : return new UCBStorageStream( pElement->m_xStream );
2758 : }
2759 :
2760 0 : return NULL;
2761 : }
2762 :
2763 0 : UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect, const OString* pKey )
2764 : {
2765 0 : OUString aName( m_aURL );
2766 0 : aName += "/";
2767 0 : aName += pElement->m_aOriginalName;
2768 0 : pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler );
2769 0 : return pElement->m_xStream;
2770 : }
2771 :
2772 0 : BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2773 : {
2774 0 : if( rEleName.isEmpty() )
2775 0 : return NULL;
2776 :
2777 0 : return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2778 : }
2779 :
2780 0 : BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2781 : {
2782 0 : if( rEleName.isEmpty() )
2783 0 : return NULL;
2784 :
2785 0 : return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2786 : }
2787 :
2788 0 : BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2789 : {
2790 0 : if( rEleName.isEmpty() )
2791 0 : return NULL;
2792 :
2793 0 : return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2794 : }
2795 :
2796 0 : BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2797 : {
2798 : // try to find the storage element
2799 0 : UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2800 0 : if ( !pElement )
2801 : {
2802 : // element does not exist, check if creation is allowed
2803 0 : if( ( nMode & STREAM_NOCREATE ) )
2804 : {
2805 0 : SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2806 0 : OUString aName( pImp->m_aURL );
2807 0 : aName += "/";
2808 0 : aName += rEleName; // ???
2809 0 : UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2810 0 : pStorage->pImp->m_bIsRoot = false;
2811 0 : pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2812 0 : pStorage->SetError( GetError() );
2813 0 : return pStorage;
2814 : }
2815 :
2816 : // create a new UCBStorageElement and insert it into the list
2817 : // problem: perhaps an OLEStorage should be created ?!
2818 : // Because nothing is known about the element that should be created, an external parameter is needed !
2819 0 : pElement = new UCBStorageElement_Impl( rEleName );
2820 0 : pElement->m_bIsInserted = true;
2821 0 : pImp->m_aChildrenList.push_back( pElement );
2822 : }
2823 :
2824 0 : if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
2825 : {
2826 : // create OLE storages on a stream ( see ctor of SotStorage )
2827 : // Such a storage will be created on a UCBStorageStream; it will write into the stream
2828 : // if it is opened in direct mode or when it is committed. In this case the stream will be
2829 : // modified and then it MUST be treated as commited.
2830 0 : if ( !pElement->m_xStream.Is() )
2831 : {
2832 0 : BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2833 0 : UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr );
2834 0 : if ( !pStream )
2835 : {
2836 0 : SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2837 0 : return NULL;
2838 : }
2839 :
2840 0 : pElement->m_xStream = pStream->pImp;
2841 0 : delete pStream;
2842 : }
2843 :
2844 0 : pElement->m_xStream->PrepareCachedForReopen( nMode );
2845 0 : pElement->m_xStream->Init();
2846 :
2847 0 : pElement->m_bIsStorage = true;
2848 0 : return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
2849 : }
2850 0 : else if ( pElement->m_xStorage.Is() )
2851 : {
2852 : // storage has already been opened; if it has no external reference, it may be opened another time
2853 0 : if ( pElement->m_xStorage->m_pAntiImpl )
2854 : {
2855 : OSL_FAIL("Storage is already open!" );
2856 0 : SetError( SVSTREAM_ACCESS_DENIED ); // ???
2857 : }
2858 : else
2859 : {
2860 0 : bool bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0);
2861 0 : if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 ))
2862 : {
2863 0 : OUString aName( pImp->m_aURL );
2864 0 : aName += "/";
2865 0 : aName += pElement->m_aOriginalName;
2866 0 : UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2867 0 : pElement->m_xStorage = pStorage->pImp;
2868 0 : return pStorage;
2869 : }
2870 : else
2871 : {
2872 0 : return new UCBStorage( pElement->m_xStorage );
2873 : }
2874 : }
2875 : }
2876 0 : else if ( !pElement->m_xStream.Is() )
2877 : {
2878 : // storage is opened the first time
2879 0 : bool bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 );
2880 0 : if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2881 : {
2882 : // make sure that the root storage object has been created before substorages will be created
2883 0 : INetURLObject aFolderObj( pImp->m_aURL );
2884 0 : aFolderObj.removeSegment();
2885 :
2886 0 : Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2887 0 : pImp->m_pContent = new Content;
2888 0 : bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
2889 0 : if ( !bRet )
2890 : {
2891 0 : SetError( SVSTREAM_CANNOT_MAKE );
2892 0 : return NULL;
2893 0 : }
2894 : }
2895 :
2896 0 : UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2897 0 : if ( pStor )
2898 : {
2899 0 : if ( pElement->m_bIsInserted )
2900 0 : pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2901 :
2902 0 : return new UCBStorage( pStor );
2903 : }
2904 : }
2905 :
2906 0 : return NULL;
2907 : }
2908 :
2909 0 : UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2910 : {
2911 0 : UCBStorage_Impl* pRet = NULL;
2912 0 : OUString aName( m_aURL );
2913 0 : aName += "/";
2914 0 : aName += pElement->m_aOriginalName; // ???
2915 :
2916 0 : pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2917 :
2918 0 : if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2919 : {
2920 0 : Content aNewFolder;
2921 0 : bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
2922 0 : if ( bRet )
2923 0 : pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2924 : }
2925 : else
2926 : {
2927 0 : pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2928 : }
2929 :
2930 0 : if ( pRet )
2931 : {
2932 0 : pRet->m_bIsLinked = m_bIsLinked;
2933 0 : pRet->m_bIsRoot = false;
2934 :
2935 : // if name has been changed before creating the stream: set name!
2936 0 : pRet->m_aName = pElement->m_aOriginalName;
2937 0 : pElement->m_xStorage = pRet;
2938 : }
2939 :
2940 0 : if ( pRet )
2941 0 : pRet->Init();
2942 :
2943 0 : return pRet;
2944 : }
2945 :
2946 0 : bool UCBStorage::IsStorage( const OUString& rEleName ) const
2947 : {
2948 0 : if( rEleName.isEmpty() )
2949 0 : return false;
2950 :
2951 0 : const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2952 0 : return ( pElement && pElement->m_bIsStorage );
2953 : }
2954 :
2955 802 : bool UCBStorage::IsStream( const OUString& rEleName ) const
2956 : {
2957 802 : if( rEleName.isEmpty() )
2958 0 : return false;
2959 :
2960 802 : const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2961 802 : return ( pElement && !pElement->m_bIsStorage );
2962 : }
2963 :
2964 0 : bool UCBStorage::IsContained( const OUString & rEleName ) const
2965 : {
2966 0 : if( rEleName.isEmpty() )
2967 0 : return false;
2968 0 : const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2969 0 : return ( pElement != NULL );
2970 : }
2971 :
2972 0 : bool UCBStorage::Remove( const OUString& rEleName )
2973 : {
2974 0 : if( rEleName.isEmpty() )
2975 0 : return false;
2976 :
2977 0 : UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2978 0 : if ( pElement )
2979 : {
2980 0 : pElement->m_bIsRemoved = true;
2981 : }
2982 : else
2983 0 : SetError( SVSTREAM_FILE_NOT_FOUND );
2984 :
2985 0 : return ( pElement != NULL );
2986 : }
2987 :
2988 0 : bool UCBStorage::Rename( const OUString& rEleName, const OUString& rNewName )
2989 : {
2990 0 : if( rEleName.isEmpty()|| rNewName.isEmpty() )
2991 0 : return false;
2992 :
2993 0 : UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
2994 0 : if ( pAlreadyExisting )
2995 : {
2996 0 : SetError( SVSTREAM_ACCESS_DENIED );
2997 0 : return false; // can't change to a name that is already used
2998 : }
2999 :
3000 0 : UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3001 0 : if ( pElement )
3002 : {
3003 0 : pElement->m_aName = rNewName;
3004 : }
3005 : else
3006 0 : SetError( SVSTREAM_FILE_NOT_FOUND );
3007 :
3008 0 : return pElement != NULL;
3009 : }
3010 :
3011 0 : bool UCBStorage::MoveTo( const OUString& rEleName, BaseStorage* pNewSt, const OUString& rNewName )
3012 : {
3013 0 : if( rEleName.isEmpty() || rNewName.isEmpty() )
3014 0 : return false;
3015 :
3016 0 : if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
3017 : {
3018 0 : return Rename( rEleName, rNewName );
3019 : }
3020 : else
3021 : {
3022 : /*
3023 : if ( PTR_CAST( UCBStorage, pNewSt ) )
3024 : {
3025 : // because the element is moved, not copied, a special optimization is possible :
3026 : // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3027 : // clear original name/type of the new element
3028 : // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3029 : // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3030 : // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3031 : // belong to the new content
3032 : // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3033 : // stream of the destination object
3034 : // Not implemented at the moment ( risky?! ), perhaps later
3035 : }
3036 : */
3037 : // MoveTo is done by first copying to the new destination and then removing the old element
3038 0 : bool bRet = CopyTo( rEleName, pNewSt, rNewName );
3039 0 : if ( bRet )
3040 0 : bRet = Remove( rEleName );
3041 0 : return bRet;
3042 : }
3043 : }
3044 :
3045 0 : bool UCBStorage::ValidateFAT()
3046 : {
3047 : // ???
3048 0 : return true;
3049 : }
3050 :
3051 0 : bool UCBStorage::Validate( bool bWrite ) const
3052 : {
3053 : // ???
3054 0 : return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
3055 : }
3056 :
3057 0 : bool UCBStorage::ValidateMode( StreamMode m ) const
3058 : {
3059 : // ???
3060 0 : if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
3061 0 : return true;
3062 0 : sal_uInt16 nCurMode = 0xFFFF;
3063 0 : if( ( m & 3 ) == STREAM_READ )
3064 : {
3065 : // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3066 0 : if( ( ( m & STREAM_SHARE_DENYWRITE )
3067 0 : && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
3068 0 : || ( ( m & STREAM_SHARE_DENYALL )
3069 0 : && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
3070 0 : return true;
3071 : }
3072 : else
3073 : {
3074 : // only SHARE_DENYALL allowed
3075 : // storages open in r/o mode are OK, since only
3076 : // the commit may fail
3077 0 : if( ( m & STREAM_SHARE_DENYALL )
3078 0 : && ( nCurMode & STREAM_SHARE_DENYALL ) )
3079 0 : return true;
3080 : }
3081 :
3082 0 : return true;
3083 : }
3084 :
3085 0 : const SvStream* UCBStorage::GetSvStream() const
3086 : {
3087 : // this would cause a complete download of the file
3088 : // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3089 0 : return pImp->m_pSource;
3090 : }
3091 :
3092 0 : bool UCBStorage::Equals( const BaseStorage& rStorage ) const
3093 : {
3094 : // ???
3095 0 : return ((BaseStorage*)this) == &rStorage;
3096 : }
3097 :
3098 2436 : bool UCBStorage::IsStorageFile( SvStream* pFile )
3099 : {
3100 2436 : if ( !pFile )
3101 0 : return false;
3102 :
3103 2436 : sal_uLong nPos = pFile->Tell();
3104 2436 : pFile->Seek( STREAM_SEEK_TO_END );
3105 2436 : if ( pFile->Tell() < 4 )
3106 57 : return false;
3107 :
3108 2379 : pFile->Seek(0);
3109 2379 : sal_uInt32 nBytes(0);
3110 2379 : *pFile >> nBytes;
3111 :
3112 : // search for the magic bytes
3113 2379 : bool bRet = ( nBytes == 0x04034b50 );
3114 2379 : if ( !bRet )
3115 : {
3116 : // disk spanned file have an additional header in front of the usual one
3117 2230 : bRet = ( nBytes == 0x08074b50 );
3118 2230 : if ( bRet )
3119 : {
3120 0 : nBytes = 0;
3121 0 : *pFile >> nBytes;
3122 0 : bRet = ( nBytes == 0x04034b50 );
3123 : }
3124 : }
3125 :
3126 2379 : pFile->Seek( nPos );
3127 2379 : return bRet;
3128 : }
3129 :
3130 0 : bool UCBStorage::IsDiskSpannedFile( SvStream* pFile )
3131 : {
3132 0 : if ( !pFile )
3133 0 : return false;
3134 :
3135 0 : sal_uLong nPos = pFile->Tell();
3136 0 : pFile->Seek( STREAM_SEEK_TO_END );
3137 0 : if ( !pFile->Tell() )
3138 0 : return false;
3139 :
3140 0 : pFile->Seek(0);
3141 : sal_uInt32 nBytes;
3142 0 : *pFile >> nBytes;
3143 :
3144 : // disk spanned file have an additional header in front of the usual one
3145 0 : bool bRet = ( nBytes == 0x08074b50 );
3146 0 : if ( bRet )
3147 : {
3148 0 : *pFile >> nBytes;
3149 0 : bRet = ( nBytes == 0x04034b50 );
3150 : }
3151 :
3152 0 : pFile->Seek( nPos );
3153 0 : return bRet;
3154 : }
3155 :
3156 0 : OUString UCBStorage::GetLinkedFile( SvStream &rStream )
3157 : {
3158 0 : OUString aString;
3159 0 : sal_uLong nPos = rStream.Tell();
3160 0 : rStream.Seek( STREAM_SEEK_TO_END );
3161 0 : if ( !rStream.Tell() )
3162 0 : return aString;
3163 :
3164 0 : rStream.Seek(0);
3165 : sal_uInt32 nBytes;
3166 0 : rStream >> nBytes;
3167 0 : if( nBytes == 0x04034b50 )
3168 : {
3169 0 : OString aTmp = read_lenPrefixed_uInt8s_ToOString<sal_uInt16>(rStream);
3170 0 : if (aTmp.match("ContentURL="))
3171 : {
3172 0 : aString = OStringToOUString(aTmp.copy(11), RTL_TEXTENCODING_UTF8);
3173 0 : }
3174 : }
3175 :
3176 0 : rStream.Seek( nPos );
3177 0 : return aString;
3178 : }
3179 :
3180 0 : OUString UCBStorage::CreateLinkFile( const OUString& rName )
3181 : {
3182 : // create a stream to write the link file - use a temp file, because it may be no file content
3183 0 : INetURLObject aFolderObj( rName );
3184 0 : OUString aName = aFolderObj.GetName();
3185 0 : aFolderObj.removeSegment();
3186 0 : OUString aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) );
3187 0 : ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL );
3188 :
3189 : // get the stream from the temp file
3190 0 : SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC );
3191 :
3192 : // write header
3193 0 : *pStream << ( sal_uInt32 ) 0x04034b50;
3194 :
3195 : // assemble a new folder name in the destination folder
3196 0 : INetURLObject aObj( rName );
3197 0 : OUString aTmpName = aObj.GetName();
3198 0 : OUString aTitle = OUString( "content." );
3199 0 : aTitle += aTmpName;
3200 :
3201 : // create a folder and store its URL
3202 0 : Content aFolder( aFolderURL, Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
3203 0 : Content aNewFolder;
3204 0 : bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
3205 0 : if ( !bRet )
3206 : {
3207 0 : aFolderObj.insertName( aTitle );
3208 0 : if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3209 : {
3210 : // Hack, because already existing files give the same CommandAbortedException as any other error !
3211 : // append a number until the name can be used for a new folder
3212 0 : aTitle += ".";
3213 0 : for ( sal_Int32 i=0; !bRet; i++ )
3214 : {
3215 0 : OUString aTmp( aTitle );
3216 0 : aTmp += OUString::number( i );
3217 0 : bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder );
3218 0 : if ( bRet )
3219 0 : aTitle = aTmp;
3220 : else
3221 : {
3222 0 : aFolderObj.SetName( aTmp );
3223 0 : if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3224 : // Hack, because already existing files give the same CommandAbortedException as any other error !
3225 0 : break;
3226 : }
3227 0 : }
3228 : }
3229 : }
3230 :
3231 0 : if ( bRet )
3232 : {
3233 : // get the URL
3234 0 : aObj.SetName( aTitle );
3235 0 : OUString aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3236 :
3237 : // store it as key/value pair
3238 0 : OUString aLink = OUString("ContentURL=");
3239 0 : aLink += aURL;
3240 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(*pStream, aLink, RTL_TEXTENCODING_UTF8);
3241 0 : pStream->Flush();
3242 :
3243 : // move the stream to its desired location
3244 0 : Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
3245 0 : DELETEZ( pTempFile );
3246 0 : aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE );
3247 0 : return aURL;
3248 : }
3249 :
3250 0 : pTempFile->EnableKillingFile( true );
3251 0 : delete pTempFile;
3252 0 : return OUString();
3253 : }
3254 :
3255 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|