1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "swdetect.hxx" 21 22 #include <cppuhelper/supportsservice.hxx> 23 #include <com/sun/star/io/XInputStream.hpp> 24 #include <com/sun/star/uno/XComponentContext.hpp> 25 #include <sfx2/docfile.hxx> 26 #include <sot/storage.hxx> 27 #include <unotools/mediadescriptor.hxx> 28 29 using namespace ::com::sun::star; 30 using namespace ::com::sun::star::uno; 31 using namespace ::com::sun::star::io; 32 using namespace ::com::sun::star::task; 33 using namespace ::com::sun::star::beans; 34 using namespace ::com::sun::star::lang; 35 using utl::MediaDescriptor; 36 37 SwFilterDetect::SwFilterDetect() 38 { 39 } 40 41 SwFilterDetect::~SwFilterDetect() 42 { 43 } 44 45 OUString SAL_CALL SwFilterDetect::detect( Sequence< PropertyValue >& lDescriptor ) 46 { 47 MediaDescriptor aMediaDesc( lDescriptor ); 48 OUString aTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME(), OUString() ); 49 uno::Reference< io::XInputStream > xInStream ( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM()], uno::UNO_QUERY ); 50 if ( !xInStream.is() ) 51 return OUString(); 52 53 SfxMedium aMedium; 54 aMedium.UseInteractionHandler( false ); 55 aMedium.setStreamToLoadFrom( xInStream, true ); 56 57 SvStream *pInStrm = aMedium.GetInStream(); 58 if ( !pInStrm || pInStrm->GetError() ) 59 return OUString(); 60 61 bool bIsDetected = false; 62 63 if ( aTypeName == "writer_Rich_Text_Format" ) 64 { 65 pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); 66 bIsDetected = ( read_uInt8s_ToOString( *pInStrm, 5 ) == "{\\rtf" ); 67 } 68 else if ( aTypeName == "writer_MS_WinWord_5" ) 69 { 70 pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); 71 const sal_uInt8 nBufSize = 3; 72 sal_uInt8 nBuffer[ nBufSize ]; 73 if (pInStrm->ReadBytes(nBuffer, nBufSize) < nBufSize) 74 return OUString(); 75 76 bIsDetected = (nBuffer[0] == 0x9B && nBuffer[1] == 0xA5 && nBuffer[2] == 0x21) // WinWord 1 77 || (nBuffer[0] == 0x9C && nBuffer[1] == 0xA5 && nBuffer[2] == 0x21) // PMWord 1 78 || (nBuffer[0] == 0xDB && nBuffer[1] == 0xA5 && nBuffer[2] == 0x2D) // WinWord 2 79 || (nBuffer[0] == 0xDC && nBuffer[1] == 0xA5 && nBuffer[2] == 0x65); // WinWord 6.0/95, as a single stream file 80 } 81 else 82 { 83 // Do not attempt to create an SotStorage on a 84 // 0-length stream as that would create the compound 85 // document header on the stream and effectively write to 86 // disk! 87 pInStrm->Seek( STREAM_SEEK_TO_BEGIN ); 88 if ( pInStrm->remainingSize() == 0 ) 89 return OUString(); 90 91 try 92 { 93 tools::SvRef<SotStorage> aStorage = new SotStorage ( pInStrm, false ); 94 if ( !aStorage->GetError() ) 95 { 96 bIsDetected = aStorage->IsContained( "WordDocument" ); 97 if ( bIsDetected && aTypeName.startsWith( "writer_MS_Word_97" ) ) 98 { 99 bIsDetected = ( aStorage->IsContained("0Table") || aStorage->IsContained("1Table") ); 100 101 // If we are checking the template type, and the document is not a .dot, don't 102 // mis-detect it. 103 if ( bIsDetected && aTypeName == "writer_MS_Word_97_Vorlage" ) 104 { 105 // Super ugly hack, but we don't want to use the whole WW8Fib thing here in 106 // the swd library, apparently. We know (do we?) that the "aBits1" byte, as 107 // the variable is called in WW8Fib::WW8Fib(SvStream&,sal_uInt8,sal_uInt32), 108 // is at offset 10 in the WordDocument stream. The fDot bit is bit 0x01 of 109 // that byte. 110 tools::SvRef<SotStorageStream> xWordDocument = aStorage->OpenSotStream("WordDocument", StreamMode::STD_READ); 111 xWordDocument->Seek( 10 ); 112 if ( xWordDocument->Tell() == 10 ) 113 { 114 sal_uInt8 aBits1; 115 xWordDocument->ReadUChar( aBits1 ); 116 // Check fDot bit 117 bIsDetected = ((aBits1 & 0x01) == 0x01); 118 } 119 } 120 } 121 } 122 } 123 catch (...) 124 { 125 bIsDetected = false; 126 } 127 } 128 129 if ( bIsDetected ) 130 return aTypeName; 131 132 return OUString(); 133 } 134 135 /* XServiceInfo */ 136 OUString SAL_CALL SwFilterDetect::getImplementationName() 137 { 138 return "com.sun.star.comp.writer.FormatDetector"; 139 } 140 141 /* XServiceInfo */ 142 sal_Bool SAL_CALL SwFilterDetect::supportsService( const OUString& sServiceName ) 143 { 144 return cppu::supportsService(this, sServiceName); 145 } 146 147 /* XServiceInfo */ 148 Sequence< OUString > SAL_CALL SwFilterDetect::getSupportedServiceNames() 149 { 150 return { "com.sun.star.frame.ExtendedTypeDetection", "com.sun.star.text.FormatDetector", "com.sun.star.text.W4WFormatDetector" }; 151 } 152 153 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* 154 com_sun_star_comp_writer_FormatDetector_get_implementation(css::uno::XComponentContext*, 155 css::uno::Sequence<css::uno::Any> const &) 156 { 157 return cppu::acquire(new SwFilterDetect()); 158 } 159 160 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 161
