summaryrefslogtreecommitdiff
path: root/oox/source/xls/biffdetector.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/xls/biffdetector.cxx')
-rw-r--r--oox/source/xls/biffdetector.cxx231
1 files changed, 231 insertions, 0 deletions
diff --git a/oox/source/xls/biffdetector.cxx b/oox/source/xls/biffdetector.cxx
new file mode 100644
index 000000000000..038d7d732425
--- /dev/null
+++ b/oox/source/xls/biffdetector.cxx
@@ -0,0 +1,231 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/biffdetector.hxx"
+
+#include <algorithm>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/mediadescriptor.hxx>
+#include <rtl/strbuf.hxx>
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/ole/olestorage.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+using ::comphelper::MediaDescriptor;
+using ::rtl::OStringBuffer;
+using ::rtl::OUString;
+
+// ============================================================================
+
+Sequence< OUString > BiffDetector_getSupportedServiceNames()
+{
+ Sequence< OUString > aServiceNames( 1 );
+ aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.frame.ExtendedTypeDetection" );
+ return aServiceNames;
+}
+
+OUString BiffDetector_getImplementationName()
+{
+ return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.BiffDetector" );
+}
+
+Reference< XInterface > SAL_CALL BiffDetector_createInstance( const Reference< XComponentContext >& rxContext ) throw( Exception )
+{
+ return static_cast< ::cppu::OWeakObject* >( new BiffDetector( rxContext ) );
+}
+
+// ============================================================================
+
+BiffDetector::BiffDetector( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
+ mxContext( rxContext, UNO_SET_THROW )
+{
+}
+
+BiffDetector::~BiffDetector()
+{
+}
+
+/*static*/ BiffType BiffDetector::detectStreamBiffVersion( BinaryInputStream& rInStream )
+{
+ BiffType eBiff = BIFF_UNKNOWN;
+ if( !rInStream.isEof() && rInStream.isSeekable() && (rInStream.getLength() > 4) )
+ {
+ sal_Int64 nOldPos = rInStream.tell();
+ rInStream.seekToStart();
+ sal_uInt16 nBofId, nBofSize;
+ rInStream >> nBofId >> nBofSize;
+
+ if( (4 <= nBofSize) && (nBofSize <= 16) && (rInStream.tell() + nBofSize <= rInStream.getLength()) )
+ {
+ switch( nBofId )
+ {
+ case BIFF2_ID_BOF:
+ eBiff = BIFF2;
+ break;
+ case BIFF3_ID_BOF:
+ eBiff = BIFF3;
+ break;
+ case BIFF4_ID_BOF:
+ eBiff = BIFF4;
+ break;
+ case BIFF5_ID_BOF:
+ {
+ if( 6 <= nBofSize )
+ {
+ sal_uInt16 nVersion;
+ rInStream >> nVersion;
+ // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
+ switch( nVersion & 0xFF00 )
+ {
+ case 0: eBiff = BIFF5; break; // #i44031# #i62752#
+ case BIFF_BOF_BIFF2: eBiff = BIFF2; break;
+ case BIFF_BOF_BIFF3: eBiff = BIFF3; break;
+ case BIFF_BOF_BIFF4: eBiff = BIFF4; break;
+ case BIFF_BOF_BIFF5: eBiff = BIFF5; break;
+ case BIFF_BOF_BIFF8: eBiff = BIFF8; break;
+ default: OSL_ENSURE( false,
+ OStringBuffer( "lclDetectStreamBiffVersion - unknown BIFF version: 0x" ).
+ append( static_cast< sal_Int32 >( nVersion ), 16 ).getStr() );
+ }
+ }
+ }
+ break;
+ // else do nothing, no BIFF stream
+ }
+ }
+ rInStream.seek( nOldPos );
+ }
+ return eBiff;
+}
+
+/*static*/ BiffType BiffDetector::detectStorageBiffVersion( OUString& orWorkbookStreamName, const StorageRef& rxStorage )
+{
+ static const OUString saBookName = CREATE_OUSTRING( "Book" );
+ static const OUString saWorkbookName = CREATE_OUSTRING( "Workbook" );
+
+ BiffType eBiff = BIFF_UNKNOWN;
+ if( rxStorage.get() )
+ {
+ if( rxStorage->isStorage() )
+ {
+ // try to open the "Book" stream
+ BinaryXInputStream aBookStrm5( rxStorage->openInputStream( saBookName ), true );
+ BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 );
+
+ // try to open the "Workbook" stream
+ BinaryXInputStream aBookStrm8( rxStorage->openInputStream( saWorkbookName ), true );
+ BiffType eBookStrm8Biff = detectStreamBiffVersion( aBookStrm8 );
+
+ // decide which stream to use
+ if( (eBookStrm8Biff != BIFF_UNKNOWN) && ((eBookStrm5Biff == BIFF_UNKNOWN) || (eBookStrm8Biff > eBookStrm5Biff)) )
+ {
+ /* Only "Workbook" stream exists; or both streams exist, and
+ "Workbook" has higher BIFF version than "Book" stream. */
+ eBiff = eBookStrm8Biff;
+ orWorkbookStreamName = saWorkbookName;
+ }
+ else if( eBookStrm5Biff != BIFF_UNKNOWN )
+ {
+ /* Only "Book" stream exists; or both streams exist, and
+ "Book" has higher BIFF version than "Workbook" stream. */
+ eBiff = eBookStrm5Biff;
+ orWorkbookStreamName = saBookName;
+ }
+ }
+ else
+ {
+ // no storage, try plain input stream from medium (even for BIFF5+)
+ BinaryXInputStream aStrm( rxStorage->openInputStream( OUString() ), false );
+ eBiff = detectStreamBiffVersion( aStrm );
+ orWorkbookStreamName = OUString();
+ }
+ }
+
+ return eBiff;
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL BiffDetector::getImplementationName() throw( RuntimeException )
+{
+ return BiffDetector_getImplementationName();
+}
+
+sal_Bool SAL_CALL BiffDetector::supportsService( const OUString& rService ) throw( RuntimeException )
+{
+ const Sequence< OUString > aServices = BiffDetector_getSupportedServiceNames();
+ const OUString* pArray = aServices.getConstArray();
+ const OUString* pArrayEnd = pArray + aServices.getLength();
+ return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
+}
+
+Sequence< OUString > SAL_CALL BiffDetector::getSupportedServiceNames() throw( RuntimeException )
+{
+ return BiffDetector_getSupportedServiceNames();
+}
+
+// com.sun.star.document.XExtendedFilterDetect interface ----------------------
+
+OUString SAL_CALL BiffDetector::detect( Sequence< PropertyValue >& rDescriptor ) throw( RuntimeException )
+{
+ OUString aTypeName;
+
+ MediaDescriptor aDescriptor( rDescriptor );
+ aDescriptor.addInputStream();
+
+ Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
+ Reference< XInputStream > xInStrm( aDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY_THROW );
+ StorageRef xStorage( new ::oox::ole::OleStorage( xFactory, xInStrm, true ) );
+
+ OUString aWorkbookName;
+ switch( detectStorageBiffVersion( aWorkbookName, xStorage ) )
+ {
+ case BIFF2:
+ case BIFF3:
+ case BIFF4: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_40" ); break;
+ case BIFF5: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_95" ); break;
+ case BIFF8: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_97" ); break;
+ default:;
+ }
+
+ return aTypeName;
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox