File: | home/maarten/src/libreoffice/core/sc/source/ui/unoobj/exceldetect.cxx |
Warning: | line 76, column 1 Potential leak of memory pointed to by 'xStorage.pObj' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
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/. | |||
8 | */ | |||
9 | ||||
10 | #include "exceldetect.hxx" | |||
11 | ||||
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> | |||
16 | ||||
17 | #include <sfx2/docfile.hxx> | |||
18 | #include <unotools/mediadescriptor.hxx> | |||
19 | #include <sot/storage.hxx> | |||
20 | #include <tools/diagnose_ex.h> | |||
21 | ||||
22 | using namespace com::sun::star; | |||
23 | using utl::MediaDescriptor; | |||
24 | ||||
25 | ScExcelBiffDetect::ScExcelBiffDetect() {} | |||
26 | ScExcelBiffDetect::~ScExcelBiffDetect() {} | |||
27 | ||||
28 | OUString ScExcelBiffDetect::getImplementationName() | |||
29 | { | |||
30 | return "com.sun.star.comp.calc.ExcelBiffFormatDetector"; | |||
31 | } | |||
32 | ||||
33 | sal_Bool ScExcelBiffDetect::supportsService( const OUString& aName ) | |||
34 | { | |||
35 | return cppu::supportsService(this, aName); | |||
36 | } | |||
37 | ||||
38 | uno::Sequence<OUString> ScExcelBiffDetect::getSupportedServiceNames() | |||
39 | { | |||
40 | return { "com.sun.star.frame.ExtendedTypeDetection" }; | |||
41 | } | |||
42 | ||||
43 | namespace { | |||
44 | ||||
45 | bool hasStream(const uno::Reference<io::XInputStream>& xInStream, const OUString& rName) | |||
46 | { | |||
47 | SfxMedium aMedium; | |||
48 | aMedium.UseInteractionHandler(false); | |||
49 | aMedium.setStreamToLoadFrom(xInStream, true); | |||
50 | SvStream* pStream = aMedium.GetInStream(); | |||
51 | if (!pStream) | |||
52 | return false; | |||
53 | ||||
54 | sal_uInt64 const nSize = pStream->TellEnd(); | |||
55 | pStream->Seek(0); | |||
56 | ||||
57 | if (!nSize) | |||
58 | { | |||
59 | // 0-size stream. Failed. | |||
60 | return false; | |||
61 | } | |||
62 | ||||
63 | try | |||
64 | { | |||
65 | tools::SvRef<SotStorage> xStorage = new SotStorage(pStream, false); | |||
66 | if (!xStorage.is() || xStorage->GetError()) | |||
67 | return false; | |||
68 | return xStorage->IsStream(rName); | |||
69 | } | |||
70 | catch (const css::ucb::ContentCreationException &) | |||
71 | { | |||
72 | TOOLS_WARN_EXCEPTION("sc", "hasStream")do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "hasStream" << " " << exceptionToString (tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/unoobj/exceldetect.cxx" ":" "72" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "hasStream" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "hasStream" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/unoobj/exceldetect.cxx" ":" "72" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "hasStream" << " " << exceptionToString (tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/unoobj/exceldetect.cxx" ":" "72" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "hasStream" << " " << exceptionToString (tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "hasStream" << " " << exceptionToString(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/unoobj/exceldetect.cxx" ":" "72" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
73 | } | |||
74 | ||||
75 | return false; | |||
76 | } | |||
| ||||
77 | ||||
78 | /** | |||
79 | * We detect BIFF 2, 3 and 4 file types together since the only thing that | |||
80 | * set them apart is the BOF ID. | |||
81 | */ | |||
82 | bool isExcel40(const uno::Reference<io::XInputStream>& xInStream) | |||
83 | { | |||
84 | SfxMedium aMedium; | |||
85 | aMedium.UseInteractionHandler(false); | |||
86 | aMedium.setStreamToLoadFrom(xInStream, true); | |||
87 | SvStream* pStream = aMedium.GetInStream(); | |||
88 | if (!pStream) | |||
89 | return false; | |||
90 | ||||
91 | sal_uInt64 const nSize = pStream->TellEnd(); | |||
92 | pStream->Seek(0); | |||
93 | ||||
94 | if (nSize < 4) | |||
95 | return false; | |||
96 | ||||
97 | sal_uInt16 nBofId, nBofSize; | |||
98 | pStream->ReadUInt16( nBofId ).ReadUInt16( nBofSize ); | |||
99 | ||||
100 | switch (nBofId) | |||
101 | { | |||
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) | |||
106 | break; | |||
107 | default: | |||
108 | return false; | |||
109 | } | |||
110 | ||||
111 | if (nBofSize < 4 || 16 < nBofSize) | |||
112 | // BOF record must be sized between 4 and 16 for BIFF 2, 3 and 4. | |||
113 | return false; | |||
114 | ||||
115 | sal_uInt64 const nPos = pStream->Tell(); | |||
116 | if (nSize - nPos < nBofSize) | |||
117 | // BOF record doesn't have required bytes. | |||
118 | return false; | |||
119 | ||||
120 | return true; | |||
121 | } | |||
122 | ||||
123 | bool isTemplate(const OUString& rType) | |||
124 | { | |||
125 | return rType.indexOf("_VorlageTemplate") != -1; | |||
126 | } | |||
127 | ||||
128 | } | |||
129 | ||||
130 | OUString ScExcelBiffDetect::detect( uno::Sequence<beans::PropertyValue>& lDescriptor ) | |||
131 | { | |||
132 | MediaDescriptor aMediaDesc(lDescriptor); | |||
133 | OUString aType; | |||
134 | aMediaDesc[MediaDescriptor::PROP_TYPENAME()] >>= aType; | |||
135 | if (aType.isEmpty()) | |||
| ||||
136 | // Type is not given. We can't proceed. | |||
137 | return OUString(); | |||
138 | ||||
139 | aMediaDesc.addInputStream(); | |||
140 | uno::Reference<io::XInputStream> xInStream(aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM()], uno::UNO_QUERY); | |||
141 | if (!xInStream.is()) | |||
142 | // No input stream. | |||
143 | return OUString(); | |||
144 | ||||
145 | if (aType == "calc_MS_Excel_97" || aType == "calc_MS_Excel_97_VorlageTemplate") | |||
146 | { | |||
147 | // See if this stream is an Excel 97/XP/2003 (BIFF8) stream. | |||
148 | if (!hasStream(xInStream, "Workbook")) | |||
149 | // BIFF8 is expected to contain a stream named "Workbook". | |||
150 | return OUString(); | |||
151 | ||||
152 | aMediaDesc[MediaDescriptor::PROP_FILTERNAME()] <<= isTemplate(aType) ? OUString("MS Excel 97 Vorlage/Template") : OUString("MS Excel 97"); | |||
153 | } | |||
154 | ||||
155 | else if (aType == "calc_MS_Excel_95" || aType == "calc_MS_Excel_95_VorlageTemplate") | |||
156 | { | |||
157 | // See if this stream is an Excel 95 (BIFF5) stream. | |||
158 | if (!hasStream(xInStream, "Book")) | |||
159 | return OUString(); | |||
160 | ||||
161 | aMediaDesc[MediaDescriptor::PROP_FILTERNAME()] <<= isTemplate(aType) ? OUString("MS Excel 95 Vorlage/Template") : OUString("MS Excel 95"); | |||
162 | } | |||
163 | ||||
164 | else if (aType == "calc_MS_Excel_5095" || aType == "calc_MS_Excel_5095_VorlageTemplate") | |||
165 | { | |||
166 | // See if this stream is an Excel 5.0/95 stream. | |||
167 | if (!hasStream(xInStream, "Book")) | |||
168 | return OUString(); | |||
169 | ||||
170 | aMediaDesc[MediaDescriptor::PROP_FILTERNAME()] <<= isTemplate(aType) ? OUString("MS Excel 5.0/95 Vorlage/Template") : OUString("MS Excel 5.0/95"); | |||
171 | } | |||
172 | ||||
173 | else if (aType == "calc_MS_Excel_40" || aType == "calc_MS_Excel_40_VorlageTemplate") | |||
174 | { | |||
175 | // See if this stream is an Excel 4.0 stream. | |||
176 | if (!isExcel40(xInStream)) | |||
177 | return OUString(); | |||
178 | ||||
179 | aMediaDesc[MediaDescriptor::PROP_FILTERNAME()] <<= isTemplate(aType) ? OUString("MS Excel 4.0 Vorlage/Template") : OUString("MS Excel 4.0"); | |||
180 | } | |||
181 | ||||
182 | else | |||
183 | // Nothing to detect. | |||
184 | return OUString(); | |||
185 | ||||
186 | aMediaDesc >> lDescriptor; | |||
187 | return aType; | |||
188 | } | |||
189 | ||||
190 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) css::uno::XInterface* | |||
191 | com_sun_star_comp_calc_ExcelBiffFormatDetector_get_implementation(css::uno::XComponentContext* /*context*/, | |||
192 | css::uno::Sequence<css::uno::Any> const &) | |||
193 | { | |||
194 | return cppu::acquire(new ScExcelBiffDetect); | |||
195 | } | |||
196 | ||||
197 | ||||
198 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |