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