1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "exceldetect.hxx"
12 #include <com/sun/star/io/XInputStream.hpp>
13 #include <com/sun/star/ucb/ContentCreationException.hpp>
14 #include <com/sun/star/uno/XComponentContext.hpp>
15 #include <cppuhelper/supportsservice.hxx>
17 #include <sfx2/docfile.hxx>
18 #include <unotools/mediadescriptor.hxx>
19 #include <sot/storage.hxx>
20 #include <comphelper/diagnose_ex.hxx>
22 using namespace com::sun::star
;
23 using utl::MediaDescriptor
;
25 ScExcelBiffDetect::ScExcelBiffDetect() {}
26 ScExcelBiffDetect::~ScExcelBiffDetect() {}
28 OUString
ScExcelBiffDetect::getImplementationName()
30 return u
"com.sun.star.comp.calc.ExcelBiffFormatDetector"_ustr
;
33 sal_Bool
ScExcelBiffDetect::supportsService( const OUString
& aName
)
35 return cppu::supportsService(this, aName
);
38 uno::Sequence
<OUString
> ScExcelBiffDetect::getSupportedServiceNames()
40 return { u
"com.sun.star.frame.ExtendedTypeDetection"_ustr
};
45 bool hasStream(const uno::Reference
<io::XInputStream
>& xInStream
, const OUString
& rName
)
48 aMedium
.UseInteractionHandler(false);
49 aMedium
.setStreamToLoadFrom(xInStream
, true);
50 SvStream
* pStream
= aMedium
.GetInStream();
54 sal_uInt64
const nSize
= pStream
->TellEnd();
59 // 0-size stream. Failed.
65 rtl::Reference
<SotStorage
> xStorage
= new SotStorage(pStream
, false);
66 if (!xStorage
.is() || xStorage
->GetError())
68 return xStorage
->IsStream(rName
);
70 catch (const css::ucb::ContentCreationException
&)
72 TOOLS_WARN_EXCEPTION("sc", "hasStream");
79 * We detect BIFF 2, 3 and 4 file types together since the only thing that
80 * set them apart is the BOF ID.
82 bool isExcel40(const uno::Reference
<io::XInputStream
>& xInStream
)
85 aMedium
.UseInteractionHandler(false);
86 aMedium
.setStreamToLoadFrom(xInStream
, true);
87 SvStream
* pStream
= aMedium
.GetInStream();
91 sal_uInt64
const nSize
= pStream
->TellEnd();
97 sal_uInt16 nBofId
, nBofSize
;
98 pStream
->ReadUInt16( nBofId
).ReadUInt16( nBofSize
);
102 case 0x0009: // Excel 2.1 worksheet (BIFF 2)
103 case 0x0209: // Excel 3.0 worksheet (BIFF 3)
104 case 0x0409: // Excel 4.0 worksheet (BIFF 4)
105 case 0x0809: // Excel 5.0 worksheet (BIFF 5), some apps create such files (fdo#70100)
111 if (nBofSize
< 4 || 16 < nBofSize
)
112 // BOF record must be sized between 4 and 16 for BIFF 2, 3 and 4.
115 sal_uInt64
const nPos
= pStream
->Tell();
116 if (nSize
- nPos
< nBofSize
)
117 // BOF record doesn't have required bytes.
123 bool isTemplate(std::u16string_view rType
)
125 return rType
.find(u
"_VorlageTemplate") != std::u16string_view::npos
;
130 OUString
ScExcelBiffDetect::detect( uno::Sequence
<beans::PropertyValue
>& lDescriptor
)
132 MediaDescriptor
aMediaDesc(lDescriptor
);
134 aMediaDesc
[MediaDescriptor::PROP_TYPENAME
] >>= aType
;
136 // Type is not given. We can't proceed.
139 aMediaDesc
.addInputStream();
140 uno::Reference
<io::XInputStream
> xInStream(aMediaDesc
[MediaDescriptor::PROP_INPUTSTREAM
], uno::UNO_QUERY
);
145 if (aType
== "calc_MS_Excel_97" || aType
== "calc_MS_Excel_97_VorlageTemplate")
147 // See if this stream is an Excel 97/XP/2003 (BIFF8) stream.
148 if (!hasStream(xInStream
, u
"Workbook"_ustr
))
149 // BIFF8 is expected to contain a stream named "Workbook".
152 aMediaDesc
[MediaDescriptor::PROP_FILTERNAME
] <<= isTemplate(aType
) ? u
"MS Excel 97 Vorlage/Template"_ustr
: u
"MS Excel 97"_ustr
;
155 else if (aType
== "calc_MS_Excel_95" || aType
== "calc_MS_Excel_95_VorlageTemplate")
157 // See if this stream is an Excel 95 (BIFF5) stream.
158 if (!hasStream(xInStream
, u
"Book"_ustr
))
161 aMediaDesc
[MediaDescriptor::PROP_FILTERNAME
] <<= isTemplate(aType
) ? u
"MS Excel 95 Vorlage/Template"_ustr
: u
"MS Excel 95"_ustr
;
164 else if (aType
== "calc_MS_Excel_5095" || aType
== "calc_MS_Excel_5095_VorlageTemplate")
166 // See if this stream is an Excel 5.0/95 stream.
167 if (!hasStream(xInStream
, u
"Book"_ustr
))
170 aMediaDesc
[MediaDescriptor::PROP_FILTERNAME
] <<= isTemplate(aType
) ? u
"MS Excel 5.0/95 Vorlage/Template"_ustr
: u
"MS Excel 5.0/95"_ustr
;
173 else if (aType
== "calc_MS_Excel_40" || aType
== "calc_MS_Excel_40_VorlageTemplate")
175 // See if this stream is an Excel 4.0 stream.
176 if (!isExcel40(xInStream
))
179 aMediaDesc
[MediaDescriptor::PROP_FILTERNAME
] <<= isTemplate(aType
) ? u
"MS Excel 4.0 Vorlage/Template"_ustr
: u
"MS Excel 4.0"_ustr
;
183 // Nothing to detect.
186 aMediaDesc
>> lDescriptor
;
190 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
191 com_sun_star_comp_calc_ExcelBiffFormatDetector_get_implementation(css::uno::XComponentContext
* /*context*/,
192 css::uno::Sequence
<css::uno::Any
> const &)
194 return cppu::acquire(new ScExcelBiffDetect
);
198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */