xref: /aoo41x/main/oox/source/xls/biffdetector.cxx (revision ca5ec200)
1*ca5ec200SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*ca5ec200SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*ca5ec200SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*ca5ec200SAndrew Rist  * distributed with this work for additional information
6*ca5ec200SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*ca5ec200SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*ca5ec200SAndrew Rist  * "License"); you may not use this file except in compliance
9*ca5ec200SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*ca5ec200SAndrew Rist  *
11*ca5ec200SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist  *
13*ca5ec200SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*ca5ec200SAndrew Rist  * software distributed under the License is distributed on an
15*ca5ec200SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ca5ec200SAndrew Rist  * KIND, either express or implied.  See the License for the
17*ca5ec200SAndrew Rist  * specific language governing permissions and limitations
18*ca5ec200SAndrew Rist  * under the License.
19*ca5ec200SAndrew Rist  *
20*ca5ec200SAndrew Rist  *************************************************************/
21*ca5ec200SAndrew Rist 
22*ca5ec200SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "oox/xls/biffdetector.hxx"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <algorithm>
27cdf0e10cSrcweir #include <com/sun/star/io/XInputStream.hpp>
28cdf0e10cSrcweir #include <com/sun/star/uno/XComponentContext.hpp>
29cdf0e10cSrcweir #include <comphelper/mediadescriptor.hxx>
30cdf0e10cSrcweir #include <rtl/strbuf.hxx>
31cdf0e10cSrcweir #include "oox/helper/binaryinputstream.hxx"
32cdf0e10cSrcweir #include "oox/ole/olestorage.hxx"
33cdf0e10cSrcweir 
34cdf0e10cSrcweir namespace oox {
35cdf0e10cSrcweir namespace xls {
36cdf0e10cSrcweir 
37cdf0e10cSrcweir // ============================================================================
38cdf0e10cSrcweir 
39cdf0e10cSrcweir using namespace ::com::sun::star::beans;
40cdf0e10cSrcweir using namespace ::com::sun::star::io;
41cdf0e10cSrcweir using namespace ::com::sun::star::lang;
42cdf0e10cSrcweir using namespace ::com::sun::star::uno;
43cdf0e10cSrcweir 
44cdf0e10cSrcweir using ::comphelper::MediaDescriptor;
45cdf0e10cSrcweir using ::rtl::OStringBuffer;
46cdf0e10cSrcweir using ::rtl::OUString;
47cdf0e10cSrcweir 
48cdf0e10cSrcweir // ============================================================================
49cdf0e10cSrcweir 
BiffDetector_getSupportedServiceNames()50cdf0e10cSrcweir Sequence< OUString > BiffDetector_getSupportedServiceNames()
51cdf0e10cSrcweir {
52cdf0e10cSrcweir     Sequence< OUString > aServiceNames( 1 );
53cdf0e10cSrcweir     aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.frame.ExtendedTypeDetection" );
54cdf0e10cSrcweir     return aServiceNames;
55cdf0e10cSrcweir }
56cdf0e10cSrcweir 
BiffDetector_getImplementationName()57cdf0e10cSrcweir OUString BiffDetector_getImplementationName()
58cdf0e10cSrcweir {
59cdf0e10cSrcweir     return CREATE_OUSTRING( "com.sun.star.comp.oox.xls.BiffDetector" );
60cdf0e10cSrcweir }
61cdf0e10cSrcweir 
BiffDetector_createInstance(const Reference<XComponentContext> & rxContext)62cdf0e10cSrcweir Reference< XInterface > SAL_CALL BiffDetector_createInstance( const Reference< XComponentContext >& rxContext ) throw( Exception )
63cdf0e10cSrcweir {
64cdf0e10cSrcweir     return static_cast< ::cppu::OWeakObject* >( new BiffDetector( rxContext ) );
65cdf0e10cSrcweir }
66cdf0e10cSrcweir 
67cdf0e10cSrcweir // ============================================================================
68cdf0e10cSrcweir 
BiffDetector(const Reference<XComponentContext> & rxContext)69cdf0e10cSrcweir BiffDetector::BiffDetector( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
70cdf0e10cSrcweir     mxContext( rxContext, UNO_SET_THROW )
71cdf0e10cSrcweir {
72cdf0e10cSrcweir }
73cdf0e10cSrcweir 
~BiffDetector()74cdf0e10cSrcweir BiffDetector::~BiffDetector()
75cdf0e10cSrcweir {
76cdf0e10cSrcweir }
77cdf0e10cSrcweir 
detectStreamBiffVersion(BinaryInputStream & rInStream)78cdf0e10cSrcweir /*static*/ BiffType BiffDetector::detectStreamBiffVersion( BinaryInputStream& rInStream )
79cdf0e10cSrcweir {
80cdf0e10cSrcweir     BiffType eBiff = BIFF_UNKNOWN;
81cdf0e10cSrcweir     if( !rInStream.isEof() && rInStream.isSeekable() && (rInStream.size() > 4) )
82cdf0e10cSrcweir     {
83cdf0e10cSrcweir         sal_Int64 nOldPos = rInStream.tell();
84cdf0e10cSrcweir         rInStream.seekToStart();
85cdf0e10cSrcweir         sal_uInt16 nBofId, nBofSize;
86cdf0e10cSrcweir         rInStream >> nBofId >> nBofSize;
87cdf0e10cSrcweir 
88cdf0e10cSrcweir         if( (4 <= nBofSize) && (nBofSize <= 16) && (rInStream.tell() + nBofSize <= rInStream.size()) )
89cdf0e10cSrcweir         {
90cdf0e10cSrcweir             switch( nBofId )
91cdf0e10cSrcweir             {
92cdf0e10cSrcweir                 case BIFF2_ID_BOF:
93cdf0e10cSrcweir                     eBiff = BIFF2;
94cdf0e10cSrcweir                 break;
95cdf0e10cSrcweir                 case BIFF3_ID_BOF:
96cdf0e10cSrcweir                     eBiff = BIFF3;
97cdf0e10cSrcweir                 break;
98cdf0e10cSrcweir                 case BIFF4_ID_BOF:
99cdf0e10cSrcweir                     eBiff = BIFF4;
100cdf0e10cSrcweir                 break;
101cdf0e10cSrcweir                 case BIFF5_ID_BOF:
102cdf0e10cSrcweir                 {
103cdf0e10cSrcweir                     if( 6 <= nBofSize )
104cdf0e10cSrcweir                     {
105cdf0e10cSrcweir                         sal_uInt16 nVersion;
106cdf0e10cSrcweir                         rInStream >> nVersion;
107cdf0e10cSrcweir                         // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
108cdf0e10cSrcweir                         switch( nVersion & 0xFF00 )
109cdf0e10cSrcweir                         {
110cdf0e10cSrcweir                             case 0:                 eBiff = BIFF5;  break;  // #i44031# #i62752#
111cdf0e10cSrcweir                             case BIFF_BOF_BIFF2:    eBiff = BIFF2;  break;
112cdf0e10cSrcweir                             case BIFF_BOF_BIFF3:    eBiff = BIFF3;  break;
113cdf0e10cSrcweir                             case BIFF_BOF_BIFF4:    eBiff = BIFF4;  break;
114cdf0e10cSrcweir                             case BIFF_BOF_BIFF5:    eBiff = BIFF5;  break;
115cdf0e10cSrcweir                             case BIFF_BOF_BIFF8:    eBiff = BIFF8;  break;
116cdf0e10cSrcweir                             default:    OSL_ENSURE( false,
117cdf0e10cSrcweir                                 OStringBuffer( "lclDetectStreamBiffVersion - unknown BIFF version: 0x" ).
118cdf0e10cSrcweir                                 append( static_cast< sal_Int32 >( nVersion ), 16 ).getStr() );
119cdf0e10cSrcweir                         }
120cdf0e10cSrcweir                     }
121cdf0e10cSrcweir                 }
122cdf0e10cSrcweir                 break;
123cdf0e10cSrcweir                 // else do nothing, no BIFF stream
124cdf0e10cSrcweir             }
125cdf0e10cSrcweir         }
126cdf0e10cSrcweir         rInStream.seek( nOldPos );
127cdf0e10cSrcweir     }
128cdf0e10cSrcweir     return eBiff;
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
detectStorageBiffVersion(OUString & orWorkbookStreamName,const StorageRef & rxStorage)131cdf0e10cSrcweir /*static*/ BiffType BiffDetector::detectStorageBiffVersion( OUString& orWorkbookStreamName, const StorageRef& rxStorage )
132cdf0e10cSrcweir {
133cdf0e10cSrcweir     static const OUString saBookName = CREATE_OUSTRING( "Book" );
134cdf0e10cSrcweir     static const OUString saWorkbookName = CREATE_OUSTRING( "Workbook" );
135cdf0e10cSrcweir 
136cdf0e10cSrcweir     BiffType eBiff = BIFF_UNKNOWN;
137cdf0e10cSrcweir     if( rxStorage.get() )
138cdf0e10cSrcweir     {
139cdf0e10cSrcweir         if( rxStorage->isStorage() )
140cdf0e10cSrcweir         {
141cdf0e10cSrcweir             // try to open the "Book" stream
142cdf0e10cSrcweir             BinaryXInputStream aBookStrm5( rxStorage->openInputStream( saBookName ), true );
143cdf0e10cSrcweir             BiffType eBookStrm5Biff = detectStreamBiffVersion( aBookStrm5 );
144cdf0e10cSrcweir 
145cdf0e10cSrcweir             // try to open the "Workbook" stream
146cdf0e10cSrcweir             BinaryXInputStream aBookStrm8( rxStorage->openInputStream( saWorkbookName ), true );
147cdf0e10cSrcweir             BiffType eBookStrm8Biff = detectStreamBiffVersion( aBookStrm8 );
148cdf0e10cSrcweir 
149cdf0e10cSrcweir             // decide which stream to use
150cdf0e10cSrcweir             if( (eBookStrm8Biff != BIFF_UNKNOWN) && ((eBookStrm5Biff == BIFF_UNKNOWN) || (eBookStrm8Biff > eBookStrm5Biff)) )
151cdf0e10cSrcweir             {
152cdf0e10cSrcweir                 /*  Only "Workbook" stream exists; or both streams exist, and
153cdf0e10cSrcweir                     "Workbook" has higher BIFF version than "Book" stream. */
154cdf0e10cSrcweir                 eBiff = eBookStrm8Biff;
155cdf0e10cSrcweir                 orWorkbookStreamName = saWorkbookName;
156cdf0e10cSrcweir             }
157cdf0e10cSrcweir             else if( eBookStrm5Biff != BIFF_UNKNOWN )
158cdf0e10cSrcweir             {
159cdf0e10cSrcweir                 /*  Only "Book" stream exists; or both streams exist, and
160cdf0e10cSrcweir                     "Book" has higher BIFF version than "Workbook" stream. */
161cdf0e10cSrcweir                 eBiff = eBookStrm5Biff;
162cdf0e10cSrcweir                 orWorkbookStreamName = saBookName;
163cdf0e10cSrcweir             }
164cdf0e10cSrcweir         }
165cdf0e10cSrcweir         else
166cdf0e10cSrcweir         {
167cdf0e10cSrcweir             // no storage, try plain input stream from medium (even for BIFF5+)
168cdf0e10cSrcweir             BinaryXInputStream aStrm( rxStorage->openInputStream( OUString() ), false );
169cdf0e10cSrcweir             eBiff = detectStreamBiffVersion( aStrm );
170cdf0e10cSrcweir             orWorkbookStreamName = OUString();
171cdf0e10cSrcweir         }
172cdf0e10cSrcweir     }
173cdf0e10cSrcweir 
174cdf0e10cSrcweir     return eBiff;
175cdf0e10cSrcweir }
176cdf0e10cSrcweir 
177cdf0e10cSrcweir // com.sun.star.lang.XServiceInfo interface -----------------------------------
178cdf0e10cSrcweir 
getImplementationName()179cdf0e10cSrcweir OUString SAL_CALL BiffDetector::getImplementationName() throw( RuntimeException )
180cdf0e10cSrcweir {
181cdf0e10cSrcweir     return BiffDetector_getImplementationName();
182cdf0e10cSrcweir }
183cdf0e10cSrcweir 
supportsService(const OUString & rService)184cdf0e10cSrcweir sal_Bool SAL_CALL BiffDetector::supportsService( const OUString& rService ) throw( RuntimeException )
185cdf0e10cSrcweir {
186cdf0e10cSrcweir     const Sequence< OUString > aServices = BiffDetector_getSupportedServiceNames();
187cdf0e10cSrcweir     const OUString* pArray = aServices.getConstArray();
188cdf0e10cSrcweir     const OUString* pArrayEnd = pArray + aServices.getLength();
189cdf0e10cSrcweir     return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
190cdf0e10cSrcweir }
191cdf0e10cSrcweir 
getSupportedServiceNames()192cdf0e10cSrcweir Sequence< OUString > SAL_CALL BiffDetector::getSupportedServiceNames() throw( RuntimeException )
193cdf0e10cSrcweir {
194cdf0e10cSrcweir     return BiffDetector_getSupportedServiceNames();
195cdf0e10cSrcweir }
196cdf0e10cSrcweir 
197cdf0e10cSrcweir // com.sun.star.document.XExtendedFilterDetect interface ----------------------
198cdf0e10cSrcweir 
detect(Sequence<PropertyValue> & rDescriptor)199cdf0e10cSrcweir OUString SAL_CALL BiffDetector::detect( Sequence< PropertyValue >& rDescriptor ) throw( RuntimeException )
200cdf0e10cSrcweir {
201cdf0e10cSrcweir     OUString aTypeName;
202cdf0e10cSrcweir 
203cdf0e10cSrcweir     MediaDescriptor aDescriptor( rDescriptor );
204cdf0e10cSrcweir     aDescriptor.addInputStream();
205cdf0e10cSrcweir 
206cdf0e10cSrcweir     Reference< XInputStream > xInStrm( aDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY_THROW );
207cdf0e10cSrcweir     StorageRef xStorage( new ::oox::ole::OleStorage( mxContext, xInStrm, true ) );
208cdf0e10cSrcweir 
209cdf0e10cSrcweir     OUString aWorkbookName;
210cdf0e10cSrcweir     switch( detectStorageBiffVersion( aWorkbookName, xStorage ) )
211cdf0e10cSrcweir     {
212cdf0e10cSrcweir         case BIFF2:
213cdf0e10cSrcweir         case BIFF3:
214cdf0e10cSrcweir         case BIFF4: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_40" );  break;
215cdf0e10cSrcweir         case BIFF5: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_95" );  break;
216cdf0e10cSrcweir         case BIFF8: aTypeName = CREATE_OUSTRING( "calc_MS_Excel_97" );  break;
217cdf0e10cSrcweir         default:;
218cdf0e10cSrcweir     }
219cdf0e10cSrcweir 
220cdf0e10cSrcweir     return aTypeName;
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir // ============================================================================
224cdf0e10cSrcweir 
225cdf0e10cSrcweir } // namespace xls
226cdf0e10cSrcweir } // namespace oox
227