LibreOffice Module filter (master) 1
xmlfilterjar.cxx
Go to the documentation of this file.
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 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <com/sun/star/io/XActiveDataControl.hpp>
21#include <com/sun/star/io/XInputStream.hpp>
22#include <com/sun/star/io/XActiveDataSink.hpp>
23#include <com/sun/star/beans/NamedValue.hpp>
24#include <com/sun/star/container/XNameContainer.hpp>
25#include <com/sun/star/container/XNamed.hpp>
26#include <com/sun/star/container/XChild.hpp>
27#include <com/sun/star/lang/IllegalArgumentException.hpp>
28#include <com/sun/star/lang/XUnoTunnel.hpp>
29#include <com/sun/star/util/XChangesBatch.hpp>
30#include <com/sun/star/uno/XComponentContext.hpp>
31
32
35#include <osl/file.hxx>
38#include <unotools/tempfile.hxx>
39#include <svl/urihelper.hxx>
41#include <tools/stream.hxx>
42#include <tools/urlobj.hxx>
43
44#include <rtl/uri.hxx>
45
46#include "xmlfiltercommon.hxx"
47#include "xmlfilterjar.hxx"
50
51using namespace osl;
52using namespace comphelper;
53using namespace com::sun::star;
54using namespace com::sun::star::lang;
55using namespace com::sun::star::uno;
56using namespace com::sun::star::util;
57using namespace com::sun::star::container;
58using namespace com::sun::star::beans;
59using namespace com::sun::star::io;
60
61using ::rtl::Uri;
62
63constexpr OUStringLiteral sVndSunStarPackage(u"vnd.sun.star.Package:");
64
66: mxContext( rxContext ),
67 sXSLTPath( "$(user)/xslt/" ),
68 sTemplatePath( "$(user)/template/" ),
69 sProgPath( "$(prog)/" )
70{
71 SvtPathOptions aOptions;
75}
76
77static OUString encodeZipUri( const OUString& rURI )
78{
79 return Uri::encode( rURI, rtl_UriCharClassUric, rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8 );
80}
81
83static Reference< XInterface > addFolder( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, const OUString& rName )
84{
85 if ( rName == ".." || rName == "." )
86 throw lang::IllegalArgumentException();
87
88 Sequence< Any > aArgs{ Any(true) };
89
90 Reference< XInterface > xFolder( xFactory->createInstanceWithArguments(aArgs) );
91 Reference< XNamed > xNamed( xFolder, UNO_QUERY );
92 Reference< XChild > xChild( xFolder, UNO_QUERY );
93
94 if( xNamed.is() && xChild.is() )
95 {
96 OUString aName( encodeZipUri( rName ) );
97 xNamed->setName( aName );
98 xChild->setParent( xRootFolder );
99 }
100
101 return xFolder;
102}
103
105static void addFile_( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, Reference< XInputStream > const & xInput, const OUString& aName )
106{
107 Reference< XActiveDataSink > xSink( xFactory->createInstance(), UNO_QUERY );
108 Reference< XUnoTunnel > xTunnel( xSink, UNO_QUERY );
109 if( xSink.is() && xTunnel.is())
110 {
111 Reference< XNameContainer > xNameContainer(xRootFolder, UNO_QUERY );
112 xNameContainer->insertByName(encodeZipUri( aName ), Any(xTunnel));
113 xSink->setInputStream( xInput );
114 }
115}
116
117void XMLFilterJarHelper::addFile( Reference< XInterface > const & xRootFolder, Reference< XSingleServiceFactory > const & xFactory, const OUString& rSourceFile )
118{
119 if( rSourceFile.isEmpty() ||
120 rSourceFile.startsWith("http:") ||
121 rSourceFile.startsWith("https:") ||
122 rSourceFile.startsWith("jar:") ||
123 rSourceFile.startsWith("ftp:") )
124 return;
125
126 OUString aFileURL( rSourceFile );
127
128 if( !aFileURL.matchIgnoreAsciiCase("file://") )
129 {
131 }
132
133 INetURLObject aURL( aFileURL );
134 OUString aName( aURL.getName() );
135
136 SvFileStream* pStream = new SvFileStream(aFileURL, StreamMode::READ );
137 Reference< XInputStream > xInput( new utl::OSeekableInputStreamWrapper( pStream, true ) );
138 addFile_( xRootFolder, xFactory, xInput, aName );
139}
140
141bool XMLFilterJarHelper::savePackage( const OUString& rPackageURL, const std::vector<filter_info_impl*>& rFilters )
142{
143 try
144 {
145 osl::File::remove( rPackageURL );
146
147 // create the package jar file
148
149 Sequence< Any > aArguments{ Any(rPackageURL),
150 // let ZipPackage be used ( no manifest.xml is required )
151 Any(beans::NamedValue(
152 "StorageFormat", Any(OUString(ZIP_STORAGE_FORMAT_STRING)))) };
153
155 mxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
156 "com.sun.star.packages.comp.ZipPackage",
157 aArguments, mxContext ), UNO_QUERY );
158
159 if( xIfc.is() )
160 {
162
163 // get root zip folder
164 Reference< XInterface > xRootFolder;
165 xIfc->getByHierarchicalName( "/" ) >>= xRootFolder;
166
167 // export filters files
168 for (auto const& filter : rFilters)
169 {
170 Reference< XInterface > xFilterRoot( addFolder( xRootFolder, xFactory, filter->maFilterName ) );
171
172 if( xFilterRoot.is() )
173 {
174 if( !filter->maExportXSLT.isEmpty() )
175 addFile( xFilterRoot, xFactory, filter->maExportXSLT );
176 try
177 {
178 if( !filter->maImportXSLT.isEmpty() )
179 addFile( xFilterRoot, xFactory, filter->maImportXSLT );
180 }
181 catch(const css::container::ElementExistException&)
182 {
183 // in case of same named import / export XSLT the latter
184 // is ignored
185 TOOLS_WARN_EXCEPTION("filter.xslt", "same named xslt filter exception!");
186 }
187
188 if( !filter->maImportTemplate.isEmpty() )
189 addFile( xFilterRoot, xFactory, filter->maImportTemplate );
190 }
191 }
192
193 // create TypeDetection.xcu
194 utl::TempFileFast aTempFile;
195 SvStream* pStream = aTempFile.GetStream(StreamMode::READWRITE);
196
197 {
198 Reference< XOutputStream > xOS( new ::utl::OOutputStreamWrapper( *pStream ) );
199
200 TypeDetectionExporter aExporter( mxContext );
201 aExporter.doExport(xOS,rFilters);
202 }
203
204 pStream->Seek(0);
206 addFile_( xRootFolder, xFactory, XIS, "TypeDetection.xcu" );
207
208 Reference< XChangesBatch > xBatch( xIfc, UNO_QUERY );
209 if( xBatch.is() )
210 xBatch->commitChanges();
211
212 return true;
213 }
214 }
215 catch( const Exception& )
216 {
217 TOOLS_WARN_EXCEPTION("filter.xslt", "");
218 }
219
220 osl::File::remove( rPackageURL );
221
222 return false;
223}
224
225
226void XMLFilterJarHelper::openPackage( const OUString& rPackageURL,
227 std::vector< std::unique_ptr<filter_info_impl> >& rFilters )
228{
229 try
230 {
231 // create the package jar file
232
233 // let ZipPackage be used ( no manifest.xml is required )
234 beans::NamedValue aArg;
235 aArg.Name = "StorageFormat";
236 aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING);
237 Sequence< Any > aArguments{ Any(rPackageURL), Any(aArg) };
238
240 mxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
241 "com.sun.star.packages.comp.ZipPackage",
242 aArguments, mxContext ), UNO_QUERY );
243
244 if( xIfc.is() )
245 {
246 // get root zip folder
247 Reference< XInterface > xRootFolder;
248 xIfc->getByHierarchicalName( "/" ) >>= xRootFolder;
249
250 OUString szTypeDetection("TypeDetection.xcu");
251 if( xIfc->hasByHierarchicalName( szTypeDetection ) )
252 {
253 Reference< XActiveDataSink > xTypeDetection;
254 xIfc->getByHierarchicalName( szTypeDetection ) >>= xTypeDetection;
255
256 if( xTypeDetection.is() )
257 {
258 Reference< XInputStream > xIS( xTypeDetection->getInputStream() );
259
260 std::vector< std::unique_ptr<filter_info_impl> > aFilters;
262
263 // copy all files used by the filters imported from the
264 // typedetection to office/user/xslt
265 for (auto& filter : aFilters)
266 {
267 if( copyFiles( xIfc, filter.get() ) )
268 {
269 rFilters.push_back(std::move(filter));
270 }
271 else
272 {
273 // failed to copy all files
274 filter.reset();
275 }
276 }
277 }
278 }
279 }
280 }
281 catch( const Exception& )
282 {
283 TOOLS_WARN_EXCEPTION("filter.xslt", "");
284 }
285}
286
288{
289 bool bOk = copyFile( xIfc, pFilter->maExportXSLT, sXSLTPath );
290
291 if( bOk )
292 bOk = copyFile( xIfc, pFilter->maImportXSLT, sXSLTPath );
293
294 if( bOk )
295 bOk = copyFile( xIfc, pFilter->maImportTemplate, sTemplatePath );
296
297 return bOk;
298}
299
300bool XMLFilterJarHelper::copyFile( const Reference< XHierarchicalNameAccess >& xIfc, OUString& rURL, std::u16string_view rTargetURL )
301{
302 if( !rURL.matchIgnoreAsciiCase( sVndSunStarPackage ) )
303 return true;
304
305 try
306 {
307 OUString szPackagePath( encodeZipUri( rURL.copy( sVndSunStarPackage.getLength() ) ) );
308
309 if ( ::comphelper::OStorageHelper::PathHasSegment( szPackagePath, u".." )
310 || ::comphelper::OStorageHelper::PathHasSegment( szPackagePath, u"." ) )
311 throw lang::IllegalArgumentException();
312
313 if( xIfc->hasByHierarchicalName( szPackagePath ) )
314 {
316 xIfc->getByHierarchicalName( szPackagePath ) >>= xFileEntry;
317
318 if( xFileEntry.is() )
319 {
320 Reference< XInputStream > xIS( xFileEntry->getInputStream() );
321
322 INetURLObject aBaseURL( rTargetURL );
323
324 rURL = URIHelper::SmartRel2Abs( aBaseURL, szPackagePath, Link<OUString *, bool>(), false );
325
326 if( !rURL.isEmpty() )
327 {
328 // create output directory if needed
329 if( !createDirectory( rURL ) )
330 return false;
331
332 ::osl::File file(rURL);
333 ::osl::FileBase::RC rc =
334 file.open(osl_File_OpenFlag_Write|osl_File_OpenFlag_Create);
335 if (::osl::FileBase::E_EXIST == rc) {
336 rc = file.open(osl_File_OpenFlag_Write);
337 if (::osl::FileBase::E_None == rc) {
338 file.setSize(0); // #i97170# truncate
339 }
340 }
341 if (::osl::FileBase::E_None != rc) {
342 throw RuntimeException();
343 }
346
347 return copyStreams( xIS, xOS );
348 }
349 }
350 }
351 }
352 catch( const Exception& )
353 {
354 TOOLS_WARN_EXCEPTION("filter.xslt", "");
355 }
356 return false;
357}
358
359/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt64 Seek(sal_uInt64 nPos)
OUString SubstituteVariable(const OUString &rVar) const
void doExport(const css::uno::Reference< css::io::XOutputStream > &xOS, const std::vector< filter_info_impl * > &rFilters)
static void doImport(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::io::XInputStream > &xOS, std::vector< std::unique_ptr< filter_info_impl > > &rFilters)
XMLFilterJarHelper(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
css::uno::Reference< css::uno::XComponentContext > mxContext
void openPackage(const OUString &rPackageURL, std::vector< std::unique_ptr< filter_info_impl > > &rFilters)
void addFile(css::uno::Reference< css::uno::XInterface > const &xRootFolder, css::uno::Reference< css::lang::XSingleServiceFactory > const &xFactory, const OUString &rSourceFile)
bool savePackage(const OUString &rPackageURL, const std::vector< filter_info_impl * > &rFilters)
bool copyFiles(const css::uno::Reference< css::container::XHierarchicalNameAccess > &xIfc, filter_info_impl *pFilter)
static bool copyFile(const css::uno::Reference< css::container::XHierarchicalNameAccess > &xIfc, OUString &rURL, std::u16string_view rTargetURL)
static bool PathHasSegment(std::u16string_view aPath, std::u16string_view aSegment)
SvStream * GetStream(StreamMode eMode)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
uno::Reference< uno::XComponentContext > mxContext
float u
Reference< XSingleServiceFactory > xFactory
Sequence< PropertyValue > aArguments
OUString aName
tools::SvRef< SvBaseLink > xSink
SVL_DLLPUBLIC OUString SmartRel2Abs(INetURLObject const &rTheBaseURIRef, OUString const &rTheRelURIRef, Link< OUString *, bool > const &rMaybeFileHdl=Link< OUString *, bool >(), bool bCheckFileExists=true, bool bIgnoreFragment=false, INetURLObject::EncodeMechanism eEncodeMechanism=INetURLObject::EncodeMechanism::WasEncoded, INetURLObject::DecodeMechanism eDecodeMechanism=INetURLObject::DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)
@ Exception
Shape IDs per cluster in DGG atom.
constexpr OUStringLiteral ZIP_STORAGE_FORMAT_STRING
bool createDirectory(std::u16string_view rURL)
bool copyStreams(const css::uno::Reference< css::io::XInputStream > &xIS, const css::uno::Reference< css::io::XOutputStream > &xOS)
static Reference< XInterface > addFolder(Reference< XInterface > const &xRootFolder, Reference< XSingleServiceFactory > const &xFactory, const OUString &rName)
static void addFile_(Reference< XInterface > const &xRootFolder, Reference< XSingleServiceFactory > const &xFactory, Reference< XInputStream > const &xInput, const OUString &aName)
constexpr OUStringLiteral sVndSunStarPackage(u"vnd.sun.star.Package:")
static OUString encodeZipUri(const OUString &rURI)