/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace com::sun::star::ucb { class XProgressHandler; } namespace com::sun::star::uno { class XComponentContext; } namespace com::sun::star::util { struct DateTime; } namespace { OUString canonic(OUString const & url) { INetURLObject o(url); SAL_WARN_IF(o.HasError(), "unotools.ucbhelper", "Invalid URL \"" << url << '"'); return o.GetMainURL(INetURLObject::DecodeMechanism::NONE); } ucbhelper::Content content(OUString const & url) { return ucbhelper::Content( canonic(url), utl::UCBContentHelper::getDefaultCommandEnvironment(), comphelper::getProcessComponentContext()); } ucbhelper::Content content(INetURLObject const & url) { return ucbhelper::Content( url.GetMainURL(INetURLObject::DecodeMechanism::NONE), utl::UCBContentHelper::getDefaultCommandEnvironment(), comphelper::getProcessComponentContext()); } std::vector getContents(OUString const & url) { try { std::vector cs; ucbhelper::Content c(content(url)); css::uno::Sequence args { "Title" }; css::uno::Reference res( c.createCursor(args), css::uno::UNO_SET_THROW); css::uno::Reference acc( res, css::uno::UNO_QUERY_THROW); while (res->next()) { cs.push_back(acc->queryContentIdentifierString()); } return cs; } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "getContents(" << url << ")"); return std::vector(); } } OUString getCasePreservingUrl(const INetURLObject& url) { return content(url).executeCommand( "getCasePreservingURL", css::uno::Any()). get(); } DateTime convert(css::util::DateTime const & dt) { return DateTime(dt); } } css::uno::Reference< css::ucb::XCommandEnvironment > utl::UCBContentHelper::getDefaultCommandEnvironment() { css::uno::Reference< css::task::XInteractionHandler > xIH( css::task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr ) ); css::uno::Reference< css::ucb::XProgressHandler > xProgress; rtl::Reference pCommandEnv = new ::ucbhelper::CommandEnvironment( new comphelper::SimpleFileAccessInteraction( xIH ), xProgress ); return pCommandEnv; } bool utl::UCBContentHelper::IsDocument(OUString const & url) { try { return content(url).isDocument(); } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::IsDocument(" << url << ")"); return false; } } css::uno::Any utl::UCBContentHelper::GetProperty( OUString const & url, OUString const & property) { try { return content(url).getPropertyValue(property); } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::GetProperty(" << url << ", " << property << ")"); return css::uno::Any(); } } bool utl::UCBContentHelper::IsFolder(OUString const & url) { try { return content(url).isFolder(); } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::IsFolder(" << url << ")"); return false; } } bool utl::UCBContentHelper::GetTitle( OUString const & url, OUString * title) { assert(title != nullptr); try { return content(url).getPropertyValue("Title") >>= *title; } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::GetTitle(" << url << ")"); return false; } } bool utl::UCBContentHelper::Kill(OUString const & url) { try { content(url).executeCommand( "delete", css::uno::Any(true)); return true; } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION("unotools.ucbhelper", "UCBContentHelper::Kill(" << url << ")"); return false; } } bool utl::UCBContentHelper::MakeFolder( ucbhelper::Content & parent, OUString const & title, ucbhelper::Content & result) { bool exists = false; try { const css::uno::Sequence info( parent.queryCreatableContentsInfo()); for (const auto& rInfo : info) { // Simply look for the first KIND_FOLDER: if ((rInfo.Attributes & css::ucb::ContentInfoAttribute::KIND_FOLDER) != 0) { // Make sure the only required bootstrap property is "Title": if ( rInfo.Properties.getLength() != 1 || rInfo.Properties[0].Name != "Title" ) { continue; } if (parent.insertNewContent(rInfo.Type, { "Title" }, { css::uno::Any(title) }, result)) { return true; } } } } catch (css::ucb::InteractiveIOException const & e) { if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) { exists = true; } else { TOOLS_INFO_EXCEPTION( "unotools.ucbhelper", "UCBContentHelper::MakeFolder(" << title << ")"); } } catch (css::ucb::NameClashException const &) { exists = true; } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION( "unotools.ucbhelper", "UCBContentHelper::MakeFolder(" << title << ") "); } if (exists) { INetURLObject o(parent.getURL()); o.Append(title); result = content(o); return true; } else { return false; } } bool utl::UCBContentHelper::IsYounger( OUString const & younger, OUString const & older) { try { return convert( content(younger).getPropertyValue( "DateModified"). get()) > convert( content(older).getPropertyValue( "DateModified"). get()); } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION( "unotools.ucbhelper", "UCBContentHelper::IsYounger(" << younger << ", " << older << ")"); return false; } } bool utl::UCBContentHelper::Exists(OUString const & url) { OUString pathname; if (osl::FileBase::getSystemPathFromFileURL(url, pathname) == osl::FileBase::E_None) { // Try to create a directory entry for the given URL: OUString url2; if (osl::FileBase::getFileURLFromSystemPath(pathname, url2) == osl::FileBase::E_None) { // #106526 osl_getDirectoryItem is an existence check, no further // osl_getFileStatus call necessary: osl::DirectoryItem item; return osl::DirectoryItem::get(url2, item) == osl::FileBase::E_None; } else { return false; } } else { // Divide URL into folder and name part: INetURLObject o(url); OUString name( o.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset)); o.removeSegment(); o.removeFinalSlash(); std::vector cs( getContents(o.GetMainURL(INetURLObject::DecodeMechanism::NONE))); return std::any_of(cs.begin(), cs.end(), [&name](const OUString& rItem) { return INetURLObject(rItem). getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset). equalsIgnoreAsciiCase(name); }); } } bool utl::UCBContentHelper::IsSubPath( OUString const & parent, OUString const & child) { // The comparison is done in the following way: // - First, compare case sensitively // - If names are different, try a fallback comparing case insensitively // - If the last comparison succeeded, get case preserving normalized names // for the files and compare them // (The second step is required because retrieving the normalized names // might be very expensive in some cases.) INetURLObject candidate(child); INetURLObject folder(parent); if (candidate.GetProtocol() != folder.GetProtocol()) { return false; } INetURLObject candidateLower(child.toAsciiLowerCase()); INetURLObject folderLower(parent.toAsciiLowerCase()); try { INetURLObject tmp; do { if (candidate == folder || (candidate.GetProtocol() == INetProtocol::File && candidateLower == folderLower && (getCasePreservingUrl(candidate) == getCasePreservingUrl(folder)))) { return true; } tmp = candidate; } while (candidate.removeSegment() && candidateLower.removeSegment() && candidate != tmp); // INetURLObject::removeSegment sometimes returns true without // modifying the URL, e.g., in case of "file:///" } catch (css::uno::RuntimeException const &) { throw; } catch (css::ucb::CommandAbortedException const &) { assert(false && "this cannot happen"); throw; } catch (css::uno::Exception const &) { TOOLS_INFO_EXCEPTION( "unotools.ucbhelper", "UCBContentHelper::IsSubPath(" << parent << ", " << child << ")"); } return false; } bool utl::UCBContentHelper::EqualURLs( OUString const & url1, OUString const & url2) { if (url1.isEmpty() || url2.isEmpty()) { return false; } css::uno::Reference< css::ucb::XUniversalContentBroker > ucb( css::ucb::UniversalContentBroker::create( comphelper::getProcessComponentContext())); return ucb->compareContentIds( ucb->createContentIdentifier(canonic(url1)), ucb->createContentIdentifier(canonic(url2))) == 0; } bool utl::UCBContentHelper::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 { try { INetURLObject aURL( rFolder ); OUString aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); aURL.removeSegment(); ::ucbhelper::Content aParent; if ( ::ucbhelper::Content::create( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, xCtx, aParent ) ) { return ::utl::UCBContentHelper::MakeFolder(aParent, aTitle, result); } } catch (...) { } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */