/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base, public comphelper::ByteReader
{ protected:
std::mutex m_aMutex;
OUString m_aURL;
std::unique_ptr<SvStream> m_pSvStream;
static SvGlobalName GetClassId_Impl( SotClipboardFormatId nFormat )
{ switch ( nFormat )
{ case SotClipboardFormatId::STARWRITER_8 : case SotClipboardFormatId::STARWRITER_8_TEMPLATE : return SvGlobalName( SO3_SW_CLASSID_60 ); case SotClipboardFormatId::STARWRITERWEB_8 : return SvGlobalName( SO3_SWWEB_CLASSID_60 ); case SotClipboardFormatId::STARWRITERGLOB_8 : case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE : return SvGlobalName( SO3_SWGLOB_CLASSID_60 ); case SotClipboardFormatId::STARDRAW_8 : case SotClipboardFormatId::STARDRAW_8_TEMPLATE : return SvGlobalName( SO3_SDRAW_CLASSID_60 ); case SotClipboardFormatId::STARIMPRESS_8 : case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE : return SvGlobalName( SO3_SIMPRESS_CLASSID_60 ); case SotClipboardFormatId::STARCALC_8 : case SotClipboardFormatId::STARCALC_8_TEMPLATE : return SvGlobalName( SO3_SC_CLASSID_60 ); case SotClipboardFormatId::STARCHART_8 : case SotClipboardFormatId::STARCHART_8_TEMPLATE : return SvGlobalName( SO3_SCH_CLASSID_60 ); case SotClipboardFormatId::STARMATH_8 : case SotClipboardFormatId::STARMATH_8_TEMPLATE : return SvGlobalName( SO3_SM_CLASSID_60 ); case SotClipboardFormatId::STARWRITER_60 : return SvGlobalName( SO3_SW_CLASSID_60 ); case SotClipboardFormatId::STARWRITERWEB_60 : return SvGlobalName( SO3_SWWEB_CLASSID_60 ); case SotClipboardFormatId::STARWRITERGLOB_60 : return SvGlobalName( SO3_SWGLOB_CLASSID_60 ); case SotClipboardFormatId::STARDRAW_60 : return SvGlobalName( SO3_SDRAW_CLASSID_60 ); case SotClipboardFormatId::STARIMPRESS_60 : return SvGlobalName( SO3_SIMPRESS_CLASSID_60 ); case SotClipboardFormatId::STARCALC_60 : return SvGlobalName( SO3_SC_CLASSID_60 ); case SotClipboardFormatId::STARCHART_60 : return SvGlobalName( SO3_SCH_CLASSID_60 ); case SotClipboardFormatId::STARMATH_60 : return SvGlobalName( SO3_SM_CLASSID_60 ); default : return SvGlobalName();
}
}
// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle // class, that uses the refcounted object as impl-class.
class UCBStorageStream_Impl : public SvRefBase, public SvStream
{ virtual ~UCBStorageStream_Impl() override; public:
UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
OUString m_aOriginalName;// the original name before accessing the stream
OUString m_aName; // the actual name ( changed with a Rename command at the parent )
OUString m_aURL; // the full path name to create the content
OUString m_aContentType;
OUString m_aOriginalContentType;
OString m_aKey;
::ucbhelper::Content* m_pContent; // the content that provides the data
Reference<XInputStream> m_rSource; // the stream covering the original data of the content
std::unique_ptr<SvStream> m_pStream; // the stream worked on; for readonly streams it is the original stream of the content // for read/write streams it's a copy into a temporary file
OUString m_aTempURL; // URL of this temporary stream
ErrCode m_nError;
StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing ) bool m_bSourceRead; // Source still contains useful information bool m_bModified; // only modified streams will be sent to the original content bool m_bCommited; // sending the streams is coordinated by the root storage of the package bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages // this means that the root storage does an autocommit when its external // reference is destroyed bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
void Free(); bool Init(); bool Clear();
sal_Int16 Commit(); // if modified and committed: transfer an XInputStream to the content void Revert(); // discard all changes
BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
sal_uInt64 GetSize();
sal_uInt64 ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary, // no seeking is produced void ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
void CopySourceToTemporary(); // same as ReadSourceWriteToTemporary() // but the writing is done at the end of temporary // pointer position is not changed using SvStream::SetError; void SetError( ErrCode nError ); void PrepareCachedForReopen( StreamMode nMode );
};
class UCBStorage_Impl : public SvRefBase
{ virtual ~UCBStorage_Impl() override; public:
UCBStorage* m_pAntiImpl; // only valid if external references exists
OUString m_aName; // the actual name ( changed with a Rename command at the parent )
OUString m_aURL; // the full path name to create the content
OUString m_aContentType;
OUString m_aOriginalContentType;
std::optional<::ucbhelper::Content> m_oContent; // the content that provides the storage elements
std::unique_ptr<::utl::TempFileNamed> m_pTempFile; // temporary file, only for storages on stream
SvStream* m_pSource; // original stream, only for storages on a stream
ErrCode m_nError;
StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing ) bool m_bCommited; // sending the streams is coordinated by the root storage of the package bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages // this means that the root storage does an autocommit when its external // reference is destroyed bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts bool m_bIsLinked; bool m_bListCreated;
SotClipboardFormatId m_nFormat;
OUString m_aUserTypeName;
SvGlobalName m_aClassId;
// this struct contains all necessary information on an element inside a UCBStorage struct UCBStorageElement_Impl
{
OUString m_aName; // the actual URL relative to the root "folder"
OUString m_aOriginalName;// the original name in the content
sal_uInt64 m_nSize; bool m_bIsFolder; // Only true when it is a UCBStorage ! bool m_bIsStorage; // Also true when it is an OLEStorage ! bool m_bIsRemoved; // element will be removed on commit bool m_bIsInserted; // element will be removed on revert
UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
if ( bRepair )
{
xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
aTemp += "?repairpackage";
}
m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
} catch (const ContentCreationException&)
{ // content could not be created
SetError( SVSTREAM_CANNOT_MAKE );
} catch (const RuntimeException&)
{ // any other error - not specified
SetError( ERRCODE_IO_GENERAL );
}
}
void UCBStorageStream_Impl::ReadSourceWriteTemporary()
{ // read source stream till the end and copy all the data to // the current position of the temporary stream
sal_uInt64 UCBStorageStream_Impl::ReadSourceWriteTemporary(sal_uInt64 aLength)
{ // read aLength byte from the source stream and copy them to the current // position of the temporary stream
void UCBStorageStream_Impl::CopySourceToTemporary()
{ // current position of the temporary stream is not changed if( m_bSourceRead )
{
sal_uInt64 aPos = m_pStream->Tell();
m_pStream->Seek( STREAM_SEEK_TO_END );
ReadSourceWriteTemporary();
m_pStream->Seek( aPos );
}
}
// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
{
std::size_t aResult = 0;
if( !Init() ) return 0;
// read data that is in temporary stream
aResult = m_pStream->ReadBytes( pData, nSize ); if( m_bSourceRead && aResult < nSize )
{ // read the tail of the data from original stream // copy this tail to the temporary stream
sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
{ // check if a truncated STREAM_SEEK_TO_END was passed
assert(nPos != SAL_MAX_UINT32);
if( !Init() ) return 0;
sal_uInt64 aResult;
if( nPos == STREAM_SEEK_TO_END )
{
m_pStream->Seek( STREAM_SEEK_TO_END );
ReadSourceWriteTemporary();
aResult = m_pStream->Tell();
} else
{ // the problem is that even if nPos is larger the length // of the stream, the stream pointer will be moved to this position // so we have to check if temporary stream does not contain required position
if( m_pStream->Tell() > nPos
|| m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
{ // no copying is required
aResult = m_pStream->Seek( nPos );
} else
{ // the temp stream pointer points to the end now
aResult = m_pStream->Tell();
DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
}
if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
{ // it means that all the Source stream was copied already // but the required position still was not reached // for writable streams it should be done
m_pStream->SetStreamSize( nPos );
aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
}
}
}
}
BaseStorage* UCBStorageStream_Impl::CreateStorage()
{ // create an OLEStorage on a SvStream ( = this ) // it gets the root attribute because otherwise it would probably not write before my root is committed
UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
// GetError() call clears error code for OLE storages, must be changed in future const ErrCode nTmpErr = pStorage->GetError();
pStorage->SetError( nTmpErr );
sal_Int16 UCBStorageStream_Impl::Commit()
{ // send stream to the original content // the parent storage is responsible for the correct handling of deleted contents if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
{ // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage // was committed as well ( if not opened in direct mode )
if ( m_bModified )
{ try
{
CopySourceToTemporary();
// release all stream handles
Free();
// the temporary file does not exist only for truncated streams
DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!"); if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) ) throw RuntimeException();
InsertCommandArgument aArg; // create wrapper to stream that is only used while reading inside package component
aArg.Data.set(new FileStreamWrapper_Impl(m_aTempURL));
aArg.ReplaceExisting = true;
m_pContent->executeCommand( u"insert"_ustr, Any(aArg) );
// wrapper now controls lifetime of temporary file
m_aTempURL.clear();
INetURLObject aObj( m_aURL );
aObj.setName( m_aName );
m_aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
m_bModified = false;
m_bSourceRead = true;
} catch (const CommandAbortedException&)
{ // any command wasn't executed successfully - not specified
SetError( ERRCODE_IO_GENERAL ); return COMMIT_RESULT_FAILURE;
} catch (const RuntimeException&)
{ // any other error - not specified
SetError( ERRCODE_IO_GENERAL ); return COMMIT_RESULT_FAILURE;
} catch (const Exception&)
{ // any other error - not specified
SetError( ERRCODE_IO_GENERAL ); return COMMIT_RESULT_FAILURE;
}
void UCBStorageStream_Impl::Revert()
{ // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" ! if ( m_bCommited )
{
OSL_FAIL("Revert while commit is in progress!" ); return; // ???
}
Free(); if ( !m_aTempURL.isEmpty() )
{
osl::File::remove(m_aTempURL);
m_aTempURL.clear();
}
m_bSourceRead = false; try
{
m_rSource = m_pContent->openStream(); if( m_rSource.is() )
{ if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) ) // stream is in use and should be truncated
m_bSourceRead = false; else
{
m_nMode &= ~StreamMode::TRUNC;
m_bSourceRead = true;
}
} else
SetError( SVSTREAM_CANNOT_MAKE );
} catch (const ContentCreationException&)
{
SetError( ERRCODE_IO_GENERAL );
} catch (const RuntimeException&)
{
SetError( ERRCODE_IO_GENERAL );
} catch (const Exception&)
{
}
void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
{ bool isWritable = bool( m_nMode & StreamMode::WRITE ); if ( isWritable )
{ // once stream was writable, never reset to readonly
nMode |= StreamMode::WRITE;
}
m_nMode = nMode;
Free();
if ( nMode & StreamMode::TRUNC )
{
m_bSourceRead = false; // usually it should be 0 already but just in case...
if ( !m_aTempURL.isEmpty() )
{
osl::File::remove(m_aTempURL);
m_aTempURL.clear();
}
}
}
UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
{ // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized // to class UCBStorageStream !
pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
StorageBase::m_nMode = pImp->m_nMode;
}
UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
: pImp( pImpl )
{
pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
pImp->m_pAntiImpl = this;
SetError( pImp->m_nError );
StorageBase::m_nMode = pImp->m_nMode;
}
bool UCBStorageStream::ValidateMode( StreamMode m ) const
{ // ??? if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx returntrue; if( ( m & StreamMode::READWRITE) == StreamMode::READ )
{ // only SHARE_DENYWRITE or SHARE_DENYALL allowed if( ( m & StreamMode::SHARE_DENYWRITE )
|| ( m & StreamMode::SHARE_DENYALL ) ) returntrue;
} else
{ // only SHARE_DENYALL allowed // storages open in r/o mode are OK, since only // the commit may fail if( m & StreamMode::SHARE_DENYALL ) returntrue;
}
UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
{ // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized // to class UCBStorage !
pImp = new UCBStorage_Impl( rStrm, this, bDirect );
UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
{ // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized // to class UCBStorage !
pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
pImp->AddFirstRef();
pImp->Init();
StorageBase::m_nMode = pImp->m_nMode;
}
UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
{ // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized // to class UCBStorage !
pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
pImp->AddFirstRef();
pImp->Init();
StorageBase::m_nMode = pImp->m_nMode;
}
UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
{ // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized // to class UCBStorage !
pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
pImp->AddFirstRef();
pImp->Init();
StorageBase::m_nMode = pImp->m_nMode;
}
UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
: pImp( pImpl )
{
pImp->m_pAntiImpl = this;
SetError( pImp->m_nError );
pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
StorageBase::m_nMode = pImp->m_nMode;
}
UCBStorage::~UCBStorage()
{ if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) ) // DirectMode is simulated with an AutoCommit
Commit();
if ( m_bIsRoot )
{ // create the special package URL for the package content
m_aURL = "vnd.sun.star.pkg://" +
INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
if ( m_nMode & StreamMode::WRITE )
{ // the root storage opens the package, so make sure that there is any
::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
}
} else
{ // substorages are opened like streams: the URL is a "child URL" of the root package URL
m_aURL = rName; if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
m_bIsLinked = true;
}
}
UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
: m_pAntiImpl( pStorage )
, m_pTempFile( new ::utl::TempFileNamed )
, m_pSource( &rStream )
, m_nError( ERRCODE_NONE )
, m_bCommited( false )
, m_bDirect( bDirect )
, m_bIsRoot( true )
, m_bIsLinked( false )
, m_bListCreated( false )
, m_nFormat( SotClipboardFormatId::NONE )
, m_bRepairPackage( false )
{ // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call, // which will be called in the storages' dtor
m_pTempFile->EnableKillingFile();
DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
// UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only // accessed readonly // the root storage opens the package; create the special package URL for the package content
m_aURL = "vnd.sun.star.pkg://" +
INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
// copy data into the temporary file
std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true/* bFileExists */ )); if ( pStream )
{
rStream.Seek(0);
rStream.ReadStream( *pStream );
pStream->Flush();
pStream.reset();
}
// close stream and let content access the file
m_pSource->Seek(0);
void UCBStorage_Impl::Init()
{ // name is last segment in URL
INetURLObject aObj( m_aURL ); if ( m_aName.isEmpty() ) // if the name was not already set to a temp name
m_aName = aObj.GetLastName();
if ( !m_oContent )
CreateContent();
if ( m_oContent )
{ if ( m_bIsLinked )
{ if( m_bIsRoot )
{
ReadContent(); if ( m_nError == ERRCODE_NONE )
{ // read the manifest.xml file
aObj.Append( u"META-INF" );
aObj.Append( u"manifest.xml" );
// create input stream
std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ )); // no stream means no manifest.xml if ( pStream )
{ if ( !pStream->GetError() )
{
rtl::Reference<::utl::OInputStreamWrapper> pHelper = new ::utl::OInputStreamWrapper( *pStream );
// create a manifest reader object that will read in the manifest from the stream
Reference < css::packages::manifest::XManifestReader > xReader =
css::packages::manifest::ManifestReader::create(
::comphelper::getProcessComponentContext() ) ;
Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( pHelper );
// cleanup
xReader = nullptr;
pHelper = nullptr;
SetProps( aProps, OUString() );
}
}
}
} else
ReadContent();
} else
{ // get the manifest information from the package try {
Any aAny = m_oContent->getPropertyValue(u"MediaType"_ustr);
OUString aTmp; if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
m_aContentType = m_aOriginalContentType = aTmp;
} catch (const Exception&)
{
SAL_WARN( "sot", "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
}
}
}
if ( m_aContentType.isEmpty() ) return;
// get the clipboard format using the content type
css::datatransfer::DataFlavor aDataFlavor;
aDataFlavor.MimeType = m_aContentType;
m_nFormat = SotExchange::GetFormat( aDataFlavor );
// get the ClassId using the clipboard format ( internal table )
m_aClassId = GetClassId_Impl( m_nFormat );
// get human presentable name using the clipboard format
SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
m_aUserTypeName = aDataFlavor.HumanPresentableName;
void UCBStorage_Impl::CreateContent()
{ try
{ // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
rtl::Reference< ::ucbhelper::CommandEnvironment > xComEnv;
OUString aTemp( m_aURL );
if ( m_bRepairPackage )
{
xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
m_xProgressHandler );
aTemp += "?repairpackage";
}
m_oContent.emplace( aTemp, xComEnv, comphelper::getProcessComponentContext() );
} catch (const ContentCreationException&)
{ // content could not be created
SetError( SVSTREAM_CANNOT_MAKE );
} catch (const RuntimeException&)
{ // any other error - not specified
SetError( SVSTREAM_CANNOT_MAKE );
}
}
void UCBStorage_Impl::ReadContent()
{ if ( m_bListCreated ) return;
m_bListCreated = true;
try
{
GetContent(); if ( !m_oContent ) return;
// create cursor for access to children
Reference< XResultSet > xResultSet = m_oContent->createCursor( { u"Title"_ustr, u"IsFolder"_ustr, u"MediaType"_ustr, u"Size"_ustr }, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
Reference< XRow > xRow( xResultSet, UNO_QUERY ); if ( xResultSet.is() )
{ while ( xResultSet->next() )
{ // insert all into the children list
OUString aTitle( xRow->getString(1) ); if ( m_bIsLinked )
{ // unpacked storages have to deal with the meta-inf folder by themselves if ( aTitle == "META-INF" ) continue;
}
OUString aMediaType;
Any aAny = aContent.getPropertyValue(u"MediaType"_ustr); if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
pElement->m_bIsStorage = true; elseif ( aMediaType.isEmpty() )
{ // older files didn't have that special content type, so they must be detected
OpenStream( pElement, StreamMode::STD_READ, m_bDirect ); if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
pElement->m_bIsStorage = true; else
pElement->m_xStream->Free();
}
}
}
}
} catch (const InteractiveIOException& r)
{ if ( r.Code != IOErrorCode_NOT_EXISTING )
SetError( ERRCODE_IO_GENERAL );
} catch (const CommandAbortedException&)
{ // any command wasn't executed successfully - not specified if ( !( m_nMode & StreamMode::WRITE ) ) // if the folder was just inserted and not already committed, this is not an error!
SetError( ERRCODE_IO_GENERAL );
} catch (const RuntimeException&)
{ // any other error - not specified
SetError( ERRCODE_IO_GENERAL );
} catch (const ResultSetException&)
{ // means that the package file is broken
SetError( ERRCODE_IO_BROKENPACKAGE );
} catch (const SQLException&)
{ // means that the file can be broken
SetError( ERRCODE_IO_WRONGFORMAT );
} catch (const Exception&)
{ // any other error - not specified
SetError( ERRCODE_IO_GENERAL );
}
}
// get the clipboard format using the content type
css::datatransfer::DataFlavor aDataFlavor;
aDataFlavor.MimeType = m_aContentType;
m_nFormat = SotExchange::GetFormat( aDataFlavor );
// get the ClassId using the clipboard format ( internal table )
m_aClassId = GetClassId_Impl( m_nFormat );
// get human presentable name using the clipboard format
SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
m_aUserTypeName = aDataFlavor.HumanPresentableName;
}
// first my own properties // first property is the "FullPath" name // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
OUString aPath( rPath ); if ( !m_bIsRoot )
aPath += m_aName;
aPath += "/";
Sequence < PropertyValue > aProps{ comphelper::makePropertyValue(u"MediaType"_ustr, m_aContentType),
comphelper::makePropertyValue(u"FullPath"_ustr, aPath) };
pSequence[nProps++] = aProps;
if ( m_bIsRoot ) // the "FullPath" of a child always starts without '/'
aPath.clear();
// now the properties of my elements for (auto& pElement : m_aChildrenList)
{
DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" ); if ( pElement->m_bIsFolder && pElement->m_xStorage.is() ) // storages add there properties by themselves ( see above )
pElement->m_xStorage->GetProps( nProps, rSequence, aPath ); else
{ // properties of streams
OUString aElementPath = aPath + pElement->m_aName;
aProps = { comphelper::makePropertyValue(u"MediaType"_ustr, pElement->GetContentType()),
comphelper::makePropertyValue(u"FullPath"_ustr, aElementPath) };
pSequence[ nProps++ ] = aProps;
}
}
}
bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
{ // a new substorage is inserted into a UCBStorage ( given by the parameter pContent ) // it must be inserted with a title and a type bool bRet = false;
for ( const ContentInfo & rCurr : aInfo )
{ // Simply look for the first KIND_FOLDER... if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
{ // Make sure the only required bootstrap property is "Title", const Sequence< Property > & rProps = rCurr.Properties; if ( rProps.getLength() != 1 ) continue;
// remove old content, create an "empty" new one and initialize it with the new inserted
m_oContent.emplace( aNewFolder );
bRet = true;
}
}
}
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.