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/util/DateTime.hpp"
46 #include "comphelper/processfactory.hxx"
47 #include "cppuhelper/exc_hlp.hxx"
48 #include "osl/file.hxx"
49 #include "rtl/string.h"
50 #include "rtl/ustring.h"
51 #include "rtl/ustring.hxx"
52 #include "sal/log.hxx"
53 #include "sal/types.h"
54 #include "tools/datetime.hxx"
55 #include "tools/urlobj.hxx"
56 #include "ucbhelper/commandenvironment.hxx"
57 #include "ucbhelper/content.hxx"
58 #include "unotools/localfilehelper.hxx"
59 #include "unotools/ucbhelper.hxx"
63 rtl::OUString
canonic(rtl::OUString
const & url
) {
65 SAL_WARN_IF(o
.HasError(), "unotools", "Invalid URL \"" << url
<< '"');
66 return o
.GetMainURL(INetURLObject::NO_DECODE
);
69 ucbhelper::Content
content(rtl::OUString
const & url
) {
70 return ucbhelper::Content(
72 css::uno::Reference
<css::ucb::XCommandEnvironment
>(),
73 comphelper::getProcessComponentContext());
76 ucbhelper::Content
content(INetURLObject
const & url
) {
77 return ucbhelper::Content(
78 url
.GetMainURL(INetURLObject::NO_DECODE
),
79 css::uno::Reference
<css::ucb::XCommandEnvironment
>(),
80 comphelper::getProcessComponentContext());
83 std::vector
<rtl::OUString
> getContents(rtl::OUString
const & url
) {
85 std::vector
<rtl::OUString
> cs
;
86 ucbhelper::Content
c(content(url
));
87 css::uno::Sequence
<rtl::OUString
> args(1);
88 args
[0] = rtl::OUString("Title");
89 css::uno::Reference
<css::sdbc::XResultSet
> res(
90 c
.createCursor(args
, ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS
),
91 css::uno::UNO_SET_THROW
);
92 css::uno::Reference
<com::sun::star::ucb::XContentAccess
> acc(
93 res
, css::uno::UNO_QUERY_THROW
);
95 cs
.push_back(acc
->queryContentIdentifierString());
98 } catch (css::uno::RuntimeException
const &) {
100 } catch (css::ucb::CommandAbortedException
const &) {
101 assert(false); // this cannot happen
103 } catch (css::uno::Exception
const &) {
104 css::uno::Any
e(cppu::getCaughtException());
107 "getContents(" << url
<< ") " << e
.getValueType().getTypeName()
108 << " \"" << e
.get
<css::uno::Exception
>().Message
<< '"');
109 return std::vector
<rtl::OUString
>();
113 rtl::OUString
getCasePreservingUrl(INetURLObject url
) {
115 content(url
).executeCommand(
116 rtl::OUString("getCasePreservingURL"),
118 get
<rtl::OUString
>();
121 DateTime
convert(css::util::DateTime
const & dt
) {
123 Date(dt
.Day
, dt
.Month
, dt
.Year
),
124 Time(dt
.Hours
, dt
.Minutes
, dt
.Seconds
, dt
.HundredthSeconds
));
129 bool utl::UCBContentHelper::IsDocument(rtl::OUString
const & url
) {
131 return content(url
).isDocument();
132 } catch (css::uno::RuntimeException
const &) {
134 } catch (css::ucb::CommandAbortedException
const &) {
135 assert(false); // this cannot happen
137 } catch (css::uno::Exception
const &) {
138 css::uno::Any
e(cppu::getCaughtException());
141 "UCBContentHelper::IsDocument(" << url
<< ") "
142 << e
.getValueType().getTypeName() << " \""
143 << e
.get
<css::uno::Exception
>().Message
<< '"');
148 css::uno::Any
utl::UCBContentHelper::GetProperty(
149 rtl::OUString
const & url
, rtl::OUString
const & property
)
152 return content(url
).getPropertyValue(property
);
153 } catch (css::uno::RuntimeException
const &) {
155 } catch (css::ucb::CommandAbortedException
const &) {
156 assert(false); // this cannot happen
158 } catch (css::uno::Exception
const &) {
159 css::uno::Any
e(cppu::getCaughtException());
162 "UCBContentHelper::GetProperty(" << url
<< ", " << property
<< ") "
163 << e
.getValueType().getTypeName() << " \""
164 << e
.get
<css::uno::Exception
>().Message
<< '"');
165 return css::uno::Any();
169 bool utl::UCBContentHelper::IsFolder(rtl::OUString
const & url
) {
171 return content(url
).isFolder();
172 } catch (css::uno::RuntimeException
const &) {
174 } catch (css::ucb::CommandAbortedException
const &) {
175 assert(false); // this cannot happen
177 } catch (css::uno::Exception
const &) {
178 css::uno::Any
e(cppu::getCaughtException());
181 "UCBContentHelper::IsFolder(" << url
<< ") "
182 << e
.getValueType().getTypeName() << " \""
183 << e
.get
<css::uno::Exception
>().Message
<< '"');
188 bool utl::UCBContentHelper::GetTitle(
189 rtl::OUString
const & url
, rtl::OUString
* title
)
193 return content(url
).getPropertyValue(rtl::OUString("Title")) >>= *title
;
194 } catch (css::uno::RuntimeException
const &) {
196 } catch (css::ucb::CommandAbortedException
const &) {
197 assert(false); // this cannot happen
199 } catch (css::uno::Exception
const &) {
200 css::uno::Any
e(cppu::getCaughtException());
203 "UCBContentHelper::GetTitle(" << url
<< ") "
204 << e
.getValueType().getTypeName() << " \""
205 << e
.get
<css::uno::Exception
>().Message
<< '"');
210 bool utl::UCBContentHelper::Kill(rtl::OUString
const & url
) {
212 content(url
).executeCommand(
213 rtl::OUString("delete"),
214 css::uno::makeAny(true));
216 } catch (css::uno::RuntimeException
const &) {
218 } catch (css::ucb::CommandAbortedException
const &) {
219 assert(false); // this cannot happen
221 } catch (css::uno::Exception
const &) {
222 css::uno::Any
e(cppu::getCaughtException());
225 "UCBContentHelper::Kill(" << url
<< ") "
226 << e
.getValueType().getTypeName() << " \""
227 << e
.get
<css::uno::Exception
>().Message
<< '"');
232 bool utl::UCBContentHelper::MakeFolder(
233 ucbhelper::Content
& parent
, rtl::OUString
const & title
,
234 ucbhelper::Content
& result
, bool exclusive
)
238 css::uno::Sequence
<css::ucb::ContentInfo
> info(
239 parent
.queryCreatableContentsInfo());
240 for (sal_Int32 i
= 0; i
< info
.getLength(); ++i
) {
241 // Simply look for the first KIND_FOLDER:
242 if ((info
[i
].Attributes
243 & css::ucb::ContentInfoAttribute::KIND_FOLDER
)
246 // Make sure the only required bootstrap property is "Title":
247 if ( info
[i
].Properties
.getLength() != 1 || info
[i
].Properties
[0].Name
!= "Title" )
251 css::uno::Sequence
<rtl::OUString
> keys(1);
252 keys
[0] = rtl::OUString("Title");
253 css::uno::Sequence
<css::uno::Any
> values(1);
255 if (parent
.insertNewContent(info
[i
].Type
, keys
, values
, result
))
261 } catch (css::ucb::InteractiveIOException
const & e
) {
262 if (e
.Code
== css::ucb::IOErrorCode_ALREADY_EXISTING
) {
267 "UCBContentHelper::MakeFolder(" << title
268 << ") InteractiveIOException \"" << e
.Message
269 << "\", code " << +e
.Code
);
271 } catch (css::ucb::NameClashException
const &) {
273 } catch (css::uno::RuntimeException
const &) {
275 } catch (css::ucb::CommandAbortedException
const &) {
276 assert(false); // this cannot happen
278 } catch (css::uno::Exception
const &) {
279 css::uno::Any
e(cppu::getCaughtException());
282 "UCBContentHelper::MakeFolder(" << title
<< ") "
283 << e
.getValueType().getTypeName() << " \""
284 << e
.get
<css::uno::Exception
>().Message
<< '"');
286 if (exists
&& !exclusive
) {
287 INetURLObject
o(parent
.getURL());
296 sal_Int64
utl::UCBContentHelper::GetSize(rtl::OUString
const & url
) {
299 bool ok
= (content(url
).getPropertyValue(rtl::OUString("Size")) >>= n
);
302 "UCBContentHelper::GetSize(" << url
303 << "): Size cannot be determined");
305 } catch (css::uno::RuntimeException
const &) {
307 } catch (css::ucb::CommandAbortedException
const &) {
308 assert(false); // this cannot happen
310 } catch (css::uno::Exception
const &) {
311 css::uno::Any
e(cppu::getCaughtException());
314 "UCBContentHelper::GetSize(" << url
<< ") "
315 << e
.getValueType().getTypeName() << " \""
316 << e
.get
<css::uno::Exception
>().Message
<< '"');
321 bool utl::UCBContentHelper::IsYounger(
322 rtl::OUString
const & younger
, rtl::OUString
const & older
)
327 content(younger
).getPropertyValue(
328 rtl::OUString("DateModified")).
329 get
<css::util::DateTime
>())
331 content(older
).getPropertyValue(
332 rtl::OUString("DateModified")).
333 get
<css::util::DateTime
>());
334 } catch (css::uno::RuntimeException
const &) {
336 } catch (css::ucb::CommandAbortedException
const &) {
337 assert(false); // this cannot happen
339 } catch (css::uno::Exception
const &) {
340 css::uno::Any
e(cppu::getCaughtException());
343 "UCBContentHelper::IsYounger(" << younger
<< ", " << older
<< ") "
344 << e
.getValueType().getTypeName() << " \""
345 << e
.get
<css::uno::Exception
>().Message
<< '"');
350 bool utl::UCBContentHelper::Exists(rtl::OUString
const & url
) {
351 rtl::OUString pathname
;
352 if (utl::LocalFileHelper::ConvertURLToPhysicalName(url
, pathname
)) {
353 // Try to create a directory entry for the given URL:
355 if (osl::FileBase::getFileURLFromSystemPath(pathname
, url2
)
356 == osl::FileBase::E_None
)
358 // #106526 osl_getDirectoryItem is an existence check, no further
359 // osl_getFileStatus call necessary:
360 osl::DirectoryItem item
;
361 return osl::DirectoryItem::get(url2
, item
) == osl::FileBase::E_None
;
366 // Divide URL into folder and name part:
367 INetURLObject
o(url
);
370 INetURLObject::LAST_SEGMENT
, true,
371 INetURLObject::DECODE_WITH_CHARSET
));
373 o
.removeFinalSlash();
374 std::vector
<rtl::OUString
> cs(
375 getContents(o
.GetMainURL(INetURLObject::NO_DECODE
)));
376 for (std::vector
<rtl::OUString
>::iterator
i(cs
.begin()); i
!= cs
.end();
379 if (INetURLObject(*i
).getName(
380 INetURLObject::LAST_SEGMENT
, true,
381 INetURLObject::DECODE_WITH_CHARSET
).
382 equalsIgnoreAsciiCase(name
))
391 bool utl::UCBContentHelper::IsSubPath(
392 rtl::OUString
const & parent
, rtl::OUString
const & child
)
394 // The comparison is done in the following way:
395 // - First, compare case sensitively
396 // - If names are different, try a fallback comparing case insensitively
397 // - If the last comparison succeeded, get case preserving normalized names
398 // for the files and compare them
399 // (The second step is required because retrieving the normalized names
400 // might be very expensive in some cases.)
401 INetURLObject
candidate(child
);
402 INetURLObject
folder(parent
);
403 if (candidate
.GetProtocol() != folder
.GetProtocol()) {
406 INetURLObject
candidateLower(child
.toAsciiLowerCase());
407 INetURLObject
folderLower(parent
.toAsciiLowerCase());
411 if (candidate
== folder
412 || (candidate
.GetProtocol() == INET_PROT_FILE
413 && candidateLower
== folderLower
414 && (getCasePreservingUrl(candidate
)
415 == getCasePreservingUrl(folder
))))
420 } while (candidate
.removeSegment() && candidateLower
.removeSegment()
421 && candidate
!= tmp
);
422 // INetURLObject::removeSegment sometimes returns true without
423 // modifying the URL, e.g., in case of "file:///"
424 } catch (css::uno::RuntimeException
const &) {
426 } catch (css::ucb::CommandAbortedException
const &) {
427 assert(false); // this cannot happen
429 } catch (css::uno::Exception
const &) {
430 css::uno::Any
e(cppu::getCaughtException());
433 "UCBContentHelper::IsSubPath(" << parent
<< ", " << child
<< ") "
434 << e
.getValueType().getTypeName() << " \""
435 << e
.get
<css::uno::Exception
>().Message
<< '"');
440 bool utl::UCBContentHelper::EqualURLs(
441 rtl::OUString
const & url1
, rtl::OUString
const & url2
)
443 if (url1
.isEmpty() || url2
.isEmpty()) {
446 css::uno::Reference
< css::ucb::XUniversalContentBroker
> ucb(
447 css::ucb::UniversalContentBroker::create(
448 comphelper::getProcessComponentContext()));
450 ucb
->compareContentIds(
451 ucb
->createContentIdentifier(canonic(url1
)),
452 ucb
->createContentIdentifier(canonic(url2
)))
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */