Kaydet (Commit) 97fa7024 authored tarafından Miklos Vajna's avatar Miklos Vajna

Related: tdf#108269 oox: allow recovering broken DOCM files

The content type inside an OOXML file differs for DOCX and DOCM. These
must be in sync with the file extension, otherwise MSO refuses to open
the file. We used to always write the DOCX content-type even for files
which had the DOCM extension.

Allow users to recover those broken files by detecting a "has docm
extension but docx content-type" file as docm, so re-saving it will
produce output that's accepted by MSO as well.

Change-Id: I7d60c6f6c1d0421e95b3dc9e8fff617f101919f5
Reviewed-on: https://gerrit.libreoffice.org/38342Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst f883a6b4
...@@ -61,7 +61,7 @@ namespace core { ...@@ -61,7 +61,7 @@ namespace core {
class FilterDetectDocHandler : public ::cppu::WeakImplHelper< css::xml::sax::XFastDocumentHandler > class FilterDetectDocHandler : public ::cppu::WeakImplHelper< css::xml::sax::XFastDocumentHandler >
{ {
public: public:
explicit FilterDetectDocHandler( const css::uno::Reference< css::uno::XComponentContext >& rxContext, OUString& rFilter ); explicit FilterDetectDocHandler( const css::uno::Reference< css::uno::XComponentContext >& rxContext, OUString& rFilter, const OUString& rFileName );
virtual ~FilterDetectDocHandler() override; virtual ~FilterDetectDocHandler() override;
// XFastDocumentHandler // XFastDocumentHandler
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
private: private:
void parseRelationship( const AttributeList& rAttribs ); void parseRelationship( const AttributeList& rAttribs );
static OUString getFilterNameFromContentType( const OUString& rContentType ); static OUString getFilterNameFromContentType( const OUString& rContentType, const OUString& rFileName );
void parseContentTypesDefault( const AttributeList& rAttribs ); void parseContentTypesDefault( const AttributeList& rAttribs );
void parseContentTypesOverride( const AttributeList& rAttribs ); void parseContentTypesOverride( const AttributeList& rAttribs );
...@@ -89,6 +89,7 @@ private: ...@@ -89,6 +89,7 @@ private:
typedef ::std::vector< sal_Int32 > ContextVector; typedef ::std::vector< sal_Int32 > ContextVector;
OUString& mrFilterName; OUString& mrFilterName;
OUString maFileName;
ContextVector maContextStack; ContextVector maContextStack;
OUString maTargetPath; OUString maTargetPath;
css::uno::Reference< css::uno::XComponentContext > mxContext; css::uno::Reference< css::uno::XComponentContext > mxContext;
......
...@@ -52,8 +52,9 @@ using utl::MediaDescriptor; ...@@ -52,8 +52,9 @@ using utl::MediaDescriptor;
using comphelper::IDocPasswordVerifier; using comphelper::IDocPasswordVerifier;
using comphelper::DocPasswordVerifierResult; using comphelper::DocPasswordVerifierResult;
FilterDetectDocHandler::FilterDetectDocHandler( const Reference< XComponentContext >& rxContext, OUString& rFilterName ) : FilterDetectDocHandler::FilterDetectDocHandler( const Reference< XComponentContext >& rxContext, OUString& rFilterName, const OUString& rFileName ) :
mrFilterName( rFilterName ), mrFilterName( rFilterName ),
maFileName(rFileName),
mxContext( rxContext ) mxContext( rxContext )
{ {
maContextStack.reserve( 2 ); maContextStack.reserve( 2 );
...@@ -160,12 +161,12 @@ void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs ) ...@@ -160,12 +161,12 @@ void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs )
} }
} }
OUString FilterDetectDocHandler::getFilterNameFromContentType( const OUString& rContentType ) OUString FilterDetectDocHandler::getFilterNameFromContentType( const OUString& rContentType, const OUString& rFileName )
{ {
if( rContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" ) if( rContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" && !rFileName.endsWith("docm") )
return OUString( "writer_MS_Word_2007" ); return OUString( "writer_MS_Word_2007" );
if( rContentType == "application/vnd.ms-word.document.macroEnabled.main+xml" ) if( rContentType == "application/vnd.ms-word.document.macroEnabled.main+xml" || rFileName.endsWith("docm") )
return OUString( "writer_MS_Word_2007_VBA" ); return OUString( "writer_MS_Word_2007_VBA" );
if( rContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml" || if( rContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml" ||
...@@ -209,14 +210,14 @@ void FilterDetectDocHandler::parseContentTypesDefault( const AttributeList& rAtt ...@@ -209,14 +210,14 @@ void FilterDetectDocHandler::parseContentTypesDefault( const AttributeList& rAtt
OUString aExtension = rAttribs.getString( XML_Extension, OUString() ); OUString aExtension = rAttribs.getString( XML_Extension, OUString() );
sal_Int32 nExtPos = maTargetPath.getLength() - aExtension.getLength(); sal_Int32 nExtPos = maTargetPath.getLength() - aExtension.getLength();
if( (nExtPos > 0) && (maTargetPath[ nExtPos - 1 ] == '.') && maTargetPath.match( aExtension, nExtPos ) ) if( (nExtPos > 0) && (maTargetPath[ nExtPos - 1 ] == '.') && maTargetPath.match( aExtension, nExtPos ) )
mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) ); mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ), maFileName );
} }
} }
void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAttribs ) void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAttribs )
{ {
if( rAttribs.getString( XML_PartName, OUString() ).equals( maTargetPath ) ) if( rAttribs.getString( XML_PartName, OUString() ).equals( maTargetPath ) )
mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) ); mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ), maFileName );
} }
/* Helper for XServiceInfo */ /* Helper for XServiceInfo */
...@@ -400,7 +401,11 @@ OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq ...@@ -400,7 +401,11 @@ OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq
aParser.registerNamespace( NMSP_packageRel ); aParser.registerNamespace( NMSP_packageRel );
aParser.registerNamespace( NMSP_officeRel ); aParser.registerNamespace( NMSP_officeRel );
aParser.registerNamespace( NMSP_packageContentTypes ); aParser.registerNamespace( NMSP_packageContentTypes );
aParser.setDocumentHandler( new FilterDetectDocHandler( mxContext, aFilterName ) );
OUString aFileName;
aMediaDescriptor[utl::MediaDescriptor::PROP_URL()] >>= aFileName;
aParser.setDocumentHandler( new FilterDetectDocHandler( mxContext, aFilterName, aFileName ) );
/* Parse '_rels/.rels' to get the target path and '[Content_Types].xml' /* Parse '_rels/.rels' to get the target path and '[Content_Types].xml'
to determine the content type of the part at the target path. */ to determine the content type of the part at the target path. */
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#include <com/sun/star/text/HoriOrientation.hpp> #include <com/sun/star/text/HoriOrientation.hpp>
#include <com/sun/star/text/RelOrientation.hpp> #include <com/sun/star/text/RelOrientation.hpp>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
class Test : public SwModelTestBase class Test : public SwModelTestBase
{ {
public: public:
...@@ -82,6 +85,14 @@ DECLARE_SW_ROUNDTRIP_TEST(testDocmSave, "hello.docm", nullptr, DocmTest) ...@@ -82,6 +85,14 @@ DECLARE_SW_ROUNDTRIP_TEST(testDocmSave, "hello.docm", nullptr, DocmTest)
"application/vnd.ms-word.document.macroEnabled.main+xml"); "application/vnd.ms-word.document.macroEnabled.main+xml");
} }
DECLARE_SW_ROUNDTRIP_TEST(testBadDocm, "bad.docm", nullptr, DocmTest)
{
SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
CPPUNIT_ASSERT(pTextDoc);
// This was 'MS Word 2007 XML', broken docm files were not recognized.
CPPUNIT_ASSERT_EQUAL(OUString("MS Word 2007 XML VBA"), pTextDoc->GetDocShell()->GetMedium()->GetFilter()->GetName());
}
DECLARE_OOXMLEXPORT_TEST(testTdf92045, "tdf92045.docx") DECLARE_OOXMLEXPORT_TEST(testTdf92045, "tdf92045.docx")
{ {
// This was true, <w:effect w:val="none"/> resulted in setting the blinking font effect. // This was true, <w:effect w:val="none"/> resulted in setting the blinking font effect.
......
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