From d98ce1a81919fd86abb43cdb19a448f406190088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 17 Oct 2014 15:19:05 -0400 Subject: [PATCH] libwinpr-clipboard: initial commit --- winpr/include/winpr/clipboard.h | 56 +++ winpr/libwinpr/CMakeLists.txt | 2 +- winpr/libwinpr/clipboard/CMakeLists.txt | 23 ++ winpr/libwinpr/clipboard/ModuleOptions.cmake | 9 + winpr/libwinpr/clipboard/clipboard.c | 350 ++++++++++++++++++ winpr/libwinpr/clipboard/clipboard.h | 52 +++ winpr/libwinpr/clipboard/test/.gitignore | 3 + winpr/libwinpr/clipboard/test/CMakeLists.txt | 25 ++ .../clipboard/test/TestClipboardFormats.c | 38 ++ 9 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 winpr/include/winpr/clipboard.h create mode 100644 winpr/libwinpr/clipboard/CMakeLists.txt create mode 100644 winpr/libwinpr/clipboard/ModuleOptions.cmake create mode 100644 winpr/libwinpr/clipboard/clipboard.c create mode 100644 winpr/libwinpr/clipboard/clipboard.h create mode 100644 winpr/libwinpr/clipboard/test/.gitignore create mode 100644 winpr/libwinpr/clipboard/test/CMakeLists.txt create mode 100644 winpr/libwinpr/clipboard/test/TestClipboardFormats.c diff --git a/winpr/include/winpr/clipboard.h b/winpr/include/winpr/clipboard.h new file mode 100644 index 000000000..3271f4280 --- /dev/null +++ b/winpr/include/winpr/clipboard.h @@ -0,0 +1,56 @@ +/** + * WinPR: Windows Portable Runtime + * Clipboard Functions + * + * Copyright 2014 Marc-Andre Moreau + * + * 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_H +#define WINPR_CLIPBOARD_H + +#include +#include + +typedef struct _wClipboard wClipboard; +typedef struct _wClipboardFormat wClipboardFormat; + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API void ClipboardLock(wClipboard* clipboard); +WINPR_API void ClipboardUnlock(wClipboard* clipboard); + +WINPR_API BOOL ClipboardEmpty(wClipboard* clipboard); +WINPR_API UINT32 ClipboardCountFormats(wClipboard* clipboard); +WINPR_API UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds); +WINPR_API UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name); + +WINPR_API const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId); +WINPR_API const void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize); +WINPR_API BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size); + +WINPR_API UINT64 ClipboardGetOwner(wClipboard* clipboard); +WINPR_API void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId); + +WINPR_API wClipboard* ClipboardCreate(); +WINPR_API void ClipboardDestroy(wClipboard* clipboard); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_CLIPBOARD_H */ + diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index 0b3c5d7dc..13d864efb 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -83,7 +83,7 @@ foreach(DIR ${WINPR_CORE}) endforeach() set(WINPR_LEVEL2 winsock sspi winhttp asn1 sspicli crt bcrypt rpc credui - wtsapi dsparse wnd smartcard nt) + wtsapi dsparse wnd smartcard nt clipboard) foreach(DIR ${WINPR_LEVEL2}) add_subdirectory(${DIR}) diff --git a/winpr/libwinpr/clipboard/CMakeLists.txt b/winpr/libwinpr/clipboard/CMakeLists.txt new file mode 100644 index 000000000..1b22e53f4 --- /dev/null +++ b/winpr/libwinpr/clipboard/CMakeLists.txt @@ -0,0 +1,23 @@ +# WinPR: Windows Portable Runtime +# libwinpr-clipboard cmake build script +# +# Copyright 2014 Marc-Andre Moreau +# +# 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( + clipboard.c) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/winpr/libwinpr/clipboard/ModuleOptions.cmake b/winpr/libwinpr/clipboard/ModuleOptions.cmake new file mode 100644 index 000000000..f8ebeaa1e --- /dev/null +++ b/winpr/libwinpr/clipboard/ModuleOptions.cmake @@ -0,0 +1,9 @@ + +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") + diff --git a/winpr/libwinpr/clipboard/clipboard.c b/winpr/libwinpr/clipboard/clipboard.c new file mode 100644 index 000000000..e3fbf25d9 --- /dev/null +++ b/winpr/libwinpr/clipboard/clipboard.c @@ -0,0 +1,350 @@ +/** + * WinPR: Windows Portable Runtime + * Clipboard Functions + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "clipboard.h" + +/** + * Clipboard (Windows): + * msdn.microsoft.com/en-us/library/windows/desktop/ms648709/ + * + * W3C Clipboard API and events: + * http://www.w3.org/TR/clipboard-apis/ + */ + +/** + * Synthesized Clipboard Formats + * + * Clipboard Format Conversion Format + * + * CF_BITMAP CF_DIB + * CF_BITMAP CF_DIBV5 + * CF_DIB CF_BITMAP + * CF_DIB CF_PALETTE + * CF_DIB CF_DIBV5 + * CF_DIBV5 CF_BITMAP + * CF_DIBV5 CF_DIB + * CF_DIBV5 CF_PALETTE + * CF_ENHMETAFILE CF_METAFILEPICT + * CF_METAFILEPICT CF_ENHMETAFILE + * CF_OEMTEXT CF_TEXT + * CF_OEMTEXT CF_UNICODETEXT + * CF_TEXT CF_OEMTEXT + * CF_TEXT CF_UNICODETEXT + * CF_UNICODETEXT CF_OEMTEXT + * CF_UNICODETEXT CF_TEXT + */ + +const char* CF_STANDARD_STRINGS[CF_MAX] = +{ + "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 */ +}; + +wClipboardFormat* ClipboardFindFormat(wClipboard* clipboard, UINT32 formatId, const char* name) +{ + UINT32 index; + wClipboardFormat* format = NULL; + + if (formatId) + { + for (index = 0; index < clipboard->numFormats; index++) + { + if (formatId == clipboard->formats[index].formatId) + { + format = &clipboard->formats[index]; + break; + } + } + } + else if (name) + { + for (index = 0; index < clipboard->numFormats; index++) + { + if (strcmp(name, clipboard->formats[index].formatName) == 0) + { + format = &clipboard->formats[index]; + break; + } + } + } + else + { + /* special "CF_RAW" case */ + + if (clipboard->numFormats > 0) + { + format = &clipboard->formats[0]; + + if (format->formatId) + return NULL; + + if (!format->formatName || (strcmp(format->formatName, CF_STANDARD_STRINGS[0]) == 0)) + return format; + } + } + + return format; +} + +void ClipboardLock(wClipboard* clipboard) +{ + EnterCriticalSection(&(clipboard->lock)); +} + +void ClipboardUnlock(wClipboard* clipboard) +{ + LeaveCriticalSection(&(clipboard->lock)); +} + +BOOL ClipboardEmpty(wClipboard* clipboard) +{ + if (clipboard->data) + { + free((void*) clipboard->data); + clipboard->data = NULL; + } + + clipboard->size = 0; + clipboard->sequenceNumber++; + + return TRUE; +} + +UINT32 ClipboardCountFormats(wClipboard* clipboard) +{ + return clipboard->numFormats; +} + +UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds) +{ + UINT32 index; + UINT32* pFormatIds; + wClipboardFormat* format; + + if (!ppFormatIds) + return 0; + + pFormatIds = *ppFormatIds; + + if (!pFormatIds) + { + pFormatIds = malloc(clipboard->numFormats * sizeof(UINT32)); + + if (!pFormatIds) + return 0; + + *ppFormatIds = pFormatIds; + } + + for (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; + + format = ClipboardFindFormat(clipboard, 0, name); + + if (format) + return format->formatId; + + if ((clipboard->numFormats + 1) >= clipboard->maxFormats) + { + clipboard->maxFormats *= 2; + + clipboard->formats = (wClipboardFormat*) realloc(clipboard->formats, + clipboard->maxFormats * sizeof(wClipboardFormat)); + + if (!clipboard->formats) + return 0; + } + + 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 ClipboardInitFormats(wClipboard* clipboard) +{ + UINT32 formatId = 0; + wClipboardFormat* format; + + for (formatId = 0; formatId < CF_MAX; formatId++) + { + format = &(clipboard->formats[clipboard->numFormats++]); + ZeroMemory(format, sizeof(wClipboardFormat)); + + format->formatId = formatId; + format->formatName = _strdup(CF_STANDARD_STRINGS[formatId]); + + if (!format->formatName) + return FALSE; + } + + return TRUE; +} + +const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId) +{ + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, formatId, NULL); + + if (!format) + return NULL; + + return format->formatName; +} + +const void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize) +{ + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, formatId, NULL); + + if (!format) + return NULL; + + *pSize = clipboard->size; + + return clipboard->data; +} + +BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size) +{ + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, formatId, NULL); + + if (!format) + return FALSE; + + free((void*) clipboard->data); + clipboard->data = data; + clipboard->size = size; + + clipboard->formatId = formatId; + clipboard->sequenceNumber++; + + return TRUE; +} + +UINT64 ClipboardGetOwner(wClipboard* clipboard) +{ + return clipboard->ownerId; +} + +void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId) +{ + clipboard->ownerId = ownerId; +} + +wClipboard* ClipboardCreate() +{ + wClipboard* clipboard; + + clipboard = (wClipboard*) calloc(1, sizeof(wClipboard)); + + if (clipboard) + { + clipboard->nextFormatId = 0xC000; + clipboard->sequenceNumber = 0; + + InitializeCriticalSectionAndSpinCount(&(clipboard->lock), 4000); + + clipboard->numFormats = 0; + clipboard->maxFormats = 64; + clipboard->formats = (wClipboardFormat*) malloc(clipboard->maxFormats * sizeof(wClipboardFormat)); + + if (!clipboard->formats) + { + free(clipboard); + return NULL; + } + + ClipboardInitFormats(clipboard); + } + + return clipboard; +} + +void ClipboardDestroy(wClipboard* clipboard) +{ + UINT32 index; + wClipboardFormat* format; + + if (!clipboard) + return; + + for (index = 0; index < clipboard->numFormats; index++) + { + format = &(clipboard->formats[index]); + free((void*) format->formatName); + } + + clipboard->numFormats = 0; + free(clipboard->formats); + + DeleteCriticalSection(&(clipboard->lock)); + + free(clipboard); +} diff --git a/winpr/libwinpr/clipboard/clipboard.h b/winpr/libwinpr/clipboard/clipboard.h new file mode 100644 index 000000000..f68f0250b --- /dev/null +++ b/winpr/libwinpr/clipboard/clipboard.h @@ -0,0 +1,52 @@ +/** + * WinPR: Windows Portable Runtime + * Clipboard Functions + * + * Copyright 2014 Marc-Andre Moreau + * + * 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 + +struct _wClipboardFormat +{ + UINT32 formatId; + const char* formatName; +}; + +struct _wClipboard +{ + UINT64 ownerId; + + /* clipboard formats */ + + UINT32 numFormats; + UINT32 maxFormats; + UINT32 nextFormatId; + wClipboardFormat* formats; + + /* clipboard data */ + + UINT32 size; + const void* data; + UINT32 formatId; + UINT32 sequenceNumber; + + CRITICAL_SECTION lock; +}; + +#endif /* WINPR_CLIPBOARD_PRIVATE_H */ diff --git a/winpr/libwinpr/clipboard/test/.gitignore b/winpr/libwinpr/clipboard/test/.gitignore new file mode 100644 index 000000000..87ac98143 --- /dev/null +++ b/winpr/libwinpr/clipboard/test/.gitignore @@ -0,0 +1,3 @@ +TestClipboard +TestClipboard.c + diff --git a/winpr/libwinpr/clipboard/test/CMakeLists.txt b/winpr/libwinpr/clipboard/test/CMakeLists.txt new file mode 100644 index 000000000..add603595 --- /dev/null +++ b/winpr/libwinpr/clipboard/test/CMakeLists.txt @@ -0,0 +1,25 @@ + +set(MODULE_NAME "TestClipboard") +set(MODULE_PREFIX "TEST_CLIPBOARD") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestClipboardFormats.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +target_link_libraries(${MODULE_NAME} winpr) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_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") diff --git a/winpr/libwinpr/clipboard/test/TestClipboardFormats.c b/winpr/libwinpr/clipboard/test/TestClipboardFormats.c new file mode 100644 index 000000000..6d040ec78 --- /dev/null +++ b/winpr/libwinpr/clipboard/test/TestClipboardFormats.c @@ -0,0 +1,38 @@ + +#include +#include + +int TestClipboardFormats(int argc, char* argv[]) +{ + UINT32 index; + UINT32 count; + UINT32 formatId; + UINT32* pFormatIds; + const char* formatName; + wClipboard* clipboard; + + clipboard = ClipboardCreate(); + + formatId = ClipboardRegisterFormat(clipboard, "UFT8_STRING"); + formatId = ClipboardRegisterFormat(clipboard, "text/html"); + formatId = ClipboardRegisterFormat(clipboard, "image/bmp"); + formatId = ClipboardRegisterFormat(clipboard, "image/png"); + + pFormatIds = NULL; + count = ClipboardGetFormatIds(clipboard, &pFormatIds); + + for (index = 0; index < count; index++) + { + formatId = pFormatIds[index]; + formatName = ClipboardGetFormatName(clipboard, formatId); + + fprintf(stderr, "Format: 0x%04X %s\n", formatId, formatName); + } + + free(pFormatIds); + + ClipboardDestroy(clipboard); + + return 0; +} +