Avoid potential negative array index access to cached text.
[LibreOffice.git] / writerperfect / source / impress / KeynoteImportFilter.cxx
blobc2fb11012391c5b1d60779befb08a01eef322f52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* KeynoteImportFilter: Sets up the filter, and calls OdpExporter
3 * to do the actual filtering
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 */
10 #include <memory>
11 #include <com/sun/star/beans/NamedValue.hpp>
12 #include <com/sun/star/beans/PropertyValue.hpp>
13 #include <com/sun/star/io/XInputStream.hpp>
14 #include <com/sun/star/uno/Reference.h>
15 #include <com/sun/star/ucb/XContent.hpp>
16 #include <comphelper/processfactory.hxx>
17 #include <cppuhelper/supportsservice.hxx>
19 #include <libetonyek/libetonyek.h>
20 #include <ucbhelper/content.hxx>
21 #include <unotools/ucbhelper.hxx>
23 #include <DirectoryStream.hxx>
24 #include <WPXSvInputStream.hxx>
26 #include "KeynoteImportFilter.hxx"
28 using writerperfect::WPXSvInputStream;
30 namespace beans = com::sun::star::beans;
31 namespace ucb = com::sun::star::ucb;
33 bool KeynoteImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput,
34 OdpGenerator& rGenerator, utl::MediaDescriptor&)
36 return libetonyek::EtonyekDocument::parse(&rInput, &rGenerator);
39 bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName)
41 if (libetonyek::EtonyekDocument::isSupported(&rInput))
43 rTypeName = "impress_Keynote_Document";
44 return true;
47 return false;
50 // XExtendedFilterDetection
51 OUString SAL_CALL
52 KeynoteImportFilter::detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor)
54 sal_Int32 nLength = Descriptor.getLength();
55 sal_Int32 nNewLength = nLength + 2;
56 sal_Int32 nComponentDataLocation = -1;
57 sal_Int32 nTypeNameLocation = -1;
58 sal_Int32 nUCBContentLocation = -1;
59 bool bIsPackage = false;
60 bool bUCBContentChanged = false;
61 const beans::PropertyValue* pValue = Descriptor.getConstArray();
62 css::uno::Reference<com::sun::star::io::XInputStream> xInputStream;
63 css::uno::Reference<ucb::XContent> xContent;
64 css::uno::Sequence<beans::NamedValue> lComponentDataNV;
65 css::uno::Sequence<beans::PropertyValue> lComponentDataPV;
66 bool bComponentDataNV = true;
68 for (sal_Int32 i = 0; i < nLength; i++)
70 if (pValue[i].Name == "TypeName")
72 nTypeNameLocation = i;
73 --nNewLength;
75 if (pValue[i].Name == "ComponentData")
77 bComponentDataNV = pValue[i].Value >>= lComponentDataNV;
78 if (!bComponentDataNV)
79 pValue[i].Value >>= lComponentDataPV;
80 nComponentDataLocation = i;
81 --nNewLength;
83 else if (pValue[i].Name == "InputStream")
85 pValue[i].Value >>= xInputStream;
87 else if (pValue[i].Name == "UCBContent")
89 pValue[i].Value >>= xContent;
90 nUCBContentLocation = i;
94 assert(nNewLength >= nLength);
96 if (!xInputStream.is())
97 return OUString();
99 std::unique_ptr<librevenge::RVNGInputStream> input
100 = std::make_unique<WPXSvInputStream>(xInputStream);
102 /* Apple Keynote documents come in two variants:
103 * * actual files (zip), only produced by Keynote 5 (at least with
104 * default settings)
105 * * packages (IOW, directories), produced by Keynote 1-4 and again
106 * starting with 6.
107 * But since the libetonyek import only works with a stream, we need
108 * to pass it one for the whole package. Here we determine if that
109 * is needed.
111 * Note: for convenience, we also recognize that the main XML file
112 * from a package was passed and pass the whole package to the
113 * filter instead.
115 if (xContent.is())
117 ucbhelper::Content aContent(xContent, utl::UCBContentHelper::getDefaultCommandEnvironment(),
118 comphelper::getProcessComponentContext());
121 if (aContent.isFolder())
123 input = std::make_unique<writerperfect::DirectoryStream>(xContent);
124 bIsPackage = true;
127 catch (...)
129 return OUString();
133 libetonyek::EtonyekDocument::Type type = libetonyek::EtonyekDocument::TYPE_UNKNOWN;
134 const libetonyek::EtonyekDocument::Confidence confidence
135 = libetonyek::EtonyekDocument::isSupported(input.get(), &type);
136 if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE == confidence)
137 || (libetonyek::EtonyekDocument::TYPE_KEYNOTE != type))
138 return OUString();
140 if (confidence == libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART)
142 if (bIsPackage) // we passed a directory stream, but the filter claims it's APXL file?
143 return OUString();
145 std::unique_ptr<writerperfect::DirectoryStream> xDir
146 = writerperfect::DirectoryStream::createForParent(xContent);
147 auto pDir = xDir.get();
148 input = std::move(xDir);
149 if (bool(input))
151 if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT
152 == libetonyek::EtonyekDocument::isSupported(input.get()))
154 xContent = pDir->getContent();
155 bUCBContentChanged = true;
156 bIsPackage = true;
158 else
160 // The passed stream has been detected as APXL file, but its parent dir is not a valid Keynote
161 // package? Something is wrong here...
162 return OUString();
167 // we do not need to insert ComponentData if this is not a package
168 if (!bIsPackage && (nComponentDataLocation == -1))
169 --nNewLength;
171 if (nNewLength > nLength)
172 Descriptor.realloc(nNewLength);
173 auto pDescriptor = Descriptor.getArray();
175 if (nTypeNameLocation == -1)
177 assert(nLength < nNewLength);
178 nTypeNameLocation = nLength++;
179 pDescriptor[nTypeNameLocation].Name = "TypeName";
182 if (bIsPackage && (nComponentDataLocation == -1))
184 assert(nLength < nNewLength);
185 nComponentDataLocation = nLength++;
186 pDescriptor[nComponentDataLocation].Name = "ComponentData";
189 if (bIsPackage)
191 if (bComponentDataNV)
193 const sal_Int32 nCDSize = lComponentDataNV.getLength();
194 lComponentDataNV.realloc(nCDSize + 1);
195 beans::NamedValue aValue;
196 aValue.Name = "IsPackage";
197 aValue.Value <<= true;
198 lComponentDataNV.getArray()[nCDSize] = aValue;
199 pDescriptor[nComponentDataLocation].Value <<= lComponentDataNV;
201 else
203 const sal_Int32 nCDSize = lComponentDataPV.getLength();
204 lComponentDataPV.realloc(nCDSize + 1);
205 beans::PropertyValue aProp;
206 aProp.Name = "IsPackage";
207 aProp.Value <<= true;
208 aProp.Handle = -1;
209 aProp.State = beans::PropertyState_DIRECT_VALUE;
210 lComponentDataPV.getArray()[nCDSize] = aProp;
211 pDescriptor[nComponentDataLocation].Value <<= lComponentDataPV;
215 if (bUCBContentChanged)
216 pDescriptor[nUCBContentLocation].Value <<= xContent;
218 static constexpr OUString sTypeName(u"impress_AppleKeynote"_ustr);
219 pDescriptor[nTypeNameLocation].Value <<= sTypeName;
221 return sTypeName;
224 // XServiceInfo
225 OUString SAL_CALL KeynoteImportFilter::getImplementationName()
227 return "org.libreoffice.comp.Impress.KeynoteImportFilter";
230 sal_Bool SAL_CALL KeynoteImportFilter::supportsService(const OUString& rServiceName)
232 return cppu::supportsService(this, rServiceName);
235 css::uno::Sequence<OUString> SAL_CALL KeynoteImportFilter::getSupportedServiceNames()
237 return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" };
240 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
241 org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation(
242 css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&)
244 return cppu::acquire(new KeynoteImportFilter(context));
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */