handle Keynote package format too
Change-Id: I3023bcba0a3d3bd83aca56e4ef72a892da5b55cf
This commit is contained in:
@@ -35,6 +35,7 @@ $(eval $(call gb_Library_use_libraries,wpftimpress,\
|
||||
sal \
|
||||
sot \
|
||||
tl \
|
||||
ucbhelper \
|
||||
utl \
|
||||
xo \
|
||||
$(gb_UWINAPI) \
|
||||
|
@@ -38,6 +38,7 @@ $(eval $(call gb_StaticLibrary_use_api,writerperfect,\
|
||||
))
|
||||
|
||||
$(eval $(call gb_StaticLibrary_add_exception_objects,writerperfect,\
|
||||
writerperfect/source/common/DirectoryStream \
|
||||
writerperfect/source/common/DocumentHandler \
|
||||
writerperfect/source/common/WPXSvStream \
|
||||
))
|
||||
|
164
writerperfect/source/common/DirectoryStream.cxx
Normal file
164
writerperfect/source/common/DirectoryStream.cxx
Normal file
@@ -0,0 +1,164 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* writerperfect
|
||||
* Version: MPL 2.0 / LGPLv2.1+
|
||||
*
|
||||
* 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/.
|
||||
*
|
||||
* Major Contributor(s):
|
||||
* Copyright (C) 2007 Fridrich Strba (fridrich.strba@bluewin.ch)
|
||||
*
|
||||
* For minor contributions see the git repository.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU Lesser General Public License Version 2.1 or later
|
||||
* (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
|
||||
* applicable instead of those above.
|
||||
*
|
||||
* For further information visit http://libwpd.sourceforge.net
|
||||
*/
|
||||
|
||||
#include <com/sun/star/io/XInputStream.hpp>
|
||||
#include <com/sun/star/sdbc/XResultSet.hpp>
|
||||
#include <com/sun/star/sdbc/XRow.hpp>
|
||||
#include <com/sun/star/ucb/XContent.hpp>
|
||||
#include <com/sun/star/ucb/XContentAccess.hpp>
|
||||
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
|
||||
|
||||
#include <com/sun/star/uno/Reference.hxx>
|
||||
#include <com/sun/star/uno/Sequence.hxx>
|
||||
|
||||
#include <comphelper/processfactory.hxx>
|
||||
|
||||
#include <rtl/ustring.hxx>
|
||||
|
||||
#include <ucbhelper/content.hxx>
|
||||
|
||||
#include "DirectoryStream.hxx"
|
||||
#include "WPXSvStream.hxx"
|
||||
|
||||
namespace io = com::sun::star::io;
|
||||
namespace sdbc = com::sun::star::sdbc;
|
||||
namespace ucb = com::sun::star::ucb;
|
||||
namespace uno = com::sun::star::uno;
|
||||
|
||||
namespace writerperfect
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct NotADirectoryException
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
uno::Reference<io::XInputStream> findStream(ucbhelper::Content &rContent, const rtl::OUString &rName)
|
||||
{
|
||||
uno::Reference<io::XInputStream> xInputStream;
|
||||
|
||||
uno::Sequence<rtl::OUString> lPropNames(1);
|
||||
lPropNames[0] = "Title";
|
||||
try
|
||||
{
|
||||
const uno::Reference<sdbc::XResultSet> xResultSet(
|
||||
rContent.createCursor(lPropNames, ucbhelper::INCLUDE_DOCUMENTS_ONLY));
|
||||
if (xResultSet->first())
|
||||
{
|
||||
const uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, uno::UNO_QUERY_THROW);
|
||||
const uno::Reference<sdbc::XRow> xRow(xResultSet, uno::UNO_QUERY_THROW);
|
||||
do
|
||||
{
|
||||
const rtl::OUString aTitle(xRow->getString(1));
|
||||
if (aTitle == rName)
|
||||
{
|
||||
const uno::Reference<ucb::XContent> xSubContent(xContentAccess->queryContent());
|
||||
ucbhelper::Content aSubContent(xSubContent, uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
|
||||
xInputStream = aSubContent.openStream();
|
||||
break;
|
||||
}
|
||||
} while (xResultSet->next());
|
||||
}
|
||||
}
|
||||
catch (uno::RuntimeException)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
catch (uno::Exception)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
return xInputStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct DirectoryStream::Impl
|
||||
{
|
||||
Impl(const uno::Reference<ucb::XContent> &rxContent);
|
||||
|
||||
uno::Reference<ucb::XContent> xContent;
|
||||
};
|
||||
|
||||
DirectoryStream::Impl::Impl(const uno::Reference<ucb::XContent> &rxContent)
|
||||
: xContent(rxContent)
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryStream::DirectoryStream(const com::sun::star::uno::Reference<com::sun::star::ucb::XContent> &xContent)
|
||||
: m_pImpl(new Impl(xContent))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryStream::~DirectoryStream()
|
||||
{
|
||||
delete m_pImpl;
|
||||
}
|
||||
|
||||
bool DirectoryStream::isOLEStream()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
WPXInputStream *DirectoryStream::getDocumentOLEStream(const char *const pName)
|
||||
{
|
||||
WPXInputStream *input = 0;
|
||||
|
||||
ucbhelper::Content aContent(m_pImpl->xContent, uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
|
||||
const uno::Reference<io::XInputStream> xInputStream(findStream(aContent, rtl::OUString::createFromAscii(pName)));
|
||||
if (xInputStream.is())
|
||||
input = new WPXSvInputStream(xInputStream);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
const unsigned char *DirectoryStream::read(const unsigned long, unsigned long &nNumBytesRead)
|
||||
{
|
||||
nNumBytesRead = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DirectoryStream::seek(const long, const WPX_SEEK_TYPE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
long DirectoryStream::tell()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DirectoryStream::atEOS()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
48
writerperfect/source/common/DirectoryStream.hxx
Normal file
48
writerperfect/source/common/DirectoryStream.hxx
Normal file
@@ -0,0 +1,48 @@
|
||||
/* -*- 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/.
|
||||
*/
|
||||
|
||||
#ifndef DIRECTORYSTREAM_H_INCLUDED
|
||||
#define DIRECTORYSTREAM_H_INCLUDED
|
||||
|
||||
#include <libwpd-stream/libwpd-stream.h>
|
||||
|
||||
#include <com/sun/star/uno/Reference.h>
|
||||
|
||||
namespace com { namespace sun { namespace star { namespace ucb {
|
||||
class XContent;
|
||||
} } } }
|
||||
|
||||
namespace writerperfect
|
||||
{
|
||||
|
||||
class DirectoryStream : public WPXInputStream
|
||||
{
|
||||
struct Impl;
|
||||
|
||||
public:
|
||||
explicit DirectoryStream(const com::sun::star::uno::Reference<com::sun::star::ucb::XContent> &xContent);
|
||||
virtual ~DirectoryStream();
|
||||
|
||||
virtual bool isOLEStream();
|
||||
virtual WPXInputStream *getDocumentOLEStream(const char *pName);
|
||||
|
||||
virtual const unsigned char *read(unsigned long nNumBytes, unsigned long &nNumBytesRead);
|
||||
virtual int seek(long nOffset, WPX_SEEK_TYPE eSeekType);
|
||||
virtual long tell();
|
||||
virtual bool atEOS();
|
||||
|
||||
private:
|
||||
Impl *m_pImpl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DIRECTORYSTREAM_H_INCLUDED
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
@@ -7,10 +7,19 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <osl/diagnose.h>
|
||||
#include <rtl/tencinfo.h>
|
||||
|
||||
#include <comphelper/processfactory.hxx>
|
||||
#include <comphelper/types.hxx>
|
||||
|
||||
#include <com/sun/star/beans/NamedValue.hpp>
|
||||
#include <com/sun/star/container/XChild.hpp>
|
||||
#include <com/sun/star/io/XInputStream.hpp>
|
||||
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
|
||||
#include <com/sun/star/ucb/XContent.hpp>
|
||||
#include <com/sun/star/xml/sax/XAttributeList.hpp>
|
||||
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
|
||||
#include <com/sun/star/xml/sax/InputSource.hpp>
|
||||
@@ -18,17 +27,22 @@
|
||||
#include <com/sun/star/io/XSeekable.hpp>
|
||||
#include <com/sun/star/uno/Reference.h>
|
||||
|
||||
#include <ucbhelper/content.hxx>
|
||||
|
||||
#include <xmloff/attrlist.hxx>
|
||||
|
||||
#include <libetonyek/libetonyek.h>
|
||||
#include <libodfgen/libodfgen.hxx>
|
||||
|
||||
#include "common/DirectoryStream.hxx"
|
||||
#include "common/DocumentHandler.hxx"
|
||||
#include "common/WPXSvStream.hxx"
|
||||
#include "KeynoteImportFilter.hxx"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
using namespace ::com::sun::star::uno;
|
||||
using com::sun::star::uno::Reference;
|
||||
using com::sun::star::io::XInputStream;
|
||||
@@ -48,6 +62,46 @@ using com::sun::star::xml::sax::XAttributeList;
|
||||
using com::sun::star::xml::sax::XDocumentHandler;
|
||||
using com::sun::star::xml::sax::XParser;
|
||||
|
||||
namespace beans = com::sun::star::beans;
|
||||
namespace container = com::sun::star::container;
|
||||
namespace ucb = com::sun::star::ucb;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template<class T>
|
||||
sal_Bool lcl_queryIsPackage( const Sequence<T> &lComponentData )
|
||||
{
|
||||
sal_Bool bIsPackage = sal_False;
|
||||
|
||||
const sal_Int32 nLength = lComponentData.getLength();
|
||||
const T *pValue = lComponentData.getConstArray();
|
||||
for ( sal_Int32 i = 0; i < nLength; ++i)
|
||||
{
|
||||
if ( pValue[i].Name == "IsPackage" )
|
||||
{
|
||||
pValue[i].Value >>= bIsPackage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bIsPackage;
|
||||
}
|
||||
|
||||
sal_Bool lcl_isPackage( const Any &rComponentData )
|
||||
{
|
||||
Sequence < beans::NamedValue > lComponentDataNV;
|
||||
Sequence < beans::PropertyValue > lComponentDataPV;
|
||||
|
||||
if ( rComponentData >>= lComponentDataNV )
|
||||
return lcl_queryIsPackage( lComponentDataNV );
|
||||
else if ( rComponentData >>= lComponentDataPV )
|
||||
return lcl_queryIsPackage( lComponentDataPV );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sal_Bool SAL_CALL KeynoteImportFilter::filter( const Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor )
|
||||
throw (RuntimeException)
|
||||
@@ -56,10 +110,16 @@ throw (RuntimeException)
|
||||
sal_Int32 nLength = aDescriptor.getLength();
|
||||
const PropertyValue *pValue = aDescriptor.getConstArray();
|
||||
Reference < XInputStream > xInputStream;
|
||||
Reference < ucb::XContent > xContent;
|
||||
sal_Bool bIsPackage = sal_False;
|
||||
for ( sal_Int32 i = 0 ; i < nLength; i++)
|
||||
{
|
||||
if ( pValue[i].Name == "InputStream" )
|
||||
if ( pValue[i].Name == "ComponentData" )
|
||||
bIsPackage = lcl_isPackage( pValue[i].Value );
|
||||
else if ( pValue[i].Name == "InputStream" )
|
||||
pValue[i].Value >>= xInputStream;
|
||||
else if ( pValue[i].Name == "UCBContent" )
|
||||
pValue[i].Value >>= xContent;
|
||||
}
|
||||
if ( !xInputStream.is() )
|
||||
{
|
||||
@@ -67,6 +127,12 @@ throw (RuntimeException)
|
||||
return sal_False;
|
||||
}
|
||||
|
||||
if ( bIsPackage && !xContent.is() )
|
||||
{
|
||||
SAL_WARN("writerperfect", "the input claims to be a package, but does not have UCBContent");
|
||||
bIsPackage = false;
|
||||
}
|
||||
|
||||
// An XML import service: what we push sax messages to..
|
||||
Reference < XDocumentHandler > xInternalHandler(
|
||||
mxContext->getServiceManager()->createInstanceWithContext(
|
||||
@@ -81,10 +147,14 @@ throw (RuntimeException)
|
||||
// writes to in-memory target doc
|
||||
DocumentHandler xHandler(xInternalHandler);
|
||||
|
||||
WPXSvInputStream input( xInputStream );
|
||||
shared_ptr< WPXInputStream > input;
|
||||
if ( bIsPackage )
|
||||
input.reset( new writerperfect::DirectoryStream( xContent ) );
|
||||
else
|
||||
input.reset( new WPXSvInputStream( xInputStream ) );
|
||||
|
||||
OdpGenerator exporter(&xHandler, ODF_FLAT_XML);
|
||||
bool tmpParseResult = libetonyek::KEYDocument::parse(&input, &exporter);
|
||||
bool tmpParseResult = libetonyek::KEYDocument::parse(input.get(), &exporter);
|
||||
return tmpParseResult;
|
||||
}
|
||||
|
||||
@@ -107,37 +177,155 @@ OUString SAL_CALL KeynoteImportFilter::detect( com::sun::star::uno::Sequence< Pr
|
||||
throw( com::sun::star::uno::RuntimeException )
|
||||
{
|
||||
SAL_INFO("writerperfect", "KeynoteImportFilter::detect");
|
||||
OUString sTypeName;
|
||||
|
||||
sal_Int32 nLength = Descriptor.getLength();
|
||||
sal_Int32 location = nLength;
|
||||
sal_Int32 nNewLength = nLength + 2;
|
||||
sal_Int32 nComponentDataLocation = -1;
|
||||
sal_Int32 nTypeNameLocation = -1;
|
||||
sal_Int32 nUCBContentLocation = -1;
|
||||
bool bIsPackage = false;
|
||||
bool bUCBContentChanged = false;
|
||||
const PropertyValue *pValue = Descriptor.getConstArray();
|
||||
Reference < XInputStream > xInputStream;
|
||||
Reference < ucb::XContent > xContent;
|
||||
Sequence < beans::NamedValue > lComponentDataNV;
|
||||
Sequence < beans::PropertyValue > lComponentDataPV;
|
||||
bool bComponentDataNV = true;
|
||||
|
||||
for ( sal_Int32 i = 0 ; i < nLength; i++)
|
||||
{
|
||||
if ( pValue[i].Name == "TypeName" )
|
||||
location=i;
|
||||
{
|
||||
nTypeNameLocation = i;
|
||||
--nNewLength;
|
||||
}
|
||||
if ( pValue[i].Name == "ComponentData" )
|
||||
{
|
||||
bComponentDataNV = pValue[i].Value >>= lComponentDataNV;
|
||||
if (!bComponentDataNV)
|
||||
pValue[i].Value >>= lComponentDataPV;
|
||||
nComponentDataLocation = i;
|
||||
--nNewLength;
|
||||
}
|
||||
else if ( pValue[i].Name == "InputStream" )
|
||||
{
|
||||
pValue[i].Value >>= xInputStream;
|
||||
}
|
||||
else if ( pValue[i].Name == "UCBContent" )
|
||||
{
|
||||
pValue[i].Value >>= xContent;
|
||||
nUCBContentLocation = i;
|
||||
}
|
||||
}
|
||||
|
||||
assert(nNewLength >= nLength);
|
||||
|
||||
if (!xInputStream.is())
|
||||
return OUString();
|
||||
|
||||
WPXSvInputStream input( xInputStream );
|
||||
shared_ptr< WPXInputStream > input( new WPXSvInputStream( xInputStream ) );
|
||||
|
||||
if (libetonyek::KEYDocument::isSupported(&input))
|
||||
sTypeName = "impress_AppleKeynote";
|
||||
|
||||
if (!sTypeName.isEmpty())
|
||||
/* Apple Keynote documents come in two variants:
|
||||
* * actual files (zip), only produced by Keynote 5 (at least with
|
||||
* default settings)
|
||||
* * packages (IOW, directories), produced by Keynote 1-4 and again
|
||||
* starting with 6.
|
||||
* But since the libetonyek import only works with a stream, we need
|
||||
* to pass it one for the whole package. Here we determine if that
|
||||
* is needed.
|
||||
*
|
||||
* Note: for convenience, we also recognize that the main XML file
|
||||
* from a package was passed and pass the whole package to the
|
||||
* filter instead.
|
||||
*/
|
||||
if ( xContent.is() )
|
||||
{
|
||||
if ( location == nLength )
|
||||
ucbhelper::Content aContent( xContent, Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
|
||||
if ( aContent.isFolder() )
|
||||
{
|
||||
Descriptor.realloc(nLength+1);
|
||||
Descriptor[location].Name = "TypeName";
|
||||
input.reset( new writerperfect::DirectoryStream( xContent ) );
|
||||
bIsPackage = true;
|
||||
}
|
||||
|
||||
Descriptor[location].Value <<=sTypeName;
|
||||
libetonyek::KEYDocumentType type = libetonyek::KEY_DOCUMENT_TYPE_UNKNOWN;
|
||||
if ( !libetonyek::KEYDocument::isSupported( input.get(), &type ) )
|
||||
return OUString();
|
||||
|
||||
if ( type == libetonyek::KEY_DOCUMENT_TYPE_APXL_FILE )
|
||||
{
|
||||
assert( !bIsPackage );
|
||||
|
||||
const Reference < container::XChild > xChild( xContent, UNO_QUERY );
|
||||
if ( xChild.is() )
|
||||
{
|
||||
const Reference < ucb::XContent > xPackageContent( xChild->getParent(), UNO_QUERY );
|
||||
if ( xPackageContent.is() )
|
||||
{
|
||||
input.reset( new writerperfect::DirectoryStream( xPackageContent ) );
|
||||
if ( libetonyek::KEYDocument::isSupported( input.get() ) )
|
||||
{
|
||||
xContent = xPackageContent;
|
||||
bUCBContentChanged = true;
|
||||
bIsPackage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we do not need to insert ComponentData if this is not a package
|
||||
if ( !bIsPackage && ( nComponentDataLocation == -1 ) )
|
||||
--nNewLength;
|
||||
|
||||
if ( nNewLength > nLength )
|
||||
Descriptor.realloc( nNewLength );
|
||||
|
||||
if ( nTypeNameLocation == -1 )
|
||||
{
|
||||
assert( nLength < nNewLength );
|
||||
nTypeNameLocation = nLength++;
|
||||
Descriptor[nTypeNameLocation].Name = "TypeName";
|
||||
}
|
||||
|
||||
if ( bIsPackage && ( nComponentDataLocation == -1 ) )
|
||||
{
|
||||
assert( nLength < nNewLength );
|
||||
nComponentDataLocation = nLength++;
|
||||
Descriptor[nComponentDataLocation].Name = "ComponentData";
|
||||
}
|
||||
|
||||
if ( bIsPackage )
|
||||
{
|
||||
if (bComponentDataNV)
|
||||
{
|
||||
const sal_Int32 nCDSize = lComponentDataNV.getLength();
|
||||
lComponentDataNV.realloc( nCDSize + 1 );
|
||||
beans::NamedValue aValue;
|
||||
aValue.Name = "IsPackage";
|
||||
aValue.Value = comphelper::makeBoolAny(sal_True);
|
||||
lComponentDataNV[nCDSize] = aValue;
|
||||
Descriptor[nComponentDataLocation].Value <<= lComponentDataNV;
|
||||
}
|
||||
else
|
||||
{
|
||||
const sal_Int32 nCDSize = lComponentDataPV.getLength();
|
||||
lComponentDataPV.realloc( nCDSize + 1 );
|
||||
beans::PropertyValue aProp;
|
||||
aProp.Name = "IsPackage";
|
||||
aProp.Value = comphelper::makeBoolAny(sal_True);
|
||||
aProp.Handle = -1;
|
||||
aProp.State = beans::PropertyState_DIRECT_VALUE;
|
||||
lComponentDataPV[nCDSize] = aProp;
|
||||
Descriptor[nComponentDataLocation].Value <<= lComponentDataPV;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bUCBContentChanged )
|
||||
Descriptor[nUCBContentLocation].Value <<= xContent;
|
||||
|
||||
const OUString sTypeName("impress_AppleKeynote");
|
||||
Descriptor[nTypeNameLocation].Value <<= sTypeName;
|
||||
|
||||
return sTypeName;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user