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