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 committed: 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 commits 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 necessary 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 until 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 useful 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 then 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 than 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 copying 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 committed
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 committed 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 necessary 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 than 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( pHelper );
1880
1881 // create a manifest reader object that will read in the manifest from the stream
1882 Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader =
1883 Reference< ::com::sun::star::packages::manifest::XManifestReader >
1884 ( ::comphelper::getProcessServiceFactory()->createInstance(
1885 ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestReader" )), UNO_QUERY) ;
1886 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1887
1888 // cleanup
1889 xReader = NULL;
1890 xInputStream = NULL;
1891 SetProps( aProps, String() );
1892 }
1893
1894 delete pStream;
1895 }
1896 }
1897 }
1898 else
1899 ReadContent();
1900 }
1901 else
1902 {
1903 // get the manifest information from the package
1904 try {
1905 Any aAny = m_pContent->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
1906 rtl::OUString aTmp;
1907 if ( ( aAny >>= aTmp ) && aTmp.getLength() )
1908 m_aContentType = m_aOriginalContentType = aTmp;
1909 }
1910 catch( Exception& )
1911 {
1912 DBG_ASSERT( sal_False,
1913 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1914 }
1915 }
1916 }
1917
1918 if ( m_aContentType.Len() )
1919 {
1920 // get the clipboard format using the content type
1921 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
1922 aDataFlavor.MimeType = m_aContentType;
1923 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1924
1925 // get the ClassId using the clipboard format ( internal table )
1926 m_aClassId = GetClassId_Impl( m_nFormat );
1927
1928 // get human presentable name using the clipboard format
1929 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1930 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1931
1932 if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1933 ReadContent();
1934 }
1935 }
1936
1937 void UCBStorage_Impl::CreateContent()
1938 {
1939 try
1940 {
1941 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1942 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1943
1944 ::rtl::OUString aTemp( m_aURL );
1945
1946 if ( m_bRepairPackage )
1947 {
1948 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
1949 m_xProgressHandler );
1950 aTemp += rtl::OUString::createFromAscii("?repairpackage");
1951 }
1952
1953 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
1954 }
1955 catch ( ContentCreationException& )
1956 {
1957 // content could not be created
1958 SetError( SVSTREAM_CANNOT_MAKE );
1959 }
1960 catch ( RuntimeException& )
1961 {
1962 // any other error - not specified
1963 SetError( SVSTREAM_CANNOT_MAKE );
1964 }
1965 }
1966
1967 void UCBStorage_Impl::ReadContent()
1968 {
1969 if ( m_bListCreated )
1970 return;
1971
1972 m_bListCreated = sal_True;
1973
1974 // create cursor for access to children
1975 Sequence< ::rtl::OUString > aProps(4);
1976 ::rtl::OUString* pProps = aProps.getArray();
1977 pProps[0] = ::rtl::OUString::createFromAscii( "Title" );
1978 pProps[1] = ::rtl::OUString::createFromAscii( "IsFolder" );
1979 pProps[2] = ::rtl::OUString::createFromAscii( "MediaType" );
1980 pProps[3] = ::rtl::OUString::createFromAscii( "Size" );
1981 ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS;
1982
1983 try
1984 {
1985 GetContent();
1986 if ( !m_pContent )
1987 return;
1988
1989 Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude );
1990 Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
1991 Reference< XRow > xRow( xResultSet, UNO_QUERY );
1992 if ( xResultSet.is() )
1993 {
1994 while ( xResultSet->next() )
1995 {
1996 // insert all into the children list
1997 ::rtl::OUString aTitle( xRow->getString(1) );
1998 ::rtl::OUString aContentType;
1999 if ( m_bIsLinked )
2000 {
2001 // unpacked storages have to deal with the meta-inf folder by themselves
2002 if( aTitle.equalsAscii("META-INF") )
2003 continue;
2004 }
2005 else
2006 {
2007 aContentType = xRow->getString(3);
2008 }
2009
2010 sal_Bool bIsFolder( xRow->getBoolean(2) );
2011 sal_Int64 nSize = xRow->getLong(4);
2012 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (sal_uLong) nSize );
2013 m_aChildrenList.Insert( pElement, LIST_APPEND );
2014
2015 sal_Bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
2016 if ( bIsFolder )
2017 {
2018 if ( m_bIsLinked )
2019 OpenStorage( pElement, m_nMode, m_bDirect );
2020 if ( pElement->m_xStorage.Is() )
2021 pElement->m_xStorage->Init();
2022 }
2023 else if ( bIsOfficeDocument )
2024 {
2025 // streams can be external OLE objects, so they are now folders, but storages!
2026 String aName( m_aURL );
2027 aName += '/';
2028 aName += String( xRow->getString(1) );
2029
2030 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
2031 if ( m_bRepairPackage )
2032 {
2033 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
2034 m_xProgressHandler );
2035 aName += String( RTL_CONSTASCII_USTRINGPARAM( "?repairpackage" ) );
2036 }
2037
2038 ::ucbhelper::Content aContent( aName, xComEnv );
2039
2040 ::rtl::OUString aMediaType;
2041 Any aAny = aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
2042 if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
2043 pElement->m_bIsStorage = sal_True;
2044 else if ( !aMediaType.getLength() )
2045 {
2046 // older files didn't have that special content type, so they must be detected
2047 OpenStream( pElement, STREAM_STD_READ, m_bDirect );
2048 if ( Storage::IsStorageFile( pElement->m_xStream ) )
2049 pElement->m_bIsStorage = sal_True;
2050 else
2051 pElement->m_xStream->Free();
2052 }
2053 }
2054 }
2055 }
2056 }
2057 catch ( InteractiveIOException& r )
2058 {
2059 if ( r.Code != IOErrorCode_NOT_EXISTING )
2060 SetError( ERRCODE_IO_GENERAL );
2061 }
2062 catch ( CommandAbortedException& )
2063 {
2064 // any command wasn't executed successfully - not specified
2065 if ( !( m_nMode & STREAM_WRITE ) )
2066 // if the folder was just inserted and not already committed, this is not an error!
2067 SetError( ERRCODE_IO_GENERAL );
2068 }
2069 catch ( RuntimeException& )
2070 {
2071 // any other error - not specified
2072 SetError( ERRCODE_IO_GENERAL );
2073 }
2074 catch ( ResultSetException& )
2075 {
2076 // means that the package file is broken
2077 SetError( ERRCODE_IO_BROKENPACKAGE );
2078 }
2079 catch ( SQLException& )
2080 {
2081 // means that the file can be broken
2082 SetError( ERRCODE_IO_WRONGFORMAT );
2083 }
2084 catch ( Exception& )
2085 {
2086 // any other error - not specified
2087 SetError( ERRCODE_IO_GENERAL );
2088 }
2089 }
2090
2091 void UCBStorage_Impl::SetError( long nError )
2092 {
2093 if ( !m_nError )
2094 {
2095 m_nError = nError;
2096 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
2097 }
2098 }
2099
2100 sal_Int32 UCBStorage_Impl::GetObjectCount()
2101 {
2102 sal_Int32 nCount = m_aChildrenList.Count();
2103 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2104 while ( pElement )
2105 {
2106 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2107 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2108 nCount += pElement->m_xStorage->GetObjectCount();
2109 pElement = m_aChildrenList.Next();
2110 }
2111
2112 return nCount;
2113 }
2114
2115 ::rtl::OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const ::rtl::OUString& rPath )
2116 {
2117 sal_Bool bFound = sal_False;
2118 for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
2119 {
2120 const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
2121 ::rtl::OUString aType;
2122
2123 for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
2124 {
2125 const PropertyValue& rAny = rMyProps[nProps];
2126 if ( rAny.Name.equalsAscii("FullPath") )
2127 {
2128 rtl::OUString aTmp;
2129 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
2130 bFound = sal_True;
2131 if ( aType.getLength() )
2132 break;
2133 }
2134 else if ( rAny.Name.equalsAscii("MediaType") )
2135 {
2136 if ( ( rAny.Value >>= aType ) && aType.getLength() && bFound )
2137 break;
2138 }
2139 }
2140
2141 if ( bFound )
2142 return aType;
2143 }
2144
2145 return ::rtl::OUString();
2146 }
2147
2148 void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2149 {
2150 String aPath( rPath );
2151 if ( !m_bIsRoot )
2152 aPath += m_aName;
2153 aPath += '/';
2154
2155 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
2156
2157 if ( m_bIsRoot )
2158 // the "FullPath" of a child always starts without '/'
2159 aPath.Erase();
2160
2161 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2162 while ( pElement )
2163 {
2164 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2165 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2166 pElement->m_xStorage->SetProps( rSequence, aPath );
2167 else
2168 {
2169 String aElementPath( aPath );
2170 aElementPath += pElement->m_aName;
2171 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
2172 }
2173
2174 pElement = m_aChildrenList.Next();
2175 }
2176
2177 if ( m_aContentType.Len() )
2178 {
2179 // get the clipboard format using the content type
2180 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2181 aDataFlavor.MimeType = m_aContentType;
2182 m_nFormat = SotExchange::GetFormat( aDataFlavor );
2183
2184 // get the ClassId using the clipboard format ( internal table )
2185 m_aClassId = GetClassId_Impl( m_nFormat );
2186
2187 // get human presentable name using the clipboard format
2188 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
2189 m_aUserTypeName = aDataFlavor.HumanPresentableName;
2190 }
2191 }
2192
2193 void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2194 {
2195 // first my own properties
2196 Sequence < PropertyValue > aProps(2);
2197
2198 // first property is the "FullPath" name
2199 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2200 String aPath( rPath );
2201 if ( !m_bIsRoot )
2202 aPath += m_aName;
2203 aPath += '/';
2204 aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2205 aProps[0].Value <<= (::rtl::OUString ) m_aContentType;
2206 aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2207 aProps[1].Value <<= (::rtl::OUString ) aPath;
2208 rSequence[ nProps++ ] = aProps;
2209
2210 if ( m_bIsRoot )
2211 // the "FullPath" of a child always starts without '/'
2212 aPath.Erase();
2213
2214 // now the properties of my elements
2215 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2216 while ( pElement )
2217 {
2218 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2219 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2220 // storages add there properties by themselves ( see above )
2221 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
2222 else
2223 {
2224 // properties of streams
2225 String aElementPath( aPath );
2226 aElementPath += pElement->m_aName;
2227 aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2228 aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType();
2229 aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2230 aProps[1].Value <<= (::rtl::OUString ) aElementPath;
2231 rSequence[ nProps++ ] = aProps;
2232 }
2233
2234 pElement = m_aChildrenList.Next();
2235 }
2236 }
2237
2238 UCBStorage_Impl::~UCBStorage_Impl()
2239 {
2240 if ( m_pUNOStorageHolderList )
2241 {
2242 for ( UNOStorageHolderList::iterator aIter = m_pUNOStorageHolderList->begin();
2243 aIter != m_pUNOStorageHolderList->end(); aIter++ )
2244 if ( *aIter )
2245 {
2246 (*aIter)->InternalDispose();
2247 (*aIter)->release();
2248 (*aIter) = NULL;
2249 }
2250
2251 m_pUNOStorageHolderList->clear();
2252 DELETEZ( m_pUNOStorageHolderList );
2253 }
2254
2255 // first delete elements!
2256 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2257 while ( pElement )
2258 {
2259 delete pElement;
2260 pElement = m_aChildrenList.Next();
2261 }
2262
2263 m_aChildrenList.Clear();
2264 delete m_pContent;
2265 delete m_pTempFile;
2266 }
2267
2268 sal_Bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
2269 {
2270 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2271 // it must be inserted with a title and a type
2272 sal_Bool bRet = sal_False;
2273
2274 try
2275 {
2276 Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
2277 sal_Int32 nCount = aInfo.getLength();
2278 if ( nCount == 0 )
2279 return sal_False;
2280
2281 for ( sal_Int32 i = 0; i < nCount; ++i )
2282 {
2283 // Simply look for the first KIND_FOLDER...
2284 const ContentInfo & rCurr = aInfo[i];
2285 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
2286 {
2287 // Make sure the only required bootstrap property is "Title",
2288 const Sequence< Property > & rProps = rCurr.Properties;
2289 if ( rProps.getLength() != 1 )
2290 continue;
2291
2292 if ( !rProps[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
2293 continue;
2294
2295 Sequence < ::rtl::OUString > aNames(1);
2296 ::rtl::OUString* pNames = aNames.getArray();
2297 pNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
2298 Sequence < Any > aValues(1);
2299 Any* pValues = aValues.getArray();
2300 pValues[0] = makeAny( ::rtl::OUString( m_aName ) );
2301
2302 Content aNewFolder;
2303 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
2304 continue;
2305
2306 // remove old content, create an "empty" new one and initialize it with the new inserted
2307 DELETEZ( m_pContent );
2308 m_pContent = new ::ucbhelper::Content( aNewFolder );
2309 bRet = sal_True;
2310 }
2311 }
2312 }
2313 catch ( CommandAbortedException& )
2314 {
2315 // any command wasn't executed successfully - not specified
2316 SetError( ERRCODE_IO_GENERAL );
2317 }
2318 catch ( RuntimeException& )
2319 {
2320 // any other error - not specified
2321 SetError( ERRCODE_IO_GENERAL );
2322 }
2323 catch ( Exception& )
2324 {
2325 // any other error - not specified
2326 SetError( ERRCODE_IO_GENERAL );
2327 }
2328
2329 return bRet;
2330 }
2331
2332 sal_Int16 UCBStorage_Impl::Commit()
2333 {
2334 // send all changes to the package
2335 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2336 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
2337
2338 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2339 // commit command has been sent
2340 if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) )
2341 {
2342 try
2343 {
2344 // all errors will be caught in the "catch" statement outside the loop
2345 while ( pElement && nRet )
2346 {
2347 ::ucbhelper::Content* pContent = pElement->GetContent();
2348 sal_Bool bDeleteContent = sal_False;
2349 if ( !pContent && pElement->IsModified() )
2350 {
2351 // if the element has never been opened, no content has been created until now
2352 bDeleteContent = sal_True; // remember to delete it later
2353 String aName( m_aURL );
2354 aName += '/';
2355 aName += pElement->m_aOriginalName;
2356 pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
2357 }
2358
2359 if ( pElement->m_bIsRemoved )
2360 {
2361 // was it inserted, then removed (so there would be nothing to do!)
2362 if ( !pElement->m_bIsInserted )
2363 {
2364 // first remove all open stream handles
2365 if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() )
2366 {
2367 pContent->executeCommand( ::rtl::OUString::createFromAscii("delete"), makeAny( sal_Bool( sal_True ) ) );
2368 nRet = COMMIT_RESULT_SUCCESS;
2369 }
2370 else
2371 // couldn't release stream because there are external references to it
2372 nRet = COMMIT_RESULT_FAILURE;
2373 }
2374 }
2375 else
2376 {
2377 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2378 if ( pElement->m_xStorage.Is() )
2379 {
2380 // element is a storage
2381 // do a commit in the following cases:
2382 // - if storage is already inserted, and changed
2383 // - storage is not in a package
2384 // - it's a new storage, try to insert and commit if successful inserted
2385 if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
2386 {
2387 nLocalRet = pElement->m_xStorage->Commit();
2388 pContent = pElement->GetContent();
2389 }
2390 }
2391 else if ( pElement->m_xStream.Is() )
2392 {
2393 // element is a stream
2394 nLocalRet = pElement->m_xStream->Commit();
2395 if ( pElement->m_xStream->m_bIsOLEStorage )
2396 {
2397 // OLE storage should be stored encrypted, if the storage uses encryption
2398 pElement->m_xStream->m_aContentType = String::CreateFromAscii("application/vnd.sun.star.oleobject");
2399 Any aValue;
2400 aValue <<= (sal_Bool) sal_True;
2401 pElement->m_xStream->m_pContent->setPropertyValue(String::CreateFromAscii("Encrypted"), aValue );
2402 }
2403
2404 pContent = pElement->GetContent();
2405 }
2406
2407 if ( pElement->m_aName != pElement->m_aOriginalName )
2408 {
2409 // name ( title ) of the element was changed
2410 nLocalRet = COMMIT_RESULT_SUCCESS;
2411 Any aAny;
2412 aAny <<= (rtl::OUString) pElement->m_aName;
2413 pContent->setPropertyValue( ::rtl::OUString::createFromAscii("Title"), aAny );
2414 }
2415
2416 if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() )
2417 {
2418 // mediatype of the element was changed
2419 nLocalRet = COMMIT_RESULT_SUCCESS;
2420 Any aAny;
2421 aAny <<= (rtl::OUString) pElement->GetContentType();
2422 pContent->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
2423 }
2424
2425 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2426 nRet = nLocalRet;
2427 }
2428
2429 if ( bDeleteContent )
2430 // content was created inside the loop
2431 delete pContent;
2432
2433 if ( nRet == COMMIT_RESULT_FAILURE )
2434 break;
2435
2436 pElement = m_aChildrenList.Next();
2437 }
2438 }
2439 catch ( ContentCreationException& )
2440 {
2441 // content could not be created
2442 SetError( ERRCODE_IO_NOTEXISTS );
2443 return COMMIT_RESULT_FAILURE;
2444 }
2445 catch ( CommandAbortedException& )
2446 {
2447 // any command wasn't executed successfully - not specified
2448 SetError( ERRCODE_IO_GENERAL );
2449 return COMMIT_RESULT_FAILURE;
2450 }
2451 catch ( RuntimeException& )
2452 {
2453 // any other error - not specified
2454 SetError( ERRCODE_IO_GENERAL );
2455 return COMMIT_RESULT_FAILURE;
2456 }
2457 catch ( Exception& )
2458 {
2459 // any other error - not specified
2460 SetError( ERRCODE_IO_GENERAL );
2461 return COMMIT_RESULT_FAILURE;
2462 }
2463
2464 if ( m_bIsRoot && m_pContent )
2465 {
2466 // the root storage must flush the root package content
2467 if ( nRet == COMMIT_RESULT_SUCCESS )
2468 {
2469 try
2470 {
2471 // commit the media type to the JAR file
2472 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2473 Any aType;
2474 aType <<= (rtl::OUString) m_aContentType;
2475 m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType );
2476
2477 if ( m_bIsLinked )
2478 {
2479 // write a manifest file
2480 // first create a subfolder "META-inf"
2481 Content aNewSubFolder;
2482 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, String::CreateFromAscii("META-INF"), aNewSubFolder );
2483 if ( bRet )
2484 {
2485 // create a stream to write the manifest file - use a temp file
2486 String aURL( aNewSubFolder.getURL() );
2487 ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL );
2488
2489 // get the stream from the temp file and create an output stream wrapper
2490 SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE );
2491 ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2492 com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper );
2493
2494 // create a manifest writer object that will fill the stream
2495 Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter =
2496 Reference< ::com::sun::star::packages::manifest::XManifestWriter >
2497 ( ::comphelper::getProcessServiceFactory()->createInstance(
2498 ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestWriter" )), UNO_QUERY) ;
2499 sal_Int32 nCount = GetObjectCount() + 1;
2500 Sequence < Sequence < PropertyValue > > aProps( nCount );
2501 sal_Int32 nProps = 0;
2502 GetProps( nProps, aProps, String() );
2503 xWriter->writeManifestSequence( xOutputStream, aProps );
2504
2505 // move the stream to its desired location
2506 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
2507 xWriter = NULL;
2508 xOutputStream = NULL;
2509 DELETEZ( pTempFile );
2510 aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE );
2511 }
2512 }
2513 else
2514 {
2515 #if OSL_DEBUG_LEVEL > 1
2516 fprintf ( stderr, "Files: %i\n", nOpenFiles );
2517 fprintf ( stderr, "Streams: %i\n", nOpenStreams );
2518 #endif
2519 // force writing
2520 Any aAny;
2521 m_pContent->executeCommand( ::rtl::OUString::createFromAscii("flush"), aAny );
2522 if ( m_pSource != 0 )
2523 {
2524 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ );
2525 m_pSource->SetStreamSize(0);
2526 // m_pSource->Seek(0);
2527 *pStream >> *m_pSource;
2528 DELETEZ( pStream );
2529 m_pSource->Seek(0);
2530 }
2531 }
2532 }
2533 catch ( CommandAbortedException& )
2534 {
2535 // how to tell the content : forget all changes ?!
2536 // or should we assume that the content does it by itself because he throwed an exception ?!
2537 // any command wasn't executed successfully - not specified
2538 SetError( ERRCODE_IO_GENERAL );
2539 return COMMIT_RESULT_FAILURE;
2540 }
2541 catch ( RuntimeException& )
2542 {
2543 // how to tell the content : forget all changes ?!
2544 // or should we assume that the content does it by itself because he throwed an exception ?!
2545 // any other error - not specified
2546 SetError( ERRCODE_IO_GENERAL );
2547 return COMMIT_RESULT_FAILURE;
2548 }
2549 catch ( InteractiveIOException& r )
2550 {
2551 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2552 SetError( ERRCODE_IO_ACCESSDENIED );
2553 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2554 SetError( ERRCODE_IO_NOTEXISTS );
2555 else if ( r.Code == IOErrorCode_CANT_READ )
2556 SetError( ERRCODE_IO_CANTREAD );
2557 else if ( r.Code == IOErrorCode_CANT_WRITE )
2558 SetError( ERRCODE_IO_CANTWRITE );
2559 else
2560 SetError( ERRCODE_IO_GENERAL );
2561
2562 return COMMIT_RESULT_FAILURE;
2563 }
2564 catch ( Exception& )
2565 {
2566 // how to tell the content : forget all changes ?!
2567 // or should we assume that the content does it by itself because he throwed an exception ?!
2568 // any other error - not specified
2569 SetError( ERRCODE_IO_GENERAL );
2570 return COMMIT_RESULT_FAILURE;
2571 }
2572 }
2573 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2574 {
2575 // how to tell the content : forget all changes ?! Should we ?!
2576 SetError( ERRCODE_IO_GENERAL );
2577 return nRet;
2578 }
2579
2580 // after successful root commit all elements names and types are adjusted and all removed elements
2581 // are also removed from the lists
2582 UCBStorageElement_Impl* pInnerElement = m_aChildrenList.First();
2583 sal_Bool bRet = sal_True;
2584 while ( pInnerElement && bRet )
2585 {
2586 UCBStorageElement_Impl* pNext = m_aChildrenList.Next();
2587 if ( pInnerElement->m_bIsRemoved )
2588 {
2589 // is this correct use of our list class ?!
2590 m_aChildrenList.Remove( pInnerElement );
2591 }
2592 else
2593 {
2594 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2595 pInnerElement->m_bIsInserted = sal_False;
2596 }
2597
2598 pInnerElement = pNext;
2599 }
2600 }
2601
2602 m_bCommited = sal_False;
2603 }
2604
2605 return nRet;
2606 }
2607
2608 sal_Bool UCBStorage_Impl::Revert()
2609 {
2610 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2611 sal_Bool bRet = sal_True;
2612 while ( pElement && bRet )
2613 {
2614 pElement->m_bIsRemoved = sal_False;
2615 if ( pElement->m_bIsInserted )
2616 {
2617 m_aChildrenList.Remove( pElement ); // correct usage of list ???
2618 }
2619 else
2620 {
2621 if ( pElement->m_xStream.Is() )
2622 {
2623 pElement->m_xStream->m_bCommited = sal_False;
2624 pElement->m_xStream->Revert();
2625 }
2626 else if ( pElement->m_xStorage.Is() )
2627 {
2628 pElement->m_xStorage->m_bCommited = sal_False;
2629 pElement->m_xStorage->Revert();
2630 }
2631
2632 pElement->m_aName = pElement->m_aOriginalName;
2633 pElement->m_bIsRemoved = sal_False;
2634 }
2635
2636 pElement = m_aChildrenList.Next();
2637 }
2638
2639 return bRet;
2640 }
2641
2642 const String& UCBStorage::GetName() const
2643 {
2644 return pImp->m_aName; // pImp->m_aURL ?!
2645 }
2646
2647 sal_Bool UCBStorage::IsRoot() const
2648 {
2649 return pImp->m_bIsRoot;
2650 }
2651
2652 void UCBStorage::SetDirty()
2653 {
2654 pImp->m_bDirty = sal_True;
2655 }
2656
2657 void UCBStorage::SetClass( const SvGlobalName & rClass, sal_uLong nOriginalClipFormat, const String & rUserTypeName )
2658 {
2659 pImp->m_aClassId = rClass;
2660 pImp->m_nFormat = nOriginalClipFormat;
2661 pImp->m_aUserTypeName = rUserTypeName;
2662
2663 // in UCB storages only the content type will be stored, all other information can be reconstructed
2664 // ( see the UCBStorage_Impl::Init() method )
2665 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2666 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2667 pImp->m_aContentType = aDataFlavor.MimeType;
2668 }
2669
2670 void UCBStorage::SetClassId( const ClsId& rClsId )
2671 {
2672 pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId );
2673 if ( pImp->m_aClassId == SvGlobalName() )
2674 return;
2675
2676 // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2677 // stored in one the substreams
2678 // UCB storages store the content type information as content type in the manifest file and so this information must be
2679 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2680 // the content type
2681 pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2682 if ( pImp->m_nFormat )
2683 {
2684 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2685 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2686 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2687 pImp->m_aContentType = aDataFlavor.MimeType;
2688 }
2689 }
2690
2691 const ClsId& UCBStorage::GetClassId() const
2692 {
2693 return ( const ClsId& ) pImp->m_aClassId.GetCLSID();
2694 }
2695
2696 void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, sal_uLong /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ )
2697 {
2698 // ???
2699 }
2700
2701 sal_Bool UCBStorage::ShouldConvert()
2702 {
2703 // ???
2704 return sal_False;
2705 }
2706
2707 SvGlobalName UCBStorage::GetClassName()
2708 {
2709 return pImp->m_aClassId;
2710 }
2711
2712 sal_uLong UCBStorage::GetFormat()
2713 {
2714 return pImp->m_nFormat;
2715 }
2716
2717 String UCBStorage::GetUserName()
2718 {
2719 DBG_ERROR("UserName is not implemented in UCB storages!" );
2720 return pImp->m_aUserTypeName;
2721 }
2722
2723 void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2724 {
2725 // put information in childrenlist into StorageInfoList
2726 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2727 while ( pElement )
2728 {
2729 if ( !pElement->m_bIsRemoved )
2730 {
2731 // problem: what about the size of a substorage ?!
2732 sal_uLong nSize = pElement->m_nSize;
2733 if ( pElement->m_xStream.Is() )
2734 nSize = pElement->m_xStream->GetSize();
2735 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2736 pList->Append( aInfo );
2737 }
2738
2739 pElement = pImp->m_aChildrenList.Next();
2740 }
2741 }
2742
2743 sal_Bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const String& rNew ) const
2744 {
2745 // insert stream or storage into the list or stream of the destination storage
2746 // not into the content, this will be done on commit !
2747 // be aware of name changes !
2748 if ( !rElement.m_bIsStorage )
2749 {
2750 // copy the streams data
2751 // the destination stream must not be open
2752 BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2753 BaseStorageStream* pStream = NULL;
2754 sal_Bool bDeleteStream = sal_False;
2755
2756 // if stream is already open, it is allowed to copy it, so be aware of this
2757 if ( rElement.m_xStream.Is() )
2758 pStream = rElement.m_xStream->m_pAntiImpl;
2759 if ( !pStream )
2760 {
2761 pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect );
2762 bDeleteStream = sal_True;
2763 }
2764
2765 pStream->CopyTo( pOtherStream );
2766 SetError( pStream->GetError() );
2767 if( pOtherStream->GetError() )
2768 pDest->SetError( pOtherStream->GetError() );
2769 else
2770 pOtherStream->Commit();
2771
2772 if ( bDeleteStream )
2773 delete pStream;
2774 delete pOtherStream;
2775 }
2776 else
2777 {
2778 // copy the storage content
2779 // the destination storage must not be open
2780 BaseStorage* pStorage = NULL;
2781
2782 // if stream is already open, it is allowed to copy it, so be aware of this
2783 sal_Bool bDeleteStorage = sal_False;
2784 if ( rElement.m_xStorage.Is() )
2785 pStorage = rElement.m_xStorage->m_pAntiImpl;
2786 if ( !pStorage )
2787 {
2788 pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2789 bDeleteStorage = sal_True;
2790 }
2791
2792 UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
2793 UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );
2794
2795 sal_Bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2796 BaseStorage* pOtherStorage = bOpenUCBStorage ?
2797 pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) :
2798 pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2799
2800 // For UCB storages, the class id and the format id may differ,
2801 // do passing the class id is not sufficient.
2802 if( bOpenUCBStorage )
2803 pOtherStorage->SetClass( pStorage->GetClassName(),
2804 pStorage->GetFormat(),
2805 pUCBCopy->pImp->m_aUserTypeName );
2806 else
2807 pOtherStorage->SetClassId( pStorage->GetClassId() );
2808 pStorage->CopyTo( pOtherStorage );
2809 SetError( pStorage->GetError() );
2810 if( pOtherStorage->GetError() )
2811 pDest->SetError( pOtherStorage->GetError() );
2812 else
2813 pOtherStorage->Commit();
2814
2815 if ( bDeleteStorage )
2816 delete pStorage;
2817 delete pOtherStorage;
2818 }
2819
2820 return sal_Bool( Good() && pDest->Good() );
2821 }
2822
2823 UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const String& rName ) const
2824 {
2825 DBG_ASSERT( rName.Len(), "Name is empty!" );
2826 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2827 while ( pElement )
2828 {
2829 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2830 break;
2831 pElement = pImp->m_aChildrenList.Next();
2832 }
2833
2834 return pElement;
2835 }
2836
2837 sal_Bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2838 {
2839 DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
2840 if ( pDestStg == ((BaseStorage*)this) )
2841 return sal_False;
2842
2843 // perhaps it's also a problem if one storage is a parent of the other ?!
2844 // or if not: could be optimized ?!
2845
2846 // For UCB storages, the class id and the format id may differ,
2847 // do passing the class id is not sufficient.
2848 if( pDestStg->ISA( UCBStorage ) )
2849 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2850 pImp->m_aUserTypeName );
2851 else
2852 pDestStg->SetClassId( GetClassId() );
2853 pDestStg->SetDirty();
2854
2855 sal_Bool bRet = sal_True;
2856 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2857 while ( pElement && bRet )
2858 {
2859 if ( !pElement->m_bIsRemoved )
2860 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2861 pElement = pImp->m_aChildrenList.Next();
2862 }
2863
2864 if( !bRet )
2865 SetError( pDestStg->GetError() );
2866 return sal_Bool( Good() && pDestStg->Good() );
2867 }
2868
2869 sal_Bool UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew )
2870 {
2871 if( !rElemName.Len() )
2872 return sal_False;
2873
2874 if ( pDest == ((BaseStorage*) this) )
2875 {
2876 // can't double an element
2877 return sal_False;
2878 }
2879 else
2880 {
2881 // for copying no optimization is useful, because in every case the stream data must be copied
2882 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2883 if ( pElement )
2884 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2885 else
2886 {
2887 SetError( SVSTREAM_FILE_NOT_FOUND );
2888 return sal_False;
2889 }
2890 }
2891 }
2892
2893 sal_Bool UCBStorage::Commit()
2894 {
2895 // mark this storage for sending it on root commit
2896 pImp->m_bCommited = sal_True;
2897 if ( pImp->m_bIsRoot )
2898 // the root storage coordinates committing by sending a Commit command to its content
2899 return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2900 else
2901 return sal_True;
2902 }
2903
2904 sal_Bool UCBStorage::Revert()
2905 {
2906 return pImp->Revert();
2907 }
2908
2909 BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
2910 {
2911 if( !rEleName.Len() )
2912 return NULL;
2913
2914 // try to find the storage element
2915 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2916 if ( !pElement )
2917 {
2918 // element does not exist, check if creation is allowed
2919 if( ( nMode & STREAM_NOCREATE ) )
2920 {
2921 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2922 String aName( pImp->m_aURL );
2923 aName += '/';
2924 aName += rEleName;
2925 UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2926 pStream->SetError( GetError() );
2927 pStream->pImp->m_aName = rEleName;
2928 return pStream;
2929 }
2930 else
2931 {
2932 // create a new UCBStorageElement and insert it into the list
2933 pElement = new UCBStorageElement_Impl( rEleName );
2934 pElement->m_bIsInserted = sal_True;
2935 pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
2936 }
2937 }
2938
2939 if ( pElement && !pElement->m_bIsFolder )
2940 {
2941 // check if stream is already created
2942 if ( pElement->m_xStream.Is() )
2943 {
2944 // stream has already been created; if it has no external reference, it may be opened another time
2945 if ( pElement->m_xStream->m_pAntiImpl )
2946 {
2947 DBG_ERROR("Stream is already open!" );
2948 SetError( SVSTREAM_ACCESS_DENIED ); // ???
2949 return NULL;
2950 }
2951 else
2952 {
2953 // check if stream is opened with the same keyword as before
2954 // if not, generate a new stream because it could be encrypted vs. decrypted!
2955 ByteString aKey;
2956 if ( pKey )
2957 aKey = *pKey;
2958 if ( pElement->m_xStream->m_aKey == aKey )
2959 {
2960 pElement->m_xStream->PrepareCachedForReopen( nMode );
2961
2962 // DBG_ASSERT( bDirect == pElement->m_xStream->m_bDirect, "Wrong DirectMode!" );
2963 return new UCBStorageStream( pElement->m_xStream );
2964 }
2965 }
2966 }
2967
2968 // stream is opened the first time
2969 pImp->OpenStream( pElement, nMode, bDirect, pKey );
2970
2971 // if name has been changed before creating the stream: set name!
2972 pElement->m_xStream->m_aName = rEleName;
2973 return new UCBStorageStream( pElement->m_xStream );
2974 }
2975
2976 return NULL;
2977 }
2978
2979 UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
2980 {
2981 String aName( m_aURL );
2982 aName += '/';
2983 aName += pElement->m_aOriginalName;
2984 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler );
2985 return pElement->m_xStream;
2986 }
2987
2988 BaseStorage* UCBStorage::OpenUCBStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
2989 {
2990 if( !rEleName.Len() )
2991 return NULL;
2992
2993 return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
2994 }
2995
2996 BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
2997 {
2998 if( !rEleName.Len() )
2999 return NULL;
3000
3001 return OpenStorage_Impl( rEleName, nMode, bDirect, sal_False );
3002 }
3003
3004 BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
3005 {
3006 if( !rEleName.Len() )
3007 return NULL;
3008
3009 return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
3010 }
3011
3012 BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, sal_Bool bDirect, sal_Bool bForceUCBStorage )
3013 {
3014 // try to find the storage element
3015 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3016 if ( !pElement )
3017 {
3018 // element does not exist, check if creation is allowed
3019 if( ( nMode & STREAM_NOCREATE ) )
3020 {
3021 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3022 String aName( pImp->m_aURL );
3023 aName += '/';
3024 aName += rEleName; // ???
3025 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3026 pStorage->pImp->m_bIsRoot = sal_False;
3027 pStorage->pImp->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3028 pStorage->SetError( GetError() );
3029 return pStorage;
3030 }
3031
3032 // create a new UCBStorageElement and insert it into the list
3033 // problem: perhaps an OLEStorage should be created ?!
3034 // Because nothing is known about the element that should be created, an external parameter is needed !
3035 pElement = new UCBStorageElement_Impl( rEleName );
3036 pElement->m_bIsInserted = sal_True;
3037 pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
3038 }
3039
3040 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
3041 {
3042 // create OLE storages on a stream ( see ctor of SotStorage )
3043 // Such a storage will be created on a UCBStorageStream; it will write into the stream
3044 // if it is opened in direct mode or when it is committed. In this case the stream will be
3045 // modified and then it MUST be treated as committed.
3046 if ( !pElement->m_xStream.Is() )
3047 {
3048 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
3049 UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr );
3050 if ( !pStream )
3051 {
3052 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3053 return NULL;
3054 }
3055
3056 pElement->m_xStream = pStream->pImp;
3057 delete pStream;
3058 }
3059
3060 pElement->m_xStream->PrepareCachedForReopen( nMode );
3061 pElement->m_xStream->Init();
3062
3063 pElement->m_bIsStorage = sal_True;
3064 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
3065 }
3066 else if ( pElement->m_xStorage.Is() )
3067 {
3068 // storage has already been opened; if it has no external reference, it may be opened another time
3069 if ( pElement->m_xStorage->m_pAntiImpl )
3070 {
3071 DBG_ERROR("Storage is already open!" );
3072 SetError( SVSTREAM_ACCESS_DENIED ); // ???
3073 }
3074 else
3075 {
3076 sal_Bool bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0);
3077 if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 ))
3078 {
3079 String aName( pImp->m_aURL );
3080 aName += '/';
3081 aName += pElement->m_aOriginalName;
3082 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3083 pElement->m_xStorage = pStorage->pImp;
3084 return pStorage;
3085 }
3086 else
3087 {
3088 // DBG_ASSERT( bDirect == pElement->m_xStorage->m_bDirect, "Wrong DirectMode!" );
3089 return new UCBStorage( pElement->m_xStorage );
3090 }
3091 }
3092 }
3093 else if ( !pElement->m_xStream.Is() )
3094 {
3095 // storage is opened the first time
3096 sal_Bool bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 );
3097 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
3098 {
3099 // make sure that the root storage object has been created before substorages will be created
3100 INetURLObject aFolderObj( pImp->m_aURL );
3101 String aName = aFolderObj.GetName();
3102 aFolderObj.removeSegment();
3103
3104 Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >() );
3105 pImp->m_pContent = new Content;
3106 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
3107 if ( !bRet )
3108 {
3109 SetError( SVSTREAM_CANNOT_MAKE );
3110 return NULL;
3111 }
3112 }
3113
3114 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
3115 if ( pStor )
3116 {
3117 if ( pElement->m_bIsInserted )
3118 pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3119
3120 return new UCBStorage( pStor );
3121 }
3122 }
3123
3124 return NULL;
3125 }
3126
3127 UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect )
3128 {
3129 UCBStorage_Impl* pRet = NULL;
3130 String aName( m_aURL );
3131 aName += '/';
3132 aName += pElement->m_aOriginalName; // ???
3133
3134 pElement->m_bIsStorage = pElement->m_bIsFolder = sal_True;
3135
3136 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
3137 {
3138 Content aNewFolder;
3139 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
3140 if ( bRet )
3141 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
3142 }
3143 else
3144 {
3145 pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
3146 }
3147
3148 if ( pRet )
3149 {
3150 pRet->m_bIsLinked = m_bIsLinked;
3151 pRet->m_bIsRoot = sal_False;
3152
3153 // if name has been changed before creating the stream: set name!
3154 pRet->m_aName = pElement->m_aOriginalName;
3155 pElement->m_xStorage = pRet;
3156 }
3157
3158 if ( pRet )
3159 pRet->Init();
3160
3161 return pRet;
3162 }
3163
3164 sal_Bool UCBStorage::IsStorage( const String& rEleName ) const
3165 {
3166 if( !rEleName.Len() )
3167 return sal_False;
3168
3169 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3170 return ( pElement && pElement->m_bIsStorage );
3171 }
3172
3173 sal_Bool UCBStorage::IsStream( const String& rEleName ) const
3174 {
3175 if( !rEleName.Len() )
3176 return sal_False;
3177
3178 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3179 return ( pElement && !pElement->m_bIsStorage );
3180 }
3181
3182 sal_Bool UCBStorage::IsContained( const String & rEleName ) const
3183 {
3184 if( !rEleName.Len() )
3185 return sal_False;
3186 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3187 return ( pElement != NULL );
3188 }
3189
3190 sal_Bool UCBStorage::Remove( const String& rEleName )
3191 {
3192 if( !rEleName.Len() )
3193 return sal_False;
3194
3195 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3196 if ( pElement )
3197 {
3198 pElement->m_bIsRemoved = sal_True;
3199 }
3200 else
3201 SetError( SVSTREAM_FILE_NOT_FOUND );
3202
3203 return ( pElement != NULL );
3204 }
3205
3206 sal_Bool UCBStorage::Rename( const String& rEleName, const String& rNewName )
3207 {
3208 if( !rEleName.Len()|| !rNewName.Len() )
3209 return sal_False;
3210
3211 UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
3212 if ( pAlreadyExisting )
3213 {
3214 SetError( SVSTREAM_ACCESS_DENIED );
3215 return sal_False; // can't change to a name that is already used
3216 }
3217
3218 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3219 if ( pElement )
3220 {
3221 pElement->m_aName = rNewName;
3222 }
3223 else
3224 SetError( SVSTREAM_FILE_NOT_FOUND );
3225
3226 return pElement != NULL;
3227 }
3228
3229 sal_Bool UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName )
3230 {
3231 if( !rEleName.Len() || !rNewName.Len() )
3232 return sal_False;
3233
3234 if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
3235 {
3236 return Rename( rEleName, rNewName );
3237 }
3238 else
3239 {
3240 /*
3241 if ( PTR_CAST( UCBStorage, pNewSt ) )
3242 {
3243 // because the element is moved, not copied, a special optimization is possible :
3244 // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3245 // clear original name/type of the new element
3246 // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3247 // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3248 // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3249 // belong to the new content
3250 // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3251 // stream of the destination object
3252 // Not implemented at the moment ( risky?! ), perhaps later
3253 }
3254 */
3255 // MoveTo is done by first copying to the new destination and then removing the old element
3256 sal_Bool bRet = CopyTo( rEleName, pNewSt, rNewName );
3257 if ( bRet )
3258 bRet = Remove( rEleName );
3259 return bRet;
3260 }
3261 }
3262
3263 sal_Bool UCBStorage::ValidateFAT()
3264 {
3265 // ???
3266 return sal_True;
3267 }
3268
3269 sal_Bool UCBStorage::Validate( sal_Bool bWrite ) const
3270 {
3271 // ???
3272 return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
3273 }
3274
3275 sal_Bool UCBStorage::ValidateMode( StreamMode m ) const
3276 {
3277 // ???
3278 if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
3279 return sal_True;
3280 sal_uInt16 nCurMode = 0xFFFF;
3281 if( ( m & 3 ) == STREAM_READ )
3282 {
3283 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3284 if( ( ( m & STREAM_SHARE_DENYWRITE )
3285 && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
3286 || ( ( m & STREAM_SHARE_DENYALL )
3287 && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
3288 return sal_True;
3289 }
3290 else
3291 {
3292 // only SHARE_DENYALL allowed
3293 // storages open in r/o mode are OK, since only
3294 // the commit may fail
3295 if( ( m & STREAM_SHARE_DENYALL )
3296 && ( nCurMode & STREAM_SHARE_DENYALL ) )
3297 return sal_True;
3298 }
3299
3300 return sal_True;
3301 }
3302
3303 const SvStream* UCBStorage::GetSvStream() const
3304 {
3305 // this would cause a complete download of the file
3306 // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3307 return pImp->m_pSource;
3308 }
3309
3310 sal_Bool UCBStorage::Equals( const BaseStorage& rStorage ) const
3311 {
3312 // ???
3313 return ((BaseStorage*)this) == &rStorage;
3314 }
3315
3316 sal_Bool UCBStorage::IsStorageFile( const String& rFileName )
3317 {
3318 String aFileURL = rFileName;
3319 INetURLObject aObj( aFileURL );
3320 if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
3321 {
3322 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFileName, aFileURL );
3323 aObj.SetURL( aFileURL );
3324 aFileURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3325 }
3326
3327 SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_STD_READ );
3328 sal_Bool bRet = UCBStorage::IsStorageFile( pStm );
3329 delete pStm;
3330 return bRet;
3331 }
3332
3333 sal_Bool UCBStorage::IsStorageFile( SvStream* pFile )
3334 {
3335 if ( !pFile )
3336 return sal_False;
3337
3338 sal_uLong nPos = pFile->Tell();
3339 pFile->Seek( STREAM_SEEK_TO_END );
3340 if ( pFile->Tell() < 4 )
3341 return sal_False;
3342
3343 pFile->Seek(0);
3344 sal_uInt32 nBytes;
3345 *pFile >> nBytes;
3346
3347 // search for the magic bytes
3348 sal_Bool bRet = ( nBytes == 0x04034b50 );
3349 if ( !bRet )
3350 {
3351 // disk spanned file have an additional header in front of the usual one
3352 bRet = ( nBytes == 0x08074b50 );
3353 if ( bRet )
3354 {
3355 *pFile >> nBytes;
3356 bRet = ( nBytes == 0x04034b50 );
3357 }
3358 }
3359
3360 pFile->Seek( nPos );
3361 return bRet;
3362 }
3363
3364 sal_Bool UCBStorage::IsDiskSpannedFile( SvStream* pFile )
3365 {
3366 if ( !pFile )
3367 return sal_False;
3368
3369 sal_uLong nPos = pFile->Tell();
3370 pFile->Seek( STREAM_SEEK_TO_END );
3371 if ( !pFile->Tell() )
3372 return sal_False;
3373
3374 pFile->Seek(0);
3375 sal_uInt32 nBytes;
3376 *pFile >> nBytes;
3377
3378 // disk spanned file have an additional header in front of the usual one
3379 sal_Bool bRet = ( nBytes == 0x08074b50 );
3380 if ( bRet )
3381 {
3382 *pFile >> nBytes;
3383 bRet = ( nBytes == 0x04034b50 );
3384 }
3385
3386 pFile->Seek( nPos );
3387 return bRet;
3388 }
3389
3390 String UCBStorage::GetLinkedFile( SvStream &rStream )
3391 {
3392 String aString;
3393 sal_uLong nPos = rStream.Tell();
3394 rStream.Seek( STREAM_SEEK_TO_END );
3395 if ( !rStream.Tell() )
3396 return aString;
3397
3398 rStream.Seek(0);
3399 sal_uInt32 nBytes;
3400 rStream >> nBytes;
3401 if( nBytes == 0x04034b50 )
3402 {
3403 ByteString aTmp;
3404 rStream.ReadByteString( aTmp );
3405 if ( aTmp.CompareTo( "ContentURL=", 11 ) == COMPARE_EQUAL )
3406 {
3407 aTmp.Erase( 0, 11 );
3408 aString = String( aTmp, RTL_TEXTENCODING_UTF8 );
3409 }
3410 }
3411
3412 rStream.Seek( nPos );
3413 return aString;
3414 }
3415
3416 String UCBStorage::CreateLinkFile( const String& rName )
3417 {
3418 // create a stream to write the link file - use a temp file, because it may be no file content
3419 INetURLObject aFolderObj( rName );
3420 String aName = aFolderObj.GetName();
3421 aFolderObj.removeSegment();
3422 String aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) );
3423 ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL );
3424
3425 // get the stream from the temp file
3426 SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC );
3427
3428 // write header
3429 *pStream << ( sal_uInt32 ) 0x04034b50;
3430
3431 // assemble a new folder name in the destination folder
3432 INetURLObject aObj( rName );
3433 String aTmpName = aObj.GetName();
3434 String aTitle = String::CreateFromAscii( "content." );
3435 aTitle += aTmpName;
3436
3437 // create a folder and store its URL
3438 Content aFolder( aFolderURL, Reference < XCommandEnvironment >() );
3439 Content aNewFolder;
3440 sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
3441 if ( !bRet )
3442 {
3443 aFolderObj.insertName( aTitle );
3444 if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3445 {
3446 // Hack, because already existing files give the same CommandAbortedException as any other error !
3447 // append a number until the name can be used for a new folder
3448 aTitle += '.';
3449 for ( sal_Int32 i=0; !bRet; i++ )
3450 {
3451 String aTmp( aTitle );
3452 aTmp += String::CreateFromInt32( i );
3453 bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder );
3454 if ( bRet )
3455 aTitle = aTmp;
3456 else
3457 {
3458 aFolderObj.SetName( aTmp );
3459 if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3460 // Hack, because already existing files give the same CommandAbortedException as any other error !
3461 break;
3462 }
3463 }
3464 }
3465 }
3466
3467 if ( bRet )
3468 {
3469 // get the URL
3470 aObj.SetName( aTitle );
3471 String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3472
3473 // store it as key/value pair
3474 String aLink = String::CreateFromAscii("ContentURL=");
3475 aLink += aURL;
3476 pStream->WriteByteString( aLink, RTL_TEXTENCODING_UTF8 );
3477 pStream->Flush();
3478
3479 // move the stream to its desired location
3480 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
3481 DELETEZ( pTempFile );
3482 aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE );
3483 return aURL;
3484 }
3485
3486 pTempFile->EnableKillingFile( sal_True );
3487 delete pTempFile;
3488 return String();
3489 }
3490
3491 sal_Bool UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
3492 {
3493 if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
3494 return sal_False;
3495
3496 if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
3497 {
3498 ::rtl::OUString aTmp;
3499 rValue >>= aTmp;
3500 pImp->m_aContentType = aTmp;
3501 }
3502
3503 try
3504 {
3505 if ( pImp->GetContent() )
3506 {
3507 pImp->m_pContent->setPropertyValue( rName, rValue );
3508 return sal_True;
3509 }
3510 }
3511 catch ( Exception& )
3512 {
3513 }
3514
3515 return sal_False;
3516 }
3517
3518 sal_Bool UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
3519 {
3520 try
3521 {
3522 if ( pImp->GetContent() )
3523 {
3524 rValue = pImp->m_pContent->getPropertyValue( rName );
3525 return sal_True;
3526 }
3527 }
3528 catch ( Exception& )
3529 {
3530 }
3531
3532 return sal_False;
3533 }
3534
3535 sal_Bool UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
3536 {
3537 UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName );
3538 if ( !pEle )
3539 return sal_False;
3540
3541 if ( !pEle->m_bIsFolder )
3542 {
3543 if ( !pEle->m_xStream.Is() )
3544 pImp->OpenStream( pEle, pImp->m_nMode, pImp->m_bDirect );
3545 if ( pEle->m_xStream->m_nError )
3546 {
3547 pEle->m_xStream.Clear();
3548 return sal_False;
3549 }
3550
3551 try
3552 {
3553 if ( pEle->m_xStream->m_pContent )
3554 {
3555 rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName );
3556 return sal_True;
3557 }
3558 }
3559 catch ( Exception& )
3560 {
3561 }
3562 }
3563 else
3564 {
3565 if ( !pEle->m_xStorage.Is() )
3566 pImp->OpenStorage( pEle, pImp->m_nMode, pImp->m_bDirect );
3567 if ( pEle->m_xStorage->m_nError )
3568 {
3569 pEle->m_xStorage.Clear();
3570 return sal_False;
3571 }
3572
3573 try
3574 {
3575 if ( pEle->m_xStorage->GetContent() )
3576 {
3577 rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName );
3578 return sal_True;
3579 }
3580 }
3581 catch ( Exception& )
3582 {
3583 }
3584 }
3585
3586 return sal_False;
3587 }
3588
3589 UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList()
3590 {
3591 if ( !pImp->m_pUNOStorageHolderList )
3592 pImp->m_pUNOStorageHolderList = new UNOStorageHolderList;
3593
3594 return pImp->m_pUNOStorageHolderList;
3595 }
3596
3597