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 <sal/config.h>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/sdbc/XResultSet.hpp>
27 #include <com/sun/star/task/XInteractionHandler.hpp>
28 #include <com/sun/star/ucb/CommandAbortedException.hpp>
29 #include <com/sun/star/ucb/ContentInfo.hpp>
30 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
31 #include <com/sun/star/ucb/IOErrorCode.hpp>
32 #include <com/sun/star/ucb/InteractiveIOException.hpp>
33 #include <com/sun/star/ucb/NameClashException.hpp>
34 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
35 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
36 #include <com/sun/star/ucb/XContentAccess.hpp>
37 #include <com/sun/star/ucb/XContentIdentifier.hpp>
38 #include <com/sun/star/ucb/XProgressHandler.hpp>
39 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
40 #include <com/sun/star/uno/Any.hxx>
41 #include <com/sun/star/uno/Exception.hpp>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/uno/RuntimeException.hpp>
44 #include <com/sun/star/uno/Sequence.hxx>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 #include <com/sun/star/util/DateTime.hpp>
47 #include <comphelper/processfactory.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <osl/file.hxx>
50 #include <rtl/string.h>
51 #include <rtl/ustring.h>
52 #include <rtl/ustring.hxx>
53 #include <sal/log.hxx>
54 #include <sal/types.h>
55 #include <tools/datetime.hxx>
56 #include <tools/urlobj.hxx>
57 #include <ucbhelper/commandenvironment.hxx>
58 #include <ucbhelper/content.hxx>
59 #include <unotools/localfilehelper.hxx>
60 #include <unotools/ucbhelper.hxx>
64 OUString
canonic(OUString
const & url
) {
66 SAL_WARN_IF(o
.HasError(), "unotools.ucbhelper", "Invalid URL \"" << url
<< '"');
67 return o
.GetMainURL(INetURLObject::NO_DECODE
);
70 ucbhelper::Content
content(OUString
const & url
) {
71 return ucbhelper::Content(
73 css::uno::Reference
<css::ucb::XCommandEnvironment
>(),
74 comphelper::getProcessComponentContext());
77 ucbhelper::Content
content(INetURLObject
const & url
) {
78 return ucbhelper::Content(
79 url
.GetMainURL(INetURLObject::NO_DECODE
),
80 css::uno::Reference
<css::ucb::XCommandEnvironment
>(),
81 comphelper::getProcessComponentContext());
84 std::vector
<OUString
> getContents(OUString
const & url
) {
86 std::vector
<OUString
> cs
;
87 ucbhelper::Content
c(content(url
));
88 css::uno::Sequence
<OUString
> args(1);
90 css::uno::Reference
<css::sdbc::XResultSet
> res(
91 c
.createCursor(args
, ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS
),
92 css::uno::UNO_SET_THROW
);
93 css::uno::Reference
<com::sun::star::ucb::XContentAccess
> acc(
94 res
, css::uno::UNO_QUERY_THROW
);
96 cs
.push_back(acc
->queryContentIdentifierString());
99 } catch (css::uno::RuntimeException
const &) {
101 } catch (css::ucb::CommandAbortedException
const &) {
102 assert(false && "this cannot happen");
104 } catch (css::uno::Exception
const &) {
105 css::uno::Any
e(cppu::getCaughtException());
107 "unotools.ucbhelper",
108 "getContents(" << url
<< ") " << e
.getValueType().getTypeName()
109 << " \"" << e
.get
<css::uno::Exception
>().Message
<< '"');
110 return std::vector
<OUString
>();
114 OUString
getCasePreservingUrl(const INetURLObject
& url
) {
116 content(url
).executeCommand(
117 OUString("getCasePreservingURL"),
122 DateTime
convert(css::util::DateTime
const & dt
) {
128 bool utl::UCBContentHelper::IsDocument(OUString
const & url
) {
130 return content(url
).isDocument();
131 } catch (css::uno::RuntimeException
const &) {
133 } catch (css::ucb::CommandAbortedException
const &) {
134 assert(false && "this cannot happen");
136 } catch (css::uno::Exception
const &) {
137 css::uno::Any
e(cppu::getCaughtException());
139 "unotools.ucbhelper",
140 "UCBContentHelper::IsDocument(" << url
<< ") "
141 << e
.getValueType().getTypeName() << " \""
142 << e
.get
<css::uno::Exception
>().Message
<< '"');
147 css::uno::Any
utl::UCBContentHelper::GetProperty(
148 OUString
const & url
, OUString
const & property
)
151 return content(url
).getPropertyValue(property
);
152 } catch (css::uno::RuntimeException
const &) {
154 } catch (css::ucb::CommandAbortedException
const &) {
155 assert(false && "this cannot happen");
157 } catch (css::uno::Exception
const &) {
158 css::uno::Any
e(cppu::getCaughtException());
160 "unotools.ucbhelper",
161 "UCBContentHelper::GetProperty(" << url
<< ", " << property
<< ") "
162 << e
.getValueType().getTypeName() << " \""
163 << e
.get
<css::uno::Exception
>().Message
<< '"');
164 return css::uno::Any();
168 bool utl::UCBContentHelper::IsFolder(OUString
const & url
) {
170 return content(url
).isFolder();
171 } catch (css::uno::RuntimeException
const &) {
173 } catch (css::ucb::CommandAbortedException
const &) {
174 assert(false && "this cannot happen");
176 } catch (css::uno::Exception
const &) {
177 css::uno::Any
e(cppu::getCaughtException());
179 "unotools.ucbhelper",
180 "UCBContentHelper::IsFolder(" << url
<< ") "
181 << e
.getValueType().getTypeName() << " \""
182 << e
.get
<css::uno::Exception
>().Message
<< '"');
187 bool utl::UCBContentHelper::GetTitle(
188 OUString
const & url
, OUString
* title
)
192 return content(url
).getPropertyValue("Title") >>= *title
;
193 } catch (css::uno::RuntimeException
const &) {
195 } catch (css::ucb::CommandAbortedException
const &) {
196 assert(false && "this cannot happen");
198 } catch (css::uno::Exception
const &) {
199 css::uno::Any
e(cppu::getCaughtException());
201 "unotools.ucbhelper",
202 "UCBContentHelper::GetTitle(" << url
<< ") "
203 << e
.getValueType().getTypeName() << " \""
204 << e
.get
<css::uno::Exception
>().Message
<< '"');
209 bool utl::UCBContentHelper::Kill(OUString
const & url
) {
211 content(url
).executeCommand(
213 css::uno::makeAny(true));
215 } catch (css::uno::RuntimeException
const &) {
217 } catch (css::ucb::CommandAbortedException
const &) {
218 assert(false && "this cannot happen");
220 } catch (css::uno::Exception
const &) {
221 css::uno::Any
e(cppu::getCaughtException());
223 "unotools.ucbhelper",
224 "UCBContentHelper::Kill(" << url
<< ") "
225 << e
.getValueType().getTypeName() << " \""
226 << e
.get
<css::uno::Exception
>().Message
<< '"');
231 bool utl::UCBContentHelper::MakeFolder(
232 ucbhelper::Content
& parent
, OUString
const & title
,
233 ucbhelper::Content
& result
, bool exclusive
)
237 css::uno::Sequence
<css::ucb::ContentInfo
> info(
238 parent
.queryCreatableContentsInfo());
239 for (sal_Int32 i
= 0; i
< info
.getLength(); ++i
) {
240 // Simply look for the first KIND_FOLDER:
241 if ((info
[i
].Attributes
242 & css::ucb::ContentInfoAttribute::KIND_FOLDER
)
245 // Make sure the only required bootstrap property is "Title":
246 if ( info
[i
].Properties
.getLength() != 1 || info
[i
].Properties
[0].Name
!= "Title" )
250 css::uno::Sequence
<OUString
> keys(1);
252 css::uno::Sequence
<css::uno::Any
> values(1);
254 if (parent
.insertNewContent(info
[i
].Type
, keys
, values
, result
))
260 } catch (css::ucb::InteractiveIOException
const & e
) {
261 if (e
.Code
== css::ucb::IOErrorCode_ALREADY_EXISTING
) {
265 "unotools.ucbhelper",
266 "UCBContentHelper::MakeFolder(" << title
267 << ") InteractiveIOException \"" << e
.Message
268 << "\", code " << +e
.Code
);
270 } catch (css::ucb::NameClashException
const &) {
272 } catch (css::uno::RuntimeException
const &) {
274 } catch (css::ucb::CommandAbortedException
const &) {
275 assert(false && "this cannot happen");
277 } catch (css::uno::Exception
const &) {
278 css::uno::Any
e(cppu::getCaughtException());
280 "unotools.ucbhelper",
281 "UCBContentHelper::MakeFolder(" << title
<< ") "
282 << e
.getValueType().getTypeName() << " \""
283 << e
.get
<css::uno::Exception
>().Message
<< '"');
285 if (exists
&& !exclusive
) {
286 INetURLObject
o(parent
.getURL());
295 sal_Int64
utl::UCBContentHelper::GetSize(OUString
const & url
) {
298 bool ok
= (content(url
).getPropertyValue("Size") >>= n
);
300 !ok
, "unotools.ucbhelper",
301 "UCBContentHelper::GetSize(" << url
302 << "): Size cannot be determined");
304 } catch (css::uno::RuntimeException
const &) {
306 } catch (css::ucb::CommandAbortedException
const &) {
307 assert(false && "this cannot happen");
309 } catch (css::uno::Exception
const &) {
310 css::uno::Any
e(cppu::getCaughtException());
312 "unotools.ucbhelper",
313 "UCBContentHelper::GetSize(" << url
<< ") "
314 << e
.getValueType().getTypeName() << " \""
315 << e
.get
<css::uno::Exception
>().Message
<< '"');
320 bool utl::UCBContentHelper::IsYounger(
321 OUString
const & younger
, OUString
const & older
)
326 content(younger
).getPropertyValue(
327 OUString("DateModified")).
328 get
<css::util::DateTime
>())
330 content(older
).getPropertyValue(
331 OUString("DateModified")).
332 get
<css::util::DateTime
>());
333 } catch (css::uno::RuntimeException
const &) {
335 } catch (css::ucb::CommandAbortedException
const &) {
336 assert(false && "this cannot happen");
338 } catch (css::uno::Exception
const &) {
339 css::uno::Any
e(cppu::getCaughtException());
341 "unotools.ucbhelper",
342 "UCBContentHelper::IsYounger(" << younger
<< ", " << older
<< ") "
343 << e
.getValueType().getTypeName() << " \""
344 << e
.get
<css::uno::Exception
>().Message
<< '"');
349 bool utl::UCBContentHelper::Exists(OUString
const & url
) {
351 if (utl::LocalFileHelper::ConvertURLToPhysicalName(url
, pathname
)) {
352 // Try to create a directory entry for the given URL:
354 if (osl::FileBase::getFileURLFromSystemPath(pathname
, url2
)
355 == osl::FileBase::E_None
)
357 // #106526 osl_getDirectoryItem is an existence check, no further
358 // osl_getFileStatus call necessary:
359 osl::DirectoryItem item
;
360 return osl::DirectoryItem::get(url2
, item
) == osl::FileBase::E_None
;
365 // Divide URL into folder and name part:
366 INetURLObject
o(url
);
369 INetURLObject::LAST_SEGMENT
, true,
370 INetURLObject::DECODE_WITH_CHARSET
));
372 o
.removeFinalSlash();
373 std::vector
<OUString
> cs(
374 getContents(o
.GetMainURL(INetURLObject::NO_DECODE
)));
375 for (std::vector
<OUString
>::iterator
i(cs
.begin()); i
!= cs
.end();
378 if (INetURLObject(*i
).getName(
379 INetURLObject::LAST_SEGMENT
, true,
380 INetURLObject::DECODE_WITH_CHARSET
).
381 equalsIgnoreAsciiCase(name
))
390 bool utl::UCBContentHelper::IsSubPath(
391 OUString
const & parent
, OUString
const & child
)
393 // The comparison is done in the following way:
394 // - First, compare case sensitively
395 // - If names are different, try a fallback comparing case insensitively
396 // - If the last comparison succeeded, get case preserving normalized names
397 // for the files and compare them
398 // (The second step is required because retrieving the normalized names
399 // might be very expensive in some cases.)
400 INetURLObject
candidate(child
);
401 INetURLObject
folder(parent
);
402 if (candidate
.GetProtocol() != folder
.GetProtocol()) {
405 INetURLObject
candidateLower(child
.toAsciiLowerCase());
406 INetURLObject
folderLower(parent
.toAsciiLowerCase());
410 if (candidate
== folder
411 || (candidate
.GetProtocol() == INetProtocol::File
412 && candidateLower
== folderLower
413 && (getCasePreservingUrl(candidate
)
414 == getCasePreservingUrl(folder
))))
419 } while (candidate
.removeSegment() && candidateLower
.removeSegment()
420 && candidate
!= tmp
);
421 // INetURLObject::removeSegment sometimes returns true without
422 // modifying the URL, e.g., in case of "file:///"
423 } catch (css::uno::RuntimeException
const &) {
425 } catch (css::ucb::CommandAbortedException
const &) {
426 assert(false && "this cannot happen");
428 } catch (css::uno::Exception
const &) {
429 css::uno::Any
e(cppu::getCaughtException());
431 "unotools.ucbhelper",
432 "UCBContentHelper::IsSubPath(" << parent
<< ", " << child
<< ") "
433 << e
.getValueType().getTypeName() << " \""
434 << e
.get
<css::uno::Exception
>().Message
<< '"');
439 bool utl::UCBContentHelper::EqualURLs(
440 OUString
const & url1
, OUString
const & url2
)
442 if (url1
.isEmpty() || url2
.isEmpty()) {
445 css::uno::Reference
< css::ucb::XUniversalContentBroker
> ucb(
446 css::ucb::UniversalContentBroker::create(
447 comphelper::getProcessComponentContext()));
449 ucb
->compareContentIds(
450 ucb
->createContentIdentifier(canonic(url1
)),
451 ucb
->createContentIdentifier(canonic(url2
)))
455 bool utl::UCBContentHelper::ensureFolder(
456 css::uno::Reference
< css::uno::XComponentContext
> xCtx
,
457 css::uno::Reference
< css::ucb::XCommandEnvironment
> xEnv
,
458 const OUString
& rFolder
, ucbhelper::Content
& result
) throw()
462 INetURLObject
aURL( rFolder
);
463 OUString aTitle
= aURL
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
464 aURL
.removeSegment();
465 ::ucbhelper::Content aParent
;
467 if ( ::ucbhelper::Content::create( aURL
.GetMainURL( INetURLObject::NO_DECODE
),
468 xEnv
, xCtx
, aParent
) )
470 return ::utl::UCBContentHelper::MakeFolder(aParent
, aTitle
, result
);
480 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */