fdo#75487 Add support for svgz to SvgFilter and co.
Draw can open a svg file directly as a "document" not only as a picture (which is handled by "graphicfilter" in vcl). This commit adds support to also open svgz files by decompressing the stream first. Change-Id: I241e695076b380735dc9b9fc27f5416fff68f6ab
This commit is contained in:
@@ -40,6 +40,11 @@
|
|||||||
#include <com/sun/star/drawing/framework/ResourceId.hpp>
|
#include <com/sun/star/drawing/framework/ResourceId.hpp>
|
||||||
#include <comphelper/processfactory.hxx>
|
#include <comphelper/processfactory.hxx>
|
||||||
|
|
||||||
|
#include <unotools/mediadescriptor.hxx>
|
||||||
|
#include <unotools/ucbstreamhelper.hxx>
|
||||||
|
#include <unotools/streamwrap.hxx>
|
||||||
|
#include <tools/zcodec.hxx>
|
||||||
|
|
||||||
#include <osl/mutex.hxx>
|
#include <osl/mutex.hxx>
|
||||||
|
|
||||||
#include "svgfilter.hxx"
|
#include "svgfilter.hxx"
|
||||||
@@ -47,9 +52,10 @@
|
|||||||
|
|
||||||
using namespace ::com::sun::star;
|
using namespace ::com::sun::star;
|
||||||
|
|
||||||
|
namespace
|
||||||
// - SVGFilter -
|
{
|
||||||
|
static const char constFilterName[] = "svg_Scalable_Vector_Graphics";
|
||||||
|
}
|
||||||
|
|
||||||
SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
|
SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
|
||||||
mxContext( rxCtx ),
|
mxContext( rxCtx ),
|
||||||
@@ -62,12 +68,9 @@ SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
|
|||||||
mbPresentation( sal_False ),
|
mbPresentation( sal_False ),
|
||||||
mbExportAll( sal_False ),
|
mbExportAll( sal_False ),
|
||||||
mpObjects( NULL )
|
mpObjects( NULL )
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SVGFilter::~SVGFilter()
|
SVGFilter::~SVGFilter()
|
||||||
{
|
{
|
||||||
DBG_ASSERT( mpSVGDoc == NULL, "mpSVGDoc not destroyed" );
|
DBG_ASSERT( mpSVGDoc == NULL, "mpSVGDoc not destroyed" );
|
||||||
@@ -77,8 +80,6 @@ SVGFilter::~SVGFilter()
|
|||||||
DBG_ASSERT( mpObjects == NULL, "mpObjects not destroyed" );
|
DBG_ASSERT( mpObjects == NULL, "mpObjects not destroyed" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescriptor )
|
sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescriptor )
|
||||||
throw (RuntimeException, std::exception)
|
throw (RuntimeException, std::exception)
|
||||||
{
|
{
|
||||||
@@ -242,70 +243,102 @@ sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescripto
|
|||||||
return bRet;
|
return bRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SAL_CALL SVGFilter::cancel( ) throw (RuntimeException, std::exception)
|
void SAL_CALL SVGFilter::cancel( ) throw (RuntimeException, std::exception)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SAL_CALL SVGFilter::setSourceDocument( const Reference< XComponent >& xDoc )
|
void SAL_CALL SVGFilter::setSourceDocument( const Reference< XComponent >& xDoc )
|
||||||
throw (IllegalArgumentException, RuntimeException, std::exception)
|
throw (IllegalArgumentException, RuntimeException, std::exception)
|
||||||
{
|
{
|
||||||
mxSrcDoc = xDoc;
|
mxSrcDoc = xDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SAL_CALL SVGFilter::setTargetDocument( const Reference< XComponent >& xDoc )
|
void SAL_CALL SVGFilter::setTargetDocument( const Reference< XComponent >& xDoc )
|
||||||
throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException, std::exception)
|
throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException, std::exception)
|
||||||
{
|
{
|
||||||
mxDstDoc = xDoc;
|
mxDstDoc = xDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SAL_CALL SVGFilter::isStreamGZip(uno::Reference<io::XInputStream> xInput)
|
||||||
|
|
||||||
OUString SAL_CALL SVGFilter::detect( Sequence< PropertyValue >& io_rDescriptor ) throw (RuntimeException, std::exception)
|
|
||||||
{
|
{
|
||||||
uno::Reference< io::XInputStream > xInput;
|
uno::Reference<io::XSeekable> xSeek(xInput, uno::UNO_QUERY);
|
||||||
|
if(xSeek.is())
|
||||||
|
xSeek->seek(0);
|
||||||
|
|
||||||
const beans::PropertyValue* pAttribs = io_rDescriptor.getConstArray();
|
uno::Sequence<sal_Int8> aBuffer(2);
|
||||||
const sal_Int32 nAttribs = io_rDescriptor.getLength();
|
const sal_uInt64 nBytes = xInput->readBytes(aBuffer, 2);
|
||||||
for( sal_Int32 i = 0; i < nAttribs; i++ )
|
if (nBytes == 2)
|
||||||
{
|
{
|
||||||
if ( pAttribs[i].Name == "InputStream" )
|
const sal_Int8* pBuffer = aBuffer.getConstArray();
|
||||||
pAttribs[i].Value >>= xInput;
|
if (pBuffer[0] == (sal_Int8)0x1F && pBuffer[1] == (sal_Int8)0x8B)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if( !xInput.is() )
|
|
||||||
return OUString();
|
|
||||||
|
|
||||||
uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
|
|
||||||
if( xSeek.is() )
|
|
||||||
xSeek->seek( 0 );
|
|
||||||
|
|
||||||
// read the first 1024 bytes & check a few magic string
|
|
||||||
// constants (heuristically)
|
|
||||||
const sal_Int32 nLookAhead = 1024;
|
|
||||||
uno::Sequence< sal_Int8 > aBuf( nLookAhead );
|
|
||||||
const sal_uInt64 nBytes=xInput->readBytes(aBuf, nLookAhead);
|
|
||||||
const sal_Int8* const pBuf=aBuf.getConstArray();
|
|
||||||
|
|
||||||
sal_Int8 aMagic1[] = {'<', 's', 'v', 'g'};
|
|
||||||
if( std::search(pBuf, pBuf+nBytes,
|
|
||||||
aMagic1, aMagic1+sizeof(aMagic1)/sizeof(*aMagic1)) != pBuf+nBytes )
|
|
||||||
return OUString("svg_Scalable_Vector_Graphics");
|
|
||||||
|
|
||||||
sal_Int8 aMagic2[] = {'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' ', 's', 'v', 'g'};
|
|
||||||
if( std::search(pBuf, pBuf+nBytes,
|
|
||||||
aMagic2, aMagic2+sizeof(aMagic2)/sizeof(*aMagic2)) != pBuf+nBytes )
|
|
||||||
return OUString("svg_Scalable_Vector_Graphics");
|
|
||||||
|
|
||||||
return OUString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SAL_CALL SVGFilter::isStreamSvg(uno::Reference<io::XInputStream> xInput)
|
||||||
|
{
|
||||||
|
uno::Reference<io::XSeekable> xSeek(xInput, uno::UNO_QUERY);
|
||||||
|
if(xSeek.is())
|
||||||
|
xSeek->seek(0);
|
||||||
|
|
||||||
|
const sal_Int32 nLookAhead = 1024;
|
||||||
|
uno::Sequence<sal_Int8> aBuffer(nLookAhead);
|
||||||
|
const sal_uInt64 nBytes = xInput->readBytes(aBuffer, nLookAhead);
|
||||||
|
const sal_Int8* pBuffer = aBuffer.getConstArray();
|
||||||
|
|
||||||
|
sal_Int8 aMagic1[] = {'<', 's', 'v', 'g'};
|
||||||
|
sal_Int32 aMagic1Size = sizeof(aMagic1) / sizeof(*aMagic1);
|
||||||
|
|
||||||
|
if (std::search(pBuffer, pBuffer + nBytes, aMagic1, aMagic1 + aMagic1Size) != pBuffer + nBytes )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sal_Int8 aMagic2[] = {'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' ', 's', 'v', 'g'};
|
||||||
|
sal_Int32 aMagic2Size = sizeof(aMagic2) / sizeof(*aMagic2);
|
||||||
|
|
||||||
|
if (std::search(pBuffer, pBuffer + nBytes, aMagic2, aMagic2 + aMagic2Size) != pBuffer + nBytes)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OUString SAL_CALL SVGFilter::detect(Sequence<PropertyValue>& rDescriptor) throw (RuntimeException, std::exception)
|
||||||
|
{
|
||||||
|
utl::MediaDescriptor aMediaDescriptor(rDescriptor);
|
||||||
|
uno::Reference<io::XInputStream> xInput(aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM()], UNO_QUERY);
|
||||||
|
|
||||||
|
if (!xInput.is())
|
||||||
|
return OUString();
|
||||||
|
|
||||||
|
if (isStreamGZip(xInput))
|
||||||
|
{
|
||||||
|
boost::scoped_ptr<SvStream> aStream(utl::UcbStreamHelper::CreateStream(xInput, true ));
|
||||||
|
if(!aStream.get())
|
||||||
|
return OUString();
|
||||||
|
|
||||||
|
SvStream* pMemoryStream = new SvMemoryStream;
|
||||||
|
uno::Reference<io::XSeekable> xSeek(xInput, uno::UNO_QUERY);
|
||||||
|
if (!xSeek.is())
|
||||||
|
return OUString();
|
||||||
|
xSeek->seek(0);
|
||||||
|
|
||||||
|
GZCodec aCodec;
|
||||||
|
aCodec.BeginCompression();
|
||||||
|
aCodec.Decompress(*aStream.get(), *pMemoryStream);
|
||||||
|
aCodec.EndCompression();
|
||||||
|
pMemoryStream->Seek(STREAM_SEEK_TO_BEGIN);
|
||||||
|
uno::Reference<io::XInputStream> xDecompressedInput(new utl::OSeekableInputStreamWrapper(pMemoryStream, true));
|
||||||
|
|
||||||
|
if (xDecompressedInput.is() && isStreamSvg(xDecompressedInput))
|
||||||
|
return OUString(constFilterName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isStreamSvg(xInput))
|
||||||
|
return OUString(constFilterName);
|
||||||
|
}
|
||||||
|
return OUString();
|
||||||
|
}
|
||||||
|
|
||||||
#define SVG_FILTER_IMPL_NAME "com.sun.star.comp.Draw.SVGFilter"
|
#define SVG_FILTER_IMPL_NAME "com.sun.star.comp.Draw.SVGFilter"
|
||||||
#define SVG_WRITER_IMPL_NAME "com.sun.star.comp.Draw.SVGWriter"
|
#define SVG_WRITER_IMPL_NAME "com.sun.star.comp.Draw.SVGWriter"
|
||||||
|
@@ -309,6 +309,9 @@ private:
|
|||||||
const Reference< XPropertySetInfo > & rxPropSetInfo );
|
const Reference< XPropertySetInfo > & rxPropSetInfo );
|
||||||
DECL_LINK( CalcFieldHdl, EditFieldInfo* );
|
DECL_LINK( CalcFieldHdl, EditFieldInfo* );
|
||||||
|
|
||||||
|
bool isStreamGZip(css::uno::Reference<css::io::XInputStream> xInput);
|
||||||
|
bool isStreamSvg(css::uno::Reference<css::io::XInputStream> xInput);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// XFilter
|
// XFilter
|
||||||
|
@@ -39,24 +39,49 @@
|
|||||||
#include <com/sun/star/io/XActiveDataSource.hpp>
|
#include <com/sun/star/io/XActiveDataSource.hpp>
|
||||||
#include <com/sun/star/task/XStatusIndicator.hpp>
|
#include <com/sun/star/task/XStatusIndicator.hpp>
|
||||||
|
|
||||||
|
#include <unotools/mediadescriptor.hxx>
|
||||||
|
#include <tools/zcodec.hxx>
|
||||||
|
|
||||||
using namespace ::com::sun::star;
|
using namespace ::com::sun::star;
|
||||||
using namespace ::svgi;
|
using namespace ::svgi;
|
||||||
|
|
||||||
sal_Bool SVGFilter::implImport( const Sequence< PropertyValue >& rDescriptor )
|
sal_Bool SVGFilter::implImport( const Sequence< PropertyValue >& rDescriptor )
|
||||||
throw (RuntimeException)
|
throw (RuntimeException)
|
||||||
{
|
{
|
||||||
uno::Reference< io::XInputStream > xInputStream;
|
utl::MediaDescriptor aMediaDescriptor(rDescriptor);
|
||||||
uno::Reference< task::XStatusIndicator > xStatus;
|
uno::Reference<io::XInputStream> xInputStream;
|
||||||
const sal_Int32 nLength = rDescriptor.getLength();
|
uno::Reference<task::XStatusIndicator> xStatus;
|
||||||
const beans::PropertyValue* pAttribs = rDescriptor.getConstArray();
|
|
||||||
for ( sal_Int32 i=0 ; i<nLength; ++i, ++pAttribs )
|
xInputStream = uno::Reference<io::XInputStream>(aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM()], UNO_QUERY);
|
||||||
|
xStatus = uno::Reference<task::XStatusIndicator>(aMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()], UNO_QUERY);
|
||||||
|
|
||||||
|
if (isStreamGZip(xInputStream))
|
||||||
{
|
{
|
||||||
if ( pAttribs->Name == "InputStream" )
|
uno::Reference<io::XSeekable> xSeek(xInputStream, uno::UNO_QUERY);
|
||||||
{
|
if (!xSeek.is())
|
||||||
pAttribs->Value >>= xInputStream;
|
return sal_False;
|
||||||
}
|
xSeek->seek(0);
|
||||||
else if ( pAttribs->Name == "StatusIndicator" )
|
|
||||||
pAttribs->Value >>= xStatus;
|
boost::scoped_ptr<SvStream> aStream(utl::UcbStreamHelper::CreateStream(xInputStream, true ));
|
||||||
|
if(!aStream.get())
|
||||||
|
return sal_False;
|
||||||
|
|
||||||
|
SvStream* pMemoryStream = new SvMemoryStream;
|
||||||
|
GZCodec aCodec;
|
||||||
|
aCodec.BeginCompression();
|
||||||
|
aCodec.Decompress(*aStream.get(), *pMemoryStream);
|
||||||
|
aCodec.EndCompression();
|
||||||
|
pMemoryStream->Seek(STREAM_SEEK_TO_BEGIN);
|
||||||
|
uno::Reference<io::XInputStream> xDecompressedInput(new utl::OSeekableInputStreamWrapper(pMemoryStream, true));
|
||||||
|
if (!xDecompressedInput.is())
|
||||||
|
return sal_False;
|
||||||
|
xInputStream = xDecompressedInput;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uno::Reference<io::XSeekable> xSeek(xInputStream, uno::UNO_QUERY);
|
||||||
|
if (xSeek.is())
|
||||||
|
xSeek->seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
OSL_ASSERT(xInputStream.is());
|
OSL_ASSERT(xInputStream.is());
|
||||||
|
Reference in New Issue
Block a user