Branch data 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/XCommandEnvironment.hpp"
35 : : #include "com/sun/star/ucb/XContentAccess.hpp"
36 : : #include "com/sun/star/ucb/XContentIdentifier.hpp"
37 : : #include "com/sun/star/ucb/XContentIdentifierFactory.hpp"
38 : : #include "com/sun/star/ucb/XProgressHandler.hpp"
39 : : #include "com/sun/star/uno/Any.hxx"
40 : : #include "com/sun/star/uno/Exception.hpp"
41 : : #include "com/sun/star/uno/Reference.hxx"
42 : : #include "com/sun/star/uno/RuntimeException.hpp"
43 : : #include "com/sun/star/uno/Sequence.hxx"
44 : : #include "com/sun/star/util/DateTime.hpp"
45 : : #include "comphelper/processfactory.hxx"
46 : : #include "cppuhelper/exc_hlp.hxx"
47 : : #include "osl/file.hxx"
48 : : #include "rtl/oustringostreaminserter.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 "ucbhelper/contentbroker.hxx"
59 : : #include "unotools/localfilehelper.hxx"
60 : : #include "unotools/ucbhelper.hxx"
61 : :
62 : : namespace {
63 : :
64 : : namespace css = com::sun::star;
65 : :
66 : 11785 : rtl::OUString canonic(rtl::OUString const & url) {
67 [ + - ]: 11785 : INetURLObject o(url);
68 : : SAL_WARN_IF(o.HasError(), "unotools", "Invalid URL \"" << url << '"');
69 [ + - ][ + - ]: 11785 : return o.GetMainURL(INetURLObject::NO_DECODE);
70 : : }
71 : :
72 : 7333 : ucbhelper::Content content(rtl::OUString const & url) {
73 : : return ucbhelper::Content(
74 : : canonic(url),
75 [ + - ][ + + ]: 7333 : css::uno::Reference<css::ucb::XCommandEnvironment>());
76 : : }
77 : :
78 : 75 : ucbhelper::Content content(INetURLObject const & url) {
79 : : return ucbhelper::Content(
80 : : url.GetMainURL(INetURLObject::NO_DECODE),
81 [ + - ][ + - ]: 75 : css::uno::Reference<css::ucb::XCommandEnvironment>());
82 : : }
83 : :
84 : 0 : std::vector<rtl::OUString> getContents(rtl::OUString const & url) {
85 : : try {
86 [ # # ]: 0 : std::vector<rtl::OUString> cs;
87 [ # # ]: 0 : ucbhelper::Content c(content(url));
88 [ # # ]: 0 : css::uno::Sequence<rtl::OUString> args(1);
89 [ # # ]: 0 : args[0] = rtl::OUString("Title");
90 : : css::uno::Reference<css::sdbc::XResultSet> res(
91 : : c.createCursor(args, ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS),
92 [ # # ][ # # ]: 0 : css::uno::UNO_SET_THROW);
93 : : css::uno::Reference<com::sun::star::ucb::XContentAccess> acc(
94 [ # # ]: 0 : res, css::uno::UNO_QUERY_THROW);
95 [ # # ][ # # ]: 0 : while (res->next()) {
[ # # ]
96 [ # # ][ # # ]: 0 : cs.push_back(acc->queryContentIdentifierString());
[ # # ]
97 : : }
98 [ # # ][ # # ]: 0 : return cs;
99 : 0 : } catch (css::uno::RuntimeException const &) {
100 : 0 : throw;
101 : 0 : } catch (css::ucb::CommandAbortedException const &) {
102 : : assert(false); // this cannot happen
103 : 0 : throw;
104 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
105 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
106 : : SAL_INFO(
107 : : "unotools",
108 : : "getContents(" << url << ") " << e.getValueType().getTypeName()
109 : : << " \"" << e.get<css::uno::Exception>().Message << '"');
110 [ # # ]: 0 : return std::vector<rtl::OUString>();
111 : : }
112 : : }
113 : :
114 : 0 : rtl::OUString getCasePreservingUrl(INetURLObject url) {
115 : : return
116 : : content(url).executeCommand(
117 : : rtl::OUString("getCasePreservingURL"),
118 : : css::uno::Any()).
119 [ # # ][ # # ]: 0 : get<rtl::OUString>();
[ # # ][ # # ]
120 : : }
121 : :
122 : 0 : DateTime convert(css::util::DateTime const & dt) {
123 : : return DateTime(
124 : : Date(dt.Day, dt.Month, dt.Year),
125 [ # # ]: 0 : Time(dt.Hours, dt.Minutes, dt.Seconds, dt.HundredthSeconds));
126 : : }
127 : :
128 : : }
129 : :
130 : 2752 : bool utl::UCBContentHelper::IsDocument(rtl::OUString const & url) {
131 : : try {
132 [ + - ][ + + ]: 4016 : return content(url).isDocument();
[ + - ]
133 : 0 : } catch (css::uno::RuntimeException const &) {
134 : 0 : throw;
135 : 0 : } catch (css::ucb::CommandAbortedException const &) {
136 : : assert(false); // this cannot happen
137 : 0 : throw;
138 [ - - - + ]: 2528 : } catch (css::uno::Exception const &) {
139 [ - + ]: 1264 : css::uno::Any e(cppu::getCaughtException());
140 : : SAL_INFO(
141 : : "unotools",
142 : : "UCBContentHelper::IsDocument(" << url << ") "
143 : : << e.getValueType().getTypeName() << " \""
144 : : << e.get<css::uno::Exception>().Message << '"');
145 : 1264 : return false;
146 : : }
147 : : }
148 : :
149 : 0 : css::uno::Any utl::UCBContentHelper::GetProperty(
150 : : rtl::OUString const & url, rtl::OUString const & property)
151 : : {
152 : : try {
153 [ # # ][ # # ]: 0 : return content(url).getPropertyValue(property);
[ # # ]
154 : 0 : } catch (css::uno::RuntimeException const &) {
155 : 0 : throw;
156 : 0 : } catch (css::ucb::CommandAbortedException const &) {
157 : : assert(false); // this cannot happen
158 : 0 : throw;
159 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
160 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
161 : : SAL_INFO(
162 : : "unotools",
163 : : "UCBContentHelper::GetProperty(" << url << ", " << property << ") "
164 : : << e.getValueType().getTypeName() << " \""
165 : : << e.get<css::uno::Exception>().Message << '"');
166 : 0 : return css::uno::Any();
167 : : }
168 : : }
169 : :
170 : 4269 : bool utl::UCBContentHelper::IsFolder(rtl::OUString const & url) {
171 : : try {
172 [ + + ][ + + ]: 5462 : return content(url).isFolder();
[ + - ]
173 : 0 : } catch (css::uno::RuntimeException const &) {
174 : 0 : throw;
175 : 0 : } catch (css::ucb::CommandAbortedException const &) {
176 : : assert(false); // this cannot happen
177 : 0 : throw;
178 [ - - - + ]: 2386 : } catch (css::uno::Exception const &) {
179 [ - + ]: 1193 : css::uno::Any e(cppu::getCaughtException());
180 : : SAL_INFO(
181 : : "unotools",
182 : : "UCBContentHelper::IsFolder(" << url << ") "
183 : : << e.getValueType().getTypeName() << " \""
184 : : << e.get<css::uno::Exception>().Message << '"');
185 : 1193 : return false;
186 : : }
187 : : }
188 : :
189 : 0 : bool utl::UCBContentHelper::GetTitle(
190 : : rtl::OUString const & url, rtl::OUString * title)
191 : : {
192 : : assert(title != 0);
193 : : try {
194 [ # # ][ # # ]: 0 : return content(url).getPropertyValue(rtl::OUString("Title")) >>= *title;
[ # # ]
195 : 0 : } catch (css::uno::RuntimeException const &) {
196 : 0 : throw;
197 : 0 : } catch (css::ucb::CommandAbortedException const &) {
198 : : assert(false); // this cannot happen
199 : 0 : throw;
200 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
201 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
202 : : SAL_INFO(
203 : : "unotools",
204 : : "UCBContentHelper::GetTitle(" << url << ") "
205 : : << e.getValueType().getTypeName() << " \""
206 : : << e.get<css::uno::Exception>().Message << '"');
207 : 0 : return false;
208 : : }
209 : : }
210 : :
211 : 312 : bool utl::UCBContentHelper::Kill(rtl::OUString const & url) {
212 : : try {
213 : : content(url).executeCommand(
214 : : rtl::OUString("delete"),
215 [ + - ][ + - ]: 312 : css::uno::makeAny(true));
[ + - ][ + - ]
216 : 312 : return true;
217 : 0 : } catch (css::uno::RuntimeException const &) {
218 : 0 : throw;
219 : 0 : } catch (css::ucb::CommandAbortedException const &) {
220 : : assert(false); // this cannot happen
221 : 0 : throw;
222 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
223 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
224 : : SAL_INFO(
225 : : "unotools",
226 : : "UCBContentHelper::Kill(" << url << ") "
227 : : << e.getValueType().getTypeName() << " \""
228 : : << e.get<css::uno::Exception>().Message << '"');
229 : 0 : return false;
230 : : }
231 : : }
232 : :
233 : 597 : bool utl::UCBContentHelper::MakeFolder(
234 : : ucbhelper::Content & parent, rtl::OUString const & title,
235 : : ucbhelper::Content & result, bool exclusive)
236 : : {
237 : 597 : bool exists = false;
238 : : try {
239 : : css::uno::Sequence<css::ucb::ContentInfo> info(
240 [ + - ]: 597 : parent.queryCreatableContentsInfo());
241 [ + - ]: 1194 : for (sal_Int32 i = 0; i < info.getLength(); ++i) {
242 : : // Simply look for the first KIND_FOLDER:
243 [ + - ][ + + ]: 1194 : if ((info[i].Attributes
244 : : & css::ucb::ContentInfoAttribute::KIND_FOLDER)
245 : : != 0)
246 : : {
247 : : // Make sure the only required bootstrap property is "Title":
248 [ + - ][ + - ]: 597 : if ( info[i].Properties.getLength() != 1 || info[i].Properties[0].Name != "Title" )
[ + - ][ + - ]
[ - + ][ - + ]
249 : : {
250 : 0 : continue;
251 : : }
252 [ + - ]: 597 : css::uno::Sequence<rtl::OUString> keys(1);
253 [ + - ]: 597 : keys[0] = rtl::OUString("Title");
254 [ + - ]: 597 : css::uno::Sequence<css::uno::Any> values(1);
255 [ + - ][ + - ]: 597 : values[0] <<= title;
256 [ + - ][ + + ]: 597 : if (parent.insertNewContent(info[i].Type, keys, values, result))
[ + - ]
257 : : {
258 : 522 : return true;
259 [ + - ][ + - ]: 597 : }
[ + - ][ - + ]
260 : : }
261 [ + - ][ - + ]: 597 : }
262 : 0 : } catch (css::ucb::InteractiveIOException const & e) {
263 [ # # ]: 0 : if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) {
264 : 0 : exists = true;
265 : : } else {
266 : : SAL_INFO(
267 : : "unotools",
268 : : "UCBContentHelper::MakeFolder(" << title
269 : : << ") InteractiveIOException \"" << e.Message
270 : : << "\", code " << +e.Code);
271 : : }
272 : 75 : } catch (css::ucb::NameClashException const &) {
273 : 75 : exists = true;
274 : 0 : } catch (css::uno::RuntimeException const &) {
275 : 0 : throw;
276 : 0 : } catch (css::ucb::CommandAbortedException const &) {
277 : : assert(false); // this cannot happen
278 : 0 : throw;
279 [ - - + - : 75 : } catch (css::uno::Exception const &) {
- - ]
280 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
281 : : SAL_INFO(
282 : : "unotools",
283 : : "UCBContentHelper::MakeFolder(" << title << ") "
284 : : << e.getValueType().getTypeName() << " \""
285 : 0 : << e.get<css::uno::Exception>().Message << '"');
286 : : }
287 [ + - ][ + - ]: 75 : if (exists && !exclusive) {
288 [ + - ][ + - ]: 75 : INetURLObject o(parent.getURL());
289 [ + - ]: 75 : o.Append(title);
290 [ + - ][ + - ]: 75 : result = content(o);
[ + - ]
291 [ + - ]: 75 : return true;
292 : : } else {
293 : 597 : return false;
294 : : }
295 : : }
296 : :
297 : 0 : sal_Int64 utl::UCBContentHelper::GetSize(rtl::OUString const & url) {
298 : : try {
299 : 0 : sal_Int64 n = 0;
300 [ # # ][ # # ]: 0 : bool ok = (content(url).getPropertyValue(rtl::OUString("Size")) >>= n);
[ # # ]
301 : : SAL_INFO_IF(
302 : : !ok, "unotools",
303 : : "UCBContentHelper::GetSize(" << url
304 : : << "): Size cannot be determined");
305 : 0 : return n;
306 : 0 : } catch (css::uno::RuntimeException const &) {
307 : 0 : throw;
308 : 0 : } catch (css::ucb::CommandAbortedException const &) {
309 : : assert(false); // this cannot happen
310 : 0 : throw;
311 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
312 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
313 : : SAL_INFO(
314 : : "unotools",
315 : : "UCBContentHelper::GetSize(" << url << ") "
316 : : << e.getValueType().getTypeName() << " \""
317 : : << e.get<css::uno::Exception>().Message << '"');
318 : 0 : return 0;
319 : : }
320 : : }
321 : :
322 : 0 : bool utl::UCBContentHelper::IsYounger(
323 : : rtl::OUString const & younger, rtl::OUString const & older)
324 : : {
325 : : try {
326 : : return
327 : : convert(
328 : : content(younger).getPropertyValue(
329 : : rtl::OUString("DateModified")).
330 [ # # ][ # # ]: 0 : get<css::util::DateTime>())
[ # # ]
331 : : > convert(
332 : : content(older).getPropertyValue(
333 : : rtl::OUString("DateModified")).
334 [ # # ][ # # ]: 0 : get<css::util::DateTime>());
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
335 : 0 : } catch (css::uno::RuntimeException const &) {
336 : 0 : throw;
337 : 0 : } catch (css::ucb::CommandAbortedException const &) {
338 : : assert(false); // this cannot happen
339 : 0 : throw;
340 [ # # # # ]: 0 : } catch (css::uno::Exception const &) {
341 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
342 : : SAL_INFO(
343 : : "unotools",
344 : : "UCBContentHelper::IsYounger(" << younger << ", " << older << ") "
345 : : << e.getValueType().getTypeName() << " \""
346 : : << e.get<css::uno::Exception>().Message << '"');
347 : 0 : return false;
348 : : }
349 : : }
350 : :
351 : 396 : bool utl::UCBContentHelper::Exists(rtl::OUString const & url) {
352 : 396 : rtl::OUString pathname;
353 [ + - ][ + - ]: 396 : if (utl::LocalFileHelper::ConvertURLToPhysicalName(url, pathname)) {
354 : : // Try to create a directory entry for the given URL:
355 : 396 : rtl::OUString url2;
356 [ + - ][ + - ]: 396 : if (osl::FileBase::getFileURLFromSystemPath(pathname, url2)
357 : : == osl::FileBase::E_None)
358 : : {
359 : : // #106526 osl_getDirectoryItem is an existence check, no further
360 : : // osl_getFileStatus call necessary:
361 : 396 : osl::DirectoryItem item;
362 [ + - ][ + - ]: 396 : return osl::DirectoryItem::get(url2, item) == osl::FileBase::E_None;
363 : : } else {
364 : 0 : return false;
365 : 396 : }
366 : : } else {
367 : : // Divide URL into folder and name part:
368 [ # # ]: 0 : INetURLObject o(url);
369 : : rtl::OUString name(
370 : : o.getName(
371 : : INetURLObject::LAST_SEGMENT, true,
372 [ # # ]: 0 : INetURLObject::DECODE_WITH_CHARSET));
373 [ # # ]: 0 : o.removeSegment();
374 [ # # ]: 0 : o.removeFinalSlash();
375 : : std::vector<rtl::OUString> cs(
376 [ # # ][ # # ]: 0 : getContents(o.GetMainURL(INetURLObject::NO_DECODE)));
377 [ # # ][ # # ]: 0 : for (std::vector<rtl::OUString>::iterator i(cs.begin()); i != cs.end();
378 : : ++i)
379 : : {
380 [ # # ]: 0 : if (INetURLObject(*i).getName(
381 : : INetURLObject::LAST_SEGMENT, true,
382 : : INetURLObject::DECODE_WITH_CHARSET).
383 [ # # ][ # # ]: 0 : equalsIgnoreAsciiCase(name))
[ # # ]
384 : : {
385 : 0 : return true;
386 : : }
387 : : }
388 [ # # ]: 0 : return false;
389 : 396 : }
390 : : }
391 : :
392 : 0 : bool utl::UCBContentHelper::IsSubPath(
393 : : rtl::OUString const & parent, rtl::OUString const & child)
394 : : {
395 : : // The comparison is done in the following way:
396 : : // - First, compare case sensitively
397 : : // - If names are different, try a fallback comparing case insensitively
398 : : // - If the last comparison succeeded, get case preserving normalized names
399 : : // for the files and compare them
400 : : // (The second step is required because retrieving the normalized names
401 : : // might be very expensive in some cases.)
402 [ # # ]: 0 : INetURLObject candidate(child);
403 [ # # ]: 0 : INetURLObject folder(parent);
404 [ # # ]: 0 : if (candidate.GetProtocol() != folder.GetProtocol()) {
405 : 0 : return false;
406 : : }
407 [ # # ]: 0 : INetURLObject candidateLower(child.toAsciiLowerCase());
408 [ # # ]: 0 : INetURLObject folderLower(parent.toAsciiLowerCase());
409 : : try {
410 [ # # ]: 0 : INetURLObject tmp;
411 [ # # ][ # # ]: 0 : do {
[ # # ][ # # ]
412 [ # # ]: 0 : if (candidate == folder
[ # # # # ]
[ # # # # ]
[ # # ]
413 : 0 : || (candidate.GetProtocol() == INET_PROT_FILE
414 [ # # ]: 0 : && candidateLower == folderLower
415 : : && (getCasePreservingUrl(candidate)
416 [ # # ][ # # ]: 0 : == getCasePreservingUrl(folder))))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # #
# # # # ]
417 : : {
418 : 0 : return true;
419 : : }
420 [ # # ]: 0 : tmp = candidate;
421 [ # # ][ # # ]: 0 : } while (candidate.removeSegment() && candidateLower.removeSegment()
422 [ # # ][ # # ]: 0 : && candidate != tmp);
[ # # ]
423 : : // INetURLObject::removeSegment sometimes returns true without
424 : : // modifying the URL, e.g., in case of "file:///"
425 : 0 : } catch (css::uno::RuntimeException const &) {
426 : 0 : throw;
427 : 0 : } catch (css::ucb::CommandAbortedException const &) {
428 : : assert(false); // this cannot happen
429 : 0 : throw;
430 [ # # # # : 0 : } catch (css::uno::Exception const &) {
# # ]
431 [ # # ]: 0 : css::uno::Any e(cppu::getCaughtException());
432 : : SAL_INFO(
433 : : "unotools",
434 : : "UCBContentHelper::IsSubPath(" << parent << ", " << child << ") "
435 : : << e.getValueType().getTypeName() << " \""
436 : 0 : << e.get<css::uno::Exception>().Message << '"');
437 : : }
438 [ # # ][ # # ]: 0 : return false;
[ # # ][ # # ]
439 : : }
440 : :
441 : 2255 : bool utl::UCBContentHelper::EqualURLs(
442 : : rtl::OUString const & url1, rtl::OUString const & url2)
443 : : {
444 [ + + ][ - + ]: 2255 : if (url1.isEmpty() || url2.isEmpty()) {
[ + + ]
445 : 29 : return false;
446 : : }
447 : 2226 : ucbhelper::ContentBroker * broker = ucbhelper::ContentBroker::get();
448 [ - + ]: 2226 : if (broker == 0) {
449 : : throw css::uno::RuntimeException(
450 : : rtl::OUString( "no ucbhelper::ContentBroker"),
451 [ # # ]: 0 : css::uno::Reference<css::uno::XInterface>());
452 : : }
453 : : return
454 [ + - ]: 4481 : broker->getContentProviderInterface()->compareContentIds(
455 [ + - ][ + - ]: 4452 : (broker->getContentIdentifierFactoryInterface()->
456 : 2226 : createContentIdentifier(canonic(url1))),
457 [ + - ][ + - ]: 4452 : (broker->getContentIdentifierFactoryInterface()->
458 [ + - ][ + - ]: 6678 : createContentIdentifier(canonic(url2))))
[ + - ][ + - ]
[ + - ]
459 : 2226 : == 0;
460 : : }
461 : :
462 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|