xref: /aoo41x/main/oox/source/xls/biffdetector.cxx (revision cdf0e10c)
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