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