summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric Bosdonnat <cedric.bosdonnat@free.fr>2012-05-29 15:18:29 +0200
committerCédric Bosdonnat <cedric.bosdonnat@free.fr>2012-06-04 13:28:12 +0200
commit966d20e35d5a2be2fce6c204af5c156c3ead7063 (patch)
treee23f080a8831d398508d7b1731c315310021aed8
parent12d193df238adaf67608327b36fea91003138539 (diff)
CMIS ucp: write documents back to CMIS server
This change needs a git repo build of libcmis. Change-Id: I I740d18dbf3c36d9387b867e750fcbe8e114e5362
-rw-r--r--sfx2/source/doc/docfile.cxx28
-rw-r--r--ucb/source/ucp/cmis/cmis_content.cxx516
-rw-r--r--ucb/source/ucp/cmis/cmis_content.hxx16
-rw-r--r--ucb/source/ucp/cmis/cmis_provider.cxx31
-rw-r--r--ucb/source/ucp/cmis/cmis_provider.hxx7
-rw-r--r--ucb/source/ucp/cmis/cmis_url.cxx47
-rw-r--r--ucb/source/ucp/cmis/cmis_url.hxx18
-rw-r--r--ucbhelper/Library_ucbhelper.mk2
-rw-r--r--ucbhelper/Package_inc.mk2
-rw-r--r--ucbhelper/inc/ucbhelper/std_inputstream.hxx119
-rw-r--r--ucbhelper/inc/ucbhelper/std_outputstream.hxx73
-rw-r--r--ucbhelper/source/provider/std_inputstream.cxx187
-rw-r--r--ucbhelper/source/provider/std_outputstream.cxx98
13 files changed, 1004 insertions, 140 deletions
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 27d4398da299..6271acd84493 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -33,6 +33,7 @@
#include <com/sun/star/task/XInteractionHandler.hpp>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
#include <com/sun/star/document/LockedDocumentRequest.hpp>
#include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
@@ -1918,6 +1919,7 @@ void SfxMedium::Transfer_Impl()
Reference< ::com::sun::star::ucb::XProgressHandler >() );
rtl::OUString aDestURL( aDest.GetMainURL( INetURLObject::NO_DECODE ) );
+
if ( ::utl::LocalFileHelper::IsLocalFile( aDestURL ) || !aDest.removeSegment() )
{
TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
@@ -1939,8 +1941,30 @@ void SfxMedium::Transfer_Impl()
::ucbhelper::Content aSourceContent;
::ucbhelper::Content aTransferContent;
- String aFileName = GetLongName();
- if ( !aFileName.Len() )
+ // Get the parent URL from the XChild if possible: why would the URL necessarily have
+ // a hierarchical path? It's not the case for CMIS.
+ ::ucbhelper::Content aDestContent;
+ ::ucbhelper::Content::create( aDestURL, xComEnv, aDestContent );
+ Reference< ::com::sun::star::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
+ rtl::OUString sParentUrl;
+ if ( xChild.is( ) )
+ {
+ Reference< ::com::sun::star::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
+ if ( xParent.is( ) )
+ {
+ sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
+ }
+ }
+
+ if ( !sParentUrl.isEmpty() )
+ aDest = INetURLObject( sParentUrl );
+
+ // LongName wasn't defined anywhere, only used here... get the Title instead
+ // as it's less probably empty
+ rtl::OUString aFileName;
+ Any aAny = aDestContent.getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Title" )) );
+ aAny >>= aFileName;
+ if ( aFileName.isEmpty() )
aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
try
diff --git a/ucb/source/ucp/cmis/cmis_content.cxx b/ucb/source/ucp/cmis/cmis_content.cxx
index 8c12f93157b8..ead9f2da4ab0 100644
--- a/ucb/source/ucp/cmis/cmis_content.cxx
+++ b/ucb/source/ucp/cmis/cmis_content.cxx
@@ -32,10 +32,19 @@
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/ucb/ContentInfo.hpp>
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
+#include <com/sun/star/ucb/MissingInputStreamException.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/ucb/NameClashException.hpp>
#include <com/sun/star/ucb/OpenMode.hpp>
#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
+#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
#include <com/sun/star/ucb/XCommandInfo.hpp>
#include <com/sun/star/ucb/XDynamicResultSet.hpp>
@@ -44,17 +53,80 @@
#include <ucbhelper/cancelcommandexecution.hxx>
#include <ucbhelper/contentidentifier.hxx>
-#include <ucbhelper/fd_inputstream.hxx>
+#include <ucbhelper/std_inputstream.hxx>
+#include <ucbhelper/std_outputstream.hxx>
#include <ucbhelper/propertyvalueset.hxx>
+#include <ucbhelper/simpleauthenticationrequest.hxx>
#include "cmis_content.hxx"
#include "cmis_provider.hxx"
-#include "cmis_url.hxx"
+#define OUSTR_TO_STDSTR(s) string( rtl::OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
using namespace com::sun::star;
using namespace std;
+namespace
+{
+ class AuthProvider : public libcmis::AuthProvider
+ {
+ const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment>& m_xEnv;
+ rtl::OUString m_sUrl;
+ rtl::OUString m_sBindingUrl;
+
+ public:
+ AuthProvider ( const com::sun::star::uno::Reference<
+ com::sun::star::ucb::XCommandEnvironment>& xEnv,
+ rtl::OUString sUrl,
+ rtl::OUString sBindingUrl ):
+ m_xEnv( xEnv ), m_sUrl( sUrl ), m_sBindingUrl( sBindingUrl ) { }
+
+ bool authenticationQuery( string& username, string& password );
+ };
+
+ bool AuthProvider::authenticationQuery( string& username, string& password )
+ {
+ if ( m_xEnv.is() )
+ {
+ uno::Reference< task::XInteractionHandler > xIH
+ = m_xEnv->getInteractionHandler();
+
+ if ( xIH.is() )
+ {
+ rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
+ = new ucbhelper::SimpleAuthenticationRequest(
+ m_sUrl, m_sBindingUrl, ::rtl::OUString(),
+ rtl::OUString::createFromAscii( username.c_str( ) ),
+ rtl::OUString::createFromAscii( password.c_str( ) ),
+ ::rtl::OUString(), true, false );
+ xIH->handle( xRequest.get() );
+
+ rtl::Reference< ucbhelper::InteractionContinuation > xSelection
+ = xRequest->getSelection();
+
+ if ( xSelection.is() )
+ {
+ // Handler handled the request.
+ uno::Reference< task::XInteractionAbort > xAbort(
+ xSelection.get(), uno::UNO_QUERY );
+ if ( !xAbort.is() )
+ {
+ const rtl::Reference<
+ ucbhelper::InteractionSupplyAuthentication > & xSupp
+ = xRequest->getAuthenticationSupplier();
+
+ username = OUSTR_TO_STDSTR( xSupp->getUserName() );
+ password = OUSTR_TO_STDSTR( xSupp->getPassword() );
+
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
+
namespace cmis
{
Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
@@ -62,43 +134,85 @@ namespace cmis
throw ( ucb::ContentCreationException )
: ContentImplHelper( rxSMgr, pProvider, Identifier ),
m_pProvider( pProvider ),
- m_pSession( NULL )
+ m_pSession( NULL ),
+ m_bTransient( false )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf(stderr, "New Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
-#endif
// Split the URL into bits
- cmis::URL url( m_xIdentifier->getContentIdentifier() );
+ m_sURL = m_xIdentifier->getContentIdentifier( );
+ cmis::URL url( m_sURL );
- // Initiate a CMIS session
- m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) );
+ // Look for a cached session
+ m_pSession = pProvider->getSession( url.getBindingUrl( ) );
+ if ( NULL == m_pSession )
+ {
+ // Initiate a CMIS session and register it as we found nothing
+ m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) );
+ pProvider->registerSession( url.getBindingUrl( ), m_pSession );
+ }
- // Get the content Object
- m_pObject = m_pSession->getObject( url.getObjectId() );
+ m_sObjectId = url.getObjectId( );
+ m_sBindingUrl = url.getBindingUrl( );
}
Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, ContentProvider *pProvider,
const uno::Reference< ucb::XContentIdentifier >& Identifier,
- sal_Bool /*bIsFolder*/)
+ sal_Bool bIsFolder )
throw ( ucb::ContentCreationException )
: ContentImplHelper( rxSMgr, pProvider, Identifier ),
m_pProvider( pProvider ),
- m_pSession( NULL )
+ m_pSession( NULL ),
+ m_bTransient( true )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf(stderr, "TODO - Create Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
-#endif
- // TODO Implement me
+ // Split the URL into bits
+ m_sURL = m_xIdentifier->getContentIdentifier( );
+ cmis::URL url( m_sURL );
+
+ // Look for a cached session
+ m_pSession = pProvider->getSession( url.getBindingUrl( ) );
+ if ( NULL == m_pSession )
+ {
+ // Initiate a CMIS session and register it as we found nothing
+ m_pSession = libcmis::SessionFactory::createSession( url.getSessionParams( ) );
+ pProvider->registerSession( url.getBindingUrl( ), m_pSession );
+ }
+
+ m_sObjectId = url.getObjectId( );
+ m_sBindingUrl = url.getBindingUrl( );
+
+ // Get the object type
+ string typeId = bIsFolder ? "cmis:folder" : "cmis:document";
+ m_pObjectType = m_pSession->getType( typeId );
}
Content::~Content()
{
- delete m_pSession;
}
- bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/)
+ libcmis::ObjectPtr Content::getObject( )
{
- return m_pObject->getBaseType( ) == "cmis::folder";
+ try
+ {
+ if ( !m_pObject.get() )
+ m_pObject = m_pSession->getObject( OUSTR_TO_STDSTR( m_sObjectId ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ SAL_INFO( "cmisucp", "Unexpected exception: " << e.what() );
+ }
+
+ return m_pObject;
+ }
+
+ void Content::resetAuthProvider( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
+ {
+ libcmis::AuthProviderPtr authProvider( new AuthProvider( xEnv, m_sURL, m_sBindingUrl ) );
+ m_pSession->setAuthenticationProvider( authProvider );
+ }
+
+ bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
+ {
+ resetAuthProvider( xEnv );
+ return getObject( )->getBaseType( ) == "cmis:folder";
}
uno::Any Content::getBadArgExcept()
@@ -110,11 +224,10 @@ namespace cmis
uno::Reference< sdbc::XRow > Content::getPropertyValues(
const uno::Sequence< beans::Property >& rProperties,
- const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
+ const uno::Reference< ucb::XCommandEnvironment >& xEnv )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::getPropertyValues()\n" );
-#endif
+ resetAuthProvider( xEnv );
+
rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xSMgr );
sal_Int32 nProps;
@@ -126,59 +239,84 @@ namespace cmis
for( sal_Int32 n = 0; n < nProps; ++n )
{
const beans::Property& rProp = pProps[ n ];
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "Property: %s\n", rtl::OUStringToOString( rProp.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
-#endif
if ( rProp.Name == "IsDocument" )
{
- if ( m_pObject->getBaseType( ) == "cmis:document" )
+ if ( getObject()->getBaseType( ) == "cmis:document" )
xRow->appendBoolean( rProp, true );
else
xRow->appendVoid( rProp );
}
else if ( rProp.Name == "IsFolder" )
{
- if( m_pObject->getBaseType( ) == "cmis:folder" )
+ if( getObject()->getBaseType( ) == "cmis:folder" )
xRow->appendBoolean( rProp, true );
else
xRow->appendVoid( rProp );
}
+ else if ( rProp.Name == "Title" )
+ {
+ string name = getObject()->getName();
+ xRow->appendString( rProp, rtl::OUString::createFromAscii( name.c_str() ) );
+ }
else if ( rProp.Name == "TitleOnServer" )
{
- // TODO Set the path instead of the name
- xRow->appendString( rProp, rtl::OUString::createFromAscii( m_pObject->getName().c_str() ) );
+ string path;
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get( ) );
+ if ( NULL != document )
+ {
+ vector< boost::shared_ptr< libcmis::Folder > > parents = document->getParents( );
+ if ( parents.size() > 0 )
+ path = parents.front( )->getPath( );
+
+ if ( path[ path.length() - 1 ] != '/' )
+ path += "/";
+ path += getObject()->getName( );
+ }
+ else
+ {
+ libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject().get( ) );
+ if ( NULL != folder )
+ path = folder->getPath( );
+ }
+
+ xRow->appendString( rProp, rtl::OUString::createFromAscii( path.c_str() ) );
}
else if ( rProp.Name == "IsReadOnly" )
{
- // TODO Fix this value
- xRow->appendBoolean( rProp, sal_True );
+ boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject()->getAllowableActions( );
+ sal_Bool bReadOnly = sal_False;
+ if ( allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) )
+ bReadOnly = sal_True;
+
+ xRow->appendBoolean( rProp, bReadOnly );
}
else if ( rProp.Name == "DateCreated" )
{
// TODO Fix this value
+ SAL_INFO( "cmisucp", "TODO - Fix property value " << rProp.Name );
xRow->appendVoid( rProp );
}
else if ( rProp.Name == "DateModified" )
{
// TODO Fix this value
+ SAL_INFO( "cmisucp", "TODO - Fix property value " << rProp.Name );
xRow->appendVoid( rProp );
}
else if ( rProp.Name == "Size" )
{
- libcmis::Document* document = dynamic_cast< libcmis::Document* >( m_pObject.get( ) );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get( ) );
if ( NULL != document )
xRow->appendLong( rProp, document->getContentLength() );
else
xRow->appendVoid( rProp );
}
-#if OSL_DEBUG_LEVEL > 1
- else
+ else if ( rProp.Name == "CreatableContentsInfo" )
{
- fprintf( stderr, "Looking for unsupported property %s\n",
- rtl::OUStringToOString( rProp.Name, RTL_TEXTENCODING_UTF8 ).getStr( ) );
+ xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
}
-#endif
+ else
+ SAL_INFO( "cmisucp", "Looking for unsupported property " << rProp.Name );
}
return uno::Reference< sdbc::XRow >( xRow.get() );
@@ -186,9 +324,7 @@ namespace cmis
void Content::queryChildren( ContentRefList& /*rChildren*/ )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::queryChildren()\n" );
-#endif
+ SAL_INFO( "cmisucp", "TODO - Content::queryChildren()" );
// TODO Implement me
}
@@ -210,10 +346,8 @@ namespace cmis
if ( bOpenFolder && bIsFolder )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::open() - Folder case\n" );
-#endif
- // TODO Implement the folder case
+ SAL_INFO( "cmisucp", "TODO - Content::open() - Folder case" );
+ // TODO Handle the folder case
}
else if ( rOpenCommand.Sink.is() )
{
@@ -234,10 +368,7 @@ namespace cmis
// Note: rOpenCommand.Sink may contain an XStream
// implementation. Support for this type of
// sink is optional...
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "Failed to load data from '%s'\n",
- rtl::OUStringToOString( m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8 ).getStr() );
-#endif
+ SAL_INFO( "cmisucp", "Failed to copy data to sink" );
ucbhelper::cancelCommandExecution(
uno::makeAny (ucb::UnsupportedDataSinkException
@@ -247,36 +378,115 @@ namespace cmis
}
}
else
- fprintf( stderr, "Open falling through ..." );
+ SAL_INFO( "cmisucp", "Open falling through ..." );
return aRet;
}
- void Content::transfer( const ucb::TransferInfo& /*rTransferInfo*/,
- const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
+ void Content::transfer( const ucb::TransferInfo& rTransferInfo,
+ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
throw( uno::Exception )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::transfer()\n" );
-#endif
- // TODO Implement me
+ // If the source isn't on the same CMIS repository, then simply copy
+ INetURLObject aSourceUrl( rTransferInfo.SourceURL );
+ if ( aSourceUrl.GetProtocol() != INET_PROT_CMIS_ATOM )
+ {
+ rtl::OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( );
+ if ( sSrcBindingUrl != m_sBindingUrl )
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::makeAny(
+ ucb::InteractiveBadTransferURLException(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
+ "Unsupported URL scheme!" )),
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+ }
+
+ SAL_INFO( "cmisucp", "TODO - Content::transfer()" );
}
- void Content::insert( const uno::Reference< io::XInputStream > & /*xInputStream*/,
- sal_Bool /*bReplaceExisting*/, const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
+ void Content::insert( const uno::Reference< io::XInputStream > & xInputStream,
+ sal_Bool bReplaceExisting, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
throw( uno::Exception )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::insert()\n" );
-#endif
- // TODO Implement me
+ SAL_INFO( "cmisucp", "TODO - Content::insert()" );
+
+ if ( !xInputStream.is() )
+ {
+ ucbhelper::cancelCommandExecution( uno::makeAny
+ ( ucb::MissingInputStreamException
+ ( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+
+ try
+ {
+ // For transient content, the URL is the one of the parent
+ if ( m_bTransient )
+ {
+ // Try to get the object from the server if there is any
+ libcmis::Folder* pFolder = dynamic_cast< libcmis::Folder* >( getObject( ).get( ) );
+ if ( pFolder != NULL )
+ {
+ map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
+ if ( it == m_pObjectProps.end( ) )
+ {
+ ucbhelper::cancelCommandExecution( uno::makeAny
+ ( uno::RuntimeException( "Missing name property",
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+ string newName = it->second->getStrings( ).front( );
+ string newPath = pFolder->getPath( );
+ if ( newPath[ newPath.size( ) - 1 ] != '/' )
+ newPath += "/";
+ newPath += newName;
+
+ libcmis::ObjectPtr object = m_pSession->getObjectByPath( newPath );
+
+ if ( NULL != object.get( ) )
+ {
+ // Are the base type matching?
+ if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() )
+ {
+ ucbhelper::cancelCommandExecution( uno::makeAny
+ ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+
+ // Update the existing object if it's a document
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) );
+ if ( NULL != document )
+ {
+ boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
+ uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
+ copyData( xInputStream, xOutput );
+ document->setContentStream( pOut, string( ), bReplaceExisting );
+ }
+ }
+ else
+ {
+ // TODO We need to create a brand new object... either folder or document
+ }
+ }
+ }
+ else
+ {
+ // TODO Update the current object... but I'm not sure this case can happen with UCB
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ throw uno::Exception( rtl::OUString::createFromAscii( e.what( ) ), *this );
+ }
}
- void Content::destroy( sal_Bool /*bDeletePhysical*/ ) throw( uno::Exception )
+ void Content::destroy( sal_Bool /*bDeletePhysical*/ ) throw ( uno::Exception )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::destroy()\n" );
-#endif
+ SAL_INFO( "cmisucp", "TODO - Content::destroy()" );
// TODO Implement me
}
@@ -298,13 +508,57 @@ namespace cmis
const uno::Sequence< beans::PropertyValue >& rValues,
const uno::Reference< ucb::XCommandEnvironment >& )
{
+ // Get the already set properties if possible
+ if ( !m_bTransient && getObject( ).get( ) )
+ m_pObjectProps = getObject()->getProperties( );
+
sal_Int32 nCount = rValues.getLength();
uno::Sequence< uno::Any > aRet( nCount );
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::setPropertyValue()\n" );
-#endif
- // TODO Implement me
+ const beans::PropertyValue* pValues = rValues.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const beans::PropertyValue& rValue = pValues[ n ];
+ if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ||
+ rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ||
+ rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ||
+ rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ||
+ rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ||
+ rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
+ {
+ lang::IllegalAccessException e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")),
+ static_cast< cppu::OWeakObject* >( this ) );
+ aRet[ n ] <<= e;
+ }
+ else if ( rValue.Name == "Title" )
+ {
+ rtl::OUString aNewTitle;
+ if (!( rValue.Value >>= aNewTitle ))
+ {
+ aRet[ n ] <<= beans::IllegalTypeException
+ ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property value has wrong type!")),
+ static_cast< cppu::OWeakObject * >( this ) );
+ continue;
+ }
+
+ if ( aNewTitle.getLength() <= 0 )
+ {
+ aRet[ n ] <<= lang::IllegalArgumentException
+ ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Empty title not allowed!")),
+ static_cast< cppu::OWeakObject * >( this ), -1 );
+ continue;
+
+ }
+
+ setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ) );
+ }
+ else
+ {
+ lang::IllegalAccessException e ( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Property is read-only!")),
+ static_cast< cppu::OWeakObject* >( this ) );
+ aRet[ n ] <<= e;
+ }
+ }
return aRet;
}
@@ -317,14 +571,18 @@ namespace cmis
uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY );
uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY );
+ uno::Reference< io::XActiveDataStreamer > xDataStreamer = uno::Reference< io::XActiveDataStreamer >( xSink, uno::UNO_QUERY );
- if ( !xOut.is() && !xDataSink.is() )
+ if ( !xOut.is() && !xDataSink.is() && ( !xDataStreamer.is() || !xDataStreamer->getStream().is() ) )
return sal_False;
- libcmis::Document* document = dynamic_cast< libcmis::Document* >( m_pObject.get() );
- FILE* fd = document->getContent( );
+ if ( xDataStreamer.is() && !xOut.is() )
+ xOut = xDataStreamer->getStream()->getOutputStream();
+
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject().get() );
+ boost::shared_ptr< istream > aIn = document->getContentStream( );
- uno::Reference< io::XInputStream > xIn = new ucbhelper::FdInputStream( fd );
+ uno::Reference< io::XInputStream > xIn = new ucbhelper::StdInputStream( aIn );
if( !xIn.is( ) )
return sal_False;
@@ -339,17 +597,17 @@ namespace cmis
sal_Bool Content::exchangeIdentity( const uno::Reference< ucb::XContentIdentifier >& /*xNewId*/ )
{
sal_Bool bRet = sal_False;
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::exchangeIdentity()\n" );
-#endif
+ SAL_INFO( "cmisucp", "TODO - Content::exchangeIdentity()" );
// TODO Implement me
return bRet;
}
uno::Sequence< beans::Property > Content::getProperties(
- const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
+ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
{
+ resetAuthProvider( xEnv );
+
static const beans::Property aGenericProperties[] =
{
beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
@@ -358,6 +616,9 @@ namespace cmis
beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
-1, getCppuBooleanType(),
beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
+ beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
+ -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
+ beans::PropertyAttribute::BOUND ),
beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TitleOnServer" ) ),
-1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
beans::PropertyAttribute::BOUND ),
@@ -373,6 +634,9 @@ namespace cmis
beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ),
-1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ),
beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
+ beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
+ -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
+ beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
};
const int nProps = SAL_N_ELEMENTS(aGenericProperties);
@@ -382,6 +646,8 @@ namespace cmis
uno::Sequence< ucb::CommandInfo > Content::getCommands(
const uno::Reference< ucb::XCommandEnvironment > & xEnv )
{
+ resetAuthProvider( xEnv );
+
static ucb::CommandInfo aCommandInfoTable[] =
{
// Required commands
@@ -426,10 +692,31 @@ namespace cmis
{
rtl::OUString sRet;
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::getParentURL()\n" );
-#endif
- // TODO Implement me
+ SAL_INFO( "cmisucp", "Content::getParentURL()" );
+
+ string parentId;
+
+ libcmis::ObjectPtr pObj = getObject( );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( ).get( ) );
+ if ( NULL != document )
+ {
+ vector< boost::shared_ptr< libcmis::Folder > > parents = document->getParents( );
+ if ( parents.size( ) > 0 )
+ parentId = parents.front( )->getId( );
+ }
+ else
+ {
+ libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( ).get( ) );
+ if ( NULL != folder )
+ parentId = folder->getFolderParent( )->getId( );
+ }
+
+ if ( !parentId.empty() )
+ {
+ URL aUrl( m_sURL );
+ aUrl.setObjectId( rtl::OUString::createFromAscii( parentId.c_str( ) ) );
+ sRet = aUrl.asString( );
+ }
return sRet;
}
@@ -478,6 +765,9 @@ namespace cmis
const uno::Reference< ucb::XCommandEnvironment >& xEnv )
throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException )
{
+ SAL_INFO( "cmisucp", "Content::execute( ) - " << aCommand.Name );
+ resetAuthProvider( xEnv );
+
uno::Any aRet;
if ( aCommand.Name == "getPropertyValues" )
@@ -531,19 +821,11 @@ namespace cmis
{
sal_Bool bDeletePhysical = sal_False;
aCommand.Argument >>= bDeletePhysical;
-
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::execute() - delete\n" );
-#endif
- // TODO Actually delete it
-
destroy( bDeletePhysical );
}
else
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "cmis::Content::execute() - UNKNOWN COMMAND\n" );
-#endif
+ SAL_INFO( "cmisucp", "Unknown command to execute" );
ucbhelper::cancelCommandExecution
( uno::makeAny( ucb::UnsupportedCommandException
@@ -557,9 +839,7 @@ namespace cmis
void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "TODO - cmis::Content::abort()\n" );
-#endif
+ SAL_INFO( "cmisucp", "TODO - Content::abort()" );
// TODO Implement me
}
@@ -573,7 +853,6 @@ namespace cmis
const ucb::ContentInfo& Info ) throw( uno::RuntimeException )
{
bool create_document;
- const char *name;
if ( Info.Type == CMIS_FILE_TYPE )
create_document = true;
@@ -581,33 +860,23 @@ namespace cmis
create_document = false;
else
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "Failed to create new content '%s'",
- rtl::OUStringToOString(Info.Type, RTL_TEXTENCODING_UTF8).getStr() );
-#endif
+ SAL_INFO( "cmisucp", "Unknown type of content to create" );
return uno::Reference< ucb::XContent >();
}
-#if OSL_DEBUG_LEVEL > 1
- fprintf( stderr, "createNewContent (%d)", (int) create_document );
-#endif
-
- rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
-
- if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
- aURL += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
-
- name = create_document ? "[New_Content]" : "[New_Collection]";
- aURL += rtl::OUString::createFromAscii( name );
+ rtl::OUString sParentURL = m_xIdentifier->getContentIdentifier();
+ URL aParentURL( sParentURL );
- uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(m_xSMgr, aURL));
+ // Set the parent URL for the transient objects
+ uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(m_xSMgr, sParentURL));
try
{
return new ::cmis::Content( m_xSMgr, m_pProvider, xId, !create_document );
- } catch ( ucb::ContentCreationException & )
+ }
+ catch ( ucb::ContentCreationException & )
{
- return uno::Reference< ucb::XContent >();
+ return uno::Reference< ucb::XContent >();
}
}
@@ -652,6 +921,7 @@ namespace cmis
const uno::Reference< ucb::XCommandEnvironment >& xEnv)
throw( uno::RuntimeException )
{
+ resetAuthProvider( xEnv );
if ( isFolder( xEnv ) )
{
uno::Sequence< ucb::ContentInfo > seq(2);
@@ -682,6 +952,24 @@ namespace cmis
return uno::Sequence< ucb::ContentInfo >();
}
}
+
+ void Content::setCmisProperty( std::string sName, std::string sValue )
+ {
+ if ( m_pObjectType.get( ) )
+ {
+ map< string, libcmis::PropertyTypePtr > propsTypes = m_pObjectType->getPropertiesTypes( );
+ map< string, libcmis::PropertyTypePtr >::iterator typeIt = propsTypes.find( sName );
+
+ if ( typeIt != propsTypes.end( ) )
+ {
+ libcmis::PropertyTypePtr propType = typeIt->second;
+ vector< string > values;
+ values.push_back( sValue );
+ libcmis::PropertyPtr property( new libcmis::Property( propType, values ) );
+ m_pObjectProps.insert( pair< string, libcmis::PropertyPtr >( sName, property ) );
+ }
+ }
+ }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/cmis/cmis_content.hxx b/ucb/source/ucp/cmis/cmis_content.hxx
index ef7503a0dfbe..e80a6d278bf3 100644
--- a/ucb/source/ucp/cmis/cmis_content.hxx
+++ b/ucb/source/ucp/cmis/cmis_content.hxx
@@ -29,6 +29,8 @@
#ifndef CMIS_CONTENT_HXX
#define CMIS_CONTENT_HXX
+#include "cmis_url.hxx"
+
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/ucb/ContentCreationException.hpp>
@@ -68,9 +70,18 @@ class Content : public ::ucbhelper::ContentImplHelper, public com::sun::star::uc
private:
ContentProvider* m_pProvider;
libcmis::Session* m_pSession;
- libcmis::CmisObjectPtr m_pObject;
+ libcmis::ObjectPtr m_pObject;
+ rtl::OUString m_sObjectId;
+ rtl::OUString m_sURL;
+ rtl::OUString m_sBindingUrl;
+
+ // Members to be set for non-persistent content
+ bool m_bTransient;
+ libcmis::ObjectTypePtr m_pObjectType;
+ std::map< std::string, libcmis::PropertyPtr > m_pObjectProps;
bool isFolder(const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv);
+ void setCmisProperty( std::string sName, std::string sValue );
com::sun::star::uno::Any getBadArgExcept();
@@ -112,6 +123,9 @@ private:
sal_Bool exchangeIdentity(const com::sun::star::uno::Reference< com::sun::star::ucb::XContentIdentifier >& xNewId);
+ void resetAuthProvider( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv );
+ libcmis::ObjectPtr getObject( );
+
public:
Content( const com::sun::star::uno::Reference<
com::sun::star::lang::XMultiServiceFactory >& rxSMgr, ContentProvider *pProvider,
diff --git a/ucb/source/ucp/cmis/cmis_provider.cxx b/ucb/source/ucp/cmis/cmis_provider.cxx
index f733cf0ea22a..a13e9f777ff1 100644
--- a/ucb/source/ucp/cmis/cmis_provider.cxx
+++ b/ucb/source/ucp/cmis/cmis_provider.cxx
@@ -45,12 +45,6 @@ ContentProvider::queryContent(
throw( com::sun::star::ucb::IllegalIdentifierException,
uno::RuntimeException )
{
-#if OSL_DEBUG_LEVEL > 1
- fprintf(stderr, "QueryContent: '%s'\n",
- rtl::OUStringToOString
- (Identifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
-#endif
-
osl::MutexGuard aGuard( m_aMutex );
// Check, if a content with given id already exists...
@@ -60,7 +54,8 @@ ContentProvider::queryContent(
try
{
- xContent = new ::cmis::Content(m_xSMgr, this, Identifier);
+ xContent = new ::cmis::Content( m_xSMgr, this, Identifier );
+ registerNewContent( xContent );
}
catch ( com::sun::star::ucb::ContentCreationException const & )
{
@@ -73,14 +68,36 @@ ContentProvider::queryContent(
return xContent;
}
+libcmis::Session* ContentProvider::getSession( const rtl::OUString& sBindingUrl )
+{
+ libcmis::Session* pSession = NULL;
+ std::map< rtl::OUString, libcmis::Session* >::iterator it = m_aSessionCache.find( sBindingUrl );
+ if ( it != m_aSessionCache.end( ) )
+ {
+ pSession = it->second;
+ }
+ return pSession;
+}
+
+void ContentProvider::registerSession( const rtl::OUString& sBindingUrl, libcmis::Session* pSession )
+{
+ m_aSessionCache.insert( std::pair< rtl::OUString, libcmis::Session* >( sBindingUrl, pSession ) );
+}
+
ContentProvider::ContentProvider(
const uno::Reference< lang::XMultiServiceFactory >& rSMgr )
: ::ucbhelper::ContentProviderImplHelper( rSMgr )
{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "ContentProvider::ContentProvider( )\n" );
+#endif
}
ContentProvider::~ContentProvider()
{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "ContentProvider::~ContentProvider( )\n" );
+#endif
}
XINTERFACE_IMPL_3( ContentProvider,
diff --git a/ucb/source/ucp/cmis/cmis_provider.hxx b/ucb/source/ucp/cmis/cmis_provider.hxx
index 090cde0f1ddf..2ade10052725 100644
--- a/ucb/source/ucp/cmis/cmis_provider.hxx
+++ b/ucb/source/ucp/cmis/cmis_provider.hxx
@@ -31,12 +31,16 @@
#include <com/sun/star/beans/Property.hpp>
#include <ucbhelper/providerhelper.hxx>
+#include <libcmis/session.hxx>
namespace cmis
{
class ContentProvider : public ::ucbhelper::ContentProviderImplHelper
{
+private:
+ std::map< rtl::OUString, libcmis::Session* > m_aSessionCache;
+
public:
ContentProvider( const ::com::sun::star::uno::Reference<
::com::sun::star::lang::XMultiServiceFactory >& rSMgr );
@@ -58,6 +62,9 @@ public:
::com::sun::star::ucb::XContentIdentifier >& Identifier )
throw( ::com::sun::star::ucb::IllegalIdentifierException,
::com::sun::star::uno::RuntimeException );
+
+ libcmis::Session* getSession( const rtl::OUString& sBindingUrl );
+ void registerSession( const rtl::OUString& sBindingUrl, libcmis::Session* pSession );
};
}
diff --git a/ucb/source/ucp/cmis/cmis_url.cxx b/ucb/source/ucp/cmis/cmis_url.cxx
index 92a6f7e24435..655518d58365 100644
--- a/ucb/source/ucp/cmis/cmis_url.cxx
+++ b/ucb/source/ucp/cmis/cmis_url.cxx
@@ -27,7 +27,6 @@
*/
#include <libcmis/session-factory.hxx>
-#include <tools/urlobj.hxx>
#include "cmis_url.hxx"
@@ -38,17 +37,17 @@ using namespace std;
namespace cmis
{
- URL::URL( rtl::OUString const & urlStr )
+ URL::URL( rtl::OUString const & urlStr ) :
+ m_aUrl( urlStr )
{
- INetURLObject url( urlStr );
- string bindingUrl( "http://" );
- bindingUrl += OUSTR_TO_STDSTR( url.GetHostPort( ) );
- bindingUrl += OUSTR_TO_STDSTR( url.GetURLPath( ) );
+ rtl::OUString bindingUrl( "http://" );
+ bindingUrl += m_aUrl.GetHostPort( );
+ bindingUrl += m_aUrl.GetURLPath( );
m_sBindingUrl = bindingUrl;
// Split the query into bits and locate the repo-id key
- rtl::OUString query = url.GetParam( );
+ rtl::OUString query = m_aUrl.GetParam( );
while ( !query.isEmpty() )
{
sal_Int32 nPos = query.indexOfAsciiL( "&", 1 );
@@ -65,8 +64,8 @@ namespace cmis
}
sal_Int32 nEqPos = segment.indexOfAsciiL( "=", 1 );
- string key = OUSTR_TO_STDSTR( segment.copy( 0, nEqPos ) );
- string value = OUSTR_TO_STDSTR( segment.copy( nEqPos +1 ) );
+ rtl::OUString key = segment.copy( 0, nEqPos );
+ rtl::OUString value = segment.copy( nEqPos +1 );
if ( key == "repo-id" )
m_sRepositoryId = value;
@@ -79,16 +78,40 @@ namespace cmis
map< int, string > URL::getSessionParams( )
{
map< int, string > params;
- params[ATOMPUB_URL] = m_sBindingUrl;
- params[REPOSITORY_ID] = m_sRepositoryId;
+ params[ATOMPUB_URL] = OUSTR_TO_STDSTR( m_sBindingUrl );
+ params[REPOSITORY_ID] = OUSTR_TO_STDSTR( m_sRepositoryId );
+ params[USERNAME] = OUSTR_TO_STDSTR( m_aUrl.GetUser() );
+ params[PASSWORD] = OUSTR_TO_STDSTR( m_aUrl.GetPass() );
return params;
}
- string URL::getObjectId( )
+ rtl::OUString URL::getObjectId( )
{
return m_aQuery["id"];
}
+
+ rtl::OUString URL::getBindingUrl( )
+ {
+ return m_sBindingUrl;
+ }
+
+ void URL::setObjectId( rtl::OUString sId )
+ {
+ m_aQuery["id"] = sId;
+ updateUrlQuery( );
+ }
+
+ rtl::OUString URL::asString( )
+ {
+ return m_aUrl.GetMainURL( INetURLObject::NO_DECODE );
+ }
+
+ void URL::updateUrlQuery( )
+ {
+ rtl::OUString sParam = "repo-id=" + m_sRepositoryId + "&id=" + m_aQuery["id"];
+ m_aUrl.SetParam( sParam );
+ }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/cmis/cmis_url.hxx b/ucb/source/ucp/cmis/cmis_url.hxx
index 1859102fa59e..18d13f166f37 100644
--- a/ucb/source/ucp/cmis/cmis_url.hxx
+++ b/ucb/source/ucp/cmis/cmis_url.hxx
@@ -32,22 +32,32 @@
#include <string>
#include <rtl/ustring.hxx>
+#include <tools/urlobj.hxx>
namespace cmis
{
class URL
{
private:
- std::string m_sBindingUrl;
- std::string m_sRepositoryId;
+ INetURLObject m_aUrl;
+ rtl::OUString m_sBindingUrl;
+ rtl::OUString m_sRepositoryId;
- std::map< std::string, std::string > m_aQuery;
+ std::map< rtl::OUString, rtl::OUString > m_aQuery;
public:
URL( rtl::OUString const & urlStr );
std::map< int, std::string > getSessionParams( );
- std::string getObjectId( );
+ rtl::OUString getObjectId( );
+ rtl::OUString getBindingUrl( );
+ void setObjectId( rtl::OUString sId );
+
+ rtl::OUString asString( );
+
+ private:
+
+ void updateUrlQuery( );
};
}
diff --git a/ucbhelper/Library_ucbhelper.mk b/ucbhelper/Library_ucbhelper.mk
index 166226d616c4..7de5f82cd96e 100644
--- a/ucbhelper/Library_ucbhelper.mk
+++ b/ucbhelper/Library_ucbhelper.mk
@@ -70,6 +70,8 @@ $(eval $(call gb_Library_add_exception_objects,ucbhelper,\
ucbhelper/source/provider/interactionrequest \
ucbhelper/source/provider/providerhelper \
ucbhelper/source/provider/fd_inputstream \
+ ucbhelper/source/provider/std_inputstream \
+ ucbhelper/source/provider/std_outputstream \
ucbhelper/source/client/proxydecider \
ucbhelper/source/client/content \
ucbhelper/source/client/contentbroker \
diff --git a/ucbhelper/Package_inc.mk b/ucbhelper/Package_inc.mk
index ccce9c9eaed2..25a197ebd47a 100644
--- a/ucbhelper/Package_inc.mk
+++ b/ucbhelper/Package_inc.mk
@@ -55,5 +55,7 @@ $(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/providerhelper.hxx
$(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/simplenameclashresolverequest.hxx,ucbhelper/simplenameclashresolverequest.hxx))
$(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/macros.hxx,ucbhelper/macros.hxx))
$(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/fd_inputstream.hxx,ucbhelper/fd_inputstream.hxx))
+$(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/std_inputstream.hxx,ucbhelper/std_inputstream.hxx))
+$(eval $(call gb_Package_add_file,ucbhelper_inc,inc/ucbhelper/std_outputstream.hxx,ucbhelper/std_outputstream.hxx))
# vim: set noet sw=4 ts=4:
diff --git a/ucbhelper/inc/ucbhelper/std_inputstream.hxx b/ucbhelper/inc/ucbhelper/std_inputstream.hxx
new file mode 100644
index 000000000000..2068f45eab4a
--- /dev/null
+++ b/ucbhelper/inc/ucbhelper/std_inputstream.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright 2012 LibreOffice contributors.
+ *
+ * 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/.
+ */
+
+#ifndef _UCBHELPER_STD_INPUTSTREAM_HXX_
+#define _UCBHELPER_STD_INPUTSTREAM_HXX_
+
+#include <boost/shared_ptr.hpp>
+#include <istream>
+
+#include <rtl/ustring.hxx>
+#include <osl/mutex.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+#include "ucbhelper/ucbhelperdllapi.h"
+
+
+namespace ucbhelper
+{
+ namespace css = com::sun::star;
+
+ /** Implements a seekable InputStream
+ * working on an std::istream
+ */
+ class UCBHELPER_DLLPUBLIC StdInputStream
+ : public cppu::OWeakObject,
+ public com::sun::star::io::XInputStream,
+ public com::sun::star::io::XSeekable
+ {
+ public:
+
+ StdInputStream( boost::shared_ptr< std::istream > pStream );
+
+ ~StdInputStream();
+
+ virtual css::uno::Any SAL_CALL queryInterface ( const css::uno::Type& rType )
+ throw ( css::uno::RuntimeException );
+
+ virtual void SAL_CALL acquire( ) throw ( );
+
+ virtual void SAL_CALL release( ) throw ( );
+
+ virtual sal_Int32 SAL_CALL
+ readBytes ( css::uno::Sequence< sal_Int8 >& aData,
+ sal_Int32 nBytesToRead )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual sal_Int32 SAL_CALL
+ readSomeBytes ( css::uno::Sequence< sal_Int8 >& aData,
+ sal_Int32 nMaxBytesToRead )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual void SAL_CALL
+ skipBytes ( sal_Int32 nBytesToSkip )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual sal_Int32 SAL_CALL
+ available ( )
+ throw ( css::io::NotConnectedException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual void SAL_CALL
+ closeInput ( )
+ throw ( css::io::NotConnectedException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+
+ /** XSeekable
+ */
+
+ virtual void SAL_CALL
+ seek ( sal_Int64 location )
+ throw ( css::lang::IllegalArgumentException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+
+ virtual sal_Int64 SAL_CALL
+ getPosition ( )
+ throw ( css::io::IOException, css::uno::RuntimeException );
+
+
+ virtual sal_Int64 SAL_CALL
+ getLength ( )
+ throw ( css::io::IOException,
+ css::uno::RuntimeException );
+
+ private:
+
+ osl::Mutex m_aMutex;
+ boost::shared_ptr< std::istream > m_pStream;
+ sal_Int64 m_nLength;
+ };
+
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/inc/ucbhelper/std_outputstream.hxx b/ucbhelper/inc/ucbhelper/std_outputstream.hxx
new file mode 100644
index 000000000000..b83b17e630e1
--- /dev/null
+++ b/ucbhelper/inc/ucbhelper/std_outputstream.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright 2012 LibreOffice contributors.
+ *
+ * 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/.
+ */
+
+#ifndef _UCBHELPER_STD_OUTPUTSTREAM_HXX_
+#define _UCBHELPER_STD_OUTPUTSTREAM_HXX_
+
+#include <boost/shared_ptr.hpp>
+#include <ostream>
+
+#include <osl/mutex.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include "ucbhelper/ucbhelperdllapi.h"
+
+namespace ucbhelper
+{
+ namespace css = com::sun::star;
+
+ /** Implements a OutputStream
+ * working on an std::ostream
+ */
+ class UCBHELPER_DLLPUBLIC StdOutputStream :
+ public cppu::OWeakObject,
+ public css::io::XOutputStream
+ {
+ public:
+
+ StdOutputStream( boost::shared_ptr< std::ostream > pStream );
+
+ ~StdOutputStream( );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& rType )
+ throw ( css::uno::RuntimeException );
+
+ virtual void SAL_CALL acquire ( ) throw ( );
+
+ virtual void SAL_CALL release ( ) throw ( );
+
+ virtual void SAL_CALL writeBytes ( const css::uno::Sequence< sal_Int8 >& aData )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual void SAL_CALL flush ( )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ virtual void SAL_CALL closeOutput ( )
+ throw ( css::io::NotConnectedException,
+ css::io::BufferSizeExceededException,
+ css::io::IOException,
+ css::uno::RuntimeException );
+
+ private:
+
+ osl::Mutex m_aMutex;
+ boost::shared_ptr< std::ostream > m_pStream;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/std_inputstream.cxx b/ucbhelper/source/provider/std_inputstream.cxx
new file mode 100644
index 000000000000..049313197e8a
--- /dev/null
+++ b/ucbhelper/source/provider/std_inputstream.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright 2012 LibreOffice contributors.
+ *
+ * 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/.
+ */
+
+#include "ucbhelper/std_inputstream.hxx"
+
+using namespace std;
+using namespace com::sun::star;
+
+namespace ucbhelper
+{
+ StdInputStream::StdInputStream( boost::shared_ptr< istream > pStream ) :
+ m_pStream( pStream ),
+ m_nLength( 0 )
+ {
+ if ( m_pStream.get() )
+ {
+ streampos nInitPos = m_pStream->tellg( );
+ m_pStream->seekg( 0, ios_base::end );
+ streampos nEndPos = m_pStream->tellg( );
+ m_pStream->seekg( nInitPos, ios_base::beg );
+
+ m_nLength = sal_Int64( nEndPos - nInitPos );
+ }
+ }
+
+ StdInputStream::~StdInputStream()
+ {
+ }
+
+ uno::Any SAL_CALL StdInputStream::queryInterface( const uno::Type& rType ) throw ( uno::RuntimeException )
+ {
+ uno::Any aRet = ::cppu::queryInterface( rType,
+ ( static_cast< XInputStream* >( this ) ),
+ ( static_cast< XSeekable* >( this ) ) );
+
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+ }
+
+ void SAL_CALL StdInputStream::acquire( ) throw( )
+ {
+ OWeakObject::acquire();
+ }
+
+ void SAL_CALL StdInputStream::release( ) throw( )
+ {
+ OWeakObject::release();
+ }
+
+ sal_Int32 SAL_CALL StdInputStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+ throw( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException)
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( 0 <= nBytesToRead && aData.getLength() < nBytesToRead )
+ aData.realloc( nBytesToRead );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ sal_Int32 nRead = 0;
+ try
+ {
+ m_pStream->read( reinterpret_cast< char* >( aData.getArray( ) ), nBytesToRead );
+ nRead = m_pStream->gcount();
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "StdInputStream::readBytes() error: " << e.what() );
+ throw io::IOException( );
+ }
+
+ return nRead;
+ }
+
+ sal_Int32 SAL_CALL StdInputStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData,
+ sal_Int32 nMaxBytesToRead )
+ throw( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException)
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( 0 <= nMaxBytesToRead && aData.getLength() < nMaxBytesToRead )
+ aData.realloc( nMaxBytesToRead );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ sal_Int32 nRead = 0;
+ try
+ {
+ nRead = m_pStream->readsome( reinterpret_cast< char* >( aData.getArray( ) ), nMaxBytesToRead );
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "StdInputStream::readBytes() error: " << e.what() );
+ throw io::IOException( );
+ }
+ return nRead;
+ }
+
+ void SAL_CALL StdInputStream::skipBytes( sal_Int32 nBytesToSkip )
+ throw( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ try
+ {
+ m_pStream->seekg( nBytesToSkip, ios_base::cur );
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "StdInputStream::readBytes() error: " << e.what() );
+ throw io::IOException( );
+ }
+ }
+
+ sal_Int32 SAL_CALL StdInputStream::available( )
+ throw(io::NotConnectedException, io::IOException, uno::RuntimeException )
+ {
+ return sal::static_int_cast< sal_Int32 >( m_nLength - getPosition() );
+ }
+
+ void SAL_CALL StdInputStream::closeInput( )
+ throw( io::NotConnectedException, io::IOException, uno::RuntimeException)
+ {
+ // No need to implement this for an istream
+ }
+
+ void SAL_CALL StdInputStream::seek( sal_Int64 location )
+ throw( lang::IllegalArgumentException, io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( location < 0 || location > m_nLength )
+ throw lang::IllegalArgumentException(
+ "Location can't be negative or greater than the length",
+ static_cast< cppu::OWeakObject* >( this ), 0 );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ try
+ {
+ m_pStream->clear( ); // may be needed to rewind the stream
+ m_pStream->seekg( location, ios_base::beg );
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "StdInputStream::readBytes() error: " << e.what() );
+ throw io::IOException( );
+ }
+ }
+
+ sal_Int64 SAL_CALL StdInputStream::getPosition( )
+ throw( io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ sal_Int64 nPos = m_pStream->tellg( );
+ if ( -1 == nPos )
+ throw io::IOException( );
+
+ return nPos;
+ }
+
+ sal_Int64 SAL_CALL StdInputStream::getLength( )
+ throw ( io::IOException, uno::RuntimeException )
+ {
+ return m_nLength;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/std_outputstream.cxx b/ucbhelper/source/provider/std_outputstream.cxx
new file mode 100644
index 000000000000..f2f7ebdc2746
--- /dev/null
+++ b/ucbhelper/source/provider/std_outputstream.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright 2012 LibreOffice contributors.
+ *
+ * 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/.
+ */
+
+#include "ucbhelper/std_outputstream.hxx"
+
+using namespace std;
+using namespace com::sun::star;
+
+namespace ucbhelper
+{
+ StdOutputStream::StdOutputStream( boost::shared_ptr< ostream > pStream ) :
+ m_pStream( pStream )
+ {
+ }
+
+ StdOutputStream::~StdOutputStream()
+ {
+ if ( m_pStream.get( ) )
+ m_pStream->setstate( ios::eofbit );
+ }
+
+ uno::Any SAL_CALL StdOutputStream::queryInterface( const uno::Type& rType ) throw ( uno::RuntimeException )
+ {
+ uno::Any aRet = ::cppu::queryInterface( rType, ( static_cast< XOutputStream* >( this ) ) );
+
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+ }
+
+ void SAL_CALL StdOutputStream::acquire( ) throw( )
+ {
+ OWeakObject::acquire();
+ }
+
+ void SAL_CALL StdOutputStream::release( ) throw( )
+ {
+ OWeakObject::release();
+ }
+
+ void SAL_CALL StdOutputStream::writeBytes ( const uno::Sequence< sal_Int8 >& aData )
+ throw ( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ try
+ {
+ m_pStream->write( reinterpret_cast< const char* >( aData.getConstArray( ) ), aData.getLength( ) );
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "Exception caught when calling write: " << e.what() );
+ throw io::IOException( );
+ }
+ }
+
+ void SAL_CALL StdOutputStream::flush ( )
+ throw ( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ try
+ {
+ m_pStream->flush( );
+ }
+ catch ( const ios_base::failure& e )
+ {
+ SAL_INFO( "ucbhelper", "Exception caught when calling flush: " << e.what() );
+ throw io::IOException( );
+ }
+ }
+
+ void SAL_CALL StdOutputStream::closeOutput ( )
+ throw ( io::NotConnectedException, io::BufferSizeExceededException,
+ io::IOException, uno::RuntimeException )
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pStream.get() )
+ throw io::IOException( );
+
+ m_pStream->setstate( ios_base::eofbit );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */