Line data Source code
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/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"
60 :
61 : namespace {
62 :
63 10061 : rtl::OUString canonic(rtl::OUString const & url) {
64 10061 : INetURLObject o(url);
65 : SAL_WARN_IF(o.HasError(), "unotools", "Invalid URL \"" << url << '"');
66 10061 : return o.GetMainURL(INetURLObject::NO_DECODE);
67 : }
68 :
69 651 : ucbhelper::Content content(rtl::OUString const & url) {
70 : return ucbhelper::Content(
71 : canonic(url),
72 : css::uno::Reference<css::ucb::XCommandEnvironment>(),
73 651 : comphelper::getProcessComponentContext());
74 : }
75 :
76 8 : ucbhelper::Content content(INetURLObject const & url) {
77 : return ucbhelper::Content(
78 : url.GetMainURL(INetURLObject::NO_DECODE),
79 : css::uno::Reference<css::ucb::XCommandEnvironment>(),
80 8 : comphelper::getProcessComponentContext());
81 : }
82 :
83 0 : std::vector<rtl::OUString> getContents(rtl::OUString const & url) {
84 : try {
85 0 : std::vector<rtl::OUString> cs;
86 0 : ucbhelper::Content c(content(url));
87 0 : css::uno::Sequence<rtl::OUString> args(1);
88 0 : args[0] = rtl::OUString("Title");
89 : css::uno::Reference<css::sdbc::XResultSet> res(
90 : c.createCursor(args, ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS),
91 0 : css::uno::UNO_SET_THROW);
92 : css::uno::Reference<com::sun::star::ucb::XContentAccess> acc(
93 0 : res, css::uno::UNO_QUERY_THROW);
94 0 : while (res->next()) {
95 0 : cs.push_back(acc->queryContentIdentifierString());
96 : }
97 0 : return cs;
98 0 : } catch (css::uno::RuntimeException const &) {
99 0 : throw;
100 0 : } catch (css::ucb::CommandAbortedException const &) {
101 : assert(false); // this cannot happen
102 0 : throw;
103 0 : } catch (css::uno::Exception const &) {
104 0 : 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 0 : return std::vector<rtl::OUString>();
110 : }
111 : }
112 :
113 0 : rtl::OUString getCasePreservingUrl(INetURLObject url) {
114 : return
115 : content(url).executeCommand(
116 : rtl::OUString("getCasePreservingURL"),
117 : css::uno::Any()).
118 0 : get<rtl::OUString>();
119 : }
120 :
121 0 : DateTime convert(css::util::DateTime const & dt) {
122 : return DateTime(
123 : Date(dt.Day, dt.Month, dt.Year),
124 0 : Time(dt.Hours, dt.Minutes, dt.Seconds, dt.HundredthSeconds));
125 : }
126 :
127 : }
128 :
129 397 : bool utl::UCBContentHelper::IsDocument(rtl::OUString const & url) {
130 : try {
131 397 : return content(url).isDocument();
132 0 : } catch (css::uno::RuntimeException const &) {
133 0 : throw;
134 0 : } catch (css::ucb::CommandAbortedException const &) {
135 : assert(false); // this cannot happen
136 0 : throw;
137 82 : } catch (css::uno::Exception const &) {
138 41 : 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 41 : return false;
145 : }
146 : }
147 :
148 0 : css::uno::Any utl::UCBContentHelper::GetProperty(
149 : rtl::OUString const & url, rtl::OUString const & property)
150 : {
151 : try {
152 0 : return content(url).getPropertyValue(property);
153 0 : } catch (css::uno::RuntimeException const &) {
154 0 : throw;
155 0 : } catch (css::ucb::CommandAbortedException const &) {
156 : assert(false); // this cannot happen
157 0 : throw;
158 0 : } catch (css::uno::Exception const &) {
159 0 : 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 0 : return css::uno::Any();
166 : }
167 : }
168 :
169 195 : bool utl::UCBContentHelper::IsFolder(rtl::OUString const & url) {
170 : try {
171 195 : return content(url).isFolder();
172 0 : } catch (css::uno::RuntimeException const &) {
173 0 : throw;
174 0 : } catch (css::ucb::CommandAbortedException const &) {
175 : assert(false); // this cannot happen
176 0 : throw;
177 74 : } catch (css::uno::Exception const &) {
178 37 : 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 37 : return false;
185 : }
186 : }
187 :
188 0 : bool utl::UCBContentHelper::GetTitle(
189 : rtl::OUString const & url, rtl::OUString * title)
190 : {
191 : assert(title != 0);
192 : try {
193 0 : return content(url).getPropertyValue(rtl::OUString("Title")) >>= *title;
194 0 : } catch (css::uno::RuntimeException const &) {
195 0 : throw;
196 0 : } catch (css::ucb::CommandAbortedException const &) {
197 : assert(false); // this cannot happen
198 0 : throw;
199 0 : } catch (css::uno::Exception const &) {
200 0 : 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 0 : return false;
207 : }
208 : }
209 :
210 59 : bool utl::UCBContentHelper::Kill(rtl::OUString const & url) {
211 : try {
212 : content(url).executeCommand(
213 : rtl::OUString("delete"),
214 59 : css::uno::makeAny(true));
215 59 : return true;
216 0 : } catch (css::uno::RuntimeException const &) {
217 0 : throw;
218 0 : } catch (css::ucb::CommandAbortedException const &) {
219 : assert(false); // this cannot happen
220 0 : throw;
221 0 : } catch (css::uno::Exception const &) {
222 0 : 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 0 : return false;
229 : }
230 : }
231 :
232 14 : bool utl::UCBContentHelper::MakeFolder(
233 : ucbhelper::Content & parent, rtl::OUString const & title,
234 : ucbhelper::Content & result, bool exclusive)
235 : {
236 14 : bool exists = false;
237 : try {
238 : css::uno::Sequence<css::ucb::ContentInfo> info(
239 14 : parent.queryCreatableContentsInfo());
240 28 : for (sal_Int32 i = 0; i < info.getLength(); ++i) {
241 : // Simply look for the first KIND_FOLDER:
242 28 : if ((info[i].Attributes
243 : & css::ucb::ContentInfoAttribute::KIND_FOLDER)
244 : != 0)
245 : {
246 : // Make sure the only required bootstrap property is "Title":
247 14 : if ( info[i].Properties.getLength() != 1 || info[i].Properties[0].Name != "Title" )
248 : {
249 0 : continue;
250 : }
251 14 : css::uno::Sequence<rtl::OUString> keys(1);
252 14 : keys[0] = rtl::OUString("Title");
253 14 : css::uno::Sequence<css::uno::Any> values(1);
254 14 : values[0] <<= title;
255 14 : if (parent.insertNewContent(info[i].Type, keys, values, result))
256 : {
257 6 : return true;
258 14 : }
259 : }
260 14 : }
261 0 : } catch (css::ucb::InteractiveIOException const & e) {
262 0 : if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) {
263 0 : exists = true;
264 : } else {
265 : SAL_INFO(
266 : "unotools",
267 : "UCBContentHelper::MakeFolder(" << title
268 : << ") InteractiveIOException \"" << e.Message
269 : << "\", code " << +e.Code);
270 : }
271 16 : } catch (css::ucb::NameClashException const &) {
272 8 : exists = true;
273 0 : } catch (css::uno::RuntimeException const &) {
274 0 : throw;
275 0 : } catch (css::ucb::CommandAbortedException const &) {
276 : assert(false); // this cannot happen
277 0 : throw;
278 0 : } catch (css::uno::Exception const &) {
279 0 : css::uno::Any e(cppu::getCaughtException());
280 : SAL_INFO(
281 : "unotools",
282 : "UCBContentHelper::MakeFolder(" << title << ") "
283 : << e.getValueType().getTypeName() << " \""
284 0 : << e.get<css::uno::Exception>().Message << '"');
285 : }
286 8 : if (exists && !exclusive) {
287 8 : INetURLObject o(parent.getURL());
288 8 : o.Append(title);
289 8 : result = content(o);
290 8 : return true;
291 : } else {
292 0 : return false;
293 : }
294 : }
295 :
296 0 : sal_Int64 utl::UCBContentHelper::GetSize(rtl::OUString const & url) {
297 : try {
298 0 : sal_Int64 n = 0;
299 0 : 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 0 : return n;
305 0 : } catch (css::uno::RuntimeException const &) {
306 0 : throw;
307 0 : } catch (css::ucb::CommandAbortedException const &) {
308 : assert(false); // this cannot happen
309 0 : throw;
310 0 : } catch (css::uno::Exception const &) {
311 0 : 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 0 : return 0;
318 : }
319 : }
320 :
321 0 : bool utl::UCBContentHelper::IsYounger(
322 : rtl::OUString const & younger, rtl::OUString const & older)
323 : {
324 : try {
325 : return
326 : convert(
327 : content(younger).getPropertyValue(
328 : rtl::OUString("DateModified")).
329 0 : get<css::util::DateTime>())
330 : > convert(
331 : content(older).getPropertyValue(
332 : rtl::OUString("DateModified")).
333 0 : get<css::util::DateTime>());
334 0 : } catch (css::uno::RuntimeException const &) {
335 0 : throw;
336 0 : } catch (css::ucb::CommandAbortedException const &) {
337 : assert(false); // this cannot happen
338 0 : throw;
339 0 : } catch (css::uno::Exception const &) {
340 0 : 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 0 : return false;
347 : }
348 : }
349 :
350 0 : bool utl::UCBContentHelper::Exists(rtl::OUString const & url) {
351 0 : rtl::OUString pathname;
352 0 : if (utl::LocalFileHelper::ConvertURLToPhysicalName(url, pathname)) {
353 : // Try to create a directory entry for the given URL:
354 0 : rtl::OUString url2;
355 0 : if (osl::FileBase::getFileURLFromSystemPath(pathname, url2)
356 : == osl::FileBase::E_None)
357 : {
358 : // #106526 osl_getDirectoryItem is an existence check, no further
359 : // osl_getFileStatus call necessary:
360 0 : osl::DirectoryItem item;
361 0 : return osl::DirectoryItem::get(url2, item) == osl::FileBase::E_None;
362 : } else {
363 0 : return false;
364 0 : }
365 : } else {
366 : // Divide URL into folder and name part:
367 0 : INetURLObject o(url);
368 : rtl::OUString name(
369 : o.getName(
370 : INetURLObject::LAST_SEGMENT, true,
371 0 : INetURLObject::DECODE_WITH_CHARSET));
372 0 : o.removeSegment();
373 0 : o.removeFinalSlash();
374 : std::vector<rtl::OUString> cs(
375 0 : getContents(o.GetMainURL(INetURLObject::NO_DECODE)));
376 0 : for (std::vector<rtl::OUString>::iterator i(cs.begin()); i != cs.end();
377 : ++i)
378 : {
379 0 : if (INetURLObject(*i).getName(
380 : INetURLObject::LAST_SEGMENT, true,
381 : INetURLObject::DECODE_WITH_CHARSET).
382 0 : equalsIgnoreAsciiCase(name))
383 : {
384 0 : return true;
385 : }
386 : }
387 0 : return false;
388 0 : }
389 : }
390 :
391 0 : bool utl::UCBContentHelper::IsSubPath(
392 : rtl::OUString const & parent, rtl::OUString const & child)
393 : {
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 0 : INetURLObject candidate(child);
402 0 : INetURLObject folder(parent);
403 0 : if (candidate.GetProtocol() != folder.GetProtocol()) {
404 0 : return false;
405 : }
406 0 : INetURLObject candidateLower(child.toAsciiLowerCase());
407 0 : INetURLObject folderLower(parent.toAsciiLowerCase());
408 : try {
409 0 : INetURLObject tmp;
410 0 : do {
411 0 : if (candidate == folder
412 0 : || (candidate.GetProtocol() == INET_PROT_FILE
413 0 : && candidateLower == folderLower
414 : && (getCasePreservingUrl(candidate)
415 0 : == getCasePreservingUrl(folder))))
416 : {
417 0 : return true;
418 : }
419 0 : tmp = candidate;
420 0 : } while (candidate.removeSegment() && candidateLower.removeSegment()
421 0 : && candidate != tmp);
422 : // INetURLObject::removeSegment sometimes returns true without
423 : // modifying the URL, e.g., in case of "file:///"
424 0 : } catch (css::uno::RuntimeException const &) {
425 0 : throw;
426 0 : } catch (css::ucb::CommandAbortedException const &) {
427 : assert(false); // this cannot happen
428 0 : throw;
429 0 : } catch (css::uno::Exception const &) {
430 0 : css::uno::Any e(cppu::getCaughtException());
431 : SAL_INFO(
432 : "unotools",
433 : "UCBContentHelper::IsSubPath(" << parent << ", " << child << ") "
434 : << e.getValueType().getTypeName() << " \""
435 0 : << e.get<css::uno::Exception>().Message << '"');
436 : }
437 0 : return false;
438 : }
439 :
440 4711 : bool utl::UCBContentHelper::EqualURLs(
441 : rtl::OUString const & url1, rtl::OUString const & url2)
442 : {
443 4711 : if (url1.isEmpty() || url2.isEmpty()) {
444 6 : return false;
445 : }
446 : css::uno::Reference< css::ucb::XUniversalContentBroker > ucb(
447 : css::ucb::UniversalContentBroker::create(
448 4705 : comphelper::getProcessComponentContext()));
449 : return
450 4705 : ucb->compareContentIds(
451 9410 : ucb->createContentIdentifier(canonic(url1)),
452 18820 : ucb->createContentIdentifier(canonic(url2)))
453 9410 : == 0;
454 : }
455 :
456 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|