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