LibreOffice Module writerperfect (master) 1
KeynoteImportFilter.cxx
Go to the documentation of this file.
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
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 <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>
18
19#include <libetonyek/libetonyek.h>
20#include <ucbhelper/content.hxx>
22
23#include <DirectoryStream.hxx>
24#include <WPXSvInputStream.hxx>
25
27
29
31namespace ucb = com::sun::star::ucb;
32
33bool KeynoteImportFilter::doImportDocument(weld::Window*, librevenge::RVNGInputStream& rInput,
34 OdpGenerator& rGenerator, utl::MediaDescriptor&)
35{
36 return libetonyek::EtonyekDocument::parse(&rInput, &rGenerator);
37}
38
39bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream& rInput, OUString& rTypeName)
40{
41 if (libetonyek::EtonyekDocument::isSupported(&rInput))
42 {
43 rTypeName = "impress_Keynote_Document";
44 return true;
45 }
46
47 return false;
48}
49
50// XExtendedFilterDetection
51OUString SAL_CALL
52KeynoteImportFilter::detect(css::uno::Sequence<css::beans::PropertyValue>& Descriptor)
53{
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;
67
68 for (sal_Int32 i = 0; i < nLength; i++)
69 {
70 if (pValue[i].Name == "TypeName")
71 {
72 nTypeNameLocation = i;
73 --nNewLength;
74 }
75 if (pValue[i].Name == "ComponentData")
76 {
77 bComponentDataNV = pValue[i].Value >>= lComponentDataNV;
78 if (!bComponentDataNV)
79 pValue[i].Value >>= lComponentDataPV;
80 nComponentDataLocation = i;
81 --nNewLength;
82 }
83 else if (pValue[i].Name == "InputStream")
84 {
85 pValue[i].Value >>= xInputStream;
86 }
87 else if (pValue[i].Name == "UCBContent")
88 {
89 pValue[i].Value >>= xContent;
90 nUCBContentLocation = i;
91 }
92 }
93
94 assert(nNewLength >= nLength);
95
96 if (!xInputStream.is())
97 return OUString();
98
99 std::unique_ptr<librevenge::RVNGInputStream> input
100 = std::make_unique<WPXSvInputStream>(xInputStream);
101
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.
110 *
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.
114 */
115 if (xContent.is())
116 {
119 try
120 {
121 if (aContent.isFolder())
122 {
123 input = std::make_unique<writerperfect::DirectoryStream>(xContent);
124 bIsPackage = true;
125 }
126 }
127 catch (...)
128 {
129 return OUString();
130 }
131 }
132
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();
139
140 if (confidence == libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART)
141 {
142 if (bIsPackage) // we passed a directory stream, but the filter claims it's APXL file?
143 return OUString();
144
145 std::unique_ptr<writerperfect::DirectoryStream> xDir
147 auto pDir = xDir.get();
148 input = std::move(xDir);
149 if (bool(input))
150 {
151 if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT
152 == libetonyek::EtonyekDocument::isSupported(input.get()))
153 {
154 xContent = pDir->getContent();
155 bUCBContentChanged = true;
156 bIsPackage = true;
157 }
158 else
159 {
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();
163 }
164 }
165 }
166
167 // we do not need to insert ComponentData if this is not a package
168 if (!bIsPackage && (nComponentDataLocation == -1))
169 --nNewLength;
170
171 if (nNewLength > nLength)
172 Descriptor.realloc(nNewLength);
173 auto pDescriptor = Descriptor.getArray();
174
175 if (nTypeNameLocation == -1)
176 {
177 assert(nLength < nNewLength);
178 nTypeNameLocation = nLength++;
179 pDescriptor[nTypeNameLocation].Name = "TypeName";
180 }
181
182 if (bIsPackage && (nComponentDataLocation == -1))
183 {
184 assert(nLength < nNewLength);
185 nComponentDataLocation = nLength++;
186 pDescriptor[nComponentDataLocation].Name = "ComponentData";
187 }
188
189 if (bIsPackage)
190 {
191 if (bComponentDataNV)
192 {
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;
200 }
201 else
202 {
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;
212 }
213 }
214
215 if (bUCBContentChanged)
216 pDescriptor[nUCBContentLocation].Value <<= xContent;
217
218 static constexpr OUStringLiteral sTypeName(u"impress_AppleKeynote");
219 pDescriptor[nTypeNameLocation].Value <<= OUString(sTypeName);
220
221 return sTypeName;
222}
223
224// XServiceInfo
226{
227 return "org.libreoffice.comp.Impress.KeynoteImportFilter";
228}
229
230sal_Bool SAL_CALL KeynoteImportFilter::supportsService(const OUString& rServiceName)
231{
232 return cppu::supportsService(this, rServiceName);
233}
234
235css::uno::Sequence<OUString> SAL_CALL KeynoteImportFilter::getSupportedServiceNames()
236{
237 return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" };
238}
239
240extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
242 css::uno::XComponentContext* const context, const css::uno::Sequence<css::uno::Any>&)
243{
244 return cppu::acquire(new KeynoteImportFilter(context));
245}
246
247/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation(css::uno::XComponentContext *const context, const css::uno::Sequence< css::uno::Any > &)
virtual bool doDetectFormat(librevenge::RVNGInputStream &rInput, OUString &rTypeName) override
virtual OUString SAL_CALL getImplementationName() override
virtual bool doImportDocument(weld::Window *pParent, librevenge::RVNGInputStream &rInput, OdpGenerator &rGenerator, utl::MediaDescriptor &) override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual OUString SAL_CALL detect(css::uno::Sequence< css::beans::PropertyValue > &Descriptor) override
static std::unique_ptr< DirectoryStream > createForParent(const css::uno::Reference< css::ucb::XContent > &xContent)
float u
Reference< XComponentContext > getProcessComponentContext()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
UNOTOOLS_DLLPUBLIC css::uno::Reference< css::ucb::XCommandEnvironment > getDefaultCommandEnvironment()
OUString Name
unsigned char sal_Bool
ResultType type
sal_Int32 nLength