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