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