Kaydet (Commit) 220a3686 authored tarafından Michael Stahl's avatar Michael Stahl

oox: refactor embedded media import

Currently the oox import creates a temp file and leaks it, and there is
no way to clean it up afterwards.  Unfortunately it turns out that
SdrModel has no way to access the imported OOXML storage, so add a
really ugly hack to get the embedded media into the SdrMediaObj by
setting both MediaURL and PrivateStream properties (currently oox really
wants to set the properties in alphabetical order too...)

Change-Id: I5a235fbeb08e7bc17faf066de52b94867e9a79a2
üst 8b7f96d2
......@@ -72,6 +72,7 @@ public:
getSnapshot();
::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream>
GetInputStream();
void SetInputStream(css::uno::Reference<css::io::XInputStream> const&);
protected:
......
......@@ -22,6 +22,8 @@
#include <sal/config.h>
#include <com/sun/star/io/XInputStream.hpp>
#include <oox/drawingml/fillproperties.hxx>
#include <oox/helper/helper.hxx>
......@@ -36,7 +38,8 @@ namespace drawingml {
struct GraphicProperties
{
BlipFillProperties maBlipProps; ///< Properties for the graphic.
OUString msMediaTempFile; ///< Audio/Video temporary file.
OUString m_sMediaPackageURL; ///< Audio/Video URL.
css::uno::Reference<css::io::XInputStream> m_xMediaStream; ///< Audio/Video input stream.
/** Overwrites all members that are explicitly set in rSourceProps. */
void assignUsed( const GraphicProperties& rSourceProps );
......
......@@ -753,8 +753,12 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelpe
rPropMap.setProperty(PROP_AdjustContrast, nContrast);
// Media content
if( !msMediaTempFile.isEmpty() )
rPropMap.setProperty(PROP_MediaURL, msMediaTempFile);
assert(m_xMediaStream.is() != m_sMediaPackageURL.isEmpty());
if (m_xMediaStream.is() && !m_sMediaPackageURL.isEmpty())
{
rPropMap.setProperty(PROP_PrivateStream, m_xMediaStream);
rPropMap.setProperty(PROP_MediaURL, m_sMediaPackageURL);
}
}
bool ArtisticEffectProperties::isEmpty() const
......
......@@ -49,20 +49,19 @@ using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::xml::sax;
using namespace ::oox::core;
static OUString lcl_CopyToTempFile(const OUString& rStream, const oox::core::XmlFilterBase& rFilter)
static uno::Reference<io::XInputStream>
lcl_GetMediaStream(const OUString& rStream, const oox::core::XmlFilterBase& rFilter)
{
if (rStream.isEmpty())
return OUString();
return nullptr;
Reference< XInputStream > xInStrm( rFilter.openInputStream(rStream), UNO_SET_THROW );
Reference< XTempFile > xTempFile( TempFile::create(rFilter.getComponentContext()) );
Reference< XOutputStream > xOutStrm( xTempFile->getOutputStream(), UNO_SET_THROW );
oox::BinaryXOutputStream aOutStrm( xOutStrm, false );
oox::BinaryXInputStream aInStrm( xInStrm, false );
aInStrm.copyToStream( aOutStrm );
xTempFile->setRemoveFile( false );
return xTempFile->getUri();
return xInStrm;
}
static OUString lcl_GetMediaReference(const OUString& rStream)
{
return rStream.isEmpty() ? OUString() : "vnd.sun.star.Package:" + rStream;
}
namespace oox {
......@@ -86,8 +85,11 @@ ContextHandlerRef GraphicShapeContext::onCreateContext( sal_Int32 aElementToken,
return new BlipFillContext( *this, rAttribs, mpShapePtr->getGraphicProperties().maBlipProps );
case XML_wavAudioFile:
{
mpShapePtr->getGraphicProperties().msMediaTempFile =
lcl_CopyToTempFile( getEmbeddedWAVAudioFile(getRelations(), rAttribs), getFilter() );
OUString const path(getEmbeddedWAVAudioFile(getRelations(), rAttribs));
mpShapePtr->getGraphicProperties().m_xMediaStream =
lcl_GetMediaStream(path, getFilter());
mpShapePtr->getGraphicProperties().m_sMediaPackageURL =
lcl_GetMediaReference(path);
}
break;
case XML_audioFile:
......@@ -95,8 +97,10 @@ ContextHandlerRef GraphicShapeContext::onCreateContext( sal_Int32 aElementToken,
{
OUString rPath = getRelations().getFragmentPathFromRelId(
rAttribs.getString(R_TOKEN(link)).get() );
mpShapePtr->getGraphicProperties().msMediaTempFile =
lcl_CopyToTempFile( rPath, getFilter() );
mpShapePtr->getGraphicProperties().m_xMediaStream =
lcl_GetMediaStream(rPath, getFilter());
mpShapePtr->getGraphicProperties().m_sMediaPackageURL =
lcl_GetMediaReference(rPath);
}
break;
}
......
......@@ -405,7 +405,7 @@ Reference< XShape > Shape::createAndInsert(
OUString aServiceName;
if( rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->msMediaTempFile.isEmpty() )
mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
{
aServiceName = finalizeServiceName( rFilterBase, "com.sun.star.presentation.MediaShape", aShapeRectHmm );
bIsEmbMedia = true;
......
......@@ -808,6 +808,7 @@ void SdImportTest::testBnc591147()
OUString sVideoURL("emptyURL");
bool bSucess = xPropSet->getPropertyValue("MediaURL") >>= sVideoURL;
CPPUNIT_ASSERT_MESSAGE( "MediaURL property is not set", bSucess );
CPPUNIT_ASSERT_MESSAGE("MediaURL is empty", !sVideoURL.isEmpty());
// Second page has audio file inserted
xPage.set( xDoc->getDrawPages()->getByIndex(1), uno::UNO_QUERY_THROW );
......@@ -818,6 +819,7 @@ void SdImportTest::testBnc591147()
OUString sAudioURL("emptyURL");
bSucess = xPropSet->getPropertyValue("MediaURL") >>= sAudioURL;
CPPUNIT_ASSERT_MESSAGE( "MediaURL property is not set", bSucess );
CPPUNIT_ASSERT_MESSAGE("MediaURL is empty", !sAudioURL.isEmpty());
CPPUNIT_ASSERT_MESSAGE( "sAudioURL and sVideoURL should not be equal", sAudioURL != sVideoURL );
......
......@@ -66,6 +66,7 @@ struct SdrMediaObj::Impl
::avmedia::MediaItem m_MediaProperties;
::boost::shared_ptr< MediaTempFile > m_pTempFile;
uno::Reference< graphic::XGraphic > m_xCachedSnapshot;
OUString m_LastFailedPkgURL;
};
TYPEINIT1( SdrMediaObj, SdrRectObj );
......@@ -326,6 +327,53 @@ static bool lcl_HandleJsonPackageURL(
}
#endif
static bool lcl_CopyToTempFile(
uno::Reference<io::XInputStream> const& xInStream,
OUString & o_rTempFileURL)
{
OUString tempFileURL;
::osl::FileBase::RC const err =
::osl::FileBase::createTempFile(0, 0, & tempFileURL);
if (::osl::FileBase::E_None != err)
{
SAL_INFO("svx", "cannot create temp file");
return false;
}
try
{
::ucbhelper::Content tempContent(tempFileURL,
uno::Reference<ucb::XCommandEnvironment>(),
comphelper::getProcessComponentContext());
tempContent.writeStream(xInStream, true); // copy stream to file
}
catch (uno::Exception const& e)
{
SAL_WARN("svx", "exception: '" << e.Message << "'");
return false;
}
o_rTempFileURL = tempFileURL;
return true;
}
void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
{
if (m_pImpl->m_pTempFile || m_pImpl->m_LastFailedPkgURL.isEmpty())
{
SAL_WARN("svx", "this is only intended for embedded media");
return;
}
OUString tempFileURL;
bool const bSuccess = lcl_CopyToTempFile(xStream, tempFileURL);
if (bSuccess)
{
m_pImpl->m_pTempFile.reset(new MediaTempFile(tempFileURL));
m_pImpl->m_MediaProperties.setURL(
m_pImpl->m_LastFailedPkgURL, tempFileURL, "");
}
m_pImpl->m_LastFailedPkgURL = ""; // once only
}
/// copy a stream from XStorage to temp file
static bool lcl_HandlePackageURL(
OUString const & rURL,
......@@ -357,30 +405,7 @@ static bool lcl_HandlePackageURL(
SAL_WARN("svx", "no stream?");
return false;
}
OUString tempFileURL;
::osl::FileBase::RC const err =
::osl::FileBase::createTempFile(0, 0, & tempFileURL);
if (::osl::FileBase::E_None != err)
{
SAL_INFO("svx", "cannot create temp file");
return false;
}
try
{
::ucbhelper::Content tempContent(tempFileURL,
uno::Reference<ucb::XCommandEnvironment>(),
comphelper::getProcessComponentContext());
tempContent.writeStream(xInStream, true); // copy stream to file
}
catch (uno::Exception const& e)
{
SAL_WARN("svx", "exception: '" << e.Message << "'");
return false;
}
o_rTempFileURL = tempFileURL;
return true;
return lcl_CopyToTempFile(xInStream, o_rTempFileURL);
}
void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
......@@ -420,6 +445,9 @@ void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProper
{
m_pImpl->m_pTempFile.reset();
m_pImpl->m_MediaProperties.setURL("", "", "");
// UGLY: oox import also gets here, because unlike ODF
// getDocumentStorage() is not the imported file...
m_pImpl->m_LastFailedPkgURL = url;
}
}
else
......
......@@ -730,7 +730,7 @@ SfxItemPropertyMapEntry const * ImplGetSvxMediaShapePropertyMap()
// #i68101#
{ OUString(UNO_NAME_MISC_OBJ_TITLE), OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
{ OUString(UNO_NAME_MISC_OBJ_DESCRIPTION), OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
{OUString("PrivateStream"), OWN_ATTR_MEDIA_STREAM, cppu::UnoType<css::io::XInputStream>::get(), ::com::sun::star::beans::PropertyAttribute::READONLY, 0},
{OUString("PrivateStream"), OWN_ATTR_MEDIA_STREAM, cppu::UnoType<css::io::XInputStream>::get(), 0, 0},
{OUString("PrivateTempFileURL"), OWN_ATTR_MEDIA_TEMPFILEURL, cppu::UnoType<OUString>::get(), ::com::sun::star::beans::PropertyAttribute::READONLY, 0},
{ OUString("MediaMimeType"), OWN_ATTR_MEDIA_MIMETYPE, cppu::UnoType<OUString>::get(), 0, 0},
{ OUString("FallbackGraphic"), OWN_ATTR_FALLBACK_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), ::com::sun::star::beans::PropertyAttribute::READONLY, 0},
......
......@@ -808,6 +808,7 @@ SvxMediaShape::~SvxMediaShape() throw()
bool SvxMediaShape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertySimpleEntry* pProperty, const ::com::sun::star::uno::Any& rValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException)
{
if( ((pProperty->nWID >= OWN_ATTR_MEDIA_URL) && (pProperty->nWID <= OWN_ATTR_MEDIA_ZOOM))
|| (pProperty->nWID == OWN_ATTR_MEDIA_STREAM)
|| (pProperty->nWID == OWN_ATTR_MEDIA_MIMETYPE) )
{
SdrMediaObj* pMedia = static_cast< SdrMediaObj* >( mpObj.get() );
......@@ -886,6 +887,31 @@ bool SvxMediaShape::setPropertyValueImpl( const OUString& rName, const SfxItemPr
}
break;
case OWN_ATTR_MEDIA_STREAM:
try
{
uno::Reference<io::XInputStream> xStream;
if (rValue >>= xStream)
{
pMedia->SetInputStream(xStream);
}
}
catch (const css::ucb::ContentCreationException& e)
{
throw css::lang::WrappedTargetException(
"ContentCreationException Setting InputStream!",
static_cast<OWeakObject *>(this),
makeAny(e));
}
catch (const css::ucb::CommandFailedException& e)
{
throw css::lang::WrappedTargetException(
"CommandFailedException Setting InputStream!",
static_cast<OWeakObject *>(this),
makeAny(e));
}
break;
default:
OSL_FAIL("SvxMediaShape::setPropertyValueImpl(), unknown argument!");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment