libdndcp_la_SOURCES += copyPasteCompat.c
libdndcp_la_SOURCES += vmCopyPasteDnDWrapper.cpp
libdndcp_la_SOURCES += copyPasteDnDX11.cpp
+libdndcp_la_SOURCES += copyPasteDnDUtil.cpp
libdndcp_la_SOURCES += copyPasteCompatX11.c
libdndcp_la_SOURCES += copyPasteUIX11.cpp
libdndcp_la_SOURCES += dndUIX11.cpp
--- /dev/null
+/*********************************************************
+ * Copyright (c) 2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPasteDnDUtil.cpp --
+ *
+ * This is the utility file to keep the common API's
+ * for Copy/Paste and Drag/Drop functionality.
+ *
+ */
+
+
+#include "copyPasteDnDUtil.h"
+#include "file.h"
+#include "dndFileContentsUtil.h"
+#include "dndFileList.hh"
+#include "copyPasteUIX11.h"
+#include "cpNameUtil.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * LocalPrepareFileContents --
+ *
+ * Try to extract file contents from Clipboard. Write all files to a
+ * temporary staging directory. Construct uri list.
+ *
+ * Results:
+ * true if success, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+bool
+LocalPrepareFileContents(const CPClipboard *clip, // IN
+ std::vector<utf::string>& fileContentsList) // OUT
+{
+ void *buf = NULL;
+ size_t sz = 0;
+ XDR xdrs;
+ CPFileContents fileContents;
+ CPFileContentsList *contentsList = NULL;
+ size_t nFiles = 0;
+ CPFileItem *fileItem = NULL;
+ char *tempDir = NULL;
+ size_t i = 0;
+ bool ret = false;
+
+ if (!CPClipboard_GetItem(clip, CPFORMAT_FILECONTENTS, &buf, &sz)) {
+ Warning("%s: CPClipboard_GetItem failed\n", __FUNCTION__);
+ return false;
+ }
+
+ /* Extract file contents from buf. */
+ xdrmem_create(&xdrs, (char *)buf, sz, XDR_DECODE);
+ memset(&fileContents, 0, sizeof fileContents);
+
+ if (!xdr_CPFileContents(&xdrs, &fileContents)) {
+ Warning("%s: xdr_CPFileContents failed.\n", __FUNCTION__);
+ xdr_destroy(&xdrs);
+ return false;
+ }
+ xdr_destroy(&xdrs);
+
+ contentsList = fileContents.CPFileContents_u.fileContentsV1;
+ if (!contentsList) {
+ Warning("%s: invalid contentsList.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ nFiles = contentsList->fileItem.fileItem_len;
+ if (0 == nFiles) {
+ Warning("%s: invalid nFiles.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ fileItem = contentsList->fileItem.fileItem_val;
+ if (!fileItem) {
+ Warning("%s: invalid fileItem.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ /*
+ * Write files into a temporary staging directory. These files will be moved
+ * to final destination, or deleted on next reboot.
+ */
+ tempDir = DnD_CreateStagingDirectory();
+ if (!tempDir) {
+ Warning("%s: DnD_CreateStagingDirectory failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ fileContentsList.clear();
+
+ for (i = 0; i < nFiles; i++) {
+ utf::string fileName;
+ utf::string filePathName;
+ VmTimeType createTime = -1;
+ VmTimeType accessTime = -1;
+ VmTimeType writeTime = -1;
+ VmTimeType attrChangeTime = -1;
+
+ if (!fileItem[i].cpName.cpName_val ||
+ 0 == fileItem[i].cpName.cpName_len) {
+ Warning("%s: invalid fileItem[%" FMTSZ "u].cpName.\n", __FUNCTION__, i);
+ goto exit;
+ }
+
+ /*
+ * '\0' is used as directory separator in cross-platform name. Now turn
+ * '\0' in data into DIRSEPC.
+ *
+ * Note that we don't convert the final '\0' into DIRSEPC so the string
+ * is NUL terminated.
+ */
+ CPNameUtil_CharReplace(fileItem[i].cpName.cpName_val,
+ fileItem[i].cpName.cpName_len - 1,
+ '\0',
+ DIRSEPC);
+ fileName = fileItem[i].cpName.cpName_val;
+ filePathName = tempDir;
+ filePathName += DIRSEPS + fileName;
+
+ if ((fileItem[i].validFlags & CP_FILE_VALID_TYPE) &&
+ CP_FILE_TYPE_DIRECTORY == fileItem[i].type) {
+ if (!File_CreateDirectory(filePathName.c_str())) {
+ goto exit;
+ }
+ g_debug("%s: created directory [%s].\n",
+ __FUNCTION__, filePathName.c_str());
+ } else if ((fileItem[i].validFlags & CP_FILE_VALID_TYPE) &&
+ CP_FILE_TYPE_REGULAR == fileItem[i].type) {
+ FileIODescriptor file;
+ FileIOResult fileErr;
+
+ FileIO_Invalidate(&file);
+
+ fileErr = FileIO_Open(&file,
+ filePathName.c_str(),
+ FILEIO_ACCESS_WRITE,
+ FILEIO_OPEN_CREATE_EMPTY);
+ if (!FileIO_IsSuccess(fileErr)) {
+ goto exit;
+ }
+
+ fileErr = FileIO_Write(&file,
+ fileItem[i].content.content_val,
+ fileItem[i].content.content_len,
+ NULL);
+
+ FileIO_Close(&file);
+ g_debug("%s: created file [%s].\n", __FUNCTION__, filePathName.c_str());
+ } else {
+ /*
+ * Right now only Windows can provide CPFORMAT_FILECONTENTS data.
+ * Symlink file is not expected. Continue with next file if the
+ * type is not valid.
+ */
+ continue;
+ }
+
+ /* Update file time attributes. */
+ createTime = (fileItem->validFlags & CP_FILE_VALID_CREATE_TIME) ?
+ fileItem->createTime: -1;
+ accessTime = (fileItem->validFlags & CP_FILE_VALID_ACCESS_TIME) ?
+ fileItem->accessTime: -1;
+ writeTime = (fileItem->validFlags & CP_FILE_VALID_WRITE_TIME) ?
+ fileItem->writeTime: -1;
+ attrChangeTime = (fileItem->validFlags & CP_FILE_VALID_CHANGE_TIME) ?
+ fileItem->attrChangeTime: -1;
+
+ if (!File_SetTimes(filePathName.c_str(),
+ createTime,
+ accessTime,
+ writeTime,
+ attrChangeTime)) {
+ /* Not a critical error, only log it. */
+ g_debug("%s: File_SetTimes failed with file [%s].\n",
+ __FUNCTION__, filePathName.c_str());
+ }
+
+ /* Update file permission attributes. */
+ if (fileItem->validFlags & CP_FILE_VALID_PERMS) {
+ if (Posix_Chmod(filePathName.c_str(),
+ fileItem->permissions) < 0) {
+ /* Not a critical error, only log it. */
+ g_debug("%s: Posix_Chmod failed with file [%s].\n",
+ __FUNCTION__, filePathName.c_str());
+ }
+ }
+
+ /*
+ * If there is no DIRSEPC inside the fileName, this file/directory is a
+ * top level one. We only put top level name into uri list.
+ */
+ if (fileName.find(DIRSEPS, 0) == utf::string::npos) {
+ fileContentsList.push_back(filePathName);
+ }
+ }
+ g_debug("%s: created uri list\n", __FUNCTION__);
+ ret = true;
+
+exit:
+ xdr_free((xdrproc_t)xdr_CPFileContents, (char *)&fileContents);
+ if (tempDir && !ret) {
+ DnD_DeleteStagingFiles(tempDir, FALSE);
+ }
+ free(tempDir);
+ return ret;
+}
#include "file.h"
#include "dnd.h"
#include "dndMsg.h"
+#include "copyPasteDnDUtil.h"
extern "C" {
#include "dndClipboard.h"
if (CPClipboard_ItemExists(clip, CPFORMAT_FILECONTENTS)) {
g_debug("%s: File contents data\n", __FUNCTION__);
- if (LocalPrepareFileContents(clip)) {
+ if (LocalPrepareFileContents(clip, mHGFileContentsList)) {
refClipboard->set(mListTargets,
sigc::mem_fun(this, &CopyPasteUIX11::LocalGetFileContentsRequestCB),
sigc::mem_fun(this, &CopyPasteUIX11::LocalClearClipboardCB));
}
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteUIX11::LocalPrepareFileContents --
- *
- * Try to extract file contents from mClipboard. Write all files to a
- * temporary staging directory. Construct uri list.
- *
- * Results:
- * true if success, false otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-bool
-CopyPasteUIX11::LocalPrepareFileContents(const CPClipboard *clip) // IN
-{
- void *buf = NULL;
- size_t sz = 0;
- XDR xdrs;
- CPFileContents fileContents;
- CPFileContentsList *contentsList = NULL;
- size_t nFiles = 0;
- CPFileItem *fileItem = NULL;
- char *tempDir = NULL;
- size_t i = 0;
- bool ret = false;
-
- if (!CPClipboard_GetItem(clip, CPFORMAT_FILECONTENTS, &buf, &sz)) {
- g_debug("%s: CPClipboard_GetItem failed\n", __FUNCTION__);
- return false;
- }
-
- /* Extract file contents from buf. */
- xdrmem_create(&xdrs, (char *)buf, sz, XDR_DECODE);
- memset(&fileContents, 0, sizeof fileContents);
-
- if (!xdr_CPFileContents(&xdrs, &fileContents)) {
- g_debug("%s: xdr_CPFileContents failed.\n", __FUNCTION__);
- xdr_destroy(&xdrs);
- return false;
- }
- xdr_destroy(&xdrs);
-
- contentsList = fileContents.CPFileContents_u.fileContentsV1;
- if (!contentsList) {
- g_debug("%s: invalid contentsList.\n", __FUNCTION__);
- goto exit;
- }
-
- nFiles = contentsList->fileItem.fileItem_len;
- if (0 == nFiles) {
- g_debug("%s: invalid nFiles.\n", __FUNCTION__);
- goto exit;
- }
-
- fileItem = contentsList->fileItem.fileItem_val;
- if (!fileItem) {
- g_debug("%s: invalid fileItem.\n", __FUNCTION__);
- goto exit;
- }
-
- /*
- * Write files into a temporary staging directory. These files will be moved
- * to final destination, or deleted on next reboot.
- */
- tempDir = DnD_CreateStagingDirectory();
- if (!tempDir) {
- g_debug("%s: DnD_CreateStagingDirectory failed.\n", __FUNCTION__);
- goto exit;
- }
-
- mHGFileContentsList.clear();
-
- for (i = 0; i < nFiles; i++) {
- utf::string fileName;
- utf::string filePathName;
- VmTimeType createTime = -1;
- VmTimeType accessTime = -1;
- VmTimeType writeTime = -1;
- VmTimeType attrChangeTime = -1;
-
- if (!fileItem[i].cpName.cpName_val ||
- 0 == fileItem[i].cpName.cpName_len) {
- g_debug("%s: invalid fileItem[%" FMTSZ "u].cpName.\n", __FUNCTION__, i);
- goto exit;
- }
-
- /*
- * '\0' is used as directory separator in cross-platform name. Now turn
- * '\0' in data into DIRSEPC.
- *
- * Note that we don't convert the final '\0' into DIRSEPC so the string
- * is NUL terminated.
- */
- CPNameUtil_CharReplace(fileItem[i].cpName.cpName_val,
- fileItem[i].cpName.cpName_len - 1,
- '\0',
- DIRSEPC);
- fileName = fileItem[i].cpName.cpName_val;
- filePathName = tempDir;
- filePathName += DIRSEPS + fileName;
-
- if (fileItem[i].validFlags & CP_FILE_VALID_TYPE &&
- CP_FILE_TYPE_DIRECTORY == fileItem[i].type) {
- if (!File_CreateDirectory(filePathName.c_str())) {
- goto exit;
- }
- g_debug("%s: created directory [%s].\n",
- __FUNCTION__, filePathName.c_str());
- } else if (fileItem[i].validFlags & CP_FILE_VALID_TYPE &&
- CP_FILE_TYPE_REGULAR == fileItem[i].type) {
- FileIODescriptor file;
- FileIOResult fileErr;
-
- FileIO_Invalidate(&file);
-
- fileErr = FileIO_Open(&file,
- filePathName.c_str(),
- FILEIO_ACCESS_WRITE,
- FILEIO_OPEN_CREATE_EMPTY);
- if (!FileIO_IsSuccess(fileErr)) {
- goto exit;
- }
-
- fileErr = FileIO_Write(&file,
- fileItem[i].content.content_val,
- fileItem[i].content.content_len,
- NULL);
-
- FileIO_Close(&file);
- g_debug("%s: created file [%s].\n", __FUNCTION__, filePathName.c_str());
- } else {
- /*
- * Right now only Windows can provide CPFORMAT_FILECONTENTS data.
- * Symlink file is not expected. Continue with next file if the
- * type is not valid.
- */
- continue;
- }
-
- /* Update file time attributes. */
- createTime = fileItem->validFlags & CP_FILE_VALID_CREATE_TIME ?
- fileItem->createTime: -1;
- accessTime = fileItem->validFlags & CP_FILE_VALID_ACCESS_TIME ?
- fileItem->accessTime: -1;
- writeTime = fileItem->validFlags & CP_FILE_VALID_WRITE_TIME ?
- fileItem->writeTime: -1;
- attrChangeTime = fileItem->validFlags & CP_FILE_VALID_CHANGE_TIME ?
- fileItem->attrChangeTime: -1;
-
- if (!File_SetTimes(filePathName.c_str(),
- createTime,
- accessTime,
- writeTime,
- attrChangeTime)) {
- /* Not a critical error, only log it. */
- g_debug("%s: File_SetTimes failed with file [%s].\n",
- __FUNCTION__, filePathName.c_str());
- }
-
- /* Update file permission attributes. */
- if (fileItem->validFlags & CP_FILE_VALID_PERMS) {
- if (Posix_Chmod(filePathName.c_str(),
- fileItem->permissions) < 0) {
- /* Not a critical error, only log it. */
- g_debug("%s: Posix_Chmod failed with file [%s].\n",
- __FUNCTION__, filePathName.c_str());
- }
- }
-
- /*
- * If there is no DIRSEPC inside the fileName, this file/directory is a
- * top level one. We only put top level name into uri list.
- */
- if (fileName.find(DIRSEPS, 0) == utf::string::npos) {
- mHGFileContentsList.push_back(filePathName);
- }
- }
- g_debug("%s: created uri list\n", __FUNCTION__);
- ret = true;
-
-exit:
- xdr_free((xdrproc_t)xdr_CPFileContents, (char *)&fileContents);
- if (tempDir && !ret) {
- DnD_DeleteStagingFiles(tempDir, FALSE);
- }
- free(tempDir);
- return ret;
-}
-
-
/*
*-----------------------------------------------------------------------------
*
void LocalClipboardTimestampCB(const Gtk::SelectionData& sd);
void LocalPrimTimestampCB(const Gtk::SelectionData& sd);
void LocalReceivedFileListCB(const Gtk::SelectionData& selection_data);
- bool LocalPrepareFileContents(const CPClipboard *clip);
#endif
void GetLocalFilesDone(bool success);
void SendClipNotChanged(void);
utf::string mHGTextData;
std::string mHGRTFData;
bool mGetTimestampOnly;
- std::vector<utf::string> mHGFileContentsList;
#endif
+ std::vector<utf::string> mHGFileContentsList;
DND_FILE_TRANSFER_STATUS mHGGetFileStatus;
bool mBlockAdded;
--- /dev/null
+/*********************************************************
+ * Copyright (c) 2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file copyPasteDnDUtil.h
+ *
+ * Utility functions for Drag and Drop and Copy and Paste.
+ *
+ */
+
+#ifndef COPYPASTE_DND_UTIL_H
+#define COPYPASTE_DND_UTIL_H
+
+#include "dndClipboard.h"
+#include <vector>
+#include "stringxx/string.hh"
+
+bool LocalPrepareFileContents(const CPClipboard *clip,
+ std::vector<utf::string>& fileContentsList);
+
+#endif