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:
Tomaž Vajngerl
2014-03-02 22:06:13 +01:00
parent 51e7a789a1
commit 4f7aa27c62
3 changed files with 121 additions and 60 deletions

View File

@@ -40,6 +40,11 @@
#include <com/sun/star/drawing/framework/ResourceId.hpp>
#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 "svgfilter.hxx"
@@ -47,9 +52,10 @@
using namespace ::com::sun::star;
// - SVGFilter -
namespace
{
static const char constFilterName[] = "svg_Scalable_Vector_Graphics";
}
SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
mxContext( rxCtx ),
@@ -62,12 +68,9 @@ SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
mbPresentation( sal_False ),
mbExportAll( sal_False ),
mpObjects( NULL )
{
}
SVGFilter::~SVGFilter()
{
DBG_ASSERT( mpSVGDoc == NULL, "mpSVGDoc not destroyed" );
@@ -77,8 +80,6 @@ SVGFilter::~SVGFilter()
DBG_ASSERT( mpObjects == NULL, "mpObjects not destroyed" );
}
sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescriptor )
throw (RuntimeException, std::exception)
{
@@ -242,70 +243,102 @@ sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescripto
return bRet;
}
void SAL_CALL SVGFilter::cancel( ) throw (RuntimeException, std::exception)
{
}
void SAL_CALL SVGFilter::setSourceDocument( const Reference< XComponent >& xDoc )
throw (IllegalArgumentException, RuntimeException, std::exception)
{
mxSrcDoc = xDoc;
}
void SAL_CALL SVGFilter::setTargetDocument( const Reference< XComponent >& xDoc )
throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException, std::exception)
{
mxDstDoc = xDoc;
}
OUString SAL_CALL SVGFilter::detect( Sequence< PropertyValue >& io_rDescriptor ) throw (RuntimeException, std::exception)
bool SAL_CALL SVGFilter::isStreamGZip(uno::Reference<io::XInputStream> xInput)
{
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();
const sal_Int32 nAttribs = io_rDescriptor.getLength();
for( sal_Int32 i = 0; i < nAttribs; i++ )
uno::Sequence<sal_Int8> aBuffer(2);
const sal_uInt64 nBytes = xInput->readBytes(aBuffer, 2);
if (nBytes == 2)
{
if ( pAttribs[i].Name == "InputStream" )
pAttribs[i].Value >>= xInput;
const sal_Int8* pBuffer = aBuffer.getConstArray();
if (pBuffer[0] == (sal_Int8)0x1F && pBuffer[1] == (sal_Int8)0x8B)
return true;
}
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();
return false;
}
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_WRITER_IMPL_NAME "com.sun.star.comp.Draw.SVGWriter"

View File

@@ -309,6 +309,9 @@ private:
const Reference< XPropertySetInfo > & rxPropSetInfo );
DECL_LINK( CalcFieldHdl, EditFieldInfo* );
bool isStreamGZip(css::uno::Reference<css::io::XInputStream> xInput);
bool isStreamSvg(css::uno::Reference<css::io::XInputStream> xInput);
protected:
// XFilter

View File

@@ -39,24 +39,49 @@
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
#include <unotools/mediadescriptor.hxx>
#include <tools/zcodec.hxx>
using namespace ::com::sun::star;
using namespace ::svgi;
sal_Bool SVGFilter::implImport( const Sequence< PropertyValue >& rDescriptor )
throw (RuntimeException)
{
uno::Reference< io::XInputStream > xInputStream;
uno::Reference< task::XStatusIndicator > xStatus;
const sal_Int32 nLength = rDescriptor.getLength();
const beans::PropertyValue* pAttribs = rDescriptor.getConstArray();
for ( sal_Int32 i=0 ; i<nLength; ++i, ++pAttribs )
utl::MediaDescriptor aMediaDescriptor(rDescriptor);
uno::Reference<io::XInputStream> xInputStream;
uno::Reference<task::XStatusIndicator> xStatus;
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" )
{
pAttribs->Value >>= xInputStream;
}
else if ( pAttribs->Name == "StatusIndicator" )
pAttribs->Value >>= xStatus;
uno::Reference<io::XSeekable> xSeek(xInputStream, uno::UNO_QUERY);
if (!xSeek.is())
return sal_False;
xSeek->seek(0);
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());