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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
33 #include <comphelper/oslfile2streamwrap.hxx>
34 #include <comphelper/storagehelper.hxx>
35 #include <osl/file.hxx>
36 #include <unotools/pathoptions.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <unotools/tempfile.hxx>
39 #include <svl/urihelper.hxx>
40 #include <comphelper/diagnose_ex.hxx>
41 #include <tools/stream.hxx>
42 #include <tools/urlobj.hxx>
44 #include <rtl/uri.hxx>
46 #include "xmlfiltercommon.hxx"
47 #include "xmlfilterjar.hxx"
48 #include "typedetectionexport.hxx"
49 #include "typedetectionimport.hxx"
52 using namespace comphelper
;
53 using namespace com::sun::star
;
54 using namespace com::sun::star::lang
;
55 using namespace com::sun::star::uno
;
56 using namespace com::sun::star::util
;
57 using namespace com::sun::star::container
;
58 using namespace com::sun::star::beans
;
59 using namespace com::sun::star::io
;
63 constexpr OUStringLiteral
sVndSunStarPackage(u
"vnd.sun.star.Package:");
65 XMLFilterJarHelper::XMLFilterJarHelper( const Reference
< XComponentContext
>& rxContext
)
66 : mxContext( rxContext
),
67 sXSLTPath( "$(user)/xslt/" ),
68 sTemplatePath( "$(user)/template/" ),
69 sProgPath( "$(prog)/" )
71 SvtPathOptions aOptions
;
72 sProgPath
= aOptions
.SubstituteVariable( sProgPath
);
73 sXSLTPath
= aOptions
.SubstituteVariable( sXSLTPath
);
74 sTemplatePath
= aOptions
.SubstituteVariable( sTemplatePath
);
77 static OUString
encodeZipUri( const OUString
& rURI
)
79 return Uri::encode( rURI
, rtl_UriCharClassUric
, rtl_UriEncodeCheckEscapes
, RTL_TEXTENCODING_UTF8
);
83 static Reference
< XInterface
> addFolder( Reference
< XInterface
> const & xRootFolder
, Reference
< XSingleServiceFactory
> const & xFactory
, const OUString
& rName
)
85 if ( rName
== ".." || rName
== "." )
86 throw lang::IllegalArgumentException();
88 Sequence
< Any
> aArgs
{ Any(true) };
90 Reference
< XInterface
> xFolder( xFactory
->createInstanceWithArguments(aArgs
) );
91 Reference
< XNamed
> xNamed( xFolder
, UNO_QUERY
);
92 Reference
< XChild
> xChild( xFolder
, UNO_QUERY
);
94 if( xNamed
.is() && xChild
.is() )
96 OUString
aName( encodeZipUri( rName
) );
97 xNamed
->setName( aName
);
98 xChild
->setParent( xRootFolder
);
104 /// @throws Exception
105 static void addFile_( Reference
< XInterface
> const & xRootFolder
, Reference
< XSingleServiceFactory
> const & xFactory
, Reference
< XInputStream
> const & xInput
, const OUString
& aName
)
107 Reference
< XActiveDataSink
> xSink( xFactory
->createInstance(), UNO_QUERY
);
108 Reference
< XUnoTunnel
> xTunnel( xSink
, UNO_QUERY
);
109 if( xSink
.is() && xTunnel
.is())
111 Reference
< XNameContainer
> xNameContainer(xRootFolder
, UNO_QUERY
);
112 xNameContainer
->insertByName(encodeZipUri( aName
), Any(xTunnel
));
113 xSink
->setInputStream( xInput
);
117 void XMLFilterJarHelper::addFile( Reference
< XInterface
> const & xRootFolder
, Reference
< XSingleServiceFactory
> const & xFactory
, const OUString
& rSourceFile
)
119 if( rSourceFile
.isEmpty() ||
120 rSourceFile
.startsWith("http:") ||
121 rSourceFile
.startsWith("https:") ||
122 rSourceFile
.startsWith("jar:") ||
123 rSourceFile
.startsWith("ftp:") )
126 OUString
aFileURL( rSourceFile
);
128 if( !aFileURL
.matchIgnoreAsciiCase("file://") )
130 aFileURL
= URIHelper::SmartRel2Abs( INetURLObject(sProgPath
), aFileURL
, Link
<OUString
*, bool>(), false );
133 INetURLObject
aURL( aFileURL
);
134 OUString
aName( aURL
.getName() );
136 SvFileStream
* pStream
= new SvFileStream(aFileURL
, StreamMode::READ
);
137 Reference
< XInputStream
> xInput( new utl::OSeekableInputStreamWrapper( pStream
, true ) );
138 addFile_( xRootFolder
, xFactory
, xInput
, aName
);
141 bool XMLFilterJarHelper::savePackage( const OUString
& rPackageURL
, const std::vector
<filter_info_impl
*>& rFilters
)
145 osl::File::remove( rPackageURL
);
147 // create the package jar file
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
)))) };
154 Reference
< XHierarchicalNameAccess
> xIfc(
155 mxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
156 "com.sun.star.packages.comp.ZipPackage",
157 aArguments
, mxContext
), UNO_QUERY
);
161 Reference
< XSingleServiceFactory
> xFactory( xIfc
, UNO_QUERY
);
163 // get root zip folder
164 Reference
< XInterface
> xRootFolder
;
165 xIfc
->getByHierarchicalName( "/" ) >>= xRootFolder
;
167 // export filters files
168 for (auto const& filter
: rFilters
)
170 Reference
< XInterface
> xFilterRoot( addFolder( xRootFolder
, xFactory
, filter
->maFilterName
) );
172 if( xFilterRoot
.is() )
174 if( !filter
->maExportXSLT
.isEmpty() )
175 addFile( xFilterRoot
, xFactory
, filter
->maExportXSLT
);
178 if( !filter
->maImportXSLT
.isEmpty() )
179 addFile( xFilterRoot
, xFactory
, filter
->maImportXSLT
);
181 catch(const css::container::ElementExistException
&)
183 // in case of same named import / export XSLT the latter
185 TOOLS_WARN_EXCEPTION("filter.xslt", "same named xslt filter exception!");
188 if( !filter
->maImportTemplate
.isEmpty() )
189 addFile( xFilterRoot
, xFactory
, filter
->maImportTemplate
);
193 // create TypeDetection.xcu
194 utl::TempFileFast aTempFile
;
195 SvStream
* pStream
= aTempFile
.GetStream(StreamMode::READWRITE
);
198 Reference
< XOutputStream
> xOS( new ::utl::OOutputStreamWrapper( *pStream
) );
200 TypeDetectionExporter
aExporter( mxContext
);
201 aExporter
.doExport(xOS
,rFilters
);
205 Reference
< XInputStream
> XIS( new utl::OSeekableInputStreamWrapper( *pStream
) );
206 addFile_( xRootFolder
, xFactory
, XIS
, "TypeDetection.xcu" );
208 Reference
< XChangesBatch
> xBatch( xIfc
, UNO_QUERY
);
210 xBatch
->commitChanges();
215 catch( const Exception
& )
217 TOOLS_WARN_EXCEPTION("filter.xslt", "");
220 osl::File::remove( rPackageURL
);
226 void XMLFilterJarHelper::openPackage( const OUString
& rPackageURL
,
227 std::vector
< std::unique_ptr
<filter_info_impl
> >& rFilters
)
231 // create the package jar file
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
) };
239 Reference
< XHierarchicalNameAccess
> xIfc(
240 mxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
241 "com.sun.star.packages.comp.ZipPackage",
242 aArguments
, mxContext
), UNO_QUERY
);
246 // get root zip folder
247 Reference
< XInterface
> xRootFolder
;
248 xIfc
->getByHierarchicalName( "/" ) >>= xRootFolder
;
250 OUString
szTypeDetection("TypeDetection.xcu");
251 if( xIfc
->hasByHierarchicalName( szTypeDetection
) )
253 Reference
< XActiveDataSink
> xTypeDetection
;
254 xIfc
->getByHierarchicalName( szTypeDetection
) >>= xTypeDetection
;
256 if( xTypeDetection
.is() )
258 Reference
< XInputStream
> xIS( xTypeDetection
->getInputStream() );
260 std::vector
< std::unique_ptr
<filter_info_impl
> > aFilters
;
261 TypeDetectionImporter::doImport( mxContext
, xIS
, aFilters
);
263 // copy all files used by the filters imported from the
264 // typedetection to office/user/xslt
265 for (auto& filter
: aFilters
)
267 if( copyFiles( xIfc
, filter
.get() ) )
269 rFilters
.push_back(std::move(filter
));
273 // failed to copy all files
281 catch( const Exception
& )
283 TOOLS_WARN_EXCEPTION("filter.xslt", "");
287 bool XMLFilterJarHelper::copyFiles( const Reference
< XHierarchicalNameAccess
>& xIfc
, filter_info_impl
* pFilter
)
289 bool bOk
= copyFile( xIfc
, pFilter
->maExportXSLT
, sXSLTPath
);
292 bOk
= copyFile( xIfc
, pFilter
->maImportXSLT
, sXSLTPath
);
295 bOk
= copyFile( xIfc
, pFilter
->maImportTemplate
, sTemplatePath
);
300 bool XMLFilterJarHelper::copyFile( const Reference
< XHierarchicalNameAccess
>& xIfc
, OUString
& rURL
, std::u16string_view rTargetURL
)
302 if( !rURL
.matchIgnoreAsciiCase( sVndSunStarPackage
) )
307 OUString
szPackagePath( encodeZipUri( rURL
.copy( sVndSunStarPackage
.getLength() ) ) );
309 if ( ::comphelper::OStorageHelper::PathHasSegment( szPackagePath
, u
".." )
310 || ::comphelper::OStorageHelper::PathHasSegment( szPackagePath
, u
"." ) )
311 throw lang::IllegalArgumentException();
313 if( xIfc
->hasByHierarchicalName( szPackagePath
) )
315 Reference
< XActiveDataSink
> xFileEntry
;
316 xIfc
->getByHierarchicalName( szPackagePath
) >>= xFileEntry
;
318 if( xFileEntry
.is() )
320 Reference
< XInputStream
> xIS( xFileEntry
->getInputStream() );
322 INetURLObject
aBaseURL( rTargetURL
);
324 rURL
= URIHelper::SmartRel2Abs( aBaseURL
, szPackagePath
, Link
<OUString
*, bool>(), false );
326 if( !rURL
.isEmpty() )
328 // create output directory if needed
329 if( !createDirectory( rURL
) )
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
341 if (::osl::FileBase::E_None
!= rc
) {
342 throw RuntimeException();
344 Reference
< XOutputStream
> const xOS(
345 new comphelper::OSLOutputStreamWrapper(file
));
347 return copyStreams( xIS
, xOS
);
352 catch( const Exception
& )
354 TOOLS_WARN_EXCEPTION("filter.xslt", "");
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */