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