Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / unotools / source / ucbhelper / ucbhelper.cxx
blob2961fff80a24a3ff17a96ba6d14ddbd001eb769d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <cassert>
23 #include <vector>
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"
61 namespace {
63 rtl::OUString canonic(rtl::OUString const & url) {
64 INetURLObject o(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(
71 canonic(url),
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) {
84 try {
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);
94 while (res->next()) {
95 cs.push_back(acc->queryContentIdentifierString());
97 return cs;
98 } catch (css::uno::RuntimeException const &) {
99 throw;
100 } catch (css::ucb::CommandAbortedException const &) {
101 assert(false); // this cannot happen
102 throw;
103 } catch (css::uno::Exception const &) {
104 css::uno::Any e(cppu::getCaughtException());
105 SAL_INFO(
106 "unotools",
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) {
114 return
115 content(url).executeCommand(
116 rtl::OUString("getCasePreservingURL"),
117 css::uno::Any()).
118 get<rtl::OUString>();
121 DateTime convert(css::util::DateTime const & dt) {
122 return DateTime(
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) {
130 try {
131 return content(url).isDocument();
132 } catch (css::uno::RuntimeException const &) {
133 throw;
134 } catch (css::ucb::CommandAbortedException const &) {
135 assert(false); // this cannot happen
136 throw;
137 } catch (css::uno::Exception const &) {
138 css::uno::Any e(cppu::getCaughtException());
139 SAL_INFO(
140 "unotools",
141 "UCBContentHelper::IsDocument(" << url << ") "
142 << e.getValueType().getTypeName() << " \""
143 << e.get<css::uno::Exception>().Message << '"');
144 return false;
148 css::uno::Any utl::UCBContentHelper::GetProperty(
149 rtl::OUString const & url, rtl::OUString const & property)
151 try {
152 return content(url).getPropertyValue(property);
153 } catch (css::uno::RuntimeException const &) {
154 throw;
155 } catch (css::ucb::CommandAbortedException const &) {
156 assert(false); // this cannot happen
157 throw;
158 } catch (css::uno::Exception const &) {
159 css::uno::Any e(cppu::getCaughtException());
160 SAL_INFO(
161 "unotools",
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) {
170 try {
171 return content(url).isFolder();
172 } catch (css::uno::RuntimeException const &) {
173 throw;
174 } catch (css::ucb::CommandAbortedException const &) {
175 assert(false); // this cannot happen
176 throw;
177 } catch (css::uno::Exception const &) {
178 css::uno::Any e(cppu::getCaughtException());
179 SAL_INFO(
180 "unotools",
181 "UCBContentHelper::IsFolder(" << url << ") "
182 << e.getValueType().getTypeName() << " \""
183 << e.get<css::uno::Exception>().Message << '"');
184 return false;
188 bool utl::UCBContentHelper::GetTitle(
189 rtl::OUString const & url, rtl::OUString * title)
191 assert(title != 0);
192 try {
193 return content(url).getPropertyValue(rtl::OUString("Title")) >>= *title;
194 } catch (css::uno::RuntimeException const &) {
195 throw;
196 } catch (css::ucb::CommandAbortedException const &) {
197 assert(false); // this cannot happen
198 throw;
199 } catch (css::uno::Exception const &) {
200 css::uno::Any e(cppu::getCaughtException());
201 SAL_INFO(
202 "unotools",
203 "UCBContentHelper::GetTitle(" << url << ") "
204 << e.getValueType().getTypeName() << " \""
205 << e.get<css::uno::Exception>().Message << '"');
206 return false;
210 bool utl::UCBContentHelper::Kill(rtl::OUString const & url) {
211 try {
212 content(url).executeCommand(
213 rtl::OUString("delete"),
214 css::uno::makeAny(true));
215 return true;
216 } catch (css::uno::RuntimeException const &) {
217 throw;
218 } catch (css::ucb::CommandAbortedException const &) {
219 assert(false); // this cannot happen
220 throw;
221 } catch (css::uno::Exception const &) {
222 css::uno::Any e(cppu::getCaughtException());
223 SAL_INFO(
224 "unotools",
225 "UCBContentHelper::Kill(" << url << ") "
226 << e.getValueType().getTypeName() << " \""
227 << e.get<css::uno::Exception>().Message << '"');
228 return false;
232 bool utl::UCBContentHelper::MakeFolder(
233 ucbhelper::Content & parent, rtl::OUString const & title,
234 ucbhelper::Content & result, bool exclusive)
236 bool exists = false;
237 try {
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)
244 != 0)
246 // Make sure the only required bootstrap property is "Title":
247 if ( info[i].Properties.getLength() != 1 || info[i].Properties[0].Name != "Title" )
249 continue;
251 css::uno::Sequence<rtl::OUString> keys(1);
252 keys[0] = rtl::OUString("Title");
253 css::uno::Sequence<css::uno::Any> values(1);
254 values[0] <<= title;
255 if (parent.insertNewContent(info[i].Type, keys, values, result))
257 return true;
261 } catch (css::ucb::InteractiveIOException const & e) {
262 if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) {
263 exists = true;
264 } else {
265 SAL_INFO(
266 "unotools",
267 "UCBContentHelper::MakeFolder(" << title
268 << ") InteractiveIOException \"" << e.Message
269 << "\", code " << +e.Code);
271 } catch (css::ucb::NameClashException const &) {
272 exists = true;
273 } catch (css::uno::RuntimeException const &) {
274 throw;
275 } catch (css::ucb::CommandAbortedException const &) {
276 assert(false); // this cannot happen
277 throw;
278 } catch (css::uno::Exception const &) {
279 css::uno::Any e(cppu::getCaughtException());
280 SAL_INFO(
281 "unotools",
282 "UCBContentHelper::MakeFolder(" << title << ") "
283 << e.getValueType().getTypeName() << " \""
284 << e.get<css::uno::Exception>().Message << '"');
286 if (exists && !exclusive) {
287 INetURLObject o(parent.getURL());
288 o.Append(title);
289 result = content(o);
290 return true;
291 } else {
292 return false;
296 sal_Int64 utl::UCBContentHelper::GetSize(rtl::OUString const & url) {
297 try {
298 sal_Int64 n = 0;
299 bool ok = (content(url).getPropertyValue(rtl::OUString("Size")) >>= n);
300 SAL_INFO_IF(
301 !ok, "unotools",
302 "UCBContentHelper::GetSize(" << url
303 << "): Size cannot be determined");
304 return n;
305 } catch (css::uno::RuntimeException const &) {
306 throw;
307 } catch (css::ucb::CommandAbortedException const &) {
308 assert(false); // this cannot happen
309 throw;
310 } catch (css::uno::Exception const &) {
311 css::uno::Any e(cppu::getCaughtException());
312 SAL_INFO(
313 "unotools",
314 "UCBContentHelper::GetSize(" << url << ") "
315 << e.getValueType().getTypeName() << " \""
316 << e.get<css::uno::Exception>().Message << '"');
317 return 0;
321 bool utl::UCBContentHelper::IsYounger(
322 rtl::OUString const & younger, rtl::OUString const & older)
324 try {
325 return
326 convert(
327 content(younger).getPropertyValue(
328 rtl::OUString("DateModified")).
329 get<css::util::DateTime>())
330 > convert(
331 content(older).getPropertyValue(
332 rtl::OUString("DateModified")).
333 get<css::util::DateTime>());
334 } catch (css::uno::RuntimeException const &) {
335 throw;
336 } catch (css::ucb::CommandAbortedException const &) {
337 assert(false); // this cannot happen
338 throw;
339 } catch (css::uno::Exception const &) {
340 css::uno::Any e(cppu::getCaughtException());
341 SAL_INFO(
342 "unotools",
343 "UCBContentHelper::IsYounger(" << younger << ", " << older << ") "
344 << e.getValueType().getTypeName() << " \""
345 << e.get<css::uno::Exception>().Message << '"');
346 return false;
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:
354 rtl::OUString url2;
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;
362 } else {
363 return false;
365 } else {
366 // Divide URL into folder and name part:
367 INetURLObject o(url);
368 rtl::OUString name(
369 o.getName(
370 INetURLObject::LAST_SEGMENT, true,
371 INetURLObject::DECODE_WITH_CHARSET));
372 o.removeSegment();
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();
377 ++i)
379 if (INetURLObject(*i).getName(
380 INetURLObject::LAST_SEGMENT, true,
381 INetURLObject::DECODE_WITH_CHARSET).
382 equalsIgnoreAsciiCase(name))
384 return true;
387 return false;
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()) {
404 return false;
406 INetURLObject candidateLower(child.toAsciiLowerCase());
407 INetURLObject folderLower(parent.toAsciiLowerCase());
408 try {
409 INetURLObject tmp;
410 do {
411 if (candidate == folder
412 || (candidate.GetProtocol() == INET_PROT_FILE
413 && candidateLower == folderLower
414 && (getCasePreservingUrl(candidate)
415 == getCasePreservingUrl(folder))))
417 return true;
419 tmp = candidate;
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 &) {
425 throw;
426 } catch (css::ucb::CommandAbortedException const &) {
427 assert(false); // this cannot happen
428 throw;
429 } catch (css::uno::Exception const &) {
430 css::uno::Any e(cppu::getCaughtException());
431 SAL_INFO(
432 "unotools",
433 "UCBContentHelper::IsSubPath(" << parent << ", " << child << ") "
434 << e.getValueType().getTypeName() << " \""
435 << e.get<css::uno::Exception>().Message << '"');
437 return false;
440 bool utl::UCBContentHelper::EqualURLs(
441 rtl::OUString const & url1, rtl::OUString const & url2)
443 if (url1.isEmpty() || url2.isEmpty()) {
444 return false;
446 css::uno::Reference< css::ucb::XUniversalContentBroker > ucb(
447 css::ucb::UniversalContentBroker::create(
448 comphelper::getProcessComponentContext()));
449 return
450 ucb->compareContentIds(
451 ucb->createContentIdentifier(canonic(url1)),
452 ucb->createContentIdentifier(canonic(url2)))
453 == 0;
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */