LibreOffice Module unotools (master) 1
ucbhelper.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 <sal/config.h>
21
22#include <cassert>
23#include <vector>
24
25#include <com/sun/star/sdbc/XResultSet.hpp>
26#include <com/sun/star/task/XInteractionHandler.hpp>
27#include <com/sun/star/task/InteractionHandler.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/XUniversalContentBroker.hpp>
38#include <com/sun/star/uno/Any.hxx>
39#include <com/sun/star/uno/Exception.hpp>
40#include <com/sun/star/uno/Reference.hxx>
41#include <com/sun/star/uno/RuntimeException.hpp>
42#include <com/sun/star/uno/Sequence.hxx>
45#include <osl/file.hxx>
46#include <rtl/ustring.hxx>
47#include <sal/log.hxx>
48#include <tools/datetime.hxx>
49#include <tools/urlobj.hxx>
52#include <ucbhelper/content.hxx>
54
55namespace com::sun::star::ucb { class XProgressHandler; }
56namespace com::sun::star::uno { class XComponentContext; }
57namespace com::sun::star::util { struct DateTime; }
58
59namespace {
60
61OUString canonic(OUString const & url) {
62 INetURLObject o(url);
63 SAL_WARN_IF(o.HasError(), "unotools.ucbhelper", "Invalid URL \"" << url << '"');
64 return o.GetMainURL(INetURLObject::DecodeMechanism::NONE);
65}
66
67ucbhelper::Content content(OUString const & url) {
68 return ucbhelper::Content(
69 canonic(url),
72}
73
74ucbhelper::Content content(INetURLObject const & url) {
75 return ucbhelper::Content(
79}
80
81std::vector<OUString> getContents(OUString const & url) {
82 try {
83 std::vector<OUString> cs;
84 ucbhelper::Content c(content(url));
85 css::uno::Sequence<OUString> args { "Title" };
86 css::uno::Reference<css::sdbc::XResultSet> res( c.createCursor(args), css::uno::UNO_SET_THROW);
87 css::uno::Reference<css::ucb::XContentAccess> acc( res, css::uno::UNO_QUERY_THROW);
88 while (res->next()) {
89 cs.push_back(acc->queryContentIdentifierString());
90 }
91 return cs;
92 } catch (css::uno::RuntimeException const &) {
93 throw;
94 } catch (css::ucb::CommandAbortedException const &) {
95 assert(false && "this cannot happen");
96 throw;
97 } catch (css::uno::Exception const &) {
98 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "getContents(" << url << ")");
99 return std::vector<OUString>();
100 }
101}
102
103OUString getCasePreservingUrl(const INetURLObject& url) {
104 return
105 content(url).executeCommand(
106 "getCasePreservingURL",
107 css::uno::Any()).
108 get<OUString>();
109}
110
111DateTime convert(css::util::DateTime const & dt) {
112 return DateTime(dt);
113}
114
115}
116
117css::uno::Reference< css::ucb::XCommandEnvironment > utl::UCBContentHelper::getDefaultCommandEnvironment()
118{
119 css::uno::Reference< css::task::XInteractionHandler > xIH(
120 css::task::InteractionHandler::createWithParent(
122
123 css::uno::Reference< css::ucb::XProgressHandler > xProgress;
125 new ::ucbhelper::CommandEnvironment(
126 new comphelper::SimpleFileAccessInteraction( xIH ), xProgress );
127
128 return pCommandEnv;
129}
130
131bool utl::UCBContentHelper::IsDocument(OUString const & url) {
132 try {
133 return content(url).isDocument();
134 } catch (css::uno::RuntimeException const &) {
135 throw;
136 } catch (css::ucb::CommandAbortedException const &) {
137 assert(false && "this cannot happen");
138 throw;
139 } catch (css::uno::Exception const &) {
140 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::IsDocument(" << url << ")");
141 return false;
142 }
143}
144
146 OUString const & url, OUString const & property)
147{
148 try {
149 return content(url).getPropertyValue(property);
150 } catch (css::uno::RuntimeException const &) {
151 throw;
152 } catch (css::ucb::CommandAbortedException const &) {
153 assert(false && "this cannot happen");
154 throw;
155 } catch (css::uno::Exception const &) {
156 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::GetProperty(" << url << ", " << property << ")");
157 return css::uno::Any();
158 }
159}
160
161bool utl::UCBContentHelper::IsFolder(OUString const & url) {
162 try {
163 return content(url).isFolder();
164 } catch (css::uno::RuntimeException const &) {
165 throw;
166 } catch (css::ucb::CommandAbortedException const &) {
167 assert(false && "this cannot happen");
168 throw;
169 } catch (css::uno::Exception const &) {
170 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::IsFolder(" << url << ")");
171 return false;
172 }
173}
174
176 OUString const & url, OUString * title)
177{
178 assert(title != nullptr);
179 try {
180 return content(url).getPropertyValue("Title") >>= *title;
181 } catch (css::uno::RuntimeException const &) {
182 throw;
183 } catch (css::ucb::CommandAbortedException const &) {
184 assert(false && "this cannot happen");
185 throw;
186 } catch (css::uno::Exception const &) {
187 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::GetTitle(" << url << ")");
188 return false;
189 }
190}
191
192bool utl::UCBContentHelper::Kill(OUString const & url) {
193 try {
194 content(url).executeCommand(
195 "delete",
196 css::uno::Any(true));
197 return true;
198 } catch (css::uno::RuntimeException const &) {
199 throw;
200 } catch (css::ucb::CommandAbortedException const &) {
201 assert(false && "this cannot happen");
202 throw;
203 } catch (css::uno::Exception const &) {
204 TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::Kill(" << url << ")");
205 return false;
206 }
207}
208
210 ucbhelper::Content & parent, OUString const & title,
212{
213 bool exists = false;
214 try {
215 const css::uno::Sequence<css::ucb::ContentInfo> info(
217 for (const auto& rInfo : info) {
218 // Simply look for the first KIND_FOLDER:
219 if ((rInfo.Attributes
220 & css::ucb::ContentInfoAttribute::KIND_FOLDER)
221 != 0)
222 {
223 // Make sure the only required bootstrap property is "Title":
224 if ( rInfo.Properties.getLength() != 1 || rInfo.Properties[0].Name != "Title" )
225 {
226 continue;
227 }
228 if (parent.insertNewContent(rInfo.Type, { "Title" }, { css::uno::Any(title) }, result))
229 {
230 return true;
231 }
232 }
233 }
234 } catch (css::ucb::InteractiveIOException const & e) {
235 if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) {
236 exists = true;
237 } else {
239 "unotools.ucbhelper",
240 "UCBContentHelper::MakeFolder(" << title << ")");
241 }
242 } catch (css::ucb::NameClashException const &) {
243 exists = true;
244 } catch (css::uno::RuntimeException const &) {
245 throw;
246 } catch (css::ucb::CommandAbortedException const &) {
247 assert(false && "this cannot happen");
248 throw;
249 } catch (css::uno::Exception const &) {
251 "unotools.ucbhelper",
252 "UCBContentHelper::MakeFolder(" << title << ") ");
253 }
254 if (exists) {
255 INetURLObject o(parent.getURL());
256 o.Append(title);
257 result = content(o);
258 return true;
259 } else {
260 return false;
261 }
262}
263
265 OUString const & younger, OUString const & older)
266{
267 try {
268 return
269 convert(
270 content(younger).getPropertyValue(
271 "DateModified").
272 get<css::util::DateTime>())
273 > convert(
274 content(older).getPropertyValue(
275 "DateModified").
276 get<css::util::DateTime>());
277 } catch (css::uno::RuntimeException const &) {
278 throw;
279 } catch (css::ucb::CommandAbortedException const &) {
280 assert(false && "this cannot happen");
281 throw;
282 } catch (css::uno::Exception const &) {
284 "unotools.ucbhelper",
285 "UCBContentHelper::IsYounger(" << younger << ", " << older << ")");
286 return false;
287 }
288}
289
290bool utl::UCBContentHelper::Exists(OUString const & url) {
291 OUString pathname;
292 if (osl::FileBase::getSystemPathFromFileURL(url, pathname)
293 == osl::FileBase::E_None)
294 {
295 // Try to create a directory entry for the given URL:
296 OUString url2;
297 if (osl::FileBase::getFileURLFromSystemPath(pathname, url2)
298 == osl::FileBase::E_None)
299 {
300 // #106526 osl_getDirectoryItem is an existence check, no further
301 // osl_getFileStatus call necessary:
302 osl::DirectoryItem item;
303 return osl::DirectoryItem::get(url2, item) == osl::FileBase::E_None;
304 } else {
305 return false;
306 }
307 } else {
308 // Divide URL into folder and name part:
309 INetURLObject o(url);
310 OUString name(
311 o.getName(
314 o.removeSegment();
316 std::vector<OUString> cs(
318 return std::any_of(cs.begin(), cs.end(),
319 [&name](const OUString& rItem) {
320 return INetURLObject(rItem).
321 getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset).
322 equalsIgnoreAsciiCase(name); });
323 }
324}
325
327 OUString const & parent, OUString const & child)
328{
329 // The comparison is done in the following way:
330 // - First, compare case sensitively
331 // - If names are different, try a fallback comparing case insensitively
332 // - If the last comparison succeeded, get case preserving normalized names
333 // for the files and compare them
334 // (The second step is required because retrieving the normalized names
335 // might be very expensive in some cases.)
336 INetURLObject candidate(child);
337 INetURLObject folder(parent);
338 if (candidate.GetProtocol() != folder.GetProtocol()) {
339 return false;
340 }
341 INetURLObject candidateLower(child.toAsciiLowerCase());
342 INetURLObject folderLower(parent.toAsciiLowerCase());
343 try {
344 INetURLObject tmp;
345 do {
346 if (candidate == folder
347 || (candidate.GetProtocol() == INetProtocol::File
348 && candidateLower == folderLower
349 && (getCasePreservingUrl(candidate)
350 == getCasePreservingUrl(folder))))
351 {
352 return true;
353 }
354 tmp = candidate;
355 } while (candidate.removeSegment() && candidateLower.removeSegment()
356 && candidate != tmp);
357 // INetURLObject::removeSegment sometimes returns true without
358 // modifying the URL, e.g., in case of "file:///"
359 } catch (css::uno::RuntimeException const &) {
360 throw;
361 } catch (css::ucb::CommandAbortedException const &) {
362 assert(false && "this cannot happen");
363 throw;
364 } catch (css::uno::Exception const &) {
366 "unotools.ucbhelper",
367 "UCBContentHelper::IsSubPath(" << parent << ", " << child << ")");
368 }
369 return false;
370}
371
373 OUString const & url1, OUString const & url2)
374{
375 if (url1.isEmpty() || url2.isEmpty()) {
376 return false;
377 }
378 css::uno::Reference< css::ucb::XUniversalContentBroker > ucb(
379 css::ucb::UniversalContentBroker::create(
381 return
382 ucb->compareContentIds(
383 ucb->createContentIdentifier(canonic(url1)),
384 ucb->createContentIdentifier(canonic(url2)))
385 == 0;
386}
387
389 const css::uno::Reference< css::uno::XComponentContext >& xCtx,
390 const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv,
391 std::u16string_view rFolder, ucbhelper::Content & result) noexcept
392{
393 try
394 {
395 INetURLObject aURL( rFolder );
397 aURL.removeSegment();
398 ::ucbhelper::Content aParent;
399
401 xEnv, xCtx, aParent ) )
402 {
404 }
405 }
406 catch (...)
407 {
408 }
409
410 return false;
411}
412
413/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DateTime(DateTimeInitEmpty)
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool removeFinalSlash()
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
INetProtocol GetProtocol() const
bool Append(std::u16string_view rTheSegment, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
const OUString & getURL() const
static bool create(const OUString &rURL, const css::uno::Reference< css::ucb::XCommandEnvironment > &rEnv, const css::uno::Reference< css::uno::XComponentContext > &rCtx, Content &rContent)
bool insertNewContent(const OUString &rContentType, const css::uno::Sequence< OUString > &rPropertyNames, const css::uno::Sequence< css::uno::Any > &rPropertyValues, Content &rNewContent)
css::uno::Sequence< css::ucb::ContentInfo > queryCreatableContentsInfo()
#define TOOLS_INFO_EXCEPTION(area, stream)
URL aURL
const char * name
#define SAL_WARN_IF(condition, area, stream)
OUString get(TranslateId sContextAndId, const std::locale &loc)
Definition: resmgr.cxx:211
Reference< XComponentContext > getProcessComponentContext()
convert
args
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
UNOTOOLS_DLLPUBLIC bool Exists(OUString const &url)
Definition: ucbhelper.cxx:290
UNOTOOLS_DLLPUBLIC bool IsDocument(OUString const &url)
Definition: ucbhelper.cxx:131
UNOTOOLS_DLLPUBLIC bool MakeFolder(ucbhelper::Content &parent, OUString const &title, ucbhelper::Content &result)
Definition: ucbhelper.cxx:209
UNOTOOLS_DLLPUBLIC css::uno::Any GetProperty(OUString const &url, OUString const &property)
Definition: ucbhelper.cxx:145
UNOTOOLS_DLLPUBLIC bool ensureFolder(const css::uno::Reference< css::uno::XComponentContext > &xCtx, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, std::u16string_view rFolder, ucbhelper::Content &result) noexcept
like mkdir -p
Definition: ucbhelper.cxx:388
UNOTOOLS_DLLPUBLIC css::uno::Reference< css::ucb::XCommandEnvironment > getDefaultCommandEnvironment()
Returns a default XCommandEnvironment to be used when creating a ucbhelper::Content.
Definition: ucbhelper.cxx:117
UNOTOOLS_DLLPUBLIC bool EqualURLs(OUString const &url1, OUString const &url2)
Definition: ucbhelper.cxx:372
UNOTOOLS_DLLPUBLIC bool IsFolder(OUString const &url)
Definition: ucbhelper.cxx:161
UNOTOOLS_DLLPUBLIC bool IsSubPath(OUString const &parent, OUString const &child)
Definition: ucbhelper.cxx:326
UNOTOOLS_DLLPUBLIC bool IsYounger(OUString const &younger, OUString const &older)
Definition: ucbhelper.cxx:264
UNOTOOLS_DLLPUBLIC bool GetTitle(OUString const &url, OUString *title)
Definition: ucbhelper.cxx:175
UNOTOOLS_DLLPUBLIC bool Kill(OUString const &url)
Definition: ucbhelper.cxx:192
Any result