cid#1607171 Data race condition
[LibreOffice.git] / ucb / source / ucp / gio / gio_content.cxx
blob7a5b910a073e482395f4322015bdcb4afbf177f3
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 <rtl/uri.hxx>
23 #include <utility>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sal/macros.h>
28 #include <osl/time.h>
29 #include <sal/log.hxx>
31 #include <com/sun/star/beans/IllegalTypeException.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/beans/XPropertySetInfo.hpp>
35 #include <com/sun/star/io/IOException.hpp>
36 #include <com/sun/star/io/XActiveDataSink.hpp>
37 #include <com/sun/star/io/XOutputStream.hpp>
38 #include <com/sun/star/lang/IllegalAccessException.hpp>
39 #include <com/sun/star/lang/IllegalArgumentException.hpp>
40 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
41 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
42 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
43 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
44 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
45 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
46 #include <com/sun/star/ucb/NameClashException.hpp>
47 #include <com/sun/star/ucb/OpenMode.hpp>
48 #include <com/sun/star/ucb/XCommandInfo.hpp>
49 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
50 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
51 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
52 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
53 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
54 #include <com/sun/star/ucb/XContentCreator.hpp>
56 #include <comphelper/seekableinput.hxx>
57 #include <cppuhelper/exc_hlp.hxx>
58 #include <cppuhelper/queryinterface.hxx>
59 #include <ucbhelper/contentidentifier.hxx>
60 #include <ucbhelper/propertyvalueset.hxx>
61 #include <ucbhelper/cancelcommandexecution.hxx>
62 #include <ucbhelper/macros.hxx>
63 #include <vcl/svapp.hxx>
65 #include "gio_content.hxx"
66 #include "gio_provider.hxx"
67 #include "gio_resultset.hxx"
68 #include "gio_inputstream.hxx"
69 #include "gio_outputstream.hxx"
70 #include "gio_mount.hxx"
72 namespace gio
75 Content::Content(
76 const css::uno::Reference< css::uno::XComponentContext >& rxContext,
77 ContentProvider* pProvider,
78 const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier)
79 : ContentImplHelper( rxContext, pProvider, Identifier ),
80 m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(false)
82 SAL_INFO("ucb.ucp.gio", "New Content ('" << m_xIdentifier->getContentIdentifier() << "')");
85 Content::Content(
86 const css::uno::Reference< css::uno::XComponentContext >& rxContext,
87 ContentProvider* pProvider,
88 const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier,
89 bool bIsFolder)
90 : ContentImplHelper( rxContext, pProvider, Identifier ),
91 m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(true)
93 SAL_INFO("ucb.ucp.gio", "Create Content ('" << m_xIdentifier->getContentIdentifier() << "')");
94 mpInfo = g_file_info_new();
95 g_file_info_set_file_type(mpInfo, bIsFolder ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR);
98 Content::~Content()
100 if (mpInfo) g_object_unref(mpInfo);
101 if (mpFile) g_object_unref(mpFile);
104 OUString Content::getParentURL()
106 OUString sURL;
107 if (GFile* pFile = g_file_get_parent(getGFile()))
109 char* pPath = g_file_get_uri(pFile);
110 g_object_unref(pFile);
111 sURL = OUString::createFromAscii(pPath);
112 g_free(pPath);
114 return sURL;
117 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
119 //TODO
120 //stick a map from each CommandId to a new GCancellable and propagate
121 //it throughout the g_file_* calls
124 OUString SAL_CALL Content::getContentType()
126 return isFolder(css::uno::Reference< css::ucb::XCommandEnvironment >())
127 ? GIO_FOLDER_TYPE
128 : GIO_FILE_TYPE;
131 #define EXCEPT(aExcept) \
132 do { \
133 if (bThrow) throw aExcept;\
134 aRet <<= aExcept;\
135 } while(false)
137 css::uno::Any convertToException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext, bool bThrow)
139 css::uno::Any aRet;
141 gint eCode = pError->code;
142 OUString sMessage(pError->message, strlen(pError->message), RTL_TEXTENCODING_UTF8);
143 g_error_free(pError);
145 OUString sName;
147 css::uno::Sequence< css::uno::Any > aArgs{ css::uno::Any(sName) };
149 switch (eCode)
151 case G_IO_ERROR_FAILED:
152 { css::io::IOException aExcept(sMessage, rContext);
153 EXCEPT(aExcept); }
154 break;
155 case G_IO_ERROR_NOT_MOUNTED:
156 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
157 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING_PATH, aArgs);
158 EXCEPT(aExcept); }
159 break;
160 case G_IO_ERROR_NOT_FOUND:
161 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
162 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING, aArgs);
163 EXCEPT(aExcept); }
164 break;
165 case G_IO_ERROR_EXISTS:
166 { css::ucb::NameClashException aExcept(sMessage, rContext,
167 css::task::InteractionClassification_ERROR, sName);
168 EXCEPT(aExcept); }
169 break;
170 case G_IO_ERROR_INVALID_ARGUMENT:
171 { css::lang::IllegalArgumentException aExcept(sMessage, rContext, -1 );
172 EXCEPT(aExcept); }
173 break;
174 case G_IO_ERROR_PERMISSION_DENIED:
175 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
176 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_ACCESS_DENIED, aArgs);
177 EXCEPT(aExcept); }
178 break;
179 case G_IO_ERROR_IS_DIRECTORY:
180 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
181 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
182 EXCEPT(aExcept); }
183 break;
184 case G_IO_ERROR_NOT_REGULAR_FILE:
185 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
186 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
187 EXCEPT(aExcept); }
188 break;
189 case G_IO_ERROR_NOT_DIRECTORY:
190 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
191 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_DIRECTORY, aArgs);
192 EXCEPT(aExcept); }
193 break;
194 case G_IO_ERROR_FILENAME_TOO_LONG:
195 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
196 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NAME_TOO_LONG, aArgs);
197 EXCEPT(aExcept); }
198 break;
199 case G_IO_ERROR_FAILED_HANDLED: /* Operation failed and a helper program
200 has already interacted with the user. Do not display any error
201 dialog */
202 case G_IO_ERROR_PENDING:
203 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
204 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_PENDING, aArgs);
205 EXCEPT(aExcept); }
206 break;
207 case G_IO_ERROR_CLOSED:
208 case G_IO_ERROR_CANCELLED:
209 case G_IO_ERROR_TOO_MANY_LINKS:
210 case G_IO_ERROR_WRONG_ETAG:
211 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
212 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_GENERAL, aArgs);
213 EXCEPT(aExcept); }
214 break;
215 case G_IO_ERROR_NOT_SUPPORTED:
216 case G_IO_ERROR_CANT_CREATE_BACKUP:
217 case G_IO_ERROR_WOULD_MERGE:
218 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
219 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_SUPPORTED, aArgs);
220 EXCEPT(aExcept); }
221 break;
222 case G_IO_ERROR_NO_SPACE:
223 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
224 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_OUT_OF_DISK_SPACE, aArgs);
225 EXCEPT(aExcept); }
226 break;
227 case G_IO_ERROR_INVALID_FILENAME:
228 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
229 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_INVALID_CHARACTER, aArgs);
230 EXCEPT(aExcept); }
231 break;
232 case G_IO_ERROR_READ_ONLY:
233 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
234 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_WRITE_PROTECTED, aArgs);
235 EXCEPT(aExcept); }
236 break;
237 case G_IO_ERROR_TIMED_OUT:
238 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
239 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_DEVICE_NOT_READY, aArgs);
240 EXCEPT(aExcept); }
241 break;
242 case G_IO_ERROR_WOULD_RECURSE:
243 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
244 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_RECURSIVE, aArgs);
245 EXCEPT(aExcept); }
246 break;
247 case G_IO_ERROR_BUSY:
248 case G_IO_ERROR_WOULD_BLOCK:
249 { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
250 css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_LOCKING_VIOLATION, aArgs);
251 EXCEPT(aExcept); }
252 break;
253 case G_IO_ERROR_HOST_NOT_FOUND:
254 { css::ucb::InteractiveNetworkResolveNameException aExcept(sMessage, rContext,
255 css::task::InteractionClassification_ERROR, OUString());
256 EXCEPT(aExcept);}
257 break;
258 default:
259 case G_IO_ERROR_ALREADY_MOUNTED:
260 case G_IO_ERROR_NOT_EMPTY:
261 case G_IO_ERROR_NOT_SYMBOLIC_LINK:
262 case G_IO_ERROR_NOT_MOUNTABLE_FILE:
263 { css::ucb::InteractiveNetworkGeneralException aExcept(sMessage, rContext,
264 css::task::InteractionClassification_ERROR);
265 EXCEPT(aExcept);}
266 break;
268 return aRet;
271 void convertToIOException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext)
275 convertToException(pError, rContext);
277 catch (const css::io::IOException&)
279 throw;
281 catch (const css::uno::RuntimeException&)
283 throw;
285 catch (const css::uno::Exception& e)
287 css::uno::Any a(cppu::getCaughtException());
288 throw css::lang::WrappedTargetRuntimeException(
289 "wrapped Exception " + e.Message,
290 css::uno::Reference<css::uno::XInterface>(), a);
294 css::uno::Any Content::mapGIOError( GError *pError )
296 if (!pError)
297 return getBadArgExcept();
299 return convertToException(pError, getXWeak(), false);
302 css::uno::Any Content::getBadArgExcept()
304 return css::uno::Any( css::lang::IllegalArgumentException(
305 u"Wrong argument type!"_ustr,
306 getXWeak(), -1) );
309 namespace {
311 class MountOperation
313 ucb::ucp::gio::glib::MainContextRef mContext;
314 GMainLoop *mpLoop;
315 GMountOperation *mpAuthentication;
316 GError *mpError;
317 static void Completed(GObject *source, GAsyncResult *res, gpointer user_data);
318 public:
319 explicit MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv);
320 ~MountOperation();
321 GError *Mount(GFile *pFile);
326 MountOperation::MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv) : mpError(nullptr)
328 ucb::ucp::gio::glib::MainContextRef oldContext(g_main_context_ref_thread_default());
329 mContext.reset(g_main_context_new());
330 mpLoop = g_main_loop_new(mContext.get(), FALSE);
331 g_main_context_push_thread_default(mContext.get());
332 mpAuthentication = ooo_mount_operation_new(std::move(oldContext), xEnv);
335 void MountOperation::Completed(GObject *source, GAsyncResult *res, gpointer user_data)
337 MountOperation *pThis = static_cast<MountOperation*>(user_data);
338 g_file_mount_enclosing_volume_finish(G_FILE(source), res, &(pThis->mpError));
339 g_main_loop_quit(pThis->mpLoop);
342 GError *MountOperation::Mount(GFile *pFile)
344 g_file_mount_enclosing_volume(pFile, G_MOUNT_MOUNT_NONE, mpAuthentication, nullptr, MountOperation::Completed, this);
346 //HACK: At least the gdk_threads_set_lock_functions(GdkThreadsEnter,
347 // GdkThreadsLeave) call in vcl/unx/gtk/app/gtkinst.cxx will lead to
348 // GdkThreadsLeave unlock the SolarMutex down to zero at the end of
349 // g_main_loop_run, so we need ~SolarMutexReleaser to raise it back to
350 // the original value again:
351 if (comphelper::SolarMutex::get()->IsCurrentThread())
353 SolarMutexReleaser rel;
354 g_main_loop_run(mpLoop);
356 else
358 g_main_loop_run(mpLoop);
361 return mpError;
364 MountOperation::~MountOperation()
366 g_object_unref(mpAuthentication);
367 g_main_context_pop_thread_default(mContext.get());
368 g_main_loop_unref(mpLoop);
371 GFileInfo* Content::getGFileInfo(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv, GError **ppError)
373 GError * err = nullptr;
374 if (mpInfo == nullptr && !mbTransient) {
375 for (bool retried = false;; retried = true) {
376 mpInfo = g_file_query_info(
377 getGFile(), "*", G_FILE_QUERY_INFO_NONE, nullptr, &err);
378 if (mpInfo != nullptr) {
379 break;
381 assert(err != nullptr);
382 if (err->code != G_IO_ERROR_NOT_MOUNTED || retried) {
383 break;
385 SAL_INFO(
386 "ucb.ucp.gio",
387 "G_IO_ERROR_NOT_MOUNTED \"" << err->message
388 << "\", trying to mount");
389 g_error_free(err);
390 err = MountOperation(xEnv).Mount(getGFile());
391 if (err != nullptr) {
392 break;
396 if (ppError != nullptr) {
397 *ppError = err;
398 } else if (err != nullptr) {
399 SAL_WARN(
400 "ucb.ucp.gio",
401 "ignoring GError \"" << err->message << "\" for <"
402 << m_xIdentifier->getContentIdentifier() << ">");
403 g_error_free(err);
405 return mpInfo;
408 GFile* Content::getGFile()
410 if (!mpFile)
411 mpFile = g_file_new_for_uri(OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
412 return mpFile;
415 bool Content::isFolder(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
417 GFileInfo *pInfo = getGFileInfo(xEnv);
418 return pInfo && (g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY);
421 static css::util::DateTime getDateFromUnix (time_t t)
423 TimeValue tv;
424 tv.Nanosec = 0;
425 // coverity[store_truncates_time_t] - TODO: sal_uInt32 TimeValue::Seconds is only large enough
426 // for integer time_t values < 2^32 representing dates until year 2106:
427 tv.Seconds = t;
428 oslDateTime dt;
430 if ( osl_getDateTimeFromTimeValue( &tv, &dt ) )
431 return css::util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours,
432 dt.Day, dt.Month, dt.Year, false);
433 else
434 return css::util::DateTime();
437 css::uno::Reference< css::sdbc::XRow > Content::getPropertyValues(
438 const css::uno::Sequence< css::beans::Property >& rProperties,
439 const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
441 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
443 GFileInfo *pInfo = nullptr;
444 for( const css::beans::Property& rProp : rProperties )
446 if ( rProp.Name == "IsDocument" )
448 getFileInfo(xEnv, &pInfo, true);
449 if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE))
450 xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_REGULAR ||
451 g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_UNKNOWN ) );
452 else
453 xRow->appendVoid( rProp );
455 else if ( rProp.Name == "IsFolder" )
457 getFileInfo(xEnv, &pInfo, true);
458 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) )
459 xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_DIRECTORY ));
460 else
461 xRow->appendVoid( rProp );
463 else if ( rProp.Name == "Title" )
465 getFileInfo(xEnv, &pInfo, false);
466 if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
468 const char *pName = g_file_info_get_display_name(pInfo);
469 xRow->appendString( rProp, OUString(pName, strlen(pName), RTL_TEXTENCODING_UTF8) );
471 else
472 xRow->appendVoid(rProp);
474 else if ( rProp.Name == "IsReadOnly" )
476 getFileInfo(xEnv, &pInfo, true);
477 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE ) )
478 xRow->appendBoolean( rProp, !g_file_info_get_attribute_boolean( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE) );
479 else
480 xRow->appendVoid( rProp );
482 else if ( rProp.Name == "DateCreated" )
484 getFileInfo(xEnv, &pInfo, true);
485 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CREATED ) )
486 xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CREATED)) );
487 else
488 xRow->appendVoid( rProp );
490 else if ( rProp.Name == "DateModified" )
492 getFileInfo(xEnv, &pInfo, true);
493 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED ) )
494 xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED)) );
495 else
496 xRow->appendVoid( rProp );
498 else if ( rProp.Name == "Size" )
500 getFileInfo(xEnv, &pInfo, true);
501 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_SIZE) )
502 xRow->appendLong( rProp, ( g_file_info_get_size( pInfo ) ));
503 else
504 xRow->appendVoid( rProp );
506 else if ( rProp.Name == "IsVolume" )
508 //What do we use this for ?
509 xRow->appendBoolean( rProp, false );
511 else if ( rProp.Name == "IsCompactDisc" )
513 getFileInfo(xEnv, &pInfo, true);
514 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT ) )
515 xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT) );
516 else
517 xRow->appendVoid( rProp );
519 else if ( rProp.Name == "IsRemoveable" )
521 getFileInfo(xEnv, &pInfo, true);
522 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) )
523 xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) );
524 else
525 xRow->appendVoid( rProp );
527 else if ( rProp.Name == "IsFloppy" )
529 xRow->appendBoolean( rProp, false );
531 else if ( rProp.Name == "IsHidden" )
533 getFileInfo(xEnv, &pInfo, true);
534 if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) )
535 xRow->appendBoolean( rProp, ( g_file_info_get_is_hidden ( pInfo ) ) );
536 else
537 xRow->appendVoid( rProp );
539 else if ( rProp.Name == "CreatableContentsInfo" )
541 xRow->appendObject( rProp, css::uno::Any( queryCreatableContentsInfo( xEnv ) ) );
543 else
545 SAL_WARN(
546 "ucb.ucp.gio",
547 "Looking for unsupported property " << rProp.Name);
548 xRow->appendVoid(rProp);
552 return xRow;
555 static css::lang::IllegalAccessException
556 getReadOnlyException( const css::uno::Reference< css::uno::XInterface >& rContext )
558 return css::lang::IllegalAccessException (u"Property is read-only!"_ustr, rContext );
561 void Content::queryChildren( ContentRefList& rChildren )
563 // Obtain a list with a snapshot of all currently instantiated contents
564 // from provider and extract the contents which are direct children
565 // of this content.
567 ucbhelper::ContentRefList aAllContents;
568 m_xProvider->queryExistingContents( aAllContents );
570 OUString aURL = m_xIdentifier->getContentIdentifier();
571 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
573 if ( nURLPos != ( aURL.getLength() - 1 ) )
574 aURL += "/";
576 sal_Int32 nLen = aURL.getLength();
578 for ( const auto& rContent : aAllContents )
580 ucbhelper::ContentImplHelperRef xChild = rContent;
581 OUString aChildURL = xChild->getIdentifier()->getContentIdentifier();
583 // Is aURL a prefix of aChildURL?
584 if ( ( aChildURL.getLength() > nLen ) && aChildURL.startsWith( aURL ) )
586 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
588 if ( ( nPos == -1 ) || ( nPos == ( aChildURL.getLength() - 1 ) ) )
590 // No further slashes / only a final slash. It's a child!
591 rChildren.emplace_back(static_cast< ::gio::Content * >(xChild.get() ) );
597 bool Content::exchangeIdentity( const css::uno::Reference< css::ucb::XContentIdentifier >& xNewId )
599 if ( !xNewId.is() )
600 return false;
602 css::uno::Reference< css::ucb::XContent > xThis = this;
604 if ( mbTransient )
606 m_xIdentifier = xNewId;
607 return false;
610 OUString aOldURL = m_xIdentifier->getContentIdentifier();
612 // Exchange own identity.
613 if ( exchange( xNewId ) )
615 // Process instantiated children...
616 ContentRefList aChildren;
617 queryChildren( aChildren );
619 for ( const auto& rChild : aChildren )
621 ContentRef xChild = rChild;
623 // Create new content identifier for the child...
624 css::uno::Reference< css::ucb::XContentIdentifier > xOldChildId = xChild->getIdentifier();
625 OUString aOldChildURL = xOldChildId->getContentIdentifier();
626 OUString aNewChildURL = aOldChildURL.replaceAt(
627 0, aOldURL.getLength(), xNewId->getContentIdentifier() );
629 css::uno::Reference< css::ucb::XContentIdentifier > xNewChildId
630 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
632 if ( !xChild->exchangeIdentity( xNewChildId ) )
633 return false;
635 return true;
638 return false;
641 void Content::getFileInfo(
642 css::uno::Reference<css::ucb::XCommandEnvironment> const & env, GFileInfo ** info, bool fail)
644 assert(info != nullptr);
645 if (*info != nullptr)
646 return;
648 GError * err = nullptr;
649 *info = getGFileInfo(env, &err);
650 if (*info == nullptr && !mbTransient && fail)
652 ucbhelper::cancelCommandExecution(mapGIOError(err), env);
654 else if (err != nullptr)
656 g_error_free(err);
660 css::uno::Sequence< css::uno::Any > Content::setPropertyValues(
661 const css::uno::Sequence< css::beans::PropertyValue >& rValues,
662 const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
664 GError *pError=nullptr;
665 GFileInfo *pNewInfo=nullptr;
666 GFileInfo *pInfo = getGFileInfo(xEnv, &pError);
667 if (pInfo)
668 pNewInfo = g_file_info_dup(pInfo);
669 else
671 if (!mbTransient)
672 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
673 else
675 if (pError)
676 g_error_free(pError);
677 pNewInfo = g_file_info_new();
681 sal_Int32 nCount = rValues.getLength();
683 css::beans::PropertyChangeEvent aEvent;
684 aEvent.Source = getXWeak();
685 aEvent.Further = false;
686 aEvent.PropertyHandle = -1;
688 sal_Int32 nChanged = 0, nTitlePos = -1;
689 OUString aNewTitle;
690 css::uno::Sequence< css::beans::PropertyChangeEvent > aChanges(nCount);
691 auto aChangesRange = asNonConstRange(aChanges);
693 css::uno::Sequence< css::uno::Any > aRet( nCount );
694 auto aRetRange = asNonConstRange(aRet);
695 const css::beans::PropertyValue* pValues = rValues.getConstArray();
696 for ( sal_Int32 n = 0; n < nCount; ++n )
698 const css::beans::PropertyValue& rValue = pValues[ n ];
699 SAL_INFO("ucb.ucp.gio", "Set prop '" << rValue.Name << "'");
700 if ( rValue.Name == "ContentType" ||
701 rValue.Name == "MediaType" ||
702 rValue.Name == "IsDocument" ||
703 rValue.Name == "IsFolder" ||
704 rValue.Name == "Size" ||
705 rValue.Name == "CreatableContentsInfo" )
707 aRetRange[ n ] <<= getReadOnlyException( getXWeak() );
709 else if ( rValue.Name == "Title" )
711 if (!( rValue.Value >>= aNewTitle ))
713 aRetRange[ n ] <<= css::beans::IllegalTypeException
714 ( u"Property value has wrong type!"_ustr,
715 getXWeak() );
716 continue;
719 if ( aNewTitle.isEmpty() )
721 aRetRange[ n ] <<= css::lang::IllegalArgumentException
722 ( u"Empty title not allowed!"_ustr,
723 getXWeak(), -1 );
724 continue;
728 OString sNewTitle = OUStringToOString(aNewTitle, RTL_TEXTENCODING_UTF8);
729 const char *newName = sNewTitle.getStr();
730 const char *oldName = g_file_info_get_name( pInfo);
732 if (!newName || !oldName || strcmp(newName, oldName))
734 SAL_INFO("ucb.ucp.gio", "Set new name to '" << newName << "'");
736 aEvent.PropertyName = "Title";
737 if (oldName)
738 aEvent.OldValue <<= OUString(oldName, strlen(oldName), RTL_TEXTENCODING_UTF8);
739 aEvent.NewValue <<= aNewTitle;
740 aChangesRange[ nChanged ] = aEvent;
741 nTitlePos = nChanged++;
743 g_file_info_set_name(pNewInfo, newName);
746 else
748 SAL_WARN("ucb.ucp.gio", "Unknown property " << rValue.Name);
749 aRetRange[ n ] <<= getReadOnlyException( getXWeak() );
753 if (nChanged)
755 bool bOk = true;
756 if (!mbTransient)
758 if ((bOk = doSetFileInfo(pNewInfo)))
760 for (sal_Int32 i = 0; i < nChanged; ++i)
761 aRetRange[ i ] = getBadArgExcept();
765 if (bOk)
767 if (nTitlePos > -1)
769 OUString aNewURL = getParentURL();
770 if (!aNewURL.isEmpty() && aNewURL[aNewURL.getLength() - 1] != '/')
771 aNewURL += "/";
772 aNewURL += aNewTitle;
774 css::uno::Reference< css::ucb::XContentIdentifier > xNewId
775 = new ::ucbhelper::ContentIdentifier( aNewURL );
777 if (!exchangeIdentity( xNewId ) )
779 aRetRange[ nTitlePos ] <<= css::uno::Exception
780 ( u"Exchange failed!"_ustr,
781 getXWeak() );
785 if (!mbTransient) //Discard and refetch
787 g_object_unref(mpInfo);
788 mpInfo = nullptr;
791 if (mpInfo)
793 g_file_info_copy_into(pNewInfo, mpInfo);
794 g_object_unref(pNewInfo);
796 else
797 mpInfo = pNewInfo;
799 pNewInfo = nullptr;
801 if (mpFile) //Discard and refetch
803 g_object_unref(mpFile);
804 mpFile = nullptr;
808 aChanges.realloc( nChanged );
809 notifyPropertiesChange( aChanges );
812 if (pNewInfo)
813 g_object_unref(pNewInfo);
815 return aRet;
818 bool Content::doSetFileInfo(GFileInfo *pNewInfo)
820 g_assert (!mbTransient);
822 bool bOk = true;
823 GFile *pFile = getGFile();
824 if(!g_file_set_attributes_from_info(pFile, pNewInfo, G_FILE_QUERY_INFO_NONE, nullptr, nullptr))
825 bOk = false;
826 return bOk;
829 const int TRANSFER_BUFFER_SIZE = 65536;
831 void Content::copyData( const css::uno::Reference< css::io::XInputStream >& xIn,
832 const css::uno::Reference< css::io::XOutputStream >& xOut )
834 css::uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
836 g_return_if_fail( xIn.is() && xOut.is() );
838 while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
839 xOut->writeBytes( theData );
841 xOut->closeOutput();
844 bool Content::feedSink( const css::uno::Reference< css::uno::XInterface >& xSink )
846 if ( !xSink.is() )
847 return false;
849 css::uno::Reference< css::io::XOutputStream > xOut(xSink, css::uno::UNO_QUERY );
850 css::uno::Reference< css::io::XActiveDataSink > xDataSink(xSink, css::uno::UNO_QUERY );
852 if ( !xOut.is() && !xDataSink.is() )
853 return false;
855 GError *pError=nullptr;
856 GFileInputStream *pStream = g_file_read(getGFile(), nullptr, &pError);
857 if (!pStream)
858 convertToException(pError, getXWeak());
860 css::uno::Reference< css::io::XInputStream > xIn(
861 new comphelper::OSeekableInputWrapper(
862 new ::gio::InputStream(pStream), m_xContext));
864 if ( xOut.is() )
865 copyData( xIn, xOut );
867 if ( xDataSink.is() )
868 xDataSink->setInputStream( xIn );
870 return true;
873 css::uno::Any Content::open(const css::ucb::OpenCommandArgument2 & rOpenCommand,
874 const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv )
876 bool bIsFolder = isFolder(xEnv);
878 if (!g_file_query_exists(getGFile(), nullptr))
880 css::uno::Sequence< css::uno::Any > aArgs{ css::uno::Any(
881 m_xIdentifier->getContentIdentifier()) };
882 css::uno::Any aErr(
883 css::ucb::InteractiveAugmentedIOException(OUString(), getXWeak(),
884 css::task::InteractionClassification_ERROR,
885 bIsFolder ? css::ucb::IOErrorCode_NOT_EXISTING_PATH : css::ucb::IOErrorCode_NOT_EXISTING, aArgs)
888 ucbhelper::cancelCommandExecution(aErr, xEnv);
891 css::uno::Any aRet;
893 bool bOpenFolder = (
894 ( rOpenCommand.Mode == css::ucb::OpenMode::ALL ) ||
895 ( rOpenCommand.Mode == css::ucb::OpenMode::FOLDERS ) ||
896 ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENTS )
899 if ( bOpenFolder && bIsFolder )
901 css::uno::Reference< css::ucb::XDynamicResultSet > xSet
902 = new DynamicResultSet( m_xContext, this, rOpenCommand, xEnv );
903 aRet <<= xSet;
905 else if ( rOpenCommand.Sink.is() )
907 if (
908 ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
909 ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
912 ucbhelper::cancelCommandExecution(
913 css::uno::Any ( css::ucb::UnsupportedOpenModeException
914 ( OUString(), getXWeak(),
915 sal_Int16( rOpenCommand.Mode ) ) ),
916 xEnv );
919 if ( !feedSink( rOpenCommand.Sink ) )
921 // Note: rOpenCommand.Sink may contain an XStream
922 // implementation. Support for this type of
923 // sink is optional...
924 SAL_WARN("ucb.ucp.gio", "Failed to load data from '" << m_xIdentifier->getContentIdentifier() << "'");
926 ucbhelper::cancelCommandExecution(
927 css::uno::Any (css::ucb::UnsupportedDataSinkException
928 ( OUString(), getXWeak(),
929 rOpenCommand.Sink ) ),
930 xEnv );
933 else
934 SAL_INFO("ucb.ucp.gio", "Open falling through ...");
935 return aRet;
938 css::uno::Any SAL_CALL Content::execute(
939 const css::ucb::Command& aCommand,
940 sal_Int32 /*CommandId*/,
941 const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
943 SAL_INFO("ucb.ucp.gio", "Content::execute " << aCommand.Name);
944 css::uno::Any aRet;
946 if ( aCommand.Name == "getPropertyValues" )
948 css::uno::Sequence< css::beans::Property > Properties;
949 if ( !( aCommand.Argument >>= Properties ) )
950 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
951 aRet <<= getPropertyValues( Properties, xEnv );
953 else if ( aCommand.Name == "getPropertySetInfo" )
954 aRet <<= getPropertySetInfo( xEnv, false );
955 else if ( aCommand.Name == "getCommandInfo" )
956 aRet <<= getCommandInfo( xEnv, false );
957 else if ( aCommand.Name == "open" )
959 css::ucb::OpenCommandArgument2 aOpenCommand;
960 if ( !( aCommand.Argument >>= aOpenCommand ) )
961 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
962 aRet = open( aOpenCommand, xEnv );
964 else if ( aCommand.Name == "transfer" )
966 css::ucb::TransferInfo transferArgs;
967 if ( !( aCommand.Argument >>= transferArgs ) )
968 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
969 transfer( transferArgs, xEnv );
971 else if ( aCommand.Name == "setPropertyValues" )
973 css::uno::Sequence< css::beans::PropertyValue > aProperties;
974 if ( !( aCommand.Argument >>= aProperties ) || !aProperties.hasElements() )
975 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
976 aRet <<= setPropertyValues( aProperties, xEnv );
978 else if (aCommand.Name == "createNewContent"
979 && isFolder( xEnv ) )
981 css::ucb::ContentInfo arg;
982 if ( !( aCommand.Argument >>= arg ) )
983 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
984 aRet <<= createNewContent( arg );
986 else if ( aCommand.Name == "insert" )
988 css::ucb::InsertCommandArgument arg;
989 if ( !( aCommand.Argument >>= arg ) )
990 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
991 insert( arg.Data, arg.ReplaceExisting, xEnv );
993 else if ( aCommand.Name == "delete" )
995 bool bDeletePhysical = false;
996 aCommand.Argument >>= bDeletePhysical;
998 //If no delete physical, try and trashcan it, if that doesn't work go
999 //ahead and try and delete it anyway
1000 if (!bDeletePhysical && !g_file_trash(getGFile(), nullptr, nullptr))
1001 bDeletePhysical = true;
1003 if (bDeletePhysical)
1005 GError *pError = nullptr;
1006 if (!g_file_delete( getGFile(), nullptr, &pError))
1007 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1010 destroy( bDeletePhysical );
1012 else
1014 SAL_WARN("ucb.ucp.gio", "Unknown command " << aCommand.Name);
1016 ucbhelper::cancelCommandExecution
1017 ( css::uno::Any( css::ucb::UnsupportedCommandException
1018 ( OUString(),
1019 getXWeak() ) ),
1020 xEnv );
1023 return aRet;
1026 void Content::destroy( bool bDeletePhysical )
1028 css::uno::Reference< css::ucb::XContent > xThis = this;
1030 deleted();
1032 ::gio::Content::ContentRefList aChildren;
1033 queryChildren( aChildren );
1035 for ( auto& rChild : aChildren )
1037 rChild->destroy( bDeletePhysical );
1041 void Content::insert(const css::uno::Reference< css::io::XInputStream > &xInputStream,
1042 bool bReplaceExisting, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv )
1044 GError *pError = nullptr;
1045 GFileInfo *pInfo = getGFileInfo(xEnv);
1047 if ( pInfo &&
1048 g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
1049 g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY )
1051 SAL_INFO("ucb.ucp.gio", "Make directory");
1052 if( !g_file_make_directory( getGFile(), nullptr, &pError))
1053 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1054 return;
1057 if ( !xInputStream.is() )
1059 ucbhelper::cancelCommandExecution( css::uno::Any
1060 ( css::ucb::MissingInputStreamException
1061 ( OUString(), getXWeak() ) ),
1062 xEnv );
1065 GFileOutputStream* pOutStream = nullptr;
1066 if ( bReplaceExisting )
1068 if (!(pOutStream = g_file_replace(getGFile(), nullptr, false, G_FILE_CREATE_PRIVATE, nullptr, &pError)))
1069 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1071 else
1073 if (!(pOutStream = g_file_create (getGFile(), G_FILE_CREATE_PRIVATE, nullptr, &pError)))
1074 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1077 css::uno::Reference < css::io::XOutputStream > xOutput = new ::gio::OutputStream(pOutStream);
1078 copyData( xInputStream, xOutput );
1080 if (mbTransient)
1082 mbTransient = false;
1083 inserted();
1087 const GFileCopyFlags DEFAULT_COPYDATA_FLAGS =
1088 static_cast<GFileCopyFlags>(G_FILE_COPY_OVERWRITE|G_FILE_COPY_TARGET_DEFAULT_PERMS);
1090 void Content::transfer( const css::ucb::TransferInfo& aTransferInfo, const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
1092 OUString sDest = m_xIdentifier->getContentIdentifier();
1093 if (!sDest.endsWith("/")) {
1094 sDest += "/";
1096 if (!aTransferInfo.NewTitle.isEmpty())
1098 sDest += rtl::Uri::encode( aTransferInfo.NewTitle,
1099 rtl_UriCharClassPchar,
1100 rtl_UriEncodeIgnoreEscapes,
1101 RTL_TEXTENCODING_UTF8 );
1103 else
1104 sDest += OUString::createFromAscii(g_file_get_basename(getGFile()));
1106 GFile *pDest = g_file_new_for_uri(OUStringToOString(sDest, RTL_TEXTENCODING_UTF8).getStr());
1107 GFile *pSource = g_file_new_for_uri(OUStringToOString(aTransferInfo.SourceURL, RTL_TEXTENCODING_UTF8).getStr());
1109 bool bSuccess = false;
1110 GError *pError = nullptr;
1111 if (aTransferInfo.MoveData)
1112 bSuccess = g_file_move(pSource, pDest, G_FILE_COPY_OVERWRITE, nullptr, nullptr, nullptr, &pError);
1113 else
1114 bSuccess = g_file_copy(pSource, pDest, DEFAULT_COPYDATA_FLAGS, nullptr, nullptr, nullptr, &pError);
1115 g_object_unref(pSource);
1116 g_object_unref(pDest);
1117 if (!bSuccess) {
1118 SAL_INFO(
1119 "ucb.ucp.gio",
1120 "transfer <" << aTransferInfo.SourceURL << "> to <" << sDest << "> (MoveData = "
1121 << int(aTransferInfo.MoveData) << ") failed with \"" << pError->message << "\"");
1122 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1126 css::uno::Sequence< css::ucb::ContentInfo > Content::queryCreatableContentsInfo(
1127 const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
1129 if ( isFolder( xEnv ) )
1132 // Minimum set of props we really need
1133 css::uno::Sequence< css::beans::Property > props
1135 { u"Title"_ustr, -1, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::BOUND }
1138 return
1140 { GIO_FILE_TYPE, ( css::ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | css::ucb::ContentInfoAttribute::KIND_DOCUMENT ), props },
1141 { GIO_FOLDER_TYPE, css::ucb::ContentInfoAttribute::KIND_FOLDER, props }
1144 else
1146 return {};
1150 css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1152 return queryCreatableContentsInfo( css::uno::Reference< css::ucb::XCommandEnvironment >() );
1155 css::uno::Reference< css::ucb::XContent >
1156 SAL_CALL Content::createNewContent( const css::ucb::ContentInfo& Info )
1158 bool create_document;
1159 const char *name;
1161 if ( Info.Type == GIO_FILE_TYPE )
1162 create_document = true;
1163 else if ( Info.Type == GIO_FOLDER_TYPE )
1164 create_document = false;
1165 else
1167 SAL_WARN("ucb.ucp.gio", "Failed to create new content '" << Info.Type << "'");
1168 return css::uno::Reference< css::ucb::XContent >();
1171 SAL_INFO("ucb.ucp.gio", "createNewContent (" << create_document << ")");
1172 OUString aURL = m_xIdentifier->getContentIdentifier();
1174 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1175 aURL += "/";
1177 name = create_document ? "[New_Content]" : "[New_Collection]";
1178 aURL += OUString::createFromAscii( name );
1180 css::uno::Reference< css::ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(aURL));
1184 return new ::gio::Content( m_xContext, m_pProvider, xId, !create_document );
1185 } catch ( css::ucb::ContentCreationException & )
1187 return css::uno::Reference< css::ucb::XContent >();
1191 css::uno::Sequence< css::uno::Type > SAL_CALL Content::getTypes()
1193 if ( isFolder( css::uno::Reference< css::ucb::XCommandEnvironment >() ) )
1195 static cppu::OTypeCollection s_aFolderCollection
1196 (CPPU_TYPE_REF( css::lang::XTypeProvider ),
1197 CPPU_TYPE_REF( css::lang::XServiceInfo ),
1198 CPPU_TYPE_REF( css::lang::XComponent ),
1199 CPPU_TYPE_REF( css::ucb::XContent ),
1200 CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
1201 CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
1202 CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
1203 CPPU_TYPE_REF( css::beans::XPropertyContainer ),
1204 CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
1205 CPPU_TYPE_REF( css::container::XChild ),
1206 CPPU_TYPE_REF( css::ucb::XContentCreator ) );
1207 return s_aFolderCollection.getTypes();
1209 else
1211 static cppu::OTypeCollection s_aFileCollection
1212 (CPPU_TYPE_REF( css::lang::XTypeProvider ),
1213 CPPU_TYPE_REF( css::lang::XServiceInfo ),
1214 CPPU_TYPE_REF( css::lang::XComponent ),
1215 CPPU_TYPE_REF( css::ucb::XContent ),
1216 CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
1217 CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
1218 CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
1219 CPPU_TYPE_REF( css::beans::XPropertyContainer ),
1220 CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
1221 CPPU_TYPE_REF( css::container::XChild ) );
1223 return s_aFileCollection.getTypes();
1227 css::uno::Sequence< css::beans::Property > Content::getProperties(
1228 const css::uno::Reference< css::ucb::XCommandEnvironment > & /*xEnv*/ )
1230 static const css::beans::Property aGenericProperties[] =
1232 css::beans::Property( u"IsDocument"_ustr,
1233 -1, cppu::UnoType<bool>::get(),
1234 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1235 css::beans::Property( u"IsFolder"_ustr,
1236 -1, cppu::UnoType<bool>::get(),
1237 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1238 css::beans::Property( u"Title"_ustr,
1239 -1, cppu::UnoType<OUString>::get(),
1240 css::beans::PropertyAttribute::BOUND ),
1241 css::beans::Property( u"IsReadOnly"_ustr,
1242 -1, cppu::UnoType<bool>::get(),
1243 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1244 css::beans::Property( u"DateCreated"_ustr,
1245 -1, cppu::UnoType<css::util::DateTime>::get(),
1246 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1247 css::beans::Property( u"DateModified"_ustr,
1248 -1, cppu::UnoType<css::util::DateTime>::get(),
1249 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1250 css::beans::Property( u"Size"_ustr,
1251 -1, cppu::UnoType<sal_Int64>::get(),
1252 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1253 css::beans::Property( u"IsVolume"_ustr,
1254 1, cppu::UnoType<bool>::get(),
1255 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1256 css::beans::Property( u"IsCompactDisc"_ustr,
1257 -1, cppu::UnoType<bool>::get(),
1258 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1259 css::beans::Property( u"IsRemoveable"_ustr,
1260 -1, cppu::UnoType<bool>::get(),
1261 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1262 css::beans::Property( u"IsHidden"_ustr,
1263 -1, cppu::UnoType<bool>::get(),
1264 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
1265 css::beans::Property( u"CreatableContentsInfo"_ustr,
1266 -1, cppu::UnoType<css::uno::Sequence< css::ucb::ContentInfo >>::get(),
1267 css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY )
1270 const int nProps = SAL_N_ELEMENTS(aGenericProperties);
1271 return css::uno::Sequence< css::beans::Property > ( aGenericProperties, nProps );
1274 css::uno::Sequence< css::ucb::CommandInfo > Content::getCommands( const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv)
1276 static const css::ucb::CommandInfo aCommandInfoTable[] =
1278 // Required commands
1279 css::ucb::CommandInfo
1280 ( u"getCommandInfo"_ustr,
1281 -1, cppu::UnoType<void>::get() ),
1282 css::ucb::CommandInfo
1283 ( u"getPropertySetInfo"_ustr,
1284 -1, cppu::UnoType<void>::get() ),
1285 css::ucb::CommandInfo
1286 ( u"getPropertyValues"_ustr,
1287 -1, cppu::UnoType<css::uno::Sequence< css::beans::Property >>::get() ),
1288 css::ucb::CommandInfo
1289 ( u"setPropertyValues"_ustr,
1290 -1, cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get() ),
1292 // Optional standard commands
1293 css::ucb::CommandInfo
1294 ( u"delete"_ustr,
1295 -1, cppu::UnoType<bool>::get() ),
1296 css::ucb::CommandInfo
1297 ( u"insert"_ustr,
1298 -1, cppu::UnoType<css::ucb::InsertCommandArgument>::get() ),
1299 css::ucb::CommandInfo
1300 ( u"open"_ustr,
1301 -1, cppu::UnoType<css::ucb::OpenCommandArgument2>::get() ),
1303 // Folder Only, omitted if not a folder
1304 css::ucb::CommandInfo
1305 ( u"transfer"_ustr,
1306 -1, cppu::UnoType<css::ucb::TransferInfo>::get() ),
1307 css::ucb::CommandInfo
1308 ( u"createNewContent"_ustr,
1309 -1, cppu::UnoType<css::ucb::ContentInfo>::get() )
1312 const int nProps = SAL_N_ELEMENTS(aCommandInfoTable);
1313 return css::uno::Sequence< css::ucb::CommandInfo >(aCommandInfoTable, isFolder(xEnv) ? nProps : nProps - 2);
1316 XTYPEPROVIDER_COMMON_IMPL( Content );
1318 void SAL_CALL Content::acquire() noexcept
1320 ContentImplHelper::acquire();
1323 void SAL_CALL Content::release() noexcept
1325 ContentImplHelper::release();
1328 css::uno::Any SAL_CALL Content::queryInterface( const css::uno::Type & rType )
1330 css::uno::Any aRet = cppu::queryInterface( rType, static_cast< css::ucb::XContentCreator * >( this ) );
1331 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1334 OUString SAL_CALL Content::getImplementationName()
1336 return u"com.sun.star.comp.GIOContent"_ustr;
1339 css::uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
1341 css::uno::Sequence<OUString> aSNS { u"com.sun.star.ucb.GIOContent"_ustr };
1342 return aSNS;
1347 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */