1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/xls/biffdetector.hxx" 29 30 #include <algorithm> 31 #include <com/sun/star/io/XInputStream.hpp> 32 #include <com/sun/star/uno/XComponentContext.hpp> 33 #include <comphelper/mediadescriptor.hxx> 34 #include <rtl/strbuf.hxx> 35 #include "oox/helper/binaryinputstream.hxx" 36 #include "oox/ole/olestorage.hxx" 37 38 namespace oox { 39 namespace xls { 40 41 // ============================================================================ 42 43 using namespace ::com::sun::star::beans; 44 using namespace ::com::sun::star::io; 45 using namespace ::com::sun::star::lang; 46 using namespace ::com::sun::star::uno; 47 48 using ::comphelper::MediaDescriptor; 49 using ::rtl::OStringBuffer; 50 using ::rtl::OUString; 51 52 // ============================================================================ 53 54 Sequence< OUString > BiffDetector_getSupportedServiceNames() 55 { 56 Sequence< OUString > aServiceNames( 1 ); 57 aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.frame.ExtendedTypeDetection" ); 58 return aServiceNames; 59 } 60 61 OUString BiffDetector_getImplementationName() 62 { 63 return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.BiffDetector" ); 64 } 65 66 Reference< XInterface > SAL_CALL BiffDetector_createInstance( const Reference< XComponentContext >& rxContext ) throw( Exception ) 67 { 68 return static_cast< ::cppu::OWeakObject* >( new BiffDetector( rxContext ) ); 69 } 70 71 // ============================================================================ 72 73 BiffDetector::BiffDetector( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) : 74 mxContext( rxContext, UNO_SET_THROW ) 75 { 76 } 77 78 BiffDetector::~BiffDetector() 79 { 80 } 81 82 /*static*/ BiffType BiffDetector::detectStreamBiffVersion( BinaryInputStream& rInStream ) 83 { 84 BiffType eBiff = BIFF_UNKNOWN; 85 if( !rInStream.isEof() && rInStream.isSeekable() && (rInStream.size() > 4) ) 86 { 87 sal_Int64 nOldPos = rInStream.tell(); 88 rInStream.seekToStart(); 89 sal_uInt16 nBofId, nBofSize; 90 rInStream >> nBofId >> nBofSize; 91 92 if( (4 <= nBofSize) && (nBofSize <= 16) && (rInStream.tell() + nBofSize <= rInStream.size()) ) 93 { 94 switch( nBofId ) 95 { 96 case BIFF2_ID_BOF: 97 eBiff = BIFF2; 98 break; 99 case BIFF3_ID_BOF: 100 eBiff = BIFF3; 101 break; 102 case BIFF4_ID_BOF: 103 eBiff = BIFF4; 104 break; 105 case BIFF5_ID_BOF: 106 { 107 if( 6 <= nBofSize ) 108 { 109 sal_uInt16 nVersion; 110 rInStream >> nVersion; 111 // #i23425# #i44031# #i62752# there are some *really* broken documents out there... 112 switch( nVersion & 0xFF00 ) 113 { 114 case 0: eBiff = BIFF5; break; // #i44031# #i62752# 115 case BIFF_BOF_BIFF2: eBiff = BIFF2; break; 116 case BIFF_BOF_BIFF3: eBiff = BIFF3; break; 117 case BIFF_BOF_BIFF4: eBiff = BIFF4; break; 118 case BIFF_BOF_BIFF5: eBiff = BIFF5; break; 119 case BIFF_BOF_BIFF8: eBiff = BIFF8; break; 120 default: OSL_ENSURE( false, 121 OStringBuffer( "lclDetectStreamBiffVersion - unknown BIFF version: 0x" ). 122 append( static_cast< sal_Int32 >( nVersion ), 16 ).getStr() ); 123 } 124 } 125 } 126 break; 127 // else do nothing, no BIFF stream 128 } 129 } 130 rInStream.seek( nOldPos ); 131 } 132 return eBiff; 133 } 134 135 /*static*/ BiffType BiffDetector::detectStorageBiffVersion( OUString& orWorkbookStreamName, const StorageRef& rxStorage ) 136 { 137 static const OUString saBookName = CREATE_OUSTRING( "Book" ); 138 static const OUString saWorkbookName = CREATE_OUSTRING( "Workbook" ); 139 140 BiffType eBiff = BIFF_UNKNOWN; 141 if( rxStorage.get() ) 142 { 143 if( rxStorage->isStorage() ) 144 { 145 // try to open the "Book" stream 146 BinaryXInputStream aBookStrm5( rxStorage->openInputStream( saBookName ), true ); 147 BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 ); 148 149 // try to open the "Workbook" stream 150 BinaryXInputStream aBookStrm8( rxStorage->openInputStream( saWorkbookName ), true ); 151 BiffType eBookStrm8Biff = detectStreamBiffVersion( aBookStrm8 ); 152 153 // decide which stream to use 154 if( (eBookStrm8Biff != BIFF_UNKNOWN) && ((eBookStrm5Biff == BIFF_UNKNOWN) || (eBookStrm8Biff > eBookStrm5Biff)) ) 155 { 156 /* Only "Workbook" stream exists; or both streams exist, and 157 "Workbook" has higher BIFF version than "Book" stream. */ 158 eBiff = eBookStrm8Biff; 159 orWorkbookStreamName = saWorkbookName; 160 } 161 else if( eBookStrm5Biff != BIFF_UNKNOWN ) 162 { 163 /* Only "Book" stream exists; or both streams exist, and 164 "Book" has higher BIFF version than "Workbook" stream. */ 165 eBiff = eBookStrm5Biff; 166 orWorkbookStreamName = saBookName; 167 } 168 } 169 else 170 { 171 // no storage, try plain input stream from medium (even for BIFF5+) 172 BinaryXInputStream aStrm( rxStorage->openInputStream( OUString() ), false ); 173 eBiff = detectStreamBiffVersion( aStrm ); 174 orWorkbookStreamName = OUString(); 175 } 176 } 177 178 return eBiff; 179 } 180 181 // com.sun.star.lang.XServiceInfo interface ----------------------------------- 182 183 OUString SAL_CALL BiffDetector::getImplementationName() throw( RuntimeException ) 184 { 185 return BiffDetector_getImplementationName(); 186 } 187 188 sal_Bool SAL_CALL BiffDetector::supportsService( const OUString& rService ) throw( RuntimeException ) 189 { 190 const Sequence< OUString > aServices = BiffDetector_getSupportedServiceNames(); 191 const OUString* pArray = aServices.getConstArray(); 192 const OUString* pArrayEnd = pArray + aServices.getLength(); 193 return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd; 194 } 195 196 Sequence< OUString > SAL_CALL BiffDetector::getSupportedServiceNames() throw( RuntimeException ) 197 { 198 return BiffDetector_getSupportedServiceNames(); 199 } 200 201 // com.sun.star.document.XExtendedFilterDetect interface ---------------------- 202 203 OUString SAL_CALL BiffDetector::detect( Sequence< PropertyValue >& rDescriptor ) throw( RuntimeException ) 204 { 205 OUString aTypeName; 206 207 MediaDescriptor aDescriptor( rDescriptor ); 208 aDescriptor.addInputStream(); 209 210 Reference< XInputStream > xInStrm( aDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY_THROW ); 211 StorageRef xStorage( new ::oox::ole::OleStorage( mxContext, xInStrm, true ) ); 212 213 OUString aWorkbookName; 214 switch( detectStorageBiffVersion( aWorkbookName, xStorage ) ) 215 { 216 case BIFF2: 217 case BIFF3: 218 case BIFF4: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_40" ); break; 219 case BIFF5: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_95" ); break; 220 case BIFF8: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_97" ); break; 221 default:; 222 } 223 224 return aTypeName; 225 } 226 227 // ============================================================================ 228 229 } // namespace xls 230 } // namespace oox 231