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