Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
22
third_party/FreeRDP/winpr/libwinpr/clipboard/CMakeLists.txt
vendored
Normal file
22
third_party/FreeRDP/winpr/libwinpr/clipboard/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-clipboard cmake build script
|
||||
#
|
||||
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed 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
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
winpr_module_add(synthetic.c clipboard.c clipboard.h synthetic_file.h synthetic_file.c)
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
7
third_party/FreeRDP/winpr/libwinpr/clipboard/ModuleOptions.cmake
vendored
Normal file
7
third_party/FreeRDP/winpr/libwinpr/clipboard/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
set(MINWIN_LAYER "0")
|
||||
set(MINWIN_GROUP "none")
|
||||
set(MINWIN_MAJOR_VERSION "0")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "clipboard")
|
||||
set(MINWIN_LONG_NAME "Clipboard Functions")
|
||||
set(MODULE_LIBRARY_NAME "clipboard")
|
||||
771
third_party/FreeRDP/winpr/libwinpr/clipboard/clipboard.c
vendored
Normal file
771
third_party/FreeRDP/winpr/libwinpr/clipboard/clipboard.c
vendored
Normal file
@@ -0,0 +1,771 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Clipboard Functions
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/collections.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
#include "clipboard.h"
|
||||
|
||||
#include "synthetic_file.h"
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("clipboard")
|
||||
|
||||
const char* const mime_text_plain = "text/plain";
|
||||
|
||||
/**
|
||||
* Clipboard (Windows):
|
||||
* msdn.microsoft.com/en-us/library/windows/desktop/ms648709/
|
||||
*
|
||||
* W3C Clipboard API and events:
|
||||
* http://www.w3.org/TR/clipboard-apis/
|
||||
*/
|
||||
|
||||
static const char* CF_STANDARD_STRINGS[] = {
|
||||
"CF_RAW", /* 0 */
|
||||
"CF_TEXT", /* 1 */
|
||||
"CF_BITMAP", /* 2 */
|
||||
"CF_METAFILEPICT", /* 3 */
|
||||
"CF_SYLK", /* 4 */
|
||||
"CF_DIF", /* 5 */
|
||||
"CF_TIFF", /* 6 */
|
||||
"CF_OEMTEXT", /* 7 */
|
||||
"CF_DIB", /* 8 */
|
||||
"CF_PALETTE", /* 9 */
|
||||
"CF_PENDATA", /* 10 */
|
||||
"CF_RIFF", /* 11 */
|
||||
"CF_WAVE", /* 12 */
|
||||
"CF_UNICODETEXT", /* 13 */
|
||||
"CF_ENHMETAFILE", /* 14 */
|
||||
"CF_HDROP", /* 15 */
|
||||
"CF_LOCALE", /* 16 */
|
||||
"CF_DIBV5" /* 17 */
|
||||
};
|
||||
|
||||
const char* ClipboardGetFormatIdString(UINT32 formatId)
|
||||
{
|
||||
if (formatId < ARRAYSIZE(CF_STANDARD_STRINGS))
|
||||
return CF_STANDARD_STRINGS[formatId];
|
||||
return "CF_REGISTERED_FORMAT";
|
||||
}
|
||||
|
||||
static wClipboardFormat* ClipboardFindFormat(wClipboard* clipboard, UINT32 formatId,
|
||||
const char* name)
|
||||
{
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return nullptr;
|
||||
|
||||
if (formatId)
|
||||
{
|
||||
for (UINT32 index = 0; index < clipboard->numFormats; index++)
|
||||
{
|
||||
wClipboardFormat* cformat = &clipboard->formats[index];
|
||||
if (formatId == cformat->formatId)
|
||||
{
|
||||
format = cformat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (name)
|
||||
{
|
||||
for (UINT32 index = 0; index < clipboard->numFormats; index++)
|
||||
{
|
||||
wClipboardFormat* cformat = &clipboard->formats[index];
|
||||
if (!cformat->formatName)
|
||||
continue;
|
||||
|
||||
if (strcmp(name, cformat->formatName) == 0)
|
||||
{
|
||||
format = cformat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* special "CF_RAW" case */
|
||||
if (clipboard->numFormats > 0)
|
||||
{
|
||||
format = &clipboard->formats[0];
|
||||
|
||||
if (format->formatId)
|
||||
return nullptr;
|
||||
|
||||
if (!format->formatName || (strcmp(format->formatName, CF_STANDARD_STRINGS[0]) == 0))
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
static wClipboardSynthesizer* ClipboardFindSynthesizer(wClipboardFormat* format, UINT32 formatId)
|
||||
{
|
||||
if (!format)
|
||||
return nullptr;
|
||||
|
||||
for (UINT32 index = 0; index < format->numSynthesizers; index++)
|
||||
{
|
||||
wClipboardSynthesizer* synthesizer = &(format->synthesizers[index]);
|
||||
|
||||
if (formatId == synthesizer->syntheticId)
|
||||
return synthesizer;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClipboardLock(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&(clipboard->lock));
|
||||
}
|
||||
|
||||
void ClipboardUnlock(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return;
|
||||
|
||||
LeaveCriticalSection(&(clipboard->lock));
|
||||
}
|
||||
|
||||
BOOL ClipboardEmpty(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return FALSE;
|
||||
|
||||
if (clipboard->data)
|
||||
{
|
||||
free(clipboard->data);
|
||||
clipboard->data = nullptr;
|
||||
}
|
||||
|
||||
clipboard->size = 0;
|
||||
clipboard->formatId = 0;
|
||||
clipboard->sequenceNumber++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT32 ClipboardCountRegisteredFormats(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
return clipboard->numFormats;
|
||||
}
|
||||
|
||||
UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** ppFormatIds)
|
||||
{
|
||||
UINT32* pFormatIds = nullptr;
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
if (!ppFormatIds)
|
||||
return 0;
|
||||
|
||||
pFormatIds = *ppFormatIds;
|
||||
|
||||
if (!pFormatIds)
|
||||
{
|
||||
pFormatIds = calloc(clipboard->numFormats, sizeof(UINT32));
|
||||
|
||||
if (!pFormatIds)
|
||||
return 0;
|
||||
|
||||
*ppFormatIds = pFormatIds;
|
||||
}
|
||||
|
||||
for (UINT32 index = 0; index < clipboard->numFormats; index++)
|
||||
{
|
||||
format = &(clipboard->formats[index]);
|
||||
pFormatIds[index] = format->formatId;
|
||||
}
|
||||
|
||||
return clipboard->numFormats;
|
||||
}
|
||||
|
||||
UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name)
|
||||
{
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, 0, name);
|
||||
|
||||
if (format)
|
||||
return format->formatId;
|
||||
|
||||
if ((clipboard->numFormats + 1) >= clipboard->maxFormats)
|
||||
{
|
||||
UINT32 numFormats = clipboard->maxFormats * 2;
|
||||
wClipboardFormat* tmpFormat = nullptr;
|
||||
tmpFormat =
|
||||
(wClipboardFormat*)realloc(clipboard->formats, numFormats * sizeof(wClipboardFormat));
|
||||
|
||||
if (!tmpFormat)
|
||||
return 0;
|
||||
|
||||
clipboard->formats = tmpFormat;
|
||||
clipboard->maxFormats = numFormats;
|
||||
}
|
||||
|
||||
format = &(clipboard->formats[clipboard->numFormats]);
|
||||
ZeroMemory(format, sizeof(wClipboardFormat));
|
||||
|
||||
if (name)
|
||||
{
|
||||
format->formatName = _strdup(name);
|
||||
|
||||
if (!format->formatName)
|
||||
return 0;
|
||||
}
|
||||
|
||||
format->formatId = clipboard->nextFormatId++;
|
||||
clipboard->numFormats++;
|
||||
return format->formatId;
|
||||
}
|
||||
|
||||
BOOL ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, UINT32 syntheticId,
|
||||
CLIPBOARD_SYNTHESIZE_FN pfnSynthesize)
|
||||
{
|
||||
UINT32 index = 0;
|
||||
wClipboardFormat* format = nullptr;
|
||||
wClipboardSynthesizer* synthesizer = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return FALSE;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
return FALSE;
|
||||
|
||||
if (format->formatId == syntheticId)
|
||||
return FALSE;
|
||||
|
||||
synthesizer = ClipboardFindSynthesizer(format, formatId);
|
||||
|
||||
if (!synthesizer)
|
||||
{
|
||||
wClipboardSynthesizer* tmpSynthesizer = nullptr;
|
||||
UINT32 numSynthesizers = format->numSynthesizers + 1;
|
||||
tmpSynthesizer = (wClipboardSynthesizer*)realloc(
|
||||
format->synthesizers, numSynthesizers * sizeof(wClipboardSynthesizer));
|
||||
|
||||
if (!tmpSynthesizer)
|
||||
return FALSE;
|
||||
|
||||
format->synthesizers = tmpSynthesizer;
|
||||
format->numSynthesizers = numSynthesizers;
|
||||
index = numSynthesizers - 1;
|
||||
synthesizer = &(format->synthesizers[index]);
|
||||
}
|
||||
|
||||
synthesizer->syntheticId = syntheticId;
|
||||
synthesizer->pfnSynthesize = pfnSynthesize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT32 ClipboardCountFormats(wClipboard* clipboard)
|
||||
{
|
||||
UINT32 count = 0;
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
return 0;
|
||||
|
||||
count = 1 + format->numSynthesizers;
|
||||
return count;
|
||||
}
|
||||
|
||||
UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds)
|
||||
{
|
||||
UINT32 count = 0;
|
||||
UINT32* pFormatIds = nullptr;
|
||||
wClipboardFormat* format = nullptr;
|
||||
wClipboardSynthesizer* synthesizer = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
return 0;
|
||||
|
||||
count = 1 + format->numSynthesizers;
|
||||
|
||||
if (!ppFormatIds)
|
||||
return 0;
|
||||
|
||||
pFormatIds = *ppFormatIds;
|
||||
|
||||
if (!pFormatIds)
|
||||
{
|
||||
pFormatIds = calloc(count, sizeof(UINT32));
|
||||
|
||||
if (!pFormatIds)
|
||||
return 0;
|
||||
|
||||
*ppFormatIds = pFormatIds;
|
||||
}
|
||||
|
||||
pFormatIds[0] = format->formatId;
|
||||
|
||||
for (UINT32 index = 1; index < count; index++)
|
||||
{
|
||||
synthesizer = &(format->synthesizers[index - 1]);
|
||||
pFormatIds[index] = synthesizer->syntheticId;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void ClipboardUninitFormats(wClipboard* clipboard)
|
||||
{
|
||||
WINPR_ASSERT(clipboard);
|
||||
for (UINT32 formatId = 0; formatId < clipboard->numFormats; formatId++)
|
||||
{
|
||||
wClipboardFormat* format = &clipboard->formats[formatId];
|
||||
free(format->formatName);
|
||||
free(format->synthesizers);
|
||||
format->formatName = nullptr;
|
||||
format->synthesizers = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL ClipboardInitFormats(wClipboard* clipboard)
|
||||
{
|
||||
UINT32 formatId = 0;
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return FALSE;
|
||||
|
||||
for (formatId = 0; formatId < CF_MAX; formatId++, clipboard->numFormats++)
|
||||
{
|
||||
format = &(clipboard->formats[clipboard->numFormats]);
|
||||
ZeroMemory(format, sizeof(wClipboardFormat));
|
||||
format->formatId = formatId;
|
||||
format->formatName = _strdup(CF_STANDARD_STRINGS[formatId]);
|
||||
|
||||
if (!format->formatName)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!ClipboardInitSynthesizers(clipboard))
|
||||
goto error;
|
||||
|
||||
return TRUE;
|
||||
error:
|
||||
|
||||
ClipboardUninitFormats(clipboard);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name)
|
||||
{
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, 0, name);
|
||||
|
||||
if (!format)
|
||||
return 0;
|
||||
|
||||
return format->formatId;
|
||||
}
|
||||
|
||||
const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId)
|
||||
{
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
if (!clipboard)
|
||||
return nullptr;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
return nullptr;
|
||||
|
||||
return format->formatName;
|
||||
}
|
||||
|
||||
void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize)
|
||||
{
|
||||
UINT32 SrcSize = 0;
|
||||
UINT32 DstSize = 0;
|
||||
void* pSrcData = nullptr;
|
||||
void* pDstData = nullptr;
|
||||
wClipboardFormat* format = nullptr;
|
||||
wClipboardSynthesizer* synthesizer = nullptr;
|
||||
|
||||
if (!clipboard || !pSize)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid parameters clipboard=%p, pSize=%p",
|
||||
WINPR_CXX_COMPAT_CAST(const void*, clipboard),
|
||||
WINPR_CXX_COMPAT_CAST(const void*, pSize));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*pSize = 0;
|
||||
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
{
|
||||
WLog_ERR(TAG, "Format [0x%08" PRIx32 "] not found", clipboard->formatId);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SrcSize = clipboard->size;
|
||||
pSrcData = clipboard->data;
|
||||
|
||||
if (formatId == format->formatId)
|
||||
{
|
||||
DstSize = SrcSize;
|
||||
pDstData = malloc(DstSize);
|
||||
|
||||
if (!pDstData)
|
||||
return nullptr;
|
||||
|
||||
CopyMemory(pDstData, pSrcData, SrcSize);
|
||||
*pSize = DstSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
synthesizer = ClipboardFindSynthesizer(format, formatId);
|
||||
|
||||
if (!synthesizer || !synthesizer->pfnSynthesize)
|
||||
{
|
||||
WLog_ERR(TAG, "No synthesizer for format %s [0x%08" PRIx32 "] --> %s [0x%08" PRIx32 "]",
|
||||
ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId,
|
||||
ClipboardGetFormatName(clipboard, formatId), formatId);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DstSize = SrcSize;
|
||||
pDstData = synthesizer->pfnSynthesize(clipboard, format->formatId, pSrcData, &DstSize);
|
||||
if (pDstData)
|
||||
*pSize = DstSize;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "getting formatId=%s [0x%08" PRIx32 "] data=%p, size=%" PRIu32,
|
||||
ClipboardGetFormatName(clipboard, formatId), formatId, pDstData, *pSize);
|
||||
return pDstData;
|
||||
}
|
||||
|
||||
BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size)
|
||||
{
|
||||
wClipboardFormat* format = nullptr;
|
||||
|
||||
WLog_DBG(TAG, "setting formatId=%s [0x%08" PRIx32 "], size=%" PRIu32,
|
||||
ClipboardGetFormatName(clipboard, formatId), formatId, size);
|
||||
if (!clipboard)
|
||||
return FALSE;
|
||||
|
||||
format = ClipboardFindFormat(clipboard, formatId, nullptr);
|
||||
|
||||
if (!format)
|
||||
return FALSE;
|
||||
|
||||
free(clipboard->data);
|
||||
|
||||
clipboard->data = calloc(size + sizeof(WCHAR), sizeof(char));
|
||||
|
||||
if (!clipboard->data)
|
||||
return FALSE;
|
||||
|
||||
memcpy(clipboard->data, data, size);
|
||||
|
||||
/* For string values we don´t know if they are '\0' terminated.
|
||||
* so set the size to the full length in bytes (e.g. string length + 1)
|
||||
*/
|
||||
switch (formatId)
|
||||
{
|
||||
case CF_TEXT:
|
||||
case CF_OEMTEXT:
|
||||
clipboard->size = (UINT32)(strnlen(clipboard->data, size) + 1UL);
|
||||
break;
|
||||
case CF_UNICODETEXT:
|
||||
clipboard->size =
|
||||
(UINT32)((_wcsnlen(clipboard->data, size / sizeof(WCHAR)) + 1UL) * sizeof(WCHAR));
|
||||
break;
|
||||
default:
|
||||
clipboard->size = size;
|
||||
break;
|
||||
}
|
||||
|
||||
clipboard->formatId = formatId;
|
||||
clipboard->sequenceNumber++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT64 ClipboardGetOwner(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return 0;
|
||||
|
||||
return clipboard->ownerId;
|
||||
}
|
||||
|
||||
void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId)
|
||||
{
|
||||
if (!clipboard)
|
||||
return;
|
||||
|
||||
clipboard->ownerId = ownerId;
|
||||
}
|
||||
|
||||
wClipboardDelegate* ClipboardGetDelegate(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return nullptr;
|
||||
|
||||
return &clipboard->delegate;
|
||||
}
|
||||
|
||||
static void ClipboardInitLocalFileSubsystem(wClipboard* clipboard)
|
||||
{
|
||||
/*
|
||||
* There can be only one local file subsystem active.
|
||||
* Return as soon as initialization succeeds.
|
||||
*/
|
||||
if (ClipboardInitSyntheticFileSubsystem(clipboard))
|
||||
{
|
||||
WLog_DBG(TAG, "initialized synthetic local file subsystem");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_WARN(TAG, "failed to initialize synthetic local file subsystem");
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "failed to initialize local file subsystem, file transfer not available");
|
||||
}
|
||||
|
||||
wClipboard* ClipboardCreate(void)
|
||||
{
|
||||
wClipboard* clipboard = (wClipboard*)calloc(1, sizeof(wClipboard));
|
||||
|
||||
if (!clipboard)
|
||||
return nullptr;
|
||||
|
||||
clipboard->nextFormatId = 0xC000;
|
||||
clipboard->sequenceNumber = 0;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(clipboard->lock), 4000))
|
||||
goto fail;
|
||||
|
||||
clipboard->numFormats = 0;
|
||||
clipboard->maxFormats = 64;
|
||||
clipboard->formats = (wClipboardFormat*)calloc(clipboard->maxFormats, sizeof(wClipboardFormat));
|
||||
|
||||
if (!clipboard->formats)
|
||||
goto fail;
|
||||
|
||||
if (!ClipboardInitFormats(clipboard))
|
||||
goto fail;
|
||||
|
||||
clipboard->delegate.clipboard = clipboard;
|
||||
ClipboardInitLocalFileSubsystem(clipboard);
|
||||
return clipboard;
|
||||
fail:
|
||||
ClipboardDestroy(clipboard);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClipboardDestroy(wClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return;
|
||||
|
||||
ArrayList_Free(clipboard->localFiles);
|
||||
clipboard->localFiles = nullptr;
|
||||
|
||||
ClipboardUninitFormats(clipboard);
|
||||
|
||||
free(clipboard->data);
|
||||
clipboard->data = nullptr;
|
||||
clipboard->size = 0;
|
||||
clipboard->numFormats = 0;
|
||||
free(clipboard->formats);
|
||||
DeleteCriticalSection(&(clipboard->lock));
|
||||
free(clipboard);
|
||||
}
|
||||
|
||||
static BOOL is_dos_drive(const char* path, size_t len)
|
||||
{
|
||||
if (len < 2)
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(path);
|
||||
if (path[1] == ':' || path[1] == '|')
|
||||
{
|
||||
if (((path[0] >= 'A') && (path[0] <= 'Z')) || ((path[0] >= 'a') && (path[0] <= 'z')))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* parse_uri_to_local_file(const char* uri, size_t uri_len)
|
||||
{
|
||||
// URI is specified by RFC 8089: https://datatracker.ietf.org/doc/html/rfc8089
|
||||
const char prefix[] = "file:";
|
||||
const char prefixTraditional[] = "file://";
|
||||
const char* localName = nullptr;
|
||||
size_t localLen = 0;
|
||||
char* buffer = nullptr;
|
||||
const size_t prefixLen = strnlen(prefix, sizeof(prefix));
|
||||
const size_t prefixTraditionalLen = strnlen(prefixTraditional, sizeof(prefixTraditional));
|
||||
|
||||
WINPR_ASSERT(uri || (uri_len == 0));
|
||||
|
||||
WLog_VRB(TAG, "processing URI: %.*s", WINPR_ASSERTING_INT_CAST(int, uri_len), uri);
|
||||
|
||||
if ((uri_len <= prefixLen) || strncmp(uri, prefix, prefixLen) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "non-'file:' URI schemes are not supported");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* https://datatracker.ietf.org/doc/html/rfc8089#appendix-F
|
||||
* - The minimal representation of a local file in a DOS- or Windows-
|
||||
* based environment with no authority field and an absolute path
|
||||
* that begins with a drive letter.
|
||||
*
|
||||
* "file:c:/path/to/file"
|
||||
*
|
||||
* - Regular DOS or Windows file URIs with vertical line characters in
|
||||
* the drive letter construct.
|
||||
*
|
||||
* "file:c|/path/to/file"
|
||||
*
|
||||
*/
|
||||
if (uri[prefixLen] != '/')
|
||||
{
|
||||
|
||||
if (is_dos_drive(&uri[prefixLen], uri_len - prefixLen))
|
||||
{
|
||||
// Dos and Windows file URI
|
||||
localName = &uri[prefixLen];
|
||||
localLen = uri_len - prefixLen;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "URI format are not supported: %s", uri);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* - The minimal representation of a local file with no authority field
|
||||
* and an absolute path that begins with a slash "/". For example:
|
||||
*
|
||||
* "file:/path/to/file"
|
||||
*
|
||||
*/
|
||||
else if ((uri_len > prefixLen + 1) && (uri[prefixLen + 1] != '/'))
|
||||
{
|
||||
if (is_dos_drive(&uri[prefixLen + 1], uri_len - prefixLen - 1))
|
||||
{
|
||||
// Dos and Windows file URI
|
||||
localName = (uri + prefixLen + 1);
|
||||
localLen = uri_len - prefixLen - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
localName = &uri[prefixLen];
|
||||
localLen = uri_len - prefixLen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* - A traditional file URI for a local file with an empty authority.
|
||||
*
|
||||
* "file:///path/to/file"
|
||||
*/
|
||||
if ((uri_len < prefixTraditionalLen) ||
|
||||
strncmp(uri, prefixTraditional, prefixTraditionalLen) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "non-'file:' URI schemes are not supported");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
localName = &uri[prefixTraditionalLen];
|
||||
localLen = uri_len - prefixTraditionalLen;
|
||||
|
||||
if (localLen < 1)
|
||||
{
|
||||
WLog_ERR(TAG, "empty 'file:' URI schemes are not supported");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* "file:///c:/path/to/file"
|
||||
* "file:///c|/path/to/file"
|
||||
*/
|
||||
if (localName[0] != '/')
|
||||
{
|
||||
WLog_ERR(TAG, "URI format are not supported: %s", uri);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (is_dos_drive(&localName[1], localLen - 1))
|
||||
{
|
||||
localName++;
|
||||
localLen--;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
buffer = winpr_str_url_decode(localName, localLen);
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer[1] == '|' &&
|
||||
((buffer[0] >= 'A' && buffer[0] <= 'Z') || (buffer[0] >= 'a' && buffer[0] <= 'z')))
|
||||
buffer[1] = ':';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
77
third_party/FreeRDP/winpr/libwinpr/clipboard/clipboard.h
vendored
Normal file
77
third_party/FreeRDP/winpr/libwinpr/clipboard/clipboard.h
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Clipboard Functions
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_CLIPBOARD_PRIVATE_H
|
||||
#define WINPR_CLIPBOARD_PRIVATE_H
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 syntheticId;
|
||||
CLIPBOARD_SYNTHESIZE_FN pfnSynthesize;
|
||||
} wClipboardSynthesizer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 formatId;
|
||||
char* formatName;
|
||||
|
||||
UINT32 numSynthesizers;
|
||||
wClipboardSynthesizer* synthesizers;
|
||||
} wClipboardFormat;
|
||||
|
||||
struct s_wClipboard
|
||||
{
|
||||
UINT64 ownerId;
|
||||
|
||||
/* clipboard formats */
|
||||
|
||||
UINT32 numFormats;
|
||||
UINT32 maxFormats;
|
||||
UINT32 nextFormatId;
|
||||
wClipboardFormat* formats;
|
||||
|
||||
/* clipboard data */
|
||||
|
||||
UINT32 size;
|
||||
void* data;
|
||||
UINT32 formatId;
|
||||
UINT32 sequenceNumber;
|
||||
|
||||
/* clipboard file handling */
|
||||
|
||||
wArrayList* localFiles;
|
||||
UINT32 fileListSequenceNumber;
|
||||
|
||||
wClipboardDelegate delegate;
|
||||
|
||||
CRITICAL_SECTION lock;
|
||||
};
|
||||
|
||||
WINPR_LOCAL BOOL ClipboardInitSynthesizers(wClipboard* clipboard);
|
||||
|
||||
WINPR_LOCAL char* parse_uri_to_local_file(const char* uri, size_t uri_len);
|
||||
|
||||
extern const char* const mime_text_plain;
|
||||
|
||||
#endif /* WINPR_CLIPBOARD_PRIVATE_H */
|
||||
1205
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic.c
vendored
Normal file
1205
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1248
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic_file.c
vendored
Normal file
1248
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic_file.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic_file.h
vendored
Normal file
27
third_party/FreeRDP/winpr/libwinpr/clipboard/synthetic_file.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Clipboard Functions: POSIX file handling
|
||||
*
|
||||
* Copyright 2017 Alexei Lozovsky <a.lozovsky@gmail.com>
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_CLIPBOARD_POSIX_H
|
||||
#define WINPR_CLIPBOARD_POSIX_H
|
||||
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard);
|
||||
|
||||
#endif /* WINPR_CLIPBOARD_POSIX_H */
|
||||
40
third_party/FreeRDP/winpr/libwinpr/clipboard/test/CMakeLists.txt
vendored
Normal file
40
third_party/FreeRDP/winpr/libwinpr/clipboard/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
set(MODULE_NAME "TestClipboard")
|
||||
set(MODULE_PREFIX "TEST_CLIPBOARD")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(TESTS TestClipboardFormats.c)
|
||||
|
||||
if(BUILD_TESTING_INTERNAL)
|
||||
list(APPEND TESTS TestUri.c)
|
||||
endif()
|
||||
|
||||
set(TEST_CLIP_PNG "${CMAKE_SOURCE_DIR}/resources/FreeRDP_Icon.png")
|
||||
file(TO_NATIVE_PATH "${TEST_CLIP_PNG}" TEST_CLIP_PNG)
|
||||
|
||||
set(TEST_CLIP_BMP "${CMAKE_SOURCE_DIR}/resources/FreeRDP_Install.bmp")
|
||||
file(TO_NATIVE_PATH "${TEST_CLIP_BMP}" TEST_CLIP_BMP)
|
||||
|
||||
if(WIN32)
|
||||
string(REPLACE "\\" "\\\\" TEST_CLIP_PNG "${TEST_CLIP_PNG}")
|
||||
string(REPLACE "\\" "\\\\" TEST_CLIP_BMP "${TEST_CLIP_BMP}")
|
||||
endif()
|
||||
|
||||
add_compile_definitions(TEST_CLIP_BMP="${TEST_CLIP_BMP}")
|
||||
add_compile_definitions(TEST_CLIP_PNG="${TEST_CLIP_PNG}")
|
||||
|
||||
create_test_sourcelist(SRCS ${DRIVER} ${TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${SRCS})
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
243
third_party/FreeRDP/winpr/libwinpr/clipboard/test/TestClipboardFormats.c
vendored
Normal file
243
third_party/FreeRDP/winpr/libwinpr/clipboard/test/TestClipboardFormats.c
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/image.h>
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
int TestClipboardFormats(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
UINT32 count = 0;
|
||||
UINT32* pFormatIds = nullptr;
|
||||
const char* formatName = nullptr;
|
||||
wClipboard* clipboard = nullptr;
|
||||
UINT32 utf8StringFormatId = 0;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
clipboard = ClipboardCreate();
|
||||
if (!clipboard)
|
||||
return -1;
|
||||
|
||||
const char* mime_types[] = { "text/html", "text/html", "image/bmp",
|
||||
"image/png", "image/webp", "image/jpeg" };
|
||||
for (size_t x = 0; x < ARRAYSIZE(mime_types); x++)
|
||||
{
|
||||
const char* mime = mime_types[x];
|
||||
UINT32 id = ClipboardRegisterFormat(clipboard, mime);
|
||||
(void)fprintf(stderr, "ClipboardRegisterFormat(%s) -> 0x%08" PRIx32 "\n", mime, id);
|
||||
if (id == 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING");
|
||||
pFormatIds = nullptr;
|
||||
count = ClipboardGetRegisteredFormatIds(clipboard, &pFormatIds);
|
||||
|
||||
for (UINT32 index = 0; index < count; index++)
|
||||
{
|
||||
UINT32 formatId = pFormatIds[index];
|
||||
formatName = ClipboardGetFormatName(clipboard, formatId);
|
||||
(void)fprintf(stderr, "Format: 0x%08" PRIX32 " %s\n", formatId, formatName);
|
||||
}
|
||||
|
||||
free(pFormatIds);
|
||||
|
||||
if (1)
|
||||
{
|
||||
BOOL bSuccess = 0;
|
||||
UINT32 SrcSize = 0;
|
||||
UINT32 DstSize = 0;
|
||||
const char pSrcData[] = "this is a test string";
|
||||
char* pDstData = nullptr;
|
||||
|
||||
SrcSize = (UINT32)(strnlen(pSrcData, ARRAYSIZE(pSrcData)) + 1);
|
||||
bSuccess = ClipboardSetData(clipboard, utf8StringFormatId, pSrcData, SrcSize);
|
||||
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
|
||||
DstSize = 0;
|
||||
pDstData = (char*)ClipboardGetData(clipboard, utf8StringFormatId, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: %s\n", pDstData);
|
||||
free(pDstData);
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
UINT32 DstSize = 0;
|
||||
char* pSrcData = nullptr;
|
||||
WCHAR* pDstData = nullptr;
|
||||
DstSize = 0;
|
||||
pDstData = (WCHAR*)ClipboardGetData(clipboard, CF_UNICODETEXT, &DstSize);
|
||||
pSrcData = ConvertWCharNToUtf8Alloc(pDstData, DstSize / sizeof(WCHAR), nullptr);
|
||||
|
||||
(void)fprintf(stderr, "ClipboardGetData (synthetic): %s\n", pSrcData);
|
||||
free(pDstData);
|
||||
free(pSrcData);
|
||||
}
|
||||
|
||||
pFormatIds = nullptr;
|
||||
count = ClipboardGetFormatIds(clipboard, &pFormatIds);
|
||||
|
||||
for (UINT32 index = 0; index < count; index++)
|
||||
{
|
||||
UINT32 formatId = pFormatIds[index];
|
||||
formatName = ClipboardGetFormatName(clipboard, formatId);
|
||||
(void)fprintf(stderr, "Format: 0x%08" PRIX32 " %s\n", formatId, formatName);
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
const char* name = TEST_CLIP_BMP;
|
||||
BOOL bSuccess = FALSE;
|
||||
UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/bmp");
|
||||
|
||||
wImage* img = winpr_image_new();
|
||||
if (!img)
|
||||
goto fail;
|
||||
|
||||
if (winpr_image_read(img, name) <= 0)
|
||||
{
|
||||
winpr_image_free(img, TRUE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size_t bmpsize = 0;
|
||||
void* data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &bmpsize);
|
||||
bSuccess = ClipboardSetData(clipboard, idBmp, data, bmpsize);
|
||||
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
|
||||
|
||||
free(data);
|
||||
winpr_image_free(img, TRUE);
|
||||
if (!bSuccess)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
UINT32 id = CF_DIB;
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [CF_DIB] %p [%" PRIu32 "]\n", pDstData,
|
||||
DstSize);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
bSuccess = ClipboardSetData(clipboard, id, pDstData, DstSize);
|
||||
free(pDstData);
|
||||
if (!bSuccess)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const uint32_t id = ClipboardGetFormatId(clipboard, "HTML Format");
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
{
|
||||
FILE* fp = fopen("test.html", "w");
|
||||
if (fp)
|
||||
{
|
||||
(void)fwrite(pDstData, 1, DstSize, fp);
|
||||
(void)fclose(fp);
|
||||
}
|
||||
}
|
||||
free(pDstData);
|
||||
}
|
||||
{
|
||||
UINT32 id = ClipboardRegisterFormat(clipboard, "image/bmp");
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [image/bmp] %p [%" PRIu32 "]\n", pDstData,
|
||||
DstSize);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
free(pDstData);
|
||||
if (DstSize != bmpsize)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if defined(WINPR_UTILS_IMAGE_PNG)
|
||||
{
|
||||
UINT32 id = ClipboardRegisterFormat(clipboard, "image/png");
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [image/png] %p\n", pDstData);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
free(pDstData);
|
||||
}
|
||||
{
|
||||
const char* name = TEST_CLIP_PNG;
|
||||
BOOL bSuccess = FALSE;
|
||||
UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/png");
|
||||
|
||||
wImage* img = winpr_image_new();
|
||||
if (!img)
|
||||
goto fail;
|
||||
|
||||
if (winpr_image_read(img, name) <= 0)
|
||||
{
|
||||
winpr_image_free(img, TRUE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size_t bmpsize = 0;
|
||||
void* data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &bmpsize);
|
||||
bSuccess = ClipboardSetData(clipboard, idBmp, data, bmpsize);
|
||||
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
|
||||
|
||||
free(data);
|
||||
winpr_image_free(img, TRUE);
|
||||
if (!bSuccess)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
UINT32 id = CF_DIB;
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [CF_DIB] %p [%" PRIu32 "]\n", pDstData,
|
||||
DstSize);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
bSuccess = ClipboardSetData(clipboard, id, pDstData, DstSize);
|
||||
free(pDstData);
|
||||
if (!bSuccess)
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WINPR_UTILS_IMAGE_WEBP)
|
||||
{
|
||||
UINT32 id = ClipboardRegisterFormat(clipboard, "image/webp");
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [image/webp] %p\n", pDstData);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
free(pDstData);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WINPR_UTILS_IMAGE_JPEG)
|
||||
{
|
||||
UINT32 id = ClipboardRegisterFormat(clipboard, "image/jpeg");
|
||||
|
||||
UINT32 DstSize = 0;
|
||||
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
|
||||
(void)fprintf(stderr, "ClipboardGetData: [image/jpeg] %p\n", pDstData);
|
||||
if (!pDstData)
|
||||
goto fail;
|
||||
free(pDstData);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
fail:
|
||||
free(pFormatIds);
|
||||
ClipboardDestroy(clipboard);
|
||||
return rc;
|
||||
}
|
||||
69
third_party/FreeRDP/winpr/libwinpr/clipboard/test/TestUri.c
vendored
Normal file
69
third_party/FreeRDP/winpr/libwinpr/clipboard/test/TestUri.c
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include "winpr/wlog.h"
|
||||
|
||||
#include "../clipboard.h"
|
||||
|
||||
#define WINPR_TAG(tag) "com.winpr." tag
|
||||
#define TAG WINPR_TAG("clipboard.posix")
|
||||
|
||||
int TestUri(int argc, char* argv[])
|
||||
{
|
||||
int nRet = 0;
|
||||
const char* input[] = { /*uri, file or nullptr*/
|
||||
"file://root/a.txt",
|
||||
nullptr,
|
||||
"file:a.txt",
|
||||
nullptr,
|
||||
"file:///c:/windows/a.txt",
|
||||
"c:/windows/a.txt",
|
||||
"file:c:/windows/a.txt",
|
||||
"c:/windows/a.txt",
|
||||
"file:c|/windows/a.txt",
|
||||
"c:/windows/a.txt",
|
||||
"file:///root/a.txt",
|
||||
"/root/a.txt",
|
||||
"file:/root/a.txt",
|
||||
"/root/a.txt"
|
||||
};
|
||||
|
||||
const size_t nLen = ARRAYSIZE(input);
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
printf("input length:%" PRIuz "\n", nLen / 2);
|
||||
|
||||
for (size_t i = 0; i < nLen; i += 2)
|
||||
{
|
||||
const char* in = input[i];
|
||||
const char* cmp = input[i + 1];
|
||||
int bTest = 0;
|
||||
char* name = parse_uri_to_local_file(in, strlen(in));
|
||||
if (name && cmp)
|
||||
{
|
||||
bTest = !strcmp(name, cmp);
|
||||
if (!bTest)
|
||||
{
|
||||
printf("Test error: input: %s; Expected value: %s; output: %s\n", in, cmp, name);
|
||||
nRet++;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cmp)
|
||||
{
|
||||
printf("Test error: input: %s; Expected value: %s; output: %s\n", in, cmp, name);
|
||||
nRet++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("TestUri return value: %d\n", nRet);
|
||||
return nRet;
|
||||
}
|
||||
Reference in New Issue
Block a user