diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index 415c5441b..94ec2bf89 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ RelWithDebInfo # Binaries *.a +*.o *.so *.so.* *.dylib @@ -105,6 +106,7 @@ client/DirectFB/dfreerdp server/Sample/sfreerdp-server server/X11/xfreerdp-server xcode +libfreerdp/codec/test/TestOpenH264ASM # Other *~ @@ -113,6 +115,7 @@ Release Win32 build*/ *.orig +*.msrcIncident default.log *Amplifier XE* @@ -122,3 +125,6 @@ default.log *.txt.user *.autosave + +# etags +TAGS diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index 07653d65c..2b71fd2b8 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ include(GNUInstallDirsWrapper) include(CMakePackageConfigHelpers) # Soname versioning +set(WITH_LIBRARY_VERSIONING "ON") set(FREERDP_VERSION_MAJOR "1") set(FREERDP_VERSION_MINOR "2") set(FREERDP_VERSION_REVISION "0") @@ -232,9 +233,23 @@ endif() if(WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUNICODE -D_UNICODE") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WIN32_WINNT=0x0501") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN") + + if(NOT DEFINED CMAKE_WINDOWS_VERSION) + set(CMAKE_WINDOWS_VERSION "WINXP") + endif() + + if(CMAKE_WINDOWS_VERSION STREQUAL "WINXP") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501") + elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN7") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601") + elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN8") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602") + endif() endif() if(IOS) @@ -248,6 +263,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINPR_EXPORTS -DFREERDP_EXPORTS") if(NOT IOS) check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(unistd.h HAVE_UNISTD_H) + check_include_files(execinfo.h HAVE_EXECINFO_H) check_include_files(stdint.h HAVE_STDINT_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(sys/modem.h HAVE_SYS_MODEM_H) @@ -301,6 +317,8 @@ endif(APPLE) # Android if(ANDROID) + set(WITH_LIBRARY_VERSIONING "OFF") + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") add_definitions(-DNDK_DEBUG=1) @@ -369,9 +387,12 @@ if(UNIX OR CYGWIN) check_include_files(sys/eventfd.h HAVE_AIO_H) check_include_files(sys/eventfd.h HAVE_EVENTFD_H) check_include_files(sys/timerfd.h HAVE_TIMERFD_H) + check_include_files(poll.h HAVE_POLL_H) set(X11_FEATURE_TYPE "RECOMMENDED") + set(WAYLAND_FEATURE_TYPE "RECOMMENDED") else() set(X11_FEATURE_TYPE "DISABLED") + set(WAYLAND_FEATURE_TYPE "DISABLED") endif() if(WITH_PCSC_WINPR) @@ -381,6 +402,9 @@ endif() set(X11_FEATURE_PURPOSE "X11") set(X11_FEATURE_DESCRIPTION "X11 client and server") +set(WAYLAND_FEATURE_PURPOSE "Wayland") +set(WAYLAND_FEATURE_DESCRIPTION "Wayland client") + set(DIRECTFB_FEATURE_TYPE "OPTIONAL") set(DIRECTFB_FEATURE_PURPOSE "DirectFB") set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client") @@ -433,12 +457,17 @@ set(JPEG_FEATURE_TYPE "OPTIONAL") set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_DESCRIPTION "use JPEG library") +set(OPENH264_FEATURE_TYPE "OPTIONAL") +set(OPENH264_FEATURE_PURPOSE "codec") +set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") + set(GSM_FEATURE_TYPE "OPTIONAL") set(GSM_FEATURE_PURPOSE "codec") set(GSM_FEATURE_DESCRIPTION "GSM audio codec library") if(WIN32) set(X11_FEATURE_TYPE "DISABLED") + set(WAYLAND_FEATURE_TYPE "DISABLED") set(ZLIB_FEATURE_TYPE "DISABLED") set(DIRECTFB_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") @@ -456,6 +485,7 @@ if(APPLE) set(FFMPEG_FEATURE_TYPE "OPTIONAL") set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL") set(X11_FEATURE_TYPE "OPTIONAL") + set(WAYLAND_FEATURE_TYPE "DISABLED") if(IOS) set(X11_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") @@ -470,6 +500,7 @@ endif() if(ANDROID) set(X11_FEATURE_TYPE "DISABLED") + set(WAYLAND_FEATURE_TYPE "DISABLED") set(DIRECTFB_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") @@ -483,6 +514,7 @@ endif() find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION}) +find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION}) find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION}) if (${WITH_DIRECTFB}) message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details") @@ -504,6 +536,7 @@ find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEAT find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) +find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) if(TARGET_ARCH MATCHES "x86|x64") @@ -608,6 +641,12 @@ if (IOS) endif() endif() +# RdTk +include_directories("${CMAKE_SOURCE_DIR}/rdtk/include") +include_directories("${CMAKE_BINARY_DIR}/rdtk/include") + +add_subdirectory(rdtk) + if(WITH_CLIENT) add_subdirectory(client) endif() @@ -625,7 +664,9 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") set(FREERDP_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP") set(FREERDP_INCLUDE_DIR "include") - set(FREERDP_MONOLITHIC_BUILD ${MONOLITHIC_BUILD}) + + # keep for legacy builds + set(FREERDP_MONOLITHIC_BUILD OFF) configure_package_config_file(FreeRDPConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfig.cmake INSTALL_DESTINATION ${FREERDP_CMAKE_INSTALL_DIR} @@ -657,27 +698,11 @@ endif() include(${CMAKE_CPACK_INCLUDE_FILE}) -if(MONOLITHIC_BUILD) - set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client") - set(WINPR_PC_LIBS "-lwinpr") - if (WITH_SERVER) - set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server") - endif() -else(MONOLITHIC_BUILD) - # freerdp exports - get_property(MEXPORTS GLOBAL PROPERTY "freerdp_EXPORTS") - foreach(EXPORT_MODULE ${MEXPORTS}) - list(APPEND FREERDP_PC_LIBS "-lfreerdp-${EXPORT_MODULE}") - endforeach() - string(REPLACE ";" " " FREERDP_PC_LIBS "${FREERDP_PC_LIBS}") - - # winpr exports - get_property(MEXPORTS GLOBAL PROPERTY "winpr_EXPORTS") - foreach(EXPORT_MODULE ${MEXPORTS}) - list(APPEND WINPR_PC_LIBS "-lwinpr-${EXPORT_MODULE}") - endforeach() - string(REPLACE ";" " " WINPR_PC_LIBS "${WINPR_PC_LIBS}") -endif(MONOLITHIC_BUILD) +set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client") +set(WINPR_PC_LIBS "-lwinpr") +if (WITH_SERVER) + set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server") +endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/winpr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc @ONLY) diff --git a/channels/audin/client/CMakeLists.txt b/channels/audin/client/CMakeLists.txt index e126eab0d..52b73e12e 100644 --- a/channels/audin/client/CMakeLists.txt +++ b/channels/audin/client/CMakeLists.txt @@ -27,12 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/audin/client/alsa/CMakeLists.txt b/channels/audin/client/alsa/CMakeLists.txt index e5d1dfaf1..892a263d2 100644 --- a/channels/audin/client/alsa/CMakeLists.txt +++ b/channels/audin/client/alsa/CMakeLists.txt @@ -27,12 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES}) +set(${MODULE_PREFIX}_LIBS freerdp ${ALSA_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index e8b7259a7..d75435407 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -72,8 +72,8 @@ static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_hand if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0) { - DEBUG_WARN("snd_pcm_hw_params_malloc (%s)", - snd_strerror(error)); + WLog_ERR(TAG, "snd_pcm_hw_params_malloc (%s)", + snd_strerror(error)); return FALSE; } @@ -206,7 +206,7 @@ static void* audin_alsa_thread_func(void* arg) { if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { - DEBUG_WARN("snd_pcm_open (%s)", snd_strerror(error)); + WLog_ERR(TAG, "snd_pcm_open (%s)", snd_strerror(error)); break; } @@ -226,7 +226,7 @@ static void* audin_alsa_thread_func(void* arg) } else if (error < 0) { - DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error)); + WLog_ERR(TAG, "snd_pcm_readi (%s)", snd_strerror(error)); break; } diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 38e7625bd..15ee80d33 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -133,7 +133,7 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w DEBUG_DVC("NumFormats %d", NumFormats); if ((NumFormats < 1) || (NumFormats > 1000)) { - DEBUG_WARN("bad NumFormats %d", NumFormats); + WLog_ERR(TAG, "bad NumFormats %d", NumFormats); return 1; } Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ @@ -262,8 +262,8 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStr if (initialFormat >= (UINT32) callback->formats_count) { - DEBUG_WARN("invalid format index %d (total %d)", - initialFormat, callback->formats_count); + WLog_ERR(TAG, "invalid format index %d (total %d)", + initialFormat, callback->formats_count); return 1; } @@ -293,8 +293,8 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb if (NewFormat >= (UINT32) callback->formats_count) { - DEBUG_WARN("invalid format index %d (total %d)", - NewFormat, callback->formats_count); + WLog_ERR(TAG, "invalid format index %d (total %d)", + NewFormat, callback->formats_count); return 1; } @@ -340,7 +340,7 @@ static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, break; default: - DEBUG_WARN("unknown MessageId=0x%x", MessageId); + WLog_ERR(TAG, "unknown MessageId=0x%x", MessageId); error = 1; break; } @@ -429,7 +429,7 @@ static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi if (audin->device) { - DEBUG_WARN("existing device, abort."); + WLog_ERR(TAG, "existing device, abort."); return; } @@ -454,7 +454,7 @@ static BOOL audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI if (entry(&entryPoints) != 0) { - DEBUG_WARN("%s entry returns error.", name); + WLog_ERR(TAG, "%s entry returns error.", name); return FALSE; } @@ -613,7 +613,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (audin->device == NULL) { - DEBUG_WARN("no sound device."); + WLog_ERR(TAG, "no sound device."); } return error; diff --git a/channels/audin/client/audin_main.h b/channels/audin/client/audin_main.h index 985532b54..05dd637a0 100644 --- a/channels/audin/client/audin_main.h +++ b/channels/audin/client/audin_main.h @@ -27,13 +27,15 @@ #include #include #include -#include +#include #include +#define TAG CHANNELS_TAG("audin.client") + #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif #endif /* FREERDP_AUDIN_CLIENT_MAIN_H */ diff --git a/channels/audin/client/opensles/CMakeLists.txt b/channels/audin/client/opensles/CMakeLists.txt index ff872e69d..cd34e712b 100644 --- a/channels/audin/client/opensles/CMakeLists.txt +++ b/channels/audin/client/opensles/CMakeLists.txt @@ -28,14 +28,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils - ${OPENSLES_LIBRARIES} - ) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES}) +set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 50dbc19d8..54d601d20 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -96,7 +96,7 @@ static void* audin_opensles_thread_func(void* arg) int rc = android_RecIn(opensles->stream, buffer.s, raw_size); if (rc < 0) { - DEBUG_WARN("android_RecIn %d", rc); + WLog_ERR(TAG, "android_RecIn %d", rc); continue; } @@ -250,9 +250,9 @@ static void audin_opensles_set_format(IAudinDevice* device, break; default: - DEBUG_WARN("Encoding '%d' [%08X] not supported", - (format->wFormatTag), - format->wFormatTag); + WLog_ERR(TAG, "Encoding '%d' [%08X] not supported", + (format->wFormatTag), + format->wFormatTag); return; } @@ -309,7 +309,7 @@ static void audin_opensles_close(IAudinDevice* device) * ignore duplicate requests. */ if (!opensles->stopEvent) { - DEBUG_WARN("[ERROR] function called without matching open."); + WLog_ERR(TAG, "[ERROR] function called without matching open."); return; } diff --git a/channels/audin/client/opensles/opensl_io.c b/channels/audin/client/opensles/opensl_io.c index dda834b69..5b650be87 100644 --- a/channels/audin/client/opensles/opensl_io.c +++ b/channels/audin/client/opensles/opensl_io.c @@ -362,7 +362,7 @@ int android_RecIn(OPENSL_STREAM *p,short *buffer,int size) e = Queue_Dequeue(p->queue); if (!e) { - DEBUG_WARN("[ERROR] got e=%p from queue", e); + WLog_ERR(TAG, "[ERROR] got e=%p from queue", e); return -1; } diff --git a/channels/audin/client/pulse/CMakeLists.txt b/channels/audin/client/pulse/CMakeLists.txt index f0ddd34a2..bdbaa5b5f 100644 --- a/channels/audin/client/pulse/CMakeLists.txt +++ b/channels/audin/client/pulse/CMakeLists.txt @@ -27,12 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY}) +set(${MODULE_PREFIX}_LIBS freerdp ${PULSE_LIBRARY}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index b731c2246..90e9cdb7c 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -94,16 +94,16 @@ static BOOL audin_pulse_connect(IAudinDevice* device) if (pa_context_connect(pulse->context, NULL, 0, NULL)) { - DEBUG_WARN("pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_context_connect failed (%d)", + pa_context_errno(pulse->context)); return FALSE; } pa_threaded_mainloop_lock(pulse->mainloop); if (pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_WARN("pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", + pa_context_errno(pulse->context)); return FALSE; } for (;;) @@ -113,8 +113,8 @@ static BOOL audin_pulse_connect(IAudinDevice* device) break; if (!PA_CONTEXT_IS_GOOD(state)) { - DEBUG_WARN("bad context state (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "bad context state (%d)", + pa_context_errno(pulse->context)); break; } pa_threaded_mainloop_wait(pulse->mainloop); @@ -297,7 +297,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length */ if (pulse->buffer == NULL) { - /* fprintf(stderr, "%s: ignoring input, pulse buffer not ready.\n", __func__); */ + /* WLog_ERR(TAG, "%s: ignoring input, pulse buffer not ready.\n", __func__); */ return; } @@ -415,8 +415,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u &buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_WARN("pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", + pa_context_errno(pulse->context)); return; } @@ -427,8 +427,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u break; if (!PA_STREAM_IS_GOOD(state)) { - DEBUG_WARN("bad stream state (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "bad stream state (%d)", + pa_context_errno(pulse->context)); break; } pa_threaded_mainloop_wait(pulse->mainloop); @@ -512,7 +512,7 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt if (!pulse->mainloop) { - DEBUG_WARN("pa_threaded_mainloop_new failed"); + WLog_ERR(TAG, "pa_threaded_mainloop_new failed"); audin_pulse_free((IAudinDevice*) pulse); return 1; } @@ -521,7 +521,7 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt if (!pulse->context) { - DEBUG_WARN("pa_context_new failed"); + WLog_ERR(TAG, "pa_context_new failed"); audin_pulse_free((IAudinDevice*) pulse); return 1; } diff --git a/channels/audin/client/winmm/CMakeLists.txt b/channels/audin/client/winmm/CMakeLists.txt index 10db102ad..f4adaddc7 100644 --- a/channels/audin/client/winmm/CMakeLists.txt +++ b/channels/audin/client/winmm/CMakeLists.txt @@ -26,12 +26,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib) +set(${MODULE_PREFIX}_LIBS freerdp winmm.lib) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/server/CMakeLists.txt b/channels/audin/server/CMakeLists.txt index e23d33192..c093ec538 100644 --- a/channels/audin/server/CMakeLists.txt +++ b/channels/audin/server/CMakeLists.txt @@ -24,12 +24,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index 9f7506abb..3f6e1ab0c 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -34,7 +34,9 @@ #include #include #include +#include +#define TAG CHANNELS_TAG("audin.server") #define MSG_SNDIN_VERSION 0x01 #define MSG_SNDIN_FORMATS 0x02 #define MSG_SNDIN_OPEN 0x03 @@ -345,24 +347,16 @@ static void* audin_server_thread_func(void* arg) Stream_SetPosition(s, 0); + WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned); + if (BytesReturned < 1) + continue; + Stream_EnsureRemainingCapacity(s, BytesReturned); if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { - if (BytesReturned == 0) - break; - - Stream_EnsureRemainingCapacity(s, BytesReturned); - - if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), - Stream_Capacity(s), &BytesReturned) == FALSE) - { - break; - } + break; } - if (BytesReturned < 1) - continue; - Stream_Read_UINT8(s, MessageId); BytesReturned--; @@ -393,7 +387,7 @@ static void* audin_server_thread_func(void* arg) break; default: - fprintf(stderr, "audin_server_thread_func: unknown MessageId %d\n", MessageId); + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %d\n", MessageId); break; } } diff --git a/channels/client/CMakeLists.txt b/channels/client/CMakeLists.txt index 05cb34697..049bc7b0c 100644 --- a/channels/client/CMakeLists.txt +++ b/channels/client/CMakeLists.txt @@ -96,15 +96,7 @@ set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NUL configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-path winpr-file winpr-synch winpr-library winpr-interlocked) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp winpr) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) diff --git a/channels/cliprdr/client/CMakeLists.txt b/channels/cliprdr/client/CMakeLists.txt index 4df74c706..e23861515 100644 --- a/channels/cliprdr/client/CMakeLists.txt +++ b/channels/cliprdr/client/CMakeLists.txt @@ -27,15 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt) +set(${MODULE_PREFIX}_LIBS freerdp winpr) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 4389f5f58..c50e7058a 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -140,7 +140,7 @@ void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT } if (num_formats * 36 != length) - DEBUG_WARN("dataLen %d not divided by 36!", length); + WLog_ERR(TAG, "dataLen %d not divided by 36!", length); ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE; @@ -225,7 +225,7 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data formatList.msgFlags = msgFlags; formatList.dataLen = dataLen; - formatList.cFormats = 0; + formatList.numFormats = 0; while (dataLen) { @@ -235,14 +235,14 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s)); Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); - formatList.cFormats++; + formatList.numFormats++; } index = 0; dataLen = formatList.dataLen; Stream_Rewind(s, dataLen); - formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats); + formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.numFormats); formatList.formats = formats; while (dataLen) @@ -270,10 +270,13 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data index++; } + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d", + formatList.numFormats); + if (context->ServerFormatList) context->ServerFormatList(context, &formatList); - for (index = 0; index < formatList.cFormats; index++) + for (index = 0; index < formatList.numFormats; index++) free(formats[index].formatName); free(formats); @@ -315,9 +318,9 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data switch (format) { - case CB_FORMAT_TEXT: - case CB_FORMAT_DIB: - case CB_FORMAT_UNICODETEXT: + case CF_TEXT: + case CF_DIB: + case CF_UNICODETEXT: break; default: @@ -367,6 +370,9 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data cliprdr->num_format_names = 0; + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d", + cb_event->num_formats); + cliprdr_send_format_list_response(cliprdr); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); } @@ -376,6 +382,8 @@ void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse"); + /* http://msdn.microsoft.com/en-us/library/hh872154.aspx */ if (context->custom) @@ -406,6 +414,8 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest"); + if (context->custom) { CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; @@ -465,6 +475,8 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse"); + if (context->custom) { CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse; diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 7a7907021..2ec90b602 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -63,13 +63,11 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr) wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen) { wStream* s; - s = Stream_New(NULL, dataLen + 8); Stream_Write_UINT16(s, msgType); Stream_Write_UINT16(s, msgFlags); /* Write actual length after the entire packet has been constructed. */ Stream_Seek(s, 4); - return s; } @@ -77,18 +75,15 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) { int pos; UINT32 dataLen; - pos = Stream_GetPosition(s); dataLen = pos - 8; Stream_SetPosition(s, 4); Stream_Write_UINT32(s, dataLen); Stream_SetPosition(s, pos); - #ifdef WITH_DEBUG_CLIPRDR - printf("Cliprdr Sending (%d bytes)\n", dataLen + 8); - winpr_HexDump(Stream_Buffer(s), dataLen + 8); + WLog_DBG(TAG, "Cliprdr Sending (%d bytes)", dataLen + 8); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8); #endif - svc_plugin_send((rdpSvcPlugin*) cliprdr, s); } @@ -99,18 +94,21 @@ static void cliprdr_process_connect(rdpSvcPlugin* plugin) void cliprdr_print_general_capability_flags(UINT32 flags) { - fprintf(stderr, "generalFlags (0x%08X) {\n", flags); + WLog_INFO(TAG, "generalFlags (0x%08X) {", flags); if (flags & CB_USE_LONG_FORMAT_NAMES) - fprintf(stderr, "\tCB_USE_LONG_FORMAT_NAMES\n"); - if (flags & CB_STREAM_FILECLIP_ENABLED) - fprintf(stderr, "\tCB_STREAM_FILECLIP_ENABLED\n"); - if (flags & CB_FILECLIP_NO_FILE_PATHS) - fprintf(stderr, "\tCB_FILECLIP_NO_FILE_PATHS\n"); - if (flags & CB_CAN_LOCK_CLIPDATA) - fprintf(stderr, "\tCB_CAN_LOCK_CLIPDATA\n"); + WLog_INFO(TAG, "\tCB_USE_LONG_FORMAT_NAMES"); - fprintf(stderr, "}\n"); + if (flags & CB_STREAM_FILECLIP_ENABLED) + WLog_INFO(TAG, "\tCB_STREAM_FILECLIP_ENABLED"); + + if (flags & CB_FILECLIP_NO_FILE_PATHS) + WLog_INFO(TAG, "\tCB_FILECLIP_NO_FILE_PATHS"); + + if (flags & CB_CAN_LOCK_CLIPDATA) + WLog_INFO(TAG, "\tCB_CAN_LOCK_CLIPDATA"); + + WLog_INFO(TAG, "}"); } static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s) @@ -118,14 +116,10 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* UINT32 version; UINT32 generalFlags; CliprdrClientContext* context; - context = cliprdr_get_client_interface(cliprdr); - Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ - DEBUG_CLIPRDR("Version: %d", version); - #ifdef WITH_DEBUG_CLIPRDR cliprdr_print_general_capability_flags(generalFlags); #endif @@ -148,13 +142,10 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* { CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - capabilities.cCapabilitiesSets = 1; capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); - generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; generalCapabilitySet.capabilitySetLength = 12; - generalCapabilitySet.version = version; generalCapabilitySet.generalFlags = generalFlags; @@ -164,10 +155,8 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* else { RDP_CB_CLIP_CAPS* caps_event; - caps_event = (RDP_CB_CLIP_CAPS*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL); caps_event->capabilities = generalFlags; - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) caps_event); } } @@ -178,11 +167,10 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 UINT16 lengthCapability; UINT16 cCapabilitiesSets; UINT16 capabilitySetType; - Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ - DEBUG_CLIPRDR("cCapabilitiesSets %d", cCapabilitiesSets); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities"); for (i = 0; i < cCapabilitiesSets; i++) { @@ -194,9 +182,8 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 case CB_CAPSTYPE_GENERAL: cliprdr_process_general_capability(cliprdr, s); break; - default: - DEBUG_WARN("unknown cliprdr capability set: %d", capabilitySetType); + WLog_ERR(TAG, "unknown cliprdr capability set: %d", capabilitySetType); break; } } @@ -206,25 +193,20 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr) { wStream* s; UINT32 flags; - s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); - DEBUG_CLIPRDR("Sending Capabilities"); - flags = CB_USE_LONG_FORMAT_NAMES #ifdef _WIN32 | CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS #endif - ; - + ; Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */ Stream_Write_UINT16(s, 0); /* pad1 */ Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType */ Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability */ Stream_Write_UINT32(s, CB_CAPS_VERSION_2); /* version */ Stream_Write_UINT32(s, flags); /* generalFlags */ - cliprdr_packet_send(cliprdr, s); } @@ -232,10 +214,11 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); + WLog_Print(cliprdr->log, WLOG_DEBUG, "MonitorReady"); + if (context->custom) { CLIPRDR_MONITOR_READY monitorReady; - monitorReady.msgType = CB_MONITOR_READY; monitorReady.msgFlags = flags; monitorReady.dataLen = length; @@ -251,7 +234,6 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI cliprdr_send_clip_caps(cliprdr); event = (RDP_CB_MONITOR_READY_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event); } } @@ -260,8 +242,10 @@ static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream { RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event; + WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest"); + cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FilecontentsRequest, NULL, NULL); + CliprdrChannel_FilecontentsRequest, NULL, NULL); Stream_Read_UINT32(s, cb_event->streamId); Stream_Read_UINT32(s, cb_event->lindex); @@ -270,7 +254,6 @@ static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream Stream_Read_UINT32(s, cb_event->nPositionHigh); Stream_Read_UINT32(s, cb_event->cbRequested); //Stream_Read_UINT32(s, cb_event->clipDataId); - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); } @@ -278,8 +261,10 @@ static void cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStrea { RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event; + WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse"); + cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FilecontentsResponse, NULL, NULL); + CliprdrChannel_FilecontentsResponse, NULL, NULL); Stream_Read_UINT32(s, cb_event->streamId); @@ -297,8 +282,10 @@ static void cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UI { RDP_CB_LOCK_CLIPDATA_EVENT* cb_event; + WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData"); + cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_LockClipdata, NULL, NULL); + CliprdrChannel_LockClipdata, NULL, NULL); Stream_Read_UINT32(s, cb_event->clipDataId); @@ -309,8 +296,10 @@ static void cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, { RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event; + WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData"); + cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_UnLockClipdata, NULL, NULL); + CliprdrChannel_UnLockClipdata, NULL, NULL); Stream_Read_UINT32(s, cb_event->clipDataId); @@ -323,16 +312,14 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) UINT16 msgFlags; UINT32 dataLen; cliprdrPlugin* cliprdr = (cliprdrPlugin*) plugin; - Stream_Read_UINT16(s, msgType); Stream_Read_UINT16(s, msgFlags); Stream_Read_UINT32(s, dataLen); DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d", - CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); - + CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); #ifdef WITH_DEBUG_CLIPRDR - winpr_HexDump(Stream_Buffer(s), dataLen + 8); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8); #endif switch (msgType) @@ -340,56 +327,44 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) case CB_CLIP_CAPS: cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags); break; - case CB_MONITOR_READY: cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags); break; - case CB_FORMAT_LIST: cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags); break; - case CB_FORMAT_LIST_RESPONSE: cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags); break; - case CB_FORMAT_DATA_REQUEST: cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags); break; - case CB_FORMAT_DATA_RESPONSE: cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags); break; - case CB_FILECONTENTS_REQUEST: cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags); break; - case CB_FILECONTENTS_RESPONSE: cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags); break; - case CB_LOCK_CLIPDATA: cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags); break; - case CB_UNLOCK_CLIPDATA: cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags); break; - default: - DEBUG_WARN("unknown msgType %d", msgType); + WLog_ERR(TAG, "unknown msgType %d", msgType); break; } } -static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_REQUEST_EVENT * event) +static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_REQUEST_EVENT* event) { - wStream *s; + wStream* s; DEBUG_CLIPRDR("Sending File Contents Request."); - s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 24); - Stream_Write_UINT32(s, event->streamId); Stream_Write_UINT32(s, event->lindex); Stream_Write_UINT32(s, event->dwFlags); @@ -397,14 +372,12 @@ static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RD Stream_Write_UINT32(s, event->nPositionHigh); Stream_Write_UINT32(s, event->cbRequested); //Stream_Write_UINT32(s, event->clipDataId); - cliprdr_packet_send(plugin, s); } -static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_RESPONSE_EVENT * event) +static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_RESPONSE_EVENT* event) { wStream* s; - DEBUG_CLIPRDR("Sending file contents response with size = %d", event->size); if (event->size > 0) @@ -421,39 +394,30 @@ static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, R cliprdr_packet_send(plugin, s); } -static void cliprdr_process_lock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_LOCK_CLIPDATA_EVENT * event) +static void cliprdr_process_lock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_LOCK_CLIPDATA_EVENT* event) { wStream* s; - DEBUG_CLIPRDR("Sending Lock Request"); - s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); Stream_Write_UINT32(s, event->clipDataId); - cliprdr_packet_send(plugin, s); } -static void cliprdr_process_unlock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_UNLOCK_CLIPDATA_EVENT * event) +static void cliprdr_process_unlock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_UNLOCK_CLIPDATA_EVENT* event) { wStream* s; - DEBUG_CLIPRDR("Sending UnLock Request"); - s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); Stream_Write_UINT32(s, event->clipDataId); - cliprdr_packet_send(plugin, s); } -static void cliprdr_process_tempdir_event(cliprdrPlugin* plugin, RDP_CB_TEMPDIR_EVENT * event) +static void cliprdr_process_tempdir_event(cliprdrPlugin* plugin, RDP_CB_TEMPDIR_EVENT* event) { wStream* s; - DEBUG_CLIPRDR("Sending Temporary Directory."); s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 520); - Stream_Write(s, event->dirname, 520); - cliprdr_packet_send(plugin, s); } @@ -464,37 +428,29 @@ static void cliprdr_process_event(rdpSvcPlugin* plugin, wMessage* event) case CliprdrChannel_FormatList: cliprdr_process_format_list_event((cliprdrPlugin*) plugin, (RDP_CB_FORMAT_LIST_EVENT*) event); break; - case CliprdrChannel_DataRequest: cliprdr_process_format_data_request_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_REQUEST_EVENT*) event); break; - case CliprdrChannel_DataResponse: cliprdr_process_format_data_response_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_RESPONSE_EVENT*) event); break; - case CliprdrChannel_FilecontentsRequest: - cliprdr_process_filecontents_request_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_REQUEST_EVENT *) event); + cliprdr_process_filecontents_request_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_REQUEST_EVENT*) event); break; - case CliprdrChannel_FilecontentsResponse: - cliprdr_process_filecontents_response_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_RESPONSE_EVENT *) event); + cliprdr_process_filecontents_response_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) event); break; - case CliprdrChannel_LockClipdata: - cliprdr_process_lock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_LOCK_CLIPDATA_EVENT *) event); + cliprdr_process_lock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_LOCK_CLIPDATA_EVENT*) event); break; - case CliprdrChannel_UnLockClipdata: - cliprdr_process_unlock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_UNLOCK_CLIPDATA_EVENT *) event); + cliprdr_process_unlock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_UNLOCK_CLIPDATA_EVENT*) event); break; - case CliprdrChannel_TemporaryDirectory: - cliprdr_process_tempdir_event((cliprdrPlugin*) plugin, (RDP_CB_TEMPDIR_EVENT *) event); + cliprdr_process_tempdir_event((cliprdrPlugin*) plugin, (RDP_CB_TEMPDIR_EVENT*) event); break; - default: - DEBUG_WARN("unknown event type %d", GetMessageType(event->id)); + WLog_ERR(TAG, "unknown event type %d", GetMessageType(event->id)); break; } @@ -523,12 +479,12 @@ int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILIT Stream_Write_UINT16(s, 0); /* pad1 */ generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilities->capabilitySets; - Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */ Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */ Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */ Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */ + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities"); cliprdr_packet_send(cliprdr, s); return 0; @@ -543,12 +499,10 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS CLIPRDR_FORMAT* format; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - for (index = 0; index < formatList->cFormats; index++) + for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); - length += 4; - formatNameSize = 2; if (format->formatName) @@ -559,23 +513,19 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); - for (index = 0; index < formatList->cFormats; index++) + for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ if (format->formatName) { int cchWideChar; LPWSTR lpWideCharStr; - lpWideCharStr = (LPWSTR) Stream_Pointer(s); cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, - format->formatName, -1, lpWideCharStr, cchWideChar) * 2; - + format->formatName, -1, lpWideCharStr, cchWideChar) * 2; Stream_Seek(s, formatNameSize); } else @@ -584,6 +534,8 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS } } + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %d", + formatList->numFormats); cliprdr_packet_send(cliprdr, s); return 0; @@ -598,6 +550,8 @@ int cliprdr_client_format_list_response(CliprdrClientContext* context, CLIPRDR_F formatListResponse->dataLen = 0; s = cliprdr_packet_new(formatListResponse->msgType, formatListResponse->msgFlags, formatListResponse->dataLen); + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatListResponse"); cliprdr_packet_send(cliprdr, s); return 0; @@ -615,6 +569,7 @@ int cliprdr_client_format_data_request(CliprdrClientContext* context, CLIPRDR_FO s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, formatDataRequest->dataLen); Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */ + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataRequest"); cliprdr_packet_send(cliprdr, s); return 0; @@ -628,8 +583,10 @@ int cliprdr_client_format_data_response(CliprdrClientContext* context, CLIPRDR_F formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE; s = cliprdr_packet_new(formatDataResponse->msgType, formatDataResponse->msgFlags, formatDataResponse->dataLen); + Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataResponse"); cliprdr_packet_send(cliprdr, s); return 0; @@ -647,13 +604,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) cliprdr = (cliprdrPlugin*) calloc(1, sizeof(cliprdrPlugin)); cliprdr->plugin.channel_def.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP | - CHANNEL_OPTION_SHOW_PROTOCOL; + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | + CHANNEL_OPTION_SHOW_PROTOCOL; strcpy(cliprdr->plugin.channel_def.name, "cliprdr"); + cliprdr->log = WLog_Get("com.freerdp.channels.cliprdr.client"); + cliprdr->plugin.connect_callback = cliprdr_process_connect; cliprdr->plugin.receive_callback = cliprdr_process_receive; cliprdr->plugin.event_callback = cliprdr_process_event; @@ -665,19 +624,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { context = (CliprdrClientContext*) calloc(1, sizeof(CliprdrClientContext)); - context->handle = (void*) cliprdr; - context->ClientCapabilities = cliprdr_client_capabilities; context->ClientFormatList = cliprdr_client_format_list; context->ClientFormatListResponse = cliprdr_client_format_list_response; context->ClientFormatDataRequest = cliprdr_client_format_data_request; context->ClientFormatDataResponse = cliprdr_client_format_data_response; - *(pEntryPointsEx->ppInterface) = (void*) context; } svc_plugin_init((rdpSvcPlugin*) cliprdr, pEntryPoints); - return 1; } diff --git a/channels/cliprdr/client/cliprdr_main.h b/channels/cliprdr/client/cliprdr_main.h index 9aec3348a..050de26b0 100644 --- a/channels/cliprdr/client/cliprdr_main.h +++ b/channels/cliprdr/client/cliprdr_main.h @@ -23,12 +23,16 @@ #include -#include +#include #include +#define TAG CHANNELS_TAG("cliprdr.client") + struct cliprdr_plugin { rdpSvcPlugin plugin; + + wLog* log; BOOL received_caps; BOOL use_long_format_names; BOOL stream_fileclip_enabled; @@ -45,9 +49,9 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out); CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr); #ifdef WITH_DEBUG_CLIPRDR -#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(CLIPRDR, fmt, ## __VA_ARGS__) +#define DEBUG_CLIPRDR(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_CLIPRDR(fmt, ...) do { } while (0) #endif #endif /* __CLIPRDR_MAIN_H */ diff --git a/channels/cliprdr/server/CMakeLists.txt b/channels/cliprdr/server/CMakeLists.txt index 5abc3d511..0375f6d53 100644 --- a/channels/cliprdr/server/CMakeLists.txt +++ b/channels/cliprdr/server/CMakeLists.txt @@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 0e94fabea..4d20e4ada 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -25,6 +25,7 @@ #include #include +#include #include "cliprdr_main.h" /** @@ -69,9 +70,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context) UINT32 generalFlags; CLIPRDR_HEADER header; ULONG written; - - printf("CliprdrServerSendCapabilities\n"); - + WLog_DBG(TAG, "CliprdrServerSendCapabilities"); header.msgType = CB_CLIP_CAPS; header.msgFlags = 0; header.dataLen = 16; @@ -110,9 +109,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context) BOOL status; CLIPRDR_HEADER header; ULONG written; - - printf("CliprdrServerSendMonitorReady\n"); - + WLog_DBG(TAG, "CliprdrServerSendMonitorReady"); header.msgType = CB_MONITOR_READY; header.msgFlags = 0; header.dataLen = 0; @@ -138,9 +135,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex BOOL status; CLIPRDR_HEADER header; ULONG written; - - printf("CliprdrServerSendFormatListResponse\n"); - + WLog_DBG(TAG, "CliprdrServerSendFormatListResponse"); header.msgType = CB_FORMAT_LIST_RESPONSE; header.msgFlags = CB_RESPONSE_OK; header.dataLen = 0; @@ -205,10 +200,8 @@ static int cliprdr_server_receive_temporary_directory(CliprdrServerContext* cont return -1; ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, - &(context->priv->ClientTemporaryDirectory), 0, NULL, NULL); - - printf("ClientTemporaryDirectory: %s\n", context->priv->ClientTemporaryDirectory); - + &(context->priv->ClientTemporaryDirectory), 0, NULL, NULL); + WLog_DBG(TAG, "ClientTemporaryDirectory: %s", context->priv->ClientTemporaryDirectory); return 0; } @@ -251,9 +244,7 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context WCHAR* end; int length; int position; - - printf("%s\n", __FUNCTION__); - + WLog_DBG(TAG, ""); position = Stream_GetPosition(s); Stream_SetPosition(s, Stream_Length(s)); end = (WCHAR*) Stream_Pointer(s); @@ -305,10 +296,10 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context for (i = 0; i < context->priv->ClientFormatNameCount; i++) { - printf("Format %d: Id: 0x%04X Name: %s Length: %d\n", i, - context->priv->ClientFormatNames[i].id, - context->priv->ClientFormatNames[i].name, - context->priv->ClientFormatNames[i].length); + WLog_DBG(TAG, "Format %d: Id: 0x%04X Name: %s Length: %d", i, + context->priv->ClientFormatNames[i].id, + context->priv->ClientFormatNames[i].name, + context->priv->ClientFormatNames[i].length); } return 0; @@ -316,7 +307,7 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context static int cliprdr_server_receive_short_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) { - printf("%s: unimplemented\n", __FUNCTION__); + WLog_ERR(TAG, "%s: unimplemented"); return 0; } @@ -340,8 +331,8 @@ static int cliprdr_server_receive_format_list(CliprdrServerContext* context, wSt static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) { - printf("CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d\n", - header->msgType, header->msgFlags, header->dataLen); + WLog_DBG(TAG, "CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d", + header->msgType, header->msgFlags, header->dataLen); switch (header->msgType) { @@ -379,7 +370,7 @@ static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, break; default: - printf("Unexpected clipboard PDU type: %d\n", header->msgType); + WLog_DBG(TAG, "Unexpected clipboard PDU type: %d", header->msgType); break; } @@ -431,15 +422,14 @@ static void* cliprdr_server_thread(void* arg) break; } - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); + if (BytesReturned < 1) + continue; + Stream_EnsureRemainingCapacity(s, BytesReturned); + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { - if (BytesReturned) - Stream_Seek(s, BytesReturned); - } - else - { - Stream_EnsureRemainingCapacity(s, BytesReturned); + break; } if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH) diff --git a/channels/cliprdr/server/cliprdr_main.h b/channels/cliprdr/server/cliprdr_main.h index 71165045b..fd026336b 100644 --- a/channels/cliprdr/server/cliprdr_main.h +++ b/channels/cliprdr/server/cliprdr_main.h @@ -25,7 +25,9 @@ #include #include +#include +#define TAG CHANNELS_TAG("cliprdr.server") #define CLIPRDR_HEADER_LENGTH 8 struct _cliprdr_server_private diff --git a/channels/disp/client/CMakeLists.txt b/channels/disp/client/CMakeLists.txt index 704ce2334..328dc3cb6 100644 --- a/channels/disp/client/CMakeLists.txt +++ b/channels/disp/client/CMakeLists.txt @@ -27,15 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sysinfo) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c index e8827366b..b33ffb020 100644 --- a/channels/disp/client/disp_main.c +++ b/channels/disp/client/disp_main.c @@ -66,8 +66,8 @@ struct _DISP_PLUGIN DISP_LISTENER_CALLBACK* listener_callback; UINT32 MaxNumMonitors; - UINT32 MaxMonitorWidth; - UINT32 MaxMonitorHeight; + UINT32 MaxMonitorAreaFactorA; + UINT32 MaxMonitorAreaFactorB; }; typedef struct _DISP_PLUGIN DISP_PLUGIN; @@ -101,7 +101,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ - //fprintf(stderr, "NumMonitors: %d\n", NumMonitors); + //WLog_ERR(TAG, "NumMonitors: %d\n", NumMonitors); for (index = 0; index < NumMonitors; index++) { @@ -110,14 +110,17 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback if (Monitors[index].Width < 200) Monitors[index].Width = 200; - if (Monitors[index].Width > disp->MaxMonitorWidth) - Monitors[index].Width = disp->MaxMonitorWidth; + if (Monitors[index].Width > 8192) + Monitors[index].Width = 8192; + + if (Monitors[index].Width % 2) + Monitors[index].Width++; if (Monitors[index].Height < 200) Monitors[index].Height = 200; - if (Monitors[index].Height > disp->MaxMonitorHeight) - Monitors[index].Height = disp->MaxMonitorHeight; + if (Monitors[index].Height > 8192) + Monitors[index].Height = 8192; Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */ @@ -127,20 +130,19 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */ - -#if 0 - fprintf(stderr, "\t: Flags: 0x%04X\n", Monitors[index].Flags); - fprintf(stderr, "\t: Left: %d\n", Monitors[index].Left); - fprintf(stderr, "\t: Top: %d\n", Monitors[index].Top); - fprintf(stderr, "\t: Width: %d\n", Monitors[index].Width); - fprintf(stderr, "\t: Height: %d\n", Monitors[index].Height); - fprintf(stderr, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth); - fprintf(stderr, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight); - fprintf(stderr, "\t: Orientation: %d\n", Monitors[index].Orientation); -#endif - Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ + +#if 0 + WLog_DBG(TAG, "\t: Flags: 0x%04X\n", Monitors[index].Flags); + WLog_DBG(TAG, "\t: Left: %d\n", Monitors[index].Left); + WLog_DBG(TAG, "\t: Top: %d\n", Monitors[index].Top); + WLog_DBG(TAG, "\t: Width: %d\n", Monitors[index].Width); + WLog_DBG(TAG, "\t: Height: %d\n", Monitors[index].Height); + WLog_DBG(TAG, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth); + WLog_DBG(TAG, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight); + WLog_DBG(TAG, "\t: Orientation: %d\n", Monitors[index].Orientation); +#endif } Stream_SealLength(s); @@ -158,11 +160,13 @@ int disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* disp = (DISP_PLUGIN*) callback->plugin; - Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ - Stream_Read_UINT32(s, disp->MaxMonitorWidth); /* MaxMonitorWidth (4 bytes) */ - Stream_Read_UINT32(s, disp->MaxMonitorHeight); /* MaxMonitorHeight (4 bytes) */ + if (Stream_GetRemainingLength(s) < 12) + return -1; - //fprintf(stderr, "DisplayControlCapsPdu: MaxNumMonitors: %d MaxMonitorWidth: %d MaxMonitorHeight: %d\n", + Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ + Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */ + Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */ + //WLog_ERR(TAG, "DisplayControlCapsPdu: MaxNumMonitors: %d MaxMonitorWidth: %d MaxMonitorHeight: %d\n", // disp->MaxNumMonitors, disp->MaxMonitorWidth, disp->MaxMonitorHeight); return 0; @@ -173,10 +177,13 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) UINT32 type; UINT32 length; + if (Stream_GetRemainingLength(s) < 8) + return -1; + Stream_Read_UINT32(s, type); /* Type (4 bytes) */ Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - //fprintf(stderr, "Type: %d Length: %d\n", type, length); + //WLog_ERR(TAG, "Type: %d Length: %d\n", type, length); switch (type) { @@ -220,8 +227,10 @@ static int disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac DISP_CHANNEL_CALLBACK* callback; DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback; - callback = (DISP_CHANNEL_CALLBACK*) malloc(sizeof(DISP_CHANNEL_CALLBACK)); - ZeroMemory(callback, sizeof(DISP_CHANNEL_CALLBACK)); + callback = (DISP_CHANNEL_CALLBACK*) calloc(1, sizeof(DISP_CHANNEL_CALLBACK)); + + if (!callback) + return -1; callback->iface.OnDataReceived = disp_on_data_received; callback->iface.OnClose = disp_on_close; @@ -240,8 +249,10 @@ static int disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager int status; DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin; - disp->listener_callback = (DISP_LISTENER_CALLBACK*) malloc(sizeof(DISP_LISTENER_CALLBACK)); - ZeroMemory(disp->listener_callback, sizeof(DISP_LISTENER_CALLBACK)); + disp->listener_callback = (DISP_LISTENER_CALLBACK*) calloc(1, sizeof(DISP_LISTENER_CALLBACK)); + + if (!disp->listener_callback) + return -1; disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection; disp->listener_callback->plugin = pPlugin; @@ -281,11 +292,7 @@ int disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DIS return 1; } -#ifdef STATIC_CHANNELS -#define DVCPluginEntry disp_DVCPluginEntry -#endif - -int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +int disp_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { int error = 0; DISP_PLUGIN* disp; @@ -317,8 +324,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) disp->iface.pInterface = (void*) context; disp->MaxNumMonitors = 16; - disp->MaxMonitorWidth = 8192; - disp->MaxMonitorHeight = 8192; + disp->MaxMonitorAreaFactorA = 8192; + disp->MaxMonitorAreaFactorB = 8192; error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp); } diff --git a/channels/disp/client/disp_main.h b/channels/disp/client/disp_main.h index 1851618a0..23fdc2ce5 100644 --- a/channels/disp/client/disp_main.h +++ b/channels/disp/client/disp_main.h @@ -27,12 +27,12 @@ #include #include #include -#include +#include #include +#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000005 #define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 -#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000003 #endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */ diff --git a/channels/drdynvc/client/CMakeLists.txt b/channels/drdynvc/client/CMakeLists.txt index 124397d46..27e45a547 100644 --- a/channels/drdynvc/client/CMakeLists.txt +++ b/channels/drdynvc/client/CMakeLists.txt @@ -28,16 +28,6 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-synch) - install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 05146f044..2662f8be7 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -130,7 +130,7 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN if (status != CHANNEL_RC_OK) { drdynvc->channel_error = status; - DEBUG_WARN("VirtualChannelWrite failed %d", status); + WLog_ERR(TAG, "VirtualChannelWrite failed %d", status); return 1; } @@ -145,7 +145,7 @@ int drdynvc_push_event(drdynvcPlugin* drdynvc, wMessage* event) if (status != CHANNEL_RC_OK) { - DEBUG_WARN("pVirtualChannelEventPush failed %d", status); + WLog_ERR(TAG, "pVirtualChannelEventPush failed %d", status); return 1; } @@ -165,7 +165,7 @@ static int drdynvc_send_capability_response(drdynvcPlugin* drdynvc) if (status != CHANNEL_RC_OK) { - DEBUG_WARN("VirtualChannelWrite failed %d", status); + WLog_ERR(TAG, "VirtualChannelWrite failed %d", status); return 1; } @@ -270,7 +270,7 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb if (status != CHANNEL_RC_OK) { - DEBUG_WARN("VirtualChannelWrite failed %d", status); + WLog_ERR(TAG, "VirtualChannelWrite failed %d", status); return 1; } @@ -329,7 +329,7 @@ static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbC if (error != CHANNEL_RC_OK) { - DEBUG_WARN("VirtualChannelWrite failed %d", error); + WLog_ERR(TAG, "VirtualChannelWrite failed %d", error); return 1; } @@ -376,7 +376,7 @@ static void drdynvc_process_receive(rdpSvcPlugin* plugin, wStream* s) break; default: - DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd); + WLog_ERR(TAG, "unknown drdynvc cmd 0x%x", Cmd); break; } } @@ -398,7 +398,7 @@ static void drdynvc_process_connect(rdpSvcPlugin* plugin) for (index = 0; index < settings->DynamicChannelCount; index++) { args = settings->DynamicChannelArray[index]; - dvcman_load_addin(drdynvc->channel_mgr, args); + dvcman_load_addin(drdynvc->channel_mgr, args, settings); } dvcman_init(drdynvc->channel_mgr); diff --git a/channels/drdynvc/client/drdynvc_types.h b/channels/drdynvc/client/drdynvc_types.h index b7b629dcc..3160b8f35 100644 --- a/channels/drdynvc/client/drdynvc_types.h +++ b/channels/drdynvc/client/drdynvc_types.h @@ -26,12 +26,13 @@ #include #include -#include +#include +#define TAG CHANNELS_TAG("dvcman.client") #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif #endif diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index bd3718a60..bef066be7 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -71,7 +71,7 @@ static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, } else { - DEBUG_WARN("Maximum DVC listener number reached."); + WLog_WARN(TAG, "Maximum DVC listener number reached."); return 1; } } @@ -89,7 +89,7 @@ static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* p } else { - DEBUG_WARN("event_type %d push failed.", GetMessageType(pEvent->id)); + WLog_ERR(TAG, "event_type %d push failed.", GetMessageType(pEvent->id)); } return status; @@ -108,7 +108,7 @@ static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const cha } else { - DEBUG_WARN("Maximum DVC plugin number reached."); + WLog_WARN(TAG, "Maximum DVC plugin number reached."); return 1; } } @@ -135,6 +135,11 @@ ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args; } +void* dvcman_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + return (void*) ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->settings; +} + UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel) { return ((DVCMAN_CHANNEL*) channel)->channel_id; @@ -208,13 +213,11 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) return (IWTSVirtualChannelManager*) dvcman; } -int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args) +int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings) { DVCMAN_ENTRY_POINTS entryPoints; PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL; - - fprintf(stderr, "Loading Dynamic Virtual Channel %s\n", args->argv[0]); - + WLog_INFO(TAG, "Loading Dynamic Virtual Channel %s", args->argv[0]); pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0], NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC); @@ -223,8 +226,10 @@ int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args) entryPoints.iface.RegisterPlugin = dvcman_register_plugin; entryPoints.iface.GetPlugin = dvcman_get_plugin; entryPoints.iface.GetPluginData = dvcman_get_plugin_data; + entryPoints.iface.GetRdpSettings = dvcman_get_rdp_settings; entryPoints.dvcman = (DVCMAN*) pChannelMgr; entryPoints.args = args; + entryPoints.settings = settings; pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints); } @@ -381,8 +386,7 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel } else { - DEBUG_WARN("channel rejected by plugin"); - + WLog_ERR(TAG, "channel rejected by plugin"); free(channel); return 1; } @@ -402,14 +406,15 @@ int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId if (!channel) { - DEBUG_WARN("ChannelId %d not found!", ChannelId); + WLog_ERR(TAG, "ChannelId %d not found!", ChannelId); return 1; } if (channel->status == 0) { pCallback = channel->channel_callback; - pCallback->OnOpen(pCallback); + if (pCallback->OnOpen) + pCallback->OnOpen(pCallback); } return 0; @@ -426,7 +431,7 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI if (!channel) { - DEBUG_WARN("ChannelId %d not found!", ChannelId); + WLog_ERR(TAG, "ChannelId %d not found!", ChannelId); return 1; } @@ -460,7 +465,7 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI if (!channel) { - DEBUG_WARN("ChannelId %d not found!", ChannelId); + WLog_ERR(TAG, "ChannelId %d not found!", ChannelId); return 1; } @@ -468,7 +473,7 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI Stream_Release(channel->dvc_data); channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length); - Stream_AddRef(channel->dvc_data); + channel->dvc_data_length = length; return 0; } @@ -483,7 +488,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C if (!channel) { - DEBUG_WARN("ChannelId %d not found!", ChannelId); + WLog_ERR(TAG, "ChannelId %d not found!", ChannelId); return 1; } @@ -492,7 +497,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C /* Fragmented data */ if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data)) { - DEBUG_WARN("data exceeding declared length!"); + WLog_ERR(TAG, "data exceeding declared length!"); Stream_Release(channel->dvc_data); channel->dvc_data = NULL; return 1; @@ -500,7 +505,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize); - if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data)) + if (((size_t) Stream_GetPosition(channel->dvc_data)) >= channel->dvc_data_length) { Stream_SealLength(channel->dvc_data); Stream_SetPosition(channel->dvc_data, 0); diff --git a/channels/drdynvc/client/dvcman.h b/channels/drdynvc/client/dvcman.h index 3b627eae4..20f0edeb0 100644 --- a/channels/drdynvc/client/dvcman.h +++ b/channels/drdynvc/client/dvcman.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -65,6 +66,7 @@ struct _DVCMAN_ENTRY_POINTS DVCMAN* dvcman; ADDIN_ARGV* args; + rdpSettings* settings; }; typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS; @@ -80,12 +82,13 @@ struct _DVCMAN_CHANNEL IWTSVirtualChannelCallback* channel_callback; wStream* dvc_data; + UINT32 dvc_data_length; CRITICAL_SECTION lock; }; typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL; IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin); -int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args); +int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings); void dvcman_free(IWTSVirtualChannelManager* pChannelMgr); int dvcman_init(IWTSVirtualChannelManager* pChannelMgr); int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName); diff --git a/channels/drdynvc/server/CMakeLists.txt b/channels/drdynvc/server/CMakeLists.txt index f31e55815..4e09ba49d 100644 --- a/channels/drdynvc/server/CMakeLists.txt +++ b/channels/drdynvc/server/CMakeLists.txt @@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/drdynvc/server/drdynvc_main.c b/channels/drdynvc/server/drdynvc_main.c index b6436c6a5..62cdafd57 100644 --- a/channels/drdynvc/server/drdynvc_main.c +++ b/channels/drdynvc/server/drdynvc_main.c @@ -67,15 +67,14 @@ static void* drdynvc_server_thread(void* arg) break; } - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); + if (BytesReturned < 1) + continue; + Stream_EnsureRemainingCapacity(s, BytesReturned); + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { - if (BytesReturned) - Stream_Seek(s, BytesReturned); - } - else - { - Stream_EnsureRemainingCapacity(s, BytesReturned); + break; } } diff --git a/channels/drive/client/CMakeLists.txt b/channels/drive/client/CMakeLists.txt index b7f0b8d94..eb09d1a91 100644 --- a/channels/drive/client/CMakeLists.txt +++ b/channels/drive/client/CMakeLists.txt @@ -33,17 +33,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-file winpr-synch winpr-thread winpr-interlocked) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index d7b3852fc..5f3aa4718 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -49,7 +49,14 @@ #endif #ifdef HAVE_FCNTL_H +#define __USE_GNU /* for O_PATH */ #include +#undef __USE_GNU +#endif + +#ifdef _WIN32 +#pragma comment(lib, "Shlwapi.lib") +#include #endif #include "drive_file.h" @@ -187,6 +194,11 @@ static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 Creat if (STAT(file->fullpath, &st) == 0) { file->is_dir = (S_ISDIR(st.st_mode) ? TRUE : FALSE); + if (!file->is_dir && !S_ISREG(st.st_mode)) + { + file->err = EPERM; + return TRUE; + } #ifndef WIN32 if (st.st_size > (unsigned long) 0x07FFFFFFF) largeFile = TRUE; @@ -301,6 +313,25 @@ DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id, return NULL; } +#if defined(__linux__) && defined(O_PATH) + if (file->fd < 0 && file->err == EACCES) + { + /** + * We have no access permissions for the file or directory but if the + * peer is only interested in reading the object's attributes we can try + * to obtain a file descriptor who's only purpose is to perform + * operations that act purely at the file descriptor level. + * See open(2) + **/ + { + if ((file->fd = OPEN(file->fullpath, O_PATH)) >= 0) + { + file->err = 0; + } + } + } +#endif + return file; } @@ -425,6 +456,29 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w return TRUE; } +int dir_empty(const char *path) +{ +#ifdef _WIN32 + return PathIsDirectoryEmptyA(path); +#else + struct dirent *dp; + int empty = 1; + + DIR *dir = opendir(path); + if (dir == NULL) //Not a directory or doesn't exist + return 1; + + while ((dp = readdir(dir)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + continue; /* Skip . and .. */ + + empty = 0; + break; + } + closedir(dir); + return empty; +#endif +} BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; @@ -433,7 +487,11 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN int status; char* fullpath; struct STAT st; +#if defined(__linux__) && !defined(ANDROID) + struct timespec tv[2]; +#else struct timeval tv[2]; +#endif UINT64 LastWriteTime; UINT32 FileAttributes; UINT32 FileNameLength; @@ -454,14 +512,20 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; tv[0].tv_sec = st.st_atime; - tv[0].tv_usec = 0; tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); - tv[1].tv_usec = 0; #ifndef WIN32 /* TODO on win32 */ #ifdef ANDROID + tv[0].tv_usec = 0; + tv[1].tv_usec = 0; utimes(file->fullpath, tv); +#elif defined (__linux__) + tv[0].tv_nsec = 0; + tv[1].tv_nsec = 0; + futimens(file->fd, tv); #else + tv[0].tv_usec = 0; + tv[1].tv_usec = 0; futimes(file->fd, tv); #endif @@ -492,6 +556,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ + if (file->is_dir && !dir_empty(file->fullpath)) + break; + if (Length) Stream_Read_UINT8(input, file->delete_pending); else diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index 28ac5780a..36b869c72 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -117,6 +117,7 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input); BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, const char* path, wStream* output); +int dir_empty(const char *path); extern UINT sys_code_page; diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 0363b6b41..36dd232d4 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -346,6 +346,9 @@ static void drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp) } + if (file->is_dir && !dir_empty(file->fullpath)) + irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY; + Stream_Write_UINT32(irp->output, Length); irp->Complete(irp); diff --git a/channels/echo/CMakeLists.txt b/channels/echo/CMakeLists.txt index 3044e5ee5..bfa8297c9 100644 --- a/channels/echo/CMakeLists.txt +++ b/channels/echo/CMakeLists.txt @@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/echo/ChannelOptions.cmake b/channels/echo/ChannelOptions.cmake index 47a7d075e..eb4950a15 100644 --- a/channels/echo/ChannelOptions.cmake +++ b/channels/echo/ChannelOptions.cmake @@ -1,7 +1,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) -set(OPTION_SERVER_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) define_channel_options(NAME "echo" TYPE "dynamic" DESCRIPTION "Echo Virtual Channel Extension" diff --git a/channels/echo/client/CMakeLists.txt b/channels/echo/client/CMakeLists.txt index 54417f093..47ac1bf8d 100644 --- a/channels/echo/client/CMakeLists.txt +++ b/channels/echo/client/CMakeLists.txt @@ -27,12 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c index ef381e21a..f5633dd41 100644 --- a/channels/echo/client/echo_main.c +++ b/channels/echo/client/echo_main.c @@ -26,12 +26,11 @@ #include #include +#include #include #include -#include - #include "echo_main.h" typedef struct _ECHO_LISTENER_CALLBACK ECHO_LISTENER_CALLBACK; @@ -63,47 +62,21 @@ struct _ECHO_PLUGIN static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) { - int error; + int status; ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; - BYTE *pBuffer = Stream_Pointer(data); - UINT32 cbSize = Stream_GetRemainingLength(data); - -#ifdef WITH_DEBUG_DVC - int i = 0; - char* debug_buffer; - char* p; - - if (cbSize > 0) - { - debug_buffer = (char*) malloc(3 * cbSize); - ZeroMemory(debug_buffer, 3 * cbSize); - - p = debug_buffer; - - for (i = 0; i < (int) (cbSize - 1); i++) - { - sprintf(p, "%02x ", pBuffer[i]); - p += 3; - } - sprintf(p, "%02x", pBuffer[i]); - - DEBUG_DVC("ECHO %d: %s", cbSize, debug_buffer); - free(debug_buffer); - } -#endif + BYTE* pBuffer = Stream_Pointer(data); + UINT32 cbSize = Stream_GetRemainingLength(data); /* echo back what we have received. ECHO does not have any message IDs. */ - error = callback->channel->Write(callback->channel, cbSize, pBuffer, NULL); + status = callback->channel->Write(callback->channel, cbSize, pBuffer, NULL); - return error; + return status; } static int echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) { ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; - DEBUG_DVC(""); - free(callback); return 0; @@ -116,10 +89,10 @@ static int echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac ECHO_CHANNEL_CALLBACK* callback; ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback; - DEBUG_DVC(""); + callback = (ECHO_CHANNEL_CALLBACK*) calloc(1, sizeof(ECHO_CHANNEL_CALLBACK)); - callback = (ECHO_CHANNEL_CALLBACK*) malloc(sizeof(ECHO_CHANNEL_CALLBACK)); - ZeroMemory(callback, sizeof(ECHO_CHANNEL_CALLBACK)); + if (!callback) + return -1; callback->iface.OnDataReceived = echo_on_data_received; callback->iface.OnClose = echo_on_close; @@ -136,10 +109,10 @@ static int echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager { ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; - DEBUG_DVC(""); + echo->listener_callback = (ECHO_LISTENER_CALLBACK*) calloc(1, sizeof(ECHO_LISTENER_CALLBACK)); - echo->listener_callback = (ECHO_LISTENER_CALLBACK*) malloc(sizeof(ECHO_LISTENER_CALLBACK)); - ZeroMemory(echo->listener_callback, sizeof(ECHO_LISTENER_CALLBACK)); + if (!echo->listener_callback) + return -1; echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection; echo->listener_callback->plugin = pPlugin; @@ -153,36 +126,35 @@ static int echo_plugin_terminated(IWTSPlugin* pPlugin) { ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; - DEBUG_DVC(""); - - free(echo); + if (echo) + { + free(echo); + } return 0; } -#ifdef STATIC_CHANNELS -#define DVCPluginEntry echo_DVCPluginEntry -#endif - -int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +int echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { - int error = 0; + int status = 0; ECHO_PLUGIN* echo; echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo"); - if (echo == NULL) + if (!echo) { - echo = (ECHO_PLUGIN*) malloc(sizeof(ECHO_PLUGIN)); - ZeroMemory(echo, sizeof(ECHO_PLUGIN)); + echo = (ECHO_PLUGIN*) calloc(1, sizeof(ECHO_PLUGIN)); + + if (!echo) + return -1; echo->iface.Initialize = echo_plugin_initialize; echo->iface.Connected = NULL; echo->iface.Disconnected = NULL; echo->iface.Terminated = echo_plugin_terminated; - error = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo); + status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo); } - return error; + return status; } diff --git a/channels/echo/client/echo_main.h b/channels/echo/client/echo_main.h index e63eea768..1ce6a1f1d 100644 --- a/channels/echo/client/echo_main.h +++ b/channels/echo/client/echo_main.h @@ -27,12 +27,13 @@ #include #include #include -#include +#include +#define DVC_TAG CHANNELS_TAG("echo.client") #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(DVC_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif #endif /* __ECHO_MAIN_H */ diff --git a/channels/echo/server/CMakeLists.txt b/channels/echo/server/CMakeLists.txt new file mode 100644 index 000000000..8a90d903a --- /dev/null +++ b/channels/echo/server/CMakeLists.txt @@ -0,0 +1,31 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel_server("echo") + +set(${MODULE_PREFIX}_SRCS + echo_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +target_link_libraries(${MODULE_NAME} freerdp) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c new file mode 100644 index 000000000..979294d28 --- /dev/null +++ b/channels/echo/server/echo_main.c @@ -0,0 +1,234 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2014 Vic Lee + * + * 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 +#include +#include +#include +#include + +#include + +typedef struct _echo_server +{ + echo_server_context context; + + BOOL opened; + + HANDLE stopEvent; + + HANDLE thread; + void* echo_channel; + + DWORD SessionId; + +} echo_server; + +static BOOL echo_server_open_channel(echo_server* echo) +{ + DWORD Error; + HANDLE hEvent; + DWORD StartTick; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + + if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, + WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned) == FALSE) + { + return FALSE; + } + echo->SessionId = (DWORD) *pSessionId; + WTSFreeMemory(pSessionId); + + hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm); + StartTick = GetTickCount(); + + while (echo->echo_channel == NULL) + { + WaitForSingleObject(hEvent, 1000); + + echo->echo_channel = WTSVirtualChannelOpenEx(echo->SessionId, + "ECHO", WTS_CHANNEL_OPTION_DYNAMIC); + + if (echo->echo_channel) + break; + + Error = GetLastError(); + if (Error == ERROR_NOT_FOUND) + break; + + if (GetTickCount() - StartTick > 5000) + break; + } + + return echo->echo_channel ? TRUE : FALSE; +} + +static void* echo_server_thread_func(void* arg) +{ + wStream* s; + void* buffer; + DWORD nCount; + HANDLE events[8]; + BOOL ready = FALSE; + HANDLE ChannelEvent; + DWORD BytesReturned = 0; + echo_server* echo = (echo_server*) arg; + + if (echo_server_open_channel(echo) == FALSE) + { + IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + return NULL; + } + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = echo->stopEvent; + events[nCount++] = ChannelEvent; + + /* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */ + + while (1) + { + if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0) + { + IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_CLOSED); + break; + } + + if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) + { + IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_ERROR); + break; + } + + ready = *((BOOL*) buffer); + + WTSFreeMemory(buffer); + + if (ready) + { + IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_OK); + break; + } + } + + s = Stream_New(NULL, 4096); + + while (ready) + { + if (WaitForMultipleObjects(nCount, events, FALSE, INFINITE) == WAIT_OBJECT_0) + break; + + Stream_SetPosition(s, 0); + + WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned); + if (BytesReturned < 1) + continue; + Stream_EnsureRemainingCapacity(s, BytesReturned); + if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s), + (ULONG) Stream_Capacity(s), &BytesReturned) == FALSE) + { + break; + } + + IFCALL(echo->context.Response, &echo->context, (BYTE *) Stream_Buffer(s), BytesReturned); + } + + Stream_Free(s, TRUE); + WTSVirtualChannelClose(echo->echo_channel); + echo->echo_channel = NULL; + + return NULL; +} + +static void echo_server_open(echo_server_context* context) +{ + echo_server* echo = (echo_server*) context; + + if (echo->thread == NULL) + { + echo->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + echo->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) echo_server_thread_func, (void*) echo, 0, NULL); + } +} + +static void echo_server_close(echo_server_context* context) +{ + echo_server* echo = (echo_server*) context; + + if (echo->thread) + { + SetEvent(echo->stopEvent); + WaitForSingleObject(echo->thread, INFINITE); + CloseHandle(echo->thread); + CloseHandle(echo->stopEvent); + echo->thread = NULL; + echo->stopEvent = NULL; + } +} + +static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length) +{ + echo_server* echo = (echo_server*) context; + + return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR) buffer, length, NULL); +} + +echo_server_context* echo_server_context_new(HANDLE vcm) +{ + echo_server* echo; + + echo = (echo_server*) calloc(1, sizeof(echo_server)); + + echo->context.vcm = vcm; + echo->context.Open = echo_server_open; + echo->context.Close = echo_server_close; + echo->context.Request = echo_server_request; + + return (echo_server_context*) echo; +} + +void echo_server_context_free(echo_server_context* context) +{ + echo_server* echo = (echo_server*) context; + + echo_server_close(context); + + free(echo); +} diff --git a/channels/encomsp/CMakeLists.txt b/channels/encomsp/CMakeLists.txt new file mode 100644 index 000000000..be2d3748d --- /dev/null +++ b/channels/encomsp/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel("encomsp") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/encomsp/ChannelOptions.cmake b/channels/encomsp/ChannelOptions.cmake new file mode 100644 index 000000000..82ef07eab --- /dev/null +++ b/channels/encomsp/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "encomsp" TYPE "static" + DESCRIPTION "Multiparty Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEMC]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/encomsp/client/CMakeLists.txt b/channels/encomsp/client/CMakeLists.txt new file mode 100644 index 000000000..8842e5969 --- /dev/null +++ b/channels/encomsp/client/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel_client("encomsp") + +include_directories(..) + +set(${MODULE_PREFIX}_SRCS + encomsp_main.c + encomsp_main.h) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c new file mode 100644 index 000000000..cb5d67c6b --- /dev/null +++ b/channels/encomsp/client/encomsp_main.c @@ -0,0 +1,949 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 + +#include "encomsp_main.h" + +static int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) + return -1; + + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) +{ + ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING)); + + if (Stream_GetRemainingLength(s) < 2) + return -1; + + Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */ + + if (str->cchString > 1024) + return -1; + + if (Stream_GetRemainingLength(s) < (size_t) (str->cchString * 2)) + return -1; + + Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */ + + return 1; +} + +EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp) +{ + EncomspClientContext* pInterface; + pInterface = (EncomspClientContext*) encomsp->channelEntryPoints.pInterface; + return pInterface; +} + +int encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s) +{ + UINT32 status = 0; + + if (!encomsp) + return -1; + +#if 0 + WLog_INFO(TAG, "EncomspWrite (%d)", Stream_Length(s)); + winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); +#endif + + status = encomsp->channelEntryPoints.pVirtualChannelWrite(encomsp->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_Length(s), s); + + if (status != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "encomsp_virtual_channel_write: VirtualChannelWrite failed %d", status); + return -1; + } + + return 1; +} + +static int encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_FILTER_UPDATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 1) + return -1; + + Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->FilterUpdated) + { + return context->FilterUpdated(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_APPLICATION_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 6) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ApplicationCreated) + { + return context->ApplicationCreated(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_APPLICATION_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ApplicationRemoved) + { + return context->ApplicationRemoved(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_WINDOW_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->WindowCreated) + { + return context->WindowCreated(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_WINDOW_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->WindowRemoved) + { + return context->WindowRemoved(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_SHOW_WINDOW_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ShowWindow) + { + return context->ShowWindow(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_PARTICIPANT_CREATED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 10) + return -1; + + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */ + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + + if (encomsp_read_unicode_string(s, &(pdu.FriendlyName)) < 0) + return -1; + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ParticipantCreated) + { + return context->ParticipantCreated(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_PARTICIPANT_REMOVED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 12) + return -1; + + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */ + Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ParticipantRemoved) + { + return context->ParticipantRemoved(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 6) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ChangeParticipantControlLevel) + { + return context->ChangeParticipantControlLevel(context, &pdu); + } + + return 1; +} + +static int encomsp_send_change_participant_control_level_pdu(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu) +{ + wStream* s; + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) context->handle; + + pdu->Type = ODTYPE_PARTICIPANT_CTRL_CHANGED; + pdu->Length = ENCOMSP_ORDER_HEADER_SIZE + 6; + + s = Stream_New(NULL, pdu->Length); + + encomsp_write_header(s, (ENCOMSP_ORDER_HEADER*) pdu); + + Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */ + Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */ + + Stream_SealLength(s); + + encomsp_virtual_channel_write(encomsp, s); + + return 1; +} + +static int encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->GraphicsStreamPaused) + { + return context->GraphicsStreamPaused(context, &pdu); + } + + return 1; +} + +static int encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + EncomspClientContext* context; + ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu; + + context = encomsp_get_client_interface(encomsp); + + if (!context) + return -1; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->GraphicsStreamResumed) + { + return context->GraphicsStreamResumed(context, &pdu); + } + + return 1; +} + +static int encomsp_process_receive(encomspPlugin* encomsp, wStream* s) +{ + int status = 1; + ENCOMSP_ORDER_HEADER header; + + while (Stream_GetRemainingLength(s) > 0) + { + if (encomsp_read_header(s, &header) < 0) + return -1; + + //WLog_DBG(TAG, "EncomspReceive: Type: %d Length: %d", header.Type, header.Length); + + switch (header.Type) + { + case ODTYPE_FILTER_STATE_UPDATED: + status = encomsp_recv_filter_updated_pdu(encomsp, s, &header); + break; + + case ODTYPE_APP_REMOVED: + status = encomsp_recv_application_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_APP_CREATED: + status = encomsp_recv_application_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_REMOVED: + status = encomsp_recv_window_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_CREATED: + status = encomsp_recv_window_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_WND_SHOW: + status = encomsp_recv_show_window_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_REMOVED: + status = encomsp_recv_participant_removed_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_CREATED: + status = encomsp_recv_participant_created_pdu(encomsp, s, &header); + break; + + case ODTYPE_PARTICIPANT_CTRL_CHANGED: + status = encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_PAUSED: + status = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header); + break; + + case ODTYPE_GRAPHICS_STREAM_RESUMED: + status = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header); + break; + + default: + status = -1; + break; + } + + if (status < 0) + return -1; + } + + return status; +} + +static void encomsp_process_connect(encomspPlugin* encomsp) +{ + +} + +/****************************************************************************************/ + +static wListDictionary* g_InitHandles; +static wListDictionary* g_OpenHandles; + +void encomsp_add_init_handle_data(void* pInitHandle, void* pUserData) +{ + if (!g_InitHandles) + g_InitHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_InitHandles, pInitHandle, pUserData); +} + +void* encomsp_get_init_handle_data(void* pInitHandle) +{ + void* pUserData = NULL; + pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); + return pUserData; +} + +void encomsp_remove_init_handle_data(void* pInitHandle) +{ + ListDictionary_Remove(g_InitHandles, pInitHandle); +} + +void encomsp_add_open_handle_data(DWORD openHandle, void* pUserData) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + g_OpenHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData); +} + +void* encomsp_get_open_handle_data(DWORD openHandle) +{ + void* pUserData = NULL; + void* pOpenHandle = (void*) (size_t) openHandle; + pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); + return pUserData; +} + +void encomsp_remove_open_handle_data(DWORD openHandle) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); +} + +int encomsp_send(encomspPlugin* encomsp, wStream* s) +{ + UINT32 status = 0; + encomspPlugin* plugin = (encomspPlugin*) encomsp; + + if (!plugin) + { + status = CHANNEL_RC_BAD_INIT_HANDLE; + } + else + { + status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + } + + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "encomsp_send: VirtualChannelWrite failed %d", status); + } + + return status; +} + +static void encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + wStream* data_in; + + if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) + { + return; + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (encomsp->data_in) + Stream_Free(encomsp->data_in, TRUE); + + encomsp->data_in = Stream_New(NULL, totalLength); + } + + data_in = encomsp->data_in; + Stream_EnsureRemainingCapacity(data_in, (int) dataLength); + Stream_Write(data_in, pData, dataLength); + + if (dataFlags & CHANNEL_FLAG_LAST) + { + if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + { + WLog_ERR(TAG, "encomsp_plugin_process_received: read error"); + } + + encomsp->data_in = NULL; + Stream_SealLength(data_in); + Stream_SetPosition(data_in, 0); + + MessageQueue_Post(encomsp->MsgPipe->In, NULL, 0, (void*) data_in, NULL); + } +} + +static VOID VCAPITYPE encomsp_virtual_channel_open_event(DWORD openHandle, UINT event, + LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) encomsp_get_open_handle_data(openHandle); + + if (!encomsp) + { + WLog_ERR(TAG, "encomsp_virtual_channel_open_event: error no match"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; + + case CHANNEL_EVENT_USER: + break; + } +} + +static void* encomsp_virtual_channel_client_thread(void* arg) +{ + wStream* data; + wMessage message; + encomspPlugin* encomsp = (encomspPlugin*) arg; + + encomsp_process_connect(encomsp); + + while (1) + { + if (!MessageQueue_Wait(encomsp->MsgPipe->In)) + break; + + if (MessageQueue_Peek(encomsp->MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + if (message.id == 0) + { + data = (wStream*) message.wParam; + encomsp_process_receive(encomsp, data); + } + } + } + + ExitThread(0); + return NULL; +} + +static void encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData, UINT32 dataLength) +{ + UINT32 status; + + status = encomsp->channelEntryPoints.pVirtualChannelOpen(encomsp->InitHandle, + &encomsp->OpenHandle, encomsp->channelDef.name, encomsp_virtual_channel_open_event); + + encomsp_add_open_handle_data(encomsp->OpenHandle, encomsp); + + if (status != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "encomsp_virtual_channel_event_connected: open failed: status: %d", status); + return; + } + + encomsp->MsgPipe = MessagePipe_New(); + + encomsp->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) encomsp_virtual_channel_client_thread, (void*) encomsp, 0, NULL); +} + +static void encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp) +{ + MessagePipe_PostQuit(encomsp->MsgPipe, 0); + WaitForSingleObject(encomsp->thread, INFINITE); + + MessagePipe_Free(encomsp->MsgPipe); + CloseHandle(encomsp->thread); + + encomsp->channelEntryPoints.pVirtualChannelClose(encomsp->OpenHandle); + + if (encomsp->data_in) + { + Stream_Free(encomsp->data_in, TRUE); + encomsp->data_in = NULL; + } + + encomsp_remove_open_handle_data(encomsp->OpenHandle); + encomsp_remove_init_handle_data(encomsp->InitHandle); +} + +static VOID VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +{ + encomspPlugin* encomsp; + + encomsp = (encomspPlugin*) encomsp_get_init_handle_data(pInitHandle); + + if (!encomsp) + { + WLog_ERR(TAG, "encomsp_virtual_channel_init_event: error no match"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + encomsp_virtual_channel_event_connected(encomsp, pData, dataLength); + break; + + case CHANNEL_EVENT_DISCONNECTED: + break; + + case CHANNEL_EVENT_TERMINATED: + encomsp_virtual_channel_event_terminated(encomsp); + break; + } +} + +/* encomsp is always built-in */ +#define VirtualChannelEntry encomsp_VirtualChannelEntry + +BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) +{ + encomspPlugin* encomsp; + EncomspClientContext* context; + CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; + + encomsp = (encomspPlugin*) calloc(1, sizeof(encomspPlugin)); + + encomsp->channelDef.options = + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | + CHANNEL_OPTION_SHOW_PROTOCOL; + + strcpy(encomsp->channelDef.name, "encomsp"); + + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; + + if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) && + (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) + { + context = (EncomspClientContext*) calloc(1, sizeof(EncomspClientContext)); + + context->handle = (void*) encomsp; + + context->FilterUpdated = NULL; + context->ApplicationCreated = NULL; + context->ApplicationRemoved = NULL; + context->WindowCreated = NULL; + context->WindowRemoved = NULL; + context->ShowWindow = NULL; + context->ParticipantCreated = NULL; + context->ParticipantRemoved = NULL; + context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu; + context->GraphicsStreamPaused = NULL; + context->GraphicsStreamResumed = NULL; + + *(pEntryPointsEx->ppInterface) = (void*) context; + } + + CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); + + encomsp->channelEntryPoints.pVirtualChannelInit(&encomsp->InitHandle, + &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, encomsp_virtual_channel_init_event); + + encomsp->channelEntryPoints.pInterface = *(encomsp->channelEntryPoints.ppInterface); + encomsp->channelEntryPoints.ppInterface = &(encomsp->channelEntryPoints.pInterface); + + encomsp_add_init_handle_data(encomsp->InitHandle, (void*) encomsp); + + return 1; +} diff --git a/channels/encomsp/client/encomsp_main.h b/channels/encomsp/client/encomsp_main.h new file mode 100644 index 000000000..3da59b883 --- /dev/null +++ b/channels/encomsp/client/encomsp_main.h @@ -0,0 +1,51 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H +#define FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define TAG CHANNELS_TAG("encomsp.client") + +struct encomsp_plugin +{ + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints; + + HANDLE thread; + wStream* data_in; + void* InitHandle; + DWORD OpenHandle; + wMessagePipe* MsgPipe; +}; +typedef struct encomsp_plugin encomspPlugin; + +#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */ diff --git a/server/X11/cli/CMakeLists.txt b/channels/encomsp/server/CMakeLists.txt similarity index 60% rename from server/X11/cli/CMakeLists.txt rename to channels/encomsp/server/CMakeLists.txt index 6d0d45ff3..4cb47966e 100644 --- a/server/X11/cli/CMakeLists.txt +++ b/channels/encomsp/server/CMakeLists.txt @@ -1,5 +1,5 @@ # FreeRDP: A Remote Desktop Protocol Implementation -# FreeRDP X11 cmake build script +# FreeRDP cmake build script # # Copyright 2012 Marc-Andre Moreau # @@ -15,22 +15,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "xfreerdp-server-cli") -set(MODULE_PREFIX "FREERDP_SERVER_X11") +define_channel_server("encomsp") include_directories(..) set(${MODULE_PREFIX}_SRCS - xfreerdp.c) + encomsp_main.c + encomsp_main.h) -add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "xfreerdp-server" RUNTIME_OUTPUT_DIRECTORY "..") +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} xfreerdp-server) +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server) - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/X11") +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/encomsp/server/encomsp_main.c b/channels/encomsp/server/encomsp_main.c new file mode 100644 index 000000000..b3689f598 --- /dev/null +++ b/channels/encomsp/server/encomsp_main.c @@ -0,0 +1,273 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 + +#include "encomsp_main.h" + +#define TAG CHANNELS_TAG("encomsp.server") + +static int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) + return -1; + + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +#if 0 + +static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ + + return 1; +} + +static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) +{ + ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING)); + + if (Stream_GetRemainingLength(s) < 2) + return -1; + + Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */ + + if (str->cchString > 1024) + return -1; + + if (Stream_GetRemainingLength(s) < (str->cchString * 2)) + return -1; + + Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */ + + return 1; +} + +#endif + +static int encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context, wStream* s, ENCOMSP_ORDER_HEADER* header) +{ + int beg, end; + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + + if (Stream_GetRemainingLength(s) < 6) + return -1; + + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ + + end = (int) Stream_GetPosition(s); + + if ((beg + header->Length) < end) + return -1; + + if ((beg + header->Length) > end) + { + if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + return -1; + + Stream_SetPosition(s, (beg + header->Length)); + } + + if (context->ChangeParticipantControlLevel) + { + return context->ChangeParticipantControlLevel(context, &pdu); + } + + return 1; +} + +static int encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s) +{ + int status = 1; + ENCOMSP_ORDER_HEADER header; + + while (Stream_GetRemainingLength(s) > 0) + { + if (encomsp_read_header(s, &header) < 0) + return -1; + + WLog_INFO(TAG, "EncomspReceive: Type: %d Length: %d", header.Type, header.Length); + + switch (header.Type) + { + case ODTYPE_PARTICIPANT_CTRL_CHANGED: + status = encomsp_recv_change_participant_control_level_pdu(context, s, &header); + break; + + default: + status = -1; + break; + } + + if (status < 0) + return -1; + } + + return status; +} + +static void* encomsp_server_thread(void* arg) +{ + wStream* s; + DWORD status; + DWORD nCount; + void* buffer; + HANDLE events[8]; + HANDLE ChannelEvent; + DWORD BytesReturned; + ENCOMSP_ORDER_HEADER* header; + EncomspServerContext* context; + + context = (EncomspServerContext*) arg; + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + s = Stream_New(NULL, 4096); + + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->StopEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); + if (BytesReturned < 1) + continue; + Stream_EnsureRemainingCapacity(s, BytesReturned); + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + { + break; + } + + if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE) + { + header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s); + + if (header->Length >= Stream_GetPosition(s)) + { + Stream_SealLength(s); + Stream_SetPosition(s, 0); + encomsp_server_receive_pdu(context, s); + Stream_SetPosition(s, 0); + } + } + } + + Stream_Free(s, TRUE); + + return NULL; +} + +static int encomsp_server_start(EncomspServerContext* context) +{ + context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "encomsp"); + + if (!context->priv->ChannelHandle) + return -1; + + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) encomsp_server_thread, (void*) context, 0, NULL); + + return 0; +} + +static int encomsp_server_stop(EncomspServerContext* context) +{ + SetEvent(context->priv->StopEvent); + + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + + return 0; +} + +EncomspServerContext* encomsp_server_context_new(HANDLE vcm) +{ + EncomspServerContext* context; + + context = (EncomspServerContext*) calloc(1, sizeof(EncomspServerContext)); + + if (context) + { + context->vcm = vcm; + + context->Start = encomsp_server_start; + context->Stop = encomsp_server_stop; + + context->priv = (EncomspServerPrivate*) calloc(1, sizeof(EncomspServerPrivate)); + + if (context->priv) + { + + } + } + + return context; +} + +void encomsp_server_context_free(EncomspServerContext* context) +{ + if (context) + { + if (context->priv) + { + free(context->priv); + } + + free(context); + } +} diff --git a/channels/encomsp/server/encomsp_main.h b/channels/encomsp/server/encomsp_main.h new file mode 100644 index 000000000..1338f6ee0 --- /dev/null +++ b/channels/encomsp/server/encomsp_main.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H +#define FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H + +#include +#include +#include + +#include + +struct _encomsp_server_private +{ + HANDLE Thread; + HANDLE StopEvent; + void* ChannelHandle; +}; + +#endif /* FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H */ diff --git a/channels/parallel/client/CMakeLists.txt b/channels/parallel/client/CMakeLists.txt index e9a87261d..91f649a0b 100644 --- a/channels/parallel/client/CMakeLists.txt +++ b/channels/parallel/client/CMakeLists.txt @@ -24,17 +24,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-interlocked) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp winpr) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/printer/client/CMakeLists.txt b/channels/printer/client/CMakeLists.txt index 861de097e..f8bee2e36 100644 --- a/channels/printer/client/CMakeLists.txt +++ b/channels/printer/client/CMakeLists.txt @@ -40,15 +40,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) if(WITH_CUPS) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES}) diff --git a/channels/printer/client/printer_win.h b/channels/printer/client/printer_win.h index eecbb17ba..7f0660af5 100644 --- a/channels/printer/client/printer_win.h +++ b/channels/printer/client/printer_win.h @@ -20,17 +20,20 @@ #ifndef __PRINTER_WIN_H #define __PRINTER_WIN_H +#include + rdpPrinterDriver* printer_win_get_driver(void); +#define PRINTER_TAG CHANNELS_TAG("printer.client") #ifdef WITH_DEBUG_WINPR -#define DEBUG_WINPR(fmt, ...) DEBUG_CLASS(WINPR, fmt, ## __VA_ARGS__) +#define DEBUG_WINPR(fmt, ...) WLog_DBG(PRINTER_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_WINPR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_WINPR(fmt, ...) do { } while (0) #endif #endif #ifdef WIN32 #define snprintf _snprintf -#endif +#endif diff --git a/channels/rail/client/CMakeLists.txt b/channels/rail/client/CMakeLists.txt index b44ce1614..e6b1bc4f8 100644 --- a/channels/rail/client/CMakeLists.txt +++ b/channels/rail/client/CMakeLists.txt @@ -29,12 +29,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 3096f543b..eb3b371c5 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -28,6 +28,7 @@ #include #include +#include #include "rail_orders.h" @@ -522,7 +523,7 @@ BOOL rail_order_recv(railPlugin* rail, wStream* s) } default: - fprintf(stderr, "Unknown RAIL PDU order reveived."); + WLog_ERR(TAG, "Unknown RAIL PDU order reveived."); break; } diff --git a/channels/rail/client/rail_orders.h b/channels/rail/client/rail_orders.h index 217c967d4..78e6a0762 100644 --- a/channels/rail/client/rail_orders.h +++ b/channels/rail/client/rail_orders.h @@ -21,8 +21,11 @@ #ifndef __RAIL_ORDERS_H #define __RAIL_ORDERS_H +#include #include "rail_main.h" +#define TAG CHANNELS_TAG("rail.client") + BOOL rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* exec_result); BOOL rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam); BOOL rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo); diff --git a/channels/rdpdr/client/CMakeLists.txt b/channels/rdpdr/client/CMakeLists.txt index 241849b9f..39e05a505 100644 --- a/channels/rdpdr/client/CMakeLists.txt +++ b/channels/rdpdr/client/CMakeLists.txt @@ -31,17 +31,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 75778fe01..35fb742b9 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "rdpdr_main.h" @@ -122,7 +123,7 @@ BOOL devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device) if (!ServiceName) return FALSE; - fprintf(stderr, "Loading device service %s (static)\n", ServiceName); + WLog_INFO(TAG, "Loading device service %s (static)", ServiceName); entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0); if (!entry) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 5759b5154..14ee6d78f 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -31,6 +31,7 @@ #include #include +#include #include #ifdef _WIN32 @@ -451,7 +452,7 @@ static void* drive_hotplug_thread_func(void* arg) if (mfd < 0) { - fprintf(stderr, "ERROR: Unable to open /proc/mounts."); + WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts."); return NULL; } @@ -460,6 +461,8 @@ static void* drive_hotplug_thread_func(void* arg) tv.tv_sec = 1; tv.tv_usec = 0; + handle_hotplug(rdpdr); + while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) { if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0) @@ -659,9 +662,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use Stream_Write(s, Stream_Buffer(device->data), data_len); count++; - - fprintf(stderr, "registered device #%d: %s (type=%d id=%d)\n", - count, device->name, device->type, device->id); + WLog_INFO(TAG, "registered device #%d: %s (type=%d id=%d)\n", + count, device->name, device->type, device->id); } } @@ -843,7 +845,7 @@ int rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - fprintf(stderr, "rdpdr_send: VirtualChannelWrite failed %d\n", status); + WLog_ERR(TAG, "rdpdr_send: VirtualChannelWrite failed %d\n", status); } return status; @@ -881,7 +883,7 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - fprintf(stderr, "svc_plugin_process_received: read error\n"); + WLog_ERR(TAG, "svc_plugin_process_received: read error\n"); } rdpdr->data_in = NULL; @@ -901,7 +903,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev if (!rdpdr) { - fprintf(stderr, "rdpdr_virtual_channel_open_event: error no match\n"); + WLog_ERR(TAG, "rdpdr_virtual_channel_open_event: error no match\n"); return; } @@ -961,7 +963,7 @@ static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa if (status != CHANNEL_RC_OK) { - fprintf(stderr, "rdpdr_virtual_channel_event_connected: open failed: status: %d\n", status); + WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected: open failed: status: %d\n", status); return; } @@ -1007,7 +1009,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT if (!rdpdr) { - fprintf(stderr, "rdpdr_virtual_channel_init_event: error no match\n"); + WLog_ERR(TAG, "rdpdr_virtual_channel_init_event: error no match\n"); return; } diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index c29846c80..f74a135f4 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -32,6 +32,9 @@ #include #include +#include + +#define TAG CHANNELS_TAG("rdprd.client") typedef struct rdpdr_plugin rdpdrPlugin; diff --git a/channels/rdpdr/server/CMakeLists.txt b/channels/rdpdr/server/CMakeLists.txt index 17a18967e..32529e5bf 100644 --- a/channels/rdpdr/server/CMakeLists.txt +++ b/channels/rdpdr/server/CMakeLists.txt @@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index 9b67388f0..71aab4f75 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -25,8 +25,11 @@ #include #include +#include #include "rdpdr_main.h" +#define TAG "rdpdr.server" + static UINT32 g_ClientId = 0; static int rdpdr_server_send_announce_request(RdpdrServerContext* context) @@ -35,27 +38,18 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context) BOOL status; RDPDR_HEADER header; ULONG written; - - printf("RdpdrServerSendAnnounceRequest\n"); - + WLog_DBG(TAG, "RdpdrServerSendAnnounceRequest"); header.Component = RDPDR_CTYP_CORE; header.PacketId = PAKID_CORE_SERVER_ANNOUNCE; - s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8); - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ - Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); - Stream_Free(s, TRUE); - return 0; } @@ -64,16 +58,12 @@ static int rdpdr_server_receive_announce_response(RdpdrServerContext* context, w UINT32 ClientId; UINT16 VersionMajor; UINT16 VersionMinor; - Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */ Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */ Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ - - printf("Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X\n", - VersionMajor, VersionMinor, ClientId); - + WLog_DBG(TAG, "Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X", + VersionMajor, VersionMinor, ClientId); context->priv->ClientId = ClientId; - return 0; } @@ -81,7 +71,6 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context, { UINT32 UnicodeFlag; UINT32 ComputerNameLen; - Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */ Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ @@ -100,7 +89,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context, if (UnicodeFlag) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), - -1, &(context->priv->ClientComputerName), 0, NULL, NULL); + -1, &(context->priv->ClientComputerName), 0, NULL, NULL); } else { @@ -108,9 +97,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context, } Stream_Seek(s, ComputerNameLen); - - printf("ClientComputerName: %s\n", context->priv->ClientComputerName); - + WLog_DBG(TAG, "ClientComputerName: %s", context->priv->ClientComputerName); return 0; } @@ -138,7 +125,6 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context, UINT16 VersionMajor; UINT16 VersionMinor; UINT32 SpecialTypeDeviceCap; - Stream_Seek_UINT32(s); /* osType (4 bytes), ignored on receipt */ Stream_Seek_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */ Stream_Read_UINT16(s, VersionMajor); /* protocolMajorVersion (2 bytes) */ @@ -149,9 +135,7 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context, Stream_Read_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */ Stream_Seek_UINT32(s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ Stream_Read_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ - context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? TRUE : FALSE; - return 0; } @@ -162,11 +146,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context UINT32 extraFlags1; UINT32 SpecialTypeDeviceCap; RDPDR_CAPABILITY_HEADER header; - header.CapabilityType = CAP_GENERAL_TYPE; header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH + 36; header.Version = GENERAL_CAPABILITY_VERSION_02; - ioCode1 = 0; ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */ ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */ @@ -184,7 +166,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */ ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */ ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */ - extendedPdu = 0; extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */ extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */ @@ -194,12 +175,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context extraFlags1 = 0; extraFlags1 |= ENABLE_ASYNCIO; /* optional */ - SpecialTypeDeviceCap = 0; - Stream_EnsureRemainingCapacity(s, header.CapabilityLength); rdpdr_server_write_capability_set_header(s, &header); - Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */ Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */ Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */ @@ -210,7 +188,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */ Stream_Write_UINT32(s, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ - return 0; } @@ -222,14 +199,11 @@ static int rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, static int rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; - header.CapabilityType = CAP_PRINTER_TYPE; header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH; header.Version = PRINT_CAPABILITY_VERSION_01; - Stream_EnsureRemainingCapacity(s, header.CapabilityLength); rdpdr_server_write_capability_set_header(s, &header); - return 0; } @@ -241,14 +215,11 @@ static int rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wS static int rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; - header.CapabilityType = CAP_PORT_TYPE; header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH; header.Version = PORT_CAPABILITY_VERSION_01; - Stream_EnsureRemainingCapacity(s, header.CapabilityLength); rdpdr_server_write_capability_set_header(s, &header); - return 0; } @@ -260,14 +231,11 @@ static int rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, w static int rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; - header.CapabilityType = CAP_DRIVE_TYPE; header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH; header.Version = DRIVE_CAPABILITY_VERSION_02; - Stream_EnsureRemainingCapacity(s, header.CapabilityLength); rdpdr_server_write_capability_set_header(s, &header); - return 0; } @@ -279,14 +247,11 @@ static int rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* contex static int rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; - header.CapabilityType = CAP_SMARTCARD_TYPE; header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH; header.Version = SMARTCARD_CAPABILITY_VERSION_01; - Stream_EnsureRemainingCapacity(s, header.CapabilityLength); rdpdr_server_write_capability_set_header(s, &header); - return 0; } @@ -297,34 +262,23 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context RDPDR_HEADER header; UINT16 numCapabilities; ULONG written; - - printf("RdpdrServerSendCoreCapabilityRequest\n"); - + WLog_DBG(TAG, "RdpdrServerSendCoreCapabilityRequest"); header.Component = RDPDR_CTYP_CORE; header.PacketId = PAKID_CORE_SERVER_CAPABILITY; - numCapabilities = 5; - s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 512); - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */ - rdpdr_server_write_general_capability_set(context, s); rdpdr_server_write_printer_capability_set(context, s); rdpdr_server_write_port_capability_set(context, s); rdpdr_server_write_drive_capability_set(context, s); rdpdr_server_write_smartcard_capability_set(context, s); - Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); - Stream_Free(s, TRUE); - return 0; } @@ -333,7 +287,6 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con int i; UINT16 numCapabilities; RDPDR_CAPABILITY_HEADER capabilityHeader; - Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ Stream_Seek_UINT16(s); /* Padding (2 bytes) */ @@ -364,7 +317,7 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con break; default: - printf("Unknown capabilityType %d\n", capabilityHeader.CapabilityType); + WLog_DBG(TAG, "Unknown capabilityType %d", capabilityHeader.CapabilityType); Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH); break; } @@ -379,27 +332,18 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) BOOL status; RDPDR_HEADER header; ULONG written; - - printf("RdpdrServerSendClientIdConfirm\n"); - + WLog_DBG(TAG, "RdpdrServerSendClientIdConfirm"); header.Component = RDPDR_CTYP_CORE; header.PacketId = PAKID_CORE_CLIENTID_CONFIRM; - s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8); - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ - Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); - Stream_Free(s, TRUE); - return 0; } @@ -411,12 +355,9 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* UINT32 DeviceId; char PreferredDosName[9]; UINT32 DeviceDataLength; - PreferredDosName[8] = 0; - Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ - - printf("%s: DeviceCount: %d\n", __FUNCTION__, DeviceCount); + WLog_DBG(TAG, "DeviceCount: %d", DeviceCount); for (i = 0; i < DeviceCount; i++) { @@ -424,9 +365,8 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */ Stream_Read_UINT32(s, DeviceDataLength); /* DeviceDataLength (4 bytes) */ - - printf("Device %d Name: %s Id: 0x%04X DataLength: %d\n", - i, PreferredDosName, DeviceId, DeviceDataLength); + WLog_DBG(TAG, "Device %d Name: %s Id: 0x%04X DataLength: %d", + i, PreferredDosName, DeviceId, DeviceDataLength); switch (DeviceId) { @@ -461,32 +401,23 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context) BOOL status; RDPDR_HEADER header; ULONG written; - - printf("%s\n", __FUNCTION__); - + WLog_DBG(TAG, "%s"); header.Component = RDPDR_CTYP_CORE; header.PacketId = PAKID_CORE_USER_LOGGEDON; - s = Stream_New(NULL, RDPDR_HEADER_LENGTH); - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); - Stream_Free(s, TRUE); - return 0; } static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header) { - printf("RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X\n", - header->Component, header->PacketId); - - winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); + WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X", + header->Component, header->PacketId); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); if (header->Component == RDPDR_CTYP_CORE) { @@ -507,6 +438,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP if (context->priv->UserLoggedOnPdu) rdpdr_server_send_user_logged_on(context); + break; case PAKID_CORE_DEVICELIST_ANNOUNCE: @@ -545,7 +477,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP } else { - printf("Unknown RDPDR_HEADER.Component: 0x%04X\n", header->Component); + WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04X", header->Component); return -1; } @@ -564,13 +496,10 @@ static void* rdpdr_server_thread(void* arg) HANDLE ChannelEvent; DWORD BytesReturned; RdpdrServerContext* context; - context = (RdpdrServerContext*) arg; - buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; - s = Stream_New(NULL, 4096); if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) @@ -584,13 +513,11 @@ static void* rdpdr_server_thread(void* arg) nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; - rdpdr_server_send_announce_request(context); while (1) { BytesReturned = 0; - status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) @@ -598,37 +525,34 @@ static void* rdpdr_server_thread(void* arg) break; } - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Pointer(s), - Stream_Capacity(s) - Stream_GetPosition(s), &BytesReturned)) + WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); + + if (BytesReturned < 1) + continue; + + Stream_EnsureRemainingCapacity(s, BytesReturned); + + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { - if (BytesReturned) - Stream_Seek(s, BytesReturned); - } - else - { - Stream_EnsureRemainingCapacity(s, BytesReturned); + break; } if (Stream_GetPosition(s) >= RDPDR_HEADER_LENGTH) { position = Stream_GetPosition(s); Stream_SetPosition(s, 0); - Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_SetPosition(s, position); - Stream_SealLength(s); Stream_SetPosition(s, RDPDR_HEADER_LENGTH); - rdpdr_server_receive_pdu(context, s, &header); Stream_SetPosition(s, 0); } } Stream_Free(s, TRUE); - return NULL; } @@ -640,48 +564,38 @@ static int rdpdr_server_start(RdpdrServerContext* context) return -1; context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - context->priv->Thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rdpdr_server_thread, (void*) context, 0, NULL); - + (LPTHREAD_START_ROUTINE) rdpdr_server_thread, (void*) context, 0, NULL); return 0; } static int rdpdr_server_stop(RdpdrServerContext* context) { SetEvent(context->priv->StopEvent); - WaitForSingleObject(context->priv->Thread, INFINITE); CloseHandle(context->priv->Thread); - return 0; } RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm) { RdpdrServerContext* context; - context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext)); if (context) { ZeroMemory(context, sizeof(RdpdrServerContext)); - context->vcm = vcm; - context->Start = rdpdr_server_start; context->Stop = rdpdr_server_stop; - context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate)); if (context->priv) { ZeroMemory(context->priv, sizeof(RdpdrServerPrivate)); - context->priv->VersionMajor = RDPDR_VERSION_MAJOR; context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X; context->priv->ClientId = g_ClientId++; - context->priv->UserLoggedOnPdu = TRUE; } } diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index 2d3adf24c..c792e3716 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -29,17 +29,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sysinfo) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index cd837669f..fff7353c5 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -201,8 +201,8 @@ int rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId, status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); #ifdef WITH_DEBUG_RDPEI - fprintf(stderr, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d\n", - eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status); + WLog_DBG(TAG, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d", + eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status); #endif return status; @@ -239,17 +239,22 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) void rdpei_print_contact_flags(UINT32 contactFlags) { if (contactFlags & CONTACT_FLAG_DOWN) - printf(" CONTACT_FLAG_DOWN"); + WLog_DBG(TAG, " CONTACT_FLAG_DOWN"); + if (contactFlags & CONTACT_FLAG_UPDATE) - printf(" CONTACT_FLAG_UPDATE"); + WLog_DBG(TAG, " CONTACT_FLAG_UPDATE"); + if (contactFlags & CONTACT_FLAG_UP) - printf(" CONTACT_FLAG_UP"); + WLog_DBG(TAG, " CONTACT_FLAG_UP"); + if (contactFlags & CONTACT_FLAG_INRANGE) - printf(" CONTACT_FLAG_INRANGE"); + WLog_DBG(TAG, " CONTACT_FLAG_INRANGE"); + if (contactFlags & CONTACT_FLAG_INCONTACT) - printf(" CONTACT_FLAG_INCONTACT"); + WLog_DBG(TAG, " CONTACT_FLAG_INCONTACT"); + if (contactFlags & CONTACT_FLAG_CANCELED) - printf(" CONTACT_FLAG_CANCELED"); + WLog_DBG(TAG, " CONTACT_FLAG_CANCELED"); } int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) @@ -259,8 +264,8 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) RDPINPUT_CONTACT_DATA* contact; #ifdef WITH_DEBUG_RDPEI - printf("contactCount: %d\n", frame->contactCount); - printf("frameOffset: 0x%08X\n", (UINT32) frame->frameOffset); + WLog_DBG(TAG, "contactCount: %d", frame->contactCount); + WLog_DBG(TAG, "frameOffset: 0x%08X", (UINT32) frame->frameOffset); #endif rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */ @@ -284,13 +289,12 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) contact->contactRectBottom = contact->y + rectSize; #ifdef WITH_DEBUG_RDPEI - printf("contact[%d].contactId: %d\n", index, contact->contactId); - printf("contact[%d].fieldsPresent: %d\n", index, contact->fieldsPresent); - printf("contact[%d].x: %d\n", index, contact->x); - printf("contact[%d].y: %d\n", index, contact->y); - printf("contact[%d].contactFlags: 0x%04X", index, contact->contactFlags); + WLog_DBG(TAG, "contact[%d].contactId: %d", index, contact->contactId); + WLog_DBG(TAG, "contact[%d].fieldsPresent: %d", index, contact->fieldsPresent); + WLog_DBG(TAG, "contact[%d].x: %d", index, contact->x); + WLog_DBG(TAG, "contact[%d].y: %d", index, contact->y); + WLog_DBG(TAG, "contact[%d].contactFlags: 0x%04X", index, contact->contactFlags); rdpei_print_contact_flags(contact->contactFlags); - printf("\n"); #endif Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */ @@ -371,7 +375,7 @@ int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) #if 0 if (protocolVersion != RDPINPUT_PROTOCOL_V10) { - fprintf(stderr, "Unknown [MS-RDPEI] protocolVersion: 0x%08X\n", protocolVersion); + WLog_ERR(TAG, "Unknown [MS-RDPEI] protocolVersion: 0x%08X", protocolVersion); return -1; } #endif @@ -408,8 +412,8 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */ #ifdef WITH_DEBUG_RDPEI - fprintf(stderr, "rdpei_recv_pdu: eventId: %d (%s) length: %d\n", - eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength); + WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %d (%s) length: %d", + eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength); #endif switch (eventId) diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index cf4dccee0..4da19ee84 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -27,10 +27,12 @@ #include #include #include -#include +#include #include +#define TAG CHANNELS_TAG("rdpei.client") + #define RDPINPUT_HEADER_LENGTH 6 /* Protocol Version */ @@ -100,9 +102,9 @@ struct _RDPINPUT_CONTACT_POINT typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT; #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif #endif /* FREERDP_CHANNEL_RDPEI_CLIENT_MAIN_H */ diff --git a/channels/rdpgfx/client/CMakeLists.txt b/channels/rdpgfx/client/CMakeLists.txt index dc47804ce..06fe351ec 100644 --- a/channels/rdpgfx/client/CMakeLists.txt +++ b/channels/rdpgfx/client/CMakeLists.txt @@ -31,17 +31,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-codec freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sysinfo) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index a749478a8..cc02f3b4a 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -23,9 +23,14 @@ #include #include +#include + +#include "rdpgfx_common.h" #include "rdpgfx_codec.h" +#define TAG CHANNELS_TAG("rdpgfx.client") + int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { return 1; @@ -33,8 +38,6 @@ int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { - fprintf(stderr, "RdpGfxDecodeRemoteFx\n"); - return 1; } @@ -48,8 +51,91 @@ int rdpgfx_decode_planar(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) return 1; } +int rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta) +{ + UINT32 index; + RDPGFX_RECT16* regionRect; + RDPGFX_H264_QUANT_QUALITY* quantQualityVal; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ + + if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8)) + return -1; + + meta->regionRects = (RDPGFX_RECT16*) malloc(meta->numRegionRects * sizeof(RDPGFX_RECT16)); + + if (!meta->regionRects) + return -1; + + meta->quantQualityVals = (RDPGFX_H264_QUANT_QUALITY*) malloc(meta->numRegionRects * sizeof(RDPGFX_H264_QUANT_QUALITY)); + + if (!meta->quantQualityVals) + return -1; + + WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %d", (int) meta->numRegionRects); + + for (index = 0; index < meta->numRegionRects; index++) + { + regionRect = &(meta->regionRects[index]); + rdpgfx_read_rect16(s, regionRect); + WLog_DBG(TAG, "regionRects[%d]: left: %d top: %d right: %d bottom: %d", + index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom); + } + + if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 2)) + return -1; + + for (index = 0; index < meta->numRegionRects; index++) + { + quantQualityVal = &(meta->quantQualityVals[index]); + Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */ + Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */ + + quantQualityVal->qp = quantQualityVal->qpVal & 0x3F; + quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1; + quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1; + WLog_DBG(TAG, "quantQualityVals[%d]: qp: %d r: %d p: %d qualityVal: %d", + index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p, quantQualityVal->qualityVal); + } + + return 1; +} + int rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { + int status; + wStream* s; + RDPGFX_H264_BITMAP_STREAM h264; + RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + + s = Stream_New(cmd->data, cmd->length); + + if (!s) + return -1; + + status = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta)); + + if (status < 0) + return -1; + + h264.data = Stream_Pointer(s); + h264.length = (UINT32) Stream_GetRemainingLength(s); + + Stream_Free(s, FALSE); + + cmd->extra = (void*) &h264; + + if (context && context->SurfaceCommand) + { + context->SurfaceCommand(context, cmd); + } + + free(h264.meta.regionRects); + free(h264.meta.quantQualityVals); + return 1; } @@ -63,11 +149,6 @@ int rdpgfx_decode_progressive(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) return 1; } -int rdpgfx_decode_progressive_v2(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) -{ - return 1; -} - int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { int status; @@ -103,7 +184,6 @@ int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) break; case RDPGFX_CODECID_CAPROGRESSIVE_V2: - status = rdpgfx_decode_progressive_v2(gfx, cmd); break; } diff --git a/channels/rdpgfx/client/rdpgfx_common.c b/channels/rdpgfx/client/rdpgfx_common.c index fde1f9325..f66fb7782 100644 --- a/channels/rdpgfx/client/rdpgfx_common.c +++ b/channels/rdpgfx/client/rdpgfx_common.c @@ -87,6 +87,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId) int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) { + if (Stream_GetRemainingLength(s) < 8) + return -1; + Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ @@ -105,6 +108,9 @@ int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header) int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16) { + if (Stream_GetRemainingLength(s) < 4) + return -1; + Stream_Read_UINT16(s, pt16->x); /* x (2 bytes) */ Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */ @@ -121,6 +127,9 @@ int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16) int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16) { + if (Stream_GetRemainingLength(s) < 8) + return -1; + Stream_Read_UINT16(s, rect16->left); /* left (2 bytes) */ Stream_Read_UINT16(s, rect16->top); /* top (2 bytes) */ Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */ @@ -141,6 +150,9 @@ int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16) int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32) { + if (Stream_GetRemainingLength(s) < 4) + return -1; + Stream_Read_UINT8(s, color32->B); /* B (1 byte) */ Stream_Read_UINT8(s, color32->G); /* G (1 byte) */ Stream_Read_UINT8(s, color32->R); /* R (1 byte) */ diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 032b51b81..7e0c518c8 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -37,6 +37,7 @@ #include #include +#include #include "rdpgfx_common.h" #include "rdpgfx_codec.h" @@ -56,20 +57,13 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) gfx = (RDPGFX_PLUGIN*) callback->plugin; - gfx->ThinClient = TRUE; - gfx->SmallCache = FALSE; - gfx->H264 = FALSE; - - gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600; - header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; - pdu.capsSetCount = 1; + pdu.capsSetCount = 0; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; - capsSet = &capsSets[0]; - + capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_8; capsSet->flags = 0; @@ -79,8 +73,7 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; - capsSet = &capsSets[1]; - + capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_81; capsSet->flags = 0; @@ -131,9 +124,14 @@ int rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) pdu.capsSet = &capsSet; + if (Stream_GetRemainingLength(s) < 12) + return -1; + Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */ Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */ + + /*TODO: interpret this answer*/ WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%04X flags: 0x%04X", capsSet.version, capsSet.flags); @@ -180,10 +178,16 @@ int rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 12) + return -1; + Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */ Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */ Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */ + if (Stream_GetRemainingLength(s) < (pdu.monitorCount * 20)) + return -1; + pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF)); if (!pdu.monitorDefArray) @@ -200,6 +204,10 @@ int rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s } pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20)); + + if (Stream_GetRemainingLength(s) < (size_t) pad) + return -1; + Stream_Seek(s, pad); /* pad (total size is 340 bytes) */ WLog_Print(gfx->log, WLOG_DEBUG, "RecvResetGraphicsPdu: width: %d height: %d count: %d", @@ -221,6 +229,9 @@ int rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 2) + return -1; + Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %d", pdu.cacheSlot); @@ -240,8 +251,14 @@ int rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 2) + return -1; + Stream_Read_UINT16(s, pdu.importedEntriesCount); /* cacheSlot (2 bytes) */ + if (Stream_GetRemainingLength(s) < (size_t) (pdu.importedEntriesCount * 2)) + return -1; + pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16)); if (!pdu.cacheSlots) @@ -260,6 +277,8 @@ int rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea context->CacheImportReply(context, &pdu); } + free(pdu.cacheSlots); + return 1; } @@ -269,6 +288,9 @@ int rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 7) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */ Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */ @@ -291,6 +313,9 @@ int rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 2) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteSurfacePdu: surfaceId: %d", pdu.surfaceId); @@ -309,6 +334,9 @@ int rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 8) + return -1; + Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */ Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ @@ -332,6 +360,9 @@ int rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 4) + return -1; + Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ WLog_Print(gfx->log, WLOG_DEBUG, "RecvEndFramePdu: frameId: %d\n", pdu.frameId); @@ -362,6 +393,9 @@ int rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 17) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ @@ -395,9 +429,16 @@ int rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream cmd.length = pdu.bitmapDataLength; cmd.data = pdu.bitmapData; - if (context && context->SurfaceCommand) + if (cmd.codecId == RDPGFX_CODECID_H264) { - context->SurfaceCommand(context, &cmd); + rdpgfx_decode(gfx, &cmd); + } + else + { + if (context && context->SurfaceCommand) + { + context->SurfaceCommand(context, &cmd); + } } return 1; @@ -410,6 +451,9 @@ int rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 13) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */ @@ -451,6 +495,9 @@ int rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* callback, w RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 6) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */ @@ -473,12 +520,16 @@ int rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 8) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - rdpgfx_read_color32(s, &(pdu.fillPixel)); /* fillPixel (4 bytes) */ - Stream_Read_UINT16(s, pdu.fillRectCount); /* fillRectCount (2 bytes) */ + if (Stream_GetRemainingLength(s) < (size_t) (pdu.fillRectCount * 8)) + return -1; + pdu.fillRects = (RDPGFX_RECT16*) calloc(pdu.fillRectCount, sizeof(RDPGFX_RECT16)); if (!pdu.fillRects) @@ -497,6 +548,8 @@ int rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { context->SolidFill(context, &pdu); } + + free(pdu.fillRects); return 1; } @@ -509,13 +562,17 @@ int rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 14) + return -1; + Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */ - rdpgfx_read_rect16(s, &(pdu.rectSrc)); /* rectSrc (8 bytes ) */ - Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */ + if (Stream_GetRemainingLength(s) < (size_t) (pdu.destPtsCount * 4)) + return -1; + pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); if (!pdu.destPts) @@ -538,6 +595,8 @@ int rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea context->SurfaceToSurface(context, &pdu); } + free(pdu.destPts); + return 1; } @@ -547,6 +606,9 @@ int rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 20) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */ Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ @@ -574,10 +636,16 @@ int rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 6) + return -1; + Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */ + if (Stream_GetRemainingLength(s) < (size_t) (pdu.destPtsCount * 4)) + return -1; + pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); if (!pdu.destPts) @@ -608,6 +676,9 @@ int rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wSt RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 12) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */ Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */ @@ -630,6 +701,9 @@ int rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wSt RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + if (Stream_GetRemainingLength(s) < 18) + return -1; + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */ Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */ @@ -655,7 +729,10 @@ int rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) beg = Stream_GetPosition(s); - rdpgfx_read_header(s, &header); + status = rdpgfx_read_header(s, &header); + + if (status < 0) + return -1; #if 1 WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d", @@ -733,17 +810,23 @@ int rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) break; default: - fprintf(stderr, "Unknown GFX cmdId: 0x%04X\n", header.cmdId); + status = -1; break; } + if (status < 0) + { + WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04X)", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); + return -1; + } + end = Stream_GetPosition(s); if (end != (beg + header.pduLength)) { - fprintf(stderr, "Unexpected gfx pdu end: Actual: %d, Expected: %d\n", - end, (beg + header.pduLength)); - + WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %d", + end, (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } @@ -763,18 +846,24 @@ static int rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (status < 0) { - printf("zgfx_decompress failure! status: %d\n", status); + WLog_DBG(TAG, "zgfx_decompress failure! status: %d", status); return 0; } s = Stream_New(pDstData, DstSize); - while (Stream_GetPosition(s) < Stream_Length(s)) + while (((size_t) Stream_GetPosition(s)) < Stream_Length(s)) { status = rdpgfx_recv_pdu(callback, s); + + if (status < 0) + break; } Stream_Free(s, TRUE); + + //free(Stream_Buffer(data)); + //Stream_Free(data,TRUE); return status; } @@ -960,11 +1049,7 @@ void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot) return pData; } -#ifdef STATIC_CHANNELS -#define DVCPluginEntry rdpgfx_DVCPluginEntry -#endif - -int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +int rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { int status = 0; RDPGFX_PLUGIN* gfx; @@ -979,7 +1064,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (!gfx) return -1; - gfx->log = WLog_Get("com.freerdp.gfx.client"); + gfx->log = WLog_Get(TAG); + gfx->settings = (rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints); gfx->iface.Initialize = rdpgfx_plugin_initialize; gfx->iface.Connected = NULL; @@ -991,7 +1077,18 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (!gfx->SurfaceTable) return -1; - gfx->ThinClient = TRUE; + gfx->ThinClient = gfx->settings->GfxThinClient; + gfx->SmallCache = gfx->settings->GfxSmallCache; + gfx->Progressive = gfx->settings->GfxProgressive; + gfx->ProgressiveV2 = gfx->settings->GfxProgressiveV2; + gfx->H264 = gfx->settings->GfxH264; + + if (gfx->H264) + gfx->SmallCache = TRUE; + + if (gfx->SmallCache) + gfx->ThinClient = FALSE; + gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600; context = (RdpgfxClientContext*) calloc(1, sizeof(RdpgfxClientContext)); @@ -1010,6 +1107,9 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) gfx->zgfx = zgfx_context_new(FALSE); + if (!gfx->zgfx) + return -1; + status = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) gfx); } diff --git a/channels/rdpgfx/client/rdpgfx_main.h b/channels/rdpgfx/client/rdpgfx_main.h index e1dc362ea..96d91b4b9 100644 --- a/channels/rdpgfx/client/rdpgfx_main.h +++ b/channels/rdpgfx/client/rdpgfx_main.h @@ -28,9 +28,11 @@ #include #include - +#include #include +#define TAG CHANNELS_TAG("rdpgfx.client") + struct _RDPGFX_CHANNEL_CALLBACK { IWTSVirtualChannelCallback iface; @@ -59,9 +61,12 @@ struct _RDPGFX_PLUGIN RDPGFX_LISTENER_CALLBACK* listener_callback; wLog* log; + rdpSettings* settings; BOOL ThinClient; BOOL SmallCache; + BOOL Progressive; + BOOL ProgressiveV2; BOOL H264; ZGFX_CONTEXT* zgfx; diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index 64bdb2bff..53d16e832 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -25,17 +25,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sysinfo winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpsnd/client/alsa/CMakeLists.txt b/channels/rdpsnd/client/alsa/CMakeLists.txt index d96a0495c..411ca642c 100644 --- a/channels/rdpsnd/client/alsa/CMakeLists.txt +++ b/channels/rdpsnd/client/alsa/CMakeLists.txt @@ -27,15 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES}) diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 0edc08d93..569822349 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include "rdpsnd_main.h" @@ -68,7 +68,7 @@ struct rdpsnd_alsa_plugin #define SND_PCM_CHECK(_func, _status) \ if (_status < 0) \ { \ - fprintf(stderr, "%s: %d\n", _func, _status); \ + WLog_ERR(TAG, "%s: %d\n", _func, _status); \ return -1; \ } @@ -106,8 +106,8 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) if (alsa->buffer_size > buffer_size_max) { - fprintf(stderr, "Warning: requested sound buffer size %d, got %d instead\n", - (int) alsa->buffer_size, (int) buffer_size_max); + WLog_ERR(TAG, "Warning: requested sound buffer size %d, got %d instead\n", + (int) alsa->buffer_size, (int) buffer_size_max); alsa->buffer_size = buffer_size_max; } @@ -262,7 +262,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) if (status < 0) { - DEBUG_WARN("snd_mixer_open failed"); + WLog_ERR(TAG, "snd_mixer_open failed"); return; } @@ -270,7 +270,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) if (status < 0) { - DEBUG_WARN("snd_mixer_attach failed"); + WLog_ERR(TAG, "snd_mixer_attach failed"); snd_mixer_close(alsa->mixer_handle); return; } @@ -279,7 +279,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) if (status < 0) { - DEBUG_WARN("snd_mixer_selem_register failed"); + WLog_ERR(TAG, "snd_mixer_selem_register failed"); snd_mixer_close(alsa->mixer_handle); return; } @@ -288,7 +288,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) if (status < 0) { - DEBUG_WARN("snd_mixer_load failed"); + WLog_ERR(TAG, "snd_mixer_load failed"); snd_mixer_close(alsa->mixer_handle); return; } @@ -310,7 +310,7 @@ static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, i if (status < 0) { - DEBUG_WARN("snd_pcm_open failed"); + WLog_ERR(TAG, "snd_pcm_open failed"); } else { @@ -579,7 +579,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) } else if (status < 0) { - fprintf(stderr, "status: %d\n", status); + WLog_ERR(TAG, "status: %d\n", status); snd_pcm_close(alsa->pcm_handle); alsa->pcm_handle = NULL; rdpsnd_alsa_open((rdpsndDevicePlugin*) alsa, NULL, alsa->latency); @@ -599,8 +599,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) wave->wLocalTimeB += wave->wPlaybackDelay; wave->wLatency = (UINT16) (wave->wLocalTimeB - wave->wLocalTimeA); wave->wTimeStampB = wave->wTimeStampA + wave->wLatency; - - //fprintf(stderr, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency); + //WLog_ERR(TAG, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency); } static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] = diff --git a/channels/rdpsnd/client/ios/CMakeLists.txt b/channels/rdpsnd/client/ios/CMakeLists.txt index 673a4f99c..0190a6b7a 100644 --- a/channels/rdpsnd/client/ios/CMakeLists.txt +++ b/channels/rdpsnd/client/ios/CMakeLists.txt @@ -33,16 +33,13 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${AUDIO_TOOL} ${CORE_AUDIO} ${CORE_FOUNDATION}) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp} + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpsnd/client/ios/TPCircularBuffer.c b/channels/rdpsnd/client/ios/TPCircularBuffer.c index 1dcf47190..137ec789f 100644 --- a/channels/rdpsnd/client/ios/TPCircularBuffer.c +++ b/channels/rdpsnd/client/ios/TPCircularBuffer.c @@ -37,7 +37,7 @@ #define reportResult(result,operation) (_reportResult((result),(operation),__FILE__,__LINE__)) static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) { if ( result != ERR_SUCCESS ) { - printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result)); + WLog_DBG(TAG, "%s:%d: %s: %s\n", file, line, operation, mach_error_string(result)); return false; } return true; @@ -108,7 +108,7 @@ bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) { if ( virtualAddress != bufferAddress+buffer->length ) { // If the memory is not contiguous, clean up both allocated buffers and try again if ( retries-- == 0 ) { - printf("Couldn't map buffer memory to end of buffer\n"); + WLog_DBG(TAG, "Couldn't map buffer memory to end of buffer"); return false; } diff --git a/channels/rdpsnd/client/mac/CMakeLists.txt b/channels/rdpsnd/client/mac/CMakeLists.txt index 8a6f93cb8..103c40665 100644 --- a/channels/rdpsnd/client/mac/CMakeLists.txt +++ b/channels/rdpsnd/client/mac/CMakeLists.txt @@ -33,16 +33,13 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${AUDIO_TOOL} ${CORE_AUDIO} ${CORE_FOUNDATION}) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp) + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 96ffacd89..cfcfa51ad 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -121,7 +121,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in if (status != 0) { - fprintf(stderr, "AudioQueueNewOutput failure\n"); + WLog_ERR(TAG, "AudioQueueNewOutput failure\n"); return; } @@ -135,7 +135,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in if (status != 0) { - printf("AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n"); + WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n"); } for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) @@ -144,7 +144,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in if (status != 0) { - fprintf(stderr, "AudioQueueAllocateBuffer failed\n"); + WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n"); } } @@ -219,7 +219,7 @@ static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) if (status != 0) { - fprintf(stderr, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume); + WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume); } } @@ -238,7 +238,7 @@ static void rdpsnd_mac_start(rdpsndDevicePlugin* device) if (status != 0) { - fprintf(stderr, "AudioQueueStart failed\n"); + WLog_ERR(TAG, "AudioQueueStart failed\n"); } mac->isPlaying = TRUE; diff --git a/channels/rdpsnd/client/opensles/CMakeLists.txt b/channels/rdpsnd/client/opensles/CMakeLists.txt index dc5465a8e..9060761bf 100644 --- a/channels/rdpsnd/client/opensles/CMakeLists.txt +++ b/channels/rdpsnd/client/opensles/CMakeLists.txt @@ -28,13 +28,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils - ${OPENSLES_LIBRARIES}) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES}) +set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index d836afa33..b709ad8f1 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include "opensl_io.h" #include "rdpsnd_main.h" @@ -187,7 +187,7 @@ static void rdpsnd_opensles_open(rdpsndDevicePlugin* device, assert(opensles->stream); if (!opensles->stream) - DEBUG_WARN("android_OpenAudioDevice failed"); + WLog_ERR(TAG, "android_OpenAudioDevice failed"); else rdpsnd_opensles_set_volume(device, opensles->volume); @@ -364,7 +364,7 @@ static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, ret = android_AudioOut(opensles->stream, src.s, size / 2); if (ret < 0) - DEBUG_WARN("android_AudioOut failed (%d)", ret); + WLog_ERR(TAG, "android_AudioOut failed (%d)", ret); } static void rdpsnd_opensles_start(rdpsndDevicePlugin* device) diff --git a/channels/rdpsnd/client/pulse/CMakeLists.txt b/channels/rdpsnd/client/pulse/CMakeLists.txt index 6b6de1ecc..46d525749 100644 --- a/channels/rdpsnd/client/pulse/CMakeLists.txt +++ b/channels/rdpsnd/client/pulse/CMakeLists.txt @@ -27,12 +27,8 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY}) +list(APPEND ${MODULE_PREFIX}_LIBS freerdp) if(GSM_FOUND) list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES}) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index c4fc84637..06c7bde74 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include "rdpsnd_main.h" @@ -195,13 +195,12 @@ void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) } #if 0 - fprintf(stderr, "Server "); + WLog_ERR(TAG, "Server "); rdpsnd_print_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); - fprintf(stderr, "\n"); - - fprintf(stderr, "Client "); + WLog_ERR(TAG, "\n"); + WLog_ERR(TAG, "Client "); rdpsnd_print_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); - fprintf(stderr, "\n"); + WLog_ERR(TAG, "\n"); #endif } @@ -544,7 +543,7 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); - //fprintf(stderr, "msgType %d BodySize %d\n", msgType, BodySize); + //WLog_ERR(TAG, "msgType %d BodySize %d\n", msgType, BodySize); switch (msgType) { @@ -569,7 +568,7 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) break; default: - DEBUG_WARN("unknown msgType %d", msgType); + WLog_ERR(TAG, "unknown msgType %d", msgType); break; } @@ -580,7 +579,7 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlug { if (rdpsnd->device) { - DEBUG_WARN("existing device, abort."); + WLog_ERR(TAG, "existing device, abort."); return; } @@ -606,7 +605,7 @@ static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD if (entry(&entryPoints) != 0) { - DEBUG_WARN("%s entry returns error.", name); + WLog_ERR(TAG, "%s entry returns error.", name); return FALSE; } @@ -795,7 +794,7 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd) if (!rdpsnd->device) { - DEBUG_WARN("no sound device."); + WLog_ERR(TAG, "no sound device."); return; } @@ -875,7 +874,7 @@ int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - fprintf(stderr, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status); + WLog_ERR(TAG, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status); } return status; @@ -907,7 +906,7 @@ static void rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, { if (Stream_Capacity(s) != Stream_GetPosition(s)) { - fprintf(stderr, "rdpsnd_virtual_channel_event_data_received: read error\n"); + WLog_ERR(TAG, "rdpsnd_virtual_channel_event_data_received: read error\n"); } plugin->data_in = NULL; @@ -927,7 +926,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event(DWORD openHandle, UINT e if (!plugin) { - fprintf(stderr, "rdpsnd_virtual_channel_open_event: error no match\n"); + WLog_ERR(TAG, "rdpsnd_virtual_channel_open_event: error no match\n"); return; } @@ -987,7 +986,7 @@ static void rdpsnd_virtual_channel_event_connected(rdpsndPlugin* plugin, LPVOID if (status != CHANNEL_RC_OK) { - fprintf(stderr, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status); + WLog_ERR(TAG, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status); return; } @@ -1040,7 +1039,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event(LPVOID pInitHandle, UINT if (!plugin) { - fprintf(stderr, "rdpsnd_virtual_channel_init_event: error no match\n"); + WLog_ERR(TAG, "rdpsnd_virtual_channel_init_event: error no match\n"); return; } diff --git a/channels/rdpsnd/client/rdpsnd_main.h b/channels/rdpsnd/client/rdpsnd_main.h index 84508a1d5..5b9c41358 100644 --- a/channels/rdpsnd/client/rdpsnd_main.h +++ b/channels/rdpsnd/client/rdpsnd_main.h @@ -25,9 +25,12 @@ #include #include #include +#include + +#define TAG CHANNELS_TAG("rdpsnd.client") #if defined(WITH_DEBUG_SND) -#define DEBUG_SND(fmt, ...) DEBUG_CLASS("rdpsnd", fmt, ## __VA_ARGS__) +#define DEBUG_SND(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else #define DEBUG_SND(fmt, ...) do { } while (0) #endif diff --git a/channels/rdpsnd/client/winmm/CMakeLists.txt b/channels/rdpsnd/client/winmm/CMakeLists.txt index a75d5fe1c..2c670c3ba 100644 --- a/channels/rdpsnd/client/winmm/CMakeLists.txt +++ b/channels/rdpsnd/client/winmm/CMakeLists.txt @@ -26,17 +26,9 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) - +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 961b95e83..cbae34e72 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -34,6 +34,7 @@ #include #include +#include #include "rdpsnd_main.h" @@ -101,11 +102,11 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO switch (uMsg) { case MM_WOM_OPEN: - fprintf(stderr, "MM_WOM_OPEN\n"); + WLog_ERR(TAG, "MM_WOM_OPEN\n"); break; case MM_WOM_CLOSE: - fprintf(stderr, "MM_WOM_CLOSE\n"); + WLog_ERR(TAG, "MM_WOM_CLOSE\n"); break; case MM_WOM_DONE: @@ -121,9 +122,8 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO if (!wave) return; - fprintf(stderr, "MM_WOM_DONE: dwBufferLength: %d cBlockNo: %d\n", - lpWaveHdr->dwBufferLength, wave->cBlockNo); - + WLog_ERR(TAG, "MM_WOM_DONE: dwBufferLength: %d cBlockNo: %d\n", + lpWaveHdr->dwBufferLength, wave->cBlockNo); wave->wLocalTimeB = GetTickCount(); wTimeDelta = wave->wLocalTimeB - wave->wLocalTimeA; wave->wTimeStampB = wave->wTimeStampA + wTimeDelta; @@ -155,7 +155,7 @@ static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (mmResult != MMSYSERR_NOERROR) { - fprintf(stderr, "waveOutOpen failed: %d\n", mmResult); + WLog_ERR(TAG, "waveOutOpen failed: %d\n", mmResult); } } @@ -172,7 +172,7 @@ static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) if (mmResult != MMSYSERR_NOERROR) { - fprintf(stderr, "waveOutClose failure: %d\n", mmResult); + WLog_ERR(TAG, "waveOutClose failure: %d\n", mmResult); } winmm->hWaveOut = NULL; @@ -299,7 +299,7 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) if (mmResult != MMSYSERR_NOERROR) { - fprintf(stderr, "waveOutPrepareHeader failure: %d\n", mmResult); + WLog_ERR(TAG, "waveOutPrepareHeader failure: %d\n", mmResult); return; } @@ -307,7 +307,7 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) if (mmResult != MMSYSERR_NOERROR) { - fprintf(stderr, "waveOutWrite failure: %d\n", mmResult); + WLog_ERR(TAG, "waveOutWrite failure: %d\n", mmResult); waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); return; } diff --git a/channels/rdpsnd/server/CMakeLists.txt b/channels/rdpsnd/server/CMakeLists.txt index 9cb5c1d6f..09fef66e3 100644 --- a/channels/rdpsnd/server/CMakeLists.txt +++ b/channels/rdpsnd/server/CMakeLists.txt @@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index d123b8177..372e06f4a 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -29,9 +29,11 @@ #include #include +#include + #include "rdpsnd_main.h" -static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) +BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) { int pos; UINT16 i; @@ -107,8 +109,7 @@ static BOOL rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStrea Stream_Read_UINT16(s, quality); Stream_Seek_UINT16(s); // reserved - - fprintf(stderr, "Client requested sound quality: %#0X\n", quality); + WLog_ERR(TAG, "Client requested sound quality: %#0X\n", quality); return TRUE; } @@ -116,7 +117,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) { int i, num_known_format = 0; UINT32 flags, vol, pitch; - UINT16 udpPort, version; + UINT16 udpPort; BYTE lastblock; if (Stream_GetRemainingLength(s) < 20) @@ -128,7 +129,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) Stream_Read_UINT16(s, udpPort); /* wDGramPort */ Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */ Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */ - Stream_Read_UINT16(s, version); /* wVersion */ + Stream_Read_UINT16(s, context->clientVersion); /* wVersion */ Stream_Seek_UINT8(s); /* bPad */ /* this check is only a guess as cbSize can influence the size of a format record */ @@ -137,7 +138,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) if (!context->num_client_formats) { - fprintf(stderr, "%s: client doesn't support any format!\n", __FUNCTION__); + WLog_ERR(TAG, "%s: client doesn't support any format!\n", __FUNCTION__); return FALSE; } @@ -174,7 +175,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) if (!context->num_client_formats) { - fprintf(stderr, "%s: client doesn't support any known format!\n", __FUNCTION__); + WLog_ERR(TAG, "%s: client doesn't support any known format!\n", __FUNCTION__); goto out_free; } @@ -187,49 +188,20 @@ out_free: static void* rdpsnd_server_thread(void* arg) { - wStream* s; - DWORD status; - DWORD nCount; - void* buffer; - BYTE msgType; - UINT16 BodySize; + DWORD nCount, status; HANDLE events[8]; - HANDLE ChannelEvent; - DWORD bytesReturned; RdpsndServerContext* context; BOOL doRun; - BOOL waitingHeader; - DWORD expectedBytes; context = (RdpsndServerContext *)arg; - - buffer = NULL; - bytesReturned = 0; - - s = Stream_New(NULL, 4096); - if (!s) - return NULL; - - if (!WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) - { - fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", - __FUNCTION__, bytesReturned); - return NULL; - } - - CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); - WTSFreeMemory(buffer); - nCount = 0; - events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; - if (!rdpsnd_server_send_formats(context, s)) + if (!rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu)) goto out; doRun = TRUE; - waitingHeader = TRUE; - expectedBytes = 4; while (doRun) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -237,69 +209,17 @@ static void* rdpsnd_server_thread(void* arg) if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) break; - if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Pointer(s), expectedBytes, &bytesReturned)) - { - fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__); + if (rdpsnd_server_handle_messages(context) == 0) break; - } - expectedBytes -= bytesReturned; - Stream_Seek(s, bytesReturned); - - if (expectedBytes) - continue; - - Stream_SetPosition(s, 0); - if (waitingHeader) - { - /* header case */ - Stream_Read_UINT8(s, msgType); - Stream_Seek_UINT8(s); /* bPad */ - Stream_Read_UINT16(s, BodySize); - - expectedBytes = BodySize; - waitingHeader = FALSE; - Stream_SetPosition(s, 0); - Stream_EnsureCapacity(s, BodySize); - if (expectedBytes) - continue; - } - - /* when here we have the header + the body */ - switch (msgType) - { - case SNDC_WAVECONFIRM: - doRun = rdpsnd_server_recv_waveconfirm(context, s); - break; - - case SNDC_QUALITYMODE: - doRun = rdpsnd_server_recv_quality_mode(context, s); - break; - - case SNDC_FORMATS: - doRun = rdpsnd_server_recv_formats(context, s); - if (doRun) - { - IFCALL(context->Activated, context); - } - break; - - default: - fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType); - break; - } - - expectedBytes = 4; - waitingHeader = TRUE; - Stream_SetPosition(s, 0); } out: - Stream_Free(s, TRUE); return NULL; } -static BOOL rdpsnd_server_initialize(RdpsndServerContext* context) +static BOOL rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread) { + context->priv->ownThread = ownThread; return context->Start(context) >= 0; } @@ -311,7 +231,7 @@ static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client if (client_format_index < 0 || client_format_index >= context->num_client_formats) { - fprintf(stderr, "%s: index %d is not correct.\n", __FUNCTION__, client_format_index); + WLog_ERR(TAG, "%s: index %d is not correct.\n", __FUNCTION__, client_format_index); return FALSE; } @@ -323,7 +243,7 @@ static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client if (format->nSamplesPerSec == 0) { - fprintf(stderr, "%s: invalid Client Sound Format!!\n", __FUNCTION__); + WLog_ERR(TAG, "%s: invalid Client Sound Format!!\n", __FUNCTION__); return FALSE; } @@ -546,22 +466,42 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context) static int rdpsnd_server_start(RdpsndServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); - if (!context->priv->ChannelHandle) + void *buffer = NULL; + DWORD bytesReturned; + RdpsndServerPrivate *priv = context->priv; + + priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + if (!priv->ChannelHandle) return -1; - context->priv->rdpsnd_pdu = Stream_New(NULL, 4096); - if (!context->priv->rdpsnd_pdu) + if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + { + WLog_ERR(TAG, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", + __FUNCTION__, bytesReturned); + + if (buffer) + WTSFreeMemory(buffer); + goto out_close; + } + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + priv->rdpsnd_pdu = Stream_New(NULL, 4096); + if (!priv->rdpsnd_pdu) goto out_close; - context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!context->priv->StopEvent) - goto out_pdu; - context->priv->Thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); - if (!context->priv->Thread) - goto out_stopEvent; + if (priv->ownThread) + { + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!context->priv->StopEvent) + goto out_pdu; + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); + if (!context->priv->Thread) + goto out_stopEvent; + } return 0; @@ -579,12 +519,15 @@ out_close: static int rdpsnd_server_stop(RdpsndServerContext* context) { - if (context->priv->StopEvent) + if (context->priv->ownThread) { - SetEvent(context->priv->StopEvent); + if (context->priv->StopEvent) + { + SetEvent(context->priv->StopEvent); - WaitForSingleObject(context->priv->Thread, INFINITE); - CloseHandle(context->priv->Thread); + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + } } return 0; @@ -593,8 +536,9 @@ static int rdpsnd_server_stop(RdpsndServerContext* context) RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) { RdpsndServerContext* context; + RdpsndServerPrivate *priv; - context = (RdpsndServerContext*) calloc(1, sizeof(RdpsndServerContext)); + context = (RdpsndServerContext *)calloc(1, sizeof(RdpsndServerContext)); if (!context) return NULL; @@ -610,16 +554,25 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->SetVolume = rdpsnd_server_set_volume; context->Close = rdpsnd_server_close; - context->priv = (RdpsndServerPrivate*) calloc(1, sizeof(RdpsndServerPrivate)); - if (!context->priv) + context->priv = priv = (RdpsndServerPrivate *)calloc(1, sizeof(RdpsndServerPrivate)); + if (!priv) goto out_free; - context->priv->dsp_context = freerdp_dsp_context_new(); - if (!context->priv->dsp_context) + priv->dsp_context = freerdp_dsp_context_new(); + if (!priv->dsp_context) goto out_free_priv; + priv->input_stream = Stream_New(NULL, 4); + if (!priv->input_stream) + goto out_free_dsp; + + priv->expectedBytes = 4; + priv->waitingHeader = TRUE; + priv->ownThread = TRUE; return context; +out_free_dsp: + freerdp_dsp_context_free(priv->dsp_context); out_free_priv: free(context->priv); out_free: @@ -627,6 +580,15 @@ out_free: return NULL; } + +void rdpsnd_server_context_reset(RdpsndServerContext *context) +{ + context->priv->expectedBytes = 4; + context->priv->waitingHeader = TRUE; + + Stream_SetPosition(context->priv->input_stream, 0); +} + void rdpsnd_server_context_free(RdpsndServerContext* context) { if (!context->priv->StopEvent) @@ -652,3 +614,99 @@ void rdpsnd_server_context_free(RdpsndServerContext* context) free(context); } + +HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context) +{ + return context->priv->channelEvent; +} + +/* + * Handle rpdsnd messages - server side + * + * @param Server side context + * + * @return -1 if no data could be read, + * 0 on error (like connection close), + * 1 on succsess (also if further bytes need to be read) + */ +int rdpsnd_server_handle_messages(RdpsndServerContext *context) +{ + DWORD bytesReturned; + BOOL ret; + + RdpsndServerPrivate *priv = context->priv; + wStream *s = priv->input_stream; + + if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return -1; + + WLog_ERR(TAG, "%s: channel connection closed\n", __FUNCTION__); + return 0; + } + priv->expectedBytes -= bytesReturned; + Stream_Seek(s, bytesReturned); + + if (priv->expectedBytes) + return 1; + + Stream_SealLength(s); + Stream_SetPosition(s, 0); + if (priv->waitingHeader) + { + /* header case */ + Stream_Read_UINT8(s, priv->msgType); + Stream_Seek_UINT8(s); /* bPad */ + Stream_Read_UINT16(s, priv->expectedBytes); + + priv->waitingHeader = FALSE; + Stream_SetPosition(s, 0); + if (priv->expectedBytes) + { + Stream_EnsureCapacity(s, priv->expectedBytes); + return 1; + } + } + + /* when here we have the header + the body */ +#ifdef WITH_DEBUG_SND + WLog_DBG(TAG, "message type %d", priv->msgType); +#endif + priv->expectedBytes = 4; + priv->waitingHeader = TRUE; + + switch (priv->msgType) + { + case SNDC_WAVECONFIRM: + ret = rdpsnd_server_recv_waveconfirm(context, s); + break; + + case SNDC_FORMATS: + ret = rdpsnd_server_recv_formats(context, s); + + if (ret && context->clientVersion < 6) + IFCALL(context->Activated, context); + + break; + + case SNDC_QUALITYMODE: + ret = rdpsnd_server_recv_quality_mode(context, s); + Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */ + + if (ret && context->clientVersion >= 6) + IFCALL(context->Activated, context); + break; + + default: + WLog_ERR(TAG, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, priv->msgType); + ret = FALSE; + break; + } + Stream_SetPosition(s, 0); + + if (ret) + return 1; + else + return 0; +} diff --git a/channels/rdpsnd/server/rdpsnd_main.h b/channels/rdpsnd/server/rdpsnd_main.h index 6322cee4a..20ed42d80 100644 --- a/channels/rdpsnd/server/rdpsnd_main.h +++ b/channels/rdpsnd/server/rdpsnd_main.h @@ -27,14 +27,23 @@ #include #include +#include #include +#define TAG CHANNELS_TAG("rdpsnd.server") + struct _rdpsnd_server_private { + BOOL ownThread; HANDLE Thread; HANDLE StopEvent; + HANDLE channelEvent; void* ChannelHandle; + BOOL waitingHeader; + DWORD expectedBytes; + BYTE msgType; + wStream* input_stream; wStream* rdpsnd_pdu; BYTE* out_buffer; int out_buffer_size; diff --git a/channels/remdesk/CMakeLists.txt b/channels/remdesk/CMakeLists.txt new file mode 100644 index 000000000..23f1cf7b2 --- /dev/null +++ b/channels/remdesk/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel("remdesk") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/remdesk/ChannelOptions.cmake b/channels/remdesk/ChannelOptions.cmake new file mode 100644 index 000000000..17518e619 --- /dev/null +++ b/channels/remdesk/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "remdesk" TYPE "static" + DESCRIPTION "Remote Assistance Virtual Channel Extension" + SPECIFICATIONS "[MS-RA]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/remdesk/client/CMakeLists.txt b/channels/remdesk/client/CMakeLists.txt new file mode 100644 index 000000000..ed90b2948 --- /dev/null +++ b/channels/remdesk/client/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel_client("remdesk") + +set(${MODULE_PREFIX}_SRCS + remdesk_main.c + remdesk_main.h) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c new file mode 100644 index 000000000..2ad69243d --- /dev/null +++ b/channels/remdesk/client/remdesk_main.c @@ -0,0 +1,803 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 +#include + +#include "remdesk_main.h" + +RemdeskClientContext* remdesk_get_client_interface(remdeskPlugin* remdesk) +{ + RemdeskClientContext* pInterface; + pInterface = (RemdeskClientContext*) remdesk->channelEntryPoints.pInterface; + return pInterface; +} + +int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) +{ + UINT32 status = 0; + + if (!remdesk) + return -1; + + status = remdesk->channelEntryPoints.pVirtualChannelWrite(remdesk->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_Length(s), s); + + if (status != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "VirtualChannelWrite failed %d", status); + return -1; + } + + return 1; +} + +int remdesk_generate_expert_blob(remdeskPlugin* remdesk) +{ + char* name; + char* pass; + char* password; + rdpSettings* settings = remdesk->settings; + + if (remdesk->ExpertBlob) + return 1; + + if (settings->RemoteAssistancePassword) + password = settings->RemoteAssistancePassword; + else + password = settings->Password; + + if (!password) + return -1; + + name = settings->Username; + + if (!name) + name = "Expert"; + + remdesk->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password, + settings->RemoteAssistancePassStub, &(remdesk->EncryptedPassStubSize)); + + if (!remdesk->EncryptedPassStub) + return -1; + + pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub, remdesk->EncryptedPassStubSize); + + if (!pass) + return -1; + + remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass); + + if (!remdesk->ExpertBlob) + return -1; + + return 1; +} + +static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + UINT32 ChannelNameLen; + char* pChannelName = NULL; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + if (ChannelNameLen > 64) + return -1; + + if ((ChannelNameLen % 2) != 0) + return -1; + + if (Stream_GetRemainingLength(s) < ChannelNameLen) + return -1; + + ZeroMemory(header->ChannelName, sizeof(header->ChannelName)); + + pChannelName = (char*) header->ChannelName; + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), + ChannelNameLen / 2, &pChannelName, 32, NULL, NULL); + + Stream_Seek(s, ChannelNameLen); + + if (status <= 0) + return -1; + + return 1; +} + +static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int index; + UINT32 ChannelNameLen; + WCHAR ChannelNameW[32]; + + ZeroMemory(ChannelNameW, sizeof(ChannelNameW)); + + for (index = 0; index < 32; index++) + { + ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + } + + ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; + + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ + + return 1; +} + +static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) +{ + remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader); + Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */ + return 1; +} + +static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) +{ + ctlHeader->msgType = msgType; + strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + ctlHeader->DataLength = 4 + msgSize; + return 1; +} + +static int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + return 1; +} + +static int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + UINT32 versionMajor; + UINT32 versionMinor; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */ + Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */ + + return 1; +} + +static int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) +{ + wStream* s; + REMDESK_CTL_VERSION_INFO_PDU pdu; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8); + + pdu.versionMajor = 1; + pdu.versionMinor = 2; + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */ + Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */ + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + return 1; +} + +static int remdesk_recv_ctl_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header, UINT32 *pResult) +{ + UINT32 result; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, result); /* result (4 bytes) */ + + *pResult = result; + //WLog_DBG(TAG, "RemdeskRecvResult: 0x%04X", result); + return 1; +} + +static int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_AUTHENTICATE_PDU pdu; + + status = remdesk_generate_expert_blob(remdesk); + + if (status < 0) + return -1; + + pdu.expertBlob = remdesk->ExpertBlob; + pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); + + if (status <= 0) + return -1; + + cbRaConnectionStringW = status * 2; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); + + if (status <= 0) + return -1; + + cbExpertBlobW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE, + cbRaConnectionStringW + cbExpertBlobW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); + Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(raConnectionStringW); + free(expertBlobW); + + return 1; +} + +static int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; + + pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); + + if (status <= 0) + return -1; + + cbRaConnectionStringW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_REMOTE_CONTROL_DESKTOP, cbRaConnectionStringW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(raConnectionStringW); + + return 1; +} + +static int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + REMDESK_CTL_VERIFY_PASSWORD_PDU pdu; + + status = remdesk_generate_expert_blob(remdesk); + + if (status < 0) + return -1; + + pdu.expertBlob = remdesk->ExpertBlob; + + status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); + + if (status <= 0) + return -1; + + cbExpertBlobW = status * 2; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + free(expertBlobW); + + return 1; +} + +static int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) +{ + int status; + wStream* s; + REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu; + + status = remdesk_generate_expert_blob(remdesk); + + if (status < 0) + return -1; + + pdu.EncryptedPasswordLength = remdesk->EncryptedPassStubSize; + pdu.EncryptedPassword = remdesk->EncryptedPassStub; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA, + pdu.EncryptedPasswordLength); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength); + + Stream_SealLength(s); + + remdesk_virtual_channel_write(remdesk, s); + + return 1; +} + +static int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status = 1; + UINT32 msgType = 0; + UINT32 result = 0; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ + + //WLog_DBG(TAG, "msgType: %d", msgType); + + switch (msgType) + { + case REMDESK_CTL_REMOTE_CONTROL_DESKTOP: + break; + + case REMDESK_CTL_RESULT: + status = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result); + break; + + case REMDESK_CTL_AUTHENTICATE: + break; + + case REMDESK_CTL_SERVER_ANNOUNCE: + status = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header); + break; + + case REMDESK_CTL_DISCONNECT: + break; + + case REMDESK_CTL_VERSIONINFO: + status = remdesk_recv_ctl_version_info_pdu(remdesk, s, header); + + if (remdesk->Version == 1) + { + if (status >= 0) + status = remdesk_send_ctl_version_info_pdu(remdesk); + + if (status >= 0) + status = remdesk_send_ctl_authenticate_pdu(remdesk); + + if (status >= 0) + status = remdesk_send_ctl_remote_control_desktop_pdu(remdesk); + } + else if (remdesk->Version == 2) + { + if (status >= 0) + status = remdesk_send_ctl_expert_on_vista_pdu(remdesk); + + if (status >= 0) + status = remdesk_send_ctl_verify_password_pdu(remdesk); + } + + break; + + case REMDESK_CTL_ISCONNECTED: + break; + + case REMDESK_CTL_VERIFY_PASSWORD: + break; + + case REMDESK_CTL_EXPERT_ON_VISTA: + break; + + case REMDESK_CTL_RANOVICE_NAME: + break; + + case REMDESK_CTL_RAEXPERT_NAME: + break; + + case REMDESK_CTL_TOKEN: + break; + + default: + WLog_ERR(TAG, "unknown msgType: %d", msgType); + status = -1; + break; + } + + return status; +} + +static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) +{ + int status = 1; + REMDESK_CHANNEL_HEADER header; + +#if 0 + WLog_DBG(TAG, "RemdeskReceive: %d", Stream_GetRemainingLength(s)); + winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s)); +#endif + + remdesk_read_channel_header(s, &header); + + if (strcmp(header.ChannelName, "RC_CTL") == 0) + { + status = remdesk_recv_ctl_pdu(remdesk, s, &header); + } + else if (strcmp(header.ChannelName, "70") == 0) + { + + } + else if (strcmp(header.ChannelName, "71") == 0) + { + + } + else if (strcmp(header.ChannelName, ".") == 0) + { + + } + else if (strcmp(header.ChannelName, "1000.") == 0) + { + + } + else if (strcmp(header.ChannelName, "RA_FX") == 0) + { + + } + else + { + + } + + return status; +} + +static void remdesk_process_connect(remdeskPlugin* remdesk) +{ + remdesk->settings = (rdpSettings*) remdesk->channelEntryPoints.pExtendedData; +} + +/****************************************************************************************/ + +static wListDictionary* g_InitHandles; +static wListDictionary* g_OpenHandles; + +void remdesk_add_init_handle_data(void* pInitHandle, void* pUserData) +{ + if (!g_InitHandles) + g_InitHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_InitHandles, pInitHandle, pUserData); +} + +void* remdesk_get_init_handle_data(void* pInitHandle) +{ + void* pUserData = NULL; + pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); + return pUserData; +} + +void remdesk_remove_init_handle_data(void* pInitHandle) +{ + ListDictionary_Remove(g_InitHandles, pInitHandle); +} + +void remdesk_add_open_handle_data(DWORD openHandle, void* pUserData) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + g_OpenHandles = ListDictionary_New(TRUE); + + ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData); +} + +void* remdesk_get_open_handle_data(DWORD openHandle) +{ + void* pUserData = NULL; + void* pOpenHandle = (void*) (size_t) openHandle; + pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); + return pUserData; +} + +void remdesk_remove_open_handle_data(DWORD openHandle) +{ + void* pOpenHandle = (void*) (size_t) openHandle; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); +} + +int remdesk_send(remdeskPlugin* remdesk, wStream* s) +{ + UINT32 status = 0; + remdeskPlugin* plugin = (remdeskPlugin*) remdesk; + + if (!plugin) + { + status = CHANNEL_RC_BAD_INIT_HANDLE; + } + else + { + status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle, + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + } + + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "VirtualChannelWrite failed %d", status); + } + + return status; +} + +static void remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + wStream* data_in; + + if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) + { + return; + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (remdesk->data_in) + Stream_Free(remdesk->data_in, TRUE); + + remdesk->data_in = Stream_New(NULL, totalLength); + } + + data_in = remdesk->data_in; + Stream_EnsureRemainingCapacity(data_in, (int) dataLength); + Stream_Write(data_in, pData, dataLength); + + if (dataFlags & CHANNEL_FLAG_LAST) + { + if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + { + WLog_ERR(TAG, "read error"); + } + + remdesk->data_in = NULL; + Stream_SealLength(data_in); + Stream_SetPosition(data_in, 0); + + MessageQueue_Post(remdesk->MsgPipe->In, NULL, 0, (void*) data_in, NULL); + } +} + +static VOID VCAPITYPE remdesk_virtual_channel_open_event(DWORD openHandle, UINT event, + LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +{ + remdeskPlugin* remdesk; + + remdesk = (remdeskPlugin*) remdesk_get_open_handle_data(openHandle); + + if (!remdesk) + { + WLog_ERR(TAG, "error no match"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; + + case CHANNEL_EVENT_USER: + break; + } +} + +static void* remdesk_virtual_channel_client_thread(void* arg) +{ + wStream* data; + wMessage message; + remdeskPlugin* remdesk = (remdeskPlugin*) arg; + + remdesk_process_connect(remdesk); + + while (1) + { + if (!MessageQueue_Wait(remdesk->MsgPipe->In)) + break; + + if (MessageQueue_Peek(remdesk->MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + if (message.id == 0) + { + data = (wStream*) message.wParam; + remdesk_process_receive(remdesk, data); + } + } + } + + ExitThread(0); + return NULL; +} + +static void remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData, UINT32 dataLength) +{ + UINT32 status; + + status = remdesk->channelEntryPoints.pVirtualChannelOpen(remdesk->InitHandle, + &remdesk->OpenHandle, remdesk->channelDef.name, remdesk_virtual_channel_open_event); + + remdesk_add_open_handle_data(remdesk->OpenHandle, remdesk); + + if (status != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "open failed: status: %d", status); + return; + } + + remdesk->MsgPipe = MessagePipe_New(); + + remdesk->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) remdesk_virtual_channel_client_thread, (void*) remdesk, 0, NULL); +} + +static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk) +{ + MessagePipe_PostQuit(remdesk->MsgPipe, 0); + WaitForSingleObject(remdesk->thread, INFINITE); + + MessagePipe_Free(remdesk->MsgPipe); + CloseHandle(remdesk->thread); + + remdesk->channelEntryPoints.pVirtualChannelClose(remdesk->OpenHandle); + + if (remdesk->data_in) + { + Stream_Free(remdesk->data_in, TRUE); + remdesk->data_in = NULL; + } + + remdesk_remove_open_handle_data(remdesk->OpenHandle); + remdesk_remove_init_handle_data(remdesk->InitHandle); +} + +static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +{ + remdeskPlugin* remdesk; + + remdesk = (remdeskPlugin*) remdesk_get_init_handle_data(pInitHandle); + + if (!remdesk) + { + WLog_ERR(TAG, "error no match"); + return; + } + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + remdesk_virtual_channel_event_connected(remdesk, pData, dataLength); + break; + + case CHANNEL_EVENT_DISCONNECTED: + break; + + case CHANNEL_EVENT_TERMINATED: + remdesk_virtual_channel_event_terminated(remdesk); + break; + } +} + +/* remdesk is always built-in */ +#define VirtualChannelEntry remdesk_VirtualChannelEntry + +BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) +{ + remdeskPlugin* remdesk; + RemdeskClientContext* context; + CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; + + remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin)); + + if (!remdesk) + return FALSE; + + remdesk->channelDef.options = + CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | + CHANNEL_OPTION_SHOW_PROTOCOL; + + strcpy(remdesk->channelDef.name, "remdesk"); + + remdesk->Version = 2; + + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints; + + if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) && + (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) + { + context = (RemdeskClientContext*) calloc(1, sizeof(RemdeskClientContext)); + + context->handle = (void*) remdesk; + + *(pEntryPointsEx->ppInterface) = (void*) context; + } + + CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); + + remdesk->channelEntryPoints.pVirtualChannelInit(&remdesk->InitHandle, + &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, remdesk_virtual_channel_init_event); + + remdesk->channelEntryPoints.pInterface = *(remdesk->channelEntryPoints.ppInterface); + remdesk->channelEntryPoints.ppInterface = &(remdesk->channelEntryPoints.pInterface); + + remdesk_add_init_handle_data(remdesk->InitHandle, (void*) remdesk); + + return 1; +} diff --git a/channels/remdesk/client/remdesk_main.h b/channels/remdesk/client/remdesk_main.h new file mode 100644 index 000000000..e47773f57 --- /dev/null +++ b/channels/remdesk/client/remdesk_main.h @@ -0,0 +1,58 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H +#define FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#define TAG CHANNELS_TAG("remdesk.client") + +struct remdesk_plugin +{ + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints; + + HANDLE thread; + wStream* data_in; + void* InitHandle; + DWORD OpenHandle; + wMessagePipe* MsgPipe; + rdpSettings* settings; + + UINT32 Version; + char* ExpertBlob; + BYTE* EncryptedPassStub; + int EncryptedPassStubSize; +}; +typedef struct remdesk_plugin remdeskPlugin; + +#endif /* FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H */ diff --git a/channels/remdesk/server/CMakeLists.txt b/channels/remdesk/server/CMakeLists.txt new file mode 100644 index 000000000..c20bd0618 --- /dev/null +++ b/channels/remdesk/server/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel_server("remdesk") + +set(${MODULE_PREFIX}_SRCS + remdesk_main.c + remdesk_main.h) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c new file mode 100644 index 000000000..4a7670ebd --- /dev/null +++ b/channels/remdesk/server/remdesk_main.c @@ -0,0 +1,547 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 "remdesk_main.h" + +int remdesk_virtual_channel_write(RemdeskServerContext* context, wStream* s) +{ + BOOL status; + ULONG BytesWritten = 0; + + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), Stream_Length(s), &BytesWritten); + + return (status) ? 1 : -1; +} + +static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + UINT32 ChannelNameLen; + char* pChannelName = NULL; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + if (ChannelNameLen > 64) + return -1; + + if ((ChannelNameLen % 2) != 0) + return -1; + + if (Stream_GetRemainingLength(s) < ChannelNameLen) + return -1; + + ZeroMemory(header->ChannelName, sizeof(header->ChannelName)); + + pChannelName = (char*) header->ChannelName; + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), + ChannelNameLen / 2, &pChannelName, 32, NULL, NULL); + + Stream_Seek(s, ChannelNameLen); + + if (status <= 0) + return -1; + + return 1; +} + +static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int index; + UINT32 ChannelNameLen; + WCHAR ChannelNameW[32]; + + ZeroMemory(ChannelNameW, sizeof(ChannelNameW)); + + for (index = 0; index < 32; index++) + { + ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + } + + ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; + + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + + Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ + + return 1; +} + +static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) +{ + remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader); + Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */ + return 1; +} + +static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize) +{ + ctlHeader->msgType = msgType; + strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME); + ctlHeader->DataLength = 4 + msgSize; + return 1; +} + +static int remdesk_send_ctl_result_pdu(RemdeskServerContext* context, UINT32 result) +{ + wStream* s; + REMDESK_CTL_RESULT_PDU pdu; + + pdu.result = result; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_RESULT, 4); + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write_UINT32(s, pdu.result); /* result (4 bytes) */ + + Stream_SealLength(s); + + remdesk_virtual_channel_write(context, s); + + Stream_Free(s, TRUE); + + return 1; +} + +static int remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context) +{ + wStream* s; + REMDESK_CTL_VERSION_INFO_PDU pdu; + + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8); + + pdu.versionMajor = 1; + pdu.versionMinor = 2; + + s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); + + remdesk_write_ctl_header(s, &(pdu.ctlHeader)); + + Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */ + Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */ + + Stream_SealLength(s); + + remdesk_virtual_channel_write(context, s); + + return 1; +} + +static int remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + UINT32 versionMajor; + UINT32 versionMinor; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */ + Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */ + + return 1; +} + +static int remdesk_recv_ctl_remote_control_desktop_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cchStringW; + WCHAR* pStringW; + UINT32 msgLength; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; + + msgLength = header->DataLength - 4; + + pStringW = (WCHAR*) Stream_Pointer(s); + raConnectionStringW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbRaConnectionStringW = cchStringW * 2; + + pdu.raConnectionString = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, + cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + + if (status <= 0) + return -1; + + WLog_INFO(TAG, "RaConnectionString: %s", + pdu.raConnectionString); + free(pdu.raConnectionString); + + remdesk_send_ctl_result_pdu(context, 0); + + return 1; +} + +static int remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cchStringW; + WCHAR* pStringW; + UINT32 msgLength; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + int cbRaConnectionStringW = 0; + WCHAR* raConnectionStringW = NULL; + REMDESK_CTL_AUTHENTICATE_PDU pdu; + + msgLength = header->DataLength - 4; + + pStringW = (WCHAR*) Stream_Pointer(s); + raConnectionStringW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbRaConnectionStringW = cchStringW * 2; + + pStringW += cchStringW; + expertBlobW = pStringW; + cchStringW = 0; + + while ((msgLength > 0) && pStringW[cchStringW]) + { + msgLength -= 2; + cchStringW++; + } + + if (pStringW[cchStringW] || !cchStringW) + return -1; + + cchStringW++; + cbExpertBlobW = cchStringW * 2; + + pdu.raConnectionString = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, + cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + + if (status <= 0) + return -1; + + pdu.expertBlob = NULL; + + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, + cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); + + if (status <= 0) + return -1; + + WLog_INFO(TAG, "RaConnectionString: %s ExpertBlob: %s", + pdu.raConnectionString, pdu.expertBlob); + free(pdu.raConnectionString); + free(pdu.expertBlob); + + return 1; +} + +static int remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status; + int cbExpertBlobW = 0; + WCHAR* expertBlobW = NULL; + REMDESK_CTL_VERIFY_PASSWORD_PDU pdu; + + if (Stream_GetRemainingLength(s) < 8) + return -1; + + pdu.expertBlob = NULL; + expertBlobW = (WCHAR*) Stream_Pointer(s); + cbExpertBlobW = header->DataLength - 4; + + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); + WLog_INFO(TAG, "ExpertBlob: %s", pdu.expertBlob); + remdesk_send_ctl_result_pdu(context, 0); + + return 1; +} + +static int remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +{ + int status = 1; + UINT32 msgType = 0; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ + WLog_INFO(TAG, "msgType: %d", msgType); + + switch (msgType) + { + case REMDESK_CTL_REMOTE_CONTROL_DESKTOP: + status = remdesk_recv_ctl_remote_control_desktop_pdu(context, s, header); + break; + + case REMDESK_CTL_AUTHENTICATE: + status = remdesk_recv_ctl_authenticate_pdu(context, s, header); + break; + + case REMDESK_CTL_DISCONNECT: + break; + + case REMDESK_CTL_VERSIONINFO: + status = remdesk_recv_ctl_version_info_pdu(context, s, header); + break; + + case REMDESK_CTL_ISCONNECTED: + break; + + case REMDESK_CTL_VERIFY_PASSWORD: + status = remdesk_recv_ctl_verify_password_pdu(context, s, header); + break; + + case REMDESK_CTL_EXPERT_ON_VISTA: + break; + + case REMDESK_CTL_RANOVICE_NAME: + break; + + case REMDESK_CTL_RAEXPERT_NAME: + break; + + case REMDESK_CTL_TOKEN: + break; + + default: + WLog_ERR(TAG, "remdesk_recv_control_pdu: unknown msgType: %d", msgType); + status = -1; + break; + } + + return status; +} + +static int remdesk_server_receive_pdu(RemdeskServerContext* context, wStream* s) +{ + int status = 1; + REMDESK_CHANNEL_HEADER header; + +#if 0 + WLog_INFO(TAG, "RemdeskReceive: %d", Stream_GetRemainingLength(s)); + winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s)); +#endif + + remdesk_read_channel_header(s, &header); + + if (strcmp(header.ChannelName, "RC_CTL") == 0) + { + status = remdesk_recv_ctl_pdu(context, s, &header); + } + else if (strcmp(header.ChannelName, "70") == 0) + { + + } + else if (strcmp(header.ChannelName, "71") == 0) + { + + } + else if (strcmp(header.ChannelName, ".") == 0) + { + + } + else if (strcmp(header.ChannelName, "1000.") == 0) + { + + } + else if (strcmp(header.ChannelName, "RA_FX") == 0) + { + + } + else + { + + } + + return 1; +} + +static void* remdesk_server_thread(void* arg) +{ + wStream* s; + DWORD status; + DWORD nCount; + void* buffer; + UINT32* pHeader; + UINT32 PduLength; + HANDLE events[8]; + HANDLE ChannelEvent; + DWORD BytesReturned; + RemdeskServerContext* context; + + context = (RemdeskServerContext*) arg; + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + s = Stream_New(NULL, 4096); + + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = ChannelEvent; + events[nCount++] = context->priv->StopEvent; + + remdesk_send_ctl_version_info_pdu(context); + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + { + if (BytesReturned) + Stream_Seek(s, BytesReturned); + } + else + { + Stream_EnsureRemainingCapacity(s, BytesReturned); + } + + if (Stream_GetPosition(s) >= 8) + { + pHeader = (UINT32*) Stream_Buffer(s); + PduLength = pHeader[0] + pHeader[1] + 8; + + if (PduLength >= Stream_GetPosition(s)) + { + Stream_SealLength(s); + Stream_SetPosition(s, 0); + remdesk_server_receive_pdu(context, s); + Stream_SetPosition(s, 0); + } + } + } + + Stream_Free(s, TRUE); + + return NULL; +} + +static int remdesk_server_start(RemdeskServerContext* context) +{ + context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "remdesk"); + + if (!context->priv->ChannelHandle) + return -1; + + context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + context->priv->Thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) remdesk_server_thread, (void*) context, 0, NULL); + + return 1; +} + +static int remdesk_server_stop(RemdeskServerContext* context) +{ + SetEvent(context->priv->StopEvent); + + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + + return 1; +} + +RemdeskServerContext* remdesk_server_context_new(HANDLE vcm) +{ + RemdeskServerContext* context; + + context = (RemdeskServerContext*) calloc(1, sizeof(RemdeskServerContext)); + + if (context) + { + context->vcm = vcm; + + context->Start = remdesk_server_start; + context->Stop = remdesk_server_stop; + + context->priv = (RemdeskServerPrivate*) calloc(1, sizeof(RemdeskServerPrivate)); + + if (context->priv) + { + context->priv->Version = 1; + } + } + + return context; +} + +void remdesk_server_context_free(RemdeskServerContext* context) +{ + if (context) + { + if (context->priv) + { + free(context->priv); + } + + free(context); + } +} diff --git a/channels/remdesk/server/remdesk_main.h b/channels/remdesk/server/remdesk_main.h new file mode 100644 index 000000000..3c35b45a6 --- /dev/null +++ b/channels/remdesk/server/remdesk_main.h @@ -0,0 +1,42 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H +#define FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H + +#include +#include +#include + +#include +#include + +#define TAG CHANNELS_TAG("remdesk.server") + +struct _remdesk_server_private +{ + HANDLE Thread; + HANDLE StopEvent; + void* ChannelHandle; + + UINT32 Version; +}; + +#endif /* FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H */ + diff --git a/channels/serial/client/CMakeLists.txt b/channels/serial/client/CMakeLists.txt index d170689b5..1a40d472a 100644 --- a/channels/serial/client/CMakeLists.txt +++ b/channels/serial/client/CMakeLists.txt @@ -18,21 +18,13 @@ define_channel_client("serial") set(${MODULE_PREFIX}_SRCS - serial_tty.c - serial_tty.h - serial_constants.h serial_main.c) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/serial/client/serial_constants.h b/channels/serial/client/serial_constants.h deleted file mode 100644 index a42c4f001..000000000 --- a/channels/serial/client/serial_constants.h +++ /dev/null @@ -1,154 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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 __SERIAL_CONSTANTS_H -#define __SERIAL_CONSTANTS_H - -/* http://www.codeproject.com/KB/system/chaiyasit_t.aspx */ -#define SERIAL_TIMEOUT_MAX 4294967295u - -/* DR_CONTROL_REQ.IoControlCode */ -enum DR_PORT_CONTROL_REQ -{ - IOCTL_SERIAL_SET_BAUD_RATE = 0x001B0004, - IOCTL_SERIAL_GET_BAUD_RATE = 0x001B0050, - IOCTL_SERIAL_SET_LINE_CONTROL = 0x001B000C, - IOCTL_SERIAL_GET_LINE_CONTROL = 0x001B0054, - IOCTL_SERIAL_SET_TIMEOUTS = 0x001B001C, - IOCTL_SERIAL_GET_TIMEOUTS = 0x001B0020, - -/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ - IOCTL_SERIAL_GET_CHARS = 0x001B0058, - IOCTL_SERIAL_SET_CHARS = 0x001B005C, - - IOCTL_SERIAL_SET_DTR = 0x001B0024, - IOCTL_SERIAL_CLR_DTR = 0x001B0028, - IOCTL_SERIAL_RESET_DEVICE = 0x001B002C, - IOCTL_SERIAL_SET_RTS = 0x001B0030, - IOCTL_SERIAL_CLR_RTS = 0x001B0034, - IOCTL_SERIAL_SET_XOFF = 0x001B0038, - IOCTL_SERIAL_SET_XON = 0x001B003C, - IOCTL_SERIAL_SET_BREAK_ON = 0x001B0010, - IOCTL_SERIAL_SET_BREAK_OFF = 0x001B0014, - IOCTL_SERIAL_SET_QUEUE_SIZE = 0x001B0008, - IOCTL_SERIAL_GET_WAIT_MASK = 0x001B0040, - IOCTL_SERIAL_SET_WAIT_MASK = 0x001B0044, - IOCTL_SERIAL_WAIT_ON_MASK = 0x001B0048, - IOCTL_SERIAL_IMMEDIATE_CHAR = 0x001B0018, - IOCTL_SERIAL_PURGE = 0x001B004C, - IOCTL_SERIAL_GET_HANDFLOW = 0x001B0060, - IOCTL_SERIAL_SET_HANDFLOW = 0x001B0064, - IOCTL_SERIAL_GET_MODEMSTATUS = 0x001B0068, - IOCTL_SERIAL_GET_DTRRTS = 0x001B0078, - -/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */ - IOCTL_SERIAL_GET_COMMSTATUS = 0x001B006C, - - IOCTL_SERIAL_GET_PROPERTIES = 0x001B0074, - IOCTL_SERIAL_XOFF_COUNTER = 0x001B0070, - IOCTL_SERIAL_LSRMST_INSERT = 0x001B007C, - IOCTL_SERIAL_CONFIG_SIZE = 0x001B0080, - IOCTL_SERIAL_GET_STATS = 0x001B008C, - IOCTL_SERIAL_CLEAR_STATS = 0x001B0090, - IOCTL_SERIAL_GET_MODEM_CONTROL = 0x001B0094, - IOCTL_SERIAL_SET_MODEM_CONTROL = 0x001B0098, - IOCTL_SERIAL_SET_FIFO_CONTROL = 0x001B009C, -}; - -enum SERIAL_PURGE_MASK -{ - SERIAL_PURGE_TXABORT = 0x00000001, - SERIAL_PURGE_RXABORT = 0x00000002, - SERIAL_PURGE_TXCLEAR = 0x00000004, - SERIAL_PURGE_RXCLEAR = 0x00000008, -}; - -enum SERIAL_WAIT_MASK -{ - SERIAL_EV_RXCHAR = 0x0001, /* Any Character received */ - SERIAL_EV_RXFLAG = 0x0002, /* Received certain character */ - SERIAL_EV_TXEMPTY = 0x0004, /* Transmitt Queue Empty */ - SERIAL_EV_CTS = 0x0008, /* CTS changed state */ - SERIAL_EV_DSR = 0x0010, /* DSR changed state */ - SERIAL_EV_RLSD = 0x0020, /* RLSD changed state */ - SERIAL_EV_BREAK = 0x0040, /* BREAK received */ - SERIAL_EV_ERR = 0x0080, /* Line status error occurred */ - SERIAL_EV_RING = 0x0100, /* Ring signal detected */ - SERIAL_EV_PERR = 0x0200, /* Printer error occured */ - SERIAL_EV_RX80FULL = 0x0400,/* Receive buffer is 80 percent full */ - SERIAL_EV_EVENT1 = 0x0800, /* Provider specific event 1 */ - SERIAL_EV_EVENT2 = 0x1000, /* Provider specific event 2 */ -}; - -enum SERIAL_MODEM_STATUS -{ - SERIAL_MS_DTR = 0x01, - SERIAL_MS_RTS = 0x02, - SERIAL_MS_CTS = 0x10, - SERIAL_MS_DSR = 0x20, - SERIAL_MS_RNG = 0x40, - SERIAL_MS_CAR = 0x80, -}; - -enum SERIAL_HANDFLOW -{ - SERIAL_DTR_CONTROL = 0x01, - SERIAL_CTS_HANDSHAKE = 0x08, - SERIAL_ERROR_ABORT = 0x80000000, -}; - -enum SERIAL_FLOW_CONTROL -{ - SERIAL_XON_HANDSHAKE = 0x01, - SERIAL_XOFF_HANDSHAKE = 0x02, - SERIAL_DSR_SENSITIVITY = 0x40, -}; - -enum SERIAL_CHARS -{ - SERIAL_CHAR_EOF = 0, - SERIAL_CHAR_ERROR = 1, - SERIAL_CHAR_BREAK = 2, - SERIAL_CHAR_EVENT = 3, - SERIAL_CHAR_XON = 4, - SERIAL_CHAR_XOFF = 5, -}; - -enum SERIAL_ABORT_IO -{ - SERIAL_ABORT_IO_NONE = 0, - SERIAL_ABORT_IO_WRITE = 1, - SERIAL_ABORT_IO_READ = 2, -}; - -enum SERIAL_STOP_BITS -{ - SERIAL_STOP_BITS_1 = 0, - SERIAL_STOP_BITS_2 = 2, -}; - -enum SERIAL_PARITY -{ - SERIAL_NO_PARITY = 0, - SERIAL_ODD_PARITY = 1, - SERIAL_EVEN_PARITY = 2, -}; - -#endif diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index de78217bd..17d5692d7 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -4,6 +4,7 @@ * * Copyright 2011 O.S. Systems Software Ltda. * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Hewlett-Packard Development Company, L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,115 +24,206 @@ #endif #include +#include #include +#include #include #include -#include - -#ifdef HAVE_SYS_MODEM_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include -#endif -#ifdef HAVE_SYS_STRTIO_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "serial_tty.h" -#include "serial_constants.h" +#include +#include #include -#include +#include #include #include -#include -#include +#include #include #include +/* TODO: all #ifdef __linux__ could be removed once only some generic + * functions will be used. Replace CommReadFile by ReadFile, + * CommWriteFile by WriteFile etc.. */ +#if defined __linux__ && !defined ANDROID + +#define MAX_IRP_THREADS 5 + typedef struct _SERIAL_DEVICE SERIAL_DEVICE; struct _SERIAL_DEVICE { DEVICE device; - - char* path; - SERIAL_TTY* tty; + BOOL permissive; + SERIAL_DRIVER_ID ServerSerialDriverId; + HANDLE* hComm; wLog* log; - HANDLE thread; - wMessageQueue* IrpQueue; + HANDLE MainThread; + wMessageQueue* MainIrpQueue; + + /* one thread per pending IRP and indexed according their CompletionId */ + wListDictionary *IrpThreads; + UINT32 IrpThreadToBeTerminatedCount; + CRITICAL_SECTION TerminatingIrpThreadsLock; }; +typedef struct _IRP_THREAD_DATA IRP_THREAD_DATA; + +struct _IRP_THREAD_DATA +{ + SERIAL_DEVICE *serial; + IRP *irp; +}; + +static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial) +{ + /* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ + + switch(GetLastError()) + { + case ERROR_BAD_DEVICE: + return STATUS_INVALID_DEVICE_REQUEST; + + case ERROR_CALL_NOT_IMPLEMENTED: + return STATUS_NOT_IMPLEMENTED; + + case ERROR_CANCELLED: + return STATUS_CANCELLED; + + case ERROR_INSUFFICIENT_BUFFER: + return STATUS_BUFFER_TOO_SMALL; /* NB: STATUS_BUFFER_SIZE_TOO_SMALL not defined */ + + case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */ + return STATUS_INVALID_DEVICE_STATE; + + case ERROR_INVALID_HANDLE: + return STATUS_INVALID_DEVICE_REQUEST; + + case ERROR_INVALID_PARAMETER: + return STATUS_INVALID_PARAMETER; + + case ERROR_IO_DEVICE: + return STATUS_IO_DEVICE_ERROR; + + case ERROR_IO_PENDING: + return STATUS_PENDING; + + case ERROR_NOT_SUPPORTED: + return STATUS_NOT_SUPPORTED; + + case ERROR_TIMEOUT: + return STATUS_TIMEOUT; + + /* no default */ + } + + WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%lx", GetLastError()); + return STATUS_UNSUCCESSFUL; +} + static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { - int status; - UINT32 FileId; + DWORD DesiredAccess; + DWORD SharedAccess; + DWORD CreateDisposition; UINT32 PathLength; - char* path = NULL; - SERIAL_TTY* tty; - Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */ - Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ - Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* SharedAccess (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* CreateDisposition (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ + Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ + Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ + Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ + Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */ + Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */ + Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ + Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ + Stream_Seek(irp->input, PathLength); /* Path (variable) */ - Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ + assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), - PathLength / 2, &path, 0, NULL, NULL); - if (status < 1) - path = (char*) calloc(1, 1); +#ifndef _WIN32 + /* Windows 2012 server sends on a first call : + * DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES + * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ + * CreateDisposition = 0x00000001: CREATE_NEW + * + * then Windows 2012 sends : + * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA + * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ + * CreateDisposition = 0x00000001: CREATE_NEW + * + * assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); + * assert(SharedAccess == 0); + * assert(CreateDisposition == OPEN_EXISTING); + * + */ - FileId = irp->devman->id_sequence++; + WLog_Print(serial->log, WLOG_DEBUG, "DesiredAccess: 0x%lX, SharedAccess: 0x%lX, CreateDisposition: 0x%lX", DesiredAccess, SharedAccess, CreateDisposition); - tty = serial_tty_new(serial->path, FileId); + /* FIXME: As of today only the flags below are supported by CommCreateFileA: */ + DesiredAccess = GENERIC_READ | GENERIC_WRITE; + SharedAccess = 0; + CreateDisposition = OPEN_EXISTING; +#endif - if (!tty) + serial->hComm = CreateFile(serial->device.name, + DesiredAccess, + SharedAccess, + NULL, /* SecurityAttributes */ + CreateDisposition, + 0, /* FlagsAndAttributes */ + NULL); /* TemplateFile */ + + if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { + WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: Ox%lX\n", serial->device.name, GetLastError()); + irp->IoStatus = STATUS_UNSUCCESSFUL; - FileId = 0; - } - else - { - serial->tty = tty; + goto error_handle; } - Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ + _comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId); - free(path); + _comm_set_permissive(serial->hComm, serial->permissive); - irp->Complete(irp); + /* NOTE: binary mode/raw mode required for the redirection. On + * Linux, CommCreateFileA forces this setting. + */ + /* ZeroMemory(&dcb, sizeof(DCB)); */ + /* dcb.DCBlength = sizeof(DCB); */ + /* GetCommState(serial->hComm, &dcb); */ + /* dcb.fBinary = TRUE; */ + /* SetCommState(serial->hComm, &dcb); */ + + assert(irp->FileId == 0); + irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ + + irp->IoStatus = STATUS_SUCCESS; + + WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) created.", serial->device.name, irp->device->id, irp->FileId); + + error_handle: + Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ + Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ } static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) { - SERIAL_TTY* tty = serial->tty; - Stream_Seek(irp->input, 32); /* Padding (32 bytes) */ - if (!tty) + if (!CloseHandle(serial->hComm)) { + WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%d) closed.", serial->device.name, irp->device->id); irp->IoStatus = STATUS_UNSUCCESSFUL; - } - else - { - serial_tty_free(tty); - serial->tty = NULL; + goto error_handle; } + WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) closed.", serial->device.name, irp->device->id, irp->FileId); + + serial->hComm = NULL; + irp->IoStatus = STATUS_SUCCESS; + + error_handle: Stream_Zero(irp->output, 5); /* Padding (5 bytes) */ - - irp->Complete(irp); } static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) @@ -139,119 +231,175 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) UINT32 Length; UINT64 Offset; BYTE* buffer = NULL; - SERIAL_TTY* tty = serial->tty; + DWORD nbRead = 0; Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) + + buffer = (BYTE*)calloc(Length, sizeof(BYTE)); + if (buffer == NULL) { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + + /* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored + * assert(Offset == 0); + */ + + + WLog_Print(serial->log, WLOG_DEBUG, "reading %d bytes from %s", Length, serial->device.name); + + /* FIXME: CommReadFile to be replaced by ReadFile */ + if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL)) + { + irp->IoStatus = STATUS_SUCCESS; } else { - buffer = (BYTE*) malloc(Length); + WLog_Print(serial->log, WLOG_DEBUG, "read failure to %s, nbRead=%ld, last-error: 0x%lX", serial->device.name, nbRead, GetLastError()); - if (!serial_tty_read(tty, buffer, &Length)) - { - irp->IoStatus = STATUS_UNSUCCESSFUL; - free(buffer); - buffer = NULL; - Length = 0; - } - else - { - - } + irp->IoStatus = _GetLastErrorToIoStatus(serial); } - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ + WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes read from %s", nbRead, serial->device.name); - if (Length > 0) + error_handle: + + Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */ + + if (nbRead > 0) { - Stream_EnsureRemainingCapacity(irp->output, Length); - Stream_Write(irp->output, buffer, Length); + Stream_EnsureRemainingCapacity(irp->output, nbRead); + Stream_Write(irp->output, buffer, nbRead); /* ReadData */ } - free(buffer); - - irp->Complete(irp); + if (buffer) + free(buffer); } static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) { - int status; UINT32 Length; UINT64 Offset; - SERIAL_TTY* tty = serial->tty; + DWORD nbWritten = 0; Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) - { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; + /* MS-RDPESP 3.2.5.1.5: The Offset field is ignored + * assert(Offset == 0); + * + * Using a serial printer, noticed though this field could be + * set. + */ - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); - return; + WLog_Print(serial->log, WLOG_DEBUG, "writing %d bytes to %s", Length, serial->device.name); + + /* FIXME: CommWriteFile to be replaced by WriteFile */ + if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, NULL)) + { + irp->IoStatus = STATUS_SUCCESS; + } + else + { + WLog_Print(serial->log, WLOG_DEBUG, "write failure to %s, nbWritten=%ld, last-error: 0x%lX", serial->device.name, nbWritten, GetLastError()); + + irp->IoStatus = _GetLastErrorToIoStatus(serial); } - status = serial_tty_write(tty, Stream_Pointer(irp->input), Length); + WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes written to %s", nbWritten, serial->device.name); - if (status < 0) - { - irp->IoStatus = STATUS_UNSUCCESSFUL; - Length = 0; - - printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno); - - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); - return; - } - - Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */ + Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ - irp->Complete(irp); } + static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) { UINT32 IoControlCode; UINT32 InputBufferLength; + BYTE* InputBuffer = NULL; UINT32 OutputBufferLength; - UINT32 abortIo = SERIAL_ABORT_IO_NONE; - SERIAL_TTY* tty = serial->tty; + BYTE* OutputBuffer = NULL; + DWORD BytesReturned = 0; Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */ Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */ Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - if (!tty) + OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE)); + if (OutputBuffer == NULL) { - irp->IoStatus = STATUS_UNSUCCESSFUL; - OutputBufferLength = 0; + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE)); + if (InputBuffer == NULL) + { + irp->IoStatus = STATUS_NO_MEMORY; + goto error_handle; + } + + Stream_Read(irp->input, InputBuffer, InputBufferLength); + + WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); + + /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ + if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) + { + /* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s done", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); */ + + irp->IoStatus = STATUS_SUCCESS; } else { - irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo); + WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl failure: IoControlCode=[0x%X] %s, last-error: 0x%lX", + IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); + + irp->IoStatus = _GetLastErrorToIoStatus(serial); } - irp->Complete(irp); + error_handle: + + /* FIXME: find out whether it's required or not to get + * BytesReturned == OutputBufferLength when + * CommDeviceIoControl returns FALSE */ + assert(OutputBufferLength == BytesReturned); + + Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */ + + if (BytesReturned > 0) + { + Stream_EnsureRemainingCapacity(irp->output, BytesReturned); + Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */ + } + /* FIXME: Why at least Windows 2008R2 gets lost with this + * extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The + * extra byte is well required according MS-RDPEFS + * 2.2.1.5.5 */ + /* else */ + /* { */ + /* Stream_Write_UINT8(irp->output, 0); /\* Padding (1 byte) *\/ */ + /* } */ + + if (InputBuffer != NULL) + free(InputBuffer); + + if (OutputBuffer != NULL) + free(OutputBuffer); } static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) { WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n", - irp->MajorFunction, irp->MinorFunction); + irp->MajorFunction, irp->MinorFunction); switch (irp->MajorFunction) { @@ -277,92 +425,362 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) default: irp->IoStatus = STATUS_NOT_SUPPORTED; - irp->Complete(irp); break; } } + +static void* irp_thread_func(void* arg) +{ + IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg; + + /* blocks until the end of the request */ + serial_process_irp(data->serial, data->irp); + + EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock); + data->serial->IrpThreadToBeTerminatedCount++; + + data->irp->Complete(data->irp); + + LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock); + + /* NB: At this point, the server might already being reusing + * the CompletionId whereas the thread is not yet + * terminated */ + + free(data); + + ExitThread(0); + return NULL; +} + + +static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp) +{ + IRP_THREAD_DATA *data = NULL; + HANDLE irpThread = INVALID_HANDLE_VALUE; + HANDLE previousIrpThread; + uintptr_t key; + + /* for a test/debug purpose, uncomment the code below to get a + * single thread for all IRPs. NB: two IRPs could not be + * processed at the same time, typically two concurent + * Read/Write operations could block each other. */ + /* serial_process_irp(serial, irp); */ + /* irp->Complete(irp); */ + /* return; */ + + + /* NOTE: for good or bad, this implementation relies on the + * server to avoid a flooding of requests. see also _purge(). + */ + + EnterCriticalSection(&serial->TerminatingIrpThreadsLock); + while (serial->IrpThreadToBeTerminatedCount > 0) + { + /* Cleaning up termitating and pending irp + * threads. See also: irp_thread_func() */ + + HANDLE irpThread; + ULONG_PTR *ids; + int i, nbIds; + + nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); + for (i=0; iIrpThreads, (void*)id); + + /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ + waitResult = WaitForSingleObject(irpThread, 0); + if (waitResult == WAIT_OBJECT_0) + { + /* terminating thread */ + + /* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%d naturally died", id); */ + + CloseHandle(irpThread); + ListDictionary_Remove(serial->IrpThreads, (void*)id); + + serial->IrpThreadToBeTerminatedCount--; + } + else if (waitResult != WAIT_TIMEOUT) + { + /* unexpected thread state */ + + WLog_Print(serial->log, WLOG_WARN, "WaitForSingleObject, got an unexpected result=0x%lX\n", waitResult); + assert(FALSE); + } + /* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */ + } + + + if (serial->IrpThreadToBeTerminatedCount > 0) + { + WLog_Print(serial->log, WLOG_DEBUG, "%d IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount); + Sleep(1); /* 1 ms */ + } + } + LeaveCriticalSection(&serial->TerminatingIrpThreadsLock); + + /* NB: At this point and thanks to the synchronization we're + * sure that the incoming IRP uses well a recycled + * CompletionId or the server sent again an IRP already posted + * which didn't get yet a response (this later server behavior + * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and + * mstsc.exe). + * + * FIXME: behavior documented somewhere? behavior not yet + * observed with FreeRDP). + */ + + key = irp->CompletionId; + previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key); + if (previousIrpThread) + { + /* Thread still alived <=> Request still pending */ + + WLog_Print(serial->log, WLOG_DEBUG, "IRP recall: IRP with the CompletionId=%d not yet completed!", irp->CompletionId); + + assert(FALSE); /* unimplemented */ + + /* TODO: asserts that previousIrpThread handles well + * the same request by checking more details. Need an + * access to the IRP object used by previousIrpThread + */ + + /* TODO: taking over the pending IRP or sending a kind + * of wake up signal to accelerate the pending + * request + * + * To be considered: + * if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { + * pComm->PendingEvents |= SERIAL_EV_FREERDP_*; + * } + */ + + irp->Discard(irp); + return; + } + + + if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) + { + WLog_Print(serial->log, WLOG_WARN, "Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads)); + + assert(FALSE); /* unimplemented */ + + /* TODO: MAX_IRP_THREADS has been thought to avoid a + * flooding of pending requests. Use + * WaitForMultipleObjects() when available in winpr + * for threads. + */ + } + + + /* error_handle to be used ... */ + + data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA)); + if (data == NULL) + { + WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA."); + goto error_handle; + } + + data->serial = serial; + data->irp = irp; + + /* data freed by irp_thread_func */ + + irpThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE)irp_thread_func, + (void*)data, + 0, + NULL); + + if (irpThread == INVALID_HANDLE_VALUE) + { + WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread."); + goto error_handle; + } + + + key = irp->CompletionId; + ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread); + + return; + + error_handle: + + irp->IoStatus = STATUS_NO_MEMORY; + irp->Complete(irp); + + if (data) + free(data); +} + + +static void terminate_pending_irp_threads(SERIAL_DEVICE *serial) +{ + ULONG_PTR *ids; + int i, nbIds; + + nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); + + WLog_Print(serial->log, WLOG_DEBUG, "Terminating %d IRP thread(s)", nbIds); + + for (i=0; iIrpThreads, (void*)id); + + TerminateThread(irpThread, 0); + + WaitForSingleObject(irpThread, INFINITE); + + CloseHandle(irpThread); + + WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %d", id); + } + + ListDictionary_Clear(serial->IrpThreads); +} + + static void* serial_thread_func(void* arg) { IRP* irp; wMessage message; - SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; while (1) { - if (!MessageQueue_Wait(drive->IrpQueue)) + if (!MessageQueue_Wait(serial->MainIrpQueue)) break; - if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE)) + if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE)) break; if (message.id == WMQ_QUIT) + { + terminate_pending_irp_threads(serial); break; + } irp = (IRP*) message.wParam; if (irp) - serial_process_irp(drive, irp); + create_irp_thread(serial, irp); } ExitThread(0); return NULL; } + static void serial_irp_request(DEVICE* device, IRP* irp) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; - MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL); + + assert(irp != NULL); + + if (irp == NULL) + return; + + /* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this + * allows the server to send multiple simultaneous read or + * write requests. + */ + + MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); } + static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; WLog_Print(serial->log, WLOG_DEBUG, "freeing"); - MessageQueue_PostQuit(serial->IrpQueue, 0); - WaitForSingleObject(serial->thread, INFINITE); - CloseHandle(serial->thread); + MessageQueue_PostQuit(serial->MainIrpQueue, 0); + WaitForSingleObject(serial->MainThread, INFINITE); + CloseHandle(serial->MainThread); - serial_tty_free(serial->tty); + if (serial->hComm) + CloseHandle(serial->hComm); /* Clean up resources */ Stream_Free(serial->device.data, TRUE); - MessageQueue_Free(serial->IrpQueue); + MessageQueue_Free(serial->MainIrpQueue); + ListDictionary_Free(serial->IrpThreads); + DeleteCriticalSection(&serial->TerminatingIrpThreadsLock); free(serial); } +#endif /* __linux__ */ + #ifdef STATIC_CHANNELS #define DeviceServiceEntry serial_DeviceServiceEntry #endif int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { - int i, len; char* name; char* path; + char* driver; RDPDR_SERIAL* device; +#if defined __linux__ && !defined ANDROID + int i, len; SERIAL_DEVICE* serial; +#endif /* __linux__ */ device = (RDPDR_SERIAL*) pEntryPoints->device; name = device->Name; path = device->Path; + driver = device->Driver; if (!name || (name[0] == '*')) { - /* TODO: implement auto detection of parallel ports */ + /* TODO: implement auto detection of serial ports */ return 0; } if ((name && name[0]) && (path && path[0])) { - serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); + wLog* log; + WLog_Init(); + log = WLog_Get("com.freerdp.channel.serial.client"); + WLog_Print(log, WLOG_DEBUG, "initializing"); + +#ifndef __linux__ /* to be removed */ + + WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform."); + return -1; + +#else /* __linux __ */ + + WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path); + + if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) + { + return -1; + } + + serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); if (!serial) return -1; + serial->log = log; + serial->device.type = RDPDR_DTYP_SERIAL; serial->device.name = name; serial->device.IRPRequest = serial_irp_request; @@ -374,17 +792,62 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); - serial->path = path; - serial->IrpQueue = MessageQueue_New(NULL); + if (driver != NULL) + { + if (_stricmp(driver, "Serial") == 0) + serial->ServerSerialDriverId = SerialDriverSerialSys; + else if (_stricmp(driver, "SerCx") == 0) + serial->ServerSerialDriverId = SerialDriverSerCxSys; + else if (_stricmp(driver, "SerCx2") == 0) + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + else + { + assert(FALSE); - WLog_Init(); - serial->log = WLog_Get("com.freerdp.channel.serial.client"); - WLog_Print(serial->log, WLOG_DEBUG, "initializing"); + WLog_Print(serial->log, WLOG_DEBUG, "Unknown server's serial driver: %s. SerCx2 will be used", driver); + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + } + } + else + { + /* default driver */ + serial->ServerSerialDriverId = SerialDriverSerCx2Sys; + } + + + if (device->Permissive != NULL) + { + if (_stricmp(device->Permissive, "permissive") == 0) + { + serial->permissive = TRUE; + } + else + { + WLog_Print(serial->log, WLOG_DEBUG, "Unknown flag: %s", device->Permissive); + assert(FALSE); + } + } + + + WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, serial->ServerSerialDriverId); + /* TODO: implement auto detection of the server's serial driver */ + + serial->MainIrpQueue = MessageQueue_New(NULL); + + /* IrpThreads content only modified by create_irp_thread() */ + serial->IrpThreads = ListDictionary_New(FALSE); + serial->IrpThreadToBeTerminatedCount = 0; + InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); + serial->MainThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) serial_thread_func, + (void*) serial, + 0, + NULL); +#endif /* __linux __ */ } return 0; diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c deleted file mode 100644 index 9e65a71ef..000000000 --- a/channels/serial/client/serial_tty.c +++ /dev/null @@ -1,1013 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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 -#include -#include - -#include - -#ifndef _WIN32 -#include -#include -#include -#include -#endif - -#include -#include -#include -#include - -#include "serial_tty.h" -#include "serial_constants.h" - -#ifdef HAVE_SYS_MODEM_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include -#endif -#ifdef HAVE_SYS_STRTIO_H -#include -#endif - -#ifndef CRTSCTS -#define CRTSCTS 0 -#endif - -/* FIONREAD should really do the same thing as TIOCINQ, where it is not available */ - -#if !defined(TIOCINQ) && defined(FIONREAD) -#define TIOCINQ FIONREAD -#endif - -#if !defined(TIOCOUTQ) && defined(FIONWRITE) -#define TIOCOUTQ FIONWRITE -#endif - -/** - * Refer to ReactOS's ntddser.h (public domain) for constant definitions - */ - -static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len); -static void tty_set_termios(SERIAL_TTY* tty); -static BOOL tty_get_termios(SERIAL_TTY* tty); -static int tty_get_error_status(); - -UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abortIo) -{ - UINT32 result; - BYTE immediate; - int purge_mask; - UINT32 modemstate; - UINT32 begPos, endPos; - UINT32 OutputBufferLength; - UINT32 status = STATUS_SUCCESS; - UINT32 IoCtlDeviceType; - UINT32 IoCtlFunction; - UINT32 IoCtlMethod; - UINT32 IoCtlAccess; - - IoCtlMethod = (IoControlCode & 0x3); - IoCtlFunction = ((IoControlCode >> 2) & 0xFFF); - IoCtlAccess = ((IoControlCode >> 14) & 0x3); - IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF); - - /** - * FILE_DEVICE_SERIAL_PORT 0x0000001B - * FILE_DEVICE_UNKNOWN 0x00000022 - */ - - if (IoCtlDeviceType == 0x00000022) - { - IoControlCode &= 0xFFFF; - IoControlCode |= (0x0000001B << 16); - } - - Stream_Seek_UINT32(output); /* OutputBufferLength (4 bytes) */ - begPos = (UINT32) Stream_GetPosition(output); - - switch (IoControlCode) - { - case IOCTL_SERIAL_SET_BAUD_RATE: - Stream_Read_UINT32(input, tty->baud_rate); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_GET_BAUD_RATE: - OutputBufferLength = 4; - Stream_Write_UINT32(output, tty->baud_rate); - break; - - case IOCTL_SERIAL_SET_QUEUE_SIZE: - Stream_Read_UINT32(input, tty->queue_in_size); - Stream_Read_UINT32(input, tty->queue_out_size); - break; - - case IOCTL_SERIAL_SET_LINE_CONTROL: - Stream_Read_UINT8(input, tty->stop_bits); - Stream_Read_UINT8(input, tty->parity); - Stream_Read_UINT8(input, tty->word_length); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_GET_LINE_CONTROL: - OutputBufferLength = 3; - Stream_Write_UINT8(output, tty->stop_bits); - Stream_Write_UINT8(output, tty->parity); - Stream_Write_UINT8(output, tty->word_length); - break; - - case IOCTL_SERIAL_IMMEDIATE_CHAR: - Stream_Read_UINT8(input, immediate); - tty_write_data(tty, &immediate, 1); - break; - - case IOCTL_SERIAL_CONFIG_SIZE: - OutputBufferLength = 4; - Stream_Write_UINT32(output, 0); - break; - - case IOCTL_SERIAL_GET_CHARS: - OutputBufferLength = 6; - Stream_Write(output, tty->chars, 6); - break; - - case IOCTL_SERIAL_SET_CHARS: - Stream_Read(input, tty->chars, 6); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_GET_HANDFLOW: - OutputBufferLength = 16; - tty_get_termios(tty); - Stream_Write_UINT32(output, tty->control); - Stream_Write_UINT32(output, tty->xonoff); - Stream_Write_UINT32(output, tty->onlimit); - Stream_Write_UINT32(output, tty->offlimit); - break; - - case IOCTL_SERIAL_SET_HANDFLOW: - Stream_Read_UINT32(input, tty->control); - Stream_Read_UINT32(input, tty->xonoff); - Stream_Read_UINT32(input, tty->onlimit); - Stream_Read_UINT32(input, tty->offlimit); - tty_set_termios(tty); - break; - - case IOCTL_SERIAL_SET_TIMEOUTS: - Stream_Read_UINT32(input, tty->read_interval_timeout); - Stream_Read_UINT32(input, tty->read_total_timeout_multiplier); - Stream_Read_UINT32(input, tty->read_total_timeout_constant); - Stream_Read_UINT32(input, tty->write_total_timeout_multiplier); - Stream_Read_UINT32(input, tty->write_total_timeout_constant); - - /* http://www.codeproject.com/KB/system/chaiyasit_t.aspx, see 'ReadIntervalTimeout' section - http://msdn.microsoft.com/en-us/library/ms885171.aspx */ - if (tty->read_interval_timeout == SERIAL_TIMEOUT_MAX) - { - tty->read_interval_timeout = 0; - tty->read_total_timeout_multiplier = 0; - } - - break; - - case IOCTL_SERIAL_GET_TIMEOUTS: - OutputBufferLength = 20; - Stream_Write_UINT32(output, tty->read_interval_timeout); - Stream_Write_UINT32(output, tty->read_total_timeout_multiplier); - Stream_Write_UINT32(output, tty->read_total_timeout_constant); - Stream_Write_UINT32(output, tty->write_total_timeout_multiplier); - Stream_Write_UINT32(output, tty->write_total_timeout_constant); - break; - - case IOCTL_SERIAL_GET_WAIT_MASK: - OutputBufferLength = 4; - Stream_Write_UINT32(output, tty->wait_mask); - break; - - case IOCTL_SERIAL_SET_WAIT_MASK: - Stream_Read_UINT32(input, tty->wait_mask); - break; - - case IOCTL_SERIAL_SET_DTR: - ioctl(tty->fd, TIOCMGET, &result); - result |= TIOCM_DTR; - ioctl(tty->fd, TIOCMSET, &result); - tty->dtr = 1; - break; - - case IOCTL_SERIAL_CLR_DTR: - ioctl(tty->fd, TIOCMGET, &result); - result &= ~TIOCM_DTR; - ioctl(tty->fd, TIOCMSET, &result); - tty->dtr = 0; - break; - - case IOCTL_SERIAL_SET_RTS: - ioctl(tty->fd, TIOCMGET, &result); - result |= TIOCM_RTS; - ioctl(tty->fd, TIOCMSET, &result); - tty->rts = 1; - break; - - case IOCTL_SERIAL_CLR_RTS: - ioctl(tty->fd, TIOCMGET, &result); - result &= ~TIOCM_RTS; - ioctl(tty->fd, TIOCMSET, &result); - tty->rts = 0; - break; - - case IOCTL_SERIAL_GET_MODEMSTATUS: - modemstate = 0; -#ifdef TIOCMGET - ioctl(tty->fd, TIOCMGET, &result); - if (result & TIOCM_CTS) - modemstate |= SERIAL_MS_CTS; - if (result & TIOCM_DSR) - modemstate |= SERIAL_MS_DSR; - if (result & TIOCM_RNG) - modemstate |= SERIAL_MS_RNG; - if (result & TIOCM_CAR) - modemstate |= SERIAL_MS_CAR; - if (result & TIOCM_DTR) - modemstate |= SERIAL_MS_DTR; - if (result & TIOCM_RTS) - modemstate |= SERIAL_MS_RTS; -#endif - OutputBufferLength = 4; - Stream_Write_UINT32(output, modemstate); - break; - - case IOCTL_SERIAL_GET_COMMSTATUS: - OutputBufferLength = 18; - Stream_Write_UINT32(output, 0); /* Errors */ - Stream_Write_UINT32(output, 0); /* Hold reasons */ - - result = 0; -#ifdef TIOCINQ - ioctl(tty->fd, TIOCINQ, &result); -#endif - Stream_Write_UINT32(output, result); /* Amount in in queue */ - - result = 0; -#ifdef TIOCOUTQ - ioctl(tty->fd, TIOCOUTQ, &result); -#endif - Stream_Write_UINT32(output, result); /* Amount in out queue */ - Stream_Write_UINT8(output, 0); /* EofReceived */ - Stream_Write_UINT8(output, 0); /* WaitForImmediate */ - break; - - case IOCTL_SERIAL_PURGE: - Stream_Read_UINT32(input, purge_mask); - - /* See http://msdn.microsoft.com/en-us/library/ms901431.aspx - PURGE_TXCLEAR Clears the output buffer, if the driver has one. - PURGE_RXCLEAR Clears the input buffer, if the driver has one. - - It clearly states to clear the *driver* buffer, not the port buffer - */ - - if (purge_mask & SERIAL_PURGE_TXABORT) - *abortIo |= SERIAL_ABORT_IO_WRITE; - if (purge_mask & SERIAL_PURGE_RXABORT) - *abortIo |= SERIAL_ABORT_IO_READ; - break; - case IOCTL_SERIAL_WAIT_ON_MASK: - tty->event_pending = 1; - OutputBufferLength = 4; - if (serial_tty_get_event(tty, &result)) - { - Stream_Write_UINT32(output, result); - break; - } - status = STATUS_PENDING; - break; - - case IOCTL_SERIAL_SET_BREAK_ON: - tcsendbreak(tty->fd, 0); - break; - - case IOCTL_SERIAL_RESET_DEVICE: - break; - - case IOCTL_SERIAL_SET_BREAK_OFF: - break; - - case IOCTL_SERIAL_SET_XOFF: - break; - - case IOCTL_SERIAL_SET_XON: - tcflow(tty->fd, TCION); - break; - - default: - return STATUS_INVALID_PARAMETER; - } - - endPos = (UINT32) Stream_GetPosition(output); - OutputBufferLength = endPos - begPos; - - if (OutputBufferLength < 1) - { - Stream_Write_UINT8(output, 0); /* Padding (1 byte) */ - endPos = (UINT32) Stream_GetPosition(output); - OutputBufferLength = endPos - begPos; - } - - Stream_SealLength(output); - - Stream_SetPosition(output, 16); - Stream_Write_UINT32(output, OutputBufferLength); /* OutputBufferLength (4 bytes) */ - Stream_SetPosition(output, endPos); - - return status; -} - -BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length) -{ - ssize_t status; - long timeout = 90; - - /* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout - with requested read size */ - if (tty->read_total_timeout_multiplier | tty->read_total_timeout_constant) - { - timeout = - (tty->read_total_timeout_multiplier * (*Length) + - tty->read_total_timeout_constant + 99) / 100; - } - else if (tty->read_interval_timeout) - { - timeout = (tty->read_interval_timeout * (*Length) + 99) / 100; - } - - if (tty->timeout != timeout) - { - struct termios* ptermios; - - ptermios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (tcgetattr(tty->fd, ptermios) < 0) { - free(ptermios); - return FALSE; - } - - /** - * If a timeout is set, do a blocking read, which times out after some time. - * It will make FreeRDP less responsive, but it will improve serial performance, - * by not reading one character at a time. - */ - - if (timeout == 0) - { - ptermios->c_cc[VTIME] = 0; - ptermios->c_cc[VMIN] = 0; - } - else - { - ptermios->c_cc[VTIME] = timeout; - ptermios->c_cc[VMIN] = 1; - } - - tcsetattr(tty->fd, TCSANOW, ptermios); - tty->timeout = timeout; - free(ptermios); - } - - ZeroMemory(buffer, *Length); - - status = read(tty->fd, buffer, *Length); - - if (status < 0) - return FALSE; - - tty->event_txempty = status; - *Length = status; - - return TRUE; -} - -int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length) -{ - ssize_t status = 0; - UINT32 event_txempty = Length; - - while (Length > 0) - { - status = write(tty->fd, buffer, Length); - - if (status < 0) - { - if (errno == EAGAIN) - status = 0; - else - return status; - } - - Length -= status; - buffer += status; - } - - tty->event_txempty = event_txempty; - - return status; -} - -/** - * This function is used to deallocated a SERIAL_TTY structure. - * - * @param tty [in] - pointer to the SERIAL_TTY structure to deallocate. - * This will typically be allocated by a call to serial_tty_new(). - * On return, this pointer is invalid. - */ -void serial_tty_free(SERIAL_TTY* tty) -{ - if (!tty) - return; - - if (tty->fd >= 0) - { - if (tty->pold_termios) - tcsetattr(tty->fd, TCSANOW, tty->pold_termios); - - close(tty->fd); - } - - free(tty->ptermios); - free(tty->pold_termios); - free(tty); -} - -SERIAL_TTY* serial_tty_new(const char* path, UINT32 id) -{ - SERIAL_TTY* tty; - - tty = (SERIAL_TTY*) calloc(1, sizeof(SERIAL_TTY)); - - if (!tty) - return NULL; - - tty->id = id; - tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (tty->fd < 0) - { - perror("open"); - serial_tty_free(tty); - return NULL; - } - else - { - - } - - tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (!tty->ptermios) - { - serial_tty_free(tty); - return NULL; - } - - tty->pold_termios = (struct termios*) calloc(1, sizeof(struct termios)); - - if (!tty->pold_termios) - { - serial_tty_free(tty); - return NULL; - } - tcgetattr(tty->fd, tty->pold_termios); - - if (!tty_get_termios(tty)) - { - fflush(stdout); - serial_tty_free(tty); - return NULL; - } - - tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty->ptermios->c_oflag &= ~OPOST; - tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty->ptermios->c_cflag &= ~(CSIZE | PARENB); - tty->ptermios->c_cflag |= CS8; - - tty->ptermios->c_iflag = IGNPAR; - tty->ptermios->c_cflag |= CLOCAL | CREAD; - - tcsetattr(tty->fd, TCSANOW, tty->ptermios); - - tty->event_txempty = 0; - tty->event_cts = 0; - tty->event_dsr = 0; - tty->event_rlsd = 0; - tty->event_pending = 0; - - /* all read and writes should be non-blocking */ - if (fcntl(tty->fd, F_SETFL, O_NONBLOCK) == -1) - { - perror("fcntl"); - serial_tty_free(tty) ; - return NULL; - } - - tty->read_total_timeout_constant = 5; - - return tty; -} - -BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result) -{ - int bytes; - BOOL status = FALSE; - - *result = 0; - -#ifdef TIOCINQ - /* When wait_mask is set to zero we ought to cancel it all - For reference: http://msdn.microsoft.com/en-us/library/aa910487.aspx */ - if (tty->wait_mask == 0) - { - tty->event_pending = 0; - return TRUE; - } - - ioctl(tty->fd, TIOCINQ, &bytes); - - if (bytes > 0) - { - if (bytes > tty->event_rlsd) - { - tty->event_rlsd = bytes; - - if (tty->wait_mask & SERIAL_EV_RLSD) - { - *result |= SERIAL_EV_RLSD; - status = TRUE; - } - } - - if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG)) - { - *result |= SERIAL_EV_RXFLAG; - status = TRUE; - } - - if ((tty->wait_mask & SERIAL_EV_RXCHAR)) - { - *result |= SERIAL_EV_RXCHAR; - status = TRUE; - } - } - else - { - tty->event_rlsd = 0; - } -#endif - -#ifdef TIOCOUTQ - ioctl(tty->fd, TIOCOUTQ, &bytes); - if ((bytes == 0) && (tty->event_txempty > 0) && (tty->wait_mask & SERIAL_EV_TXEMPTY)) - { - *result |= SERIAL_EV_TXEMPTY; - status = TRUE; - } - tty->event_txempty = bytes; -#endif - - ioctl(tty->fd, TIOCMGET, &bytes); - if ((bytes & TIOCM_DSR) != tty->event_dsr) - { - tty->event_dsr = bytes & TIOCM_DSR; - - if (tty->wait_mask & SERIAL_EV_DSR) - { - *result |= SERIAL_EV_DSR; - status = TRUE; - } - } - - if ((bytes & TIOCM_CTS) != tty->event_cts) - { - tty->event_cts = bytes & TIOCM_CTS; - - if (tty->wait_mask & SERIAL_EV_CTS) - { - *result |= SERIAL_EV_CTS; - status = TRUE; - } - } - - if (status) - tty->event_pending = 0; - - return status; -} - -static BOOL tty_get_termios(SERIAL_TTY* tty) -{ - speed_t speed; - struct termios* ptermios; - ptermios = tty->ptermios; - - if (tcgetattr(tty->fd, ptermios) < 0) - return FALSE; - - speed = cfgetispeed(ptermios); - - switch (speed) - { -#ifdef B75 - case B75: - tty->baud_rate = 75; - break; -#endif -#ifdef B110 - case B110: - tty->baud_rate = 110; - break; -#endif -#ifdef B134 - case B134: - tty->baud_rate = 134; - break; -#endif -#ifdef B150 - case B150: - tty->baud_rate = 150; - break; -#endif -#ifdef B300 - case B300: - tty->baud_rate = 300; - break; -#endif -#ifdef B600 - case B600: - tty->baud_rate = 600; - break; -#endif -#ifdef B1200 - case B1200: - tty->baud_rate = 1200; - break; -#endif -#ifdef B1800 - case B1800: - tty->baud_rate = 1800; - break; -#endif -#ifdef B2400 - case B2400: - tty->baud_rate = 2400; - break; -#endif -#ifdef B4800 - case B4800: - tty->baud_rate = 4800; - break; -#endif -#ifdef B9600 - case B9600: - tty->baud_rate = 9600; - break; -#endif -#ifdef B19200 - case B19200: - tty->baud_rate = 19200; - break; -#endif -#ifdef B38400 - case B38400: - tty->baud_rate = 38400; - break; -#endif -#ifdef B57600 - case B57600: - tty->baud_rate = 57600; - break; -#endif -#ifdef B115200 - case B115200: - tty->baud_rate = 115200; - break; -#endif -#ifdef B230400 - case B230400: - tty->baud_rate = 230400; - break; -#endif -#ifdef B460800 - case B460800: - tty->baud_rate = 460800; - break; -#endif - default: - tty->baud_rate = 9600; - break; - } - - speed = cfgetospeed(ptermios); - tty->dtr = (speed == B0) ? 0 : 1; - - tty->stop_bits = (ptermios->c_cflag & CSTOPB) ? SERIAL_STOP_BITS_2 : SERIAL_STOP_BITS_1; - tty->parity = - (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? SERIAL_ODD_PARITY : - SERIAL_EVEN_PARITY) : SERIAL_NO_PARITY; - switch (ptermios->c_cflag & CSIZE) - { - case CS5: - tty->word_length = 5; - break; - case CS6: - tty->word_length = 6; - break; - case CS7: - tty->word_length = 7; - break; - default: - tty->word_length = 8; - break; - } - - if (ptermios->c_cflag & CRTSCTS) - { - tty->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT; - } - else - { - tty->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT; - } - - tty->xonoff = SERIAL_DSR_SENSITIVITY; - - if (ptermios->c_iflag & IXON) - tty->xonoff |= SERIAL_XON_HANDSHAKE; - - if (ptermios->c_iflag & IXOFF) - tty->xonoff |= SERIAL_XOFF_HANDSHAKE; - - tty->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART]; - tty->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP]; - tty->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF]; - tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR]; - tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL]; - - tty->timeout = ptermios->c_cc[VTIME]; - - return TRUE; -} - -static void tty_set_termios(SERIAL_TTY* tty) -{ - speed_t speed; - struct termios* ptermios; - - ptermios = tty->ptermios; - - switch (tty->baud_rate) - { -#ifdef B75 - case 75: - speed = B75; - break; -#endif -#ifdef B110 - case 110: - speed = B110; - break; -#endif -#ifdef B134 - case 134: - speed = B134; - break; -#endif -#ifdef B150 - case 150: - speed = B150; - break; -#endif -#ifdef B300 - case 300: - speed = B300; - break; -#endif -#ifdef B600 - case 600: - speed = B600; - break; -#endif -#ifdef B1200 - case 1200: - speed = B1200; - break; -#endif -#ifdef B1800 - case 1800: - speed = B1800; - break; -#endif -#ifdef B2400 - case 2400: - speed = B2400; - break; -#endif -#ifdef B4800 - case 4800: - speed = B4800; - break; -#endif -#ifdef B9600 - case 9600: - speed = B9600; - break; -#endif -#ifdef B19200 - case 19200: - speed = B19200; - break; -#endif -#ifdef B38400 - case 38400: - speed = B38400; - break; -#endif -#ifdef B57600 - case 57600: - speed = B57600; - break; -#endif -#ifdef B115200 - case 115200: - speed = B115200; - break; -#endif -#ifdef B230400 - case 230400: - speed = B115200; - break; -#endif -#ifdef B460800 - case 460800: - speed = B115200; - break; -#endif - default: - speed = B9600; - break; - } - -#ifdef CBAUD - ptermios->c_cflag &= ~CBAUD; - ptermios->c_cflag |= speed; -#else - /* on systems with separate ispeed and ospeed, we can remember the speed - in ispeed while changing DTR with ospeed */ - cfsetispeed(tty->ptermios, speed); - cfsetospeed(tty->ptermios, tty->dtr ? speed : 0); -#endif - - ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS); - - switch (tty->stop_bits) - { - case SERIAL_STOP_BITS_2: - ptermios->c_cflag |= CSTOPB; - break; - - default: - ptermios->c_cflag &= ~CSTOPB; - break; - } - - switch (tty->parity) - { - case SERIAL_EVEN_PARITY: - ptermios->c_cflag |= PARENB; - break; - - case SERIAL_ODD_PARITY: - ptermios->c_cflag |= PARENB | PARODD; - break; - - case SERIAL_NO_PARITY: - ptermios->c_cflag &= ~(PARENB | PARODD); - break; - } - - switch (tty->word_length) - { - case 5: - ptermios->c_cflag |= CS5; - break; - case 6: - ptermios->c_cflag |= CS6; - break; - case 7: - ptermios->c_cflag |= CS7; - break; - default: - ptermios->c_cflag |= CS8; - break; - } - -#if 0 - if (tty->rts) - ptermios->c_cflag |= CRTSCTS; - else - ptermios->c_cflag &= ~CRTSCTS; -#endif - - if (tty->control & SERIAL_CTS_HANDSHAKE) - { - ptermios->c_cflag |= CRTSCTS; - } - else - { - ptermios->c_cflag &= ~CRTSCTS; - } - - - if (tty->xonoff & SERIAL_XON_HANDSHAKE) - { - ptermios->c_iflag |= IXON | IMAXBEL; - } - if (tty->xonoff & SERIAL_XOFF_HANDSHAKE) - { - ptermios->c_iflag |= IXOFF | IMAXBEL; - } - - if ((tty->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0) - { - ptermios->c_iflag &= ~IXON; - ptermios->c_iflag &= ~IXOFF; - } - - ptermios->c_cc[VSTART] = tty->chars[SERIAL_CHAR_XON]; - ptermios->c_cc[VSTOP] = tty->chars[SERIAL_CHAR_XOFF]; - ptermios->c_cc[VEOF] = tty->chars[SERIAL_CHAR_EOF]; - ptermios->c_cc[VINTR] = tty->chars[SERIAL_CHAR_BREAK]; - ptermios->c_cc[VKILL] = tty->chars[SERIAL_CHAR_ERROR]; - - tcsetattr(tty->fd, TCSANOW, ptermios); -} - -static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len) -{ - ssize_t status; - - status = write(tty->fd, data, len); - - if (status < 0) - return tty_get_error_status(); - - tty->event_txempty = status; - - return STATUS_SUCCESS; -} - -static int tty_get_error_status() -{ - switch (errno) - { - case EACCES: - case ENOTDIR: - case ENFILE: - return STATUS_ACCESS_DENIED; - case EISDIR: - return STATUS_FILE_IS_A_DIRECTORY; - case EEXIST: - return STATUS_OBJECT_NAME_COLLISION; - case EBADF: - return STATUS_INVALID_HANDLE; - default: - return STATUS_NO_SUCH_FILE; - } -} diff --git a/channels/serial/client/serial_tty.h b/channels/serial/client/serial_tty.h deleted file mode 100644 index 840c448ec..000000000 --- a/channels/serial/client/serial_tty.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Serial Port Device Service Virtual Channel - * - * Copyright 2011 O.S. Systems Software Ltda. - * Copyright 2011 Eduardo Fiss Beloni - * - * 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 __SERIAL_TTY_H -#define __SERIAL_TTY_H - -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include - -#include - -typedef struct _SERIAL_TTY SERIAL_TTY; - -struct _SERIAL_TTY -{ - UINT32 id; - int fd; - - int dtr; - int rts; - UINT32 control; - UINT32 xonoff; - UINT32 onlimit; - UINT32 offlimit; - UINT32 baud_rate; - UINT32 queue_in_size; - UINT32 queue_out_size; - UINT32 wait_mask; - UINT32 read_interval_timeout; - UINT32 read_total_timeout_multiplier; - UINT32 read_total_timeout_constant; - UINT32 write_total_timeout_multiplier; - UINT32 write_total_timeout_constant; - BYTE stop_bits; - BYTE parity; - BYTE word_length; - BYTE chars[6]; - struct termios* ptermios; - struct termios* pold_termios; - int event_txempty; - int event_cts; - int event_dsr; - int event_rlsd; - int event_pending; - long timeout; -}; - -SERIAL_TTY* serial_tty_new(const char* path, UINT32 id); -void serial_tty_free(SERIAL_TTY* tty); - -BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length); -int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length); -UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io); - -BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result); - -#endif /* __SERIAL_TTY_H */ diff --git a/channels/server/CMakeLists.txt b/channels/server/CMakeLists.txt index 9285a6594..4723368cb 100644 --- a/channels/server/CMakeLists.txt +++ b/channels/server/CMakeLists.txt @@ -30,17 +30,12 @@ endforeach() add_library(${MODULE_NAME} STATIC ${${MODULE_PREFIX}_SRCS}) -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) +endif() +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-interlocked winpr-error winpr-wtsapi) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) diff --git a/channels/server/channels.c b/channels/server/channels.c index 1f470e6e9..cac4243bd 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,9 @@ void freerdp_channels_dummy() cliprdr_server_context_new(NULL); cliprdr_server_context_free(NULL); + echo_server_context_new(NULL); + echo_server_context_free(NULL); + rdpdr_server_context_new(NULL); rdpdr_server_context_free(NULL); diff --git a/channels/smartcard/client/CMakeLists.txt b/channels/smartcard/client/CMakeLists.txt index d7aaa8a69..b38464cc0 100644 --- a/channels/smartcard/client/CMakeLists.txt +++ b/channels/smartcard/client/CMakeLists.txt @@ -28,17 +28,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-smartcard winpr-synch winpr-thread winpr-interlocked winpr-environment winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index e60926ab6..f501d7717 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -372,9 +372,8 @@ void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) } else { - fprintf(stderr, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X", - irp->MajorFunction, irp->MinorFunction); - + WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X", + irp->MajorFunction, irp->MinorFunction); irp->IoStatus = STATUS_NOT_SUPPORTED; Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp); diff --git a/channels/smartcard/client/smartcard_main.h b/channels/smartcard/client/smartcard_main.h index e0172d424..d9123cda5 100644 --- a/channels/smartcard/client/smartcard_main.h +++ b/channels/smartcard/client/smartcard_main.h @@ -21,7 +21,7 @@ #ifndef FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H #define FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H -#include +#include #include #include @@ -30,6 +30,8 @@ #include #include +#define TAG CHANNELS_TAG("smartcard.client") + #define RDP_SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, (code), METHOD_BUFFERED, FILE_ANY_ACCESS) #define SCARD_IOCTL_ESTABLISHCONTEXT RDP_SCARD_CTL_CODE(5) /* SCardEstablishContext */ diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 47f77c4e9..643ba97fb 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -44,100 +44,148 @@ const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) { case SCARD_IOCTL_ESTABLISHCONTEXT: return funcName ? "SCardEstablishContext" : "SCARD_IOCTL_ESTABLISHCONTEXT"; + case SCARD_IOCTL_RELEASECONTEXT: return funcName ? "SCardReleaseContext" : "SCARD_IOCTL_RELEASECONTEXT"; + case SCARD_IOCTL_ISVALIDCONTEXT: return funcName ? "SCardIsValidContext" : "SCARD_IOCTL_ISVALIDCONTEXT"; + case SCARD_IOCTL_LISTREADERGROUPSA: return funcName ? "SCardListReaderGroupsA" : "SCARD_IOCTL_LISTREADERGROUPSA"; + case SCARD_IOCTL_LISTREADERGROUPSW: return funcName ? "SCardListReaderGroupsW" : "SCARD_IOCTL_LISTREADERGROUPSW"; + case SCARD_IOCTL_LISTREADERSA: return funcName ? "SCardListReadersA" : "SCARD_IOCTL_LISTREADERSA"; + case SCARD_IOCTL_LISTREADERSW: return funcName ? "SCardListReadersW" : "SCARD_IOCTL_LISTREADERSW"; + case SCARD_IOCTL_INTRODUCEREADERGROUPA: return funcName ? "SCardIntroduceReaderGroupA" : "SCARD_IOCTL_INTRODUCEREADERGROUPA"; + case SCARD_IOCTL_INTRODUCEREADERGROUPW: return funcName ? "SCardIntroduceReaderGroupW" : "SCARD_IOCTL_INTRODUCEREADERGROUPW"; + case SCARD_IOCTL_FORGETREADERGROUPA: return funcName ? "SCardForgetReaderGroupA" : "SCARD_IOCTL_FORGETREADERGROUPA"; + case SCARD_IOCTL_FORGETREADERGROUPW: return funcName ? "SCardForgetReaderGroupW" : "SCARD_IOCTL_FORGETREADERGROUPW"; + case SCARD_IOCTL_INTRODUCEREADERA: return funcName ? "SCardIntroduceReaderA" : "SCARD_IOCTL_INTRODUCEREADERA"; + case SCARD_IOCTL_INTRODUCEREADERW: return funcName ? "SCardIntroduceReaderW" : "SCARD_IOCTL_INTRODUCEREADERW"; + case SCARD_IOCTL_FORGETREADERA: return funcName ? "SCardForgetReaderA" : "SCARD_IOCTL_FORGETREADERA"; + case SCARD_IOCTL_FORGETREADERW: return funcName ? "SCardForgetReaderW" : "SCARD_IOCTL_FORGETREADERW"; + case SCARD_IOCTL_ADDREADERTOGROUPA: return funcName ? "SCardAddReaderToGroupA" : "SCARD_IOCTL_ADDREADERTOGROUPA"; + case SCARD_IOCTL_ADDREADERTOGROUPW: return funcName ? "SCardAddReaderToGroupW" : "SCARD_IOCTL_ADDREADERTOGROUPW"; + case SCARD_IOCTL_REMOVEREADERFROMGROUPA: return funcName ? "SCardRemoveReaderFromGroupA" : "SCARD_IOCTL_REMOVEREADERFROMGROUPA"; + case SCARD_IOCTL_REMOVEREADERFROMGROUPW: return funcName ? "SCardRemoveReaderFromGroupW" : "SCARD_IOCTL_REMOVEREADERFROMGROUPW"; + case SCARD_IOCTL_LOCATECARDSA: return funcName ? "SCardLocateCardsA" : "SCARD_IOCTL_LOCATECARDSA"; + case SCARD_IOCTL_LOCATECARDSW: return funcName ? "SCardLocateCardsW" : "SCARD_IOCTL_LOCATECARDSW"; + case SCARD_IOCTL_GETSTATUSCHANGEA: return funcName ? "SCardGetStatusChangeA" : "SCARD_IOCTL_GETSTATUSCHANGEA"; + case SCARD_IOCTL_GETSTATUSCHANGEW: return funcName ? "SCardGetStatusChangeW" : "SCARD_IOCTL_GETSTATUSCHANGEW"; + case SCARD_IOCTL_CANCEL: return funcName ? "SCardCancel" : "SCARD_IOCTL_CANCEL"; + case SCARD_IOCTL_CONNECTA: return funcName ? "SCardConnectA" : "SCARD_IOCTL_CONNECTA"; + case SCARD_IOCTL_CONNECTW: return funcName ? "SCardConnectW" : "SCARD_IOCTL_CONNECTW"; + case SCARD_IOCTL_RECONNECT: return funcName ? "SCardReconnect" : "SCARD_IOCTL_RECONNECT"; + case SCARD_IOCTL_DISCONNECT: return funcName ? "SCardDisconnect" : "SCARD_IOCTL_DISCONNECT"; + case SCARD_IOCTL_BEGINTRANSACTION: return funcName ? "SCardBeginTransaction" : "SCARD_IOCTL_BEGINTRANSACTION"; + case SCARD_IOCTL_ENDTRANSACTION: return funcName ? "SCardEndTransaction" : "SCARD_IOCTL_ENDTRANSACTION"; + case SCARD_IOCTL_STATE: return funcName ? "SCardState" : "SCARD_IOCTL_STATE"; + case SCARD_IOCTL_STATUSA: return funcName ? "SCardStatusA" : "SCARD_IOCTL_STATUSA"; + case SCARD_IOCTL_STATUSW: return funcName ? "SCardStatusW" : "SCARD_IOCTL_STATUSW"; + case SCARD_IOCTL_TRANSMIT: return funcName ? "SCardTransmit" : "SCARD_IOCTL_TRANSMIT"; + case SCARD_IOCTL_CONTROL: return funcName ? "SCardControl" : "SCARD_IOCTL_CONTROL"; + case SCARD_IOCTL_GETATTRIB: return funcName ? "SCardGetAttrib" : "SCARD_IOCTL_GETATTRIB"; + case SCARD_IOCTL_SETATTRIB: return funcName ? "SCardSetAttrib" : "SCARD_IOCTL_SETATTRIB"; + case SCARD_IOCTL_ACCESSSTARTEDEVENT: return funcName ? "SCardAccessStartedEvent" : "SCARD_IOCTL_ACCESSSTARTEDEVENT"; + case SCARD_IOCTL_LOCATECARDSBYATRA: return funcName ? "SCardLocateCardsByATRA" : "SCARD_IOCTL_LOCATECARDSBYATRA"; + case SCARD_IOCTL_LOCATECARDSBYATRW: return funcName ? "SCardLocateCardsByATRB" : "SCARD_IOCTL_LOCATECARDSBYATRW"; + case SCARD_IOCTL_READCACHEA: return funcName ? "SCardReadCacheA" : "SCARD_IOCTL_READCACHEA"; + case SCARD_IOCTL_READCACHEW: return funcName ? "SCardReadCacheW" : "SCARD_IOCTL_READCACHEW"; + case SCARD_IOCTL_WRITECACHEA: return funcName ? "SCardWriteCacheA" : "SCARD_IOCTL_WRITECACHEA"; + case SCARD_IOCTL_WRITECACHEW: return funcName ? "SCardWriteCacheW" : "SCARD_IOCTL_WRITECACHEW"; + case SCARD_IOCTL_GETTRANSMITCOUNT: return funcName ? "SCardGetTransmitCount" : "SCARD_IOCTL_GETTRANSMITCOUNT"; + case SCARD_IOCTL_RELEASESTARTEDEVENT: return funcName ? "SCardReleaseStartedEvent" : "SCARD_IOCTL_RELEASESTARTEDEVENT"; + case SCARD_IOCTL_GETREADERICON: return funcName ? "SCardGetReaderIcon" : "SCARD_IOCTL_GETREADERICON"; + case SCARD_IOCTL_GETDEVICETYPEID: return funcName ? "SCardGetDeviceTypeId" : "SCARD_IOCTL_GETDEVICETYPEID"; + default: return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN"; } @@ -154,9 +202,7 @@ static UINT32 smartcard_EstablishContext_Decode(SMARTCARD_DEVICE* smartcard, SMA return STATUS_NO_MEMORY; status = smartcard_unpack_establish_context_call(smartcard, irp->input, call); - smartcard_trace_establish_context_call(smartcard, call); - return status; } @@ -166,23 +212,18 @@ static UINT32 smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard, SMART SCARDCONTEXT hContext = -1; EstablishContext_Return ret; IRP* irp = operation->irp; - status = ret.ReturnCode = SCardEstablishContext(call->dwScope, NULL, NULL, &hContext); if (ret.ReturnCode == SCARD_S_SUCCESS) { SMARTCARD_CONTEXT* pContext; - void* key = (void*) (size_t) hContext; - + void* key = (void*)(size_t) hContext; pContext = smartcard_context_new(smartcard, hContext); - ListDictionary_Add(smartcard->rgSCardContextList, key, (void*) pContext); } smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), hContext); - smartcard_trace_establish_context_return(smartcard, &ret); - status = smartcard_pack_establish_context_return(smartcard, irp->output, &ret); if (status) @@ -200,11 +241,8 @@ static UINT32 smartcard_ReleaseContext_Decode(SMARTCARD_DEVICE* smartcard, SMART return STATUS_NO_MEMORY; status = smartcard_unpack_context_call(smartcard, irp->input, call); - smartcard_trace_context_call(smartcard, call, "ReleaseContext"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -212,21 +250,17 @@ static UINT32 smartcard_ReleaseContext_Call(SMARTCARD_DEVICE* smartcard, SMARTCA { UINT32 status; Long_Return ret; - status = ret.ReturnCode = SCardReleaseContext(operation->hContext); if (ret.ReturnCode == SCARD_S_SUCCESS) { SMARTCARD_CONTEXT* pContext; - void* key = (void*) (size_t) operation->hContext; - + void* key = (void*)(size_t) operation->hContext; pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, key); - smartcard_context_free(pContext); } smartcard_trace_long_return(smartcard, &ret, "ReleaseContext"); - return ret.ReturnCode; } @@ -239,11 +273,8 @@ static UINT32 smartcard_IsValidContext_Decode(SMARTCARD_DEVICE* smartcard, SMART return STATUS_NO_MEMORY; status = smartcard_unpack_context_call(smartcard, irp->input, call); - smartcard_trace_context_call(smartcard, call, "IsValidContext"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -251,11 +282,8 @@ static UINT32 smartcard_IsValidContext_Call(SMARTCARD_DEVICE* smartcard, SMARTCA { UINT32 status; Long_Return ret; - status = ret.ReturnCode = SCardIsValidContext(operation->hContext); - smartcard_trace_long_return(smartcard, &ret, "IsValidContext"); - return ret.ReturnCode; } @@ -268,11 +296,8 @@ static UINT32 smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCA return STATUS_NO_MEMORY; status = smartcard_unpack_list_readers_call(smartcard, irp->input, call); - smartcard_trace_list_readers_call(smartcard, call, FALSE); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -283,11 +308,8 @@ static UINT32 smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD LPSTR mszReaders = NULL; DWORD cchReaders = 0; IRP* irp = operation->irp; - cchReaders = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups, (LPSTR) &mszReaders, &cchReaders); - ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders; @@ -295,7 +317,6 @@ static UINT32 smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD return status; smartcard_trace_list_readers_return(smartcard, &ret, FALSE); - status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret); if (status) @@ -319,11 +340,8 @@ static UINT32 smartcard_ListReadersW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCA return STATUS_NO_MEMORY; status = smartcard_unpack_list_readers_call(smartcard, irp->input, call); - smartcard_trace_list_readers_call(smartcard, call, TRUE); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -334,11 +352,8 @@ static UINT32 smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD LPWSTR mszReaders = NULL; DWORD cchReaders = 0; IRP* irp = operation->irp; - cchReaders = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReadersW(operation->hContext, (LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders); - ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders * 2; @@ -346,7 +361,6 @@ static UINT32 smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD return status; smartcard_trace_list_readers_return(smartcard, &ret, TRUE); - status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -370,11 +384,8 @@ static UINT32 smartcard_GetStatusChangeA_Decode(SMARTCARD_DEVICE* smartcard, SMA return STATUS_NO_MEMORY; status = smartcard_unpack_get_status_change_a_call(smartcard, irp->input, call); - smartcard_trace_get_status_change_a_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -385,11 +396,12 @@ static UINT32 smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, SMART GetStatusChange_Return ret; LPSCARD_READERSTATEA rgReaderState = NULL; IRP* irp = operation->irp; - status = ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, call->dwTimeOut, call->rgReaderStates, call->cReaders); if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)) - return status; + { + call->cReaders=0; + } ret.cReaders = call->cReaders; ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); @@ -403,7 +415,6 @@ static UINT32 smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, SMART } smartcard_trace_get_status_change_return(smartcard, &ret, FALSE); - status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret); if (status) @@ -418,11 +429,11 @@ static UINT32 smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, SMART if (rgReaderState->szReader) free((void*) rgReaderState->szReader); } + free(call->rgReaderStates); } free(ret.rgReaderStates); - return ret.ReturnCode; } @@ -435,11 +446,8 @@ static UINT32 smartcard_GetStatusChangeW_Decode(SMARTCARD_DEVICE* smartcard, SMA return STATUS_NO_MEMORY; status = smartcard_unpack_get_status_change_w_call(smartcard, irp->input, call); - smartcard_trace_get_status_change_w_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -450,11 +458,12 @@ static UINT32 smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, SMART GetStatusChange_Return ret; LPSCARD_READERSTATEW rgReaderState = NULL; IRP* irp = operation->irp; - status = ret.ReturnCode = SCardGetStatusChangeW(operation->hContext, call->dwTimeOut, call->rgReaderStates, call->cReaders); if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)) - return status; + { + call->cReaders=0; + } ret.cReaders = call->cReaders; ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); @@ -468,7 +477,6 @@ static UINT32 smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, SMART } smartcard_trace_get_status_change_return(smartcard, &ret, TRUE); - status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret); if (status) @@ -483,11 +491,11 @@ static UINT32 smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, SMART if (rgReaderState->szReader) free((void*) rgReaderState->szReader); } + free(call->rgReaderStates); } free(ret.rgReaderStates); - return ret.ReturnCode; } @@ -500,11 +508,8 @@ static UINT32 smartcard_Cancel_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE return STATUS_NO_MEMORY; status = smartcard_unpack_context_call(smartcard, irp->input, call); - smartcard_trace_context_call(smartcard, call, "Cancel"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); - return status; } @@ -512,11 +517,8 @@ static UINT32 smartcard_Cancel_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA { LONG status; Long_Return ret; - status = ret.ReturnCode = SCardCancel(operation->hContext); - smartcard_trace_long_return(smartcard, &ret, "Cancel"); - return ret.ReturnCode; } @@ -529,11 +531,8 @@ static UINT32 smartcard_ConnectA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_O return STATUS_NO_MEMORY; status = smartcard_unpack_connect_a_call(smartcard, irp->input, call); - smartcard_trace_connect_a_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); - return status; } @@ -551,11 +550,9 @@ static UINT32 smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE } status = ret.ReturnCode = SCardConnectA(operation->hContext, (char*) call->szReader, call->Common.dwShareMode, - call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); - + call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext); smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard); - smartcard_trace_connect_return(smartcard, &ret); if (status) @@ -581,11 +578,8 @@ static UINT32 smartcard_ConnectW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_O return STATUS_NO_MEMORY; status = smartcard_unpack_connect_w_call(smartcard, irp->input, call); - smartcard_trace_connect_w_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); - return status; } @@ -603,11 +597,9 @@ static UINT32 smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE } status = ret.ReturnCode = SCardConnectW(operation->hContext, (WCHAR*) call->szReader, call->Common.dwShareMode, - call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); - + call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext); smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard); - smartcard_trace_connect_return(smartcard, &ret); if (status) @@ -633,12 +625,9 @@ static UINT32 smartcard_Reconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_ return STATUS_NO_MEMORY; status = smartcard_unpack_reconnect_call(smartcard, irp->input, call); - smartcard_trace_reconnect_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -647,12 +636,9 @@ static UINT32 smartcard_Reconnect_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP LONG status; Reconnect_Return ret; IRP* irp = operation->irp; - status = ret.ReturnCode = SCardReconnect(operation->hCard, call->dwShareMode, - call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol); - + call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol); smartcard_trace_reconnect_return(smartcard, &ret); - status = smartcard_pack_reconnect_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -670,12 +656,9 @@ static UINT32 smartcard_Disconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD return STATUS_NO_MEMORY; status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "Disconnect"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -683,9 +666,7 @@ static UINT32 smartcard_Disconnect_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O { LONG status; Long_Return ret; - status = ret.ReturnCode = SCardDisconnect(operation->hCard, call->dwDisposition); - smartcard_trace_long_return(smartcard, &ret, "Disconnect"); if (status != SCARD_S_SUCCESS) @@ -703,12 +684,9 @@ static UINT32 smartcard_BeginTransaction_Decode(SMARTCARD_DEVICE* smartcard, SMA return STATUS_NO_MEMORY; status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "BeginTransaction"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -716,11 +694,8 @@ static UINT32 smartcard_BeginTransaction_Call(SMARTCARD_DEVICE* smartcard, SMART { LONG status; Long_Return ret; - status = ret.ReturnCode = SCardBeginTransaction(operation->hCard); - smartcard_trace_long_return(smartcard, &ret, "BeginTransaction"); - return ret.ReturnCode; } @@ -733,12 +708,9 @@ static UINT32 smartcard_EndTransaction_Decode(SMARTCARD_DEVICE* smartcard, SMART return STATUS_NO_MEMORY; status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "EndTransaction"); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -746,11 +718,8 @@ static UINT32 smartcard_EndTransaction_Call(SMARTCARD_DEVICE* smartcard, SMARTCA { LONG status; Long_Return ret; - status = ret.ReturnCode = SCardEndTransaction(operation->hCard, call->dwDisposition); - smartcard_trace_long_return(smartcard, &ret, "EndTransaction"); - return ret.ReturnCode; } @@ -763,10 +732,8 @@ static UINT32 smartcard_State_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER return STATUS_NO_MEMORY; status = smartcard_unpack_state_call(smartcard, irp->input, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -775,11 +742,8 @@ static UINT32 smartcard_State_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT LONG status; State_Return ret; IRP* irp = operation->irp; - ret.cbAtrLen = SCARD_ATR_LENGTH; - status = ret.ReturnCode = SCardState(operation->hCard, &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.rgAtr, &ret.cbAtrLen); - status = smartcard_pack_state_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -797,12 +761,9 @@ static DWORD smartcard_StatusA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE return STATUS_NO_MEMORY; status = smartcard_unpack_status_call(smartcard, irp->input, call); - smartcard_trace_status_call(smartcard, call, FALSE); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -819,11 +780,9 @@ static DWORD smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA ret.cbAtrLen = call->cbAtrLen; ZeroMemory(ret.pbAtr, 32); - cchReaderLen = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardStatusA(operation->hCard, (LPSTR) &mszReaderNames, &cchReaderLen, - &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen); + &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen); if (status == SCARD_S_SUCCESS) { @@ -832,7 +791,6 @@ static DWORD smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA } smartcard_trace_status_return(smartcard, &ret, FALSE); - status = smartcard_pack_status_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -853,12 +811,9 @@ static DWORD smartcard_StatusW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE return STATUS_NO_MEMORY; status = smartcard_unpack_status_call(smartcard, irp->input, call); - smartcard_trace_status_call(smartcard, call, TRUE); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -875,17 +830,12 @@ static DWORD smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA ret.cbAtrLen = call->cbAtrLen; ZeroMemory(ret.pbAtr, 32); - cchReaderLen = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardStatusW(operation->hCard, (LPWSTR) &mszReaderNames, &cchReaderLen, - &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen); - + &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen); ret.mszReaderNames = (BYTE*) mszReaderNames; ret.cBytes = cchReaderLen * 2; - smartcard_trace_status_return(smartcard, &ret, TRUE); - status = smartcard_pack_status_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -906,12 +856,9 @@ static UINT32 smartcard_Transmit_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_O return STATUS_NO_MEMORY; status = smartcard_unpack_transmit_call(smartcard, irp->input, call); - smartcard_trace_transmit_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -920,7 +867,6 @@ static UINT32 smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE LONG status; Transmit_Return ret; IRP* irp = operation->irp; - ret.cbRecvLength = 0; ret.pbRecvBuffer = NULL; @@ -934,12 +880,9 @@ static UINT32 smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE } ret.pioRecvPci = call->pioRecvPci; - status = ret.ReturnCode = SCardTransmit(operation->hCard, call->pioSendPci, call->pbSendBuffer, - call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength)); - + call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength)); smartcard_trace_transmit_return(smartcard, &ret); - status = smartcard_pack_transmit_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -947,10 +890,13 @@ static UINT32 smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE if (call->pbSendBuffer) free(call->pbSendBuffer); + if (ret.pbRecvBuffer) free(ret.pbRecvBuffer); + if (call->pioSendPci) free(call->pioSendPci); + if (call->pioRecvPci) free(call->pioRecvPci); @@ -966,12 +912,9 @@ static UINT32 smartcard_Control_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP return STATUS_NO_MEMORY; status = smartcard_unpack_control_call(smartcard, irp->input, call); - smartcard_trace_control_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -980,7 +923,6 @@ static UINT32 smartcard_Control_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER LONG status; Control_Return ret; IRP* irp = operation->irp; - ret.cbOutBufferSize = call->cbOutBufferSize; ret.pvOutBuffer = (BYTE*) malloc(call->cbOutBufferSize); @@ -988,11 +930,9 @@ static UINT32 smartcard_Control_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER return SCARD_E_NO_MEMORY; status = ret.ReturnCode = SCardControl(operation->hCard, - call->dwControlCode, call->pvInBuffer, call->cbInBufferSize, - ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize); - + call->dwControlCode, call->pvInBuffer, call->cbInBufferSize, + ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize); smartcard_trace_control_return(smartcard, &ret); - status = smartcard_pack_control_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) @@ -1000,6 +940,7 @@ static UINT32 smartcard_Control_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER if (call->pvInBuffer) free(call->pvInBuffer); + if (ret.pvOutBuffer) free(ret.pvOutBuffer); @@ -1015,12 +956,9 @@ static UINT32 smartcard_GetAttrib_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_ return STATUS_NO_MEMORY; status = smartcard_unpack_get_attrib_call(smartcard, irp->input, call); - smartcard_trace_get_attrib_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); - return status; } @@ -1030,7 +968,6 @@ static UINT32 smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP DWORD cbAttrLen; GetAttrib_Return ret; IRP* irp = operation->irp; - ret.pbAttr = NULL; if (call->fpbAttrIsNULL) @@ -1040,19 +977,15 @@ static UINT32 smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP ret.pbAttr = (BYTE*) malloc(call->cbAttrLen); cbAttrLen = call->cbAttrLen; - status = ret.ReturnCode = SCardGetAttrib(operation->hCard, call->dwAttrId, ret.pbAttr, &cbAttrLen); - ret.cbAttrLen = cbAttrLen; - smartcard_trace_get_attrib_return(smartcard, &ret, call->dwAttrId); if (ret.ReturnCode) { WLog_Print(smartcard->log, WLOG_WARN, - "SCardGetAttrib: %s (0x%08X) cbAttrLen: %d\n", - SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->cbAttrLen); - + "SCardGetAttrib: %s (0x%08X) cbAttrLen: %d\n", + SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->cbAttrLen); Stream_Zero(irp->output, 256); return ret.ReturnCode; } @@ -1063,7 +996,6 @@ static UINT32 smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP return status; free(ret.pbAttr); - return ret.ReturnCode; } @@ -1077,12 +1009,11 @@ static UINT32 smartcard_AccessStartedEvent_Decode(SMARTCARD_DEVICE* smartcard, S if (Stream_GetRemainingLength(irp->input) < 4) { WLog_Print(smartcard->log, WLOG_WARN, "AccessStartedEvent is too short: %d", - (int) Stream_GetRemainingLength(irp->input)); + (int) Stream_GetRemainingLength(irp->input)); return SCARD_F_INTERNAL_ERROR; } Stream_Read_UINT32(irp->input, call->LongValue); /* Unused (4 bytes) */ - return SCARD_S_SUCCESS; } @@ -1090,7 +1021,6 @@ static UINT32 smartcard_AccessStartedEvent_Call(SMARTCARD_DEVICE* smartcard, SMA { UINT32 status; Long_Return ret; - status = ret.ReturnCode = SCARD_S_SUCCESS; if (!smartcard->StartedEvent) @@ -1117,7 +1047,7 @@ UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCAR if (Stream_GetRemainingLength(irp->input) < 32) { WLog_Print(smartcard->log, WLOG_WARN, "Device Control Request is too short: %d", - (int) Stream_GetRemainingLength(irp->input)); + (int) Stream_GetRemainingLength(irp->input)); return SCARD_F_INTERNAL_ERROR; } @@ -1125,23 +1055,21 @@ UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCAR Stream_Read_UINT32(irp->input, inputBufferLength); /* InputBufferLength (4 bytes) */ Stream_Read_UINT32(irp->input, ioControlCode); /* IoControlCode (4 bytes) */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ - operation->ioControlCode = ioControlCode; if (Stream_Length(irp->input) != (Stream_GetPosition(irp->input) + inputBufferLength)) { WLog_Print(smartcard->log, WLOG_WARN, - "InputBufferLength mismatch: Actual: %d Expected: %d\n", - Stream_Length(irp->input), Stream_GetPosition(irp->input) + inputBufferLength); + "InputBufferLength mismatch: Actual: %d Expected: %d\n", + Stream_Length(irp->input), Stream_GetPosition(irp->input) + inputBufferLength); return SCARD_F_INTERNAL_ERROR; } WLog_Print(smartcard->log, WLOG_DEBUG, "%s (0x%08X) FileId: %d CompletionId: %d", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, irp->FileId, irp->CompletionId); - + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, irp->FileId, irp->CompletionId); #if 0 - printf("%s (0x%08X) FileId: %d CompletionId: %d\n", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, irp->FileId, irp->CompletionId); + WLog_DBG(TAG, "%s (0x%08X) FileId: %d CompletionId: %d\n", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, irp->FileId, irp->CompletionId); #endif if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) && @@ -1384,35 +1312,29 @@ UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCAR (ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT)) { offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH); - smartcard_unpack_read_size_align(smartcard, irp->input, - Stream_GetPosition(irp->input) - offset, 8); + Stream_GetPosition(irp->input) - offset, 8); } if (((size_t) Stream_GetPosition(irp->input)) < Stream_Length(irp->input)) { UINT32 difference; - - difference = (int) (Stream_Length(irp->input) - Stream_GetPosition(irp->input)); - + difference = (int)(Stream_Length(irp->input) - Stream_GetPosition(irp->input)); WLog_Print(smartcard->log, WLOG_WARN, - "IRP was not fully parsed %s (0x%08X): Actual: %d, Expected: %d, Difference: %d", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, - (int) Stream_GetPosition(irp->input), (int) Stream_Length(irp->input), difference); - - winpr_HexDump(Stream_Pointer(irp->input), difference); + "IRP was not fully parsed %s (0x%08X): Actual: %d, Expected: %d, Difference: %d", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, + (int) Stream_GetPosition(irp->input), (int) Stream_Length(irp->input), difference); + winpr_HexDump(TAG, WLOG_WARN, Stream_Pointer(irp->input), difference); } if (((size_t) Stream_GetPosition(irp->input)) > Stream_Length(irp->input)) { UINT32 difference; - - difference = (int) (Stream_GetPosition(irp->input) - Stream_Length(irp->input)); - + difference = (int)(Stream_GetPosition(irp->input) - Stream_Length(irp->input)); WLog_Print(smartcard->log, WLOG_WARN, - "IRP was parsed beyond its end %s (0x%08X): Actual: %d, Expected: %d, Difference: %d", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, - (int) Stream_GetPosition(irp->input), (int) Stream_Length(irp->input), difference); + "IRP was parsed beyond its end %s (0x%08X): Actual: %d, Expected: %d, Difference: %d", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, + (int) Stream_GetPosition(irp->input), (int) Stream_Length(irp->input), difference); } if (status != SCARD_S_SUCCESS) @@ -1422,7 +1344,6 @@ UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCAR } operation->call = call; - return status; } @@ -1435,11 +1356,9 @@ UINT32 smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_ UINT32 ioControlCode; UINT32 outputBufferLength; UINT32 objectBufferLength; - irp = operation->irp; call = operation->call; ioControlCode = operation->ioControlCode; - /** * [MS-RDPESC] 3.2.5.1: Sending Outgoing Messages: * the output buffer length SHOULD be set to 2048 @@ -1448,13 +1367,10 @@ UINT32 smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_ * about it, but we still reserve at least 2048 bytes. */ Stream_EnsureRemainingCapacity(irp->output, 2048); - /* Device Control Response */ Stream_Seek_UINT32(irp->output); /* OutputBufferLength (4 bytes) */ - Stream_Seek(irp->output, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */ Stream_Seek(irp->output, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */ - Stream_Seek_UINT32(irp->output); /* Result (4 bytes) */ /* Call */ @@ -1670,18 +1586,17 @@ UINT32 smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_ (ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT)) { offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH); - smartcard_pack_write_size_align(smartcard, irp->output, - Stream_GetPosition(irp->output) - offset, 8); + Stream_GetPosition(irp->output) - offset, 8); } if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) && (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE)) { WLog_Print(smartcard->log, WLOG_WARN, - "IRP failure: %s (0x%08X), status: %s (0x%08X)", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, - SCardGetErrorString(result), result); + "IRP failure: %s (0x%08X), status: %s (0x%08X)", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, + SCardGetErrorString(result), result); } irp->IoStatus = 0; @@ -1689,31 +1604,23 @@ UINT32 smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_ if ((result & 0xC0000000) == 0xC0000000) { /* NTSTATUS error */ - irp->IoStatus = result; Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH); - WLog_Print(smartcard->log, WLOG_WARN, - "IRP failure: %s (0x%08X), ntstatus: 0x%08X", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result); + "IRP failure: %s (0x%08X), ntstatus: 0x%08X", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result); } Stream_SealLength(irp->output); - outputBufferLength = Stream_Length(irp->output) - RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4; objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH; Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH); - /* Device Control Response */ Stream_Write_UINT32(irp->output, outputBufferLength); /* OutputBufferLength (4 bytes) */ - smartcard_pack_common_type_header(smartcard, irp->output); /* CommonTypeHeader (8 bytes) */ smartcard_pack_private_type_header(smartcard, irp->output, objectBufferLength); /* PrivateTypeHeader (8 bytes) */ - Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */ - Stream_SetPosition(irp->output, Stream_Length(irp->output)); - return SCARD_S_SUCCESS; } diff --git a/channels/tsmf/client/CMakeLists.txt b/channels/tsmf/client/CMakeLists.txt index a92ceda1d..8febf15c8 100644 --- a/channels/tsmf/client/CMakeLists.txt +++ b/channels/tsmf/client/CMakeLists.txt @@ -40,12 +40,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils freerdp-common) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/alsa/CMakeLists.txt b/channels/tsmf/client/alsa/CMakeLists.txt index 8e1fbde13..143a69be9 100644 --- a/channels/tsmf/client/alsa/CMakeLists.txt +++ b/channels/tsmf/client/alsa/CMakeLists.txt @@ -27,13 +27,6 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES}) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp ${ALSA_LIBRARIES}) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index d442dca8c..dec1e3443 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -56,7 +56,7 @@ static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa) error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0); if(error < 0) { - DEBUG_WARN("failed to open device %s", alsa->device); + WLog_ERR(TAG, "failed to open device %s", alsa->device); return FALSE; } DEBUG_TSMF("open device %s", alsa->device); @@ -95,7 +95,7 @@ static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio, error = snd_pcm_hw_params_malloc(&hw_params); if(error < 0) { - DEBUG_WARN("snd_pcm_hw_params_malloc failed"); + WLog_ERR(TAG, "snd_pcm_hw_params_malloc failed"); return FALSE; } snd_pcm_hw_params_any(alsa->out_handle, hw_params); @@ -115,7 +115,7 @@ static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio, error = snd_pcm_sw_params_malloc(&sw_params); if(error < 0) { - DEBUG_WARN("snd_pcm_sw_params_malloc"); + WLog_ERR(TAG, "snd_pcm_sw_params_malloc"); return FALSE; } snd_pcm_sw_params_current(alsa->out_handle, sw_params); diff --git a/channels/tsmf/client/ffmpeg/CMakeLists.txt b/channels/tsmf/client/ffmpeg/CMakeLists.txt index c321d7013..d381cd97b 100644 --- a/channels/tsmf/client/ffmpeg/CMakeLists.txt +++ b/channels/tsmf/client/ffmpeg/CMakeLists.txt @@ -27,18 +27,13 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - if(APPLE) # For this to work on apple, we need to add some frameworks FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation) FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo) FIND_LIBRARY(COREVIDEODECODE_LIBRARY VideoDecodeAcceleration) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${FFMPEG_LIBRARIES} ${COREFOUNDATION_LIBRARY} ${COREVIDEO_LIBRARY} ${COREVIDEODECODE_LIBRARY}) - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} freerdp) else() set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${FFMPEG_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index e2c9da2c5..657ac29c7 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -27,10 +27,12 @@ #include +#include #include #include #include +#include #include "tsmf_constants.h" #include "tsmf_decoder.h" @@ -47,6 +49,20 @@ #define MAX_AUDIO_FRAME_SIZE 192000 #endif +#if LIBAVCODEC_VERSION_MAJOR < 55 +#define AV_CODEC_ID_VC1 CODEC_ID_VC1 +#define AV_CODEC_ID_WMAV2 CODEC_ID_WMAV2 +#define AV_CODEC_ID_WMAPRO CODEC_ID_WMAPRO +#define AV_CODEC_ID_MP3 CODEC_ID_MP3 +#define AV_CODEC_ID_MP2 CODEC_ID_MP2 +#define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO +#define AV_CODEC_ID_WMV3 CODEC_ID_WMV3 +#define AV_CODEC_ID_AAC CODEC_ID_AAC +#define AV_CODEC_ID_H264 CODEC_ID_H264 +#define AV_CODEC_ID_AC3 CODEC_ID_AC3 +#endif + + typedef struct _TSMFFFmpegDecoder { ITSMFDecoder iface; @@ -73,7 +89,7 @@ static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder) mdecoder->codec_context = avcodec_alloc_context3(NULL); if(!mdecoder->codec_context) { - DEBUG_WARN("avcodec_alloc_context failed."); + WLog_ERR(TAG, "avcodec_alloc_context failed."); return FALSE; } return TRUE; @@ -127,7 +143,7 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYP mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id); if(!mdecoder->codec) { - DEBUG_WARN("avcodec_find_decoder failed."); + WLog_ERR(TAG, "avcodec_find_decoder failed."); return FALSE; } mdecoder->codec_context->codec_id = mdecoder->codec_id; @@ -189,7 +205,7 @@ static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder) TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; if(avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0) { - DEBUG_WARN("avcodec_open2 failed."); + WLog_ERR(TAG, "avcodec_open2 failed."); return FALSE; } mdecoder->prepared = 1; @@ -213,28 +229,28 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi switch(media_type->SubType) { case TSMF_SUB_TYPE_WVC1: - mdecoder->codec_id = CODEC_ID_VC1; + mdecoder->codec_id = AV_CODEC_ID_VC1; break; case TSMF_SUB_TYPE_WMA2: - mdecoder->codec_id = CODEC_ID_WMAV2; + mdecoder->codec_id = AV_CODEC_ID_WMAV2; break; case TSMF_SUB_TYPE_WMA9: - mdecoder->codec_id = CODEC_ID_WMAPRO; + mdecoder->codec_id = AV_CODEC_ID_WMAPRO; break; case TSMF_SUB_TYPE_MP3: - mdecoder->codec_id = CODEC_ID_MP3; + mdecoder->codec_id = AV_CODEC_ID_MP3; break; case TSMF_SUB_TYPE_MP2A: - mdecoder->codec_id = CODEC_ID_MP2; + mdecoder->codec_id = AV_CODEC_ID_MP2; break; case TSMF_SUB_TYPE_MP2V: - mdecoder->codec_id = CODEC_ID_MPEG2VIDEO; + mdecoder->codec_id = AV_CODEC_ID_MPEG2VIDEO; break; case TSMF_SUB_TYPE_WMV3: - mdecoder->codec_id = CODEC_ID_WMV3; + mdecoder->codec_id = AV_CODEC_ID_WMV3; break; case TSMF_SUB_TYPE_AAC: - mdecoder->codec_id = CODEC_ID_AAC; + mdecoder->codec_id = AV_CODEC_ID_AAC; /* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data is at the end of it. See http://msdn.microsoft.com/en-us/library/dd757806.aspx */ @@ -246,10 +262,10 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi break; case TSMF_SUB_TYPE_H264: case TSMF_SUB_TYPE_AVC1: - mdecoder->codec_id = CODEC_ID_H264; + mdecoder->codec_id = AV_CODEC_ID_H264; break; case TSMF_SUB_TYPE_AC3: - mdecoder->codec_id = CODEC_ID_AC3; + mdecoder->codec_id = AV_CODEC_ID_AC3; break; default: return FALSE; @@ -285,36 +301,36 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UI #endif if(len < 0) { - DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len); + WLog_ERR(TAG, "data_size %d, avcodec_decode_video failed (%d)", data_size, len); + ret = FALSE; + } + else if (!decoded) + { + WLog_ERR(TAG, "data_size %d, no frame is decoded.", data_size); ret = FALSE; } else - if(!decoded) - { - DEBUG_WARN("data_size %d, no frame is decoded.", data_size); - ret = FALSE; - } - else - { - DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d " - "pix_fmt %d width %d height %d", - mdecoder->frame->linesize[0], mdecoder->frame->linesize[1], - mdecoder->frame->linesize[2], mdecoder->frame->linesize[3], + { + DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d " + "pix_fmt %d width %d height %d", + mdecoder->frame->linesize[0], mdecoder->frame->linesize[1], + mdecoder->frame->linesize[2], mdecoder->frame->linesize[3], + mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + mdecoder->decoded_data = malloc(mdecoder->decoded_size); + ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size); + frame = avcodec_alloc_frame(); + avpicture_fill((AVPicture*) frame, mdecoder->decoded_data, mdecoder->codec_context->pix_fmt, mdecoder->codec_context->width, mdecoder->codec_context->height); - mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - mdecoder->decoded_data = malloc(mdecoder->decoded_size); - ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size); - frame = avcodec_alloc_frame(); - avpicture_fill((AVPicture *) frame, mdecoder->decoded_data, - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame, - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - av_free(frame); - } + av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame, + mdecoder->codec_context->pix_fmt, + mdecoder->codec_context->width, mdecoder->codec_context->height); + av_free(frame); + } + return ret; } @@ -328,15 +344,14 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI BYTE *dst; int dst_offset; #if 0 - LLOGLN(0, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size)); + WLog_DBG(TAG, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size)); int i; for(i = 0; i < data_size; i++) { - LLOG(0, ("%02X ", data[i])); + WLog_DBG(TAG, ("%02X ", data[i])); if(i % 16 == 15) - LLOG(0, ("\n")); + WLog_DBG(TAG, ("\n")); } - LLOG(0, ("\n")); #endif if(mdecoder->decoded_size_max == 0) mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16; @@ -387,7 +402,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI #endif if(len <= 0 || frame_size <= 0) { - DEBUG_WARN("error decoding"); + WLog_ERR(TAG, "error decoding"); break; } src += len; @@ -427,7 +442,7 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 d case AVMEDIA_TYPE_AUDIO: return tsmf_ffmpeg_decode_audio(decoder, data, data_size, extensions); default: - DEBUG_WARN("unknown media type."); + WLog_ERR(TAG, "unknown media type."); return FALSE; } } @@ -451,8 +466,8 @@ static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder) case PIX_FMT_YUV420P: return RDP_PIXFMT_I420; default: - DEBUG_WARN("unsupported pixel format %u", - mdecoder->codec_context->pix_fmt); + WLog_ERR(TAG, "unsupported pixel format %u", + mdecoder->codec_context->pix_fmt); return (UINT32) -1; } } @@ -493,10 +508,10 @@ static void tsmf_ffmpeg_free(ITSMFDecoder *decoder) static BOOL initialized = FALSE; #ifdef STATIC_CHANNELS -#define freerdp_tsmf_client_decoder_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) +ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) { TSMFFFmpegDecoder *decoder; if(!initialized) @@ -504,8 +519,9 @@ ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) avcodec_register_all(); initialized = TRUE; } - fprintf(stderr, "TSMFDecoderEntry FFMPEG\n"); - decoder = (TSMFFFmpegDecoder *) malloc(sizeof(TSMFFFmpegDecoder)); + + WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG"); + decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder)); ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder)); decoder->iface.SetFormat = tsmf_ffmpeg_set_format; decoder->iface.Decode = tsmf_ffmpeg_decode; diff --git a/channels/tsmf/client/gstreamer/CMakeLists.txt b/channels/tsmf/client/gstreamer/CMakeLists.txt index 3415da717..ee07c947c 100644 --- a/channels/tsmf/client/gstreamer/CMakeLists.txt +++ b/channels/tsmf/client/gstreamer/CMakeLists.txt @@ -64,14 +64,6 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} - ${LIBS}) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} ${LIBS} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index 6acc6eeb3..1bfc11e51 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -87,7 +87,7 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) if (!hdl) { - DEBUG_WARN("%s: Could not allocate handle.", __func__); + WLog_ERR(TAG, "Could not allocate handle."); return -1; } @@ -97,8 +97,7 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) if (hdl->shmid < 0) { - DEBUG_WARN("%s: failed to get access to shared memory - shmget()", - __func__); + WLog_ERR(TAG, "failed to get access to shared memory - shmget()"); return -2; } else @@ -106,7 +105,7 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) if (hdl->xfwin == (int *)-1) { - DEBUG_WARN("%s: shmat failed!", __func__); + WLog_ERR(TAG, "shmat failed!"); return -3; } @@ -114,7 +113,7 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) if (!hdl->disp) { - DEBUG_WARN("Failed to open display"); + WLog_ERR(TAG, "Failed to open display"); return -4; } @@ -140,7 +139,7 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder) if (!bus) { - DEBUG_WARN("gst_pipeline_get_bus failed!"); + WLog_ERR(TAG, "gst_pipeline_get_bus failed!"); return 1; } @@ -193,7 +192,7 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) if (!hdl->subwin) { - DEBUG_WARN("Could not create subwindow!"); + WLog_ERR(TAG, "Could not create subwindow!"); } XMapWindow(hdl->disp, hdl->subwin); @@ -238,14 +237,14 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height)) { - DEBUG_WARN("Could not resize overlay!"); + WLog_ERR(TAG, "Could not resize overlay!"); } gst_video_overlay_expose(overlay); #else if (!gst_x_overlay_set_render_rectangle(overlay, 0, 0, width, height)) { - DEBUG_WARN("Could not resize overlay!"); + WLog_ERR(TAG, "Could not resize overlay!"); } gst_x_overlay_expose(overlay); diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 33a609bef..0139b8996 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -120,10 +120,10 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d state_change = gst_element_set_state(mdecoder->pipe, desired_state); if (state_change == GST_STATE_CHANGE_FAILURE) - DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name); + WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name); else if (state_change == GST_STATE_CHANGE_ASYNC) { - DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name); + WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name); mdecoder->state = desired_state; } else @@ -142,7 +142,7 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) if (!data) { - DEBUG_WARN("Could not allocate %"G_GSIZE_FORMAT" bytes of data.", size); + WLog_ERR(TAG, "Could not allocate %"G_GSIZE_FORMAT" bytes of data.", size); return NULL; } @@ -154,7 +154,7 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) if (!buffer) { - DEBUG_WARN("Could not create GstBuffer"); + WLog_ERR(TAG, "Could not create GstBuffer"); free(data); return NULL; } @@ -191,10 +191,10 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m { case TSMF_SUB_TYPE_WVC1: mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", G_TYPE_INT, 3, + "format", G_TYPE_STRING, "WVC1", NULL); break; case TSMF_SUB_TYPE_MP4S: @@ -346,7 +346,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m NULL); break; default: - DEBUG_WARN("unknown format:(%d).", media_type->SubType); + WLog_ERR(TAG, "unknown format:(%d).", media_type->SubType); return FALSE; } @@ -358,7 +358,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m if (!buffer) { - DEBUG_WARN("could not allocate GstBuffer!"); + WLog_ERR(TAG, "could not allocate GstBuffer!"); return FALSE; } @@ -375,7 +375,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m return TRUE; } -void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) +void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder) { //Cleaning up elements if (!mdecoder || !mdecoder->pipe) @@ -416,7 +416,7 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) if (!mdecoder->pipe) { - DEBUG_WARN("Failed to create new pipe"); + WLog_ERR(TAG, "Failed to create new pipe"); return FALSE; } @@ -424,7 +424,7 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) if (!mdecoder->src) { - DEBUG_WARN("Failed to get appsrc"); + WLog_ERR(TAG, "Failed to get appsrc"); return FALSE; } @@ -432,7 +432,7 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) if (!mdecoder->outsink) { - DEBUG_WARN("Failed to get sink"); + WLog_ERR(TAG, "Failed to get sink"); return FALSE; } @@ -442,7 +442,7 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) if (!mdecoder->volume) { - DEBUG_WARN("Failed to get volume"); + WLog_ERR(TAG, "Failed to get volume"); return FALSE; } } @@ -482,7 +482,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (!mdecoder) { - DEBUG_WARN("Decoder not initialized!"); + WLog_ERR(TAG, "Decoder not initialized!"); return FALSE; } @@ -498,13 +498,13 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (mdecoder->gst_caps == NULL) { - DEBUG_WARN("tsmf_gstreamer_set_format not called or invalid format."); + WLog_ERR(TAG, "tsmf_gstreamer_set_format not called or invalid format."); return FALSE; } if (!mdecoder->src) { - DEBUG_WARN("failed to construct pipeline correctly. Unable to push buffer to source element."); + WLog_ERR(TAG, "failed to construct pipeline correctly. Unable to push buffer to source element."); return FALSE; } @@ -512,7 +512,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN if (gst_buf == NULL) { - DEBUG_WARN("tsmf_get_buffer_from_data(%p, %d) failed.", data, data_size); + WLog_ERR(TAG, "tsmf_get_buffer_from_data(%p, %d) failed.", data, data_size); return FALSE; } @@ -534,7 +534,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN GST_SEEK_TYPE_SET, sample_time, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { - DEBUG_WARN("seek failed"); + WLog_ERR(TAG, "seek failed"); } mdecoder->pipeline_start_time_valid = 0; @@ -608,7 +608,7 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro if (mdecoder->paused) { - DEBUG_WARN("%s: Ignoring control PAUSE, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring control PAUSE, already received!", get_type(mdecoder)); return; } @@ -624,7 +624,7 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro if (!mdecoder->paused && !mdecoder->shutdown) { - DEBUG_WARN("%s: Ignoring control RESUME, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring control RESUME, already received!", get_type(mdecoder)); return; } @@ -642,7 +642,7 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro if (mdecoder->shutdown) { - DEBUG_WARN("%s: Ignoring control STOP, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring control STOP, already received!", get_type(mdecoder)); return; } @@ -656,7 +656,7 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); } else - DEBUG_WARN("Unknown control message %08x", control_msg); + WLog_ERR(TAG, "Unknown control message %08x", control_msg); } static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) @@ -748,10 +748,10 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream } #ifdef STATIC_CHANNELS -#define freerdp_tsmf_client_decoder_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void) +ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) { TSMFGstreamerDecoder *decoder; diff --git a/channels/tsmf/client/pulse/CMakeLists.txt b/channels/tsmf/client/pulse/CMakeLists.txt index cdfa7fe5a..f0cf8abd9 100644 --- a/channels/tsmf/client/pulse/CMakeLists.txt +++ b/channels/tsmf/client/pulse/CMakeLists.txt @@ -27,13 +27,6 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec freerdp-utils) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY}) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index 8b476eb23..f35f24902 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -72,7 +72,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) return FALSE; if(pa_context_connect(pulse->context, NULL, 0, NULL)) { - DEBUG_WARN("pa_context_connect failed (%d)", + WLog_ERR(TAG, "pa_context_connect failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -80,7 +80,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) if(pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_WARN("pa_threaded_mainloop_start failed (%d)", + WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -120,19 +120,19 @@ static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device) pulse->mainloop = pa_threaded_mainloop_new(); if(!pulse->mainloop) { - DEBUG_WARN("pa_threaded_mainloop_new failed"); + WLog_ERR(TAG, "pa_threaded_mainloop_new failed"); return FALSE; } pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); if(!pulse->context) { - DEBUG_WARN("pa_context_new failed"); + WLog_ERR(TAG, "pa_context_new failed"); return FALSE; } pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse); if(tsmf_pulse_connect(pulse)) { - DEBUG_WARN("tsmf_pulse_connect failed"); + WLog_ERR(TAG, "tsmf_pulse_connect failed"); return FALSE; } DEBUG_TSMF("open device %s", pulse->device); @@ -214,7 +214,7 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) if(!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_WARN("pa_stream_new failed (%d)", + WLog_ERR(TAG, "pa_stream_new failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -233,7 +233,7 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - DEBUG_WARN("pa_stream_connect_playback failed (%d)", + WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -244,7 +244,7 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) break; if(!PA_STREAM_IS_GOOD(state)) { - DEBUG_WARN("bad stream state (%d)", + WLog_ERR(TAG, "bad stream state (%d)", pa_context_errno(pulse->context)); break; } diff --git a/channels/tsmf/client/tsmf_audio.c b/channels/tsmf/client/tsmf_audio.c index 6c7ab2ed6..d03ebbcef 100644 --- a/channels/tsmf/client/tsmf_audio.c +++ b/channels/tsmf/client/tsmf_audio.c @@ -41,7 +41,7 @@ static ITSMFAudioDevice* tsmf_load_audio_device_by_name(const char* name, const if (audio == NULL) { - DEBUG_WARN("failed to call export function in %s", name); + WLog_ERR(TAG, "failed to call export function in %s", name); return NULL; } diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 5fac84991..5657a8dd0 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -34,10 +34,14 @@ #include "tsmf_codec.h" +#include + +#define TAG CHANNELS_TAG("tsmf.client") + typedef struct _TSMFMediaTypeMap { BYTE guid[16]; - const char *name; + const char* name; int type; } TSMFMediaTypeMap; @@ -259,31 +263,38 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] = } }; -static void tsmf_print_guid(const BYTE *guid) +static void tsmf_print_guid(const BYTE* guid) { #ifdef WITH_DEBUG_TSMF int i; - for(i = 3; i >= 0; i--) - fprintf(stderr, "%02X", guid[i]); - fprintf(stderr, "-"); - for(i = 5; i >= 4; i--) - fprintf(stderr, "%02X", guid[i]); - fprintf(stderr, "-"); - for(i = 7; i >= 6; i--) - fprintf(stderr, "%02X", guid[i]); - fprintf(stderr, "-"); - for(i = 8; i < 16; i++) + + for (i = 3; i >= 0; i--) + WLog_INFO(TAG, "%02X", guid[i]); + + WLog_INFO(TAG, "-"); + + for (i = 5; i >= 4; i--) + WLog_INFO(TAG, "%02X", guid[i]); + + WLog_INFO(TAG, "-"); + + for (i = 7; i >= 6; i--) + WLog_INFO(TAG, "%02X", guid[i]); + + WLog_INFO(TAG, "-"); + + for (i = 8; i < 16; i++) { - fprintf(stderr, "%02X", guid[i]); - if(i == 9) - fprintf(stderr, "-"); + WLog_INFO(TAG, "%02X", guid[i]); + + if (i == 9) + WLog_INFO(TAG, "-"); } - fprintf(stderr, "\n"); #endif } /* http://msdn.microsoft.com/en-us/library/dd318229.aspx */ -static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s, BOOL bypass) +static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, BOOL bypass) { UINT32 biSize; UINT32 biWidth; @@ -292,18 +303,22 @@ static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wSt Stream_Read_UINT32(s, biWidth); Stream_Read_UINT32(s, biHeight); Stream_Seek(s, 28); - if(mediatype->Width == 0) + + if (mediatype->Width == 0) mediatype->Width = biWidth; - if(mediatype->Height == 0) + + if (mediatype->Height == 0) mediatype->Height = biHeight; + /* Assume there will be no color table for video? */ - if(bypass && biSize > 40) + if (bypass && biSize > 40) Stream_Seek(s, biSize - 40); + return (bypass ? biSize : 40); } /* http://msdn.microsoft.com/en-us/library/dd407326.aspx */ -static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE *mediatype, wStream *s) +static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wStream* s) { UINT64 AvgTimePerFrame; /* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */ @@ -327,7 +342,7 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE *mediatype, wSt } /* http://msdn.microsoft.com/en-us/library/dd390700.aspx */ -static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s) +static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s) { /* typedef struct tagVIDEOINFOHEADER { @@ -358,7 +373,7 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStr return 48; } -BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) +BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) { int i; UINT32 cbFormat; @@ -367,27 +382,35 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) /* MajorType */ DEBUG_TSMF("MajorType:"); tsmf_print_guid(Stream_Pointer(s)); - for(i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++) + + for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++) { - if(memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if (memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } + mediatype->MajorType = tsmf_major_type_map[i].type; - if(mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN) + + if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN) ret = FALSE; + DEBUG_TSMF("MajorType %s", tsmf_major_type_map[i].name); Stream_Seek(s, 16); /* SubType */ DEBUG_TSMF("SubType:"); tsmf_print_guid(Stream_Pointer(s)); - for(i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++) + + for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++) { - if(memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if (memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } + mediatype->SubType = tsmf_sub_type_map[i].type; - if(mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN) + + if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN) ret = FALSE; + DEBUG_TSMF("SubType %s", tsmf_sub_type_map[i].name); Stream_Seek(s, 16); /* bFixedSizeSamples, bTemporalCompression, SampleSize */ @@ -395,23 +418,28 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) /* FormatType */ DEBUG_TSMF("FormatType:"); tsmf_print_guid(Stream_Pointer(s)); - for(i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++) + + for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++) { - if(memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0) + if (memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } + mediatype->FormatType = tsmf_format_type_map[i].type; - if(mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN) + + if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN) ret = FALSE; + DEBUG_TSMF("FormatType %s", tsmf_format_type_map[i].name); Stream_Seek(s, 16); /* cbFormat */ Stream_Read_UINT32(s, cbFormat); DEBUG_TSMF("cbFormat %d", cbFormat); #ifdef WITH_DEBUG_TSMF - winpr_HexDump(Stream_Pointer(s), cbFormat); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(s), cbFormat); #endif - switch(mediatype->FormatType) + + switch (mediatype->FormatType) { case TSMF_FORMAT_TYPE_MFVIDEOFORMAT: /* http://msdn.microsoft.com/en-us/library/aa473808.aspx */ @@ -425,11 +453,13 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) Stream_Seek(s, 80); Stream_Read_UINT32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */ Stream_Seek(s, 36); - if(cbFormat > 176) + + if (cbFormat > 176) { mediatype->ExtraDataSize = cbFormat - 176; mediatype->ExtraData = Stream_Pointer(s); } + break; case TSMF_FORMAT_TYPE_WAVEFORMATEX: /* http://msdn.microsoft.com/en-us/library/dd757720.aspx */ @@ -442,51 +472,62 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s) Stream_Read_UINT16(s, mediatype->BlockAlign); Stream_Read_UINT16(s, mediatype->BitsPerSample); Stream_Read_UINT16(s, mediatype->ExtraDataSize); - if(mediatype->ExtraDataSize > 0) + + if (mediatype->ExtraDataSize > 0) mediatype->ExtraData = Stream_Pointer(s); + break; case TSMF_FORMAT_TYPE_MPEG1VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390700.aspx */ i = tsmf_codec_parse_VIDEOINFOHEADER(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); - if(cbFormat > i) + + if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } + break; case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390707.aspx */ i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); - if(cbFormat > i) + + if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } + break; case TSMF_FORMAT_TYPE_VIDEOINFO2: i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, FALSE); - if(cbFormat > i) + + if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } + break; default: break; } - if(mediatype->SamplesPerSecond.Numerator == 0) + + if (mediatype->SamplesPerSecond.Numerator == 0) mediatype->SamplesPerSecond.Numerator = 1; - if(mediatype->SamplesPerSecond.Denominator == 0) + + if (mediatype->SamplesPerSecond.Denominator == 0) mediatype->SamplesPerSecond.Denominator = 1; + return ret; } -BOOL tsmf_codec_check_media_type(wStream *s) +BOOL tsmf_codec_check_media_type(wStream* s) { - BYTE *m; + BYTE* m; BOOL ret; TS_AM_MEDIA_TYPE mediatype; Stream_GetPointer(s, m); diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 3d17c60d0..0067cd548 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -42,7 +42,7 @@ static ITSMFDecoder *tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYP decoder = entry(); if(decoder == NULL) { - DEBUG_WARN("failed to call export function in %s", name); + WLog_ERR(TAG, "failed to call export function in %s", name); return NULL; } if(!decoder->SetFormat(decoder, media_type)) diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 40e89e439..18c654b27 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -80,7 +80,7 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman) MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW); break; default: - DEBUG_WARN("unknown capability type %d", CapabilityType); + WLog_ERR(TAG, "unknown capability type %d", CapabilityType); break; } Stream_SetPosition(ifman->output, pos + cbCapabilityLength); @@ -236,7 +236,7 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN *ifman) if(presentation) tsmf_presentation_free(presentation); else - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); Stream_EnsureRemainingCapacity(ifman->output, 4); Stream_Write_UINT32(ifman->output, 0); /* Result */ ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB; @@ -261,7 +261,7 @@ int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman) } else { - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); } ifman->output_pending = TRUE; return 0; @@ -393,13 +393,13 @@ int tsmf_ifman_on_sample(TSMF_IFMAN *ifman) presentation = tsmf_presentation_find_by_id(ifman->presentation_id); if(presentation == NULL) { - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); return 1; } stream = tsmf_stream_find_by_id(presentation, StreamId); if(stream == NULL) { - DEBUG_WARN("unknown stream id"); + WLog_ERR(TAG, "unknown stream id"); return 1; } tsmf_stream_push_sample(stream, ifman->channel_callback, @@ -420,7 +420,7 @@ int tsmf_ifman_on_flush(TSMF_IFMAN *ifman) presentation = tsmf_presentation_find_by_id(ifman->presentation_id); if(presentation == NULL) { - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); return 1; } tsmf_presentation_flush(presentation); @@ -460,7 +460,7 @@ int tsmf_ifman_on_playback_started(TSMF_IFMAN *ifman) if(presentation) tsmf_presentation_start(presentation); else - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); Stream_EnsureRemainingCapacity(ifman->output, 16); Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ Stream_Write_UINT32(ifman->output, 0); /* StreamId */ @@ -480,7 +480,7 @@ int tsmf_ifman_on_playback_paused(TSMF_IFMAN *ifman) if(presentation) tsmf_presentation_paused(presentation); else - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); return 0; } @@ -494,7 +494,7 @@ int tsmf_ifman_on_playback_restarted(TSMF_IFMAN *ifman) if(presentation) tsmf_presentation_restarted(presentation); else - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); return 0; } @@ -506,7 +506,7 @@ int tsmf_ifman_on_playback_stopped(TSMF_IFMAN *ifman) if(presentation) tsmf_presentation_stop(presentation); else - DEBUG_WARN("unknown presentation id"); + WLog_ERR(TAG, "unknown presentation id"); Stream_EnsureRemainingCapacity(ifman->output, 16); Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ Stream_Write_UINT32(ifman->output, 0); /* StreamId */ diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index ec0426fba..65ce35b4c 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -89,14 +89,14 @@ void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, Stream_Write_UINT64(s, data_size); /* cbData */ DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s)); if(!callback || !callback->channel || !callback->channel->Write) - DEBUG_WARN("callback=%p, channel=%p, write=%p", callback, + WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback, callback->channel, callback->channel->Write); else status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL); if(status) { - DEBUG_WARN("response error %d", status); + WLog_ERR(TAG, "response error %d", status); } Stream_Free(s, TRUE); } @@ -108,7 +108,7 @@ BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *eve status = callback->channel_mgr->PushEvent(callback->channel_mgr, event); if(status) { - DEBUG_WARN("response error %d", status); + WLog_ERR(TAG, "response error %d", status); return FALSE; } return TRUE; @@ -130,7 +130,7 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w /* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */ if(cbSize < 12) { - DEBUG_WARN("invalid size. cbSize=%d", cbSize); + WLog_ERR(TAG, "invalid size. cbSize=%d", cbSize); return 1; } @@ -272,7 +272,7 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w } if(status == -1) { - DEBUG_WARN("InterfaceId 0x%X FunctionId 0x%X not processed.", + WLog_ERR(TAG, "InterfaceId 0x%X FunctionId 0x%X not processed.", InterfaceId, FunctionId); /* When a request is not implemented we return empty response indicating error */ } @@ -289,7 +289,7 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL); if(status) { - DEBUG_WARN("response error %d", status); + WLog_ERR(TAG, "response error %d", status); } } Stream_Free(output, TRUE); @@ -329,6 +329,7 @@ static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallbac ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK)); callback->iface.OnDataReceived = tsmf_on_data_received; callback->iface.OnClose = tsmf_on_close; + callback->iface.OnOpen = NULL; callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 51465554b..6538983f6 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -271,7 +271,7 @@ TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCal if (!presentation) { - DEBUG_WARN("calloc failed"); + WLog_ERR(TAG, "calloc failed"); return NULL; } @@ -320,7 +320,7 @@ TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid) ArrayList_Unlock(presentation_list); if (!found) - DEBUG_WARN("presentation id %s not found", guid_to_string(guid, guid_str, sizeof(guid_str))); + WLog_WARN(TAG, "presentation id %s not found", guid_to_string(guid, guid_str, sizeof(guid_str))); return (found) ? presentation : NULL; } @@ -902,7 +902,7 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) if (stream) { - DEBUG_WARN("duplicated stream id %d!", stream_id); + WLog_ERR(TAG, "duplicated stream id %d!", stream_id); return NULL; } @@ -910,7 +910,7 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) if (!stream) { - DEBUG_WARN("Calloc failed"); + WLog_ERR(TAG, "Calloc failed"); return NULL; } @@ -966,7 +966,7 @@ void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) if (stream->decoder) { - DEBUG_WARN("duplicated call"); + WLog_ERR(TAG, "duplicated call"); return; } @@ -1071,7 +1071,7 @@ void tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pC if (!sample) { - DEBUG_WARN("calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); return; } @@ -1087,7 +1087,7 @@ void tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pC if (!sample->data) { - DEBUG_WARN("calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); free(sample); return; } diff --git a/channels/tsmf/client/tsmf_types.h b/channels/tsmf/client/tsmf_types.h index 4911209d4..07cd999fc 100644 --- a/channels/tsmf/client/tsmf_types.h +++ b/channels/tsmf/client/tsmf_types.h @@ -26,12 +26,14 @@ #include #include -#include +#include + +#define TAG CHANNELS_TAG("tsmf.client") #ifdef WITH_DEBUG_TSMF -#define DEBUG_TSMF(fmt, ...) DEBUG_CLASS(TSMF, fmt, ## __VA_ARGS__) +#define DEBUG_TSMF(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_TSMF(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_TSMF(fmt, ...) do { } while (0) #endif typedef struct _TS_AM_MEDIA_TYPE diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 7af13726c..4d5069f93 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -42,15 +42,7 @@ set(${MODULE_PREFIX}_LIBS ${UDEV_LIBRARIES} ${UUID_LIBRARIES}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-common freerdp-utils) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index f0aa961d1..b0a37fd25 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -100,7 +100,7 @@ static int func_check_isochronous_fds(IUDEVICE* pdev) ret = isoch_queue->unregister_data(isoch_queue, isoch); if (!ret) - LLOGLN(0, ("isoch_queue_unregister_data: Not found isoch data!!\n")); + WLog_DBG(TAG, "isoch_queue_unregister_data: Not found isoch data!!"); pthread_mutex_unlock(&isoch_queue->isoch_loading); @@ -124,7 +124,7 @@ static int urbdrc_process_register_request_callback(URBDRC_CHANNEL_CALLBACK* cal UINT32 NumRequestCompletion = 0; UINT32 RequestCompletion = 0; - LLOGLN(urbdrc_debug, ("urbdrc_process_register_request_callback")); + WLog_DBG(TAG, "urbdrc_process_register_request_callback"); pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); @@ -165,7 +165,7 @@ static int urbdrc_process_cancel_request(BYTE* data, UINT32 data_sizem, IUDEVMAN data_read_UINT32(data + 0, CancelId); /** RequestId */ - LLOGLN(urbdrc_debug, ("urbdrc_process_cancel_request: id 0x%x", CancelId)); + WLog_DBG(TAG, "urbdrc_process_cancel_request: id 0x%x", CancelId); pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); @@ -180,19 +180,19 @@ static int urbdrc_process_cancel_request(BYTE* data, UINT32 data_sizem, IUDEVMAN static int urbdrc_process_retract_device_request(BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, UINT32 UsbDevice) { UINT32 Reason; - LLOGLN(urbdrc_debug, ("urbdrc_process_retract_device_request")); + WLog_DBG(TAG, "urbdrc_process_retract_device_request"); data_read_UINT32(data + 0, Reason); /** Reason */ switch (Reason) { case UsbRetractReason_BlockedByPolicy: - LLOGLN(urbdrc_debug, ("UsbRetractReason_BlockedByPolicy: now it is not support")); + WLog_DBG(TAG, "UsbRetractReason_BlockedByPolicy: now it is not support"); return -1; break; default: - LLOGLN(urbdrc_debug, ("urbdrc_process_retract_device_request: Unknown Reason %d", Reason)); + WLog_DBG(TAG, "urbdrc_process_retract_device_request: Unknown Reason %d", Reason); return -1; break; } @@ -215,7 +215,7 @@ static int urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* da BYTE* out_data; int i, offset, success = 0; - LLOGLN(urbdrc_debug, ("urbdrc_process__io_control")); + WLog_DBG(TAG, "urbdrc_process__io_control"); data_read_UINT32(data + 0, IoControlCode); data_read_UINT32(data + 4, InputBufferSize); @@ -236,16 +236,16 @@ static int urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* da switch (IoControlCode) { case IOCTL_INTERNAL_USB_SUBMIT_URB: /** 0x00220003 */ - LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB")); - fprintf(stderr, " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked\n"); + WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB"); + WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked"); break; case IOCTL_INTERNAL_USB_RESET_PORT: /** 0x00220007 */ - LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_RESET_PORT")); + WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_RESET_PORT"); break; case IOCTL_INTERNAL_USB_GET_PORT_STATUS: /** 0x00220013 */ - LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS")); + WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS"); success = pdev->query_device_port_status(pdev, &usbd_status, &OutputBufferSize, OutputBuffer); @@ -261,24 +261,24 @@ static int urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* da OutputBufferSize = 4; } - LLOGLN(urbdrc_debug, ("PORT STATUS(fake!):0x%02x%02x%02x%02x", - OutputBuffer[3], OutputBuffer[2], OutputBuffer[1], OutputBuffer[0])); + WLog_DBG(TAG, "PORT STATUS(fake!):0x%02x%02x%02x%02x", + OutputBuffer[3], OutputBuffer[2], OutputBuffer[1], OutputBuffer[0]); } break; case IOCTL_INTERNAL_USB_CYCLE_PORT: /** 0x0022001F */ - LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT")); - fprintf(stderr, " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked\n"); + WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT"); + WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked"); break; case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: /** 0x00220027 */ - LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION")); - fprintf(stderr, " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked\n"); + WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); + WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked"); break; default: - LLOGLN(urbdrc_debug, ("urbdrc_process_io_control: unknown IoControlCode 0x%X", IoControlCode)); + WLog_DBG(TAG, "urbdrc_process_io_control: unknown IoControlCode 0x%X", IoControlCode); zfree(OutputBuffer); return -1; break; @@ -321,7 +321,7 @@ static int urbdrc_process_internal_io_control(URBDRC_CHANNEL_CALLBACK* callback, data_read_UINT32(data + 0, IoControlCode); - LLOGLN(urbdrc_debug, ("urbdrc_process_internal_io_control:0x%x", IoControlCode)); + WLog_DBG(TAG, "urbdrc_process_internal_io_control:0x%x", IoControlCode); data_read_UINT32(data + 4, InputBufferSize); data_read_UINT32(data + 8, OutputBufferSize); @@ -370,7 +370,7 @@ static int urbdrc_process_query_device_text(URBDRC_CHANNEL_CALLBACK* callback, B BYTE DeviceDescription[bufferSize]; int out_offset; - LLOGLN(urbdrc_debug, ("urbdrc_process_query_device_text")); + WLog_DBG(TAG, "urbdrc_process_query_device_text"); data_read_UINT32(data + 0, TextType); data_read_UINT32(data + 4, LocaleId); @@ -448,7 +448,7 @@ static int urb_select_configuration(URBDRC_CHANNEL_CALLBACK* callback, BYTE* dat if (transferDir == 0) { - fprintf(stderr, "urb_select_configuration: not support transfer out\n"); + WLog_ERR(TAG, "urb_select_configuration: not support transfer out"); return -1; } @@ -540,7 +540,7 @@ static int urb_select_interface(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, U if (transferDir == 0) { - fprintf(stderr, "urb_select_interface: not support transfer out\n"); + WLog_ERR(TAG, "urb_select_interface: not support transfer out"); return -1; } @@ -648,7 +648,7 @@ static int urb_control_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, if (length != OutputBufferSize) { - LLOGLN(urbdrc_debug, ("urb_control_transfer ERROR: buf != length")); + WLog_ERR(TAG, "urb_control_transfer ERROR: buf != length"); return -1; } @@ -675,7 +675,7 @@ static int urb_control_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, Timeout); if (ret < 0){ - LLOGLN(urbdrc_debug, ("control_transfer: error num %d!!\n", ret)); + WLog_DBG(TAG, "control_transfer: error num %d!!", ret); OutputBufferSize = 0; } @@ -866,12 +866,12 @@ static int urb_isoch_transfer(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, break; } - LLOGLN(urbdrc_debug, ("urb_isoch_transfer: EndpointAddress: 0x%x, " + WLog_DBG(TAG, "urb_isoch_transfer: EndpointAddress: 0x%x, " "TransferFlags: 0x%x, " "StartFrame: 0x%x, " "NumberOfPackets: 0x%x, " "OutputBufferSize: 0x%x " "RequestId: 0x%x", EndpointAddress, TransferFlags, StartFrame, - NumberOfPackets, OutputBufferSize, RequestId)); + NumberOfPackets, OutputBufferSize, RequestId); #if ISOCH_FIFO ISOCH_CALLBACK_QUEUE * isoch_queue = NULL; @@ -1010,7 +1010,7 @@ static int urb_control_descriptor_request(URBDRC_CHANNEL_CALLBACK* callback, memcpy(buffer, data + offset, OutputBufferSize); break; default: - LLOGLN(urbdrc_debug, ("%s: get error transferDir", __func__)); + WLog_DBG(TAG, "get error transferDir"); OutputBufferSize = 0; usbd_status = USBD_STATUS_STALL_PID; break; @@ -1030,7 +1030,7 @@ static int urb_control_descriptor_request(URBDRC_CHANNEL_CALLBACK* callback, if (ret < 0) { - LLOGLN(urbdrc_debug, ("%s:get_descriptor: error num %d", __func__, ret)); + WLog_DBG(TAG, "get_descriptor: error num %d", ret); OutputBufferSize = 0; } @@ -1073,7 +1073,7 @@ static int urb_control_get_status_request(URBDRC_CHANNEL_CALLBACK * callback, BY int offset, ret; if (transferDir == 0){ - LLOGLN(urbdrc_debug, ("urb_control_get_status_request: not support transfer out\n")); + WLog_DBG(TAG, "urb_control_get_status_request: not support transfer out"); return -1; } @@ -1105,7 +1105,7 @@ static int urb_control_get_status_request(URBDRC_CHANNEL_CALLBACK * callback, BY 1000); if (ret < 0){ - LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d!!\n", __func__, ret)); + WLog_DBG(TAG, "control_transfer: error num %d!!", ret); OutputBufferSize = 0; usbd_status = USBD_STATUS_STALL_PID; } @@ -1198,11 +1198,11 @@ static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK * callbac if (TransferFlags & USBD_TRANSFER_DIRECTION) bmRequestType |= 0x80; - LLOGLN(urbdrc_debug, ("urb_control_vendor_or_class_request: " + WLog_DBG(TAG, "urb_control_vendor_or_class_request: " "RequestId 0x%x TransferFlags: 0x%x ReqTypeReservedBits: 0x%x " "Request:0x%x Value: 0x%x Index: 0x%x OutputBufferSize: 0x%x bmRequestType: 0x%x!!", RequestId, TransferFlags, ReqTypeReservedBits, Request, Value, - Index, OutputBufferSize, bmRequestType)); + Index, OutputBufferSize, bmRequestType); ret = pdev->control_transfer( pdev, RequestId, 0, 0, bmRequestType, @@ -1215,7 +1215,7 @@ static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK * callbac 2000); if (ret < 0){ - LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d!!", __func__, ret)); + WLog_DBG(TAG, "control_transfer: error num %d!!", ret); OutputBufferSize = 0; usbd_status = USBD_STATUS_STALL_PID; } @@ -1297,18 +1297,18 @@ static int urb_os_feature_descriptor_request(URBDRC_CHANNEL_CALLBACK * callback, switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - fprintf(stderr, "Function urb_os_feature_descriptor_request: OUT Unchecked\n"); + WLog_ERR(TAG, "Function urb_os_feature_descriptor_request: OUT Unchecked"); memcpy(buffer, data + offset, OutputBufferSize); break; case USBD_TRANSFER_DIRECTION_IN: break; } - LLOGLN(urbdrc_debug, ("Ms descriptor arg: Recipient:0x%x, " + WLog_DBG(TAG, "Ms descriptor arg: Recipient:0x%x, " "InterfaceNumber:0x%x, Ms_PageIndex:0x%x, " "Ms_featureDescIndex:0x%x, OutputBufferSize:0x%x", Recipient, InterfaceNumber, Ms_PageIndex, - Ms_featureDescIndex, OutputBufferSize)); + Ms_featureDescIndex, OutputBufferSize); /** get ms string */ ret = pdev->os_feature_descriptor_request( pdev, RequestId, Recipient, @@ -1321,7 +1321,7 @@ static int urb_os_feature_descriptor_request(URBDRC_CHANNEL_CALLBACK * callback, 1000); if (ret < 0) - LLOGLN(urbdrc_debug, ("os_feature_descriptor_request: error num %d", ret)); + WLog_DBG(TAG, "os_feature_descriptor_request: error num %d", ret); offset = 36; out_size = offset + OutputBufferSize; @@ -1367,7 +1367,7 @@ static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, int out_offset, ret; if (transferDir == 0){ - LLOGLN(urbdrc_debug, ("urb_pipe_request: not support transfer out\n")); + WLog_DBG(TAG, "urb_pipe_request: not support transfer out"); return -1; } @@ -1386,7 +1386,7 @@ static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, switch (action){ case PIPE_CANCEL: - LLOGLN(urbdrc_debug, ("urb_pipe_request: PIPE_CANCEL 0x%x ", EndpointAddress)); + WLog_DBG(TAG, "urb_pipe_request: PIPE_CANCEL 0x%x ", EndpointAddress); ret = pdev->control_pipe_request( pdev, RequestId, EndpointAddress, @@ -1394,13 +1394,13 @@ static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, PIPE_CANCEL); if (ret < 0) { - LLOGLN(urbdrc_debug, ("PIPE SET HALT: error num %d", ret)); + WLog_DBG(TAG, "PIPE SET HALT: error num %d", ret); } break; case PIPE_RESET: - LLOGLN(urbdrc_debug, ("urb_pipe_request: PIPE_RESET ep 0x%x ", EndpointAddress)); + WLog_DBG(TAG, "urb_pipe_request: PIPE_RESET ep 0x%x ", EndpointAddress); ret = pdev->control_pipe_request( pdev, RequestId, EndpointAddress, @@ -1408,11 +1408,11 @@ static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, PIPE_RESET); if (ret < 0) - LLOGLN(urbdrc_debug, ("PIPE RESET: error num %d!!\n", ret)); + WLog_DBG(TAG, "PIPE RESET: error num %d!!", ret); break; default: - LLOGLN(urbdrc_debug, ("urb_pipe_request action: %d is not support!\n", action)); + WLog_DBG(TAG, "urb_pipe_request action: %d is not support!", action); break; } @@ -1459,7 +1459,7 @@ static int urb_get_current_frame_number(URBDRC_CHANNEL_CALLBACK* callback, BYTE* out_data; if (transferDir == 0){ - LLOGLN(urbdrc_debug, ("urb_get_current_frame_number: not support transfer out\n")); + WLog_DBG(TAG, "urb_get_current_frame_number: not support transfer out"); //exit(1); return -1; } @@ -1519,8 +1519,8 @@ static int urb_control_get_configuration_request(URBDRC_CHANNEL_CALLBACK* callba if (transferDir == 0) { - LLOGLN(urbdrc_debug, ("urb_control_get_configuration_request:" - " not support transfer out\n")); + WLog_DBG(TAG, "urb_control_get_configuration_request:" + " not support transfer out"); return -1; } @@ -1551,7 +1551,7 @@ static int urb_control_get_configuration_request(URBDRC_CHANNEL_CALLBACK* callba 1000); if (ret < 0){ - LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d\n", __func__, ret)); + WLog_DBG(TAG, "control_transfer: error num %d", ret); OutputBufferSize = 0; } @@ -1600,7 +1600,7 @@ static int urb_control_get_interface_request(URBDRC_CHANNEL_CALLBACK* callback, int ret, offset; if (transferDir == 0){ - LLOGLN(urbdrc_debug, ("urb_control_get_interface_request: not support transfer out\n")); + WLog_DBG(TAG, "urb_control_get_interface_request: not support transfer out"); return -1; } @@ -1629,7 +1629,7 @@ static int urb_control_get_interface_request(URBDRC_CHANNEL_CALLBACK* callback, 1000); if (ret < 0){ - LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d\n", __func__, ret)); + WLog_DBG(TAG, "control_transfer: error num %d", ret); OutputBufferSize = 0; } @@ -1700,7 +1700,7 @@ static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - fprintf(stderr, "Function urb_control_feature_request: OUT Unchecked\n"); + WLog_ERR(TAG, "Function urb_control_feature_request: OUT Unchecked"); memcpy(buffer, data + offset, OutputBufferSize); bmRequestType |= 0x00; break; @@ -1718,7 +1718,7 @@ static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE bmRequest = 0x01; /* REQUEST_CLEAR_FEATURE */ break; default: - fprintf(stderr, "urb_control_feature_request: Error Command %x\n", command); + WLog_ERR(TAG, "urb_control_feature_request: Error Command %x", command); zfree(out_data); return -1; } @@ -1733,7 +1733,7 @@ static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE 1000); if (ret < 0){ - LLOGLN(urbdrc_debug, ("feature control transfer: error num %d", ret)); + WLog_DBG(TAG, "feature control transfer: error num %d", ret); OutputBufferSize = 0; } @@ -1790,7 +1790,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B switch (URB_Function) { case URB_FUNCTION_SELECT_CONFIGURATION: /** 0x0000 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SELECT_CONFIGURATION")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_CONFIGURATION"); error = urb_select_configuration( callback, data + 8, data_sizem - 8, @@ -1800,7 +1800,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SELECT_INTERFACE: /** 0x0001 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SELECT_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_INTERFACE"); error = urb_select_interface( callback, data + 8, data_sizem - 8, @@ -1810,7 +1810,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_ABORT_PIPE: /** 0x0002 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_ABORT_PIPE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ABORT_PIPE"); error = urb_pipe_request( callback, data + 8, data_sizem - 8, MessageId, @@ -1820,31 +1820,31 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B PIPE_CANCEL); break; case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: /** 0x0003 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL"); error = -1; /** This URB function is obsolete in Windows 2000 * and later operating systems * and is not supported by Microsoft. */ break; case URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL: /** 0x0004 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL"); error = -1; /** This URB function is obsolete in Windows 2000 * and later operating systems * and is not supported by Microsoft. */ break; case URB_FUNCTION_GET_FRAME_LENGTH: /** 0x0005 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_FRAME_LENGTH")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_FRAME_LENGTH"); error = -1; /** This URB function is obsolete in Windows 2000 * and later operating systems * and is not supported by Microsoft. */ break; case URB_FUNCTION_SET_FRAME_LENGTH: /** 0x0006 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FRAME_LENGTH")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FRAME_LENGTH"); error = -1; /** This URB function is obsolete in Windows 2000 * and later operating systems * and is not supported by Microsoft. */ break; case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: /** 0x0007 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_CURRENT_FRAME_NUMBER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CURRENT_FRAME_NUMBER"); error = urb_get_current_frame_number( callback, data + 8, data_sizem - 8, @@ -1854,7 +1854,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CONTROL_TRANSFER: /** 0x0008 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CONTROL_TRANSFER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER"); error = urb_control_transfer( callback, data + 8, data_sizem - 8, @@ -1865,7 +1865,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B URB_CONTROL_TRANSFER_NONEXTERNAL); break; case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: /** 0x0009 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"); error = urb_bulk_or_interrupt_transfer( callback, data + 8, data_sizem - 8, @@ -1875,7 +1875,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_ISOCH_TRANSFER: /** 0x000A */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_ISOCH_TRANSFER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ISOCH_TRANSFER"); error = urb_isoch_transfer( callback, data + 8, data_sizem - 8, MessageId, @@ -1884,7 +1884,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: /** 0x000B */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -1895,7 +1895,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: /** 0x000C */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -1906,7 +1906,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_FEATURE_TO_DEVICE: /** 0x000D */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_DEVICE"); error = urb_control_feature_request(callback, data + 8, data_sizem - 8, @@ -1918,7 +1918,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: /** 0x000E */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_INTERFACE"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -1930,7 +1930,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_ENDPOINT"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -1942,7 +1942,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -1954,7 +1954,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -1966,7 +1966,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -1978,7 +1978,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_STATUS_FROM_DEVICE: /** 0x0013 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_STATUS_FROM_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_DEVICE"); error = urb_control_get_status_request( callback, data + 8, data_sizem - 8, @@ -1989,7 +1989,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_STATUS_FROM_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_INTERFACE"); error = urb_control_get_status_request( callback, data + 8, data_sizem - 8, @@ -2000,7 +2000,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT"); error = urb_control_get_status_request( callback, data + 8, data_sizem - 8, @@ -2011,11 +2011,11 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_RESERVED_0X0016: /** 0x0016 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVED_0X0016")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVED_0X0016"); error = -1; break; case URB_FUNCTION_VENDOR_DEVICE: /** 0x0017 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_VENDOR_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_DEVICE"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2027,7 +2027,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_VENDOR_INTERFACE: /** 0x0018 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_VENDOR_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_INTERFACE"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2039,7 +2039,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_VENDOR_ENDPOINT: /** 0x0019 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_VENDOR_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_ENDPOINT"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2051,7 +2051,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLASS_DEVICE: /** 0x001A */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLASS_DEVICE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_DEVICE"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2063,7 +2063,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLASS_INTERFACE: /** 0x001B */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLASS_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_INTERFACE"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2075,7 +2075,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLASS_ENDPOINT: /** 0x001C */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLASS_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_ENDPOINT"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2087,11 +2087,11 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_RESERVE_0X001D: /** 0x001D */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X001D")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X001D"); error = -1; break; case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL"); error = urb_pipe_request( callback, data + 8, data_sizem - 8, MessageId, @@ -2101,7 +2101,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B PIPE_RESET); break; case URB_FUNCTION_CLASS_OTHER: /** 0x001F */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLASS_OTHER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_OTHER"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2113,7 +2113,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_VENDOR_OTHER: /** 0x0020 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_VENDOR_OTHER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_OTHER"); error = urb_control_vendor_or_class_request( callback, data + 8, data_sizem - 8, @@ -2125,7 +2125,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_STATUS_FROM_OTHER: /** 0x0021 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_STATUS_FROM_OTHER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_OTHER"); error = urb_control_get_status_request( callback, data + 8, data_sizem - 8, @@ -2136,7 +2136,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_OTHER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_OTHER"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -2148,7 +2148,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_FEATURE_TO_OTHER: /** 0x0023 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_OTHER")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_OTHER"); error = urb_control_feature_request( callback, data + 8, data_sizem - 8, @@ -2160,7 +2160,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -2171,7 +2171,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -2182,7 +2182,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_CONFIGURATION: /** 0x0026 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_CONFIGURATION")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CONFIGURATION"); error = urb_control_get_configuration_request( callback, data + 8, data_sizem - 8, @@ -2192,7 +2192,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_INTERFACE: /** 0x0027 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_INTERFACE"); error = urb_control_get_interface_request( callback, data + 8, data_sizem - 8, @@ -2202,7 +2202,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -2213,7 +2213,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE"); error = urb_control_descriptor_request( callback, data + 8, data_sizem - 8, @@ -2224,7 +2224,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: /** 0x002A */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR"); error = urb_os_feature_descriptor_request( callback, data + 8, data_sizem - 8, @@ -2234,28 +2234,28 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B transferDir); break; case URB_FUNCTION_RESERVE_0X002B: /** 0x002B */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002B")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002B"); error = -1; break; case URB_FUNCTION_RESERVE_0X002C: /** 0x002C */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002C")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002C"); error = -1; break; case URB_FUNCTION_RESERVE_0X002D: /** 0x002D */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002D")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002D"); error = -1; break; case URB_FUNCTION_RESERVE_0X002E: /** 0x002E */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002E")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002E"); error = -1; break; case URB_FUNCTION_RESERVE_0X002F: /** 0x002F */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002F")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002F"); error = -1; break; /** USB 2.0 calls start at 0x0030 */ case URB_FUNCTION_SYNC_RESET_PIPE: /** 0x0030 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SYNC_RESET_PIPE")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE"); error = urb_pipe_request( callback, data + 8, data_sizem - 8, @@ -2267,7 +2267,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B error = -9; /** function not support */ break; case URB_FUNCTION_SYNC_CLEAR_STALL: /** 0x0031 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SYNC_CLEAR_STALL")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_CLEAR_STALL"); error = urb_pipe_request( callback, data + 8, data_sizem - 8, @@ -2279,7 +2279,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B error = -9; break; case URB_FUNCTION_CONTROL_TRANSFER_EX: /** 0x0032 */ - LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_CONTROL_TRANSFER_EX")); + WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER_EX"); error = urb_control_transfer( callback, data + 8, data_sizem - 8, @@ -2290,7 +2290,7 @@ static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, B URB_CONTROL_TRANSFER_EXTERNAL); break; default: - LLOGLN(urbdrc_debug, ("URB_Func: %x is not found!", URB_Function)); + WLog_DBG(TAG, "URB_Func: %x is not found!", URB_Function); break; } @@ -2331,8 +2331,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) switch (FunctionId) { case CANCEL_REQUEST: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>CANCEL_REQUEST<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>CANCEL_REQUEST<<0x%X", FunctionId); error = urbdrc_process_cancel_request( pBuffer + 8, cbSize - 8, @@ -2340,8 +2340,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) UsbDevice); break; case REGISTER_REQUEST_CALLBACK: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>REGISTER_REQUEST_CALLBACK<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>REGISTER_REQUEST_CALLBACK<<0x%X", FunctionId); error = urbdrc_process_register_request_callback( callback, pBuffer + 8, @@ -2350,8 +2350,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) UsbDevice); break; case IO_CONTROL: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>IO_CONTROL<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>IO_CONTROL<<0x%X", FunctionId); error = urbdrc_process_io_control( callback, pBuffer + 8, @@ -2360,8 +2360,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) udevman, UsbDevice); break; case INTERNAL_IO_CONTROL: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>INTERNAL_IO_CONTROL<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>INTERNAL_IO_CONTROL<<0x%X", FunctionId); error = urbdrc_process_internal_io_control( callback, pBuffer + 8, @@ -2370,8 +2370,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) udevman, UsbDevice); break; case QUERY_DEVICE_TEXT: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>QUERY_DEVICE_TEXT<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>QUERY_DEVICE_TEXT<<0x%X", FunctionId); error = urbdrc_process_query_device_text( callback, pBuffer + 8, @@ -2381,8 +2381,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) UsbDevice); break; case TRANSFER_IN_REQUEST: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>TRANSFER_IN_REQUEST<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>TRANSFER_IN_REQUEST<<0x%X", FunctionId); error = urbdrc_process_transfer_request( callback, pBuffer + 8, @@ -2393,8 +2393,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) USBD_TRANSFER_DIRECTION_IN); break; case TRANSFER_OUT_REQUEST: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>TRANSFER_OUT_REQUEST<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>TRANSFER_OUT_REQUEST<<0x%X", FunctionId); error = urbdrc_process_transfer_request( callback, pBuffer + 8, @@ -2405,8 +2405,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) USBD_TRANSFER_DIRECTION_OUT); break; case RETRACT_DEVICE: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " >>RETRACT_DEVICE<<0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " >>RETRACT_DEVICE<<0x%X", FunctionId); error = urbdrc_process_retract_device_request( pBuffer + 8, cbSize - 8, @@ -2414,8 +2414,8 @@ void* urbdrc_process_udev_data_transfer(void* arg) UsbDevice); break; default: - LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" - " unknown FunctionId 0x%X", FunctionId)); + WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" + " unknown FunctionId 0x%X", FunctionId); error = -1; break; } diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index 49386f48f..6770be4b7 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -39,10 +39,8 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${UUID_LIBRARIES} ${LIBUSB_1_LIBRARIES}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 82775fffb..d7cf55ff1 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -118,7 +118,7 @@ retry: if (completed == NULL || !*completed) { /* we obtained the event lock: do our own event handling */ - LLOGLN(10, ("doing our own event handling")); + WLog_DBG(TAG,"doing our own event handling"); r = libusb_handle_events_locked(ctx, &tv); } @@ -139,11 +139,11 @@ retry: /* we hit a race: whoever was event handling earlier finished in the * time it took us to reach this point. try the cycle again. */ libusb_unlock_event_waiters(ctx); - LLOGLN(10, ("event handler was active but went away, retrying")); + WLog_DBG(TAG,"event handler was active but went away, retrying"); goto retry; } - LLOGLN(10, ("another thread is doing event handling")); + WLog_DBG(TAG,"another thread is doing event handling"); r = libusb_wait_for_event(ctx, &poll_timeout); already_done: @@ -201,7 +201,7 @@ static void func_iso_callback(struct libusb_transfer *transfer) } else { - //fprintf(stderr, "actual length %d \n", act_len); + //WLog_ERR(TAG, "actual length %d ", act_len); //exit(EXIT_FAILURE); } } @@ -273,7 +273,7 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) case LIBUSB_ERROR_IO: *status = USBD_STATUS_STALL_PID; - LLOGLN(10, ("urb_status: LIBUSB_ERROR_IO!!\n")); + WLog_ERR(TAG,"LIBUSB_ERROR_IO!!"); break; case LIBUSB_ERROR_INVALID_PARAM: @@ -291,7 +291,7 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) if (!(pdev->status & URBDRC_DEVICE_NOT_FOUND)) { pdev->status |= URBDRC_DEVICE_NOT_FOUND; - LLOGLN(libusb_debug, ("urb_status: LIBUSB_ERROR_NO_DEVICE!!\n")); + WLog_WARN(TAG,"LIBUSB_ERROR_NO_DEVICE!!"); } } break; @@ -362,7 +362,7 @@ static int func_config_release_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle if (ret < 0) { - fprintf(stderr, "config_release_all_interface: error num %d\n", ret); + WLog_ERR(TAG, "config_release_all_interface: error num %d", ret); return -1; } } @@ -380,7 +380,7 @@ static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int Num if (ret < 0) { - fprintf(stderr, "claim_all_interface: error num %d\n", ret); + WLog_ERR(TAG, "claim_all_interface: error num %d", ret); return -1; } } @@ -394,28 +394,28 @@ static void* print_transfer_status(enum libusb_transfer_status status) switch (status) { case LIBUSB_TRANSFER_COMPLETED: - //fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_COMPLETED\n"); + //WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_COMPLETED"); break; case LIBUSB_TRANSFER_ERROR: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_ERROR\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_ERROR"); break; case LIBUSB_TRANSFER_TIMED_OUT: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_TIMED_OUT\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_TIMED_OUT"); break; case LIBUSB_TRANSFER_CANCELLED: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_CANCELLED\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_CANCELLED"); break; case LIBUSB_TRANSFER_STALL: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_STALL\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_STALL"); break; case LIBUSB_TRANSFER_NO_DEVICE: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_NO_DEVICE\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_NO_DEVICE"); break; case LIBUSB_TRANSFER_OVERFLOW: - fprintf(stderr, "Transfer Status: LIBUSB_TRANSFER_OVERFLOW\n"); + WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_OVERFLOW"); break; default: - fprintf(stderr, "Transfer Status: Get unknow error num %d (0x%x)\n", + WLog_ERR(TAG, "Transfer Status: Get unknow error num %d (0x%x)", status, status); } return 0; @@ -426,28 +426,28 @@ static void print_status(enum libusb_transfer_status status) switch (status) { case LIBUSB_TRANSFER_COMPLETED: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_COMPLETED\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_COMPLETED"); break; case LIBUSB_TRANSFER_ERROR: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_ERROR\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_ERROR"); break; case LIBUSB_TRANSFER_TIMED_OUT: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_TIMED_OUT\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_TIMED_OUT"); break; case LIBUSB_TRANSFER_CANCELLED: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_CANCELLED\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_CANCELLED"); break; case LIBUSB_TRANSFER_STALL: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_STALL\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_STALL"); break; case LIBUSB_TRANSFER_NO_DEVICE: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_NO_DEVICE\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_NO_DEVICE"); break; case LIBUSB_TRANSFER_OVERFLOW: - fprintf(stderr, "Transfer status: LIBUSB_TRANSFER_OVERFLOW\n"); + WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_OVERFLOW"); break; default: - fprintf(stderr, "Transfer status: unknow status %d(0x%x)\n", status, status); + WLog_ERR(TAG, "Transfer status: unknow status %d(0x%x)", status, status); break; } } @@ -484,7 +484,7 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) if (ret < 0) { - fprintf(stderr, "libusb_get_device_descriptor: ERROR!!\n"); + WLog_ERR(TAG, "libusb_get_device_descriptor: ERROR!!"); free(descriptor); return NULL; } @@ -510,7 +510,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb if (!udev) { - LLOGLN(0, ("%s: Can't create udev", __func__)); + WLog_ERR(TAG, "Can't create udev"); return -1; } @@ -563,7 +563,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb } pdev->port_number = atoi(p2); - LLOGLN(libusb_debug, (" Port: %d", pdev->port_number)); + WLog_DBG(TAG, " Port: %d", pdev->port_number); /* get device path */ p1 = (char*) sysfs_path; @@ -577,7 +577,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb memset(pdev->path, 0, 17); strcpy(pdev->path, p2); - LLOGLN(libusb_debug, (" DevPath: %s", pdev->path)); + WLog_DBG(TAG," DevPath: %s", pdev->path); /* query parent hub info */ dev = udev_device_get_parent(dev); @@ -587,7 +587,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb hub_found = 1; hub_bus = atoi(udev_device_get_property_value(dev,"BUSNUM")); hub_dev = atoi(udev_device_get_property_value(dev,"DEVNUM")); - LLOGLN(libusb_debug, (" Hub BUS/DEV: %d %d", hub_bus, hub_dev)); + WLog_DBG(TAG, " Hub BUS/DEV: %d %d", hub_bus, hub_dev); } udev_device_unref(dev); @@ -601,7 +601,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb if (!hub_found) { - LLOGLN(0, ("%s: hub was not found!", __func__)); + WLog_WARN(TAG,"hub was not found!"); return -1; } @@ -610,7 +610,7 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb if (libusb_dev == NULL) { - LLOGLN(0, ("%s: get hub libusb_dev fail!", __func__)); + WLog_DBG(TAG,"get hub libusb_dev fail!"); return -1; } @@ -618,11 +618,11 @@ static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_numb if (error < 0) { - LLOGLN(0, ("%s: libusb_open error!", __func__)); + WLog_DBG(TAG,"libusb_open error!"); return -1; } - LLOGLN(libusb_debug, ("%s: libusb_open success!", __func__)); + WLog_DBG(TAG,"libusb_open success!"); /* Success! */ return 0; @@ -654,8 +654,8 @@ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BY if (error < 0) { - fprintf(stderr, "%s: Set interface altsetting get error num %d\n", - __func__, error); + WLog_ERR(TAG, "Set interface altsetting get error num %d", + error); } } @@ -681,8 +681,8 @@ static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* id LibusbConfig = pdev->LibusbConfig; if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces) { - fprintf(stderr, "Select Configuration: Libusb NumberInterfaces(%d) is different " - "with MsConfig NumberInterfaces(%d)\n", + WLog_ERR(TAG, "Select Configuration: Libusb NumberInterfaces(%d) is different " + "with MsConfig NumberInterfaces(%d)", LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); } @@ -827,7 +827,7 @@ static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfiguratio ret = libusb_set_configuration(libusb_handle, bConfigurationValue); if (ret < 0){ - fprintf(stderr, "libusb_set_configuration: ERROR number %d!!\n", ret); + WLog_ERR(TAG, "libusb_set_configuration: ERROR number %d!!", ret); func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } @@ -835,7 +835,7 @@ static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfiguratio { ret = libusb_get_active_config_descriptor (libusb_dev, LibusbConfig); if (ret < 0){ - fprintf(stderr, "libusb_get_config_descriptor_by_value: ERROR number %d!!\n", ret); + WLog_ERR(TAG, "libusb_get_config_descriptor_by_value: ERROR number %d!!", ret); func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } @@ -885,7 +885,7 @@ static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId, *UsbdStatus = 0; /* if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - fprintf(stderr, "request_queue_unregister_request: not fount request 0x%x\n", RequestId); + WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId); */ return error; } @@ -918,8 +918,8 @@ static int libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType ret -= 2; if (ret <= 0 || ret < 4){ - LLOGLN(libusb_debug, ("libusb_get_string_descriptor: " - "ERROR num %d, iProduct: %d!", ret, devDescriptor->iProduct)); + WLog_DBG(TAG,"libusb_get_string_descriptor: " + "ERROR num %d, iProduct: %d!", ret, devDescriptor->iProduct); memcpy(Buffer, strDesc, strlen(strDesc)); Buffer[strlen(strDesc)] = '\0'; *BufferSize = (strlen((char *)Buffer)) * 2; @@ -947,7 +947,7 @@ static int libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType *BufferSize = (i*2); break; default: - LLOGLN(0, ("Query Text: unknown TextType %d", TextType)); + WLog_DBG(TAG,"Query Text: unknown TextType %d", TextType); break; } @@ -980,12 +980,12 @@ static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 Requ ms_string_desc, 0x12, Timeout); - //fprintf(stderr, "Get ms string: result number %d", error); + //WLog_ERR(TAG, "Get ms string: result number %d", error); if (error > 0) { BYTE bMS_Vendorcode; data_read_BYTE(ms_string_desc + 16, bMS_Vendorcode); - //fprintf(stderr, "bMS_Vendorcode:0x%x", bMS_Vendorcode); + //WLog_ERR(TAG, "bMS_Vendorcode:0x%x", bMS_Vendorcode); /** get os descriptor */ error = libusb_control_transfer(pdev->libusb_handle, LIBUSB_ENDPOINT_IN |LIBUSB_REQUEST_TYPE_VENDOR | Recipient, @@ -1004,7 +1004,7 @@ static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 Requ *UsbdStatus = USBD_STATUS_SUCCESS; /* if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - fprintf(stderr, "request_queue_unregister_request: not fount request 0x%x\n", RequestId); + WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId); */ return error; } @@ -1059,10 +1059,10 @@ static void libusb_udev_detach_kernel_driver(IUDEVICE* idev) for (i = 0; i < pdev->LibusbConfig->bNumInterfaces; i++) { err = libusb_kernel_driver_active(pdev->libusb_handle , i); - LLOGLN(libusb_debug, ("libusb_kernel_driver_active = %d\n", err)); + WLog_DBG(TAG,"libusb_kernel_driver_active = %d", err); if (err){ err = libusb_detach_kernel_driver(pdev->libusb_handle , i); - LLOGLN(libusb_debug, ("libusb_detach_kernel_driver = %d\n", err)); + WLog_DBG(TAG,"libusb_detach_kernel_driver = %d", err); } } @@ -1079,12 +1079,12 @@ static void libusb_udev_attach_kernel_driver(IUDEVICE* idev) { err = libusb_release_interface (pdev->libusb_handle, i); if (err < 0){ - LLOGLN(libusb_debug, ("libusb_release_interface: error num %d = %d", i, err)); + WLog_DBG(TAG,"libusb_release_interface: error num %d = %d", i, err); } if (err != LIBUSB_ERROR_NO_DEVICE) { err = libusb_attach_kernel_driver (pdev->libusb_handle , i); - LLOGLN(libusb_debug, ("libusb_attach_kernel_driver if%d = %d", i, err)); + WLog_DBG(TAG,"libusb_attach_kernel_driver if%d = %d", i, err); } } } @@ -1222,13 +1222,13 @@ static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStat if (ret < 0) { - LLOGLN(libusb_debug, ("libusb_control_transfer: error num %d", ret)); + WLog_DBG(TAG,"libusb_control_transfer: error num %d", ret); *BufferSize = 0; } else { - LLOGLN(libusb_debug, ("PORT STATUS:0x%02x%02x%02x%02x", - Buffer[3], Buffer[2], Buffer[1], Buffer[0])); + WLog_DBG(TAG,"PORT STATUS:0x%02x%02x%02x%02x", + Buffer[3], Buffer[2], Buffer[1], Buffer[0]); success = 1; } } @@ -1263,7 +1263,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 E if (iso_transfer == NULL) { - fprintf(stderr, "Error: libusb_alloc_transfer.\n"); + WLog_ERR(TAG, "Error: libusb_alloc_transfer."); status = -1; } @@ -1288,7 +1288,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 E if (submit < 0) { - LLOGLN(libusb_debug, ("Error: Failed to submit transfer (ret = %d).", submit)); + WLog_DBG(TAG,"Error: Failed to submit transfer (ret = %d).", submit); status = -1; func_set_usbd_status(pdev, UrbdStatus, ret); } @@ -1309,7 +1309,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 E } ret = handle_events_completed(NULL, &iso_user_data.completed); if (ret < 0) { - LLOGLN(libusb_debug, ("Error: libusb_handle_events (ret = %d).", ret)); + WLog_DBG(TAG,"Error: libusb_handle_events (ret = %d).", ret); status = -1; break; } @@ -1368,14 +1368,14 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 Request if (!ep_desc) { - fprintf(stderr, "func_get_ep_desc: endpoint 0x%x is not found!!\n", EndpointAddress); + WLog_ERR(TAG, "func_get_ep_desc: endpoint 0x%x is not found!!", EndpointAddress); return -1; } transfer_type = (ep_desc->bmAttributes) & 0x3; - LLOGLN(libusb_debug, ("urb_bulk_or_interrupt_transfer: ep:0x%x " + WLog_DBG(TAG,"urb_bulk_or_interrupt_transfer: ep:0x%x " "transfer_type %d flag:%d OutputBufferSize:0x%x", - EndpointAddress, transfer_type, TransferFlags, *BufferSize)); + EndpointAddress, transfer_type, TransferFlags, *BufferSize); switch (transfer_type) { @@ -1391,9 +1391,9 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 Request * request to wMaxPacketSize */ if (*BufferSize != (ep_desc->wMaxPacketSize)) { - LLOGLN(libusb_debug, ("Interrupt Transfer(%s): " + WLog_DBG(TAG,"Interrupt Transfer(%s): " "BufferSize is different than maxPacketsize(0x%x)", - ((transferDir)?"IN":"OUT"), ep_desc->wMaxPacketSize)); + ((transferDir)?"IN":"OUT"), ep_desc->wMaxPacketSize); if((*BufferSize) > (ep_desc->wMaxPacketSize) && transferDir == USBD_TRANSFER_DIRECTION_IN) (*BufferSize) = ep_desc->wMaxPacketSize; @@ -1402,8 +1402,8 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 Request break; default: - LLOGLN(0, ("urb_bulk_or_interrupt_transfer:" - " other transfer type 0x%X", transfer_type)); + WLog_DBG(TAG,"urb_bulk_or_interrupt_transfer:" + " other transfer type 0x%X", transfer_type); return -1; break; } @@ -1418,7 +1418,7 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 Request if (submit < 0) { - LLOGLN(libusb_debug, ("libusb_bulk_transfer: error num %d", status)); + WLog_DBG(TAG,"libusb_bulk_transfer: error num %d", status); func_set_usbd_status(pdev, UsbdStatus, status); *BufferSize = 0; } @@ -1489,12 +1489,12 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 Request *BufferSize = transfer->actual_length; } - LLOGLN(libusb_debug, ("bulk or interrupt Transfer data size : 0x%x", *BufferSize)); + WLog_DBG(TAG,"bulk or interrupt Transfer data size : 0x%x", *BufferSize); if (request) { if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - fprintf(stderr, "request_queue_unregister_request: not fount request 0x%x\n", RequestId); + WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId); } libusb_free_transfer(transfer); @@ -1528,7 +1528,7 @@ static void libusb_udev_cancel_all_transfer_request(IUDEVICE* idev) if (status < 0) { - LLOGLN(libusb_debug, ("libusb_cancel_transfer: error num %d!!\n", status)); + WLog_DBG(TAG,"libusb_cancel_transfer: error num %d!!", status); } else { @@ -1557,14 +1557,14 @@ static int func_cancel_xact_request(TRANSFER_REQUEST *request) if (status < 0) { - LLOGLN(0, ("libusb_cancel_transfer: error num %d!!", status)); + WLog_DBG(TAG,"libusb_cancel_transfer: error num %d!!", status); if (status == LIBUSB_ERROR_NOT_FOUND) return -1; } else { - LLOGLN(libusb_debug, ("libusb_cancel_transfer: Success num:0x%x!!", request->RequestId)); + WLog_DBG(TAG,"libusb_cancel_transfer: Success num:0x%x!!", request->RequestId); request->submit = -1; return 1; } @@ -1590,8 +1590,8 @@ cancel_retry: if (!request) continue; - LLOGLN(libusb_debug, ("%s: CancelId:0x%x RequestId:0x%x endpoint 0x%x!!", - __func__, RequestId, request->RequestId, request->endpoint)); + WLog_DBG(TAG,"CancelId:0x%x RequestId:0x%x endpoint 0x%x!!", + RequestId, request->RequestId, request->endpoint); if ((request && request->RequestId) == (RequestId && retry_times <= 10)) { @@ -1611,16 +1611,16 @@ cancel_retry: { retry_times++; usleep(100000); - LLOGLN(10, ("urbdrc_process_cancel_request: go retry!!")); + WLog_DBG(TAG,"urbdrc_process_cancel_request: go retry!!"); goto cancel_retry; } else if ((status < 0) || (retry_times >= 10)) { /** END */ - LLOGLN(libusb_debug, ("urbdrc_process_cancel_request: error go exit!!")); + WLog_DBG(TAG,"urbdrc_process_cancel_request: error go exit!!"); return -1; } - LLOGLN(libusb_debug, ("urbdrc_process_cancel_request: success!!")); + WLog_DBG(TAG,"urbdrc_process_cancel_request: success!!"); return 0; } @@ -1704,7 +1704,7 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) if (status < 0) { - fprintf(stderr, "USB init: Error to get HUB handle!!\n"); + WLog_ERR(TAG, "USB init: Error to get HUB handle!!"); pdev->hub_handle = NULL; } @@ -1712,7 +1712,7 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) if (!pdev->devDescriptor) { - fprintf(stderr, "USB init: Error to get device descriptor!!\n"); + WLog_ERR(TAG, "USB init: Error to get device descriptor!!"); zfree(pdev); return NULL; } @@ -1723,7 +1723,7 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) if (status < 0) { - fprintf(stderr, "libusb_get_descriptor: ERROR!!ret:%d\n", status); + WLog_ERR(TAG, "libusb_get_descriptor: ERROR!!ret:%d", status); zfree(pdev); return NULL; } @@ -1732,11 +1732,11 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) /* get the first interface and first altsetting */ interface_temp = config_temp->interface[0].altsetting[0]; - LLOGLN(0, ("Regist Device: Vid: 0x%04X Pid: 0x%04X" + WLog_DBG(TAG,"Regist Device: Vid: 0x%04X Pid: 0x%04X" " InterfaceClass = 0x%X", pdev->devDescriptor->idVendor, pdev->devDescriptor->idProduct, - interface_temp.bInterfaceClass)); + interface_temp.bInterfaceClass); /* Denied list */ switch(interface_temp.bInterfaceClass) @@ -1752,7 +1752,7 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) case CLASS_CONTENT_SECURITY: //case CLASS_WIRELESS_CONTROLLER: //case CLASS_ELSE_DEVICE: - fprintf(stderr, " Device is not supported!!\n"); + WLog_ERR(TAG, " Device is not supported!!"); zfree(pdev); return NULL; default: @@ -1818,7 +1818,7 @@ int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray) ssize_t total_device; int i, status, num = 0; - fprintf(stderr, "VID: 0x%04X PID: 0x%04X\n", idVendor, idProduct); + WLog_ERR(TAG, "VID: 0x%04X PID: 0x%04X", idVendor, idProduct); array = (UDEVICE**) malloc(16 * sizeof(UDEVICE*)); @@ -1839,7 +1839,7 @@ int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray) if (status < 0) { - fprintf(stderr, "libusb_open: (by id) error: 0x%08X (%d)\n", status, status); + WLog_ERR(TAG, "libusb_open: (by id) error: 0x%08X (%d)", status, status); zfree(descriptor); zfree(array[num]); continue; @@ -1868,7 +1868,7 @@ IUDEVICE* udev_new_by_addr(int bus_number, int dev_number) int status; UDEVICE* pDev; - LLOGLN(10, ("bus:%d dev:%d\n", bus_number, dev_number)); + WLog_DBG(TAG,"bus:%d dev:%d", bus_number, dev_number); pDev = (PUDEVICE) malloc(sizeof(UDEVICE)); @@ -1876,7 +1876,7 @@ IUDEVICE* udev_new_by_addr(int bus_number, int dev_number) if (pDev->libusb_dev == NULL) { - fprintf(stderr, "libusb_device_new: ERROR!!\n"); + WLog_ERR(TAG, "libusb_device_new: ERROR!!"); zfree(pDev); return NULL; } @@ -1885,7 +1885,7 @@ IUDEVICE* udev_new_by_addr(int bus_number, int dev_number) if (status < 0) { - fprintf(stderr, "libusb_open: (by addr) ERROR!!\n"); + WLog_ERR(TAG, "libusb_open: (by addr) ERROR!!"); zfree(pDev); return NULL; } diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index ebf5e4b5a..f8ce71503 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -116,9 +116,8 @@ static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number, } idevman->loading_unlock(idevman); - LLOGLN(libusb_debug, ("%s: bus:%d dev:%d not exist in udevman", - __func__, bus_number, dev_number)); - + WLog_WARN(TAG, "bus:%d dev:%d not exist in udevman", + bus_number, dev_number); return NULL; } @@ -206,7 +205,7 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n } else { - fprintf(stderr, "udevman_register_udevice: function error!!"); + WLog_ERR(TAG, "udevman_register_udevice: function error!!"); return 0; } @@ -270,9 +269,10 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev if (err != LIBUSB_ERROR_NO_DEVICE) { ret = libusb_reset_device(dev->libusb_handle); - if (ret<0){ - LLOGLN(10, ("libusb_reset_device: ERROR!!ret:%d\n", ret)); - } + if (ret<0) + { + WLog_ERR(TAG, "libusb_reset_device: ERROR!!ret:%d", ret); + } } /* release all interface and attach kernel driver */ @@ -390,8 +390,7 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbD return (IUDEVICE*) pdev; } - LLOGLN(libusb_debug, ("udevman_get_udevice_by_UsbDevice: 0x%x ERROR!!\n", UsbDevice)); - + WLog_ERR(TAG, "0x%x ERROR!!", UsbDevice); return NULL; } @@ -550,7 +549,7 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) CommandLineSwitchCase(arg, "dbg") { - urbdrc_debug = 0; + WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE); } CommandLineSwitchCase(arg, "dev") { diff --git a/channels/urbdrc/client/libusb/request_queue.c b/channels/urbdrc/client/libusb/request_queue.c index e5ebfef71..86035f1e4 100644 --- a/channels/urbdrc/client/libusb/request_queue.c +++ b/channels/urbdrc/client/libusb/request_queue.c @@ -100,7 +100,7 @@ TRANSFER_REQUEST* request_queue_get_request_by_endpoint(REQUEST_QUEUE* queue, BY } } pthread_mutex_unlock(&queue->request_loading); - fprintf(stderr, "request_queue_get_request_by_id: ERROR!!\n"); + WLog_ERR(TAG, "request_queue_get_request_by_id: ERROR!!"); return NULL; } diff --git a/channels/urbdrc/client/searchman.c b/channels/urbdrc/client/searchman.c index 18fc5b73e..e4b2b7d73 100644 --- a/channels/urbdrc/client/searchman.c +++ b/channels/urbdrc/client/searchman.c @@ -155,17 +155,17 @@ static void searchman_list_show(USB_SEARCHMAN* self) { int num = 0; USB_SEARCHDEV* usb; - - fprintf(stderr, "=========== Usb Search List ========= \n"); + WLog_DBG(TAG, "=========== Usb Search List ========="); self->rewind(self); while (self->has_next(self)) { usb = self->get_next(self); - fprintf(stderr, " USB %d: \n", num++); - fprintf(stderr, " idVendor: 0x%04X \n", usb->idVendor); - fprintf(stderr, " idProduct: 0x%04X \n", usb->idProduct); + WLog_DBG(TAG, " USB %d: ", num++); + WLog_DBG(TAG, " idVendor: 0x%04X", usb->idVendor); + WLog_DBG(TAG, " idProduct: 0x%04X", usb->idProduct); } - fprintf(stderr, "================= END =============== \n"); + + WLog_DBG(TAG, "================= END ==============="); } void searchman_free(USB_SEARCHMAN* self) @@ -202,7 +202,7 @@ USB_SEARCHMAN* searchman_new(void * urbdrc, UINT32 UsbDevice) if (ret != 0) { - fprintf(stderr, "searchman mutex initialization: searchman->mutex failed"); + WLog_ERR(TAG, "searchman mutex initialization: searchman->mutex failed"); exit(EXIT_FAILURE); } diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index e010bba10..e87966932 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -32,15 +32,14 @@ #include #include +#include #include "urbdrc_types.h" #include "urbdrc_main.h" #include "data_transfer.h" #include "searchman.h" -int urbdrc_debug = 0; - -static int func_hardware_id_format(IUDEVICE* pdev, char (*HardwareIds)[DEVICE_HARDWARE_ID_SIZE]) +static int func_hardware_id_format(IUDEVICE* pdev, char(*HardwareIds)[DEVICE_HARDWARE_ID_SIZE]) { char str[DEVICE_HARDWARE_ID_SIZE]; int idVendor, idProduct, bcdDevice; @@ -229,8 +228,7 @@ static int urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, UINT32 Version; UINT32 out_size; char * out_data; - - LLOGLN(10, ("urbdrc_process_capability_request")); + WLog_VRB(TAG, ""); data_read_UINT32(data + 0, Version); InterfaceId = ((STREAM_ID_NONE<<30) | CAPABILITIES_NEGOTIATOR); @@ -256,8 +254,7 @@ static int urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK* callback, char UINT32 MinorVersion; UINT32 Capabilities; char* out_data; - - LLOGLN(10, ("urbdrc_process_channel_create")); + WLog_VRB(TAG, ""); data_read_UINT32(data + 0, MajorVersion); data_read_UINT32(data + 4, MinorVersion); data_read_UINT32(data + 8, Capabilities); @@ -285,9 +282,7 @@ static int urdbrc_send_virtual_channel_add(IWTSVirtualChannel* channel, UINT32 M UINT32 out_size; UINT32 InterfaceId; char* out_data; - - LLOGLN(10, ("urdbrc_send_virtual_channel_add")); - + WLog_VRB(TAG, ""); assert(NULL != channel); assert(NULL != channel->Write); @@ -317,8 +312,7 @@ static int urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK* callback, IUDEVIC char strInstanceId[DEVICE_INSTANCE_STR_SIZE]; char* composite_str = "USB\\COMPOSITE"; int size, out_offset, cchCompatIds, bcdUSB; - - LLOGLN(10, ("urdbrc_send_usb_device_add")); + WLog_VRB(TAG, ""); InterfaceId = ((STREAM_ID_PROXY<<30) | CLIENT_DEVICE_SINK); /* USB kernel driver detach!! */ @@ -432,7 +426,7 @@ static int urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char* break; default: - LLOGLN(10, ("urbdrc_exchange_capabilities: unknown FunctionId 0x%X", FunctionId)); + WLog_ERR(TAG, "unknown FunctionId 0x%X", FunctionId); error = 1; break; } @@ -454,9 +448,7 @@ static void* urbdrc_search_usb_device(void* arg) int numobj, timeout; int busnum, devnum; int success = 0, error, on_close = 0, found = 0; - - LLOGLN(10, ("urbdrc_search_usb_device: ")); - + WLog_VRB(TAG, ""); channel_mgr = urbdrc->listener_callback->channel_mgr; /* init usb monitor */ @@ -468,7 +460,7 @@ static void* urbdrc_search_usb_device(void* arg) if (!udev) { - fprintf(stderr, "Can't create udev\n"); + WLog_ERR(TAG, "Can't create udev"); return 0; } @@ -483,7 +475,7 @@ static void* urbdrc_search_usb_device(void* arg) while (1) { - LLOGLN(10, ("======= SEARCH ======= ")); + WLog_VRB(TAG, "======= SEARCH ======= "); busnum = 0; devnum = 0; sdev = NULL; @@ -540,8 +532,8 @@ static void* urbdrc_search_usb_device(void* arg) if (sdev->idVendor == idVendor && sdev->idProduct == idProduct) { - LLOGLN(10, ("Searchman Find Device: %04x:%04x ", - sdev->idVendor, sdev->idProduct)); + WLog_VRB(TAG, "Searchman Find Device: %04x:%04x ", + sdev->idVendor, sdev->idProduct); found = 1; break; } @@ -549,8 +541,8 @@ static void* urbdrc_search_usb_device(void* arg) if (!found && udevman->isAutoAdd(udevman)) { - LLOGLN(10, ("Auto Find Device: %04x:%04x ", - idVendor, idProduct)); + WLog_VRB(TAG, "Auto Find Device: %04x:%04x ", + idVendor, idProduct); found = 2; } @@ -610,7 +602,7 @@ static void* urbdrc_search_usb_device(void* arg) if (dvc_channel == NULL) { - LLOGLN(0, ("SEARCH: dvc_channel %d is NULL!!", pdev->get_channel_id(pdev))); + WLog_ERR(TAG, "SEARCH: dvc_channel %d is NULL!!", pdev->get_channel_id(pdev)); func_close_udevice(searchman, pdev); break; } @@ -652,7 +644,7 @@ static void* urbdrc_search_usb_device(void* arg) } else { - fprintf(stderr, "No Device from receive_device(). An error occured.\n"); + WLog_ERR(TAG, "No Device from receive_device(). An error occured."); } } } @@ -732,8 +724,8 @@ void* urbdrc_new_device_create(void* arg) break; default: - LLOGLN(0, ("urbdrc_new_device_create: vchannel_status unknown value %d", - urbdrc->vchannel_status)); + WLog_ERR(TAG, "vchannel_status unknown value %d", + urbdrc->vchannel_status); break; } @@ -757,7 +749,7 @@ static int urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback break; case RIMCALL_RELEASE: - LLOGLN(10, ("urbdrc_process_channel_notification: recv RIMCALL_RELEASE")); + WLog_VRB(TAG, "recv RIMCALL_RELEASE"); pthread_t thread; TRANSFER_DATA* transfer_data; @@ -780,14 +772,14 @@ static int urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback break; default: - LLOGLN(10, ("urbdrc_process_channel_notification: unknown FunctionId 0x%X", FunctionId)); + WLog_VRB(TAG, "unknown FunctionId 0x%X", FunctionId); error = 1; break; } return error; } -static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* Buffer) +static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*) pChannelCallback; URBDRC_PLUGIN* urbdrc; @@ -796,7 +788,8 @@ static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 InterfaceId; UINT32 Mask; int error = 0; - char* pBuffer = (char*) Buffer; + char* pBuffer = (char*)Stream_Pointer(data); + UINT32 cbSize = Stream_GetRemainingLength(data); if (callback == NULL) return 0; @@ -814,7 +807,7 @@ static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, data_read_UINT32(pBuffer + 0, InterfaceTemp); InterfaceId = (InterfaceTemp & 0x0fffffff); Mask = ((InterfaceTemp & 0xf0000000)>>30); - LLOGLN(10, ("urbdrc_on_data_received: Size=%d InterfaceId=0x%X Mask=0x%X", cbSize, InterfaceId, Mask)); + WLog_VRB(TAG, "Size=%d InterfaceId=0x%X Mask=0x%X", cbSize, InterfaceId, Mask); switch (InterfaceId) { @@ -827,7 +820,7 @@ static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, break; default: - LLOGLN(10, ("urbdrc_on_data_received: InterfaceId 0x%X Start matching devices list", InterfaceId)); + WLog_VRB(TAG, "InterfaceId 0x%X Start matching devices list", InterfaceId); pthread_t thread; TRANSFER_DATA* transfer_data; @@ -835,7 +828,7 @@ static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (transfer_data == NULL) { - fprintf(stderr, "transfer_data is NULL!!"); + WLog_ERR(TAG, "transfer_data is NULL!!"); return 0; } @@ -859,7 +852,7 @@ static int urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, error = pthread_create(&thread, 0, urbdrc_process_udev_data_transfer, transfer_data); if (error < 0) - LLOGLN(0, ("Create Data Transfer Thread got error = %d", error)); + WLog_ERR(TAG, "Create Data Transfer Thread got error = %d", error); else pthread_detach(thread); @@ -880,9 +873,7 @@ static int urbdrc_on_close(IWTSVirtualChannelCallback * pChannelCallback) int found = 0; ChannelId = callback->channel_mgr->GetChannelId(callback->channel); - - LLOGLN(0, ("urbdrc_on_close: channel id %d", ChannelId)); - + WLog_INFO(TAG, "urbdrc_on_close: channel id %d", ChannelId); udevman->loading_lock(udevman); udevman->rewind(udevman); @@ -906,9 +897,7 @@ static int urbdrc_on_close(IWTSVirtualChannelCallback * pChannelCallback) } zfree(callback); - - LLOGLN(urbdrc_debug, ("urbdrc_on_close: success")); - + WLog_DBG(TAG, "success"); return 0; } @@ -917,8 +906,7 @@ static int urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallb { URBDRC_LISTENER_CALLBACK* listener_callback = (URBDRC_LISTENER_CALLBACK*) pListenerCallback; URBDRC_CHANNEL_CALLBACK* callback; - - LLOGLN(10, ("urbdrc_on_new_channel_connection:")); + WLog_VRB(TAG, ""); callback = (URBDRC_CHANNEL_CALLBACK*) malloc(sizeof(URBDRC_CHANNEL_CALLBACK)); callback->iface.OnDataReceived = urbdrc_on_data_received; callback->iface.OnClose = urbdrc_on_close; @@ -935,8 +923,7 @@ static int urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; IUDEVMAN* udevman = NULL; USB_SEARCHMAN* searchman = NULL; - - LLOGLN(10, ("urbdrc_plugin_initialize:")); + WLog_VRB(TAG, ""); urbdrc->listener_callback = (URBDRC_LISTENER_CALLBACK*) malloc(sizeof(URBDRC_LISTENER_CALLBACK)); memset(urbdrc->listener_callback, 0, sizeof(URBDRC_LISTENER_CALLBACK)); @@ -958,8 +945,7 @@ static int urbdrc_plugin_terminated(IWTSPlugin* pPlugin) URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; IUDEVMAN* udevman = urbdrc->udevman; USB_SEARCHMAN* searchman = urbdrc->searchman; - - LLOGLN(10, ("urbdrc_plugin_terminated:")); + WLog_VRB(TAG, ""); if (searchman) { @@ -1000,7 +986,7 @@ static void urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman if (urbdrc->udevman) { - DEBUG_WARN("existing device, abort."); + WLog_ERR(TAG, "existing device, abort."); return; } @@ -1025,7 +1011,7 @@ static int urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, const char* name, ADDI if (entry(&entryPoints) != 0) { - DEBUG_WARN("%s entry returns error.", name); + WLog_ERR(TAG, "%s entry returns error.", name); return FALSE; } @@ -1069,7 +1055,7 @@ static void urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) CommandLineSwitchCase(arg, "dbg") { - urbdrc_debug = 0; + WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE); } CommandLineSwitchCase(arg, "sys") { @@ -1110,8 +1096,6 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) urbdrc->searchman = NULL; urbdrc->vchannel_status = INIT_CHANNEL_IN; - urbdrc_debug = 10; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "urbdrc", (IWTSPlugin*) urbdrc); } diff --git a/channels/urbdrc/client/urbdrc_types.h b/channels/urbdrc/client/urbdrc_types.h index 3b83cee02..641478eea 100644 --- a/channels/urbdrc/client/urbdrc_types.h +++ b/channels/urbdrc/client/urbdrc_types.h @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -36,10 +36,11 @@ #include +#define TAG CHANNELS_TAG("urbdrc.client") #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif #define CAPABILITIES_NEGOTIATOR 0x00000000 @@ -316,10 +317,6 @@ enum device_descriptor_table #define MAX_URB_REQUSET_NUM 0x80 #define LOG_LEVEL 1 -#define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { printf _args ; } } while (0) -#define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { printf _args ; printf("\n"); } } while (0) #define dummy_wait_obj(void) do{ sleep(5); } while(0) #define dummy_wait_s_obj(_s) do{ sleep(_s); } while(0) @@ -333,6 +330,4 @@ enum device_descriptor_table _t = (_tp.tv_sec * 1000) + (_tp.tv_usec / 1000); \ } while (0) -extern int urbdrc_debug; - #endif /* __URBDRC_TYPES_H */ diff --git a/client/Android/CMakeLists.txt b/client/Android/CMakeLists.txt index 51521320a..33a84ec1b 100644 --- a/client/Android/CMakeLists.txt +++ b/client/Android/CMakeLists.txt @@ -62,10 +62,21 @@ else() endif() set(APPCOMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/appcompat_v7") -add_custom_target(copy_appcompat ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory ${ANDROID_SDK}/extras/android/support/v7/appcompat ${APPCOMPAT_DIR} - COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR} -) +set(supportdir "${ANDROID_SDK}/extras/android/support/v7/appcompat") +set(compatibilitydir "${ANDROID_SDK}/extras/android/compatibility/v7/appcompat") +if(EXISTS "${supportdir}" AND IS_DIRECTORY "${supportdir}") + add_custom_target(copy_appcompat ALL + COMMAND ${CMAKE_COMMAND} -E copy_directory "${supportdir}" ${APPCOMPAT_DIR} + COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR} + ) +elseif(EXISTS "${compatibilitydir}" AND IS_DIRECTORY "${compatibilitydir}") + add_custom_target(copy_appcompat ALL + COMMAND ${CMAKE_COMMAND} -E copy_directory "${compatibilitydir}" ${APPCOMPAT_DIR} + COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR} + ) +else() + message( FATAL_ERROR "${ANDROID_SDK}/extras/android/{support|compatibility}/v7/appcompat directory not found. Please install a recent version of Android Support Library, CMake will now exit." ) +endif() add_subdirectory(FreeRDPCore) add_subdirectory(aFreeRDP) diff --git a/client/Android/FreeRDPCore/AndroidManifest.xml.cmake b/client/Android/FreeRDPCore/AndroidManifest.xml.cmake index acad13f3f..1e50d7caf 100644 --- a/client/Android/FreeRDPCore/AndroidManifest.xml.cmake +++ b/client/Android/FreeRDPCore/AndroidManifest.xml.cmake @@ -25,6 +25,7 @@ android:xlargeScreens="true" /> @@ -65,7 +66,7 @@ android:windowSoftInputMode="stateHidden"> diff --git a/client/Android/FreeRDPCore/jni/CMakeLists.txt b/client/Android/FreeRDPCore/jni/CMakeLists.txt index 0ca2ff33b..2b704b79d 100644 --- a/client/Android/FreeRDPCore/jni/CMakeLists.txt +++ b/client/Android/FreeRDPCore/jni/CMakeLists.txt @@ -55,16 +55,7 @@ endif() add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dl) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} log) diff --git a/client/Android/FreeRDPCore/jni/android_cliprdr.c b/client/Android/FreeRDPCore/jni/android_cliprdr.c index f34014de5..12736e104 100644 --- a/client/Android/FreeRDPCore/jni/android_cliprdr.c +++ b/client/Android/FreeRDPCore/jni/android_cliprdr.c @@ -141,8 +141,8 @@ void android_cliprdr_init(freerdp* inst) cb->channels = inst->context->channels; cb->android_formats = (UINT32*)malloc(sizeof(UINT32) * 3); - cb->android_formats[0] = CB_FORMAT_TEXT; - cb->android_formats[1] = CB_FORMAT_UNICODETEXT; + cb->android_formats[0] = CF_TEXT; + cb->android_formats[1] = CF_UNICODETEXT; cb->android_formats[2] = CB_FORMAT_HTML; cb->android_num_formats = 3; @@ -381,21 +381,18 @@ static void android_cliprdr_process_cb_data_request_event(clipboardContext* cb, switch (event->format) { - case CB_FORMAT_RAW: - case CB_FORMAT_PNG: - case CB_FORMAT_JPEG: - case CB_FORMAT_GIF: - case CB_FORMAT_DIB: + case 0: + case CF_DIB: default: DEBUG_ANDROID("unsupported format %x\n", event->format); outbuf = NULL; break; - case CB_FORMAT_UNICODETEXT: + case CF_UNICODETEXT: outbuf = android_cliprdr_process_requested_unicodetext(cb->android_data, &size); break; - case CB_FORMAT_TEXT: + case CF_TEXT: outbuf = android_cliprdr_process_requested_text(cb->android_data, &size); break; @@ -436,21 +433,21 @@ static void android_cliprdr_process_cb_format_list_event(clipboardContext* cb, R if (cb->formats) free(cb->formats); - cb->data_format = CB_FORMAT_RAW; + cb->data_format = 0; cb->formats = event->formats; cb->num_formats = event->num_formats; event->formats = NULL; event->num_formats = 0; - if (android_cliprdr_has_format(cb->formats, cb->num_formats, CB_FORMAT_TEXT)) + if (android_cliprdr_has_format(cb->formats, cb->num_formats, CF_TEXT)) { - cb->data_format = CB_FORMAT_TEXT; - android_cliprdr_send_data_request(cb, CB_FORMAT_TEXT); + cb->data_format = CF_TEXT; + android_cliprdr_send_data_request(cb, CF_TEXT); } - else if (android_cliprdr_has_format(cb->formats, cb->num_formats, CB_FORMAT_UNICODETEXT)) + else if (android_cliprdr_has_format(cb->formats, cb->num_formats, CF_UNICODETEXT)) { - cb->data_format = CB_FORMAT_UNICODETEXT; - android_cliprdr_send_data_request(cb, CB_FORMAT_UNICODETEXT); + cb->data_format = CF_UNICODETEXT; + android_cliprdr_send_data_request(cb, CF_UNICODETEXT); } else if (android_cliprdr_has_format(cb->formats, cb->num_formats, CB_FORMAT_HTML)) { @@ -518,20 +515,17 @@ static void android_cliprdr_process_cb_data_response_event(clipboardContext* cb, } switch (cb->data_format) { - case CB_FORMAT_RAW: - case CB_FORMAT_PNG: - case CB_FORMAT_JPEG: - case CB_FORMAT_GIF: - case CB_FORMAT_DIB: + case 0: + case CF_DIB: default: DEBUG_ANDROID("unsupported format\n"); break; - case CB_FORMAT_TEXT: + case CF_TEXT: android_cliprdr_process_text(cb, event->data, event->size - 1); break; - case CB_FORMAT_UNICODETEXT: + case CF_UNICODETEXT: android_cliprdr_process_unicodetext(cb, event->data, event->size - 2); break; diff --git a/client/Android/FreeRDPCore/jni/android_debug.h b/client/Android/FreeRDPCore/jni/android_debug.h index 3a0f34fc6..b48e7f469 100644 --- a/client/Android/FreeRDPCore/jni/android_debug.h +++ b/client/Android/FreeRDPCore/jni/android_debug.h @@ -16,12 +16,13 @@ #include "config.h" #endif -#include +#include +#define ANDROID_TAG CLIENT_TAG("android") #ifdef WITH_DEBUG_ANDROID_JNI -#define DEBUG_ANDROID(fmt, ...) DEBUG_CLASS(JNI, fmt, ## __VA_ARGS__) +#define DEBUG_ANDROID(fmt, ...) WLog_DBG(ANDROID_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_ANDROID(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_ANDROID(fmt, ...) do { } while (0) #endif diff --git a/client/Android/FreeRDPCore/jni/android_event.c b/client/Android/FreeRDPCore/jni/android_event.c index 952c5a415..15452fae9 100644 --- a/client/Android/FreeRDPCore/jni/android_event.c +++ b/client/Android/FreeRDPCore/jni/android_event.c @@ -20,6 +20,9 @@ #include #include #include +#include + +#define TAG CLIENT_TAG("android") #ifdef HAVE_UNISTD_H #include @@ -49,7 +52,7 @@ void android_set_event(ANDROID_EVENT_QUEUE * queue) length = write(queue->pipe_fd[1], "sig", 4); if (length != 4) - printf("android_set_event: error\n"); + WLog_ERR(TAG, "android_set_event: error"); } @@ -62,7 +65,7 @@ void android_clear_event(ANDROID_EVENT_QUEUE * queue) length = read(queue->pipe_fd[0], &length, 4); if (length != 4) - printf("android_clear_event: error\n"); + WLog_ERR(TAG, "android_clear_event: error"); } } @@ -306,7 +309,7 @@ void android_event_queue_init(freerdp * inst) aCtx->event_queue->events = (ANDROID_EVENT**) malloc(sizeof(ANDROID_EVENT*) * aCtx->event_queue->size); if (pipe(aCtx->event_queue->pipe_fd) < 0) - printf("android_pre_connect: pipe failed\n"); + WLog_ERR(TAG, "android_pre_connect: pipe failed"); } void android_event_queue_uninit(freerdp * inst) diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.c b/client/Android/FreeRDPCore/jni/android_freerdp.c index 5f75ce40e..4d75b5236 100644 --- a/client/Android/FreeRDPCore/jni/android_freerdp.c +++ b/client/Android/FreeRDPCore/jni/android_freerdp.c @@ -141,6 +141,7 @@ BOOL android_pre_connect(freerdp* instance) static BOOL android_post_connect(freerdp* instance) { + UINT32 gdi_flags; rdpSettings *settings = instance->settings; DEBUG_ANDROID("android_post_connect"); @@ -154,9 +155,12 @@ static BOOL android_post_connect(freerdp* instance) instance->context->cache = cache_new(settings); - gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | - ((instance->settings->ColorDepth > 16) ? CLRBUF_32BPP : CLRBUF_16BPP), - NULL); + if (instance->settings->ColorDepth > 16) + gdi_flags = CLRBUF_32BPP | CLRCONV_ALPHA | CLRCONV_INVERT; + else + gdi_flags = CLRBUF_16BPP; + + gdi_init(instance, gdi_flags, NULL); instance->update->BeginPaint = android_begin_paint; instance->update->EndPaint = android_end_paint; @@ -270,40 +274,6 @@ static void android_process_channel_event(rdpChannels* channels, freerdp* instan } } -static void *jni_update_thread(void *arg) -{ - int status; - wMessage message; - wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; - - assert( NULL != instance); - - DEBUG_ANDROID("Start."); - - status = 1; - queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - - while (MessageQueue_Wait(queue)) - { - while (MessageQueue_Peek(queue, &message, TRUE)) - { - status = freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message); - - if (!status) - break; - } - - if (!status) - break; - } - - DEBUG_ANDROID("Quit."); - - ExitThread(0); - return NULL; -} - static void* jni_input_thread(void* arg) { HANDLE event[3]; @@ -394,11 +364,9 @@ static int android_freerdp_run(freerdp* instance) const rdpSettings* settings = instance->context->settings; - HANDLE update_thread; HANDLE input_thread; HANDLE channels_thread; - BOOL async_update = settings->AsyncUpdate; BOOL async_input = settings->AsyncInput; BOOL async_channels = settings->AsyncChannels; BOOL async_transport = settings->AsyncTransport; @@ -417,12 +385,6 @@ static int android_freerdp_run(freerdp* instance) return 0; } - if (async_update) - { - update_thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) jni_update_thread, instance, 0, NULL); - } - if (async_input) { input_thread = CreateThread(NULL, 0, @@ -571,15 +533,7 @@ static int android_freerdp_run(freerdp* instance) WaitForSingleObject(channels_thread, INFINITE); CloseHandle(channels_thread); } - - if (async_update) - { - wMessageQueue* update_queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - MessageQueue_PostQuit(update_queue, 0); - WaitForSingleObject(update_thread, INFINITE); - CloseHandle(update_thread); - } - + if (async_input) { wMessageQueue* input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -836,44 +790,15 @@ JNIEXPORT void JNICALL jni_freerdp_set_performance_flags( } /* store performance settings */ - if (disableWallpaper == JNI_TRUE) - settings->DisableWallpaper = TRUE; - - if (disableFullWindowDrag == JNI_TRUE) - settings->DisableFullWindowDrag = TRUE; - - if (disableMenuAnimations == JNI_TRUE) - settings->DisableMenuAnims = TRUE; - - if (disableTheming == JNI_TRUE) - settings->DisableThemes = TRUE; - - if (enableFontSmoothing == JNI_TRUE) - settings->AllowFontSmoothing = TRUE; - - if(enableDesktopComposition == JNI_TRUE) - settings->AllowDesktopComposition = TRUE; - + settings->DisableWallpaper = (disableWallpaper == JNI_TRUE) ? TRUE : FALSE; + settings->DisableFullWindowDrag = (disableFullWindowDrag == JNI_TRUE) ? TRUE : FALSE; + settings->DisableMenuAnims = (disableMenuAnimations == JNI_TRUE) ? TRUE : FALSE; + settings->DisableThemes = (disableTheming == JNI_TRUE) ? TRUE : FALSE; + settings->AllowFontSmoothing = (enableFontSmoothing == JNI_TRUE) ? TRUE : FALSE; + settings->AllowDesktopComposition = (enableDesktopComposition == JNI_TRUE) ? TRUE : FALSE; /* Create performance flags from settings */ - settings->PerformanceFlags = PERF_FLAG_NONE; - if (settings->AllowFontSmoothing) - settings->PerformanceFlags |= PERF_ENABLE_FONT_SMOOTHING; - - if (settings->AllowDesktopComposition) - settings->PerformanceFlags |= PERF_ENABLE_DESKTOP_COMPOSITION; - - if (settings->DisableWallpaper) - settings->PerformanceFlags |= PERF_DISABLE_WALLPAPER; - - if (settings->DisableFullWindowDrag) - settings->PerformanceFlags |= PERF_DISABLE_FULLWINDOWDRAG; - - if (settings->DisableMenuAnims) - settings->PerformanceFlags |= PERF_DISABLE_MENUANIMATIONS; - - if (settings->DisableThemes) - settings->PerformanceFlags |= PERF_DISABLE_THEMING; + freerdp_performance_flags_make(settings); DEBUG_ANDROID("performance_flags: %04X", settings->PerformanceFlags); } @@ -1014,7 +939,7 @@ JNIEXPORT void JNICALL jni_freerdp_set_gateway_info(JNIEnv *env, jclass cls, jin static void copy_pixel_buffer(UINT8* dstBuf, UINT8* srcBuf, int x, int y, int width, int height, int wBuf, int hBuf, int bpp) { - int i, j; + int i; int length; int scanline; UINT8 *dstp, *srcp; @@ -1025,31 +950,11 @@ static void copy_pixel_buffer(UINT8* dstBuf, UINT8* srcBuf, int x, int y, int wi srcp = (UINT8*) &srcBuf[(scanline * y) + (x * bpp)]; dstp = (UINT8*) &dstBuf[(scanline * y) + (x * bpp)]; - if (bpp == 4) + for (i = 0; i < height; i++) { - for (i = 0; i < height; i++) - { - for (j = 0; j < width * 4; j += 4) - { - // ARGB <-> ABGR - dstp[j + 0] = srcp[j + 2]; - dstp[j + 1] = srcp[j + 1]; - dstp[j + 2] = srcp[j + 0]; - dstp[j + 3] = srcp[j + 3]; - } - - srcp += scanline; - dstp += scanline; - } - } - else - { - for (i = 0; i < height; i++) - { - memcpy(dstp, srcp, length); - srcp += scanline; - dstp += scanline; - } + memcpy(dstp, srcp, length); + srcp += scanline; + dstp += scanline; } } diff --git a/client/Android/FreeRDPCore/jni/android_jni_callback.c b/client/Android/FreeRDPCore/jni/android_jni_callback.c index eac97e5fa..b8fa5dc17 100644 --- a/client/Android/FreeRDPCore/jni/android_jni_callback.c +++ b/client/Android/FreeRDPCore/jni/android_jni_callback.c @@ -18,7 +18,10 @@ #include "android_debug.h" #include "android_freerdp_jni.h" -JavaVM *jVM; +#include +#define TAG CLIENT_TAG("android") + +JavaVM* jVM; jobject jLibFreeRDPObject; const char *jLibFreeRDPPath = JAVA_LIBFREERDP_CLASS; @@ -35,7 +38,7 @@ void jni_load_class(JNIEnv *env, const char *path, jobject *objptr) if (!class) { - DEBUG_WARN("jni_load_class: failed to find class %s", path); + WLog_ERR(TAG, "jni_load_class: failed to find class %s", path); goto finish; } @@ -43,7 +46,7 @@ void jni_load_class(JNIEnv *env, const char *path, jobject *objptr) if (!method) { - DEBUG_WARN("jni_load_class: failed to find class constructor of %s", path); + WLog_ERR(TAG, "jni_load_class: failed to find class constructor of %s", path); goto finish; } @@ -51,7 +54,7 @@ void jni_load_class(JNIEnv *env, const char *path, jobject *objptr) if (!object) { - DEBUG_WARN("jni_load_class: failed create new object of %s", path); + WLog_ERR(TAG, "jni_load_class: failed create new object of %s", path); goto finish; } @@ -66,7 +69,7 @@ jint init_callback_environment(JavaVM* vm) JNIEnv* env; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { - DEBUG_WARN("JNI_OnLoad: failed to obtain current JNI environment"); + WLog_ERR(TAG, "JNI_OnLoad: failed to obtain current JNI environment"); return -1; } @@ -88,7 +91,7 @@ jboolean jni_attach_thread(JNIEnv** env) if ((*jVM)->GetEnv(jVM, (void**) env, JNI_VERSION_1_4) != JNI_OK) { - DEBUG_WARN("android_java_callback: failed to obtain current JNI environment"); + WLog_ERR(TAG, "android_java_callback: failed to obtain current JNI environment"); } return JNI_TRUE; @@ -117,15 +120,17 @@ void java_callback_void(jobject obj, const char * callback, const char* signatur jObjClass = (*env)->GetObjectClass(env, obj); - if (!jObjClass) { - DEBUG_WARN("android_java_callback: failed to get class reference"); + if (!jObjClass) + { + WLog_ERR(TAG, "android_java_callback: failed to get class reference"); goto finish; } jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature); - if (!jCallback) { - DEBUG_WARN("android_java_callback: failed to get method id"); + if (!jCallback) + { + WLog_ERR(TAG, "android_java_callback: failed to get method id"); goto finish; } @@ -151,15 +156,17 @@ jboolean java_callback_bool(jobject obj, const char * callback, const char* sign jObjClass = (*env)->GetObjectClass(env, obj); - if (!jObjClass) { - DEBUG_WARN("android_java_callback: failed to get class reference"); + if (!jObjClass) + { + WLog_ERR(TAG, "android_java_callback: failed to get class reference"); goto finish; } jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature); - if (!jCallback) { - DEBUG_WARN("android_java_callback: failed to get method id"); + if (!jCallback) + { + WLog_ERR(TAG, "android_java_callback: failed to get method id"); goto finish; } diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png index 6e028b20b..19104c8e9 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png index 90db01b5b..ae185579e 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png index 0a91eabcc..2283a9194 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png index 45ed86123..ff31f2576 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png index 6b3f7fd15..43cf97ccf 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png index 7b0dfc5e1..46b50d6ed 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png index 4683f6193..82d41702e 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png index 172ae5f3d..192c57bb3 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png index 53319e291..2ed035200 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png index a5b4a2f60..8ba27516d 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png index 039c72174..d6ea16c37 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png index c08e64f91..8dcef3e76 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png index 5b14130e3..3d824d30a 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png index 3f5142012..121b545a1 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png index 4be0f5df2..eeebc098a 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png index 421305087..e6fef76f2 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png b/client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png index 32c6dc370..8ab6ad770 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png old mode 100755 new mode 100644 index 59d78bec0..104c1b922 Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png old mode 100755 new mode 100644 index ca7637552..a6d87337d Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png old mode 100755 new mode 100644 index ae57299e4..19b33da5f Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png old mode 100755 new mode 100644 index 58505c5e0..cf2b963ea Binary files a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png and b/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png index 7afaeded1..312f5f9f4 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png index bdefbf5c6..421c3e88c 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png index b57651bed..49726f4f0 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png index 55c57d5c5..d0c26e223 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png index 89620af8c..2eaa36966 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png index 606cce4a7..99c1ad45c 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png index 760b9254d..90a813e0f 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png index 425d904ca..02aeed3ca 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png index f93a4e640..5e4e17a6d 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png index efc2f3e45..34beda8b2 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png index b137b8c6e..61a2fdd3a 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png index 49837f290..2fb688787 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png index 4e3b7d7a6..066ce3f63 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png index f0f1eb845..b0dce0e66 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png index cf5ed353b..b09dec7ae 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png b/client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png index 2fa21299f..834763550 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png index d9d565391..07f95d5dc 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png index 8922bf92c..064a2c298 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png index c5f324752..7e7b3de27 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png index 1c7c58d5d..1d8a4eac0 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png and b/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png index af637b3be..33c42e0eb 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png index 90db01b5b..ae185579e 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png index 3f8913e2a..60112c109 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png index 55335c869..6b18c0ae3 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png index 1f8a7cd47..04442c8e4 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png index 57a4099bb..014ad5927 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png index c1aa860da..9a78d64ce 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png index 04a76b589..7213223f8 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png index 9ae25ff2e..f8a055bba 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png index 4f65a619d..36041a529 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png index 2f34c7695..3a297aaa7 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png index a96bb0c4c..f78c41f96 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png index bcd3eba42..a7d5585ae 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png index e37e1dbbe..b76585af8 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png old mode 100755 new mode 100644 index 7e9342b5c..f2cafb532 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png old mode 100755 new mode 100644 index a9bdb052a..f203ce2a7 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png b/client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png index 1cad9020d..144481cb1 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png index 43a033ead..98a2bc2ca 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png index 1edb10b4e..617d4e96e 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png index 03d9c9b2d..af0fea3f5 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png index 17f257439..27e26fcbb 100644 Binary files a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png and b/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png b/client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png index 606cce4a7..99c1ad45c 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png and b/client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png b/client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png index ad325d46e..53c5b36e1 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png and b/client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png old mode 100755 new mode 100644 index 3ad31caba..ec6959cbe Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png old mode 100755 new mode 100644 index 3e9168240..53dc89293 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png old mode 100755 new mode 100644 index 9039b78e9..331fea5dc Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png old mode 100755 new mode 100644 index c01ef09ed..a17bcd78c Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png old mode 100755 new mode 100644 index 471e42171..0e67f890e Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png old mode 100755 new mode 100644 index b43956dd5..afc2b5cbd Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png old mode 100755 new mode 100644 index c92d6f225..b296f3339 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png old mode 100755 new mode 100644 index a24081b1c..fe5c072d8 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png old mode 100755 new mode 100644 index c82f696a6..d44ae11ab Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png old mode 100755 new mode 100644 index 19208ec0f..25c011b06 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png old mode 100755 new mode 100644 index ca187b5ca..ca62134a1 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png old mode 100755 new mode 100644 index 4240b5928..96577f487 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png old mode 100755 new mode 100644 index 6196b7246..8abbd6c32 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png old mode 100755 new mode 100644 index 8173d5c9c..778ad4fa6 Binary files a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png and b/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png old mode 100755 new mode 100644 index 9f91b2465..ac498e470 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png index 273e21114..98f9f5a33 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png index c82bdea37..f1fff6d4c 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png index cd58c87ee..08880bb5f 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png index f0a7afa93..90f2b1b9e 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png index 2129a1f33..dcb690489 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png index 3c1289474..b34b02e79 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png differ diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png b/client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png index b6205da61..c5275a4ce 100644 Binary files a/client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png and b/client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png differ diff --git a/client/Android/FreeRDPCore/res/layout/home.xml b/client/Android/FreeRDPCore/res/layout/home.xml index b31e565d6..bc311f573 100644 --- a/client/Android/FreeRDPCore/res/layout/home.xml +++ b/client/Android/FreeRDPCore/res/layout/home.xml @@ -1,5 +1,5 @@ - +--> + android:layout_width="match_parent" + android:layout_height="match_parent" > - - + - + + + + android:dividerHeight="1dp" /> - - - + \ No newline at end of file diff --git a/client/Android/FreeRDPCore/res/values-de/strings.xml b/client/Android/FreeRDPCore/res/values-de/strings.xml new file mode 100644 index 000000000..a9aa621f1 --- /dev/null +++ b/client/Android/FreeRDPCore/res/values-de/strings.xml @@ -0,0 +1,199 @@ + + + + Ja + Nein + Abbrechen + Fortfahren + Login + Logout + + Beenden + Impressum + Hilfe + Neue Verbindung + Einstellungen + + Verbindung + Verbinden + Edit + Löschen + + Tastatur + Funktionstasten + Touch Pointer + home + Verbindung trennen + + Manuelle Verbindungen + Aktive Sitzungen + + Mit Computer verbinden + + Login + Keine Server + Verbinde … + Trenne Verbundung … + Verbindung unterbrochen + Falsches Passwort + Ungültiger Benutzername + Verbindung hinzufügen + + Host + Label + Host + Port + Zugangsdaten + Zugangsdaten + Benutzername + Passwort + Domäne + Einstellungen + Bildschirm + Bildschirm Einstellungen + Farben + + High Color (16 Bit) + True Color (24 Bit) + Highest Quality (32 Bit) + + + 16 + 24 + 32 + + Auflösung + automatisch + an Bildschirm anpassen + Benutzerdefiniert + + automatisch + an Bildschirm anpassen + Benutzerdefiniert + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + + automatisch + an Bildschirm anpassen + Benutzerdefiniert + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + Breite + Höhe + Leistung + Leistungseinstellungen + RemoteFX + Desktop Hintergrund + Kantenglättung + Desktop Composition + Zeige Fensterinhalt während + Menü Animation + Visuelle Stile + Erweitert + Erweiterte Einstellungen + 3G Einstellungen + 3G Bildschirm + 3G Leistung + Gateway + Aktiviere Gateway + Gateway Einstellungen + SDCard umleiten + Ton umleiten + + Nicht abspielen + Auf Server abspielen + Auf Client abspielen + + + 0 + 1 + 2 + + Mikrophon umleiten + Sicherheit + + Automatisch + RDP + TLS + NLA + + + 0 + 1 + 2 + 3 + + Remote Program + Arbeitsverzeichnis + Async channel + Async transport + Async input + Async update + Konsolenmodus + + ******* + nicht gesetzt + Benutzeroberfläche + verstecke Statusleiste + verstecke Zoom Tasten + Vertausche Maustasten + Invertiere Bildlauf + Touch Zeiger automatischer Bildlauf + Zeige Dialog beim Beenden + Energiesparen + Schließe ungenutzte Verbindungen + Sicherheit + Akzeptiere alle Zertifikate + Lösche Zertifikat Cache + Nach %1$d Minuten + Deaktiviert + + Verbindungseinstellungen + Einstellungen + aFreeRDP - FreeRDP für Android + RDP Verbindungen + Hilfe + Impressum + + Verlassen ohne zu speichern? + Abbrechen um Einstellungen zu verwerfen\nFortfahren um weiter zu editieren + Konnte keine Verbindung zum Server herstellen! + + Die Bildschirmeinstellungen mussten angepasst werden, da der Server die gewählten nicht unterstützt! + Lösche Zertifikatcache! + Konnte Zertifikatcache nicht löschen! + + Prüfe Zertifikat + Die Identität des Servers konnte nicht geprüft werden. Trotzdem verbinden? + Bitte geben sie ihre Zugangsdaten ein: + Verknüpfung erzeugen + Verknüpfungsname: + Verbinden … + Einloggen … + Ãœber aFreeRDP + Verbindungseinstellungen speichern? + Die Verbindungseinstellungen wurden nicht gespeichert! Jetzt speichern? + Verbindung speichern? + Wollen sie alle Änderungen der Verbindungseinstelleungen speichern? + Nicht noch einmal nachfragen + Anwendung beenden? + Wollen sie die Anwendung wirklich beenden? + Lösche Zertifikate? + Wollen sie wirklich alle gespeicherten Zertifikate löschen? + Debug Stufe + Debug Einstellungen + diff --git a/client/Android/FreeRDPCore/res/values/theme.xml b/client/Android/FreeRDPCore/res/values/theme.xml index afee509ac..5457b1991 100644 --- a/client/Android/FreeRDPCore/res/values/theme.xml +++ b/client/Android/FreeRDPCore/res/values/theme.xml @@ -1,10 +1,10 @@ - - + + + + + + +
+ + +
+

aFreeRDP
Remote Desktop Client

+
+

+

+
+ + aFreeRDP ist ein Open Source Programm + mit nativer Unterstützung des Remote Desktop Protocol (RDP) um einen entfernten Zugriff auf Windows Desktops zu ermöglichen.
+ + +
+

Versions Information

+

+ + + + + +
aFreeRDP Version %1$s
System Version %2$s
Model %3$s
+

+
+
+ +
+

Credits

+
+ + aFreeRDP ist ein Teil von FreeRDP + +
+ +
+
+

Lizenz

+
+ + This program is free software; you can redistribute it and/or modify it under the terms of the Mozilla Public License, v. 2.0. + You can obtain an online version of the License from http://mozilla.org/MPL/2.0/. +

+

+ 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. +

+

+ A copy of the product's source code can be obtained from the FreeRDP GitHub repository at https://github.com/FreeRDP/FreeRDP.
+

+
+ + diff --git a/client/Android/aFreeRDP/assets/de_about_page/about_phone.html b/client/Android/aFreeRDP/assets/de_about_page/about_phone.html new file mode 100644 index 000000000..f3e6b8a51 --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_about_page/about_phone.html @@ -0,0 +1,201 @@ + + + + + + + + + + + + + +
+ + +
+

aFreeRDP
Remote Desktop Client

+
+

+

+
+ + aFreeRDP ist ein Open Source Programm + mit nativer Unterstützung des Remote Desktop Protocol (RDP) um einen entfernten Zugriff auf Windows Desktops zu ermöglichen.
+ + +
+

Versions Information

+

+ + + + + +
aFreeRDP Version %1$s
System Version %2$s
Model %3$s
+

+
+
+ +
+

Credits

+
+ aFreeRDP ist ein Teil von FreeRDP +
+
+
+

Lizenz

+
+ + This program is free software; you can redistribute it and/or modify it under the terms of the Mozilla Public License, v. 2.0. + You can obtain an online version of the License from http://mozilla.org/MPL/2.0/. +

+

+ 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. +

+

+ A copy of the product's source code can be obtained from the FreeRDP GitHub repository at https://github.com/FreeRDP/FreeRDP.
+

+
+ + diff --git a/client/Android/aFreeRDP/assets/de_about_page/background_transparent.png b/client/Android/aFreeRDP/assets/de_about_page/background_transparent.png new file mode 100644 index 000000000..d9d377bdf Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_about_page/background_transparent.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures.html b/client/Android/aFreeRDP/assets/de_help_page/gestures.html new file mode 100644 index 000000000..7eb82cf5b --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/gestures.html @@ -0,0 +1,159 @@ + + + + + + + +Help + + + + + + + + +
+
+ + +
+

Gesten

+

+aFreeRDP ist für Touch Geräte entwickelt worden. +Diese Gesten lassen sie die häufigsten Operationen mit ihren Fingern durchführen.

+

+ +
+
+ + + diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures.png b/client/Android/aFreeRDP/assets/de_help_page/gestures.png new file mode 100644 index 000000000..78b3e7b34 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/gestures.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.html b/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.html new file mode 100644 index 000000000..8d5b2b9e8 --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.html @@ -0,0 +1,159 @@ + + + + + + + +Help + + + + + + + + + + + +
+
+ + +
+

Gesten

+

+aFreeRDP ist für Touch Geräte entwickelt worden. +Diese Gesten lassen sie die häufigsten Operationen mit ihren Fingern durchführen.

+

+ + +
+
+ + + diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.png b/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.png new file mode 100644 index 000000000..4eea33ef4 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_gestures.png b/client/Android/aFreeRDP/assets/de_help_page/nav_gestures.png new file mode 100644 index 000000000..50bfaa232 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/nav_gestures.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_toolbar.png b/client/Android/aFreeRDP/assets/de_help_page/nav_toolbar.png new file mode 100644 index 000000000..f66b24d21 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/nav_toolbar.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_touch_pointer.png b/client/Android/aFreeRDP/assets/de_help_page/nav_touch_pointer.png new file mode 100644 index 000000000..930fc9cbf Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/nav_touch_pointer.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar.html b/client/Android/aFreeRDP/assets/de_help_page/toolbar.html new file mode 100644 index 000000000..20c9e71f2 --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/toolbar.html @@ -0,0 +1,178 @@ + + + + + + + +Help + + + + + + + + + + + +
+ + +
+ + + + +
+ +

Toolbar

+

+With the toolbar you'll be able to display and hide the main tools in your session. This allows together with the touch pointer and the gestures an intuitiv workflow for remote computing on touch sensitive screens. +

+

+ +
+
+

Tastatur

+Zeige/verstecke die standard und die erweiterte Tastatur mit Funktionstasten
+
+

Touch Zeiger

+Zeige/verstecke den gesten gesteuerten Zeiger
+
+

Beenden

+Beende die aktuelle Sitzung. Seihen sie sich bewusst, dass das Beenden kein Logout ist.
+ +
+ + +
+ + diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar.png b/client/Android/aFreeRDP/assets/de_help_page/toolbar.png new file mode 100644 index 000000000..42f055b9f Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/toolbar.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.html b/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.html new file mode 100644 index 000000000..aded46e2b --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.html @@ -0,0 +1,176 @@ + + + + + + + +Help + + + + + + + + + + + +
+ + +
+ + + + +
+ +

Toolbar

+

+With the toolbar you'll be able to display and hide the main tools in your session. This allows together with the touch pointer and the gestures an intuitiv workflow for remote computing on touch sensitive screens. +

+

+ +
+
+

Tastatur

+Zeige/verstecke die standard und die erweiterte Tastatur mit Funktionstasten
+
+

Touch Zeiger

+Zeige/verstecke den gesten gesteuerten Zeiger
+
+

Beenden

+Beende die aktuelle Sitzung. Seihen sie sich bewusst, dass das Beenden kein Logout ist. + +
+ + +
+ + diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.png b/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.png new file mode 100644 index 000000000..278cd3a9d Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.html b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.html new file mode 100644 index 000000000..939f92637 --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.html @@ -0,0 +1,164 @@ + + + + + + + +Help + + + + + + + + + + + +
+ + +
+ + + + +
+ +

Touch Pointer

+

+

+ +
+
+ + + diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.png b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.png new file mode 100644 index 000000000..af3ebcab0 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.png differ diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.html b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.html new file mode 100644 index 000000000..4c3a3f6a9 --- /dev/null +++ b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.html @@ -0,0 +1,161 @@ + + + + + + + +Help + + + + + + + + + + + +
+ + +
+ + + + +
+ +

Touch Pointer

+

+

+
+ +
+
+ + + diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.png b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.png new file mode 100644 index 000000000..ab7c59896 Binary files /dev/null and b/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/back.jpg b/client/Android/aFreeRDP/assets/help_page/back.jpg deleted file mode 100644 index 3bf3455bf..000000000 Binary files a/client/Android/aFreeRDP/assets/help_page/back.jpg and /dev/null differ diff --git a/client/Android/aFreeRDP/assets/help_page/gestures.html b/client/Android/aFreeRDP/assets/help_page/gestures.html index 858387773..533e55d0f 100644 --- a/client/Android/aFreeRDP/assets/help_page/gestures.html +++ b/client/Android/aFreeRDP/assets/help_page/gestures.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100%/1.4 Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; color:#000; diff --git a/client/Android/aFreeRDP/assets/help_page/gestures.png b/client/Android/aFreeRDP/assets/help_page/gestures.png index e49a45b8f..78b3e7b34 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/gestures.png and b/client/Android/aFreeRDP/assets/help_page/gestures.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/gestures_phone.html b/client/Android/aFreeRDP/assets/help_page/gestures_phone.html index 156d7c94d..c1c7284d1 100644 --- a/client/Android/aFreeRDP/assets/help_page/gestures_phone.html +++ b/client/Android/aFreeRDP/assets/help_page/gestures_phone.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100% Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; diff --git a/client/Android/aFreeRDP/assets/help_page/gestures_phone.png b/client/Android/aFreeRDP/assets/help_page/gestures_phone.png index 1b90a1f65..4eea33ef4 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/gestures_phone.png and b/client/Android/aFreeRDP/assets/help_page/gestures_phone.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/nav_gestures.png b/client/Android/aFreeRDP/assets/help_page/nav_gestures.png index ab1b36fba..50bfaa232 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/nav_gestures.png and b/client/Android/aFreeRDP/assets/help_page/nav_gestures.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/nav_toolbar.png b/client/Android/aFreeRDP/assets/help_page/nav_toolbar.png index 703c0013a..f66b24d21 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/nav_toolbar.png and b/client/Android/aFreeRDP/assets/help_page/nav_toolbar.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png b/client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png index 30e04568e..930fc9cbf 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png and b/client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar.html b/client/Android/aFreeRDP/assets/help_page/toolbar.html index e9ea27ab5..117ab6309 100644 --- a/client/Android/aFreeRDP/assets/help_page/toolbar.html +++ b/client/Android/aFreeRDP/assets/help_page/toolbar.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100%/1.4 Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar.png b/client/Android/aFreeRDP/assets/help_page/toolbar.png index 10c23b62b..42f055b9f 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/toolbar.png and b/client/Android/aFreeRDP/assets/help_page/toolbar.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.html b/client/Android/aFreeRDP/assets/help_page/toolbar_phone.html index f810d4b08..e4dcf6768 100644 --- a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.html +++ b/client/Android/aFreeRDP/assets/help_page/toolbar_phone.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100% Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.png b/client/Android/aFreeRDP/assets/help_page/toolbar_phone.png index a01279ce0..278cd3a9d 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.png and b/client/Android/aFreeRDP/assets/help_page/toolbar_phone.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer.html b/client/Android/aFreeRDP/assets/help_page/touch_pointer.html index 8072a1bac..939f92637 100644 --- a/client/Android/aFreeRDP/assets/help_page/touch_pointer.html +++ b/client/Android/aFreeRDP/assets/help_page/touch_pointer.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100%/1.4 Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer.png b/client/Android/aFreeRDP/assets/help_page/touch_pointer.png index f06e3889f..af3ebcab0 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/touch_pointer.png and b/client/Android/aFreeRDP/assets/help_page/touch_pointer.png differ diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html b/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html index 89d2e8de0..4c3a3f6a9 100644 --- a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html +++ b/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html @@ -21,7 +21,7 @@ body{ margin:0; padding: 0 0 0; font: 100% Helvetica; - background-image:url(back.jpg); + background-image:url(../background.jpg); background-position:center; diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png b/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png index 168749fd0..ab7c59896 100644 Binary files a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png and b/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png differ diff --git a/client/Android/aFreeRDP/assets/welcome_page/1.png b/client/Android/aFreeRDP/assets/welcome_page/1.png deleted file mode 100644 index 30025d81a..000000000 Binary files a/client/Android/aFreeRDP/assets/welcome_page/1.png and /dev/null differ diff --git a/client/Android/aFreeRDP/assets/welcome_page/2.png b/client/Android/aFreeRDP/assets/welcome_page/2.png deleted file mode 100644 index 43d3a7fe5..000000000 Binary files a/client/Android/aFreeRDP/assets/welcome_page/2.png and /dev/null differ diff --git a/client/Android/aFreeRDP/assets/welcome_page/back.jpg b/client/Android/aFreeRDP/assets/welcome_page/back.jpg deleted file mode 100644 index 3bf3455bf..000000000 Binary files a/client/Android/aFreeRDP/assets/welcome_page/back.jpg and /dev/null differ diff --git a/client/Android/aFreeRDP/assets/welcome_page/new_connection.png b/client/Android/aFreeRDP/assets/welcome_page/new_connection.png deleted file mode 100644 index dede2a28a..000000000 Binary files a/client/Android/aFreeRDP/assets/welcome_page/new_connection.png and /dev/null differ diff --git a/client/Android/aFreeRDP/assets/welcome_page/welcome.html b/client/Android/aFreeRDP/assets/welcome_page/welcome.html deleted file mode 100644 index 70df41a14..000000000 --- a/client/Android/aFreeRDP/assets/welcome_page/welcome.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - -
-
-
-

New Connection

-
- You can specify your own connection settings - just hit the button below or choose "New Connection" from the application menu.
-
-
-
-
-
- - diff --git a/client/Android/aFreeRDP/assets/welcome_page/welcome_phone.html b/client/Android/aFreeRDP/assets/welcome_page/welcome_phone.html deleted file mode 100644 index fd5ddc434..000000000 --- a/client/Android/aFreeRDP/assets/welcome_page/welcome_phone.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - -
-
-
-

New Connection

-
- You can specify your own connection settings - just hit the button below or choose "New Connection" from the application menu.
-
-
-
-
-
- - diff --git a/client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png b/client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png index 45ed86123..ff31f2576 100644 Binary files a/client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png and b/client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png differ diff --git a/client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png b/client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png index b57651bed..49726f4f0 100644 Binary files a/client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png and b/client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png differ diff --git a/client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png b/client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png index 55335c869..6b18c0ae3 100644 Binary files a/client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png and b/client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png differ diff --git a/client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png b/client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png index ad325d46e..53c5b36e1 100644 Binary files a/client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png and b/client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png differ diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c171c0dfe..14ed3633f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -36,6 +36,10 @@ if(FREERDP_VENDOR) add_subdirectory(X11) endif() + if(WITH_WAYLAND) + add_subdirectory(Wayland) + endif() + if(APPLE) if(IOS) if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/iOS") diff --git a/client/DirectFB/CMakeLists.txt b/client/DirectFB/CMakeLists.txt index 061b05c54..6cf7cead9 100644 --- a/client/DirectFB/CMakeLists.txt +++ b/client/DirectFB/CMakeLists.txt @@ -32,16 +32,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${DIRECTFB_LIBRARIES}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-codec freerdp-primitives freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-input winpr-crt) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/client/DirectFB/dfreerdp.c b/client/DirectFB/dfreerdp.c index df68a1d6c..1d645c0a6 100644 --- a/client/DirectFB/dfreerdp.c +++ b/client/DirectFB/dfreerdp.c @@ -24,6 +24,7 @@ #include #include #include + #include #include #include @@ -37,6 +38,9 @@ #include "dfreerdp.h" +#include +#define TAG CLIENT_TAG("directFB") + static HANDLE g_sem; static int g_thread_count = 0; @@ -232,18 +236,17 @@ BOOL df_post_connect(freerdp* instance) BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) { char answer; - - printf("Certificate details:\n"); - printf("\tSubject: %s\n", subject); - printf("\tIssuer: %s\n", issuer); - printf("\tThumbprint: %s\n", fingerprint); - printf("The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); + WLog_INFO(TAG, "Certificate details:"); + WLog_INFO(TAG, "\tSubject: %s", subject); + WLog_INFO(TAG, "\tIssuer: %s", issuer); + WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); + WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired. " + "Please look at the documentation on how to create local certificate store for a private CA."); while (1) { - printf("Do you trust the above certificate? (Y/N) "); + WLog_INFO(TAG, "Do you trust the above certificate? (Y/N) "); answer = fgetc(stdin); if (answer == 'y' || answer == 'Y') @@ -259,7 +262,7 @@ BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer, char* return FALSE; } -static int df_receive_channel_data(freerdp* instance, int channelId, BYTE* data, int size, int flags, int total_size) +static int df_receive_channel_data(freerdp* instance, UINT16 channelId, BYTE* data, int size, int flags, int total_size) { return freerdp_channels_data(instance, channelId, data, size, flags, total_size); } @@ -292,7 +295,7 @@ static void df_process_channel_event(rdpChannels* channels, freerdp* instance) break; default: - fprintf(stderr, "df_process_channel_event: unknown event type %d\n", GetMessageType(event->id)); + WLog_ERR(TAG, "df_process_channel_event: unknown event type %d", GetMessageType(event->id)); break; } @@ -339,17 +342,17 @@ int dfreerdp_run(freerdp* instance) if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to get channel manager file descriptor"); break; } if (df_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get dfreerdp file descriptor\n"); + WLog_ERR(TAG, "Failed to get dfreerdp file descriptor"); break; } @@ -378,24 +381,24 @@ int dfreerdp_run(freerdp* instance) (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - fprintf(stderr, "dfreerdp_run: select failed\n"); + WLog_ERR(TAG, "dfreerdp_run: select failed"); break; } } if (freerdp_check_fds(instance) != TRUE) { - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } if (df_check_fds(instance, &rfds_set) != TRUE) { - fprintf(stderr, "Failed to check dfreerdp file descriptor\n"); + WLog_ERR(TAG, "Failed to check dfreerdp file descriptor"); break; } if (freerdp_channels_check_fds(channels, instance) != TRUE) { - fprintf(stderr, "Failed to check channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } df_process_channel_event(channels, instance); diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt old mode 100755 new mode 100644 index 33c946ee2..863ec827a --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -79,14 +79,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH 1) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${EXTRA_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-cache freerdp-gdi freerdp-codec freerdp-primitives freerdp-rail freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-input winpr-crt winpr-utils) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/client/Mac/Credits.rtf b/client/Mac/Credits.rtf old mode 100755 new mode 100644 diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h old mode 100755 new mode 100644 diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 5de0da47f..ea6a8e901 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -43,6 +43,9 @@ #import "freerdp/client/cliprdr.h" #import "freerdp/client/file.h" #import "freerdp/client/cmdline.h" +#import "freerdp/log.h" + +#define TAG CLIENT_TAG("mac") void mf_Pointer_New(rdpContext* context, rdpPointer* pointer); void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer); @@ -617,7 +620,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) vkcode &= 0xFF; #if 0 - fprintf(stderr, "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n", + WLog_ERR(TAG, "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); #endif @@ -654,7 +657,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) vkcode &= 0xFF; #if 0 - fprintf(stderr, "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n", + WLog_DBG(TAG, "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); #endif @@ -683,29 +686,29 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) vkcode &= 0xFF; #if 0 - fprintf(stderr, "flagsChanged: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X extended: %d name: %s modFlags: 0x%04X\n", + WLog_DBG(TAG, "flagsChanged: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X extended: %d name: %s modFlags: 0x%04X", key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode), modFlags); if (modFlags & NSAlphaShiftKeyMask) - fprintf(stderr, "NSAlphaShiftKeyMask\n"); + WLog_DBG(TAG, "NSAlphaShiftKeyMask"); if (modFlags & NSShiftKeyMask) - fprintf(stderr, "NSShiftKeyMask\n"); + WLog_DBG(TAG, "NSShiftKeyMask"); if (modFlags & NSControlKeyMask) - fprintf(stderr, "NSControlKeyMask\n"); + WLog_DBG(TAG, "NSControlKeyMask"); if (modFlags & NSAlternateKeyMask) - fprintf(stderr, "NSAlternateKeyMask\n"); + WLog_DBG(TAG, "NSAlternateKeyMask"); if (modFlags & NSCommandKeyMask) - fprintf(stderr, "NSCommandKeyMask\n"); + WLog_DBG(TAG, "NSCommandKeyMask"); if (modFlags & NSNumericPadKeyMask) - fprintf(stderr, "NSNumericPadKeyMask\n"); + WLog_DBG(TAG, "NSNumericPadKeyMask"); if (modFlags & NSHelpKeyMask) - fprintf(stderr, "NSHelpKeyMask\n"); + WLog_DBG(TAG, "NSHelpKeyMask"); #endif if ((modFlags & NSAlphaShiftKeyMask) && !(kbdModFlags & NSAlphaShiftKeyMask)) @@ -820,6 +823,44 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) mfc->client_width = width; } +void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) +{ + rdpSettings* settings = context->settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + + } +} + +void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) +{ + rdpSettings* settings = context->settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + + } +} + BOOL mac_pre_connect(freerdp* instance) { rdpSettings* settings; @@ -832,7 +873,7 @@ BOOL mac_pre_connect(freerdp* instance) if (!settings->ServerHostname) { - fprintf(stderr, "error: server hostname was not specified with /v:[:port]\n"); + WLog_ERR(TAG, "error: server hostname was not specified with /v:[:port]"); [NSApp terminate:nil]; return -1; } @@ -867,6 +908,12 @@ BOOL mac_pre_connect(freerdp* instance) settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; + + PubSub_SubscribeChannelConnected(instance->context->pubSub, + (pChannelConnectedEventHandler) mac_OnChannelConnectedEventHandler); + + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + (pChannelDisconnectedEventHandler) mac_OnChannelDisconnectedEventHandler); freerdp_client_load_addins(instance->context->channels, instance->settings); @@ -897,10 +944,10 @@ BOOL mac_post_connect(freerdp* instance) flags = CLRCONV_ALPHA | CLRCONV_RGB555; - if (settings->ColorDepth > 16) + //if (settings->ColorDepth > 16) flags |= CLRBUF_32BPP; - else - flags |= CLRBUF_16BPP; + //else + // flags |= CLRBUF_16BPP; gdi_init(instance, flags, NULL); gdi = instance->context->gdi; @@ -1073,17 +1120,17 @@ CGContextRef mac_create_bitmap_context(rdpContext* context) CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - if (gdi->dstBpp == 16) + if (gdi->bytesPerPixel == 2) { bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, - gdi->width, gdi->height, 5, gdi->width * 2, colorSpace, - kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst); + gdi->width, gdi->height, 5, gdi->width * gdi->bytesPerPixel, + colorSpace, kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst); } else { bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, - gdi->width, gdi->height, 8, gdi->width * 4, colorSpace, - kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); + gdi->width, gdi->height, 8, gdi->width * gdi->bytesPerPixel, + colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); } CGColorSpaceRelease(colorSpace); @@ -1200,7 +1247,7 @@ static void update_activity_cb(freerdp* instance) } else { - fprintf(stderr, "update_activity_cb: No queue!\n"); + WLog_ERR(TAG, "update_activity_cb: No queue!"); } } @@ -1225,7 +1272,7 @@ static void input_activity_cb(freerdp* instance) } else { - fprintf(stderr, "input_activity_cb: No queue!\n"); + WLog_ERR(TAG, "input_activity_cb: No queue!"); } } @@ -1238,7 +1285,7 @@ static void channel_activity_cb(freerdp* instance) if (event) { - fprintf(stderr, "channel_activity_cb: message %d\n", event->id); + WLog_DBG(TAG, "channel_activity_cb: message %d", event->id); switch (GetMessageClass(event->id)) { @@ -1306,8 +1353,8 @@ void cliprdr_send_data_request(freerdp* instance, UINT32 format) /** * at the moment, only the following formats are supported - * CB_FORMAT_TEXT - * CB_FORMAT_UNICODETEXT + * CF_TEXT + * CF_UNICODETEXT */ void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event) @@ -1320,7 +1367,7 @@ void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPO if (event->size == 0) return; - if (view->pasteboard_format == CB_FORMAT_TEXT || view->pasteboard_format == CB_FORMAT_UNICODETEXT) + if (view->pasteboard_format == CF_TEXT || view->pasteboard_format == CF_UNICODETEXT) { str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; @@ -1344,8 +1391,8 @@ void cliprdr_process_cb_monitor_ready_event(freerdp* instance) /** * list of supported clipboard formats; currently only the following are supported - * CB_FORMAT_TEXT - * CB_FORMAT_UNICODETEXT + * CF_TEXT + * CF_UNICODETEXT */ void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event) @@ -1361,36 +1408,12 @@ void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_ { switch (event->formats[i]) { - case CB_FORMAT_RAW: - printf("CB_FORMAT_RAW: not yet supported\n"); - break; - - case CB_FORMAT_TEXT: - case CB_FORMAT_UNICODETEXT: - view->pasteboard_format = CB_FORMAT_UNICODETEXT; - cliprdr_send_data_request(instance, CB_FORMAT_UNICODETEXT); + case CF_TEXT: + case CF_UNICODETEXT: + view->pasteboard_format = CF_UNICODETEXT; + cliprdr_send_data_request(instance, CF_UNICODETEXT); return; break; - - case CB_FORMAT_DIB: - printf("CB_FORMAT_DIB: not yet supported\n"); - break; - - case CB_FORMAT_HTML: - printf("CB_FORMAT_HTML\n"); - break; - - case CB_FORMAT_PNG: - printf("CB_FORMAT_PNG: not yet supported\n"); - break; - - case CB_FORMAT_JPEG: - printf("CB_FORMAT_JPEG: not yet supported\n"); - break; - - case CB_FORMAT_GIF: - printf("CB_FORMAT_GIF: not yet supported\n"); - break; } } } @@ -1440,7 +1463,7 @@ void process_cliprdr_event(freerdp* instance, wMessage* event) break; default: - printf("process_cliprdr_event: unknown event type %d\n", GetMessageType(event->id)); + WLog_ERR(TAG, "process_cliprdr_event: unknown event type %d", GetMessageType(event->id)); break; } } @@ -1454,7 +1477,7 @@ void cliprdr_send_supported_format_list(freerdp* instance) event->formats = (UINT32*) malloc(sizeof(UINT32) * 1); event->num_formats = 1; - event->formats[0] = CB_FORMAT_UNICODETEXT; + event->formats[0] = CF_UNICODETEXT; freerdp_channels_send_event(instance->context->channels, (wMessage*) event); } diff --git a/client/Mac/cli/MainMenu.xib b/client/Mac/cli/MainMenu.xib old mode 100755 new mode 100644 diff --git a/client/Mac/mf_client.h b/client/Mac/mf_client.h old mode 100755 new mode 100644 diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m old mode 100755 new mode 100644 diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index fa1961951..37eb3b4a6 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -10,11 +10,17 @@ typedef struct mf_context mfContext; #include #include +#include #include #include #include #include +#include +#include +#include +#include + #include #include #include diff --git a/client/Sample/CMakeLists.txt b/client/Sample/CMakeLists.txt index c5070a7bd..f9506b315 100644 --- a/client/Sample/CMakeLists.txt +++ b/client/Sample/CMakeLists.txt @@ -24,14 +24,7 @@ set(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-utils) - +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Sample") diff --git a/client/Sample/freerdp.c b/client/Sample/freerdp.c index 4495bf9a9..d426bbc85 100644 --- a/client/Sample/freerdp.c +++ b/client/Sample/freerdp.c @@ -46,6 +46,9 @@ #include #include +#include + +#define TAG CLIENT_TAG("sample") struct tf_info { @@ -127,7 +130,7 @@ void tf_process_channel_event(rdpChannels* channels, freerdp* instance) break; default: - printf("tf_process_channel_event: unknown event type %d\n", GetMessageType(event->id)); + WLog_ERR(TAG, "unknown event type %d", GetMessageType(event->id)); break; } @@ -219,12 +222,12 @@ int tfreerdp_run(freerdp* instance) ZeroMemory(wfds, sizeof(wfds)); if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - printf("Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { - printf("Failed to get channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to get channel manager file descriptor"); break; } @@ -253,19 +256,19 @@ int tfreerdp_run(freerdp* instance) (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - printf("tfreerdp_run: select failed\n"); + WLog_ERR(TAG, "tfreerdp_run: select failed"); break; } } if (freerdp_check_fds(instance) != TRUE) { - printf("Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } if (freerdp_channels_check_fds(channels, instance) != TRUE) { - printf("Failed to check channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } tf_process_channel_event(channels, instance); @@ -294,6 +297,7 @@ void* thread_func(void* param) if (g_thread_count < 1) ReleaseSemaphore(g_sem, 1, NULL); + ExitThread(0); return NULL; } diff --git a/client/Wayland/CMakeLists.txt b/client/Wayland/CMakeLists.txt new file mode 100644 index 000000000..182fb2bea --- /dev/null +++ b/client/Wayland/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP Wayland Client cmake build script +# +# Copyright 2014 Manuel Bachmann +# +# 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. + +set(MODULE_NAME "wlfreerdp") +set(MODULE_PREFIX "FREERDP_CLIENT_WAYLAND") + +include_directories(${WAYLAND_INCLUDE_DIRS}) + +set(${MODULE_PREFIX}_SRCS + wlfreerdp.c) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${WAYLAND_LIBRARIES} freerdp-client freerdp) +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Wayland") diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c new file mode 100644 index 000000000..65f8b3226 --- /dev/null +++ b/client/Wayland/wlfreerdp.c @@ -0,0 +1,420 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Client Interface + * + * Copyright 2014 Manuel Bachmann + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct display +{ + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_shell* shell; + struct wl_shm* shm; +}; + +struct buffer +{ + struct wl_buffer* buffer; + void* shm_data; + int busy; +}; + +struct window +{ + int width, height; + struct wl_surface* surface; + struct wl_shell_surface* shell_surface; + struct wl_callback* callback; + struct buffer buffers[2]; + struct display* display; + void* data; +}; + +struct wl_context +{ + rdpContext _p; + struct display* display; + struct window* window; +}; + +static void wl_buffer_release(void* data, struct wl_buffer* wl_buffer) +{ + struct buffer* buffer = data; + + buffer->busy = 0; +} + +static const struct wl_buffer_listener wl_buffer_listener = +{ + wl_buffer_release +}; + +static void window_redraw(void* data, struct wl_callback* callback, uint32_t time); +static const struct wl_callback_listener wl_callback_listener = +{ + window_redraw +}; + +static void window_redraw(void* data, struct wl_callback* callback, uint32_t time) +{ + struct window* window = data; + struct wl_shm_pool* shm_pool; + struct buffer* buffer; + int fd; + int fdt; + + if (!window->buffers[0].busy) + buffer = &window->buffers[0]; + else if (!window->buffers[1].busy) + buffer = &window->buffers[1]; + else + return; + + fd = shm_open("wlfreerdp_shm", O_CREAT | O_TRUNC | O_RDWR, 0666); + fdt = ftruncate(fd, window->width * window->height * 4); + if (fdt != 0) + { + fprintf(stderr, "window_redraw: could not allocate memory\n"); + close(fd); + return; + } + + buffer->shm_data = mmap(0, window->width * window->height * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (buffer->shm_data == MAP_FAILED) + { + fprintf(stderr, "window_redraw: failed to memory map buffer\n"); + close(fd); + return; + } + + shm_pool = wl_shm_create_pool(window->display->shm, fd, window->width * window->height * 4); + buffer->buffer = wl_shm_pool_create_buffer(shm_pool, 0, window->width, window->height, window->width* 4, WL_SHM_FORMAT_XRGB8888); + wl_buffer_add_listener(buffer->buffer, &wl_buffer_listener, buffer); + wl_shm_pool_destroy(shm_pool); + shm_unlink("wlfreerdp_shm"); + close(fd); + + /* this is the real surface data */ + memcpy(buffer->shm_data, (void*) window->data, window->width * window->height * 4); + wl_surface_attach(window->surface, buffer->buffer, 0, 0); + wl_surface_damage(window->surface, 0, 0, window->width, window->height); + + if (callback) wl_callback_destroy(callback); + window->callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &wl_callback_listener, window); + wl_surface_commit(window->surface); + + buffer->busy = 1; + munmap(buffer->shm_data, window->width * window->height * 4); +} + +static void wl_shell_surface_handle_ping(void* data, struct wl_shell_surface* shell_surface, uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static const struct wl_shell_surface_listener wl_shell_surface_listener = +{ + wl_shell_surface_handle_ping +}; + +static void wl_registry_handle_global(void* data, struct wl_registry* registry, uint32_t id, const char *interface, uint32_t version) +{ + struct display* display = data; + + if (strcmp(interface, "wl_compositor") == 0) + display->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1); + else if (strcmp(interface, "wl_shell") == 0) + display->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1); + else if (strcmp(interface, "wl_shm") == 0) + display->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); +} + +static void wl_registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name) +{ + +} + +static const struct wl_registry_listener wl_registry_listener = +{ + wl_registry_handle_global, + wl_registry_handle_global_remove +}; + +int wl_context_new(freerdp* instance, rdpContext* context) +{ + context->channels = freerdp_channels_new(); + + return 0; +} + +void wl_context_free(freerdp* instance, rdpContext* context) +{ + +} + +void wl_begin_paint(rdpContext* context) +{ + rdpGdi* gdi; + + gdi = context->gdi; + gdi->primary->hdc->hwnd->invalid->null = 1; +} + +void wl_end_paint(rdpContext* context) +{ + rdpGdi* gdi; + struct display* display; + struct window* window; + struct wl_context* context_w; + + gdi = context->gdi; + if (gdi->primary->hdc->hwnd->invalid->null) + return; + + context_w = (struct wl_context*) context; + display = context_w->display; + window = context_w->window; + + realloc(window->data, gdi->width * gdi->height * 4); + memcpy(window->data, (void*) gdi->primary_buffer, gdi->width * gdi->height * 4); + wl_display_dispatch(display->display); +} + +BOOL wl_pre_connect(freerdp* instance) +{ + struct display* display; + struct wl_context* context; + + freerdp_channels_pre_connect(instance->context->channels, instance); + + display = malloc(sizeof(*display)); + display->display = wl_display_connect(NULL); + + if (!display->display) + { + fprintf(stderr, "wl_pre_connect: failed to connect to Wayland compositor\n"); + fprintf(stderr, "Please check that the XDG_RUNTIME_DIR environment variable is properly set.\n"); + free(display); + return FALSE; + } + + display->registry = wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, &wl_registry_listener, display); + wl_display_roundtrip(display->display); + + if (!display->compositor || !display->shell || !display->shm) + { + fprintf(stderr, "wl_pre_connect: failed to find needed compositor interfaces\n"); + free(display); + return FALSE; + } + + /* put Wayland data in the context here */ + context = (struct wl_context*) instance->context; + context->display = display; + + return TRUE; +} + +BOOL wl_post_connect(freerdp* instance) +{ + struct window* window; + struct wl_context* context; + + context = (struct wl_context*) instance->context; + + window = malloc(sizeof(*window)); + window->width = instance->settings->DesktopWidth; + window->height = instance->settings->DesktopHeight; + window->buffers[0].busy = 0; + window->buffers[1].busy = 0; + window->callback = NULL; + window->display = context->display; + window->surface = wl_compositor_create_surface(window->display->compositor); + window->shell_surface = wl_shell_get_shell_surface(window->display->shell, window->surface); + + wl_shell_surface_add_listener(window->shell_surface, &wl_shell_surface_listener, NULL); + wl_shell_surface_set_title(window->shell_surface, "FreeRDP"); + wl_shell_surface_set_toplevel(window->shell_surface); + wl_surface_damage(window->surface, 0, 0, window->width, window->height); + + /* GC/GDI logic here */ + rdpGdi* gdi; + + gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_32BPP, NULL); + gdi = instance->context->gdi; + + /* fill buffer with first image here */ + window->data = malloc (gdi->width * gdi->height *4); + memcpy(window->data, (void*) gdi->primary_buffer, gdi->width * gdi->height * 4); + instance->update->BeginPaint = wl_begin_paint; + instance->update->EndPaint = wl_end_paint; + + /* put Wayland data in the context here */ + context->window = window; + + freerdp_channels_post_connect(instance->context->channels, instance); + + window_redraw(window, NULL, 0); + + return TRUE; +} + +int wlfreerdp_run(freerdp* instance) +{ + int i; + int fds; + int max_fds; + int rcount; + int wcount; + void* rfds[32]; + void* wfds[32]; + fd_set rfds_set; + fd_set wfds_set; + + ZeroMemory(rfds, sizeof(rfds)); + ZeroMemory(wfds, sizeof(wfds)); + + freerdp_connect(instance); + + while (1) + { + rcount = 0; + wcount = 0; + if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + { + printf("Failed to get FreeRDP file descriptor"); + break; + } + if (freerdp_channels_get_fds(instance->context->channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) + { + printf("Failed to get FreeRDP file descriptor"); + break; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + FD_ZERO(&wfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) + { + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) + { + printf("wlfreerdp_run: select failed\n"); + break; + } + } + + if (freerdp_check_fds(instance) != TRUE) + { + printf("Failed to check FreeRDP file descriptor\n"); + break; + } + if (freerdp_channels_check_fds(instance->context->channels, instance) != TRUE) + { + printf("Failed to check channel manager file descriptor\n"); + break; + } + } + + struct display* display; + struct window* window; + struct wl_context* context; + + context = (struct wl_context*) instance->context; + display = context->display; + window = context->window; + free(window->buffers[0].shm_data); + free(window->buffers[1].shm_data); + free(window->data); + + wl_buffer_destroy(window->buffers[0].buffer); + wl_buffer_destroy(window->buffers[1].buffer); + wl_shell_surface_destroy(window->shell_surface); + wl_surface_destroy(window->surface); + wl_shm_destroy(display->shm); + wl_shell_destroy(display->shell); + wl_compositor_destroy(display->compositor); + wl_registry_destroy(display->registry); + wl_display_disconnect(display->display); + + freerdp_channels_close(instance->context->channels, instance); + freerdp_channels_free(instance->context->channels); + freerdp_free(instance); + + return 0; +} + +int main(int argc, char* argv[]) +{ + int status; + freerdp* instance; + + freerdp_channels_global_init(); + + instance = freerdp_new(); + instance->PreConnect = wl_pre_connect; + instance->PostConnect = wl_post_connect; + + instance->ContextSize = sizeof(struct wl_context); + instance->ContextNew = wl_context_new; + instance->ContextFree = wl_context_free; + freerdp_context_new(instance); + + status = freerdp_client_parse_command_line_arguments(argc, argv, instance->settings); + + if (status < 0) + exit(0); + + freerdp_client_load_addins(instance->context->channels, instance->settings); + + wlfreerdp_run(instance); + + freerdp_channels_global_uninit(); + + return 0; +} diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index fb14eb527..c208301c0 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -29,16 +29,16 @@ set(${MODULE_PREFIX}_SRCS wf_gdi.h wf_event.c wf_event.h + wf_channels.c + wf_channels.h wf_graphics.c wf_graphics.h wf_cliprdr.c wf_cliprdr.h - wf_window.c - wf_window.h wf_rail.c wf_rail.h - wf_interface.c - wf_interface.h + wf_client.c + wf_client.h wf_floatbar.c wf_floatbar.h wfreerdp.rc @@ -50,24 +50,17 @@ if(WITH_CLIENT_INTERFACE) else() add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) endif() - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") + if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) + endif() + set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/wfreerdp.c cli/wfreerdp.h) add_executable(${MODULE_NAME} WIN32 ${${MODULE_PREFIX}_SRCS}) endif() set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-credui winpr-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-codec freerdp-primitives freerdp-utils) - +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) if(WITH_CLIENT_INTERFACE) diff --git a/client/Windows/cli/wfreerdp.c b/client/Windows/cli/wfreerdp.c index c5f5fa0a8..8a78cbf7c 100644 --- a/client/Windows/cli/wfreerdp.c +++ b/client/Windows/cli/wfreerdp.c @@ -39,7 +39,7 @@ #include "resource.h" -#include "wf_interface.h" +#include "wf_client.h" INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { @@ -63,6 +63,8 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine settings = context->settings; wfc = (wfContext*) context; + settings->SoftwareGdi = TRUE; + context->argc = __argc; context->argv = (char**) malloc(sizeof(char*) * __argc); diff --git a/client/Windows/resource/bg.bmp b/client/Windows/resource/bg.bmp index c97ef5d99..7e90ec6ef 100644 Binary files a/client/Windows/resource/bg.bmp and b/client/Windows/resource/bg.bmp differ diff --git a/client/Windows/resource/close.bmp b/client/Windows/resource/close.bmp index 8fce91657..f9bf31eb0 100644 Binary files a/client/Windows/resource/close.bmp and b/client/Windows/resource/close.bmp differ diff --git a/client/Windows/resource/close_active.bmp b/client/Windows/resource/close_active.bmp index 2c58a3de6..43dc5b2ba 100644 Binary files a/client/Windows/resource/close_active.bmp and b/client/Windows/resource/close_active.bmp differ diff --git a/client/Windows/resource/lock.bmp b/client/Windows/resource/lock.bmp index 91d7384d9..685778735 100644 Binary files a/client/Windows/resource/lock.bmp and b/client/Windows/resource/lock.bmp differ diff --git a/client/Windows/resource/lock_active.bmp b/client/Windows/resource/lock_active.bmp index 78e2ed45e..b4fa35f22 100644 Binary files a/client/Windows/resource/lock_active.bmp and b/client/Windows/resource/lock_active.bmp differ diff --git a/client/Windows/resource/minimize.bmp b/client/Windows/resource/minimize.bmp index f4c5f6c7a..7fce92d08 100644 Binary files a/client/Windows/resource/minimize.bmp and b/client/Windows/resource/minimize.bmp differ diff --git a/client/Windows/resource/minimize_active.bmp b/client/Windows/resource/minimize_active.bmp index 152fad298..6f0b74db7 100644 Binary files a/client/Windows/resource/minimize_active.bmp and b/client/Windows/resource/minimize_active.bmp differ diff --git a/client/Windows/resource/restore.bmp b/client/Windows/resource/restore.bmp index d74eddf23..b2ae47b67 100644 Binary files a/client/Windows/resource/restore.bmp and b/client/Windows/resource/restore.bmp differ diff --git a/client/Windows/resource/restore_active.bmp b/client/Windows/resource/restore_active.bmp index f88bc4d9a..a0516afd0 100644 Binary files a/client/Windows/resource/restore_active.bmp and b/client/Windows/resource/restore_active.bmp differ diff --git a/client/Windows/resource/unlock.bmp b/client/Windows/resource/unlock.bmp index 8359ae7cc..f59b72a01 100644 Binary files a/client/Windows/resource/unlock.bmp and b/client/Windows/resource/unlock.bmp differ diff --git a/client/Windows/resource/unlock_active.bmp b/client/Windows/resource/unlock_active.bmp index 59d730d6e..a5d9c3818 100644 Binary files a/client/Windows/resource/unlock_active.bmp and b/client/Windows/resource/unlock_active.bmp differ diff --git a/client/Windows/wf_channels.c b/client/Windows/wf_channels.c new file mode 100644 index 000000000..664164c30 --- /dev/null +++ b/client/Windows/wf_channels.c @@ -0,0 +1,65 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "wf_channels.h" + +#include + +void wf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) +{ + wfContext* wfc = (wfContext*) context; + rdpSettings* settings = context->settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + + } +} + +void wf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) +{ + wfContext* wfc = (wfContext*) context; + rdpSettings* settings = context->settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + + } +} diff --git a/client/Windows/wf_channels.h b/client/Windows/wf_channels.h new file mode 100644 index 000000000..18d3ac402 --- /dev/null +++ b/client/Windows/wf_channels.h @@ -0,0 +1,33 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 __WF_CHANNELS_H +#define __WF_CHANNELS_H + +#include +#include +#include +#include +#include + +#include "wf_client.h" + +void wf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e); +void wf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e); + +#endif diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_client.c similarity index 88% rename from client/Windows/wf_interface.c rename to client/Windows/wf_client.c index ec7c70db2..40a020bb4 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_client.c @@ -36,10 +36,7 @@ #include #include -#ifdef _MSC_VER -#include -#endif - +#include #include #include #include @@ -50,13 +47,16 @@ #include #include "wf_gdi.h" +#include "wf_channels.h" #include "wf_graphics.h" #include "wf_cliprdr.h" -#include "wf_interface.h" +#include "wf_client.h" #include "resource.h" +#define TAG CLIENT_TAG("windows") + int wf_create_console(void) { if (!AllocConsole()) @@ -64,9 +64,7 @@ int wf_create_console(void) freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); - - fprintf(stderr, "Debug console created.\n"); - + WLog_INFO(TAG, "Debug console created."); return 0; } @@ -104,8 +102,8 @@ void wf_sw_end_paint(wfContext* wfc) update_rect.left = x; update_rect.top = y; - update_rect.right = x + w - 1; - update_rect.bottom = y + h - 1; + update_rect.right = x + w; + update_rect.bottom = y + h; InvalidateRect(wfc->hwnd, &update_rect, FALSE); } @@ -190,6 +188,7 @@ BOOL wf_pre_connect(freerdp* instance) context = instance->context; wfc = (wfContext*) instance->context; wfc->instance = instance; + wfc->codecs = instance->context->codecs; settings = instance->settings; @@ -201,9 +200,7 @@ BOOL wf_pre_connect(freerdp* instance) } wfc->connectionRdpFile = freerdp_client_rdp_file_new(); - - fprintf(stderr, "Using connection file: %s\n", settings->ConnectionFile); - + WLog_INFO(TAG, "Using connection file: %s", settings->ConnectionFile); freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile); freerdp_client_populate_settings_from_rdp_file(wfc->connectionRdpFile, settings); } @@ -236,9 +233,9 @@ BOOL wf_pre_connect(freerdp* instance) settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE; wfc->fullscreen = settings->Fullscreen; + if (wfc->fullscreen) wfc->fs_toggle = 1; - wfc->sw_gdi = settings->SoftwareGdi; wfc->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV)); ZeroMemory(wfc->clrconv, sizeof(CLRCONV)); @@ -291,11 +288,18 @@ BOOL wf_pre_connect(freerdp* instance) if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) || (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096)) { - fprintf(stderr, "wf_pre_connect: invalid dimensions %d %d\n", settings->DesktopWidth, settings->DesktopHeight); + WLog_ERR(TAG, "invalid dimensions %d %d", settings->DesktopWidth, settings->DesktopHeight); return 1; } freerdp_set_param_uint32(settings, FreeRDP_KeyboardLayout, (int) GetKeyboardLayout(0) & 0x0000FFFF); + + PubSub_SubscribeChannelConnected(instance->context->pubSub, + (pChannelConnectedEventHandler) wf_OnChannelConnectedEventHandler); + + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + (pChannelDisconnectedEventHandler) wf_OnChannelDisconnectedEventHandler); + freerdp_channels_pre_connect(instance->context->channels, instance); return TRUE; @@ -344,12 +348,14 @@ BOOL wf_post_connect(freerdp* instance) wfc->width = settings->DesktopWidth; wfc->height = settings->DesktopHeight; - if (wfc->sw_gdi) + if (settings->SoftwareGdi) { - gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_32BPP, NULL); + wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL); + + gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, wfc->primary->pdata); + gdi = instance->context->gdi; wfc->hdc = gdi->primary->hdc; - wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, gdi->primary_buffer); } else { @@ -375,12 +381,6 @@ BOOL wf_post_connect(freerdp* instance) if (settings->RemoteFxCodec) { wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL); - wfc->rfx_context = rfx_context_new(FALSE); - } - - if (settings->NSCodec) - { - wfc->nsc_context = nsc_context_new(); } } @@ -394,10 +394,12 @@ BOOL wf_post_connect(freerdp* instance) if (settings->EmbeddedWindow) settings->Decorations = FALSE; - if (!settings->Decorations) + if (wfc->fullscreen) + dwStyle = WS_POPUP; + else if (!settings->Decorations) dwStyle = WS_CHILD | WS_BORDER; else - dwStyle = 0; + dwStyle = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX; if (!wfc->hwnd) { @@ -422,7 +424,7 @@ BOOL wf_post_connect(freerdp* instance) ShowWindow(wfc->hwnd, SW_SHOWNORMAL); UpdateWindow(wfc->hwnd); - if (wfc->sw_gdi) + if (settings->SoftwareGdi) { instance->update->BeginPaint = (pBeginPaint) wf_sw_begin_paint; instance->update->EndPaint = (pEndPaint) wf_sw_end_paint; @@ -436,19 +438,21 @@ BOOL wf_post_connect(freerdp* instance) } pointer_cache_register_callbacks(instance->update); + wf_register_pointer(context->graphics); - if (wfc->sw_gdi != TRUE) + if (!settings->SoftwareGdi) { brush_cache_register_callbacks(instance->update); bitmap_cache_register_callbacks(instance->update); offscreen_cache_register_callbacks(instance->update); + wf_register_graphics(context->graphics); + instance->update->BitmapUpdate = wf_gdi_bitmap_update; } - wf_register_graphics(instance->context->graphics); + freerdp_channels_post_connect(context->channels, instance); - freerdp_channels_post_connect(instance->context->channels, instance); + wf_cliprdr_init(wfc, context->channels); - wf_cliprdr_init(wfc, instance->context->channels); if (wfc->fullscreen) floatbar_window_create(wfc); @@ -487,7 +491,7 @@ BOOL wf_authenticate(freerdp* instance, char** username, char** password, char** if (status != NO_ERROR) { - fprintf(stderr, "CredUIPromptForCredentials unexpected status: 0x%08X\n", status); + WLog_ERR(TAG, "CredUIPromptForCredentials unexpected status: 0x%08X", status); return FALSE; } @@ -495,9 +499,7 @@ BOOL wf_authenticate(freerdp* instance, char** username, char** password, char** ZeroMemory(Domain, sizeof(Domain)); status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, sizeof(Domain)); - - //fprintf(stderr, "User: %s Domain: %s Password: %s\n", User, Domain, Password); - + //WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password); *username = _strdup(User); if (strlen(Domain) > 0) @@ -518,15 +520,13 @@ BOOL wf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* TCHAR* read_buffer; HANDLE input_handle; #endif - - printf("Certificate details:\n"); - printf("\tSubject: %s\n", subject); - printf("\tIssuer: %s\n", issuer); - printf("\tThumbprint: %s\n", fingerprint); - printf("The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); - + WLog_INFO(TAG, "Certificate details:"); + WLog_INFO(TAG, "\tSubject: %s", subject); + WLog_INFO(TAG, "\tIssuer: %s", issuer); + WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); + WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired. " + "Please look at the documentation on how to create local certificate store for a private CA."); /* TODO: ask for user validation */ #if 0 input_handle = GetStdHandle(STD_INPUT_HANDLE); @@ -590,7 +590,8 @@ static BOOL wf_auto_reconnect(freerdp* instance) return FALSE; /* A network disconnect was detected */ - fprintf(stderr, "Network disconnect!\n"); + WLog_ERR(TAG, "Network disconnect!"); + if (!instance->settings->AutoReconnectionEnabled) { /* No auto-reconnect - just quit */ @@ -605,7 +606,8 @@ static BOOL wf_auto_reconnect(freerdp* instance) return FALSE; /* Attempt the next reconnect */ - fprintf(stderr, "Attempting reconnect (%u of %u)\n", num_retries, max_retries); + WLog_INFO(TAG, "Attempting reconnect (%u of %u)", num_retries, max_retries); + if (freerdp_reconnect(instance)) { return TRUE; @@ -614,8 +616,7 @@ static BOOL wf_auto_reconnect(freerdp* instance) Sleep(5000); } - fprintf(stderr, "Maximum reconnect retries exceeded\n"); - + WLog_ERR(TAG, "Maximum reconnect retries exceeded"); return FALSE; } @@ -652,39 +653,6 @@ void* wf_input_thread(void* arg) return NULL; } -void* wf_update_thread(void* arg) -{ - int status; - wMessage message; - wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; - - assert( NULL != instance); - - status = 1; - queue = freerdp_get_message_queue(instance, - FREERDP_UPDATE_MESSAGE_QUEUE); - - while (MessageQueue_Wait(queue)) - { - while (MessageQueue_Peek(queue, &message, TRUE)) - { - status = freerdp_message_queue_process_message(instance, - FREERDP_UPDATE_MESSAGE_QUEUE, &message); - - if (!status) - break; - } - - if (!status) - break; - } - - ExitThread(0); - - return NULL; -} - void* wf_channels_thread(void* arg) { int status; @@ -728,11 +696,9 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) rdpChannels* channels; rdpSettings* settings; - BOOL async_update; BOOL async_input; BOOL async_channels; BOOL async_transport; - HANDLE update_thread; HANDLE input_thread; HANDLE channels_thread; @@ -751,18 +717,10 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) channels = instance->context->channels; settings = instance->context->settings; - async_update = settings->AsyncUpdate; async_input = settings->AsyncInput; async_channels = settings->AsyncChannels; async_transport = settings->AsyncTransport; - if (async_update) - { - update_thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) wf_update_thread, - instance, 0, NULL); - } - if (async_input) { input_thread = CreateThread(NULL, 0, @@ -780,17 +738,23 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) rcount = 0; wcount = 0; + if (freerdp_focus_required(instance)) + { + wf_event_focus_in(wfc); + wf_event_focus_in(wfc); + } + if (!async_transport) { if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } } if (wf_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get wfreerdp file descriptor\n"); + WLog_ERR(TAG, "Failed to get wfreerdp file descriptor"); break; } @@ -798,7 +762,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) { if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to get channel manager file descriptor"); break; } } @@ -816,14 +780,14 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) /* exit if nothing to do */ if (fds_count == 0) { - fprintf(stderr, "wfreerdp_run: fds_count is zero\n"); + WLog_ERR(TAG, "wfreerdp_run: fds_count is zero"); //break; } /* do the wait */ if (MsgWaitForMultipleObjects(fds_count, fds, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED) { - fprintf(stderr, "wfreerdp_run: WaitForMultipleObjects failed: 0x%04X\n", GetLastError()); + WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%04X", GetLastError()); break; } @@ -834,7 +798,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) if (wf_auto_reconnect(instance)) continue; - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } } @@ -844,7 +808,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) } if (wf_check_fds(instance) != TRUE) { - fprintf(stderr, "Failed to check wfreerdp file descriptor\n"); + WLog_ERR(TAG, "Failed to check wfreerdp file descriptor"); break; } @@ -852,7 +816,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) { if (freerdp_channels_check_fds(channels, instance) != TRUE) { - fprintf(stderr, "Failed to check channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } @@ -905,17 +869,6 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) /* cleanup */ freerdp_channels_close(channels, instance); - if (async_update) - { - wMessageQueue* update_queue; - - update_queue = freerdp_get_message_queue(instance, - FREERDP_UPDATE_MESSAGE_QUEUE); - MessageQueue_PostQuit(update_queue, 0); - WaitForSingleObject(update_thread, INFINITE); - CloseHandle(update_thread); - } - if (async_input) { wMessageQueue* input_queue; @@ -934,9 +887,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) } freerdp_disconnect(instance); - - printf("Main thread exited.\n"); - + WLog_DBG(TAG, "Main thread exited."); ExitThread(0); return 0; @@ -960,7 +911,7 @@ DWORD WINAPI wf_keyboard_thread(LPVOID lpParam) { if (status == -1) { - fprintf(stderr, "keyboard thread error getting message\n"); + WLog_ERR(TAG, "keyboard thread error getting message"); break; } else @@ -974,11 +925,10 @@ DWORD WINAPI wf_keyboard_thread(LPVOID lpParam) } else { - fprintf(stderr, "failed to install keyboard hook\n"); + WLog_ERR(TAG, "failed to install keyboard hook"); } - printf("Keyboard thread exited.\n"); - + WLog_DBG(TAG, "Keyboard thread exited."); ExitThread(0); return (DWORD) NULL; } @@ -1002,8 +952,8 @@ int freerdp_client_focus_out(wfContext* wfc) int freerdp_client_set_window_size(wfContext* wfc, int width, int height) { - fprintf(stderr, "freerdp_client_set_window_size %d, %d", width, height); - + WLog_DBG(TAG, "freerdp_client_set_window_size %d, %d", width, height); + if ((width != wfc->client_width) || (height != wfc->client_height)) { PostThreadMessage(wfc->mainThreadId, WM_SIZE, SIZE_RESTORED, ((UINT) height << 16) | (UINT) width); @@ -1026,8 +976,7 @@ int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename) // free old settings file freerdp_client_rdp_file_free(wfc->connectionRdpFile); wfc->connectionRdpFile = freerdp_client_rdp_file_new(); - - fprintf(stderr, "Using connection file: %s\n", settings->ConnectionFile); + WLog_INFO(TAG, "Using connection file: %s", settings->ConnectionFile); if (!freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile)) { diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_client.h similarity index 97% rename from client/Windows/wf_interface.h rename to client/Windows/wf_client.h index b9aa4056c..2e36599b7 100644 --- a/client/Windows/wf_interface.h +++ b/client/Windows/wf_client.h @@ -31,7 +31,7 @@ #include #include #include -#include + #include #include #include @@ -82,6 +82,8 @@ struct wf_context int client_y; int client_width; int client_height; + UINT32 bitmap_size; + BYTE* bitmap_buffer; HANDLE keyboardThread; @@ -97,6 +99,7 @@ struct wf_context HGDI_DC hdc; UINT16 srcBpp; UINT16 dstBpp; + rdpCodecs* codecs; freerdp* instance; wfBitmap* primary; wfBitmap* drawing; @@ -110,10 +113,8 @@ struct wf_context wfBitmap* tile; DWORD mainThreadId; DWORD keyboardThreadId; - RFX_CONTEXT* rfx_context; - NSC_CONTEXT* nsc_context; - BOOL sw_gdi; + //BOOL sw_gdi; rdpFile* connectionRdpFile; diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c index d319c83de..de035e425 100644 --- a/client/Windows/wf_cliprdr.c +++ b/client/Windows/wf_cliprdr.c @@ -22,8 +22,13 @@ #endif #include -#include +#include +#include + +#include +#include +#include #include #include #include @@ -32,6 +37,11 @@ #include "wf_cliprdr.h" +#define TAG CLIENT_TAG("windows") + +extern BOOL WINAPI AddClipboardFormatListener(_In_ HWND hwnd); +extern BOOL WINAPI RemoveClipboardFormatListener(_In_ HWND hwnd); + #define WM_CLIPRDR_MESSAGE (WM_USER + 156) #define OLE_SETCLIPBOARD 1 @@ -129,7 +139,14 @@ static void clear_format_map(cliprdrContext *cliprdr) cliprdr->map_size= 0; } - +/* +2.2.2.3 Client Temporary Directory PDU (CLIPRDR_TEMP_DIRECTORY) + The Temporary Directory PDU is an optional PDU sent from the client to the server. + This PDU informs the server of a location on the client file system that MUST be + used to deposit files being copied to the client. The location MUST be accessible + by the server to be useful. Section 3.1.1.3 specifies how direct file access + impacts file copy and paste. +*/ int cliprdr_send_tempdir(cliprdrContext *cliprdr) { RDP_CB_TEMPDIR_EVENT *cliprdr_event; @@ -140,6 +157,9 @@ int cliprdr_send_tempdir(cliprdrContext *cliprdr) if (!cliprdr_event) return -1; + /* Sending the TEMP path would only be valid iff the path is accessible from the server. + This should perhaps to change to a command line parameter value + */ GetEnvironmentVariableW(L"TEMP", (LPWSTR)cliprdr_event->dirname, 260); return freerdp_channels_send_event(cliprdr->channels, (wMessage *)cliprdr_event); @@ -367,32 +387,21 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM switch (Msg) { case WM_CREATE: + DEBUG_CLIPRDR("info: %s - WM_CREATE", __FUNCTION__); cliprdr = (cliprdrContext *)((CREATESTRUCT *)lParam)->lpCreateParams; - cliprdr->hwndNextViewer = SetClipboardViewer(hWnd); - - if (cliprdr->hwndNextViewer == NULL && GetLastError() != 0) - { - DEBUG_CLIPRDR("error: SetClipboardViewer failed with 0x%0x.", GetLastError()); + if (!AddClipboardFormatListener(hWnd)) { + DEBUG_CLIPRDR("error: AddClipboardFormatListener failed with %#x.", GetLastError()); } cliprdr->hwndClipboard = hWnd; break; case WM_CLOSE: - ChangeClipboardChain(hWnd, cliprdr->hwndNextViewer); + DEBUG_CLIPRDR("info: %s - WM_CLOSE", __FUNCTION__); + RemoveClipboardFormatListener(hWnd); break; - case WM_CHANGECBCHAIN: - if (cliprdr->hwndNextViewer == (HWND)wParam) - { - cliprdr->hwndNextViewer = (HWND)lParam; - } - else if (cliprdr->hwndNextViewer != NULL) - { - SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam); - } - break; - - case WM_DRAWCLIPBOARD: + case WM_CLIPBOARDUPDATE: + DEBUG_CLIPRDR("info: %s - WM_CLIPBOARDUPDATE", __FUNCTION__); if (cliprdr->channel_initialized) { if ((GetClipboardOwner() != cliprdr->hwndClipboard) && (S_FALSE == OleIsCurrentClipboard(cliprdr->data_obj))) @@ -404,11 +413,10 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM cliprdr_send_format_list(cliprdr); } } - if (cliprdr->hwndNextViewer != NULL && cliprdr->hwndNextViewer != hWnd) - SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam); break; case WM_RENDERALLFORMATS: + DEBUG_CLIPRDR("info: %s - WM_RENDERALLFORMATS", __FUNCTION__); /* discard all contexts in clipboard */ if (!OpenClipboard(cliprdr->hwndClipboard)) { @@ -420,6 +428,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM break; case WM_RENDERFORMAT: + DEBUG_CLIPRDR("info: %s - WM_RENDERFORMAT", __FUNCTION__); if (cliprdr_send_data_request(cliprdr, (UINT32)wParam) != 0) { DEBUG_CLIPRDR("error: cliprdr_send_data_request failed."); @@ -435,9 +444,11 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM break; case WM_CLIPRDR_MESSAGE: + DEBUG_CLIPRDR("info: %s - WM_CLIPRDR_MESSAGE", __FUNCTION__); switch (wParam) { case OLE_SETCLIPBOARD: + DEBUG_CLIPRDR("info: %s - OLE_SETCLIPBOARD", __FUNCTION__); if (wf_create_file_obj(cliprdr, &cliprdr->data_obj)) if (OleSetClipboard(cliprdr->data_obj) != S_OK) wf_destroy_file_obj(cliprdr->data_obj); @@ -448,7 +459,6 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM } break; - case WM_CLIPBOARDUPDATE: case WM_DESTROYCLIPBOARD: case WM_ASKCBFORMATNAME: case WM_HSCROLLCLIPBOARD: @@ -568,7 +578,7 @@ void wf_cliprdr_init(wfContext* wfc, rdpChannels* channels) if (!wfc->instance->settings->RedirectClipboard) { wfc->cliprdr_context = NULL; - fprintf(stderr, "clipboard is not redirected.\n"); + WLog_ERR(TAG, "clipboard is not redirected."); return; } @@ -643,9 +653,12 @@ static void wf_cliprdr_process_cb_clip_caps_event(wfContext *wfc, RDP_CB_CLIP_CA static void wf_cliprdr_process_cb_monitor_ready_event(wfContext *wfc, RDP_CB_MONITOR_READY_EVENT *ready_event) { cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; - +#if 0 + /*Disabled since the current function only sends the temp directory which is not + guaranteed to be accessible to the server + */ cliprdr_send_tempdir(cliprdr); - +#endif cliprdr->channel_initialized = TRUE; cliprdr_send_format_list(wfc->cliprdr_context); @@ -658,7 +671,7 @@ static BOOL wf_cliprdr_get_file_contents(wchar_t *file_name, BYTE *buffer, int p if (file_name == NULL || buffer == NULL || puSize == NULL) { - fprintf(stderr, "get file contents Invalid Arguments.\n"); + WLog_ERR(TAG, "get file contents Invalid Arguments."); return FALSE; } hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); @@ -1175,7 +1188,7 @@ static void wf_cliprdr_process_cb_filecontents_request_event(wfContext *wfc, RDP hRet = OleGetClipboard(&pDataObj); if (!SUCCEEDED(hRet)) { - fprintf(stderr, "filecontents: get ole clipboard failed.\n"); + WLog_ERR(TAG, "filecontents: get ole clipboard failed."); goto error; } @@ -1273,7 +1286,7 @@ static void wf_cliprdr_process_cb_filecontents_request_event(wfContext *wfc, RDP event->nPositionLow, event->nPositionHigh, event->cbRequested, &uSize); if (bRet == FALSE) { - fprintf(stderr, "get file contents failed.\n"); + WLog_ERR(TAG, "get file contents failed."); uSize = 0; goto error; } @@ -1304,7 +1317,7 @@ error: IDataObject_Release(pDataObj); pDataObj = NULL; } - fprintf(stderr, "filecontents: send failed response.\n"); + WLog_ERR(TAG, "filecontents: send failed response."); cliprdr_send_response_filecontents(cliprdr, event->streamId, 0, NULL); return; } diff --git a/client/Windows/wf_cliprdr.h b/client/Windows/wf_cliprdr.h index c286bcce1..aaa5b8ce7 100644 --- a/client/Windows/wf_cliprdr.h +++ b/client/Windows/wf_cliprdr.h @@ -24,12 +24,15 @@ #include #include -#include "wf_interface.h" +#include "wf_client.h" +#include + +#define TAG CLIENT_TAG(WIN_CLIPRDR_TAG) #ifdef WITH_DEBUG_CLIPRDR -#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(WIN_CLIPRDR, fmt, ## __VA_ARGS__) +#define DEBUG_CLIPRDR(fmt, ...) WLog_DBG(WIN_CLIPRDR_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_CLIPRDR(fmt, ...) do { } while (0) #endif typedef struct format_mapping formatMapping; @@ -53,7 +56,6 @@ struct cliprdr_context { BOOL channel_initialized; HWND hwndClipboard; - HWND hwndNextViewer; HANDLE cliprdr_thread; HANDLE hmem; diff --git a/client/Windows/wf_cliprdr_EnumFORMATETC.c b/client/Windows/wf_cliprdr_EnumFORMATETC.c index d988cf560..595132915 100644 --- a/client/Windows/wf_cliprdr_EnumFORMATETC.c +++ b/client/Windows/wf_cliprdr_EnumFORMATETC.c @@ -18,6 +18,7 @@ */ #include + #include "wf_cliprdr_EnumFORMATETC.h" static void cliprdr_format_deep_copy(FORMATETC *dest, FORMATETC *source) diff --git a/client/Windows/wf_event.c b/client/Windows/wf_event.c index cc54df906..3ac978124 100644 --- a/client/Windows/wf_event.c +++ b/client/Windows/wf_event.c @@ -27,11 +27,12 @@ #include -#include "wf_interface.h" +#include "wf_client.h" #include "wf_gdi.h" #include "wf_event.h" -#include "freerdp/event.h" + +#include static HWND g_focus_hWnd; @@ -131,8 +132,8 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) freerdp_input_send_keyboard_event_ex(input, !(p->flags & LLKHF_UP), rdp_scancode); - if (p->vkCode == VK_CAPITAL) - DEBUG_KBD("caps lock is processed on client side too to toggle caps lock indicator"); + if (p->vkCode == VK_NUMLOCK || p->vkCode == VK_CAPITAL || p->vkCode == VK_SCROLL || p->vkCode == VK_KANA) + DEBUG_KBD("lock keys are processed on client side too to toggle their indicators"); else return 1; @@ -152,6 +153,34 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) return CallNextHookEx(NULL, nCode, wParam, lParam); } +void wf_event_focus_in(wfContext* wfc) +{ + UINT16 syncFlags; + rdpInput* input; + UINT16 mouseX, mouseY; + + input = wfc->instance->input; + + syncFlags = 0; + + if (GetKeyState(VK_NUMLOCK)) + syncFlags |= KBD_SYNC_NUM_LOCK; + + if (GetKeyState(VK_CAPITAL)) + syncFlags |= KBD_SYNC_CAPS_LOCK; + + if (GetKeyState(VK_SCROLL)) + syncFlags |= KBD_SYNC_SCROLL_LOCK; + + if (GetKeyState(VK_KANA)) + syncFlags |= KBD_SYNC_KANA_LOCK; + + mouseX = 0; + mouseY = 0; + + input->FocusInEvent(input, syncFlags, mouseX, mouseY); +} + static int wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { int delta; @@ -229,6 +258,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA); wfc = (wfContext*) ptr; + if (wfc != NULL) { input = wfc->instance->input; @@ -255,7 +285,10 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam // Set maximum window size for resizing minmax = (MINMAXINFO*) lParam; - wf_update_canvas_diff(wfc); + + //always use the last determined canvas diff, because it could be + //that the window is minimized when this gets called + //wf_update_canvas_diff(wfc); if (!wfc->fullscreen) { @@ -281,11 +314,14 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam wfc->client_y = windowRect.top; } - wf_size_scrollbars(wfc, LOWORD(lParam), HIWORD(lParam)); + if (wfc->client_width && wfc->client_height) + { + wf_size_scrollbars(wfc, LOWORD(lParam), HIWORD(lParam)); - // Workaround: when the window is maximized, the call to "ShowScrollBars" returns TRUE but has no effect. - if (wParam == SIZE_MAXIMIZED && !wfc->fullscreen) - SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_NOMOVE | SWP_FRAMECHANGED); + // Workaround: when the window is maximized, the call to "ShowScrollBars" returns TRUE but has no effect. + if (wParam == SIZE_MAXIMIZED && !wfc->fullscreen) + SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_NOMOVE | SWP_FRAMECHANGED); + } break; @@ -533,6 +569,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam if (alt_ctrl_down()) g_flipping_in = TRUE; g_focus_hWnd = hWnd; + freerdp_set_focus(wfc->instance); break; case WM_KILLFOCUS: diff --git a/client/Windows/wf_event.h b/client/Windows/wf_event.h index e4f1a1d2c..7cd3c57d6 100644 --- a/client/Windows/wf_event.h +++ b/client/Windows/wf_event.h @@ -22,15 +22,17 @@ #ifndef __WF_EVENT_H #define __WF_EVENT_H -#include "wf_interface.h" +#include "wf_client.h" +#include LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +#define KBD_TAG CLIENT_TAG("windows") #ifdef WITH_DEBUG_KBD -#define DEBUG_KBD(fmt, ...) DEBUG_CLASS(KBD, fmt, ## __VA_ARGS__) +#define DEBUG_KBD(fmt, ...) WLog_DBG(KBD_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_KBD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_KBD(fmt, ...) do { } while (0) #endif #endif /* __WF_EVENT_H */ diff --git a/client/Windows/wf_floatbar.c b/client/Windows/wf_floatbar.c index a6e960166..e87815db8 100644 --- a/client/Windows/wf_floatbar.c +++ b/client/Windows/wf_floatbar.c @@ -17,15 +17,15 @@ * limitations under the License. */ -#include -#include +#include +#include -#include "wf_interface.h" -#include "wf_floatbar.h" -#include "wf_window.h" -#include "wf_gdi.h" #include "resource.h" +#include "wf_client.h" +#include "wf_floatbar.h" +#include "wf_gdi.h" + typedef struct _Button Button; /* TIMERs */ diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 1c87072c4..e08d1fadb 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -35,10 +36,12 @@ #include #include -#include "wf_interface.h" +#include "wf_client.h" #include "wf_graphics.h" #include "wf_gdi.h" +#define TAG CLIENT_TAG("windows.gdi") + const BYTE wf_rop2_table[] = { R2_BLACK, /* 0 */ @@ -63,7 +66,7 @@ BOOL wf_set_rop2(HDC hdc, int rop2) { if ((rop2 < 0x01) || (rop2 > 0x10)) { - fprintf(stderr, "Unsupported ROP2: %d\n", rop2); + WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); return FALSE; } @@ -339,6 +342,106 @@ void wf_toggle_fullscreen(wfContext* wfc) } } +void wf_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) +{ + HDC hdc; + int status; + int nXDst; + int nYDst; + int nXSrc; + int nYSrc; + int nWidth; + int nHeight; + HBITMAP dib; + UINT32 index; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + BOOL compressed; + UINT32 SrcFormat; + UINT32 bitsPerPixel; + UINT32 bytesPerPixel; + BITMAP_DATA* bitmap; + rdpCodecs* codecs = context->codecs; + wfContext* wfc = (wfContext*) context; + + hdc = CreateCompatibleDC(GetDC(NULL)); + + for (index = 0; index < bitmapUpdate->number; index++) + { + bitmap = &(bitmapUpdate->rectangles[index]); + + nXSrc = 0; + nYSrc = 0; + + nXDst = bitmap->destLeft; + nYDst = bitmap->destTop; + + nWidth = bitmap->width; + nHeight = bitmap->height; + + pSrcData = bitmap->bitmapDataStream; + SrcSize = bitmap->bitmapLength; + + compressed = bitmap->compressed; + bitsPerPixel = bitmap->bitsPerPixel; + bytesPerPixel = (bitsPerPixel + 7) / 8; + + SrcFormat = gdi_get_pixel_format(bitsPerPixel, TRUE); + + if (wfc->bitmap_size < (nWidth * nHeight * 4)) + { + wfc->bitmap_size = nWidth * nHeight * 4; + wfc->bitmap_buffer = (BYTE*) _aligned_realloc(wfc->bitmap_buffer, wfc->bitmap_size, 16); + + if (!wfc->bitmap_buffer) + return; + } + + if (compressed) + { + pDstData = wfc->bitmap_buffer; + + if (bitsPerPixel < 32) + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(codecs->interleaved, pSrcData, SrcSize, bitsPerPixel, + &pDstData, PIXEL_FORMAT_XRGB32, nWidth * 4, 0, 0, nWidth, nHeight, NULL); + } + else + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(codecs->planar, pSrcData, SrcSize, &pDstData, + PIXEL_FORMAT_XRGB32, nWidth * 4, 0, 0, nWidth, nHeight, TRUE); + } + + if (status < 0) + { + WLog_ERR(TAG, "bitmap decompression failure"); + return; + } + + pSrcData = wfc->bitmap_buffer; + } + + dib = wf_create_dib(wfc, nWidth, nHeight, 32, pSrcData, NULL); + SelectObject(hdc, dib); + + nWidth = bitmap->destRight - bitmap->destLeft + 1; /* clip width */ + nHeight = bitmap->destBottom - bitmap->destTop + 1; /* clip height */ + + BitBlt(wfc->primary->hdc, nXDst, nYDst, nWidth, nHeight, hdc, 0, 0, SRCCOPY); + + gdi_InvalidateRegion(wfc->hdc, nXDst, nYDst, nWidth, nHeight); + + DeleteObject(dib); + } + + ReleaseDC(NULL, hdc); +} + void wf_gdi_palette_update(wfContext* wfc, PALETTE_UPDATE* palette) { @@ -453,12 +556,12 @@ void wf_gdi_multi_opaque_rect(wfContext* wfc, MULTI_OPAQUE_RECT_ORDER* multi_opa UINT32 brush_color; DELTA_RECT* rectangle; + brush_color = freerdp_color_convert_var_rgb(multi_opaque_rect->color, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); + for (i = 1; i < (int) multi_opaque_rect->numRectangles + 1; i++) { rectangle = &multi_opaque_rect->rectangles[i]; - brush_color = freerdp_color_convert_var_bgr(multi_opaque_rect->color, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); - rect.left = rectangle->left; rect.top = rectangle->top; rect.right = rectangle->left + rectangle->width; @@ -568,15 +671,13 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm RFX_MESSAGE* message; BITMAPINFO bitmap_info; - RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) wfc->rfx_context; - NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) wfc->nsc_context; - tile_bitmap = (char*) malloc(32); ZeroMemory(tile_bitmap, 32); if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX) { - message = rfx_process_message(rfx_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_REMOTEFX); + message = rfx_process_message(wfc->codecs->rfx, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); /* blit each tile */ for (i = 0; i < message->numTiles; i++) @@ -607,11 +708,12 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm wf_invalidate_region(wfc, tx, ty, message->rects[i].width, message->rects[i].height); } - rfx_message_free(rfx_context, message); + rfx_message_free(wfc->codecs->rfx, message); } else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC) { - nsc_process_message(nsc_context, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_NSCODEC); + nsc_process_message(wfc->codecs->nsc, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); ZeroMemory(&bitmap_info, sizeof(bitmap_info)); bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -622,7 +724,7 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm bitmap_info.bmiHeader.biCompression = BI_RGB; SetDIBitsToDevice(wfc->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, 0, 0, 0, surface_bits_command->height, - nsc_context->BitmapData, &bitmap_info, DIB_RGB_COLORS); + wfc->codecs->nsc->BitmapData, &bitmap_info, DIB_RGB_COLORS); wf_invalidate_region(wfc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height); } @@ -643,7 +745,7 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm } else { - fprintf(stderr, "Unsupported codecID %d\n", surface_bits_command->codecID); + WLog_ERR(TAG, "Unsupported codecID %d", surface_bits_command->codecID); } if (tile_bitmap != NULL) diff --git a/client/Windows/wf_gdi.h b/client/Windows/wf_gdi.h index b7ab1cfda..218e1a38b 100644 --- a/client/Windows/wf_gdi.h +++ b/client/Windows/wf_gdi.h @@ -22,7 +22,7 @@ #ifndef __WF_GDI_H #define __WF_GDI_H -#include "wf_interface.h" +#include "wf_client.h" void wf_invalidate_region(wfContext* wfc, int x, int y, int width, int height); wfBitmap* wf_image_new(wfContext* wfc, int width, int height, int bpp, BYTE* data); @@ -31,6 +31,7 @@ void wf_update_offset(wfContext* wfc); void wf_resize_window(wfContext* wfc); void wf_toggle_fullscreen(wfContext* wfc); +void wf_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate); void wf_gdi_register_update_callbacks(rdpUpdate* update); void wf_update_canvas_diff(wfContext* wfc); diff --git a/client/Windows/wf_graphics.c b/client/Windows/wf_graphics.c index 98c42b468..ab3f3b5f6 100644 --- a/client/Windows/wf_graphics.c +++ b/client/Windows/wf_graphics.c @@ -23,11 +23,14 @@ #include -#include +#include +#include #include "wf_gdi.h" #include "wf_graphics.h" +#define TAG CLIENT_TAG("windows") + HBITMAP wf_create_dib(wfContext* wfc, int width, int height, int bpp, BYTE* data, BYTE** pdata) { HDC hdc; @@ -142,36 +145,62 @@ void wf_Bitmap_Paint(wfContext* wfc, rdpBitmap* bitmap) } void wf_Bitmap_Decompress(wfContext* wfc, rdpBitmap* bitmap, - BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codec_id) + BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codecId) { + int status; UINT16 size; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + UINT32 SrcFormat; + UINT32 bytesPerPixel; - size = width * height * (bpp / 8); + bytesPerPixel = (bpp + 7) / 8; + size = width * height * 4; - if (bitmap->data == NULL) - bitmap->data = (BYTE*) malloc(size); + if (!bitmap->data) + bitmap->data = (BYTE*) _aligned_malloc(size, 16); else - bitmap->data = (BYTE*) realloc(bitmap->data, size); + bitmap->data = (BYTE*) _aligned_realloc(bitmap->data, size, 16); + + pSrcData = data; + SrcSize = (UINT32) length; + pDstData = bitmap->data; if (compressed) { - BOOL status; - - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - - if (status != TRUE) + if (bpp < 32) { - fprintf(stderr, "Bitmap Decompression Failed\n"); + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(wfc->codecs->interleaved, pSrcData, SrcSize, bpp, + &pDstData, PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, NULL); + } + else + { + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(wfc->codecs->planar, pSrcData, SrcSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, TRUE); + } + + if (status < 0) + { + WLog_ERR(TAG, "Bitmap Decompression Failed"); + return; } } else { - freerdp_image_flip(data, bitmap->data, width, height, bpp); + SrcFormat = gdi_get_pixel_format(bpp, TRUE); + + status = freerdp_image_copy(pDstData, PIXEL_FORMAT_XRGB32, width * 4, 0, 0, + width, height, pSrcData, SrcFormat, width * bytesPerPixel, 0, 0, NULL); } bitmap->compressed = FALSE; bitmap->length = size; - bitmap->bpp = bpp; + bitmap->bpp = 32; } void wf_Bitmap_SetSurface(wfContext* wfc, rdpBitmap* bitmap, BOOL primary) @@ -254,20 +283,12 @@ void wf_Pointer_SetDefault(wfContext* wfc) } -/* Graphics Module */ - -void wf_register_graphics(rdpGraphics* graphics) +void wf_register_pointer(rdpGraphics* graphics) { - rdpBitmap bitmap; + wfContext* wfc; rdpPointer pointer; - ZeroMemory(&bitmap, sizeof(rdpBitmap)); - bitmap.size = sizeof(wfBitmap); - bitmap.New = (pBitmap_New) wf_Bitmap_New; - bitmap.Free = (pBitmap_Free) wf_Bitmap_Free; - bitmap.Paint = (pBitmap_Paint) wf_Bitmap_Paint; - bitmap.Decompress = (pBitmap_Decompress) wf_Bitmap_Decompress; - bitmap.SetSurface = (pBitmap_SetSurface) wf_Bitmap_SetSurface; + wfc = (wfContext*) graphics->context; ZeroMemory(&pointer, sizeof(rdpPointer)); pointer.size = sizeof(wfPointer); @@ -277,6 +298,25 @@ void wf_register_graphics(rdpGraphics* graphics) pointer.SetNull = (pPointer_SetNull) wf_Pointer_SetNull; pointer.SetDefault = (pPointer_SetDefault) wf_Pointer_SetDefault; - graphics_register_bitmap(graphics, &bitmap); graphics_register_pointer(graphics, &pointer); } + +/* Graphics Module */ + +void wf_register_graphics(rdpGraphics* graphics) +{ + wfContext* wfc; + rdpBitmap bitmap; + + wfc = (wfContext*) graphics->context; + + ZeroMemory(&bitmap, sizeof(rdpBitmap)); + bitmap.size = sizeof(wfBitmap); + bitmap.New = (pBitmap_New) wf_Bitmap_New; + bitmap.Free = (pBitmap_Free) wf_Bitmap_Free; + bitmap.Paint = (pBitmap_Paint) wf_Bitmap_Paint; + bitmap.Decompress = (pBitmap_Decompress) wf_Bitmap_Decompress; + bitmap.SetSurface = (pBitmap_SetSurface) wf_Bitmap_SetSurface; + + graphics_register_bitmap(graphics, &bitmap); +} diff --git a/client/Windows/wf_graphics.h b/client/Windows/wf_graphics.h index a27c6a679..4b0dd69d0 100644 --- a/client/Windows/wf_graphics.h +++ b/client/Windows/wf_graphics.h @@ -20,12 +20,13 @@ #ifndef __WF_GRAPHICS_H #define __WF_GRAPHICS_H -#include "wf_interface.h" +#include "wf_client.h" HBITMAP wf_create_dib(wfContext* wfc, int width, int height, int bpp, BYTE* data, BYTE** pdata); wfBitmap* wf_image_new(wfContext* wfc, int width, int height, int bpp, BYTE* data); void wf_image_free(wfBitmap* image); +void wf_register_pointer(rdpGraphics* graphics); void wf_register_graphics(rdpGraphics* graphics); #endif /* WF_GRAPHICS */ diff --git a/client/Windows/wf_rail.c b/client/Windows/wf_rail.c index a776828fc..f50ef63ae 100644 --- a/client/Windows/wf_rail.c +++ b/client/Windows/wf_rail.c @@ -21,12 +21,12 @@ #include "config.h" #endif -#include #include + +#include #include #include -#include "wf_window.h" #include "wf_rail.h" void wf_rail_paint(wfContext* wfc, rdpRail* rail, INT32 uleft, INT32 utop, UINT32 uright, UINT32 ubottom) diff --git a/client/Windows/wf_rail.h b/client/Windows/wf_rail.h index e4cbcec4a..16e505496 100644 --- a/client/Windows/wf_rail.h +++ b/client/Windows/wf_rail.h @@ -19,7 +19,7 @@ #ifndef __WF_RAIL_H #define __WF_RAIL_H -#include "wf_interface.h" +#include "wf_client.h" void wf_rail_paint(wfContext* wfc, rdpRail* rail, INT32 uleft, INT32 utop, UINT32 uright, UINT32 ubottom); void wf_rail_register_callbacks(wfContext* wfc, rdpRail* rail); diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 6c004e678..a6bd5b5cf 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -59,7 +59,10 @@ if(WITH_CLIENT_INTERFACE) else() add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) endif() - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") + if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) + endif() + set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/xfreerdp.c cli/xfreerdp.h) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) @@ -86,16 +89,7 @@ if(WITH_MANPAGES) add_executable(generate_argument_docbook generate_argument_docbook.c) set(GAD_LIBS freerdp-client) - - set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) - - set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-utils) - - target_link_libraries(generate_argument_docbook ${GAD_LIBS}) + target_link_libraries(generate_argument_docbook ${GAD_LIBS} freerdp winpr) add_custom_command(OUTPUT xfreerdp.1 COMMAND generate_argument_docbook @@ -148,6 +142,10 @@ set(XRENDER_FEATURE_TYPE "RECOMMENDED") set(XRENDER_FEATURE_PURPOSE "rendering") set(XRENDER_FEATURE_DESCRIPTION "X11 render extension") +set(XFIXES_FEATURE_TYPE "RECOMMENDED") +set(XFIXES_FEATURE_PURPOSE "X11 xfixes extension") +set(XFIXES_FEATURE_DESCRIPTION "Useful additions to the X11 core protocol") + find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION}) find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION}) find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION}) @@ -155,6 +153,7 @@ find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSO find_feature(Xv ${XV_FEATURE_TYPE} ${XV_FEATURE_PURPOSE} ${XV_FEATURE_DESCRIPTION}) find_feature(Xi ${XI_FEATURE_TYPE} ${XI_FEATURE_PURPOSE} ${XI_FEATURE_DESCRIPTION}) find_feature(Xrender ${XRENDER_FEATURE_TYPE} ${XRENDER_FEATURE_PURPOSE} ${XRENDER_FEATURE_DESCRIPTION}) +find_feature(Xfixes ${XFIXES_FEATURE_TYPE} ${XFIXES_FEATURE_PURPOSE} ${XFIXES_FEATURE_DESCRIPTION}) if(WITH_XINERAMA) add_definitions(-DWITH_XINERAMA) @@ -192,14 +191,15 @@ if(WITH_XRENDER) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRENDER_LIBRARIES}) endif() +if(WITH_XFIXES) + add_definitions(-DWITH_XFIXES) + include_directories(${XFIXES_INCLUDE_DIRS}) + set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XFIXES_LIBRARIES}) +endif() + include_directories(${CMAKE_SOURCE_DIR}/resources) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-primitives freerdp-rail freerdp-utils) - +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp freerdp-client) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) if(WITH_IPP) diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c index 4b49f34da..22abed391 100644 --- a/client/X11/generate_argument_docbook.c +++ b/client/X11/generate_argument_docbook.c @@ -26,7 +26,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not allocate string buffer."); + WLog_ERR(TAG, "Could not allocate string buffer."); exit(-2); } /* Copy character for character and check, if it is necessary to escape. */ @@ -40,7 +40,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer."); + WLog_ERR(TAG, "Could not reallocate string buffer."); exit(-3); } tmp[cs++] = '&'; @@ -53,7 +53,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer."); + WLog_ERR(TAG, "Could not reallocate string buffer."); exit(-4); } tmp[cs++] = '&'; @@ -66,7 +66,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer."); + WLog_ERR(TAG, "Could not reallocate string buffer."); exit(-5); } tmp[cs++] = '&'; @@ -81,7 +81,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer."); + WLog_ERR(TAG, "Could not reallocate string buffer."); exit(-6); } tmp[cs++] = '&'; @@ -96,7 +96,7 @@ LPSTR tr_esc_str(LPCSTR arg) tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); if(NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer."); + WLog_ERR(TAG, "Could not reallocate string buffer."); exit(-7); } tmp[cs++] = '&'; @@ -125,7 +125,7 @@ int main(int argc, char *argv[]) fp = fopen(fname, "w"); if(NULL == fp) { - fprintf(stderr, "Could not open '%s' for writing.", fname); + WLog_ERR(TAG, "Could not open '%s' for writing.", fname); return -1; } /* The tag used as header in the manpage */ @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) * compatible XML */ if(elements < 2) { - fprintf(stderr, "The argument array 'args' is empty, writing an empty file."); + WLog_ERR(TAG, "The argument array 'args' is empty, writing an empty file."); elements = 1; } for(x=0; xsettings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -38,13 +40,25 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); + if (settings->SoftwareGdi) + gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); + else + xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + xf_cliprdr_init(xfc, (CliprdrClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface); } } void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) { xfContext* xfc = (xfContext*) context; + rdpSettings* settings = context->settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -52,6 +66,17 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); + if (settings->SoftwareGdi) + gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); + else + xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + xf_cliprdr_uninit(xfc, (CliprdrClientContext*) e->pInterface); + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + xf_encomsp_uninit(xfc, (EncomspClientContext*) e->pInterface); } } diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index dd5969d62..96fd3e52d 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 8011e6a82..121b7fca3 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -51,6 +51,8 @@ #include #endif +#include + #include #include #include @@ -85,6 +87,7 @@ #include #include #include +#include #include "xf_gdi.h" #include "xf_rail.h" @@ -98,6 +101,8 @@ #include "xf_input.h" #include "xf_channels.h" #include "xfreerdp.h" +#include +#define TAG CLIENT_TAG("x11") static long xv_port = 0; static const size_t password_size = 512; @@ -180,31 +185,41 @@ void xf_draw_screen_scaled(xfContext *xfc, int x, int y, int w, int h, BOOL scal void xf_sw_begin_paint(rdpContext *context) { - rdpGdi *gdi = context->gdi; + rdpGdi* gdi = context->gdi; gdi->primary->hdc->hwnd->invalid->null = 1; gdi->primary->hdc->hwnd->ninvalid = 0; } void xf_sw_end_paint(rdpContext *context) { - rdpGdi *gdi; + int i; INT32 x, y; UINT32 w, h; - xfContext *xfc = (xfContext *) context; - gdi = context->gdi; - if(!xfc->remote_app) + int ninvalid; + HGDI_RGN cinvalid; + xfContext* xfc = (xfContext*) context; + rdpGdi* gdi = context->gdi; + + x = gdi->primary->hdc->hwnd->invalid->x; + y = gdi->primary->hdc->hwnd->invalid->y; + w = gdi->primary->hdc->hwnd->invalid->w; + h = gdi->primary->hdc->hwnd->invalid->h; + + ninvalid = gdi->primary->hdc->hwnd->ninvalid; + cinvalid = gdi->primary->hdc->hwnd->cinvalid; + + if (!xfc->remote_app) { - if(!xfc->complex_regions) + if (!xfc->complex_regions) { - if(gdi->primary->hdc->hwnd->invalid->null) + if (gdi->primary->hdc->hwnd->invalid->null) return; - x = gdi->primary->hdc->hwnd->invalid->x; - y = gdi->primary->hdc->hwnd->invalid->y; - w = gdi->primary->hdc->hwnd->invalid->w; - h = gdi->primary->hdc->hwnd->invalid->h; + xf_lock_x11(xfc, FALSE); + XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) + + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -212,27 +227,26 @@ void xf_sw_end_paint(rdpContext *context) { XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y); } + xf_unlock_x11(xfc, FALSE); } else { - int i; - int ninvalid; - HGDI_RGN cinvalid; - if(gdi->primary->hdc->hwnd->ninvalid < 1) + if (gdi->primary->hdc->hwnd->ninvalid < 1) return; - ninvalid = gdi->primary->hdc->hwnd->ninvalid; - cinvalid = gdi->primary->hdc->hwnd->cinvalid; + xf_lock_x11(xfc, FALSE); - for(i = 0; i < ninvalid; i++) + + for (i = 0; i < ninvalid; i++) { x = cinvalid[i].x; y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - //combine xfc->primary with xfc->image + XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) + + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -241,48 +255,52 @@ void xf_sw_end_paint(rdpContext *context) XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y); } } + XFlush(xfc->display); + xf_unlock_x11(xfc, FALSE); } } else { - if(gdi->primary->hdc->hwnd->invalid->null) + if (gdi->primary->hdc->hwnd->invalid->null) return; - x = gdi->primary->hdc->hwnd->invalid->x; - y = gdi->primary->hdc->hwnd->invalid->y; - w = gdi->primary->hdc->hwnd->invalid->w; - h = gdi->primary->hdc->hwnd->invalid->h; + xf_lock_x11(xfc, FALSE); + xf_rail_paint(xfc, context->rail, x, y, x + w - 1, y + h - 1); + xf_unlock_x11(xfc, FALSE); } } -void xf_sw_desktop_resize(rdpContext *context) +void xf_sw_desktop_resize(rdpContext* context) { - rdpSettings *settings; - xfContext *xfc = (xfContext *) context; - settings = xfc->instance->settings; + rdpGdi* gdi = context->gdi; + xfContext* xfc = (xfContext*) context; + xf_lock_x11(xfc, TRUE); - if(!xfc->fullscreen) + + if (!xfc->fullscreen) { - rdpGdi *gdi = context->gdi; gdi_resize(gdi, xfc->width, xfc->height); - if(xfc->image) + + if (xfc->image) { xfc->image->data = NULL; XDestroyImage(xfc->image); + xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char *) gdi->primary_buffer, gdi->width, gdi->height, xfc->scanline_pad, 0); + (char*) gdi->primary_buffer, gdi->width, gdi->height, xfc->scanline_pad, 0); } } + xf_unlock_x11(xfc, TRUE); } void xf_hw_begin_paint(rdpContext *context) { - xfContext *xfc = (xfContext *) context; + xfContext* xfc = (xfContext*) context; xfc->hdc->hwnd->invalid->null = 1; xfc->hdc->hwnd->ninvalid = 0; } @@ -291,19 +309,23 @@ void xf_hw_end_paint(rdpContext *context) { INT32 x, y; UINT32 w, h; - xfContext *xfc = (xfContext *) context; - if(!xfc->remote_app) + xfContext* xfc = (xfContext*) context; + + if (!xfc->remote_app) { - if(!xfc->complex_regions) + if (!xfc->complex_regions) { - if(xfc->hdc->hwnd->invalid->null) + if (xfc->hdc->hwnd->invalid->null) return; + x = xfc->hdc->hwnd->invalid->x; y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; + xf_lock_x11(xfc, FALSE); - if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) + + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -311,6 +333,7 @@ void xf_hw_end_paint(rdpContext *context) { XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y); } + xf_unlock_x11(xfc, FALSE); } else @@ -318,18 +341,23 @@ void xf_hw_end_paint(rdpContext *context) int i; int ninvalid; HGDI_RGN cinvalid; - if(xfc->hdc->hwnd->ninvalid < 1) + + if (xfc->hdc->hwnd->ninvalid < 1) return; + ninvalid = xfc->hdc->hwnd->ninvalid; cinvalid = xfc->hdc->hwnd->cinvalid; + xf_lock_x11(xfc, FALSE); - for(i = 0; i < ninvalid; i++) + + for (i = 0; i < ninvalid; i++) { x = cinvalid[i].x; y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - if((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) + + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } @@ -338,20 +366,26 @@ void xf_hw_end_paint(rdpContext *context) XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y); } } + XFlush(xfc->display); + xf_unlock_x11(xfc, FALSE); } } else { - if(xfc->hdc->hwnd->invalid->null) + if (xfc->hdc->hwnd->invalid->null) return; + x = xfc->hdc->hwnd->invalid->x; y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; + xf_lock_x11(xfc, FALSE); + xf_rail_paint(xfc, context->rail, x, y, x + w - 1, y + h - 1); + xf_unlock_x11(xfc, FALSE); } } @@ -362,19 +396,24 @@ void xf_hw_desktop_resize(rdpContext *context) rdpSettings *settings; xfContext *xfc = (xfContext *) context; settings = xfc->instance->settings; + xf_lock_x11(xfc, TRUE); - if(!xfc->fullscreen) + + if (!xfc->fullscreen) { xfc->width = settings->DesktopWidth; xfc->height = settings->DesktopHeight; - if(xfc->window) + + if (xfc->window) xf_ResizeDesktopWindow(xfc, xfc->window, settings->DesktopWidth, settings->DesktopHeight); - if(xfc->primary) + + if (xfc->primary) { same = (xfc->primary == xfc->drawing) ? TRUE : FALSE; XFreePixmap(xfc->display, xfc->primary); - xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, - xfc->width, xfc->height, xfc->depth); + + xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, xfc->width, xfc->height, xfc->depth); + if(same) xfc->drawing = xfc->primary; } @@ -386,6 +425,7 @@ void xf_hw_desktop_resize(rdpContext *context) XSetForeground(xfc->display, xfc->gc, 0); XFillRectangle(xfc->display, xfc->drawable, xfc->gc, 0, 0, xfc->width, xfc->height); } + xf_unlock_x11(xfc, TRUE); } @@ -468,7 +508,7 @@ void xf_create_window(xfContext *xfc) } } -void xf_toggle_fullscreen(xfContext *xfc) +void xf_toggle_fullscreen(xfContext* xfc) { Pixmap contents = 0; WindowStateChangeEventArgs e; @@ -486,6 +526,53 @@ void xf_toggle_fullscreen(xfContext *xfc) PubSub_OnWindowStateChange(((rdpContext *) xfc)->pubSub, xfc, &e); } +void xf_toggle_control(xfContext* xfc) +{ + EncomspClientContext* encomsp; + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + encomsp = xfc->encomsp; + + if (!encomsp) + return; + + pdu.ParticipantId = 0; + pdu.Flags = ENCOMSP_REQUEST_VIEW; + + if (!xfc->controlToggle) + pdu.Flags |= ENCOMSP_REQUEST_INTERACT; + + encomsp->ChangeParticipantControlLevel(encomsp, &pdu); + + xfc->controlToggle = !xfc->controlToggle; +} + +int xf_encomsp_participant_created(EncomspClientContext* context, ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +{ +#if 0 + xfContext* xfc = (xfContext*) context->custom; + + WLog_INFO(TAG, "ParticipantCreated: ParticipantId: %d GroupId: %d Flags: 0x%04X xfc: %p", + (int) participantCreated->ParticipantId, (int) participantCreated->GroupId, + (int) participantCreated->Flags, xfc); +#endif + + return 1; +} + +void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp) +{ + xfc->encomsp = encomsp; + encomsp->custom = (void*) xfc; + + encomsp->ParticipantCreated = xf_encomsp_participant_created; +} + +void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp) +{ + xfc->encomsp = NULL; +} + void xf_lock_x11(xfContext *xfc, BOOL display) { if(!xfc->UseXThreads) @@ -526,7 +613,7 @@ BOOL xf_get_pixmap_info(xfContext *xfc) pfs = XListPixmapFormats(xfc->display, &pf_count); if(pfs == NULL) { - fprintf(stderr, "xf_get_pixmap_info: XListPixmapFormats failed\n"); + WLog_ERR(TAG, "XListPixmapFormats failed"); return 1; } for(i = 0; i < pf_count; i++) @@ -545,13 +632,13 @@ BOOL xf_get_pixmap_info(xfContext *xfc) template.screen = xfc->screen_number; if(XGetWindowAttributes(xfc->display, RootWindowOfScreen(xfc->screen), &window_attributes) == 0) { - fprintf(stderr, "xf_get_pixmap_info: XGetWindowAttributes failed\n"); + WLog_ERR(TAG, "XGetWindowAttributes failed"); return FALSE; } vis = XGetVisualInfo(xfc->display, VisualClassMask | VisualScreenMask, &template, &vi_count); if(vis == NULL) { - fprintf(stderr, "xf_get_pixmap_info: XGetVisualInfo failed\n"); + WLog_ERR(TAG, "XGetVisualInfo failed"); return FALSE; } vi = NULL; @@ -590,7 +677,7 @@ int xf_error_handler(Display *d, XErrorEvent *ev) char buf[256]; int do_abort = TRUE; XGetErrorText(d, ev->error_code, buf, sizeof(buf)); - fprintf(stderr, "%s", buf); + WLog_ERR(TAG, "%s", buf); if(do_abort) abort(); _def_error_handler(d, ev); @@ -623,6 +710,24 @@ static void xf_post_disconnect(freerdp *instance) xf_monitors_free(xfc, instance->settings); } +static void xf_play_sound(rdpContext* context, PLAY_SOUND_UPDATE* play_sound) +{ + xfContext* xfc = (xfContext*) context; + XkbBell(xfc->display, None, 100, 0); +} + +void xf_check_extensions(xfContext *context) +{ + int xkb_opcode, xkb_event, xkb_error; + int xkb_major = XkbMajorVersion; + int xkb_minor = XkbMinorVersion; + if (XkbLibraryVersion( &xkb_major, &xkb_minor ) && XkbQueryExtension(context->display, &xkb_opcode, &xkb_event, + &xkb_error, &xkb_major, &xkb_minor)) + { + context->xkbAvailable = TRUE; + } +} + /** * Callback given to freerdp_connect() to process the pre-connect operations. * It will fill the rdp_freerdp structure (instance) with the appropriate options to use for the connection. @@ -633,17 +738,22 @@ static void xf_post_disconnect(freerdp *instance) * @return TRUE if successful. FALSE otherwise. * Can exit with error code XF_EXIT_PARSE_ARGUMENTS if there is an error in the parameters. */ -BOOL xf_pre_connect(freerdp *instance) +BOOL xf_pre_connect(freerdp* instance) { - rdpChannels *channels; - rdpSettings *settings; - xfContext *xfc = (xfContext *) instance->context; + rdpChannels* channels; + rdpSettings* settings; + xfContext* xfc = (xfContext*) instance->context; + + xfc->codecs = instance->context->codecs; xfc->settings = instance->settings; xfc->instance = instance; + settings = instance->settings; channels = instance->context->channels; + settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; + ZeroMemory(settings->OrderSupport, 32); settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; @@ -669,52 +779,64 @@ BOOL xf_pre_connect(freerdp *instance) settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; + xfc->UseXThreads = TRUE; - if(xfc->UseXThreads) + + if (xfc->UseXThreads) { if(!XInitThreads()) { - fprintf(stderr, "warning: XInitThreads() failure\n"); + WLog_WARN(TAG, "XInitThreads() failure"); xfc->UseXThreads = FALSE; } } + xfc->display = XOpenDisplay(NULL); - if(!xfc->display) + + if (!xfc->display) { - fprintf(stderr, "xf_pre_connect: failed to open display: %s\n", XDisplayName(NULL)); - fprintf(stderr, "Please check that the $DISPLAY environment variable is properly set.\n"); + WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL)); + WLog_ERR(TAG, "Please check that the $DISPLAY environment variable is properly set."); return FALSE; } - if(xfc->debug) + + if (xfc->debug) { - fprintf(stderr, "Enabling X11 debug mode.\n"); + WLog_INFO(TAG, "Enabling X11 debug mode."); XSynchronize(xfc->display, TRUE); _def_error_handler = XSetErrorHandler(_xf_error_handler); } + + xf_check_extensions(xfc); + xfc->mutex = CreateMutex(NULL, FALSE, NULL); + PubSub_SubscribeChannelConnected(instance->context->pubSub, - (pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler); + (pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, - (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); + (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); + freerdp_client_load_addins(channels, instance->settings); freerdp_channels_pre_connect(channels, instance); - if(settings->AuthenticationOnly) + + if (settings->AuthenticationOnly) { /* Check --authonly has a username and password. */ - if(settings->Username == NULL) + if (!settings->Username) { - fprintf(stderr, "--authonly, but no -u username. Please provide one.\n"); + WLog_INFO(TAG, "--authonly, but no -u username. Please provide one."); return FALSE; } - if(settings->Password == NULL) + + if (!settings->Password) { - fprintf(stderr, "--authonly, but no -p password. Please provide one.\n"); + WLog_INFO(TAG, "--authonly, but no -p password. Please provide one."); return FALSE; } - fprintf(stderr, "Authentication only. Don't connect to X.\n"); - /* Avoid XWindows initialization and configuration below. */ - return TRUE; + + WLog_INFO(TAG, "Authentication only. Don't connect to X."); } + xfc->_NET_WM_ICON = XInternAtom(xfc->display, "_NET_WM_ICON", False); xfc->_MOTIF_WM_HINTS = XInternAtom(xfc->display, "_MOTIF_WM_HINTS", False); xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP", False); @@ -734,19 +856,39 @@ BOOL xf_pre_connect(freerdp *instance) xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False); xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False); xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False); + xf_keyboard_init(xfc); + xfc->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA); instance->context->cache = cache_new(instance->settings); + xfc->xfds = ConnectionNumber(xfc->display); xfc->screen_number = DefaultScreen(xfc->display); xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number); xfc->depth = DefaultDepthOfScreen(xfc->screen); xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst); + xfc->invert = (ImageByteOrder(xfc->display) == MSBFirst) ? TRUE : FALSE; xfc->complex_regions = TRUE; xfc->fullscreen = settings->Fullscreen; xfc->grab_keyboard = settings->GrabKeyboard; xfc->fullscreen_toggle = settings->ToggleFullscreen; + xf_detect_monitors(xfc, settings); + xfc->colormap = DefaultColormap(xfc->display, xfc->screen_number); + + xfc->format = PIXEL_FORMAT_XRGB32; + + if (xfc->depth == 32) + xfc->format = (!xfc->invert) ? PIXEL_FORMAT_XRGB32 : PIXEL_FORMAT_XBGR32; + else if (xfc->depth == 24) + xfc->format = (!xfc->invert) ? PIXEL_FORMAT_XRGB32 : PIXEL_FORMAT_XBGR32; + else if (xfc->depth == 16) + xfc->format = (!xfc->invert) ? PIXEL_FORMAT_RGB565 : PIXEL_FORMAT_BGR565; + else if (xfc->depth == 15) + xfc->format = (!xfc->invert) ? PIXEL_FORMAT_RGB555 : PIXEL_FORMAT_BGR555; + else + xfc->format = PIXEL_FORMAT_XRGB32; + return TRUE; } @@ -758,9 +900,9 @@ BOOL xf_pre_connect(freerdp *instance) BOOL xf_post_connect(freerdp *instance) { XGCValues gcv; - rdpCache *cache; - rdpChannels *channels; - rdpSettings *settings; + rdpCache* cache; + rdpChannels* channels; + rdpSettings* settings; ResizeWindowEventArgs e; xfContext* xfc = (xfContext*) instance->context; @@ -773,36 +915,27 @@ BOOL xf_post_connect(freerdp *instance) xf_register_graphics(instance->context->graphics); - if (xfc->settings->SoftwareGdi) + if (settings->SoftwareGdi) { - rdpGdi *gdi; + rdpGdi* gdi; UINT32 flags; flags = CLRCONV_ALPHA; - if(xfc->bpp > 16) + + if (xfc->bpp > 16) flags |= CLRBUF_32BPP; else flags |= CLRBUF_16BPP; + gdi_init(instance, flags, NULL); + gdi = instance->context->gdi; xfc->primary_buffer = gdi->primary_buffer; - - xfc->rfx = gdi->rfx_context; } else { - xfc->srcBpp = instance->settings->ColorDepth; + xfc->srcBpp = settings->ColorDepth; xf_gdi_register_update_callbacks(instance->update); xfc->hdc = gdi_CreateDC(xfc->clrconv, xfc->bpp); - - if (instance->settings->RemoteFxCodec) - { - xfc->rfx = rfx_context_new(FALSE); - } - - if (instance->settings->NSCodec) - { - xfc->nsc = nsc_context_new(); - } } xfc->originalWidth = settings->DesktopWidth; @@ -822,7 +955,7 @@ BOOL xf_post_connect(freerdp *instance) ZeroMemory(&gcv, sizeof(gcv)); - if(xfc->modifierMap) + if (xfc->modifierMap) XFreeModifiermap(xfc->modifierMap); xfc->modifierMap = XGetModifierMapping(xfc->display); @@ -836,11 +969,11 @@ BOOL xf_post_connect(freerdp *instance) XSetForeground(xfc->display, xfc->gc, BlackPixelOfScreen(xfc->screen)); XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0, xfc->width, xfc->height); XFlush(xfc->display); + xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char *) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); - xfc->bmp_codec_none = (BYTE *) malloc(64 * 64 * 4); - - if (xfc->settings->SoftwareGdi) + (char*) xfc->primary_buffer, xfc->width, xfc->height, xfc->scanline_pad, 0); + + if (settings->SoftwareGdi) { instance->update->BeginPaint = xf_sw_begin_paint; instance->update->EndPaint = xf_sw_end_paint; @@ -855,21 +988,25 @@ BOOL xf_post_connect(freerdp *instance) pointer_cache_register_callbacks(instance->update); - if (!xfc->settings->SoftwareGdi) + if (!settings->SoftwareGdi) { glyph_cache_register_callbacks(instance->update); brush_cache_register_callbacks(instance->update); bitmap_cache_register_callbacks(instance->update); offscreen_cache_register_callbacks(instance->update); palette_cache_register_callbacks(instance->update); + instance->update->BitmapUpdate = xf_gdi_bitmap_update; } + instance->update->PlaySound = xf_play_sound; + instance->update->SetKeyboardIndicators = xf_keyboard_set_indicators; instance->context->rail = rail_new(instance->settings); rail_register_update_callbacks(instance->context->rail, instance->update); xf_rail_register_callbacks(xfc, instance->context->rail); + + xfc->clipboard = xf_clipboard_new(xfc); freerdp_channels_post_connect(channels, instance); xf_tsmf_init(xfc, xv_port); - xf_cliprdr_init(xfc, channels); EventArgsInit(&e, "xfreerdp"); e.width = settings->DesktopWidth; @@ -914,23 +1051,23 @@ BOOL xf_authenticate(freerdp *instance, char **username, char **password, char * BOOL xf_verify_certificate(freerdp *instance, char *subject, char *issuer, char *fingerprint) { char answer; - printf("Certificate details:\n"); - printf("\tSubject: %s\n", subject); - printf("\tIssuer: %s\n", issuer); - printf("\tThumbprint: %s\n", fingerprint); - printf("The above X.509 certificate could not be verified, possibly because you do not have " + WLog_INFO(TAG, "Certificate details:"); + WLog_INFO(TAG, "\tSubject: %s", subject); + WLog_INFO(TAG, "\tIssuer: %s", issuer); + WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); + WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); + "Please look at the documentation on how to create local certificate store for a private CA."); while(1) { - printf("Do you trust the above certificate? (Y/N) "); + WLog_INFO(TAG, "Do you trust the above certificate? (Y/N) "); answer = fgetc(stdin); if(feof(stdin)) { - printf("\nError: Could not read answer from stdin."); + WLog_INFO(TAG, "Error: Could not read answer from stdin."); if(instance->settings->CredentialsFromStdin) - printf(" - Run without parameter \"--from-stdin\" to set trust."); - printf("\n"); + WLog_INFO(TAG, " - Run without parameter \"--from-stdin\" to set trust."); + WLog_INFO(TAG, ""); return FALSE; } if(answer == 'y' || answer == 'Y') @@ -942,7 +1079,7 @@ BOOL xf_verify_certificate(freerdp *instance, char *subject, char *issuer, char { break; } - printf("\n"); + WLog_INFO(TAG, ""); } return FALSE; } @@ -954,31 +1091,30 @@ int xf_logon_error_info(freerdp *instance, UINT32 data, UINT32 type) return 1; } -void xf_process_channel_event(rdpChannels *channels, freerdp *instance) +void xf_process_channel_event(rdpChannels* channels, freerdp* instance) { - xfContext *xfc; - wMessage *event; - xfc = (xfContext *) instance->context; + xfContext* xfc; + wMessage* event; + xfc = (xfContext*) instance->context; + event = freerdp_channels_pop_event(channels); - if(event) + + if (event) { switch(GetMessageClass(event->id)) { case RailChannel_Class: xf_process_rail_event(xfc, channels, event); break; + case TsmfChannel_Class: xf_process_tsmf_event(xfc, event); break; - case CliprdrChannel_Class: - xf_process_cliprdr_event(xfc, event); - break; - case RdpeiChannel_Class: - xf_process_rdpei_event(xfc, event); - break; + default: break; } + freerdp_event_free(event); } } @@ -1038,24 +1174,6 @@ void xf_window_free(xfContext *xfc) context->rail = NULL; } - if (xfc->rfx) - { - rfx_context_free(xfc->rfx); - xfc->rfx = NULL; - } - - if (xfc->nsc) - { - nsc_context_free(xfc->nsc); - xfc->nsc = NULL; - } - - if (xfc->clear) - { - clear_context_free(xfc->clear); - xfc->clear = NULL; - } - if (xfc->clrconv) { freerdp_clrconv_free(xfc->clrconv); @@ -1073,38 +1191,14 @@ void xf_window_free(xfContext *xfc) xfc->xv_context = NULL; } - if (xfc->clipboard_context) + if (xfc->clipboard) { - xf_cliprdr_uninit(xfc); - xfc->clipboard_context = NULL; + xf_clipboard_free(xfc->clipboard); + xfc->clipboard = NULL; } } -void* xf_update_thread(void *arg) -{ - int status; - wMessage message; - wMessageQueue *queue; - freerdp *instance = (freerdp *) arg; - assert(NULL != instance); - status = 1; - queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - while(MessageQueue_Wait(queue)) - { - while(MessageQueue_Peek(queue, &message, TRUE)) - { - status = freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message); - if(!status) - break; - } - if(!status) - break; - } - ExitThread(0); - return NULL; -} - -void *xf_input_thread(void *arg) +void* xf_input_thread(void *arg) { xfContext *xfc; HANDLE event; @@ -1118,34 +1212,39 @@ void *xf_input_thread(void *arg) assert(NULL != xfc); queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds); - while(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) + + while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { do { xf_lock_x11(xfc, FALSE); pending_status = XPending(xfc->display); xf_unlock_x11(xfc, FALSE); - if(pending_status) + + if (pending_status) { xf_lock_x11(xfc, FALSE); ZeroMemory(&xevent, sizeof(xevent)); XNextEvent(xfc->display, &xevent); process_status = xf_event_process(instance, &xevent); xf_unlock_x11(xfc, FALSE); + if(!process_status) break; } } - while(pending_status); - if(!process_status) + while (pending_status); + + if (!process_status) break; } + MessageQueue_PostQuit(queue, 0); ExitThread(0); return NULL; } -void *xf_channels_thread(void *arg) +void* xf_channels_thread(void *arg) { int status; xfContext *xfc; @@ -1157,13 +1256,17 @@ void *xf_channels_thread(void *arg) assert(NULL != xfc); channels = instance->context->channels; event = freerdp_channels_get_event_handle(instance); - while(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) + + while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { status = freerdp_channels_process_pending_messages(instance); - if(!status) + + if (!status) break; + xf_process_channel_event(channels, instance); } + ExitThread(0); return NULL; } @@ -1177,7 +1280,7 @@ BOOL xf_auto_reconnect(freerdp *instance) if(freerdp_error_info(instance) != 0) return FALSE; /* A network disconnect was detected */ - fprintf(stderr, "Network disconnect!\n"); + WLog_INFO(TAG, "Network disconnect!"); if(!instance->settings->AutoReconnectionEnabled) { /* No auto-reconnect - just quit */ @@ -1192,7 +1295,7 @@ BOOL xf_auto_reconnect(freerdp *instance) return FALSE; } /* Attempt the next reconnect */ - fprintf(stderr, "Attempting reconnect (%u of %u)\n", num_retries, max_retries); + WLog_INFO(TAG, "Attempting reconnect (%u of %u)", num_retries, max_retries); if(freerdp_reconnect(instance)) { xfc->disconnect = FALSE; @@ -1200,7 +1303,7 @@ BOOL xf_auto_reconnect(freerdp *instance) } sleep(5); } - fprintf(stderr, "Maximum reconnect retries exceeded\n"); + WLog_ERR(TAG, "Maximum reconnect retries exceeded"); return FALSE; } @@ -1211,7 +1314,7 @@ BOOL xf_auto_reconnect(freerdp *instance) * @param instance - pointer to the rdp_freerdp structure that contains the session's settings * @return A code from the enum XF_EXIT_CODE (0 if successful) */ -void *xf_thread(void *param) +void* xf_thread(void *param) { int i; int fds; @@ -1229,11 +1332,9 @@ void *xf_thread(void *param) int fd_input_event; HANDLE input_event; int select_status; - BOOL async_update; BOOL async_input; BOOL async_channels; BOOL async_transport; - HANDLE update_thread; HANDLE input_thread; HANDLE channels_thread; rdpChannels *channels; @@ -1253,7 +1354,7 @@ void *xf_thread(void *param) if(instance->settings->AuthenticationOnly) { freerdp_disconnect(instance); - fprintf(stderr, "Authentication only, exit status %d\n", !status); + WLog_ERR(TAG, "Authentication only, exit status %d", !status); ExitThread(exit_code); } if(!status) @@ -1270,14 +1371,10 @@ void *xf_thread(void *param) } channels = instance->context->channels; settings = instance->context->settings; - async_update = settings->AsyncUpdate; async_input = settings->AsyncInput; async_channels = settings->AsyncChannels; async_transport = settings->AsyncTransport; - if(async_update) - { - update_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_update_thread, instance, 0, NULL); - } + if(async_input) { input_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_input_thread, instance, 0, NULL); @@ -1304,7 +1401,7 @@ void *xf_thread(void *param) { if(freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); exit_code = XF_EXIT_CONN_FAILED; break; } @@ -1313,7 +1410,7 @@ void *xf_thread(void *param) { if(freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to get channel manager file descriptor"); exit_code = XF_EXIT_CONN_FAILED; break; } @@ -1322,7 +1419,7 @@ void *xf_thread(void *param) { if(xf_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { - fprintf(stderr, "Failed to get xfreerdp file descriptor\n"); + WLog_ERR(TAG, "Failed to get xfreerdp file descriptor"); exit_code = XF_EXIT_CONN_FAILED; break; } @@ -1359,7 +1456,7 @@ void *xf_thread(void *param) if(!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - fprintf(stderr, "xfreerdp_run: select failed\n"); + WLog_ERR(TAG, "xfreerdp_run: select failed"); break; } } @@ -1369,7 +1466,7 @@ void *xf_thread(void *param) { if(xf_auto_reconnect(instance)) continue; - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } } @@ -1377,7 +1474,7 @@ void *xf_thread(void *param) { if(freerdp_channels_check_fds(channels, instance) != TRUE) { - fprintf(stderr, "Failed to check channel manager file descriptor\n"); + WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } xf_process_channel_event(channels, instance); @@ -1386,7 +1483,7 @@ void *xf_thread(void *param) { if(xf_process_x_events(instance) != TRUE) { - fprintf(stderr, "Closed from X11\n"); + WLog_INFO(TAG, "Closed from X11"); break; } } @@ -1396,7 +1493,7 @@ void *xf_thread(void *param) { if(!freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE)) { - fprintf(stderr, "User Disconnect\n"); + WLog_INFO(TAG, "User Disconnect"); xfc->disconnect = TRUE; break; } @@ -1406,13 +1503,7 @@ void *xf_thread(void *param) /* Close the channels first. This will signal the internal message pipes * that the threads should quit. */ freerdp_channels_close(channels, instance); - if(async_update) - { - wMessageQueue *update_queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - MessageQueue_PostQuit(update_queue, 0); - WaitForSingleObject(update_thread, INFINITE); - CloseHandle(update_thread); - } + if(async_input) { wMessageQueue *input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -1471,22 +1562,29 @@ void xf_TerminateEventHandler(rdpContext *context, TerminateEventArgs *e) static void xf_ScalingFactorChangeEventHandler(rdpContext *context, ScalingFactorChangeEventArgs *e) { - xfContext *xfc = (xfContext *) context; + xfContext* xfc = (xfContext*) context; + xfc->settings->ScalingFactor += e->ScalingFactor; - if(xfc->settings->ScalingFactor > 1.2) + + if (xfc->settings->ScalingFactor > 1.2) xfc->settings->ScalingFactor = 1.2; - if(xfc->settings->ScalingFactor < 0.8) + + if (xfc->settings->ScalingFactor < 0.8) xfc->settings->ScalingFactor = 0.8; + xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor; xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor; + xf_transform_window(xfc); + { ResizeWindowEventArgs ev; EventArgsInit(&ev, "xfreerdp"); ev.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; ev.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; - PubSub_OnResizeWindow(((rdpContext *) xfc)->pubSub, xfc, &ev); + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &ev); } + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); } @@ -1507,11 +1605,12 @@ static void xfreerdp_client_global_uninit() static int xfreerdp_client_start(rdpContext *context) { - xfContext *xfc = (xfContext *) context; - rdpSettings *settings = context->settings; - if(!settings->ServerHostname) + xfContext* xfc = (xfContext *) context; + rdpSettings* settings = context->settings; + + if (!settings->ServerHostname) { - fprintf(stderr, "error: server hostname was not specified with /v:[:port]\n"); + WLog_ERR(TAG, "error: server hostname was not specified with /v:[:port]"); return -1; } xfc->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_thread, @@ -1519,11 +1618,11 @@ static int xfreerdp_client_start(rdpContext *context) return 0; } -static int xfreerdp_client_stop(rdpContext *context) +static int xfreerdp_client_stop(rdpContext* context) { - xfContext *xfc = (xfContext *) context; - assert(NULL != context); - if(context->settings->AsyncInput) + xfContext* xfc = (xfContext*) context; + + if (context->settings->AsyncInput) { wMessageQueue *queue; queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -1534,19 +1633,23 @@ static int xfreerdp_client_stop(rdpContext *context) { xfc->disconnect = TRUE; } - if(xfc->thread) + + if (xfc->thread) { CloseHandle(xfc->thread); xfc->thread = NULL; } + return 0; } -static int xfreerdp_client_new(freerdp *instance, rdpContext *context) +static int xfreerdp_client_new(freerdp* instance, rdpContext* context) { - xfContext *xfc; - rdpSettings *settings; - xfc = (xfContext *) instance->context; + xfContext* xfc; + rdpSettings* settings; + + xfc = (xfContext*) instance->context; + instance->PreConnect = xf_pre_connect; instance->PostConnect = xf_post_connect; instance->PostDisconnect = xf_post_disconnect; @@ -1554,27 +1657,33 @@ static int xfreerdp_client_new(freerdp *instance, rdpContext *context) instance->VerifyCertificate = xf_verify_certificate; instance->LogonErrorInfo = xf_logon_error_info; context->channels = freerdp_channels_new(); + settings = instance->settings; xfc->settings = instance->context->settings; + PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler); PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler); + return 0; } -static void xfreerdp_client_free(freerdp *instance, rdpContext *context) +static void xfreerdp_client_free(freerdp* instance, rdpContext* context) { - xfContext *xfc = (xfContext *) context; - if(context) + xfContext* xfc = (xfContext*) context; + + if (context) { xf_window_free(xfc); - if(xfc->bmp_codec_none) - free(xfc->bmp_codec_none); - if(xfc->display) + + if (xfc->bitmap_buffer) + _aligned_free(xfc->bitmap_buffer); + + if (xfc->display) XCloseDisplay(xfc->display); } } -int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS *pEntryPoints) +int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) { pEntryPoints->Version = 1; pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 8fb49f98e..7b5aa6cb8 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -25,62 +25,62 @@ #include #include -#include -#include +#ifdef WITH_XFIXES +#include +#endif -#include +#include +#include +#include +#include + +#include #include #include #include "xf_cliprdr.h" -#ifdef WITH_DEBUG_X11 -#define DEBUG_X11(fmt, ...) DEBUG_CLASS(X11, fmt, ## __VA_ARGS__) -#else -#define DEBUG_X11(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) -#endif +#define TAG CLIENT_TAG("x11") -#ifdef WITH_DEBUG_X11_CLIPRDR -#define DEBUG_X11_CLIPRDR(fmt, ...) DEBUG_CLASS(X11_CLIPRDR, fmt, ## __VA_ARGS__) -#else -#define DEBUG_X11_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) -#endif - -typedef struct clipboard_format_mapping clipboardFormatMapping; - -struct clipboard_format_mapping +struct xf_cliprdr_format { - Atom target_format; - UINT32 format_id; + Atom atom; + UINT32 formatId; + char* formatName; }; +typedef struct xf_cliprdr_format xfCliprdrFormat; -typedef struct clipboard_context clipboardContext; - -struct clipboard_context +struct xf_clipboard { + xfContext* xfc; rdpChannels* channels; + CliprdrClientContext* context; + + wClipboard* system; + Window root_window; Atom clipboard_atom; Atom property_atom; Atom identity_atom; - clipboardFormatMapping format_mappings[20]; - int num_format_mappings; + int numClientFormats; + xfCliprdrFormat clientFormats[20]; - /* server->client data */ - UINT32* formats; - int num_formats; + int numServerFormats; + CLIPRDR_FORMAT* serverFormats; + + int numTargets; Atom targets[20]; - int num_targets; + + int requestedFormatId; + BYTE* data; UINT32 data_format; UINT32 data_alt_format; int data_length; XEvent* respond; - /* client->server data */ Window owner; - int request_index; BOOL sync; /* INCR mechanism */ @@ -88,183 +88,48 @@ struct clipboard_context BOOL incr_starts; BYTE* incr_data; int incr_data_length; + + /* XFixes extension */ + int xfixes_event_base; + int xfixes_error_base; + BOOL xfixes_supported; }; -void xf_cliprdr_init(xfContext* xfc, rdpChannels* channels) +int xf_cliprdr_send_client_format_list(xfClipboard* clipboard); + +static void xf_cliprdr_check_owner(xfClipboard* clipboard) { - int n; - UINT32 id; - clipboardContext* cb; + Window owner; + xfContext* xfc = clipboard->xfc; - cb = (clipboardContext*) malloc(sizeof(clipboardContext)); - ZeroMemory(cb, sizeof(clipboardContext)); - - xfc->clipboard_context = cb; - - cb->channels = channels; - cb->request_index = -1; - - cb->root_window = DefaultRootWindow(xfc->display); - cb->clipboard_atom = XInternAtom(xfc->display, "CLIPBOARD", FALSE); - - if (cb->clipboard_atom == None) + if (clipboard->sync) { - DEBUG_WARN("unable to get CLIPBOARD atom"); - } + owner = XGetSelectionOwner(xfc->display, clipboard->clipboard_atom); - id = 1; - cb->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE); - cb->identity_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_ID", FALSE); - - XChangeProperty(xfc->display, xfc->drawable, cb->identity_atom, - XA_INTEGER, 32, PropModeReplace, (BYTE*) &id, 1); - - XSelectInput(xfc->display, cb->root_window, PropertyChangeMask); - - n = 0; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "_FREERDP_RAW", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_RAW; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "UTF8_STRING", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_UNICODETEXT; - - n++; - cb->format_mappings[n].target_format = XA_STRING; - cb->format_mappings[n].format_id = CB_FORMAT_TEXT; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "image/png", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_PNG; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "image/jpeg", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_JPEG; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "image/gif", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_GIF; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "image/bmp", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_DIB; - - n++; - cb->format_mappings[n].target_format = XInternAtom(xfc->display, "text/html", FALSE); - cb->format_mappings[n].format_id = CB_FORMAT_HTML; - - cb->num_format_mappings = n + 1; - cb->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE); - cb->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE); - cb->num_targets = 2; - - cb->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); -} - -void xf_cliprdr_uninit(xfContext* xfc) -{ - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - if (cb) - { - free(cb->formats); - free(cb->data); - free(cb->respond); - free(cb->incr_data); - free(cb); - xfc->clipboard_context = NULL; - } -} - -static BYTE* lf2crlf(BYTE* data, int* size) -{ - BYTE c; - BYTE* outbuf; - BYTE* out; - BYTE* in_end; - BYTE* in; - int out_size; - - out_size = (*size) * 2 + 1; - outbuf = (BYTE*) malloc(out_size); - ZeroMemory(outbuf, out_size); - - out = outbuf; - in = data; - in_end = data + (*size); - - while (in < in_end) - { - c = *in++; - if (c == '\n') + if (clipboard->owner != owner) { - *out++ = '\r'; - *out++ = '\n'; - } - else - { - *out++ = c; + clipboard->owner = owner; + xf_cliprdr_send_client_format_list(clipboard); } } - - *out++ = 0; - *size = out - outbuf; - - return outbuf; } -static void crlf2lf(BYTE* data, int* size) -{ - BYTE c; - BYTE* out; - BYTE* in; - BYTE* in_end; - - out = data; - in = data; - in_end = data + (*size); - - while (in < in_end) - { - c = *in++; - - if (c != '\r') - *out++ = c; - } - - *size = out - data; -} - -static void be2le(BYTE* data, int size) -{ - BYTE c; - - while (size >= 2) - { - c = data[0]; - data[0] = data[1]; - data[1] = c; - - data += 2; - size -= 2; - } -} - -static BOOL xf_cliprdr_is_self_owned(xfContext* xfc) +static BOOL xf_cliprdr_is_self_owned(xfClipboard* clipboard) { Atom type; UINT32 id = 0; UINT32* pid = NULL; int format, result = 0; - unsigned long length, bytes_left; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + unsigned long length; + unsigned long bytes_left; + xfContext* xfc = clipboard->xfc; - cb->owner = XGetSelectionOwner(xfc->display, cb->clipboard_atom); + clipboard->owner = XGetSelectionOwner(xfc->display, clipboard->clipboard_atom); - if (cb->owner != None) + if (clipboard->owner != None) { - result = XGetWindowProperty(xfc->display, cb->owner, - cb->identity_atom, 0, 4, 0, XA_INTEGER, + result = XGetWindowProperty(xfc->display, clipboard->owner, + clipboard->identity_atom, 0, 4, 0, XA_INTEGER, &type, &format, &length, &bytes_left, (BYTE**) &pid); } @@ -274,7 +139,7 @@ static BOOL xf_cliprdr_is_self_owned(xfContext* xfc) XFree(pid); } - if ((cb->owner == None) || (cb->owner == xfc->drawable)) + if ((clipboard->owner == None) || (clipboard->owner == xfc->drawable)) return FALSE; if (result != Success) @@ -283,514 +148,293 @@ static BOOL xf_cliprdr_is_self_owned(xfContext* xfc) return (id ? TRUE : FALSE); } -static int xf_cliprdr_select_format_by_id(clipboardContext* cb, UINT32 format_id) +static xfCliprdrFormat* xf_cliprdr_get_format_by_id(xfClipboard* clipboard, UINT32 formatId) { - int i; + UINT32 index; + xfCliprdrFormat* format; - for (i = 0; i < cb->num_format_mappings; i++) + for (index = 0; index < clipboard->numClientFormats; index++) { - if (cb->format_mappings[i].format_id == format_id) - return i; + format = &(clipboard->clientFormats[index]); + + if (format->formatId == formatId) + return format; } - return -1; + return NULL; } -static int xf_cliprdr_select_format_by_atom(clipboardContext* cb, Atom target) +static xfCliprdrFormat* xf_cliprdr_get_format_by_atom(xfClipboard* clipboard, Atom atom) { - int i; - int j; + int i, j; + xfCliprdrFormat* format; - if (cb->formats == NULL) - return -1; - - for (i = 0; i < cb->num_format_mappings; i++) + for (i = 0; i < clipboard->numClientFormats; i++) { - if (cb->format_mappings[i].target_format != target) + format = &(clipboard->clientFormats[i]); + + if (format->atom != atom) continue; - if (cb->format_mappings[i].format_id == CB_FORMAT_RAW) - return i; + if (format->formatId == 0) + return format; - for (j = 0; j < cb->num_formats; j++) + for (j = 0; j < clipboard->numServerFormats; j++) { - if (cb->format_mappings[i].format_id == cb->formats[j]) - return i; + if (clipboard->serverFormats[j].formatId == format->formatId) + return format; } } - return -1; + return NULL; } -static void xf_cliprdr_send_raw_format_list(xfContext* xfc) +static void xf_cliprdr_send_data_request(xfClipboard* clipboard, UINT32 formatId) { - Atom type; - BYTE* format_data; - int format, result; - unsigned long length, bytes_left; - RDP_CB_FORMAT_LIST_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + CLIPRDR_FORMAT_DATA_REQUEST request; - result = XGetWindowProperty(xfc->display, cb->root_window, - cb->property_atom, 0, 3600, 0, XA_STRING, - &type, &format, &length, &bytes_left, (BYTE**) &format_data); + ZeroMemory(&request, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); - if (result != Success) - { - DEBUG_WARN("XGetWindowProperty failed"); - return; - } - DEBUG_X11_CLIPRDR("format=%d len=%d bytes_left=%d", format, (int) length, (int) bytes_left); + request.requestedFormatId = formatId; - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); - - event->raw_format_data = (BYTE*) malloc(length); - CopyMemory(event->raw_format_data, format_data, length); - event->raw_format_data_size = length; - XFree(format_data); - - freerdp_channels_send_event(cb->channels, (wMessage*) event); + clipboard->context->ClientFormatDataRequest(clipboard->context, &request); } -static void xf_cliprdr_send_null_format_list(xfContext* xfc) +static void xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data, int size) { - RDP_CB_FORMAT_LIST_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + CLIPRDR_FORMAT_DATA_RESPONSE response; - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); - event->num_formats = 0; + response.msgFlags = CB_RESPONSE_OK; + response.dataLen = size; + response.requestedFormatData = data; - freerdp_channels_send_event(cb->channels, (wMessage*) event); + clipboard->context->ClientFormatDataResponse(clipboard->context, &response); } -static void xf_cliprdr_send_supported_format_list(xfContext* xfc) +static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) { int i; - RDP_CB_FORMAT_LIST_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); - - event->formats = (UINT32*) malloc(sizeof(UINT32) * cb->num_format_mappings); - event->num_formats = cb->num_format_mappings; - - for (i = 0; i < cb->num_format_mappings; i++) - event->formats[i] = cb->format_mappings[i].format_id; - - freerdp_channels_send_event(cb->channels, (wMessage*) event); -} - -static void xf_cliprdr_send_format_list(xfContext* xfc) -{ - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - if (xf_cliprdr_is_self_owned(xfc)) - { - xf_cliprdr_send_raw_format_list(xfc); - } - else if (cb->owner == None) - { - xf_cliprdr_send_null_format_list(xfc); - } - else if (cb->owner != xfc->drawable) - { - /* Request the owner for TARGETS, and wait for SelectionNotify event */ - XConvertSelection(xfc->display, cb->clipboard_atom, - cb->targets[1], cb->property_atom, xfc->drawable, CurrentTime); - } -} - -static void xf_cliprdr_send_data_request(xfContext* xfc, UINT32 format) -{ - RDP_CB_DATA_REQUEST_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_DataRequest, NULL, NULL); - - event->format = format; - - freerdp_channels_send_event(cb->channels, (wMessage*) event); -} - -static void xf_cliprdr_send_data_response(xfContext* xfc, BYTE* data, int size) -{ - RDP_CB_DATA_RESPONSE_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_DataResponse, NULL, NULL); - - event->data = data; - event->size = size; - - freerdp_channels_send_event(cb->channels, (wMessage*) event); -} - -static void xf_cliprdr_send_null_data_response(xfContext* xfc) -{ - xf_cliprdr_send_data_response(xfc, NULL, 0); -} - -static void xf_cliprdr_process_cb_monitor_ready_event(xfContext* xfc) -{ - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - xf_cliprdr_send_format_list(xfc); - cb->sync = TRUE; -} - -static void xf_cliprdr_process_cb_data_request_event(xfContext* xfc, RDP_CB_DATA_REQUEST_EVENT* event) -{ - int i; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - DEBUG_X11_CLIPRDR("format %d", event->format); - - if (xf_cliprdr_is_self_owned(xfc)) - { - /* CB_FORMAT_RAW */ - i = 0; - XChangeProperty(xfc->display, xfc->drawable, cb->property_atom, - XA_INTEGER, 32, PropModeReplace, (BYTE*) &event->format, 1); - } - else - { - i = xf_cliprdr_select_format_by_id(cb, event->format); - } - - if (i < 0) - { - DEBUG_X11_CLIPRDR("unsupported format requested"); - xf_cliprdr_send_null_data_response(xfc); - } - else - { - cb->request_index = i; - - DEBUG_X11_CLIPRDR("target=%d", (int) cb->format_mappings[i].target_format); - - XConvertSelection(xfc->display, cb->clipboard_atom, - cb->format_mappings[i].target_format, cb->property_atom, - xfc->drawable, CurrentTime); - XFlush(xfc->display); - /* After this point, we expect a SelectionNotify event from the clipboard owner. */ - } -} - -static void xf_cliprdr_get_requested_targets(xfContext* xfc) -{ - int num; - int i, j; Atom atom; - int format; BYTE* data = NULL; - unsigned long length, bytes_left; - RDP_CB_FORMAT_LIST_EVENT* event; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + int format_property; + unsigned long length; + unsigned long bytes_left; + UINT32 numFormats = 0; + CLIPRDR_FORMAT_LIST formatList; + xfCliprdrFormat* format = NULL; + CLIPRDR_FORMAT* formats = NULL; + xfContext* xfc = clipboard->xfc; - XGetWindowProperty(xfc->display, xfc->drawable, cb->property_atom, - 0, 200, 0, XA_ATOM, &atom, &format, &length, &bytes_left, &data); + if (!clipboard->numServerFormats) + return; /* server format list was not yet received */ - DEBUG_X11_CLIPRDR("type=%d format=%d length=%d bytes_left=%d", - (int) atom, format, (int) length, (int) bytes_left); + XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, + 0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data); if (length > 0) + formats = (CLIPRDR_FORMAT*) calloc(length, sizeof(CLIPRDR_FORMAT)); + + for (i = 0; i < length; i++) { - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); + atom = ((Atom*) data)[i]; - event->formats = (UINT32*) malloc(sizeof(UINT32) * cb->num_format_mappings); - num = 0; + format = xf_cliprdr_get_format_by_atom(clipboard, atom); - for (i = 0; i < length; i++) + if (format) { - atom = ((Atom*) data)[i]; - DEBUG_X11("atom %d", (int) atom); - - for (j = 0; j < cb->num_format_mappings; j++) - { - if (cb->format_mappings[j].target_format == atom) - { - DEBUG_X11("found format %d for atom %d", - cb->format_mappings[j].format_id, (int)atom); - event->formats[num++] = cb->format_mappings[j].format_id; - break; - } - } - } - - event->num_formats = num; - XFree(data); - - freerdp_channels_send_event(cb->channels, (wMessage*) event); - } - else - { - if (data) - XFree(data); - - xf_cliprdr_send_null_format_list(xfc); - } -} - -static BYTE* xf_cliprdr_process_requested_raw(BYTE* data, int* size) -{ - BYTE* outbuf; - - outbuf = (BYTE*) malloc(*size); - CopyMemory(outbuf, data, *size); - return outbuf; -} - -static BYTE* xf_cliprdr_process_requested_unicodetext(BYTE* data, int* size) -{ - char* inbuf; - WCHAR* outbuf = NULL; - int out_size; - - inbuf = (char*) lf2crlf(data, size); - out_size = ConvertToUnicode(CP_UTF8, 0, inbuf, -1, &outbuf, 0); - free(inbuf); - - *size = (int) ((out_size + 1) * 2); - - return (BYTE*) outbuf; -} - -static BYTE* xf_cliprdr_process_requested_text(BYTE* data, int* size) -{ - BYTE* outbuf; - - outbuf = lf2crlf(data, size); - - return outbuf; -} - -static BYTE* xf_cliprdr_process_requested_dib(BYTE* data, int* size) -{ - BYTE* outbuf; - - /* length should be at least BMP header (14) + sizeof(BITMAPINFOHEADER) */ - - if (*size < 54) - { - DEBUG_X11_CLIPRDR("bmp length %d too short", *size); - return NULL; - } - - *size -= 14; - outbuf = (BYTE*) malloc(*size); - ZeroMemory(outbuf, *size); - - CopyMemory(outbuf, data + 14, *size); - - return outbuf; -} - -static BYTE* xf_cliprdr_process_requested_html(BYTE* data, int* size) -{ - char* inbuf; - BYTE* in; - BYTE* outbuf; - char num[11]; - - inbuf = NULL; - - if (*size > 2) - { - if ((BYTE) data[0] == 0xFE && (BYTE) data[1] == 0xFF) - { - be2le(data, *size); - } - - if ((BYTE) data[0] == 0xFF && (BYTE) data[1] == 0xFE) - { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) (data + 2), - (*size - 2) / 2, &inbuf, 0, NULL, NULL); + formats[numFormats].formatId = format->formatId; + formats[numFormats].formatName = format->formatName; + numFormats++; } } - if (inbuf == NULL) - { - inbuf = malloc(*size + 1); - ZeroMemory(inbuf, *size + 1); + XFree(data); - CopyMemory(inbuf, data, *size); - } + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); - outbuf = (BYTE*) malloc(*size + 200); - ZeroMemory(outbuf, *size + 200); + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = numFormats; + formatList.formats = formats; - strcpy((char*) outbuf, - "Version:0.9\r\n" - "StartHTML:0000000000\r\n" - "EndHTML:0000000000\r\n" - "StartFragment:0000000000\r\n" - "EndFragment:0000000000\r\n"); + clipboard->context->ClientFormatList(clipboard->context, &formatList); - in = (BYTE*) strstr((char*) inbuf, ""); - } - strcat((char*) outbuf, ""); - /* StartFragment */ - snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); - CopyMemory(outbuf + 69, num, 10); - strcat((char*) outbuf, (char*) inbuf); - /* EndFragment */ - snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); - CopyMemory(outbuf + 93, num, 10); - strcat((char*) outbuf, ""); - if (in == NULL) - { - strcat((char*) outbuf, ""); - } - /* EndHTML */ - snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); - CopyMemory(outbuf + 43, num, 10); - - *size = strlen((char*) outbuf) + 1; - free(inbuf); - - return outbuf; + free(formats); } -static void xf_cliprdr_process_requested_data(xfContext* xfc, BOOL has_data, BYTE* data, int size) +static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) { - BYTE* outbuf; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + UINT32 index; + UINT32 count; + BOOL bSuccess; + UINT32 SrcSize; + UINT32 DstSize; + UINT32 formatId; + UINT32 altFormatId; + UINT32* pFormatIds; + const char* formatName; + BYTE* pSrcData = NULL; + BYTE* pDstData = NULL; + xfCliprdrFormat* format; - if (cb->incr_starts && has_data) + if (clipboard->incr_starts && hasData) return; - if (!has_data || data == NULL) + format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + + if (!hasData || !data || !format) { - xf_cliprdr_send_null_data_response(xfc); + xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } - switch (cb->format_mappings[cb->request_index].format_id) + formatId = 0; + altFormatId = 0; + + switch (format->formatId) { - case CB_FORMAT_RAW: - case CB_FORMAT_PNG: - case CB_FORMAT_JPEG: - case CB_FORMAT_GIF: - outbuf = xf_cliprdr_process_requested_raw(data, &size); + case CF_TEXT: + case CF_UNICODETEXT: + formatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; - case CB_FORMAT_UNICODETEXT: - outbuf = xf_cliprdr_process_requested_unicodetext(data, &size); - break; - - case CB_FORMAT_TEXT: - outbuf = xf_cliprdr_process_requested_text(data, &size); - break; - - case CB_FORMAT_DIB: - outbuf = xf_cliprdr_process_requested_dib(data, &size); + case CF_DIB: + formatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: - outbuf = xf_cliprdr_process_requested_html(data, &size); - break; - - default: - outbuf = NULL; + formatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; } - if (outbuf) - xf_cliprdr_send_data_response(xfc, outbuf, size); - else - xf_cliprdr_send_null_data_response(xfc); + SrcSize = (UINT32) size; + pSrcData = (BYTE*) malloc(SrcSize); - /* Resend the format list, otherwise the server won't request again for the next paste */ - xf_cliprdr_send_format_list(xfc); + if (!pSrcData) + return; + + CopyMemory(pSrcData, data, SrcSize); + + bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); + + pFormatIds = NULL; + count = ClipboardGetFormatIds(clipboard->system, &pFormatIds); + + for (index = 0; index < count; index++) + { + formatId = pFormatIds[index]; + formatName = ClipboardGetFormatName(clipboard->system, formatId); + + if (formatId < CF_MAX) + { + switch (formatId) + { + case CF_TEXT: + altFormatId = CF_TEXT; + break; + + case CF_UNICODETEXT: + altFormatId = CF_UNICODETEXT; + break; + + case CF_DIB: + altFormatId = CF_DIB; + break; + } + } + else if (strcmp(formatName, "HTML Format") == 0) + { + altFormatId = formatId; + break; + } + } + + free(pFormatIds); + + if (bSuccess && altFormatId) + { + DstSize = 0; + pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); + } + + if (!pDstData) + { + xf_cliprdr_send_data_response(clipboard, NULL, 0); + return; + } + + xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); } -static BOOL xf_cliprdr_get_requested_data(xfContext* xfc, Atom target) +static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) { Atom type; - int format; BYTE* data = NULL; BOOL has_data = FALSE; - unsigned long length, bytes_left, dummy; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + int format_property; + unsigned long dummy; + unsigned long length; + unsigned long bytes_left; + xfCliprdrFormat* format; + xfContext* xfc = clipboard->xfc; - if ((cb->request_index < 0) || (cb->format_mappings[cb->request_index].target_format != target)) + format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + + if (!format || (format->atom != target)) { - DEBUG_X11_CLIPRDR("invalid target"); - xf_cliprdr_send_null_data_response(xfc); + xf_cliprdr_send_data_response(clipboard, NULL, 0); return FALSE; } XGetWindowProperty(xfc->display, xfc->drawable, - cb->property_atom, 0, 0, 0, target, - &type, &format, &length, &bytes_left, &data); - - DEBUG_X11_CLIPRDR("type=%d format=%d bytes=%d request_index=%d", - (int) type, format, (int) bytes_left, cb->request_index); + clipboard->property_atom, 0, 0, 0, target, + &type, &format_property, &length, &bytes_left, &data); if (data) { XFree(data); data = NULL; } - if (bytes_left <= 0 && !cb->incr_starts) + if (bytes_left <= 0 && !clipboard->incr_starts) { - DEBUG_X11("no data"); + } - else if (type == cb->incr_atom) + else if (type == clipboard->incr_atom) { - DEBUG_X11("INCR started"); - cb->incr_starts = TRUE; - if (cb->incr_data) + clipboard->incr_starts = TRUE; + + if (clipboard->incr_data) { - free(cb->incr_data); - cb->incr_data = NULL; + free(clipboard->incr_data); + clipboard->incr_data = NULL; } - cb->incr_data_length = 0; - /* Data will be followed in PropertyNotify event */ - has_data = TRUE; + + clipboard->incr_data_length = 0; + has_data = TRUE; /* data will be followed in PropertyNotify event */ } else { if (bytes_left <= 0) { /* INCR finish */ - data = cb->incr_data; - cb->incr_data = NULL; - bytes_left = cb->incr_data_length; - cb->incr_data_length = 0; - cb->incr_starts = 0; - DEBUG_X11("INCR finished"); + data = clipboard->incr_data; + clipboard->incr_data = NULL; + bytes_left = clipboard->incr_data_length; + clipboard->incr_data_length = 0; + clipboard->incr_starts = 0; has_data = TRUE; } else if (XGetWindowProperty(xfc->display, xfc->drawable, - cb->property_atom, 0, bytes_left, 0, target, - &type, &format, &length, &dummy, &data) == Success) + clipboard->property_atom, 0, bytes_left, 0, target, + &type, &format_property, &length, &dummy, &data) == Success) { - if (cb->incr_starts) + if (clipboard->incr_starts) { - bytes_left = length * format / 8; - DEBUG_X11("%d bytes", (int)bytes_left); - cb->incr_data = (BYTE*) realloc(cb->incr_data, cb->incr_data_length + bytes_left); - CopyMemory(cb->incr_data + cb->incr_data_length, data, bytes_left); - cb->incr_data_length += bytes_left; + bytes_left = length * format_property / 8; + clipboard->incr_data = (BYTE*) realloc(clipboard->incr_data, clipboard->incr_data_length + bytes_left); + CopyMemory(clipboard->incr_data + clipboard->incr_data_length, data, bytes_left); + clipboard->incr_data_length += bytes_left; XFree(data); data = NULL; } @@ -798,12 +442,13 @@ static BOOL xf_cliprdr_get_requested_data(xfContext* xfc, Atom target) } else { - DEBUG_X11_CLIPRDR("XGetWindowProperty failed"); + } } - XDeleteProperty(xfc->display, xfc->drawable, cb->property_atom); - xf_cliprdr_process_requested_data(xfc, has_data, data, (int) bytes_left); + XDeleteProperty(xfc->display, xfc->drawable, clipboard->property_atom); + + xf_cliprdr_process_requested_data(clipboard, has_data, data, (int) bytes_left); if (data) XFree(data); @@ -811,321 +456,87 @@ static BOOL xf_cliprdr_get_requested_data(xfContext* xfc, Atom target) return TRUE; } -static void xf_cliprdr_append_target(clipboardContext* cb, Atom target) +static void xf_cliprdr_append_target(xfClipboard* clipboard, Atom target) { int i; - if (cb->num_targets >= ARRAYSIZE(cb->targets)) + if (clipboard->numTargets >= ARRAYSIZE(clipboard->targets)) return; - for (i = 0; i < cb->num_targets; i++) + for (i = 0; i < clipboard->numTargets; i++) { - if (cb->targets[i] == target) + if (clipboard->targets[i] == target) return; } - cb->targets[cb->num_targets++] = target; + clipboard->targets[clipboard->numTargets++] = target; } -static void xf_cliprdr_provide_targets(xfContext* xfc, XEvent* respond) +static void xf_cliprdr_provide_targets(xfClipboard* clipboard, XEvent* respond) { - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + xfContext* xfc = clipboard->xfc; if (respond->xselection.property != None) { - XChangeProperty(xfc->display, - respond->xselection.requestor, - respond->xselection.property, - XA_ATOM, 32, PropModeReplace, - (BYTE*) cb->targets, cb->num_targets); + XChangeProperty(xfc->display, respond->xselection.requestor, + respond->xselection.property, XA_ATOM, 32, PropModeReplace, + (BYTE*) clipboard->targets, clipboard->numTargets); } } -static void xf_cliprdr_provide_data(xfContext* xfc, XEvent* respond) +static void xf_cliprdr_provide_data(xfClipboard* clipboard, XEvent* respond, BYTE* data, UINT32 size) { - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + xfContext* xfc = clipboard->xfc; if (respond->xselection.property != None) { - XChangeProperty(xfc->display, - respond->xselection.requestor, - respond->xselection.property, - respond->xselection.target, 8, PropModeReplace, - (BYTE*) cb->data, cb->data_length); + XChangeProperty(xfc->display, respond->xselection.requestor, + respond->xselection.property, respond->xselection.target, + 8, PropModeReplace, data, size); } } -static void xf_cliprdr_process_cb_format_list_event(xfContext* xfc, RDP_CB_FORMAT_LIST_EVENT* event) +static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, XEvent* xevent) { - int i, j; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - if (cb->data) - { - free(cb->data); - cb->data = NULL; - } - - if (cb->formats) - free(cb->formats); - - cb->formats = event->formats; - cb->num_formats = event->num_formats; - event->formats = NULL; - event->num_formats = 0; - - cb->num_targets = 2; - - for (i = 0; i < cb->num_formats; i++) - { - for (j = 0; j < cb->num_format_mappings; j++) - { - if (cb->formats[i] == cb->format_mappings[j].format_id) - { - DEBUG_X11("announce format#%d : %d", i, cb->formats[i]); - xf_cliprdr_append_target(cb, cb->format_mappings[j].target_format); - } - } - } - - XSetSelectionOwner(xfc->display, cb->clipboard_atom, xfc->drawable, CurrentTime); - - if (event->raw_format_data) - { - XChangeProperty(xfc->display, cb->root_window, cb->property_atom, - XA_STRING, 8, PropModeReplace, - event->raw_format_data, event->raw_format_data_size); - } - - XFlush(xfc->display); -} - -static void xf_cliprdr_process_text(clipboardContext* cb, BYTE* data, int size) -{ - cb->data = (BYTE*) malloc(size); - CopyMemory(cb->data, data, size); - cb->data_length = size; - crlf2lf(cb->data, &cb->data_length); -} - -static void xf_cliprdr_process_unicodetext(clipboardContext* cb, BYTE* data, int size) -{ - cb->data_length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) data, size / 2, (CHAR**) &(cb->data), 0, NULL, NULL); - crlf2lf(cb->data, &cb->data_length); -} - -static BOOL xf_cliprdr_process_dib(clipboardContext* cb, BYTE* data, int size) -{ - wStream* s; - UINT16 bpp; - UINT32 offset; - UINT32 ncolors; - - /* size should be at least sizeof(BITMAPINFOHEADER) */ - - if (size < 40) - { - DEBUG_X11_CLIPRDR("dib size %d too short", size); - return FALSE; - } - - s = Stream_New(data, size); - Stream_Seek(s, 14); - Stream_Read_UINT16(s, bpp); - if ((bpp < 1) || (bpp > 32)) - { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, bpp); - return FALSE; - } - - Stream_Read_UINT32(s, ncolors); - offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0); - Stream_Free(s, FALSE); - - DEBUG_X11_CLIPRDR("offset=%d bpp=%d ncolors=%d", offset, bpp, ncolors); - - s = Stream_New(NULL, 14 + size); - Stream_Write_UINT8(s, 'B'); - Stream_Write_UINT8(s, 'M'); - Stream_Write_UINT32(s, 14 + size); - Stream_Write_UINT32(s, 0); - Stream_Write_UINT32(s, offset); - Stream_Write(s, data, size); - - cb->data = Stream_Buffer(s); - cb->data_length = Stream_GetPosition(s); - Stream_Free(s, FALSE); - return TRUE; -} - -static void xf_cliprdr_process_html(clipboardContext* cb, BYTE* data, int size) -{ - char* start_str; - char* end_str; - int start; - int end; - - start_str = strstr((char*) data, "StartHTML:"); - end_str = strstr((char*) data, "EndHTML:"); - if (start_str == NULL || end_str == NULL) - { - DEBUG_X11_CLIPRDR("invalid HTML clipboard format"); - return; - } - start = atoi(start_str + 10); - end = atoi(end_str + 8); - if (start > size || end > size || start >= end) - { - DEBUG_X11_CLIPRDR("invalid HTML offset"); - return; - } - - cb->data = (BYTE*) malloc(size - start + 1); - CopyMemory(cb->data, data + start, end - start); - cb->data_length = end - start; - crlf2lf(cb->data, &cb->data_length); -} - -static void xf_cliprdr_process_cb_data_response_event(xfContext* xfc, RDP_CB_DATA_RESPONSE_EVENT* event) -{ - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - DEBUG_X11_CLIPRDR("size=%d", event->size); - - if (!cb->respond) - { - DEBUG_X11_CLIPRDR("unexpected data"); - return; - } - - if (event->size == 0) - { - cb->respond->xselection.property = None; - } - else - { - if (cb->data) - { - free(cb->data); - cb->data = NULL; - } - - switch (cb->data_format) - { - case CB_FORMAT_RAW: - case CB_FORMAT_PNG: - case CB_FORMAT_JPEG: - case CB_FORMAT_GIF: - cb->data = event->data; - cb->data_length = event->size; - event->data = NULL; - event->size = 0; - break; - - case CB_FORMAT_TEXT: - xf_cliprdr_process_text(cb, event->data, event->size); - break; - - case CB_FORMAT_UNICODETEXT: - xf_cliprdr_process_unicodetext(cb, event->data, event->size); - break; - - case CB_FORMAT_DIB: - xf_cliprdr_process_dib(cb, event->data, event->size); - break; - - case CB_FORMAT_HTML: - xf_cliprdr_process_html(cb, event->data, event->size); - break; - - default: - cb->respond->xselection.property = None; - break; - } - xf_cliprdr_provide_data(xfc, cb->respond); - } - - XSendEvent(xfc->display, cb->respond->xselection.requestor, 0, 0, cb->respond); - XFlush(xfc->display); - free(cb->respond); - cb->respond = NULL; -} - -void xf_process_cliprdr_event(xfContext* xfc, wMessage* event) -{ - switch (GetMessageType(event->id)) - { - case CliprdrChannel_MonitorReady: - xf_cliprdr_process_cb_monitor_ready_event(xfc); - break; - - case CliprdrChannel_FormatList: - xf_cliprdr_process_cb_format_list_event(xfc, (RDP_CB_FORMAT_LIST_EVENT*) event); - break; - - case CliprdrChannel_DataRequest: - xf_cliprdr_process_cb_data_request_event(xfc, (RDP_CB_DATA_REQUEST_EVENT*) event); - break; - - case CliprdrChannel_DataResponse: - xf_cliprdr_process_cb_data_response_event(xfc, (RDP_CB_DATA_RESPONSE_EVENT*) event); - break; - - default: - DEBUG_X11_CLIPRDR("unknown event type %d", GetMessageType(event->id)); - break; - } -} - -BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent) -{ - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - if (xevent->xselection.target == cb->targets[1]) + if (xevent->xselection.target == clipboard->targets[1]) { if (xevent->xselection.property == None) { - DEBUG_X11_CLIPRDR("owner not support TARGETS. sending all format."); - xf_cliprdr_send_supported_format_list(xfc); + xf_cliprdr_send_client_format_list(clipboard); } else { - xf_cliprdr_get_requested_targets(xfc); + xf_cliprdr_get_requested_targets(clipboard); } return TRUE; } else { - return xf_cliprdr_get_requested_data(xfc, xevent->xselection.target); + return xf_cliprdr_get_requested_data(clipboard, xevent->xselection.target); } } -BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent) +static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent* xevent) { - int i; int fmt; Atom type; - UINT32 format; + UINT32 formatId; XEvent* respond; - UINT32 alt_format; + UINT32 altFormatId; BYTE* data = NULL; - BOOL delay_respond; - unsigned long length, bytes_left; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; - - DEBUG_X11_CLIPRDR("target=%d", (int) xevent->xselectionrequest.target); + BOOL delayRespond; + unsigned long length; + unsigned long bytes_left; + xfCliprdrFormat* format; + xfContext* xfc = clipboard->xfc; if (xevent->xselectionrequest.owner != xfc->drawable) - { - DEBUG_X11_CLIPRDR("not owner"); return FALSE; - } - delay_respond = FALSE; + delayRespond = FALSE; - respond = (XEvent*) malloc(sizeof(XEvent)); - ZeroMemory(respond, sizeof(XEvent)); + respond = (XEvent*) calloc(1, sizeof(XEvent)); respond->xselection.property = None; respond->xselection.type = SelectionNotify; @@ -1135,55 +546,50 @@ BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent) respond->xselection.target = xevent->xselectionrequest.target; respond->xselection.time = xevent->xselectionrequest.time; - if (xevent->xselectionrequest.target == cb->targets[0]) /* TIMESTAMP */ + if (xevent->xselectionrequest.target == clipboard->targets[0]) /* TIMESTAMP */ { /* TODO */ - DEBUG_X11_CLIPRDR("target: TIMESTAMP (unimplemented)"); } - else if (xevent->xselectionrequest.target == cb->targets[1]) /* TARGETS */ + else if (xevent->xselectionrequest.target == clipboard->targets[1]) /* TARGETS */ { /* Someone else requests our available formats */ - DEBUG_X11_CLIPRDR("target: TARGETS"); respond->xselection.property = xevent->xselectionrequest.property; - xf_cliprdr_provide_targets(xfc, respond); + xf_cliprdr_provide_targets(clipboard, respond); } else { - DEBUG_X11_CLIPRDR("target: other"); + format = xf_cliprdr_get_format_by_atom(clipboard, xevent->xselectionrequest.target); - i = xf_cliprdr_select_format_by_atom(cb, xevent->xselectionrequest.target); - - if (i >= 0 && xevent->xselectionrequest.requestor != xfc->drawable) + if (format && (xevent->xselectionrequest.requestor != xfc->drawable)) { - format = cb->format_mappings[i].format_id; - alt_format = format; + formatId = format->formatId; + altFormatId = formatId; - if (format == CB_FORMAT_RAW) + if (formatId == 0) { if (XGetWindowProperty(xfc->display, xevent->xselectionrequest.requestor, - cb->property_atom, 0, 4, 0, XA_INTEGER, + clipboard->property_atom, 0, 4, 0, XA_INTEGER, &type, &fmt, &length, &bytes_left, &data) != Success) { - DEBUG_X11_CLIPRDR("XGetWindowProperty failed"); + } + if (data) { - CopyMemory(&alt_format, data, 4); + CopyMemory(&altFormatId, data, 4); XFree(data); } } - DEBUG_X11_CLIPRDR("provide format 0x%04x alt_format 0x%04x", format, alt_format); - - if ((cb->data != 0) && (format == cb->data_format) && (alt_format == cb->data_alt_format)) + if ((clipboard->data != 0) && (formatId == clipboard->data_format) && (altFormatId == clipboard->data_alt_format)) { /* Cached clipboard data available. Send it now */ respond->xselection.property = xevent->xselectionrequest.property; - xf_cliprdr_provide_data(xfc, respond); + xf_cliprdr_provide_data(clipboard, respond, clipboard->data, clipboard->data_length); } - else if (cb->respond) + else if (clipboard->respond) { - DEBUG_X11_CLIPRDR("duplicated request"); + /* duplicate request */ } else { @@ -1191,24 +597,24 @@ BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent) * Send clipboard data request to the server. * Response will be postponed after receiving the data */ - if (cb->data) + if (clipboard->data) { - free(cb->data); - cb->data = NULL; + free(clipboard->data); + clipboard->data = NULL; } respond->xselection.property = xevent->xselectionrequest.property; - cb->respond = respond; - cb->data_format = format; - cb->data_alt_format = alt_format; - delay_respond = TRUE; + clipboard->respond = respond; + clipboard->data_format = formatId; + clipboard->data_alt_format = altFormatId; + delayRespond = TRUE; - xf_cliprdr_send_data_request(xfc, alt_format); + xf_cliprdr_send_data_request(clipboard, altFormatId); } } } - if (delay_respond == FALSE) + if (!delayRespond) { XSendEvent(xfc->display, xevent->xselectionrequest.requestor, 0, 0, respond); XFlush(xfc->display); @@ -1218,59 +624,547 @@ BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent) return TRUE; } -BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent) +static BOOL xf_cliprdr_process_selection_clear(xfClipboard* clipboard, XEvent* xevent) { - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + xfContext* xfc = clipboard->xfc; - if (xf_cliprdr_is_self_owned(xfc)) + if (xf_cliprdr_is_self_owned(clipboard)) return FALSE; - XDeleteProperty(xfc->display, cb->root_window, cb->property_atom); + XDeleteProperty(xfc->display, clipboard->root_window, clipboard->property_atom); return TRUE; } -BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent) +static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, XEvent* xevent) { - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + xfCliprdrFormat* format; + xfContext* xfc = clipboard->xfc; - if (!cb) + if (!clipboard) return TRUE; - if (xevent->xproperty.atom != cb->property_atom) + if (xevent->xproperty.atom != clipboard->property_atom) return FALSE; /* Not cliprdr-related */ - if (xevent->xproperty.window == cb->root_window) + if (xevent->xproperty.window == clipboard->root_window) { - DEBUG_X11_CLIPRDR("root window PropertyNotify"); - xf_cliprdr_send_format_list(xfc); + xf_cliprdr_send_client_format_list(clipboard); } - else if (xevent->xproperty.window == xfc->drawable && - xevent->xproperty.state == PropertyNewValue && - cb->incr_starts && cb->request_index >= 0) + else if ((xevent->xproperty.window == xfc->drawable) && + (xevent->xproperty.state == PropertyNewValue) && clipboard->incr_starts) { - DEBUG_X11_CLIPRDR("cliprdr window PropertyNotify"); - xf_cliprdr_get_requested_data(xfc, - cb->format_mappings[cb->request_index].target_format); + format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + + if (format) + xf_cliprdr_get_requested_data(clipboard, format->atom); } return TRUE; } -void xf_cliprdr_check_owner(xfContext* xfc) +void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event) { - Window owner; - clipboardContext* cb = (clipboardContext*) xfc->clipboard_context; + xfClipboard* clipboard; - if (cb->sync) + if (!xfc || !event) + return; + + clipboard = xfc->clipboard; + + if (!clipboard) + return; + +#ifdef WITH_XFIXES + if (clipboard->xfixes_supported && event->type == XFixesSelectionNotify + clipboard->xfixes_event_base) { - owner = XGetSelectionOwner(xfc->display, cb->clipboard_atom); + XFixesSelectionNotifyEvent* se = (XFixesSelectionNotifyEvent*) event; - if (cb->owner != owner) + if (se->subtype == XFixesSetSelectionOwnerNotify) { - cb->owner = owner; - xf_cliprdr_send_format_list(xfc); + if (se->selection != clipboard->clipboard_atom) + return; + + if (XGetSelectionOwner(xfc->display, se->selection) == xfc->drawable) + return; + + clipboard->owner = None; + xf_cliprdr_check_owner(clipboard); } + + return; + } +#endif + + switch (event->type) + { + case SelectionNotify: + xf_cliprdr_process_selection_notify(clipboard, event); + break; + + case SelectionRequest: + xf_cliprdr_process_selection_request(clipboard, event); + break; + + case SelectionClear: + xf_cliprdr_process_selection_clear(clipboard, event); + break; + + case PropertyNotify: + xf_cliprdr_process_property_notify(clipboard, event); + break; + + case FocusIn: + if (!clipboard->xfixes_supported) + { + xf_cliprdr_check_owner(clipboard); + } + break; } } +int xf_cliprdr_send_client_capabilities(xfClipboard* clipboard) +{ + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; + + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); + + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; + + generalCapabilitySet.version = CB_CAPS_VERSION_2; + generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES; + + clipboard->context->ClientCapabilities(clipboard->context, &capabilities); + + return 1; +} + +int xf_cliprdr_send_client_format_list(xfClipboard* clipboard) +{ + UINT32 i, numFormats; + CLIPRDR_FORMAT* formats; + CLIPRDR_FORMAT_LIST formatList; + xfContext* xfc = clipboard->xfc; + + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); + + numFormats = clipboard->numClientFormats; + formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); + + for (i = 0; i < numFormats; i++) + { + formats[i].formatId = clipboard->clientFormats[i].formatId; + formats[i].formatName = clipboard->clientFormats[i].formatName; + } + + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = numFormats; + formatList.formats = formats; + + clipboard->context->ClientFormatList(clipboard->context, &formatList); + + free(formats); + + if (clipboard->owner != xfc->drawable) + { + /* Request the owner for TARGETS, and wait for SelectionNotify event */ + XConvertSelection(xfc->display, clipboard->clipboard_atom, + clipboard->targets[1], clipboard->property_atom, xfc->drawable, CurrentTime); + } + + return 1; +} + +int xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard, BOOL status) +{ + CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; + + formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; + formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; + formatListResponse.dataLen = 0; + + clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse); + + return 1; +} + +int xf_cliprdr_send_client_format_data_request(xfClipboard* clipboard, UINT32 formatId) +{ + CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; + + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; + formatDataRequest.msgFlags = CB_RESPONSE_OK; + + formatDataRequest.requestedFormatId = formatId; + clipboard->requestedFormatId = formatId; + + clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); + + return 1; +} + +static int xf_cliprdr_monitor_ready(CliprdrClientContext* context, CLIPRDR_MONITOR_READY* monitorReady) +{ + xfClipboard* clipboard = (xfClipboard*) context->custom; + + xf_cliprdr_send_client_capabilities(clipboard); + xf_cliprdr_send_client_format_list(clipboard); + clipboard->sync = TRUE; + + return 1; +} + +static int xf_cliprdr_server_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities) +{ + //xfClipboard* clipboard = (xfClipboard*) context->custom; + + return 1; +} + +static int xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList) +{ + int i, j; + CLIPRDR_FORMAT* format; + xfClipboard* clipboard = (xfClipboard*) context->custom; + xfContext* xfc = clipboard->xfc; + + if (clipboard->data) + { + free(clipboard->data); + clipboard->data = NULL; + } + + if (clipboard->serverFormats) + { + for (i = 0; i < clipboard->numServerFormats; i++) + free(clipboard->serverFormats[i].formatName); + + free(clipboard->serverFormats); + clipboard->serverFormats = NULL; + + clipboard->numServerFormats = 0; + } + + clipboard->numServerFormats = formatList->numFormats; + clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc(clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT)); + + if (!clipboard->serverFormats) + return -1; + + for (i = 0; i < formatList->numFormats; i++) + { + format = &formatList->formats[i]; + clipboard->serverFormats[i].formatId = format->formatId; + clipboard->serverFormats[i].formatName = _strdup(format->formatName); + } + + clipboard->numTargets = 2; + + for (i = 0; i < formatList->numFormats; i++) + { + format = &formatList->formats[i]; + + for (j = 0; j < clipboard->numClientFormats; j++) + { + if (format->formatId == clipboard->clientFormats[j].formatId) + { + xf_cliprdr_append_target(clipboard, clipboard->clientFormats[j].atom); + } + } + } + + xf_cliprdr_send_client_format_list_response(clipboard, TRUE); + + XSetSelectionOwner(xfc->display, clipboard->clipboard_atom, xfc->drawable, CurrentTime); + + XFlush(xfc->display); + + return 1; +} + +static int xf_cliprdr_server_format_list_response(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +{ + //xfClipboard* clipboard = (xfClipboard*) context->custom; + + return 1; +} + +static int xf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +{ + xfCliprdrFormat* format = NULL; + UINT32 formatId = formatDataRequest->requestedFormatId; + xfClipboard* clipboard = (xfClipboard*) context->custom; + xfContext* xfc = clipboard->xfc; + + if (xf_cliprdr_is_self_owned(clipboard)) + { + format = xf_cliprdr_get_format_by_id(clipboard, 0); + + XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, + XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1); + } + else + { + format = xf_cliprdr_get_format_by_id(clipboard, formatId); + } + + if (!format) + { + xf_cliprdr_send_data_response(clipboard, NULL, 0); + return 1; + } + + clipboard->requestedFormatId = formatId; + + XConvertSelection(xfc->display, clipboard->clipboard_atom, + format->atom, clipboard->property_atom, xfc->drawable, CurrentTime); + + XFlush(xfc->display); + + /* After this point, we expect a SelectionNotify event from the clipboard owner. */ + + return 1; +} + +static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +{ + BOOL bSuccess; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 DstSize; + UINT32 SrcSize; + UINT32 formatId; + UINT32 altFormatId; + xfCliprdrFormat* format; + UINT32 size = formatDataResponse->dataLen; + BYTE* data = formatDataResponse->requestedFormatData; + xfClipboard* clipboard = (xfClipboard*) context->custom; + xfContext* xfc = clipboard->xfc; + + if (!clipboard->respond) + return 1; + + format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + + if (clipboard->data) + { + free(clipboard->data); + clipboard->data = NULL; + } + + pDstData = NULL; + + formatId = 0; + altFormatId = 0; + + switch (clipboard->data_format) + { + case CF_TEXT: + formatId = CF_TEXT; + altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + break; + + case CF_UNICODETEXT: + formatId = CF_UNICODETEXT; + altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + break; + + case CF_DIB: + formatId = CF_DIB; + altFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); + break; + + case CB_FORMAT_HTML: + formatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); + altFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); + break; + } + + SrcSize = (UINT32) size; + pSrcData = (BYTE*) malloc(SrcSize); + + if (!pSrcData) + return -1; + + CopyMemory(pSrcData, data, SrcSize); + + bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); + + if (bSuccess && altFormatId) + { + DstSize = 0; + pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); + } + + clipboard->data = pDstData; + clipboard->data_length = DstSize; + + xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize); + + XSendEvent(xfc->display, clipboard->respond->xselection.requestor, 0, 0, clipboard->respond); + XFlush(xfc->display); + + free(clipboard->respond); + clipboard->respond = NULL; + + return 1; +} + +xfClipboard* xf_clipboard_new(xfContext* xfc) +{ + int n; + UINT32 id; + rdpChannels* channels; + xfClipboard* clipboard; + + clipboard = (xfClipboard*) calloc(1, sizeof(xfClipboard)); + + xfc->clipboard = clipboard; + + clipboard->xfc = xfc; + + channels = ((rdpContext*) xfc)->channels; + clipboard->channels = channels; + + clipboard->system = ClipboardCreate(); + + clipboard->requestedFormatId = -1; + + clipboard->root_window = DefaultRootWindow(xfc->display); + clipboard->clipboard_atom = XInternAtom(xfc->display, "CLIPBOARD", FALSE); + + if (clipboard->clipboard_atom == None) + { + WLog_ERR(TAG, "unable to get CLIPBOARD atom"); + free(clipboard); + return NULL; + } + + id = 1; + clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE); + clipboard->identity_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_ID", FALSE); + + XChangeProperty(xfc->display, xfc->drawable, clipboard->identity_atom, + XA_INTEGER, 32, PropModeReplace, (BYTE*) &id, 1); + + XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask); + +#ifdef WITH_XFIXES + if (XFixesQueryExtension(xfc->display, &clipboard->xfixes_event_base, &clipboard->xfixes_error_base)) + { + int xfmajor, xfminor; + + if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor)) + { + XFixesSelectSelectionInput(xfc->display, clipboard->root_window, + clipboard->clipboard_atom, XFixesSetSelectionOwnerNotifyMask); + clipboard->xfixes_supported = TRUE; + } + else + { + WLog_ERR(TAG, "Error querying X Fixes extension version"); + } + } + else + { + WLog_ERR(TAG, "Error loading X Fixes extension"); + } +#else + WLog_ERR(TAG, "Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!"); +#endif + + n = 0; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW", False); + clipboard->clientFormats[n].formatId = 0; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "UTF8_STRING", False); + clipboard->clientFormats[n].formatId = CF_UNICODETEXT; + n++; + + clipboard->clientFormats[n].atom = XA_STRING; + clipboard->clientFormats[n].formatId = CF_TEXT; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/png", False); + clipboard->clientFormats[n].formatId = CB_FORMAT_PNG; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/jpeg", False); + clipboard->clientFormats[n].formatId = CB_FORMAT_JPEG; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/gif", False); + clipboard->clientFormats[n].formatId = CB_FORMAT_GIF; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/bmp", False); + clipboard->clientFormats[n].formatId = CF_DIB; + n++; + + clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/html", False); + clipboard->clientFormats[n].formatId = CB_FORMAT_HTML; + clipboard->clientFormats[n].formatName = _strdup("HTML Format"); + n++; + + clipboard->numClientFormats = n; + + clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE); + clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE); + clipboard->numTargets = 2; + + clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); + + return clipboard; +} + +void xf_clipboard_free(xfClipboard* clipboard) +{ + int i; + + if (!clipboard) + return; + + if (clipboard->serverFormats) + { + for (i = 0; i < clipboard->numServerFormats; i++) + free(clipboard->serverFormats[i].formatName); + + free(clipboard->serverFormats); + clipboard->serverFormats = NULL; + } + + ClipboardDestroy(clipboard->system); + + free(clipboard->data); + free(clipboard->respond); + free(clipboard->incr_data); + free(clipboard); +} + +void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr) +{ + xfc->cliprdr = cliprdr; + xfc->clipboard->context = cliprdr; + cliprdr->custom = (void*) xfc->clipboard; + + cliprdr->MonitorReady = xf_cliprdr_monitor_ready; + cliprdr->ServerCapabilities = xf_cliprdr_server_capabilities; + cliprdr->ServerFormatList = xf_cliprdr_server_format_list; + cliprdr->ServerFormatListResponse = xf_cliprdr_server_format_list_response; + cliprdr->ServerFormatDataRequest = xf_cliprdr_server_format_data_request; + cliprdr->ServerFormatDataResponse = xf_cliprdr_server_format_data_response; +} + +void xf_cliprdr_uninit(xfContext* xfc, CliprdrClientContext* cliprdr) +{ + xfc->cliprdr = NULL; + cliprdr->custom = NULL; + + if (xfc->clipboard) + xfc->clipboard->context = NULL; +} diff --git a/client/X11/xf_cliprdr.h b/client/X11/xf_cliprdr.h index 3e3d680ee..7175b3a54 100644 --- a/client/X11/xf_cliprdr.h +++ b/client/X11/xf_cliprdr.h @@ -23,13 +23,14 @@ #include "xf_client.h" #include "xfreerdp.h" -void xf_cliprdr_init(xfContext* xfc, rdpChannels* channels); -void xf_cliprdr_uninit(xfContext* xfc); -void xf_process_cliprdr_event(xfContext* xfc, wMessage* event); -BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent); -BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent); -BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent); -BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent); -void xf_cliprdr_check_owner(xfContext* xfc); +#include + +xfClipboard* xf_clipboard_new(xfContext* xfc); +void xf_clipboard_free(xfClipboard* clipboard); + +void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr); +void xf_cliprdr_uninit(xfContext* xfc, CliprdrClientContext* cliprdr); + +void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event); #endif /* __XF_CLIPRDR_H */ diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index a4692fe3a..5260fb832 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -25,6 +25,7 @@ #include #include +#include #include "xf_rail.h" #include "xf_window.h" @@ -35,6 +36,8 @@ #include "xf_event.h" #include "xf_input.h" +#define TAG CLIENT_TAG("x11") + #define CLAMP_COORDINATES(x, y) if (x < 0) x = 0; if (y < 0) y = 0 const char* const X11_EVENT_STRINGS[] = @@ -77,15 +80,15 @@ const char* const X11_EVENT_STRINGS[] = }; #ifdef WITH_DEBUG_X11 -#define DEBUG_X11(fmt, ...) DEBUG_CLASS(X11, fmt, ## __VA_ARGS__) +#define DEBUG_X11(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_X11(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_X11(fmt, ...) do { } while (0) #endif #ifdef WITH_DEBUG_X11_LOCAL_MOVESIZE -#define DEBUG_X11_LMS(fmt, ...) DEBUG_CLASS(X11_LMS, fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) do { } while (0) #endif int xf_event_action_script_init(xfContext* xfc) @@ -545,9 +548,6 @@ static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app) xf_keyboard_focus_in(xfc); - if (!app) - xf_cliprdr_check_owner(xfc); - return TRUE; } @@ -793,39 +793,6 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_SelectionNotify(xfContext* xfc, XEvent* event, BOOL app) -{ - if (!app) - { - if (xf_cliprdr_process_selection_notify(xfc, event)) - return TRUE; - } - - return TRUE; -} - -static BOOL xf_event_SelectionRequest(xfContext* xfc, XEvent* event, BOOL app) -{ - if (!app) - { - if (xf_cliprdr_process_selection_request(xfc, event)) - return TRUE; - } - - return TRUE; -} - -static BOOL xf_event_SelectionClear(xfContext* xfc, XEvent* event, BOOL app) -{ - if (!app) - { - if (xf_cliprdr_process_selection_clear(xfc, event)) - return TRUE; - } - - return TRUE; -} - static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) { /* @@ -922,11 +889,6 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) } } } - else - { - if (xf_cliprdr_process_property_notify(xfc, event)) - return TRUE; - } return TRUE; } @@ -1112,24 +1074,17 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) status = xf_event_ClientMessage(xfc, event, xfc->remote_app); break; - case SelectionNotify: - status = xf_event_SelectionNotify(xfc, event, xfc->remote_app); - break; - - case SelectionRequest: - status = xf_event_SelectionRequest(xfc, event, xfc->remote_app); - break; - - case SelectionClear: - status = xf_event_SelectionClear(xfc, event, xfc->remote_app); - break; - case PropertyNotify: status = xf_event_PropertyNotify(xfc, event, xfc->remote_app); break; } + if (!xfc->remote_app) + { + xf_cliprdr_handle_xevent(xfc, event); + } + xf_input_handle_event(xfc, event); XSync(xfc->display, FALSE); diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 1ab20af06..fcf4db5e2 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -33,6 +33,9 @@ #include "xf_gdi.h" +#include +#define TAG CLIENT_TAG("x11") + static UINT8 GDI_BS_HATCHED_PATTERNS[] = { 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */ @@ -68,7 +71,7 @@ BOOL xf_set_rop2(xfContext* xfc, int rop2) { if ((rop2 < 0x01) || (rop2 > 0x10)) { - fprintf(stderr, "Unsupported ROP2: %d\n", rop2); + WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); return FALSE; } @@ -204,7 +207,7 @@ BOOL xf_set_rop3(xfContext* xfc, int rop3) if (function < 0) { - fprintf(stderr, "Unsupported ROP3: 0x%08X\n", rop3); + WLog_ERR(TAG, "Unsupported ROP3: 0x%08X", rop3); XSetFunction(xfc->display, xfc->gc, GXclear); return FALSE; } @@ -214,6 +217,28 @@ BOOL xf_set_rop3(xfContext* xfc, int rop3) return TRUE; } +unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color) +{ + XColor x11_color; + + x11_color.flags = DoRed | DoGreen | DoBlue; + GetRGB32(x11_color.red, x11_color.green, x11_color.blue, color); + x11_color.red = x11_color.red << 8; + x11_color.green = x11_color.green << 8; + x11_color.blue = x11_color.blue << 8; + + if (XAllocColor(xfc->display, xfc->colormap, &x11_color) != 0) + { + XFreeColors(xfc->display, xfc->colormap, &x11_color.pixel, 1, 0); + } + else + { + x11_color.pixel = BlackPixel(xfc->display, xfc->screen_number); + } + + return x11_color.pixel; +} + Pixmap xf_brush_new(xfContext* xfc, int width, int height, int bpp, BYTE* data) { Pixmap bitmap; @@ -222,7 +247,7 @@ Pixmap xf_brush_new(xfContext* xfc, int width, int height, int bpp, BYTE* data) bitmap = XCreatePixmap(xfc->display, xfc->drawable, width, height, xfc->depth); - if (data != NULL) + if (data) { GC gc; @@ -236,7 +261,7 @@ Pixmap xf_brush_new(xfContext* xfc, int width, int height, int bpp, BYTE* data) XFree(image); if (cdata != data) - free(cdata); + _aligned_free(cdata); XFreeGC(xfc->display, gc); } @@ -263,14 +288,136 @@ Pixmap xf_mono_bitmap_new(xfContext* xfc, int width, int height, BYTE* data) return bitmap; } +void xf_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) +{ + int status; + int nXDst; + int nYDst; + int nXSrc; + int nYSrc; + int nWidth; + int nHeight; + UINT32 index; + XImage* image; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + BOOL compressed; + UINT32 SrcFormat; + UINT32 bitsPerPixel; + UINT32 bytesPerPixel; + BITMAP_DATA* bitmap; + rdpCodecs* codecs = context->codecs; + xfContext* xfc = (xfContext*) context; + + for (index = 0; index < bitmapUpdate->number; index++) + { + bitmap = &(bitmapUpdate->rectangles[index]); + + nXSrc = 0; + nYSrc = 0; + + nXDst = bitmap->destLeft; + nYDst = bitmap->destTop; + + nWidth = bitmap->width; + nHeight = bitmap->height; + + pSrcData = bitmap->bitmapDataStream; + SrcSize = bitmap->bitmapLength; + + compressed = bitmap->compressed; + bitsPerPixel = bitmap->bitsPerPixel; + bytesPerPixel = (bitsPerPixel + 7) / 8; + + SrcFormat = gdi_get_pixel_format(bitsPerPixel, TRUE); + + if (xfc->bitmap_size < (nWidth * nHeight * 4)) + { + xfc->bitmap_size = nWidth * nHeight * 4; + xfc->bitmap_buffer = (BYTE*) _aligned_realloc(xfc->bitmap_buffer, xfc->bitmap_size, 16); + + if (!xfc->bitmap_buffer) + return; + } + + if (compressed) + { + pDstData = xfc->bitmap_buffer; + + if (bitsPerPixel < 32) + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(codecs->interleaved, pSrcData, SrcSize, bitsPerPixel, + &pDstData, xfc->format, -1, 0, 0, nWidth, nHeight, xfc->palette); + } + else + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(codecs->planar, pSrcData, SrcSize, &pDstData, + xfc->format, -1, 0, 0, nWidth, nHeight, TRUE); + } + + if (status < 0) + { + WLog_ERR(TAG, "bitmap decompression failure"); + return; + } + + pSrcData = xfc->bitmap_buffer; + } + else + { + pDstData = xfc->bitmap_buffer; + + status = freerdp_image_copy(pDstData, xfc->format, -1, 0, 0, + nWidth, nHeight, pSrcData, SrcFormat, -1, 0, 0, xfc->palette); + + pSrcData = xfc->bitmap_buffer; + } + + xf_lock_x11(xfc, FALSE); + + XSetFunction(xfc->display, xfc->gc, GXcopy); + + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) pSrcData, nWidth, nHeight, xfc->scanline_pad, 0); + + nWidth = bitmap->destRight - bitmap->destLeft + 1; /* clip width */ + nHeight = bitmap->destBottom - bitmap->destTop + 1; /* clip height */ + + XPutImage(xfc->display, xfc->primary, xfc->gc, + image, 0, 0, nXDst, nYDst, nWidth, nHeight); + + XFree(image); + + gdi_InvalidateRegion(xfc->hdc, nXDst, nYDst, nWidth, nHeight); + + xf_unlock_x11(xfc, FALSE); + } +} + void xf_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette) { + int index; + PALETTE_ENTRY* pe; + UINT32* palette32; xfContext* xfc = (xfContext*) context; xf_lock_x11(xfc, FALSE); CopyMemory(xfc->clrconv->palette, palette, sizeof(rdpPalette)); + palette32 = (UINT32*) xfc->palette; + + for (index = 0; index < palette->number; index++) + { + pe = &(palette->entries[index]); + palette32[index] = RGB32(pe->red, pe->green, pe->blue); + } + xf_unlock_x11(xfc, FALSE); } @@ -281,7 +428,7 @@ void xf_gdi_set_bounds(rdpContext* context, rdpBounds* bounds) xf_lock_x11(xfc, FALSE); - if (bounds != NULL) + if (bounds) { clip.x = bounds->left; clip.y = bounds->top; @@ -312,7 +459,7 @@ void xf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XFillRectangle(xfc->display, xfc->drawable, xfc->gc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight); } @@ -337,8 +484,10 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) brush = &patblt->brush; xf_set_rop3(xfc, gdi_rop3_code(patblt->bRop)); - foreColor = freerdp_color_convert_var(patblt->foreColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); - backColor = freerdp_color_convert_var(patblt->backColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + foreColor = freerdp_convert_gdi_order_color(patblt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); + foreColor = xf_gdi_get_color(xfc, foreColor); + backColor = freerdp_convert_gdi_order_color(patblt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); + backColor = xf_gdi_get_color(xfc, backColor); if (brush->style == GDI_BS_SOLID) { @@ -398,13 +547,13 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) } else { - fprintf(stderr, "unimplemented brush style:%d\n", brush->style); + WLog_ERR(TAG, "unimplemented brush style:%d", brush->style); } if (xfc->drawing == xfc->primary) { XSetFunction(xfc->display, xfc->gc, GXcopy); - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight, patblt->nLeftRect, patblt->nTopRect); } @@ -429,7 +578,7 @@ void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { if (xfc->unobscured) { @@ -457,7 +606,8 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) xf_lock_x11(xfc, FALSE); - color = freerdp_color_convert_var(opaque_rect->color, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + color = freerdp_convert_gdi_order_color(opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette); + color = xf_gdi_get_color(xfc, color); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); @@ -469,12 +619,13 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XFillRectangle(xfc->display, xfc->drawable, xfc->gc, opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); } + gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); } @@ -491,7 +642,8 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult xf_lock_x11(xfc, FALSE); - color = freerdp_color_convert_var(multi_opaque_rect->color, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + color = freerdp_convert_gdi_order_color(multi_opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette); + color = xf_gdi_get_color(xfc, color); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); @@ -507,7 +659,7 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XFillRectangle(xfc->display, xfc->drawable, xfc->gc, rectangle->left, rectangle->top, @@ -522,7 +674,7 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult void xf_gdi_draw_nine_grid(rdpContext* context, DRAW_NINE_GRID_ORDER* draw_nine_grid) { - fprintf(stderr, "DrawNineGrid\n"); + WLog_ERR(TAG, "DrawNineGrid"); } void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to) @@ -533,7 +685,8 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to) xf_lock_x11(xfc, FALSE); xf_set_rop2(xfc, line_to->bRop2); - color = freerdp_color_convert_var(line_to->penColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + color = freerdp_convert_gdi_order_color(line_to->penColor, context->settings->ColorDepth, xfc->format, xfc->palette); + color = xf_gdi_get_color(xfc, color); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color); @@ -543,7 +696,7 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XDrawLine(xfc->display, xfc->drawable, xfc->gc, line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd); @@ -583,7 +736,8 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) xf_lock_x11(xfc, FALSE); xf_set_rop2(xfc, polyline->bRop2); - color = freerdp_color_convert_var(polyline->penColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + color = freerdp_convert_gdi_order_color(polyline->penColor, context->settings->ColorDepth, xfc->format, xfc->palette); + color = xf_gdi_get_color(xfc, color); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color); @@ -604,7 +758,7 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XDrawLines(xfc->display, xfc->drawable, xfc->gc, points, npoints, CoordModePrevious); } @@ -651,12 +805,13 @@ void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XCopyArea(xfc->display, bitmap->pixmap, xfc->drawable, xfc->gc, memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight, memblt->nLeftRect, memblt->nTopRect); } + gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight); } @@ -679,8 +834,10 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) brush = &mem3blt->brush; bitmap = (xfBitmap*) mem3blt->bitmap; xf_set_rop3(xfc, gdi_rop3_code(mem3blt->bRop)); - foreColor = freerdp_color_convert_var(mem3blt->foreColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); - backColor = freerdp_color_convert_var(mem3blt->backColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + foreColor = freerdp_convert_gdi_order_color(mem3blt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); + foreColor = xf_gdi_get_color(xfc, foreColor); + backColor = freerdp_convert_gdi_order_color(mem3blt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); + backColor = xf_gdi_get_color(xfc, backColor); if (brush->style == GDI_BS_PATTERN) { @@ -713,7 +870,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) } else { - fprintf(stderr, "Mem3Blt unimplemented brush style:%d\n", brush->style); + WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%d", brush->style); } XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, @@ -722,7 +879,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) if (xfc->drawing == xfc->primary) { - if (xfc->remote_app != TRUE) + if (!xfc->remote_app) { XCopyArea(xfc->display, bitmap->pixmap, xfc->drawable, xfc->gc, mem3blt->nXSrc, mem3blt->nYSrc, mem3blt->nWidth, mem3blt->nHeight, @@ -752,7 +909,8 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) xf_lock_x11(xfc, FALSE); xf_set_rop2(xfc, polygon_sc->bRop2); - brush_color = freerdp_color_convert_var(polygon_sc->brushColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + brush_color = freerdp_convert_gdi_order_color(polygon_sc->brushColor, context->settings->ColorDepth, xfc->format, xfc->palette); + brush_color = xf_gdi_get_color(xfc, brush_color); npoints = polygon_sc->numPoints + 1; points = malloc(sizeof(XPoint) * npoints); @@ -777,7 +935,7 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) break; default: - fprintf(stderr, "PolygonSC unknown fillMode: %d\n", polygon_sc->fillMode); + WLog_ERR(TAG, "PolygonSC unknown fillMode: %d", polygon_sc->fillMode); break; } @@ -813,8 +971,10 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) brush = &(polygon_cb->brush); xf_set_rop2(xfc, polygon_cb->bRop2); - foreColor = freerdp_color_convert_var(polygon_cb->foreColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); - backColor = freerdp_color_convert_var(polygon_cb->backColor, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + foreColor = freerdp_convert_gdi_order_color(polygon_cb->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); + foreColor = xf_gdi_get_color(xfc, foreColor); + backColor = freerdp_convert_gdi_order_color(polygon_cb->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); + backColor = xf_gdi_get_color(xfc, backColor); npoints = polygon_cb->numPoints + 1; points = malloc(sizeof(XPoint) * npoints); @@ -839,7 +999,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) break; default: - fprintf(stderr, "PolygonCB unknown fillMode: %d\n", polygon_cb->fillMode); + WLog_ERR(TAG, "PolygonCB unknown fillMode: %d", polygon_cb->fillMode); break; } @@ -897,7 +1057,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) } else { - fprintf(stderr, "PolygonCB unimplemented brush style:%d\n", brush->style); + WLog_ERR(TAG, "PolygonCB unimplemented brush style:%d", brush->style); } XSetFunction(xfc->display, xfc->gc, GXcopy); @@ -908,12 +1068,16 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) void xf_gdi_ellipse_sc(rdpContext* context, ELLIPSE_SC_ORDER* ellipse_sc) { - fprintf(stderr, "EllipseSC\n"); + WLog_ERR(TAG, "EllipseSC"); } void xf_gdi_ellipse_cb(rdpContext* context, ELLIPSE_CB_ORDER* ellipse_cb) { - fprintf(stderr, "EllipseCB\n"); + WLog_ERR(TAG, "EllipseCB"); +} + +void xf_gdi_frame_marker(rdpContext* context, FRAME_MARKER_ORDER* frameMarker) +{ } void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) @@ -984,35 +1148,57 @@ static void xf_gdi_surface_update_frame(xfContext* xfc, UINT16 tx, UINT16 ty, UI } } -void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) +void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd) { int i, tx, ty; XImage* image; + BYTE* pSrcData; + BYTE* pDstData; RFX_MESSAGE* message; xfContext* xfc = (xfContext*) context; xf_lock_x11(xfc, FALSE); - if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX) + if (cmd->codecID == RDP_CODEC_ID_REMOTEFX) { - message = rfx_process_message(xfc->rfx, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_REMOTEFX); + + message = rfx_process_message(xfc->codecs->rfx, cmd->bitmapData, cmd->bitmapDataLength); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); - XSetClipRectangles(xfc->display, xfc->gc, - surface_bits_command->destLeft, surface_bits_command->destTop, + XSetClipRectangles(xfc->display, xfc->gc, cmd->destLeft, cmd->destTop, (XRectangle*) message->rects, message->numRects, YXBanded); + if (xfc->bitmap_size < (64 * 64 * 4)) + { + xfc->bitmap_size = 64 * 64 * 4; + xfc->bitmap_buffer = (BYTE*) _aligned_realloc(xfc->bitmap_buffer, xfc->bitmap_size, 16); + + if (!xfc->bitmap_buffer) + return; + } + /* Draw the tiles to primary surface, each is 64x64. */ for (i = 0; i < message->numTiles; i++) { - image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, - (char*) message->tiles[i]->data, 64, 64, 32, 0); + pSrcData = message->tiles[i]->data; + pDstData = pSrcData; - tx = message->tiles[i]->x + surface_bits_command->destLeft; - ty = message->tiles[i]->y + surface_bits_command->destTop; + if ((xfc->depth != 24) || (xfc->depth != 32)) + { + pDstData = xfc->bitmap_buffer; + + freerdp_image_copy(pDstData, xfc->format, -1, 0, 0, + 64, 64, pSrcData, PIXEL_FORMAT_XRGB32, -1, 0, 0, xfc->palette); + } + + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) pDstData, 64, 64, xfc->scanline_pad, 0); + + tx = message->tiles[i]->x + cmd->destLeft; + ty = message->tiles[i]->y + cmd->destTop; XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, tx, ty, 64, 64); XFree(image); @@ -1021,102 +1207,106 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits /* Copy the updated region from backstore to the window. */ for (i = 0; i < message->numRects; i++) { - tx = message->rects[i].x + surface_bits_command->destLeft; - ty = message->rects[i].y + surface_bits_command->destTop; - if (xfc->remote_app != TRUE) + tx = message->rects[i].x + cmd->destLeft; + ty = message->rects[i].y + cmd->destTop; + + if (!xfc->remote_app) { - XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, tx, ty, message->rects[i].width, message->rects[i].height, tx, ty); + XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, + tx, ty, message->rects[i].width, message->rects[i].height, tx, ty); } xf_gdi_surface_update_frame(xfc, tx, ty, message->rects[i].width, message->rects[i].height); } XSetClipMask(xfc->display, xfc->gc, None); - rfx_message_free(xfc->rfx, message); + rfx_message_free(xfc->codecs->rfx, message); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC) + else if (cmd->codecID == RDP_CODEC_ID_NSCODEC) { - nsc_process_message(xfc->nsc, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_NSCODEC); + + nsc_process_message(xfc->codecs->nsc, cmd->bpp, cmd->width, cmd->height, cmd->bitmapData, cmd->bitmapDataLength); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); - xfc->bmp_codec_nsc = (BYTE*) realloc(xfc->bmp_codec_nsc, - surface_bits_command->width * surface_bits_command->height * 4); + if (xfc->bitmap_size < (cmd->width * cmd->height * 4)) + { + xfc->bitmap_size = cmd->width * cmd->height * 4; + xfc->bitmap_buffer = (BYTE*) _aligned_realloc(xfc->bitmap_buffer, xfc->bitmap_size, 16); - freerdp_image_flip(xfc->nsc->BitmapData, xfc->bmp_codec_nsc, - surface_bits_command->width, surface_bits_command->height, 32); + if (!xfc->bitmap_buffer) + return; + } - image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, - (char*) xfc->bmp_codec_nsc, surface_bits_command->width, surface_bits_command->height, 32, 0); + pSrcData = xfc->codecs->nsc->BitmapData; + pDstData = xfc->bitmap_buffer; + + freerdp_image_copy(pDstData, xfc->format, -1, 0, 0, + cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, xfc->palette); + + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) pDstData, cmd->width, cmd->height, xfc->scanline_pad, 0); XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height); + cmd->destLeft, cmd->destTop, cmd->width, cmd->height); + XFree(image); - free(xfc->bmp_codec_nsc); - xfc->bmp_codec_nsc = NULL; if (!xfc->remote_app) { XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height, - surface_bits_command->destLeft, surface_bits_command->destTop); + cmd->destLeft, cmd->destTop, cmd->width, cmd->height, + cmd->destLeft, cmd->destTop); } - xf_gdi_surface_update_frame(xfc, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height); + xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height); XSetClipMask(xfc->display, xfc->gc, None); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NONE) + else if (cmd->codecID == RDP_CODEC_ID_NONE) { XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); - /* Validate that the data received is large enough */ - if ((surface_bits_command->width * surface_bits_command->height * surface_bits_command->bpp / 8) <= (surface_bits_command->bitmapDataLength)) + if (xfc->bitmap_size < (cmd->width * cmd->height * 4)) { - xfc->bmp_codec_none = (BYTE*) realloc(xfc->bmp_codec_none, - surface_bits_command->width * surface_bits_command->height * 4); + xfc->bitmap_size = cmd->width * cmd->height * 4; + xfc->bitmap_buffer = (BYTE*) _aligned_realloc(xfc->bitmap_buffer, xfc->bitmap_size, 16); - freerdp_image_flip(surface_bits_command->bitmapData, xfc->bmp_codec_none, - surface_bits_command->width, surface_bits_command->height, 32); - - image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, - (char*) xfc->bmp_codec_none, surface_bits_command->width, surface_bits_command->height, 32, 0); - - XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height); - XFree(image); - free(xfc->bmp_codec_none); - xfc->bmp_codec_none = NULL; - - if (xfc->remote_app != TRUE) - { - XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height, - surface_bits_command->destLeft, surface_bits_command->destTop); - } - xf_gdi_surface_update_frame(xfc, - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height); - - XSetClipMask(xfc->display, xfc->gc, None); + if (!xfc->bitmap_buffer) + return; } - else + + pSrcData = cmd->bitmapData; + pDstData = xfc->bitmap_buffer; + + freerdp_image_copy(pDstData, xfc->format, -1, 0, 0, + cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, xfc->palette); + + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) pDstData, cmd->width, cmd->height, xfc->scanline_pad, 0); + + XPutImage(xfc->display, xfc->primary, xfc->gc, image, 0, 0, + cmd->destLeft, cmd->destTop, + cmd->width, cmd->height); + XFree(image); + + if (!xfc->remote_app) { - fprintf(stderr, "Invalid bitmap size - data is %d bytes for %dx%d\n update", surface_bits_command->bitmapDataLength, surface_bits_command->width, surface_bits_command->height); + XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, + cmd->destLeft, cmd->destTop, + cmd->width, cmd->height, cmd->destLeft, cmd->destTop); } + + xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height); + + XSetClipMask(xfc->display, xfc->gc, None); } else { - fprintf(stderr, "Unsupported codecID %d\n", surface_bits_command->codecID); + WLog_ERR(TAG, "Unsupported codecID %d", cmd->codecID); } xf_unlock_x11(xfc, FALSE); @@ -1154,5 +1344,7 @@ void xf_gdi_register_update_callbacks(rdpUpdate* update) update->SurfaceBits = xf_gdi_surface_bits; update->SurfaceFrameMarker = xf_gdi_surface_frame_marker; + + update->altsec->FrameMarker = xf_gdi_frame_marker; } diff --git a/client/X11/xf_gdi.h b/client/X11/xf_gdi.h index 413f1c6e7..eefd97c6d 100644 --- a/client/X11/xf_gdi.h +++ b/client/X11/xf_gdi.h @@ -26,5 +26,6 @@ #include "xfreerdp.h" void xf_gdi_register_update_callbacks(rdpUpdate* update); +void xf_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate); #endif /* __XF_GDI_H */ diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index fec5036b8..2cbd1d4ff 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -21,40 +21,16 @@ #include "config.h" #endif +#include #include "xf_gfx.h" +#define TAG CLIENT_TAG("x11") + int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) { xfContext* xfc = (xfContext*) context->custom; - printf("xf_ResetGraphics: width: %d height: %d\n", - resetGraphics->width, resetGraphics->height); - - if (xfc->rfx) - { - rfx_context_free(xfc->rfx); - xfc->rfx = NULL; - } - - xfc->rfx = rfx_context_new(FALSE); - - xfc->rfx->width = resetGraphics->width; - xfc->rfx->height = resetGraphics->height; - rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - - if (xfc->nsc) - { - nsc_context_free(xfc->nsc); - xfc->nsc = NULL; - } - - xfc->nsc = nsc_context_new(); - - xfc->nsc->width = resetGraphics->width; - xfc->nsc->height = resetGraphics->height; - nsc_context_set_pixel_format(xfc->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); - - xfc->clear = clear_context_new(FALSE); + freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL); region16_init(&(xfc->invalidRegion)); @@ -102,9 +78,14 @@ int xf_OutputUpdate(xfContext* xfc) if (height > xfc->height) height = xfc->height; + if (surface->stage) + { + freerdp_image_copy(surface->stage, xfc->format, surface->stageStep, 0, 0, + surface->width, surface->height, surface->data, surface->format, surface->scanline, 0, 0, NULL); + } + XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, - extents->left, extents->top, - extents->left, extents->top, width, height); + extents->left, extents->top, extents->left, extents->top, width, height); } region16_clear(&(xfc->invalidRegion)); @@ -161,8 +142,8 @@ int xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, if (!surface) return -1; - freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, - cmd->width, cmd->height, cmd->data, PIXEL_FORMAT_XRGB32, cmd->width * 4, 0, 0); + freerdp_image_copy(surface->data, surface->format, surface->scanline, cmd->left, cmd->top, + cmd->width, cmd->height, cmd->data, PIXEL_FORMAT_XRGB32, -1, 0, 0, NULL); invalidRect.left = cmd->left; invalidRect.top = cmd->top; @@ -194,12 +175,14 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP REGION16 clippingRects; RECTANGLE_16 clippingRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_REMOTEFX); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return -1; - message = rfx_process_message(xfc->rfx, cmd->data, cmd->length); + message = rfx_process_message(xfc->codecs->rfx, cmd->data, cmd->length); if (!message) return -1; @@ -238,9 +221,9 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP nWidth = updateRects[j].right - updateRects[j].left; nHeight = updateRects[j].bottom - updateRects[j].top; - freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + freerdp_image_copy(surface->data, surface->format, surface->scanline, nXDst, nYDst, nWidth, nHeight, - tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0); + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0, NULL); region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]); } @@ -248,7 +231,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP region16_uninit(&updateRegion); } - rfx_message_free(xfc->rfx, message); + rfx_message_free(xfc->codecs->rfx, message); if (!xfc->inGfxFrame) xf_OutputUpdate(xfc); @@ -259,24 +242,27 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status; - UINT32 DstSize = 0; - BYTE* pDstData = NULL; + BYTE* DstData = NULL; xfGfxSurface* surface; RECTANGLE_16 invalidRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_CLEARCODEC); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return -1; - status = clear_decompress(xfc->clear, cmd->data, cmd->length, &pDstData, &DstSize); + DstData = surface->data; - printf("xf_SurfaceCommand_ClearCodec: status: %d\n", status); + status = clear_decompress(xfc->codecs->clear, cmd->data, cmd->length, &DstData, + surface->format, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); - /* fill with pink for now to distinguish from the rest */ - - freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, - cmd->left, cmd->top, cmd->width, cmd->height, 0xFF69B4); + if (status < 0) + { + WLog_ERR(TAG, "clear_decompress failure: %d\n", status); + return -1; + } invalidRect.left = cmd->left; invalidRect.top = cmd->top; @@ -298,6 +284,8 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF xfGfxSurface* surface; RECTANGLE_16 invalidRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PLANAR); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) @@ -305,8 +293,8 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF DstData = surface->data; - status = planar_decompress(NULL, cmd->data, cmd->length, &DstData, - PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); + status = planar_decompress(xfc->codecs->planar, cmd->data, cmd->length, &DstData, + surface->format, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, FALSE); invalidRect.left = cmd->left; invalidRect.top = cmd->top; @@ -321,6 +309,180 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF return 1; } +int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + UINT32 i; + BYTE* DstData = NULL; + H264_CONTEXT* h264; + xfGfxSurface* surface; + RDPGFX_H264_METABLOCK* meta; + RDPGFX_H264_BITMAP_STREAM* bs; + + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_H264); + + h264 = xfc->codecs->h264; + + bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; + + if (!bs) + return -1; + + meta = &(bs->meta); + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = h264_decompress(xfc->codecs->h264, bs->data, bs->length, &DstData, + surface->format, surface->scanline , surface->height, meta->regionRects, meta->numRegionRects); + + if (status < 0) + { + WLog_ERR(TAG, "h264_decompress failure: %d",status); + return -1; + } + + for (i = 0; i < meta->numRegionRects; i++) + { + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), (RECTANGLE_16*) &(meta->regionRects[i])); + } + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + +int xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_ALPHACODEC); + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + WLog_DBG(TAG, "xf_SurfaceCommand_Alpha: status: %d\n", status); + /* fill with green for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0x00FF00); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + +int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int i, j; + int status; + BYTE* DstData; + RFX_RECT* rect; + int nXDst, nYDst; + int nXSrc, nYSrc; + int nWidth, nHeight; + int nbUpdateRects; + xfGfxSurface* surface; + REGION16 updateRegion; + RECTANGLE_16 updateRect; + RECTANGLE_16* updateRects; + REGION16 clippingRects; + RECTANGLE_16 clippingRect; + RFX_PROGRESSIVE_TILE* tile; + PROGRESSIVE_BLOCK_REGION* region; + + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PROGRESSIVE); + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + progressive_create_surface_context(xfc->codecs->progressive, cmd->surfaceId, surface->width, surface->height); + + DstData = surface->data; + + status = progressive_decompress(xfc->codecs->progressive, cmd->data, cmd->length, &DstData, + surface->format, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, cmd->surfaceId); + + if (status < 0) + { + WLog_ERR(TAG, "progressive_decompress failure: %d", status); + return -1; + } + + region = &(xfc->codecs->progressive->region); + + region16_init(&clippingRects); + + for (i = 0; i < region->numRects; i++) + { + rect = &(region->rects[i]); + + clippingRect.left = cmd->left + rect->x; + clippingRect.top = cmd->top + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); + } + + for (i = 0; i < region->numTiles; i++) + { + tile = region->tiles[i]; + + updateRect.left = cmd->left + tile->x; + updateRect.top = cmd->top + tile->y; + updateRect.right = updateRect.left + 64; + updateRect.bottom = updateRect.top + 64; + + region16_init(&updateRegion); + region16_intersect_rect(&updateRegion, &clippingRects, &updateRect); + updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects); + + for (j = 0; j < nbUpdateRects; j++) + { + nXDst = updateRects[j].left; + nYDst = updateRects[j].top; + nWidth = updateRects[j].right - updateRects[j].left; + nHeight = updateRects[j].bottom - updateRects[j].top; + + nXSrc = nXDst - (cmd->left + tile->x); + nYSrc = nYDst - (cmd->top + tile->y); + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, nXDst, nYDst, nWidth, nHeight, + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL); + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]); + } + + region16_uninit(&updateRegion); + } + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status = 1; @@ -345,19 +507,18 @@ int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) break; case RDPGFX_CODECID_H264: - printf("xf_SurfaceCommand_H264\n"); + status = xf_SurfaceCommand_H264(xfc, context, cmd); break; case RDPGFX_CODECID_ALPHA: - printf("xf_SurfaceCommand_Alpha\n"); + status = xf_SurfaceCommand_Alpha(xfc, context, cmd); break; case RDPGFX_CODECID_CAPROGRESSIVE: - printf("xf_SurfaceCommand_Progressive\n"); + status = xf_SurfaceCommand_Progressive(xfc, context, cmd); break; case RDPGFX_CODECID_CAPROGRESSIVE_V2: - printf("xf_SurfaceCommand_ProgressiveV2\n"); break; } @@ -366,19 +527,16 @@ int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) int xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext) { - printf("xf_DeleteEncodingContext\n"); - return 1; } int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface) { + size_t size; + UINT32 bytesPerPixel; xfGfxSurface* surface; xfContext* xfc = (xfContext*) context->custom; - printf("xf_CreateSurface: surfaceId: %d width: %d height: %d format: 0x%02X\n", - createSurface->surfaceId, createSurface->width, createSurface->height, createSurface->pixelFormat); - surface = (xfGfxSurface*) calloc(1, sizeof(xfGfxSurface)); if (!surface) @@ -388,15 +546,41 @@ int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* cr surface->width = (UINT32) createSurface->width; surface->height = (UINT32) createSurface->height; surface->alpha = (createSurface->pixelFormat == PIXEL_FORMAT_ARGB_8888) ? TRUE : FALSE; + surface->format = PIXEL_FORMAT_XRGB32; - surface->scanline = (surface->width + (surface->width % 4)) * 4; - surface->data = (BYTE*) calloc(1, surface->scanline * surface->height); + surface->scanline = surface->width * 4; + surface->scanline += (surface->scanline % (xfc->scanline_pad / 8)); + + size = surface->scanline * surface->height; + surface->data = (BYTE*) _aligned_malloc(size, 16); if (!surface->data) return -1; - surface->image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, - (char*) surface->data, surface->width, surface->height, 32, surface->scanline); + ZeroMemory(surface->data, size); + + if ((xfc->depth == 24) || (xfc->depth == 32)) + { + surface->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) surface->data, surface->width, surface->height, xfc->scanline_pad, surface->scanline); + } + else + { + bytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(xfc->format) / 8); + surface->stageStep = surface->width * bytesPerPixel; + surface->stageStep += (surface->stageStep % (xfc->scanline_pad / 8)); + size = surface->stageStep * surface->height; + + surface->stage = (BYTE*) _aligned_malloc(size, 16); + + if (!surface->stage) + return -1; + + ZeroMemory(surface->stage, size); + + surface->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*) surface->stage, surface->width, surface->height, xfc->scanline_pad, surface->stageStep); + } context->SetSurfaceData(context, surface->surfaceId, (void*) surface); @@ -406,20 +590,23 @@ int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* cr int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface) { xfGfxSurface* surface = NULL; + xfContext* xfc = (xfContext*) context->custom; surface = (xfGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId); - printf("xf_DeleteSurface: surfaceId: %d\n", deleteSurface->surfaceId); - if (surface) { XFree(surface->image); - free(surface->data); + _aligned_free(surface->data); + _aligned_free(surface->stage); free(surface); } context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); + if (xfc->codecs->progressive) + progressive_delete_surface_context(xfc->codecs->progressive, deleteSurface->surfaceId); + return 1; } @@ -436,8 +623,6 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) surface = (xfGfxSurface*) context->GetSurfaceData(context, solidFill->surfaceId); - printf("xf_SolidFill\n"); - if (!surface) return -1; @@ -460,7 +645,7 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) invalidRect.right = rect->right; invalidRect.bottom = rect->bottom; - freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + freerdp_image_fill(surface->data, surface->format, surface->scanline, rect->left, rect->top, nWidth, nHeight, color); region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); @@ -475,6 +660,7 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface) { UINT16 index; + BOOL sameSurface; int nWidth, nHeight; RDPGFX_RECT16* rectSrc; RDPGFX_POINT16* destPt; @@ -488,7 +674,9 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ surfaceSrc = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc); - if (surfaceToSurface->surfaceIdSrc != surfaceToSurface->surfaceIdDest) + sameSurface = (surfaceToSurface->surfaceIdSrc == surfaceToSurface->surfaceIdDest) ? TRUE : FALSE; + + if (!sameSurface) surfaceDst = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest); else surfaceDst = surfaceSrc; @@ -496,16 +684,24 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ if (!surfaceSrc || !surfaceDst) return -1; - nWidth = rectSrc->right - rectSrc->left + 1; - nHeight = rectSrc->bottom - rectSrc->top + 1; + nWidth = rectSrc->right - rectSrc->left; + nHeight = rectSrc->bottom - rectSrc->top; for (index = 0; index < surfaceToSurface->destPtsCount; index++) { destPt = &surfaceToSurface->destPts[index]; - freerdp_image_copy(surfaceDst->data, PIXEL_FORMAT_XRGB32, surfaceDst->scanline, - destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, PIXEL_FORMAT_XRGB32, - surfaceSrc->scanline, rectSrc->left, rectSrc->top); + if (sameSurface) + { + freerdp_image_move(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, + destPt->x, destPt->y, nWidth, nHeight, rectSrc->left, rectSrc->top); + } + else + { + freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, + destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, surfaceSrc->format, + surfaceSrc->scanline, rectSrc->left, rectSrc->top, NULL); + } invalidRect.left = destPt->x; invalidRect.top = destPt->y; @@ -523,17 +719,16 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ int xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) { + size_t size; RDPGFX_RECT16* rect; xfGfxSurface* surface; xfGfxCacheEntry* cacheEntry; + xfContext* xfc = (xfContext*) context->custom; rect = &(surfaceToCache->rectSrc); surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId); - //printf("xf_SurfaceToCache: cacheKey: 0x%016X cacheSlot: %ld\n", - // surfaceToCache->cacheKey, surfaceToCache->cacheSlot); - if (!surface) return -1; @@ -545,16 +740,22 @@ int xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* cacheEntry->width = (UINT32) (rect->right - rect->left); cacheEntry->height = (UINT32) (rect->bottom - rect->top); cacheEntry->alpha = surface->alpha; + cacheEntry->format = surface->format; - cacheEntry->scanline = (cacheEntry->width + (cacheEntry->width % 4)) * 4; - cacheEntry->data = (BYTE*) calloc(1, surface->scanline * surface->height); + cacheEntry->scanline = cacheEntry->width * 4; + cacheEntry->scanline += (cacheEntry->scanline % (xfc->scanline_pad / 8)); + + size = cacheEntry->scanline * cacheEntry->height; + cacheEntry->data = (BYTE*) _aligned_malloc(size, 16); if (!cacheEntry->data) return -1; - freerdp_image_copy(cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline, + ZeroMemory(cacheEntry->data, size); + + freerdp_image_copy(cacheEntry->data, cacheEntry->format, cacheEntry->scanline, 0, 0, cacheEntry->width, cacheEntry->height, surface->data, - PIXEL_FORMAT_XRGB32, surface->scanline, rect->left, rect->top); + surface->format, surface->scanline, rect->left, rect->top, NULL); context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (void*) cacheEntry); @@ -573,9 +774,6 @@ int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* surface = (xfGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId); cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, cacheToSurface->cacheSlot); - //printf("xf_CacheToSurface: cacheEntry: %d\n", - // cacheToSurface->cacheSlot); - if (!surface || !cacheEntry) return -1; @@ -583,9 +781,9 @@ int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* { destPt = &cacheToSurface->destPts[index]; - freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + freerdp_image_copy(surface->data, surface->format, surface->scanline, destPt->x, destPt->y, cacheEntry->width, cacheEntry->height, - cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline, 0, 0); + cacheEntry->data, cacheEntry->format, cacheEntry->scanline, 0, 0, NULL); invalidRect.left = destPt->x; invalidRect.top = destPt->y; @@ -610,13 +808,11 @@ int xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PD { xfGfxCacheEntry* cacheEntry; - //printf("xf_EvictCacheEntry\n"); - cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, evictCacheEntry->cacheSlot); if (cacheEntry) { - free(cacheEntry->data); + _aligned_free(cacheEntry->data); free(cacheEntry); } diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index ba937ee92..06039a8cf 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -23,6 +23,8 @@ #include "xf_client.h" #include "xfreerdp.h" +#include + struct xf_gfx_surface { UINT16 surfaceId; @@ -30,8 +32,11 @@ struct xf_gfx_surface UINT32 height; BOOL alpha; BYTE* data; + BYTE* stage; XImage* image; int scanline; + int stageStep; + UINT32 format; }; typedef struct xf_gfx_surface xfGfxSurface; @@ -43,6 +48,7 @@ struct xf_gfx_cache_entry BOOL alpha; BYTE* data; int scanline; + UINT32 format; }; typedef struct xf_gfx_cache_entry xfGfxCacheEntry; diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index fa24d967c..a1f8ffebb 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -36,43 +36,55 @@ #include "xf_graphics.h" +#include +#define TAG CLIENT_TAG("x11") + /* Bitmap Class */ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { + int depth; BYTE* data; Pixmap pixmap; XImage* image; + UINT32 SrcFormat; xfContext* xfc = (xfContext*) context; xf_lock_x11(xfc, FALSE); - XSetFunction(xfc->display, xfc->gc, GXcopy); + data = bitmap->data; + depth = (bitmap->bpp >= 24) ? 24 : bitmap->bpp; + pixmap = XCreatePixmap(xfc->display, xfc->drawable, bitmap->width, bitmap->height, xfc->depth); - if (bitmap->data != NULL) + if (bitmap->data) { - data = freerdp_image_convert(bitmap->data, NULL, - bitmap->width, bitmap->height, context->settings->ColorDepth, xfc->bpp, xfc->clrconv); + XSetFunction(xfc->display, xfc->gc, GXcopy); - if (bitmap->ephemeral != TRUE) + if (depth != xfc->depth) { - image = XCreateImage(xfc->display, xfc->visual, xfc->depth, - ZPixmap, 0, (char*) data, bitmap->width, bitmap->height, xfc->scanline_pad, 0); + data = _aligned_malloc(bitmap->width * bitmap->height * 4, 16); - XPutImage(xfc->display, pixmap, xfc->gc, image, 0, 0, 0, 0, bitmap->width, bitmap->height); - XFree(image); + if (!data) + return; - if (data != bitmap->data) - free(data); - } - else - { - if (data != bitmap->data) - free(bitmap->data); + SrcFormat = gdi_get_pixel_format(bitmap->bpp, TRUE); + freerdp_image_copy(data, xfc->format, -1, 0, 0, + bitmap->width, bitmap->height, bitmap->data, SrcFormat, -1, 0, 0, xfc->palette); + + _aligned_free(bitmap->data); bitmap->data = data; + + bitmap->bpp = (xfc->depth >= 24) ? 32 : xfc->depth; } + + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, + ZPixmap, 0, (char*) bitmap->data, bitmap->width, bitmap->height, xfc->scanline_pad, 0); + + XPutImage(xfc->display, pixmap, xfc->gc, image, 0, 0, 0, 0, bitmap->width, bitmap->height); + + XFree(image); } ((xfBitmap*) bitmap)->pixmap = pixmap; @@ -120,83 +132,60 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, BYTE* data, int width, int height, int bpp, int length, - BOOL compressed, int codec_id) + BOOL compressed, int codecId) { + int status; UINT16 size; - BYTE* src; - BYTE* dst; - int yindex; - int xindex; - BOOL status; - RFX_MESSAGE* msg; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + UINT32 SrcFormat; + UINT32 bytesPerPixel; xfContext* xfc = (xfContext*) context; - size = width * height * ((bpp + 7) / 8); + bytesPerPixel = (bpp + 7) / 8; + size = width * height * 4; - if (bitmap->data == NULL) - bitmap->data = (BYTE*) malloc(size); - else - bitmap->data = (BYTE*) realloc(bitmap->data, size); + bitmap->data = (BYTE*) _aligned_malloc(size, 16); - switch (codec_id) + pSrcData = data; + SrcSize = (UINT32) length; + pDstData = bitmap->data; + + if (compressed) { - case RDP_CODEC_ID_NSCODEC: - fprintf(stderr, "xf_Bitmap_Decompress: nsc not done\n"); - break; + if (bpp < 32) + { + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_INTERLEAVED); - case RDP_CODEC_ID_REMOTEFX: - rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(xfc->rfx, data, length); + status = interleaved_decompress(xfc->codecs->interleaved, pSrcData, SrcSize, bpp, + &pDstData, xfc->format, -1, 0, 0, width, height, xfc->palette); + } + else + { + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PLANAR); - if (msg == NULL) - { - fprintf(stderr, "xf_Bitmap_Decompress: rfx Decompression Failed\n"); - } - else - { - for (yindex = 0; yindex < height; yindex++) - { - src = msg->tiles[0]->data + yindex * 64 * 4; - dst = bitmap->data + yindex * width * 3; - for (xindex = 0; xindex < width; xindex++) - { - *(dst++) = *(src++); - *(dst++) = *(src++); - *(dst++) = *(src++); - src++; - } - } - rfx_message_free(xfc->rfx, msg); - } - break; + status = planar_decompress(xfc->codecs->planar, pSrcData, SrcSize, + &pDstData, xfc->format, -1, 0, 0, width, height, TRUE); + } - case RDP_CODEC_ID_JPEG: - if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) - { - fprintf(stderr, "xf_Bitmap_Decompress: jpeg Decompression Failed\n"); - } - break; + if (status < 0) + { + WLog_ERR(TAG, "Bitmap Decompression Failed"); + return; + } + } + else + { + SrcFormat = gdi_get_pixel_format(bpp, TRUE); - default: - if (compressed) - { - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - - if (!status) - { - fprintf(stderr, "xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); - } - } - else - { - freerdp_image_flip(data, bitmap->data, width, height, bpp); - } - break; + status = freerdp_image_copy(pDstData, xfc->format, -1, 0, 0, + width, height, pSrcData, SrcFormat, -1, 0, 0, xfc->palette); } bitmap->compressed = FALSE; bitmap->length = size; - bitmap->bpp = bpp; + bitmap->bpp = (xfc->depth >= 24) ? 32 : xfc->depth; } void xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) @@ -231,8 +220,10 @@ void xf_Pointer_New(rdpContext* context, rdpPointer* pointer) ci.xhot = pointer->xPos; ci.yhot = pointer->yPos; - ci.pixels = (XcursorPixel*) malloc(ci.width * ci.height * 4); - ZeroMemory(ci.pixels, ci.width * ci.height * 4); + ci.pixels = (XcursorPixel*) calloc(1, ci.width * ci.height * 4); + + if (!ci.pixels) + return; if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0)) { @@ -387,19 +378,16 @@ void xf_Glyph_Draw(rdpContext* context, rdpGlyph* glyph, int x, int y) void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height, UINT32 bgcolor, UINT32 fgcolor) { - xfContext* context_ = (xfContext*) context; xfContext* xfc = (xfContext*) context; - bgcolor = (xfc->clrconv->invert)? - freerdp_color_convert_var_bgr(bgcolor, context_->settings->ColorDepth, xfc->bpp, xfc->clrconv): - freerdp_color_convert_var_rgb(bgcolor, context_->settings->ColorDepth, xfc->bpp, xfc->clrconv); - - fgcolor = (xfc->clrconv->invert)? - freerdp_color_convert_var_bgr(fgcolor, context_->settings->ColorDepth, xfc->bpp, xfc->clrconv): - freerdp_color_convert_var_rgb(fgcolor, context_->settings->ColorDepth, xfc->bpp, xfc->clrconv); + bgcolor = freerdp_convert_gdi_order_color(bgcolor, context->settings->ColorDepth, xfc->format, xfc->palette); + fgcolor = freerdp_convert_gdi_order_color(fgcolor, context->settings->ColorDepth, xfc->format, xfc->palette); xf_lock_x11(xfc, FALSE); + fgcolor = xf_gdi_get_color(xfc, fgcolor); + bgcolor = xf_gdi_get_color(xfc, bgcolor); + XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, fgcolor); @@ -434,8 +422,10 @@ void xf_register_graphics(rdpGraphics* graphics) rdpPointer* pointer; rdpGlyph* glyph; - bitmap = (rdpBitmap*) malloc(sizeof(rdpBitmap)); - ZeroMemory(bitmap, sizeof(rdpBitmap)); + bitmap = (rdpBitmap*) calloc(1, sizeof(rdpBitmap)); + + if (!bitmap) + return; bitmap->size = sizeof(xfBitmap); @@ -448,8 +438,10 @@ void xf_register_graphics(rdpGraphics* graphics) graphics_register_bitmap(graphics, bitmap); free(bitmap); - pointer = (rdpPointer*) malloc(sizeof(rdpPointer)); - ZeroMemory(pointer, sizeof(rdpPointer)); + pointer = (rdpPointer*) calloc(1, sizeof(rdpPointer)); + + if (!pointer) + return; pointer->size = sizeof(xfPointer); @@ -462,8 +454,10 @@ void xf_register_graphics(rdpGraphics* graphics) graphics_register_pointer(graphics, pointer); free(pointer); - glyph = (rdpGlyph*) malloc(sizeof(rdpGlyph)); - ZeroMemory(glyph, sizeof(rdpGlyph)); + glyph = (rdpGlyph*) calloc(1, sizeof(rdpGlyph)); + + if (!glyph) + return; glyph->size = sizeof(xfGlyph); diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 9549bdb3a..75bc950af 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -37,6 +37,9 @@ #include "xf_event.h" #include "xf_input.h" +#include +#define TAG CLIENT_TAG("x11") + #ifdef WITH_XI #define MAX_CONTACTS 2 @@ -113,7 +116,7 @@ int xf_input_init(xfContext* xfc, Window window) if (!XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error)) { - printf("XInput extension not available.\n"); + WLog_WARN(TAG, "XInput extension not available."); return -1; } @@ -123,7 +126,7 @@ int xf_input_init(xfContext* xfc, Window window) if (major * 1000 + minor < 2002) { - printf("Server does not support XI 2.2\n"); + WLog_WARN(TAG, "Server does not support XI 2.2"); return -1; } @@ -156,9 +159,9 @@ int xf_input_init(xfContext* xfc, Window window) if (xfc->settings->MultiTouchInput) { - printf("%s (%d) \"%s\" id: %d\n", - xf_input_get_class_string(class->type), - class->type, dev->name, dev->deviceid); + WLog_INFO(TAG, "%s (%d) \"%s\" id: %d", + xf_input_get_class_string(class->type), + class->type, dev->name, dev->deviceid); } evmasks[nmasks].mask = masks[nmasks]; @@ -171,9 +174,9 @@ int xf_input_init(xfContext* xfc, Window window) { if (xfc->settings->MultiTouchInput) { - printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n", - dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", - dev->deviceid, t->mode, t->num_touches); + WLog_INFO(TAG, "%s %s touch device (id: %d, mode: %d), supporting %d touches.", + dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", + dev->deviceid, t->mode, t->num_touches); } XISetMask(masks[nmasks], XI_TouchBegin); @@ -186,9 +189,9 @@ int xf_input_init(xfContext* xfc, Window window) { if (!touch && (class->type == XIButtonClass) && strcmp(dev->name, "Virtual core pointer")) { - printf("%s button device (id: %d, mode: %d)\n", - dev->name, - dev->deviceid, t->mode); + WLog_INFO(TAG, "%s button device (id: %d, mode: %d)", + dev->name, + dev->deviceid, t->mode); XISetMask(masks[nmasks], XI_ButtonPress); XISetMask(masks[nmasks], XI_ButtonRelease); XISetMask(masks[nmasks], XI_Motion); @@ -494,7 +497,7 @@ void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) contacts[i].count = 0; active_contacts--; - break;printf("TouchBegin\n"); + break; } } } @@ -528,7 +531,7 @@ int xf_input_handle_event_local(xfContext* xfc, XEvent* event) break; default: - printf("unhandled xi type= %d\n", cookie->evtype); + WLog_ERR(TAG, "unhandled xi type= %d", cookie->evtype); break; } } @@ -619,17 +622,17 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) if (evtype == XI_TouchBegin) { - printf("TouchBegin: %d\n", touchId); + WLog_DBG(TAG, "TouchBegin: %d", touchId); contactId = rdpei->TouchBegin(rdpei, touchId, x, y); } else if (evtype == XI_TouchUpdate) { - printf("TouchUpdate: %d\n", touchId); + WLog_DBG(TAG, "TouchUpdate: %d", touchId); contactId = rdpei->TouchUpdate(rdpei, touchId, x, y); } else if (evtype == XI_TouchEnd) { - printf("TouchEnd: %d\n", touchId); + WLog_DBG(TAG, "TouchEnd: %d", touchId); contactId = rdpei->TouchEnd(rdpei, touchId, x, y); } @@ -706,21 +709,6 @@ int xf_input_init(xfContext* xfc, Window window) #endif -void xf_process_rdpei_event(xfContext* xfc, wMessage* event) -{ - switch (GetMessageType(event->id)) - { - case RdpeiChannel_ServerReady: - break; - - case RdpeiChannel_SuspendTouch: - break; - - case RdpeiChannel_ResumeTouch: - break; - } -} - int xf_input_handle_event(xfContext* xfc, XEvent* event) { #ifdef WITH_XI @@ -734,6 +722,6 @@ int xf_input_handle_event(xfContext* xfc, XEvent* event) return xf_input_handle_event_local(xfc, event); } #endif - + return 0; } diff --git a/client/X11/xf_input.h b/client/X11/xf_input.h index 367c7da23..6289fdb74 100644 --- a/client/X11/xf_input.h +++ b/client/X11/xf_input.h @@ -28,8 +28,6 @@ #endif int xf_input_init(xfContext* xfc, Window window); - int xf_input_handle_event(xfContext* xfc, XEvent* event); -void xf_process_rdpei_event(xfContext* xfc, wMessage* event); #endif diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 358b6d099..f9261327b 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -39,6 +40,9 @@ #include "xf_keyboard.h" +#include +#define TAG CLIENT_TAG("x11") + int xf_keyboard_action_script_init(xfContext* xfc) { int exitCode; @@ -191,18 +195,18 @@ void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode) if (rdp_scancode == RDP_SCANCODE_UNKNOWN) { - fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode); + WLog_ERR(TAG, "Unknown key with X keycode 0x%02x", keycode); } else if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) && !xf_keyboard_key_pressed(xfc, XK_Control_R)) { - /* Pause without Ctrl has to be sent as Ctrl + NumLock. */ + /* Pause without Ctrl has to be sent as a series of keycodes + * in a single input PDU. Pause only happens on "press"; + * no code is sent on "release". + */ if (down) { - freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_LCONTROL); - freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_NUMLOCK); - freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_LCONTROL); - freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_NUMLOCK); + freerdp_input_send_keyboard_pause_event(input); } } else @@ -238,18 +242,17 @@ int xf_keyboard_read_keyboard_state(xfContext* xfc) return state; } -BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym) +static int xf_keyboard_get_keymask(xfContext* xfc, int keysym) { - int offset; int modifierpos, key, keysymMask = 0; KeyCode keycode = XKeysymToKeycode(xfc->display, keysym); if (keycode == NoSymbol) - return FALSE; + return 0; for (modifierpos = 0; modifierpos < 8; modifierpos++) { - offset = xfc->modifierMap->max_keypermod * modifierpos; + int offset = xfc->modifierMap->max_keypermod * modifierpos; for (key = 0; key < xfc->modifierMap->max_keypermod; key++) { @@ -259,10 +262,34 @@ BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym) } } } + return keysymMask; +} + +BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym) +{ + int keysymMask = xf_keyboard_get_keymask(xfc, keysym); + + if (!keysymMask) + return FALSE; return (state & keysymMask) ? TRUE : FALSE; } +static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on, int keysym) +{ + int keysymMask; + + if (!xfc->xkbAvailable) + return FALSE; + + keysymMask = xf_keyboard_get_keymask(xfc, keysym); + if (!keysymMask) + { + return FALSE; + } + return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask, on ? keysymMask : 0); +} + UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc) { int state; @@ -405,12 +432,25 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) return TRUE; } - if (keysym == XK_Return) + if(xfc->fullscreen_toggle) + { + if (keysym == XK_Return) + { + if (mod.Ctrl && mod.Alt) + { + /* Ctrl-Alt-Enter: toggle full screen */ + xf_toggle_fullscreen(xfc); + return TRUE; + } + } + } + + if ((keysym == XK_c) || (keysym == XK_C)) { if (mod.Ctrl && mod.Alt) { - /* Ctrl-Alt-Enter: toggle full screen */ - xf_toggle_fullscreen(xfc); + /* Ctrl-Alt-C: toggle control */ + xf_toggle_control(xfc); return TRUE; } } @@ -552,3 +592,12 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) return FALSE; } +void xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags) +{ + xfContext* xfc = (xfContext*) context; + + xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, XK_Scroll_Lock); + xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock); + xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock); + xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock); +} diff --git a/client/X11/xf_keyboard.h b/client/X11/xf_keyboard.h index 05f9f2c39..501aa7fc9 100644 --- a/client/X11/xf_keyboard.h +++ b/client/X11/xf_keyboard.h @@ -57,5 +57,6 @@ BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym); UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc); void xf_keyboard_focus_in(xfContext* xfc); BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym); +void xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags); #endif /* __XF_KEYBOARD_H */ diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index e38918846..443a74088 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -29,6 +29,10 @@ #include +#include + +#define TAG CLIENT_TAG("x11") + #ifdef WITH_XINERAMA #include #endif @@ -55,10 +59,10 @@ int xf_list_monitors(xfContext* xfc) for (i = 0; i < nmonitors; i++) { - printf(" %s [%d] %dx%d\t+%d+%d\n", - (i == 0) ? "*" : " ", i, - screen[i].width, screen[i].height, - screen[i].x_org, screen[i].y_org); + WLog_DBG(TAG, " %s [%d] %dx%d\t+%d+%d", + (i == 0) ? "*" : " ", i, + screen[i].width, screen[i].height, + screen[i].x_org, screen[i].y_org); } XFree(screen); @@ -73,8 +77,7 @@ int xf_list_monitors(xfContext* xfc) display = XOpenDisplay(NULL); screen = ScreenOfDisplay(display, DefaultScreen(display)); - printf(" * [0] %dx%d\t+%d+%d\n", WidthOfScreen(screen), HeightOfScreen(screen), 0, 0); - + WLog_DBG(TAG, " * [0] %dx%d\t+%d+%d", WidthOfScreen(screen), HeightOfScreen(screen), 0, 0); XCloseDisplay(display); #endif diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 8b9318768..8e78c4a2f 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -24,7 +24,9 @@ #include #include +#include #include + #include #include #include @@ -32,10 +34,12 @@ #include "xf_window.h" #include "xf_rail.h" +#define TAG CLIENT_TAG("x11") + #ifdef WITH_DEBUG_X11_LOCAL_MOVESIZE -#define DEBUG_X11_LMS(fmt, ...) DEBUG_CLASS(X11_LMS, fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) do { } while (0) #endif void xf_rail_enable_remoteapp_mode(xfContext* xfc) @@ -66,9 +70,8 @@ void xf_rail_paint(xfContext* xfc, rdpRail* rail, INT32 uleft, INT32 utop, UINT3 UINT32 iwidth, iheight; INT32 ileft, itop; UINT32 iright, ibottom; - INT32 wleft, wtop; + INT32 wleft, wtop; UINT32 wright, wbottom; - window_list_rewind(rail->list); while (window_list_has_next(rail->list)) @@ -76,26 +79,23 @@ void xf_rail_paint(xfContext* xfc, rdpRail* rail, INT32 uleft, INT32 utop, UINT3 window = window_list_get_next(rail->list); xfw = (xfWindow*) window->extra; - /* RDP can have zero width or height windows. X cannot, so we ignore these. */ + /* RDP can have zero width or height windows. X cannot, so we ignore these. */ - if ((window->windowWidth == 0) || (window->windowHeight == 0)) - { - continue; - } + if ((window->windowWidth == 0) || (window->windowHeight == 0)) + { + continue; + } wleft = window->visibleOffsetX; wtop = window->visibleOffsetY; wright = window->visibleOffsetX + window->windowWidth - 1; wbottom = window->visibleOffsetY + window->windowHeight - 1; - ileft = MAX(uleft, wleft); itop = MAX(utop, wtop); iright = MIN(uright, wright); ibottom = MIN(ubottom, wbottom); - iwidth = iright - ileft + 1; iheight = ibottom - itop + 1; - intersect = ((iright > ileft) && (ibottom > itop)) ? TRUE : FALSE; if (intersect) @@ -105,10 +105,9 @@ void xf_rail_paint(xfContext* xfc, rdpRail* rail, INT32 uleft, INT32 utop, UINT3 } } -void xf_rail_DesktopNonMonitored(rdpRail *rail, rdpWindow* window) +void xf_rail_DesktopNonMonitored(rdpRail* rail, rdpWindow* window) { xfContext* xfc; - xfc = (xfContext*) rail->extra; xf_rail_disable_remoteapp_mode(xfc); } @@ -117,19 +116,13 @@ static void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window) { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; - xf_rail_enable_remoteapp_mode(xfc); - xfw = xf_CreateWindow(xfc, window, - window->windowOffsetX, window->windowOffsetY, - window->windowWidth, window->windowHeight, window->windowId); - + window->windowOffsetX, window->windowOffsetY, + window->windowWidth, window->windowHeight, window->windowId); xf_SetWindowStyle(xfc, xfw, window->style, window->extendedStyle); - xf_SetWindowText(xfc, xfw, window->title); - window->extra = (void*) xfw; window->extraId = (void*) xfw->handle; } @@ -138,7 +131,6 @@ static void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window) { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; @@ -148,35 +140,33 @@ static void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window) * update our local window when that rail window state is minimized */ if (xfw->rail_state == WINDOW_SHOW_MINIMIZED) - return; + return; /* Do nothing if window is already in the correct position */ - if ( xfw->left == window->visibleOffsetX && - xfw->top == window->visibleOffsetY && - xfw->width == window->windowWidth && - xfw->height == window->windowHeight) - { - /* - * Just ensure entire window area is updated to handle cases where we - * have drawn locally before getting new bitmap from the server - */ - xf_UpdateWindowArea(xfc, xfw, 0, 0, window->windowWidth, window->windowHeight); - return; - } + if (xfw->left == window->visibleOffsetX && + xfw->top == window->visibleOffsetY && + xfw->width == window->windowWidth && + xfw->height == window->windowHeight) + { + /* + * Just ensure entire window area is updated to handle cases where we + * have drawn locally before getting new bitmap from the server + */ + xf_UpdateWindowArea(xfc, xfw, 0, 0, window->windowWidth, window->windowHeight); + return; + } xf_MoveWindow(xfc, xfw, - window->visibleOffsetX, window->visibleOffsetY, - window->windowWidth, window->windowHeight); + window->visibleOffsetX, window->visibleOffsetY, + window->windowWidth, window->windowHeight); } static void xf_rail_ShowWindow(rdpRail* rail, rdpWindow* window, BYTE state) { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - xf_ShowWindow(xfc, xfw, state); } @@ -184,10 +174,8 @@ static void xf_rail_SetWindowText(rdpRail* rail, rdpWindow* window) { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - xf_SetWindowText(xfc, xfw, window->title); } @@ -195,13 +183,10 @@ static void xf_rail_SetWindowIcon(rdpRail* rail, rdpWindow* window, rdpIcon* ico { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - icon->extra = freerdp_icon_convert(icon->entry->bitsColor, NULL, icon->entry->bitsMask, - icon->entry->width, icon->entry->height, icon->entry->bpp, rail->clrconv); - + icon->entry->width, icon->entry->height, icon->entry->bpp, rail->clrconv); xf_SetWindowIcon(xfc, xfw, icon); } @@ -209,10 +194,8 @@ static void xf_rail_SetWindowRects(rdpRail* rail, rdpWindow* window) { xfContext* xfc; xfWindow* xfw; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - xf_SetWindowRects(xfc, xfw, window->windowRects, window->numWindowRects); } @@ -220,10 +203,8 @@ static void xf_rail_SetWindowVisibilityRects(rdpRail* rail, rdpWindow* window) { xfWindow* xfw; xfContext* xfc; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - xf_SetWindowVisibilityRects(xfc, xfw, window->windowRects, window->numWindowRects); } @@ -231,10 +212,8 @@ static void xf_rail_DestroyWindow(rdpRail* rail, rdpWindow* window) { xfWindow* xfw; xfContext* xfc; - xfc = (xfContext*) rail->extra; xfw = (xfWindow*) window->extra; - xf_DestroyWindow(xfc, xfw); } @@ -261,14 +240,12 @@ static void xf_send_rail_client_event(rdpChannels* channels, UINT16 event_type, { wMessage* out_event = NULL; void* payload = NULL; - payload = rail_clone_order(event_type, param); if (payload != NULL) { out_event = freerdp_event_new(RailChannel_Class, event_type, - xf_on_free_rail_client_event, payload); - + xf_on_free_rail_client_event, payload); freerdp_channels_send_event(channels, out_event); } } @@ -279,10 +256,8 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) rdpChannels* channels; rdpWindow* rail_window; RAIL_ACTIVATE_ORDER activate; - rail = ((rdpContext*) xfc)->rail; channels = ((rdpContext*) xfc)->channels; - rail_window = window_list_get_by_extra_id(rail->list, (void*) xwindow); if (rail_window == NULL) @@ -290,7 +265,6 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) activate.windowId = rail_window->windowId; activate.enabled = enabled; - xf_send_rail_client_event(channels, RailChannel_ClientActivate, &activate); } @@ -298,12 +272,9 @@ void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, UINT16 { rdpChannels* channels; RAIL_SYSCOMMAND_ORDER syscommand; - channels = ((rdpContext*) xfc)->channels; - syscommand.windowId = windowId; syscommand.command = command; - xf_send_rail_client_event(channels, RailChannel_ClientSystemCommand, &syscommand); } @@ -318,7 +289,6 @@ void xf_rail_adjust_position(xfContext* xfc, rdpWindow* window) xfWindow* xfw; rdpChannels* channels; RAIL_WINDOW_MOVE_ORDER window_move; - xfw = (xfWindow*) window->extra; channels = ((rdpContext*) xfc)->channels; @@ -326,24 +296,24 @@ void xf_rail_adjust_position(xfContext* xfc, rdpWindow* window) return; /* If current window position disagrees with RDP window position, send update to RDP server */ - if ( xfw->left != window->visibleOffsetX || - xfw->top != window->visibleOffsetY || - xfw->width != window->windowWidth || - xfw->height != window->windowHeight) - { - /* - * Although the rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY, - * we can only send unsigned integers to the rail server. Therefore, we always bring negative coordinates up to 0 - * when attempting to adjust the rail window. - */ - UINT32 offsetX = 0; - UINT32 offsetY = 0; + if (xfw->left != window->visibleOffsetX || + xfw->top != window->visibleOffsetY || + xfw->width != window->windowWidth || + xfw->height != window->windowHeight) + { + /* + * Although the rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY, + * we can only send unsigned integers to the rail server. Therefore, we always bring negative coordinates up to 0 + * when attempting to adjust the rail window. + */ + UINT32 offsetX = 0; + UINT32 offsetY = 0; - if (window->windowOffsetX < 0) - offsetX = offsetX - window->windowOffsetX; + if (window->windowOffsetX < 0) + offsetX = offsetX - window->windowOffsetX; - if (window->windowOffsetY < 0) - offsetY = offsetY - window->windowOffsetY; + if (window->windowOffsetY < 0) + offsetY = offsetY - window->windowOffsetY; /* * windowOffset corresponds to the window location on the rail server @@ -351,30 +321,26 @@ void xf_rail_adjust_position(xfContext* xfc, rdpWindow* window) * can result in blank areas for a maximized window */ window_move.windowId = window->windowId; - /* * Calculate new offsets for the rail server window * Negative offset correction + rail server window offset + (difference in visibleOffset and new window local offset) */ - window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); - window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); - - window_move.right = window_move.left + xfw->width; - window_move.bottom = window_move.top + xfw->height; - + window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); + window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); + window_move.right = window_move.left + xfw->width; + window_move.bottom = window_move.top + xfw->height; DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u" - " RDP=0x%X rc={l=%d t=%d} w=%d h=%d", - (UINT32) xfw->handle, window_move.left, window_move.top, - window_move.right, window_move.bottom, xfw->width, xfw->height, - window->windowId, - window->windowOffsetX, window->windowOffsetY, - window->windowWidth, window->windowHeight); - + " RDP=0x%X rc={l=%d t=%d} w=%d h=%d", + (UINT32) xfw->handle, window_move.left, window_move.top, + window_move.right, window_move.bottom, xfw->width, xfw->height, + window->windowId, + window->windowOffsetX, window->windowOffsetY, + window->windowWidth, window->windowHeight); xf_send_rail_client_event(channels, RailChannel_ClientWindowMove, &window_move); - } + } } -void xf_rail_end_local_move(xfContext* xfc, rdpWindow *window) +void xf_rail_end_local_move(xfContext* xfc, rdpWindow* window) { xfWindow* xfw; rdpChannels* channels; @@ -386,119 +352,103 @@ void xf_rail_end_local_move(xfContext* xfc, rdpWindow *window) unsigned int mask; int child_x; int child_y; - xfw = (xfWindow*) window->extra; channels = ((rdpContext*) xfc)->channels; - DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d", - (UINT32) xfw->handle, - xfw->left, xfw->top, xfw->right, xfw->bottom, - xfw->width, xfw->height); - + (UINT32) xfw->handle, + xfw->left, xfw->top, xfw->right, xfw->bottom, + xfw->width, xfw->height); /* * Although the rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY, * we can only send unsigned integers to the rail server. Therefore, we always bring negative coordinates up to 0 when * attempting to adjust the rail window. */ UINT32 offsetX = 0; - UINT32 offsetY = 0; + UINT32 offsetY = 0; - if (window->windowOffsetX < 0) - offsetX = offsetX - window->windowOffsetX; + if (window->windowOffsetX < 0) + offsetX = offsetX - window->windowOffsetX; - if (window->windowOffsetY < 0) - offsetY = offsetY - window->windowOffsetY; + if (window->windowOffsetY < 0) + offsetY = offsetY - window->windowOffsetY; - /* - * For keyboard moves send and explicit update to RDP server - */ + /* + * For keyboard moves send and explicit update to RDP server + */ window_move.windowId = window->windowId; - /* * Calculate new offsets for the rail server window * Negative offset correction + rail server window offset + (difference in visibleOffset and new window local offset) */ - window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); - window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); - - window_move.right = window_move.left + xfw->width; /* In the update to RDP the position is one past the window */ - window_move.bottom = window_move.top + xfw->height; - + window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); + window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); + window_move.right = window_move.left + xfw->width; /* In the update to RDP the position is one past the window */ + window_move.bottom = window_move.top + xfw->height; xf_send_rail_client_event(channels, RailChannel_ClientWindowMove, &window_move); - /* * Simulate button up at new position to end the local move (per RDP spec) */ - - XQueryPointer(xfc->display, xfw->handle, - &root_window, &child_window, - &x, &y, &child_x, &child_y, &mask); - input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y); + XQueryPointer(xfc->display, xfw->handle, + &root_window, &child_window, + &x, &y, &child_x, &child_y, &mask); + input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y); /* only send the mouse coordinates if not a keyboard move or size */ if ((xfw->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) && - (xfw->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD)) - { - input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y); - DEBUG_X11_LMS("Mouse coordinates. x= %i, y= %i", x, y); - } - + (xfw->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD)) + { + input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y); + DEBUG_X11_LMS("Mouse coordinates. x= %i, y= %i", x, y); + } + /* * Proactively update the RAIL window dimensions. There is a race condition where * we can start to receive GDI orders for the new window dimensions before we * receive the RAIL ORDER for the new window size. This avoids that race condition. */ - - window->windowOffsetX = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); - window->windowOffsetY = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); + window->windowOffsetX = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX); + window->windowOffsetY = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY); window->windowWidth = xfw->width; window->windowHeight = xfw->height; - xfw->local_move.state = LMS_TERMINATING; } void xf_process_rail_get_sysparams_event(xfContext* xfc, rdpChannels* channels, wMessage* event) { RAIL_SYSPARAM_ORDER* sysparam; - sysparam = (RAIL_SYSPARAM_ORDER*) event->wParam; - sysparam->workArea.left = xfc->workArea.x; sysparam->workArea.top = xfc->workArea.y; sysparam->workArea.right = xfc->workArea.x + xfc->workArea.width; sysparam->workArea.bottom = xfc->workArea.y + xfc->workArea.height; - sysparam->taskbarPos.left = 0; sysparam->taskbarPos.top = 0; sysparam->taskbarPos.right = 0; sysparam->taskbarPos.bottom = 0; - sysparam->dragFullWindows = FALSE; - xf_send_rail_client_event(channels, RailChannel_ClientSystemParam, sysparam); } const char* error_code_names[] = { - "RAIL_EXEC_S_OK", - "RAIL_EXEC_E_HOOK_NOT_LOADED", - "RAIL_EXEC_E_DECODE_FAILED", - "RAIL_EXEC_E_NOT_IN_ALLOWLIST", - "RAIL_EXEC_E_FILE_NOT_FOUND", - "RAIL_EXEC_E_FAIL", - "RAIL_EXEC_E_SESSION_LOCKED" + "RAIL_EXEC_S_OK", + "RAIL_EXEC_E_HOOK_NOT_LOADED", + "RAIL_EXEC_E_DECODE_FAILED", + "RAIL_EXEC_E_NOT_IN_ALLOWLIST", + "RAIL_EXEC_E_FILE_NOT_FOUND", + "RAIL_EXEC_E_FAIL", + "RAIL_EXEC_E_SESSION_LOCKED" }; void xf_process_rail_exec_result_event(xfContext* xfc, rdpChannels* channels, wMessage* event) { RAIL_EXEC_RESULT_ORDER* exec_result; - exec_result = (RAIL_EXEC_RESULT_ORDER*) event->wParam; if (exec_result->execResult != RAIL_EXEC_S_OK) { - fprintf(stderr, "RAIL exec error: execResult=%s NtError=0x%X\n", - error_code_names[exec_result->execResult], exec_result->rawResult); + WLog_ERR(TAG, "RAIL exec error: execResult=%s NtError=0x%X\n", + error_code_names[exec_result->execResult], exec_result->rawResult); xfc->disconnect = True; } else @@ -526,24 +476,21 @@ void xf_process_rail_server_minmaxinfo_event(xfContext* xfc, rdpChannels* channe rdpRail* rail; rdpWindow* rail_window = NULL; RAIL_MINMAXINFO_ORDER* minmax = (RAIL_MINMAXINFO_ORDER*) event->wParam; - rail = ((rdpContext*) xfc)->rail; rail_window = window_list_get_by_id(rail->list, minmax->windowId); if (rail_window != NULL) { - xfWindow * window = NULL; - window = (xfWindow *) rail_window->extra; - + xfWindow* window = NULL; + window = (xfWindow*) rail_window->extra; DEBUG_X11_LMS("windowId=0x%X maxWidth=%d maxHeight=%d maxPosX=%d maxPosY=%d " - "minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d", - minmax->windowId, minmax->maxWidth, minmax->maxHeight, - (INT16)minmax->maxPosX, (INT16)minmax->maxPosY, - minmax->minTrackWidth, minmax->minTrackHeight, - minmax->maxTrackWidth, minmax->maxTrackHeight); - + "minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d", + minmax->windowId, minmax->maxWidth, minmax->maxHeight, + (INT16)minmax->maxPosX, (INT16)minmax->maxPosY, + minmax->minTrackWidth, minmax->minTrackHeight, + minmax->maxTrackWidth, minmax->maxTrackHeight); xf_SetWindowMinMaxInfo(xfc, window, minmax->maxWidth, minmax->maxHeight, minmax->maxPosX, minmax->maxPosY, - minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight); + minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight); } } @@ -571,7 +518,6 @@ void xf_process_rail_server_localmovesize_event(xfContext* xfc, rdpChannels* cha Window child_window; rdpWindow* rail_window = NULL; RAIL_LOCALMOVESIZE_ORDER* movesize = (RAIL_LOCALMOVESIZE_ORDER*) event->wParam; - rail = ((rdpContext*) xfc)->rail; rail_window = window_list_get_by_id(rail->list, movesize->windowId); @@ -579,10 +525,9 @@ void xf_process_rail_server_localmovesize_event(xfContext* xfc, rdpChannels* cha { xfWindow* xfw = NULL; xfw = (xfWindow*) rail_window->extra; - DEBUG_X11_LMS("windowId=0x%X isMoveSizeStart=%d moveSizeType=%s PosX=%d PosY=%d", - movesize->windowId, movesize->isMoveSizeStart, - movetype_names[movesize->moveSizeType], (INT16) movesize->posX, (INT16) movesize->posY); + movesize->windowId, movesize->isMoveSizeStart, + movetype_names[movesize->moveSizeType], (INT16) movesize->posX, (INT16) movesize->posY); switch (movesize->moveSizeType) { @@ -591,53 +536,63 @@ void xf_process_rail_server_localmovesize_event(xfContext* xfc, rdpChannels* cha x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_RIGHT: //0x2 direction = _NET_WM_MOVERESIZE_SIZE_RIGHT; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_TOP: //0x3 direction = _NET_WM_MOVERESIZE_SIZE_TOP; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_TOPLEFT: //0x4 direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_TOPRIGHT: //0x5 direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_BOTTOM: //0x6 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_BOTTOMLEFT: //0x7 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_BOTTOMRIGHT: //0x8 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; x = movesize->posX; y = movesize->posY; break; + case RAIL_WMSZ_MOVE: //0x9 direction = _NET_WM_MOVERESIZE_MOVE; - XTranslateCoordinates(xfc->display, xfw->handle, - RootWindowOfScreen(xfc->screen), - movesize->posX, movesize->posY, &x, &y, &child_window); + XTranslateCoordinates(xfc->display, xfw->handle, + RootWindowOfScreen(xfc->screen), + movesize->posX, movesize->posY, &x, &y, &child_window); break; + case RAIL_WMSZ_KEYMOVE: //0xA direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD; x = movesize->posX; y = movesize->posY; /* FIXME: local keyboard moves not working */ return; + case RAIL_WMSZ_KEYSIZE: //0xB direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD; x = movesize->posX; @@ -649,7 +604,9 @@ void xf_process_rail_server_localmovesize_event(xfContext* xfc, rdpChannels* cha if (movesize->isMoveSizeStart) { xf_StartLocalMoveSize(xfc, xfw, direction, x, y); - } else { + } + else + { xf_EndLocalMoveSize(xfc, xfw); } } @@ -659,21 +616,18 @@ void xf_process_rail_appid_resp_event(xfContext* xfc, rdpChannels* channels, wMe { RAIL_GET_APPID_RESP_ORDER* appid_resp = (RAIL_GET_APPID_RESP_ORDER*) event->wParam; - - fprintf(stderr, "Server Application ID Response PDU: windowId=0x%X " - "applicationId=(length=%d dump)\n", - appid_resp->windowId, 512); - - winpr_HexDump((BYTE*) &appid_resp->applicationId, 512); + WLog_ERR(TAG, "Server Application ID Response PDU: windowId=0x%X " + "applicationId=(length=%d dump)\n", + appid_resp->windowId, 512); + winpr_HexDump(TAG, WLOG_ERROR, (BYTE*) &appid_resp->applicationId, 512); } void xf_process_rail_langbarinfo_event(xfContext* xfc, rdpChannels* channels, wMessage* event) { RAIL_LANGBAR_INFO_ORDER* langbar = (RAIL_LANGBAR_INFO_ORDER*) event->wParam; - - fprintf(stderr, "Language Bar Information PDU: languageBarStatus=0x%X\n", - langbar->languageBarStatus); + WLog_ERR(TAG, "Language Bar Information PDU: languageBarStatus=0x%X\n", + langbar->languageBarStatus); } void xf_process_rail_event(xfContext* xfc, rdpChannels* channels, wMessage* event) diff --git a/client/X11/xf_tsmf.c b/client/X11/xf_tsmf.c index 131d2ea2b..62d322a8a 100644 --- a/client/X11/xf_tsmf.c +++ b/client/X11/xf_tsmf.c @@ -36,6 +36,7 @@ #include #include +#include #include #include "xf_tsmf.h" @@ -57,10 +58,11 @@ struct xf_xv_context UINT32* xv_pixfmts; }; +#define TAG CLIENT_TAG("x11") #ifdef WITH_DEBUG_XV -#define DEBUG_XV(fmt, ...) DEBUG_CLASS(XV, fmt, ## __VA_ARGS__) +#define DEBUG_XV(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_XV(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_XV(fmt, ...) do { } while (0) #endif void xf_tsmf_init(xfContext* xfc, long xv_port) @@ -140,7 +142,7 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) XFree(attr); #ifdef WITH_DEBUG_XV - fprintf(stderr, "xf_tsmf_init: pixel format "); + WLog_DBG(TAG, "xf_tsmf_init: pixel format "); #endif fo = XvListImageFormats(xfc->display, xv->xv_port, &ret); if (ret > 0) @@ -152,16 +154,13 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) { xv->xv_pixfmts[i] = fo[i].id; #ifdef WITH_DEBUG_XV - fprintf(stderr, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], ((char*)(xv->xv_pixfmts + i))[1], - ((char*)(xv->xv_pixfmts + i))[2], ((char*)(xv->xv_pixfmts + i))[3]); + WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], ((char*)(xv->xv_pixfmts + i))[1], + ((char*)(xv->xv_pixfmts + i))[2], ((char*)(xv->xv_pixfmts + i))[3]); #endif } xv->xv_pixfmts[i] = 0; } XFree(fo); -#ifdef WITH_DEBUG_XV - fprintf(stderr, "\n"); -#endif } void xf_tsmf_uninit(xfContext* xfc) @@ -228,6 +227,7 @@ static void xf_process_tsmf_video_frame_event(xfContext* xfc, RDP_VIDEO_FRAME_EV XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, colorkey); + for (i = 0; i < vevent->num_visible_rects; i++) { XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 7df1f8768..14751ac38 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -39,6 +39,7 @@ #include #include +#include #ifdef WITH_XEXT #include @@ -51,16 +52,18 @@ #include "xf_input.h" +#define TAG CLIENT_TAG("x11") + #ifdef WITH_DEBUG_X11 -#define DEBUG_X11(fmt, ...) DEBUG_CLASS(X11, fmt, ## __VA_ARGS__) +#define DEBUG_X11(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_X11(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_X11(fmt, ...) do { } while (0) #endif #ifdef WITH_DEBUG_X11_LOCAL_MOVESIZE -#define DEBUG_X11_LMS(fmt, ...) DEBUG_CLASS(X11_LMS, fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_X11_LMS(fmt, ...) do { } while (0) #endif #include "FreeRDP_Icon_256px.h" @@ -114,6 +117,8 @@ void xf_SendClientEvent(xfContext *xfc, xfWindow *window, Atom atom, unsigned in unsigned int i; va_list argp; va_start(argp, numArgs); + + ZeroMemory(&xevent, sizeof(XEvent)); xevent.xclient.type = ClientMessage; xevent.xclient.serial = 0; xevent.xclient.send_event = False; @@ -161,7 +166,7 @@ BOOL xf_GetWindowProperty(xfContext *xfc, Window window, Atom property, int leng return FALSE; if(actual_type == None) { - DEBUG_WARN("Property %lu does not exist", property); + WLog_ERR(TAG, "Property %lu does not exist", property); return FALSE; } return TRUE; @@ -256,24 +261,19 @@ void xf_SetWindowStyle(xfContext *xfc, xfWindow *window, UINT32 style, UINT32 ex * TOPMOST window that is not a toolwindow is treated like a regular window(ie. task manager). * Want to do this here, since the window may have type WS_POPUP */ + else if (ex_style & WS_EX_TOPMOST) + { + window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; + } + else if (style & WS_POPUP) + { + /* this includes dialogs, popups, etc, that need to be full-fledged windows */ + window->is_transient = TRUE; + window_type = xfc->_NET_WM_WINDOW_TYPE_DIALOG; + xf_SetWindowUnlisted(xfc, window); + } else - if(ex_style & WS_EX_TOPMOST) - { - window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; - } - else - if(style & WS_POPUP) - { - /* this includes dialogs, popups, etc, that need to be full-fledged windows */ - window->is_transient = TRUE; - window_type = xfc->_NET_WM_WINDOW_TYPE_DIALOG; - xf_SetWindowUnlisted(xfc, window); - } - else - { - window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; - } - XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_WINDOW_TYPE, + XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (BYTE *) &window_type, 1); } diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index a1e6ebf16..da5de821e 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -34,6 +34,8 @@ typedef struct xf_context xfContext; #include #include #include +#include +#include #include struct xf_WorkArea @@ -66,6 +68,8 @@ struct xf_glyph }; typedef struct xf_glyph xfGlyph; +typedef struct xf_clipboard xfClipboard; + struct xf_context { rdpContext context; @@ -73,6 +77,7 @@ struct xf_context freerdp* instance; rdpSettings* settings; + rdpCodecs* codecs; GC gc; int bpp; @@ -82,6 +87,8 @@ struct xf_context int height; int srcBpp; GC gc_mono; + BOOL invert; + UINT32 format; Screen* screen; XImage* image; Pixmap primary; @@ -108,8 +115,11 @@ struct xf_context HANDLE mutex; BOOL UseXThreads; BOOL cursorHidden; + BYTE palette[256 * 4]; HGDI_DC hdc; + UINT32 bitmap_size; + BYTE* bitmap_buffer; BYTE* primary_buffer; REGION16 invalidRegion; BOOL inGfxFrame; @@ -137,6 +147,7 @@ struct xf_context BOOL mouse_active; BOOL suppress_output; BOOL fullscreen_toggle; + BOOL controlToggle; UINT32 KeyboardLayout; BOOL KeyboardState[256]; XModifierKeymap* modifierMap; @@ -147,13 +158,9 @@ struct xf_context XSetWindowAttributes attribs; BOOL complex_regions; VIRTUAL_SCREEN vscreen; - BYTE* bmp_codec_none; - BYTE* bmp_codec_nsc; - RFX_CONTEXT* rfx; - NSC_CONTEXT* nsc; - CLEAR_CONTEXT* clear; void* xv_context; - void* clipboard_context; + xfClipboard* clipboard; + CliprdrClientContext* cliprdr; Atom _NET_WM_ICON; Atom _MOTIF_WM_HINTS; @@ -182,12 +189,19 @@ struct xf_context /* Channels */ RdpeiClientContext* rdpei; RdpgfxClientContext* gfx; + EncomspClientContext* encomsp; + + BOOL xkbAvailable; }; void xf_create_window(xfContext* xfc); void xf_toggle_fullscreen(xfContext* xfc); +void xf_toggle_control(xfContext* xfc); BOOL xf_post_connect(freerdp* instance); +void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp); +void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp); + enum XF_EXIT_CODE { /* section 0-15: protocol-independent codes */ @@ -235,6 +249,8 @@ void xf_unlock_x11(xfContext* xfc, BOOL display); void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale); void xf_transform_window(xfContext* xfc); +unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color); + FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason); #endif /* __XFREERDP_H */ diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index a7a39de91..5ac33ff2a 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -47,20 +47,18 @@ add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) include_directories(${OPENSSL_INCLUDE_DIR}) include_directories(${ZLIB_INCLUDE_DIRS}) -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) +endif() +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${FREERDP_CHANNELS_CLIENT_LIBS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-utils) - - +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} + ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) @@ -71,4 +69,5 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common") if(BUILD_TESTING) add_subdirectory(test) endif() + export_complex_library(LIBNAME ${MODULE_NAME}) diff --git a/client/common/client.c b/client/common/client.c index 1fc565f9a..86eed62c5 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,57 @@ HANDLE freerdp_client_get_thread(rdpContext* context) return ((rdpClientContext*) context)->thread; } +static BOOL freerdp_client_settings_post_process(rdpSettings* settings) +{ + /* Moved GatewayUseSameCredentials logic outside of cmdline.c, so + * that the rdp file also triggers this functionality */ + if (settings->GatewayEnabled) + { + if (settings->GatewayUseSameCredentials) + { + if (settings->Username) + { + settings->GatewayUsername = _strdup(settings->Username); + if (!settings->GatewayUsername) + goto out_error; + } + if (settings->Domain) + { + settings->GatewayDomain = _strdup(settings->Domain); + if (!settings->GatewayDomain) + goto out_error; + } + if (settings->Password) + { + settings->GatewayPassword = _strdup(settings->Password); + if (!settings->GatewayPassword) + goto out_error; + } + } + } + + /* Moved logic for Multimon and Span monitors to force fullscreen, so + * that the rdp file also triggers this functionality */ + if (settings->SpanMonitors) + { + settings->UseMultimon = TRUE; + settings->Fullscreen = TRUE; + } + else if (settings->UseMultimon) + { + settings->Fullscreen = TRUE; + } + + return TRUE; + +out_error: + free(settings->GatewayUsername); + free(settings->GatewayDomain); + free(settings->GatewayPassword); + return FALSE; +} + + int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, char** argv) { int status; @@ -118,6 +170,20 @@ int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, status = freerdp_client_settings_parse_connection_file(settings, settings->ConnectionFile); } + if (settings->AssistanceFile) + { + status = freerdp_client_settings_parse_assistance_file(settings, settings->AssistanceFile); + } + + /* Only call post processing if no status/error was returned*/ + if (status < 0) + return status; + + /* This function will call logic that is applicable to the settings + * from command line parsing AND the rdp file parsing */ + if(!freerdp_client_settings_post_process(settings)) + status = -1; + return status; } @@ -167,3 +233,29 @@ int freerdp_client_settings_write_connection_file(const rdpSettings* settings, c return 0; } + +int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename) +{ + int status; + rdpAssistanceFile* file; + + file = freerdp_assistance_file_new(); + + if (!file) + return -1; + + status = freerdp_assistance_parse_file(file, filename); + + if (status < 0) + return -1; + + status = freerdp_client_populate_settings_from_assistance_file(file, settings); + + if (status < 0) + return -1; + + freerdp_assistance_file_free(file); + + return 0; +} + diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 34bbd0b6b..02db02e51 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -32,18 +32,22 @@ #include #include + #include #include #include "compatibility.h" +#include +#define TAG CLIENT_TAG("common.cmdline") + COMMAND_LINE_ARGUMENT_A args[] = { { "v", COMMAND_LINE_VALUE_REQUIRED, "[:port]", NULL, NULL, -1, NULL, "Server hostname" }, { "port", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Server port" }, { "w", COMMAND_LINE_VALUE_REQUIRED, "", "1024", NULL, -1, NULL, "Width" }, { "h", COMMAND_LINE_VALUE_REQUIRED, "", "768", NULL, -1, NULL, "Height" }, - { "size", COMMAND_LINE_VALUE_REQUIRED, "x", "1024x768", NULL, -1, NULL, "Screen size" }, + { "size", COMMAND_LINE_VALUE_REQUIRED, "x or %", "1024x768", NULL, -1, NULL, "Screen size" }, { "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Fullscreen mode" }, { "bpp", COMMAND_LINE_VALUE_REQUIRED, "", "16", NULL, -1, NULL, "Session bpp (color depth)" }, { "kbd", COMMAND_LINE_VALUE_REQUIRED, "0x or ", NULL, NULL, -1, NULL, "Keyboard layout" }, @@ -111,6 +115,10 @@ COMMAND_LINE_ARGUMENT_A args[] = { "wallpaper", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Wallpaper" }, { "gdi", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "GDI rendering" }, { "gfx", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" }, + { "gfx-thin-client", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "RDP8 graphics pipeline thin client mode" }, + { "gfx-small-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "RDP8 graphics pipeline small cache mode" }, + { "gfx-progressive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "RDP8 graphics pipeline progressive codec" }, + { "gfx-h264", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "RDP8.1 graphics pipeline H264 codec" }, { "rfx", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "RemoteFX" }, { "rfx-mode", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "RemoteFX mode" }, { "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Frame acknowledgement" }, @@ -123,6 +131,8 @@ COMMAND_LINE_ARGUMENT_A args[] = { "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "tls protocol security" }, { "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "nla protocol security" }, { "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "nla extended protocol security" }, + { "tls-ciphers", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "List of permitted openssl ciphers - see ciphers(1)" }, + { "tls-ciphers-netmon", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use tls ciphers that netmon can parse" }, { "cert-name", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "certificate name" }, { "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "ignore certificate" }, { "pcb", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Preconnection Blob" }, @@ -156,6 +166,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" }, { "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" }, { "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" }, + { "assistance", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote assistance password" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -201,7 +212,7 @@ int freerdp_client_print_command_line_help(int argc, char** argv) if (arg->Format) { - length = (int) (strlen(arg->Name) + strlen(arg->Format) + 2); + length = (int)(strlen(arg->Name) + strlen(arg->Format) + 2); str = (char*) malloc(length + 1); sprintf_s(str, length + 1, "%s:%s", arg->Name, arg->Format); printf("%-20s", str); @@ -245,8 +256,8 @@ int freerdp_client_print_command_line_help(int argc, char** argv) printf("Drive Redirection: /drive:home,/home/user\n"); printf("Smartcard Redirection: /smartcard:\n"); - printf("Printer Redirection: /printer:,\n"); - printf("Serial Port Redirection: /serial:\n"); + printf("Serial Port Redirection: /serial:,,[SerCx2|SerCx|Serial],[permissive]\n"); + printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n"); printf("Parallel Port Redirection: /parallel:\n"); printf("Printer Redirection: /printer:,\n"); printf("\n"); @@ -284,6 +295,17 @@ int freerdp_client_command_line_pre_filter(void* context, int index, int argc, L return 1; } } + + if (length > 13) + { + if (_stricmp(&(argv[index])[length - 13], ".msrcIncident") == 0) + { + settings = (rdpSettings*) context; + settings->AssistanceFile = _strdup(argv[index]); + + return 1; + } + } } return 0; @@ -400,6 +422,12 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p if (count > 2) serial->Path = _strdup(params[2]); + if (count > 3) + serial->Driver = _strdup(params[3]); + + if (count > 4) + serial->Permissive = _strdup(params[4]); + freerdp_device_collection_add(settings, (RDPDR_DEVICE*) serial); return 1; @@ -654,38 +682,19 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT } CommandLineSwitchCase(arg, "multitouch") { - char* p[1]; - int count = 1; - settings->MultiTouchInput = TRUE; - - p[0] = "rdpei"; - freerdp_client_add_dynamic_channel(settings, count, p); } CommandLineSwitchCase(arg, "gestures") { - printf("gestures\n"); settings->MultiTouchGestures = TRUE; } CommandLineSwitchCase(arg, "echo") { - char* p[1]; - int count; - - count = 1; - p[0] = "echo"; - - freerdp_client_add_dynamic_channel(settings, count, p); + settings->SupportEchoChannel = TRUE; } CommandLineSwitchCase(arg, "disp") { - char* p[1]; - int count; - - count = 1; - p[0] = "disp"; - - freerdp_client_add_dynamic_channel(settings, count, p); + settings->SupportDisplayControl = TRUE; } CommandLineSwitchCase(arg, "sound") { @@ -794,21 +803,12 @@ int freerdp_parse_username(char* username, char** user, char** domain) } else { - p = strchr(username, '@'); - - if (p) - { - length = (int) (p - username); - *user = (char*) malloc(length + 1); - strncpy(*user, username, length); - (*user)[length] = '\0'; - *domain = _strdup(&p[1]); - } - else - { - *user = _strdup(username); - *domain = NULL; - } + /* Do not break up the name for '@'; both credSSP and the + * ClientInfo PDU expect 'user@corp.net' to be transmitted + * as username 'user@corp.net', domain empty. + */ + *user = _strdup(username); + *domain = NULL; } return 0; @@ -849,6 +849,7 @@ int freerdp_parse_hostname(char* hostname, char** host, int* port) int freerdp_set_connection_type(rdpSettings* settings, int type) { settings->ConnectionType = type; + if (type == CONNECTION_TYPE_MODEM) { settings->DisableWallpaper = TRUE; @@ -1074,6 +1075,9 @@ BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags) *flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH; *flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE; + if (posix_cli_status <= COMMAND_LINE_STATUS_PRINT) + return compatibility; + if (windows_cli_count >= posix_cli_count) { *flags = COMMAND_LINE_SEPARATOR_COLON; @@ -1092,8 +1096,8 @@ BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags) } } - //printf("windows: %d/%d posix: %d/%d compat: %d/%d\n", windows_cli_status, windows_cli_count, - // posix_cli_status, posix_cli_count, old_cli_status, old_cli_count); + WLog_DBG(TAG, "windows: %d/%d posix: %d/%d compat: %d/%d", windows_cli_status, windows_cli_count, + posix_cli_status, posix_cli_count, old_cli_status, old_cli_count); return compatibility; } @@ -1169,7 +1173,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (compatibility) { - fprintf(stderr, "WARNING: Using deprecated command-line interface!\n"); + WLog_WARN(TAG, "Using deprecated command-line interface!"); return freerdp_client_parse_old_command_line_arguments(argc, argv, settings); } else @@ -1250,6 +1254,14 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->DesktopWidth = atoi(str); settings->DesktopHeight = atoi(&p[1]); } + else + { + p = strchr(str, '%'); + if(p) + { + settings->PercentScreen = atoi(str); + } + } free(str); } @@ -1260,8 +1272,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "multimon") { settings->UseMultimon = TRUE; - settings->SpanMonitors = FALSE; - settings->Fullscreen = TRUE; if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { @@ -1273,9 +1283,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "span") { - settings->UseMultimon = TRUE; settings->SpanMonitors = TRUE; - settings->Fullscreen = TRUE; } CommandLineSwitchCase(arg, "workarea") { @@ -1343,25 +1351,25 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "kbd") { - int id; + unsigned long int id; char* pEnd; - id = strtol(arg->Value, &pEnd, 16); + id = strtoul(arg->Value, &pEnd, 16); if (pEnd != (arg->Value + strlen(arg->Value))) id = 0; if (id == 0) { - id = freerdp_map_keyboard_layout_name_to_id(arg->Value); + id = (unsigned long int) freerdp_map_keyboard_layout_name_to_id(arg->Value); if (!id) { - fprintf(stderr, "Could not identify keyboard layout: %s\n", arg->Value); + WLog_ERR(TAG, "Could not identify keyboard layout: %s", arg->Value); } } - settings->KeyboardLayout = id; + settings->KeyboardLayout = (UINT32) id; } CommandLineSwitchCase(arg, "kbd-type") { @@ -1569,8 +1577,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, type = CONNECTION_TYPE_WAN; else if (_stricmp(arg->Value, "lan") == 0) type = CONNECTION_TYPE_LAN; - else if (_stricmp(arg->Value, "auto") == 0) + else if ((_stricmp(arg->Value, "autodetect") == 0) || + (_stricmp(arg->Value, "auto") == 0) || + (_stricmp(arg->Value, "detect") == 0)) + { type = CONNECTION_TYPE_AUTODETECT; + } } freerdp_set_connection_type(settings, type); @@ -1609,10 +1621,27 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "gfx") { settings->SupportGraphicsPipeline = TRUE; - settings->FastPathOutput = TRUE; - settings->ColorDepth = 32; - settings->LargePointerFlag = TRUE; - settings->FrameMarkerCommandEnabled = TRUE; + } + CommandLineSwitchCase(arg, "gfx-thin-client") + { + settings->GfxThinClient = arg->Value ? TRUE : FALSE; + settings->SupportGraphicsPipeline = TRUE; + } + CommandLineSwitchCase(arg, "gfx-small-cache") + { + settings->GfxSmallCache = arg->Value ? TRUE : FALSE; + settings->SupportGraphicsPipeline = TRUE; + } + CommandLineSwitchCase(arg, "gfx-progressive") + { + settings->GfxProgressive = arg->Value ? TRUE : FALSE; + settings->GfxThinClient = settings->GfxProgressive ? FALSE : TRUE; + settings->SupportGraphicsPipeline = TRUE; + } + CommandLineSwitchCase(arg, "gfx-h264") + { + settings->GfxH264 = arg->Value ? TRUE : FALSE; + settings->SupportGraphicsPipeline = TRUE; } CommandLineSwitchCase(arg, "rfx") { @@ -1699,7 +1728,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } else { - fprintf(stderr, "unknown protocol security: %s\n", arg->Value); + WLog_ERR(TAG, "unknown protocol security: %s", arg->Value); } } CommandLineSwitchCase(arg, "sec-rdp") @@ -1718,6 +1747,14 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->ExtSecurity = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "tls-ciphers") + { + settings->PermittedTLSCiphers = _strdup(arg->Value); + } + CommandLineSwitchCase(arg, "tls-ciphers-netmon") + { + settings->PermittedTLSCiphers = arg->Value ? _strdup("ALL:!ECDH") : NULL; + } CommandLineSwitchCase(arg, "cert-name") { settings->CertificateName = _strdup(arg->Value); @@ -1837,14 +1874,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } else { - fprintf(stderr, "reconnect-cookie: invalid base64 '%s'\n", - arg->Value); + WLog_ERR(TAG, "reconnect-cookie: invalid base64 '%s'", arg->Value); } } CommandLineSwitchCase(arg, "print-reconnect-cookie") { settings->PrintReconnectCookie = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "assistance") + { + settings->RemoteAssistanceMode = TRUE; + settings->RemoteAssistancePassword = _strdup(arg->Value); + } CommandLineSwitchDefault(arg) { } @@ -1855,19 +1896,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, freerdp_performance_flags_make(settings); - if (settings->GatewayEnabled) + if (settings->SupportGraphicsPipeline) { - if (settings->GatewayUseSameCredentials) - { - if (settings->Username) - settings->GatewayUsername = _strdup(settings->Username); - - if (settings->Domain) - settings->GatewayDomain = _strdup(settings->Domain); - - if (settings->Password) - settings->GatewayPassword = _strdup(settings->Password); - } + settings->FastPathOutput = TRUE; + settings->ColorDepth = 32; + settings->LargePointerFlag = TRUE; + settings->FrameMarkerCommandEnabled = TRUE; } arg = CommandLineFindArgumentA(args, "port"); @@ -1904,7 +1938,7 @@ int freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* { if (freerdp_channels_client_load(channels, settings, entry, data) == 0) { - fprintf(stderr, "loading channel %s\n", name); + WLog_INFO(TAG, "loading channel %s", name); return 0; } } @@ -2023,6 +2057,12 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) } } + if (settings->RemoteAssistanceMode) + { + freerdp_client_load_static_channel_addin(channels, settings, "encomsp", settings); + freerdp_client_load_static_channel_addin(channels, settings, "remdesk", settings); + } + for (index = 0; index < settings->StaticChannelCount; index++) { args = settings->StaticChannelArray[index]; @@ -2034,6 +2074,17 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) freerdp_client_load_static_channel_addin(channels, settings, "rail", settings); } + if (settings->MultiTouchInput) + { + char* p[1]; + int count; + + count = 1; + p[0] = "rdpei"; + + freerdp_client_add_dynamic_channel(settings, count, p); + } + if (settings->SupportGraphicsPipeline) { char* p[1]; @@ -2045,7 +2096,32 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) freerdp_client_add_dynamic_channel(settings, count, p); } + if (settings->SupportEchoChannel) + { + char* p[1]; + int count; + + count = 1; + p[0] = "echo"; + + freerdp_client_add_dynamic_channel(settings, count, p); + } + + if (settings->SupportDisplayControl) + { + char* p[1]; + int count; + + count = 1; + p[0] = "disp"; + + freerdp_client_add_dynamic_channel(settings, count, p); + } + if (settings->DynamicChannelCount) + settings->SupportDynamicChannels = TRUE; + + if (settings->SupportDynamicChannels) { freerdp_client_load_static_channel_addin(channels, settings, "drdynvc", settings); } diff --git a/client/common/compatibility.c b/client/common/compatibility.c index aeda88a2e..3a7d0dab9 100644 --- a/client/common/compatibility.c +++ b/client/common/compatibility.c @@ -27,12 +27,16 @@ #include #include #include + #include #include +#include #include "compatibility.h" +#define TAG CLIENT_TAG("common.compatibility") + COMMAND_LINE_ARGUMENT_A old_args[] = { { "0", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "connect to console session" }, @@ -121,7 +125,7 @@ int freerdp_client_old_process_plugin(rdpSettings* settings, ADDIN_ARGV* args) if (strcmp(args->argv[0], "cliprdr") == 0) { settings->RedirectClipboard = TRUE; - fprintf(stderr, "--plugin cliprdr -> +clipboard\n"); + WLog_WARN(TAG, "--plugin cliprdr -> +clipboard"); } else if (strcmp(args->argv[0], "rdpdr") == 0) { @@ -437,37 +441,37 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe CommandLineSwitchCase(arg, "0") { settings->ConsoleSession = TRUE; - fprintf(stderr, "-0 -> /admin\n"); + WLog_WARN(TAG, "-0 -> /admin"); } CommandLineSwitchCase(arg, "a") { settings->ColorDepth = atoi(arg->Value); - fprintf(stderr, "-a %s -> /bpp:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-a %s -> /bpp:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "c") { settings->ShellWorkingDirectory = _strdup(arg->Value); - fprintf(stderr, "-c %s -> /shell-dir:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-c %s -> /shell-dir:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "D") { settings->Decorations = FALSE; - fprintf(stderr, "-D -> -decorations\n"); + WLog_WARN(TAG, "-D -> -decorations"); } CommandLineSwitchCase(arg, "T") { settings->WindowTitle = _strdup(arg->Value); - fprintf(stderr, "-T %s -> /title:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-T %s -> /title:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "d") { settings->Domain = _strdup(arg->Value); - fprintf(stderr, "-d %s -> /d:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-d %s -> /d:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "f") { settings->Fullscreen = TRUE; - fprintf(stderr, "-f -> /f\n"); + WLog_WARN(TAG, "-f -> /f"); } CommandLineSwitchCase(arg, "g") { @@ -483,51 +487,50 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe } free(str); - - fprintf(stderr, "-g %s -> /size:%s or /w:%d /h:%d\n", arg->Value, arg->Value, - settings->DesktopWidth, settings->DesktopHeight); + WLog_WARN(TAG, "-g %s -> /size:%s or /w:%d /h:%d", arg->Value, arg->Value, + settings->DesktopWidth, settings->DesktopHeight); } CommandLineSwitchCase(arg, "k") { sscanf(arg->Value, "%X", &(settings->KeyboardLayout)); - fprintf(stderr, "-k %s -> /kbd:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-k %s -> /kbd:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "K") { settings->GrabKeyboard = FALSE; - fprintf(stderr, "-K -> -grab-keyboard\n"); + WLog_WARN(TAG, "-K -> -grab-keyboard"); } CommandLineSwitchCase(arg, "n") { settings->ClientHostname = _strdup(arg->Value); - fprintf(stderr, "-n -> /client-hostname:%s\n", arg->Value); + WLog_WARN(TAG, "-n -> /client-hostname:%s", arg->Value); } CommandLineSwitchCase(arg, "o") { settings->RemoteConsoleAudio = TRUE; - fprintf(stderr, "-o -> /audio-mode:1\n"); + WLog_WARN(TAG, "-o -> /audio-mode:1"); } CommandLineSwitchCase(arg, "p") { settings->Password = _strdup(arg->Value); - fprintf(stderr, "-p ****** -> /p:******\n"); + WLog_WARN(TAG, "-p ****** -> /p:******"); /* Hide the value from 'ps'. */ FillMemory(arg->Value, strlen(arg->Value), '*'); } CommandLineSwitchCase(arg, "s") { settings->AlternateShell = _strdup(arg->Value); - fprintf(stderr, "-s %s -> /shell:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-s %s -> /shell:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "t") { settings->ServerPort = atoi(arg->Value); - fprintf(stderr, "-t %s -> /port:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-t %s -> /port:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "u") { settings->Username = _strdup(arg->Value); - fprintf(stderr, "-u %s -> /u:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-u %s -> /u:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "x") { @@ -555,31 +558,31 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe freerdp_performance_flags_split(settings); } - fprintf(stderr, "-x %s -> /network:", arg->Value); + WLog_WARN(TAG, "-x %s -> /network:", arg->Value); if (type == CONNECTION_TYPE_MODEM) - fprintf(stderr, "modem"); + WLog_WARN(TAG, "modem"); else if (CONNECTION_TYPE_BROADBAND_HIGH) - fprintf(stderr, "broadband"); + WLog_WARN(TAG, "broadband"); else if (CONNECTION_TYPE_LAN) - fprintf(stderr, "lan"); + WLog_WARN(TAG, "lan"); - fprintf(stderr, "\n"); + WLog_WARN(TAG, ""); } CommandLineSwitchCase(arg, "X") { settings->ParentWindowId = strtol(arg->Value, NULL, 0); - fprintf(stderr, "-X %s -> /parent-window:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "-X %s -> /parent-window:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "z") { settings->CompressionEnabled = TRUE; - fprintf(stderr, "-z -> /compression\n"); + WLog_WARN(TAG, "-z -> /compression"); } CommandLineSwitchCase(arg, "app") { settings->RemoteApplicationMode = TRUE; - fprintf(stderr, "--app -> /app: + program name or alias\n"); + WLog_WARN(TAG, "--app -> /app: + program name or alias"); } CommandLineSwitchCase(arg, "ext") { @@ -588,7 +591,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe CommandLineSwitchCase(arg, "no-auth") { settings->Authentication = FALSE; - fprintf(stderr, "--no-auth -> -authentication\n"); + WLog_WARN(TAG, "--no-auth -> -authentication"); } CommandLineSwitchCase(arg, "authonly") { @@ -602,12 +605,12 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe { settings->FastPathInput = FALSE; settings->FastPathOutput = FALSE; - fprintf(stderr, "--no-fastpath -> -fast-path\n"); + WLog_WARN(TAG, "--no-fastpath -> -fast-path"); } CommandLineSwitchCase(arg, "no-motion") { settings->MouseMotion = FALSE; - fprintf(stderr, "--no-motion -> -mouse-motion\n"); + WLog_WARN(TAG, "--no-motion -> -mouse-motion"); } CommandLineSwitchCase(arg, "gdi") { @@ -616,26 +619,26 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe else if (strcmp(arg->Value, "hw") == 0) settings->SoftwareGdi = FALSE; - fprintf(stderr, "--gdi %s -> /gdi:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "--gdi %s -> /gdi:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "no-osb") { settings->OffscreenSupportLevel = FALSE; - fprintf(stderr, "--no-osb -> -offscreen-cache\n"); + WLog_WARN(TAG, "--no-osb -> -offscreen-cache"); } CommandLineSwitchCase(arg, "no-bmp-cache") { settings->BitmapCacheEnabled = FALSE; - fprintf(stderr, "--no-bmp-cache -> -bitmap-cache\n"); + WLog_WARN(TAG, "--no-bmp-cache -> -bitmap-cache"); } CommandLineSwitchCase(arg, "plugin") { - fprintf(stderr, "--plugin -> /a, /vc, /dvc and channel-specific options\n"); + WLog_WARN(TAG, "--plugin -> /a, /vc, /dvc and channel-specific options"); } CommandLineSwitchCase(arg, "rfx") { settings->RemoteFxCodec = TRUE; - fprintf(stderr, "--rfx -> /rfx\n"); + WLog_WARN(TAG, "--rfx -> /rfx"); } CommandLineSwitchCase(arg, "rfx-mode") { @@ -644,37 +647,37 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe else if (arg->Value[0] == 'i') settings->RemoteFxCodecMode = 0x02; - fprintf(stderr, "--rfx-mode -> /rfx-mode:%s\n", settings->RemoteFxCodecMode ? "image" : "video"); + WLog_WARN(TAG, "--rfx-mode -> /rfx-mode:%s", settings->RemoteFxCodecMode ? "image" : "video"); } CommandLineSwitchCase(arg, "nsc") { settings->NSCodec = TRUE; - fprintf(stderr, "--nsc -> /nsc\n"); + WLog_WARN(TAG, "--nsc -> /nsc"); } CommandLineSwitchCase(arg, "disable-wallpaper") { settings->DisableWallpaper = TRUE; - fprintf(stderr, "--disable-wallpaper -> -wallpaper\n"); + WLog_WARN(TAG, "--disable-wallpaper -> -wallpaper"); } CommandLineSwitchCase(arg, "composition") { settings->AllowDesktopComposition = TRUE; - fprintf(stderr, "--composition -> +composition\n"); + WLog_WARN(TAG, "--composition -> +composition"); } CommandLineSwitchCase(arg, "disable-full-window-drag") { settings->DisableFullWindowDrag = TRUE; - fprintf(stderr, "--disable-full-window-drag -> -window-drag\n"); + WLog_WARN(TAG, "--disable-full-window-drag -> -window-drag"); } CommandLineSwitchCase(arg, "disable-menu-animations") { settings->DisableMenuAnims = TRUE; - fprintf(stderr, "--disable-menu-animations -> -menu-anims\n"); + WLog_WARN(TAG, "--disable-menu-animations -> -menu-anims"); } CommandLineSwitchCase(arg, "disable-theming") { settings->DisableThemes = TRUE; - fprintf(stderr, "--disable-theming -> -themes\n"); + WLog_WARN(TAG, "--disable-theming -> -themes"); } CommandLineSwitchCase(arg, "ntlm") { @@ -683,7 +686,7 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe CommandLineSwitchCase(arg, "ignore-certificate") { settings->IgnoreCertificate = TRUE; - fprintf(stderr, "--ignore-certificate -> /cert-ignore\n"); + WLog_WARN(TAG, "--ignore-certificate -> /cert-ignore"); } CommandLineSwitchCase(arg, "sec") { @@ -709,22 +712,22 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe settings->NlaSecurity = TRUE; } - fprintf(stderr, "--sec %s -> /sec:%s\n", arg->Value, arg->Value); + WLog_WARN(TAG, "--sec %s -> /sec:%s", arg->Value, arg->Value); } CommandLineSwitchCase(arg, "no-rdp") { settings->RdpSecurity = FALSE; - fprintf(stderr, "--no-rdp -> -sec-rdp\n"); + WLog_WARN(TAG, "--no-rdp -> -sec-rdp"); } CommandLineSwitchCase(arg, "no-tls") { settings->TlsSecurity = FALSE; - fprintf(stderr, "--no-tls -> -sec-tls\n"); + WLog_WARN(TAG, "--no-tls -> -sec-tls"); } CommandLineSwitchCase(arg, "no-nla") { settings->NlaSecurity = FALSE; - fprintf(stderr, "--no-nla -> -sec-nla\n"); + WLog_WARN(TAG, "--no-nla -> -sec-nla"); } CommandLineSwitchCase(arg, "secure-checksum") { @@ -739,12 +742,11 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); - fprintf(stderr, "%s -> /v:%s", settings->ServerHostname, settings->ServerHostname); + WLog_WARN(TAG, "%s -> /v:%s", settings->ServerHostname, settings->ServerHostname); if (settings->ServerPort != 3389) - fprintf(stderr, " /port:%d", settings->ServerPort); - - fprintf(stderr, "\n"); + WLog_WARN(TAG, " /port:%d", settings->ServerPort); + WLog_WARN(TAG, ""); return 1; } diff --git a/client/common/file.c b/client/common/file.c index c4937343a..911593684 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -21,6 +21,7 @@ #include "config.h" #endif + #include #include @@ -41,6 +42,8 @@ #endif #include +#include +#define TAG CLIENT_TAG("common") //#define DEBUG_CLIENT_FILE 1 @@ -54,7 +57,7 @@ BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, const char* name, int va BOOL bStandard = TRUE; #ifdef DEBUG_CLIENT_FILE - fprintf(stderr, "%s:i:%d\n", name, value); + WLog_DBG(TAG, "%s:i:%d", name, value); #endif if (_stricmp(name, "use multimon") == 0) @@ -240,7 +243,7 @@ BOOL freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, const c BOOL bStandard = TRUE; #ifdef DEBUG_CLIENT_FILE - fprintf(stderr, "%s:s:%s\n", name, value); + WLog_DBG(TAG, "%s:s:%s", name, value); #endif if (_stricmp(name, "username") == 0) @@ -665,7 +668,7 @@ BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL u if (length < 0) { - fprintf(stderr, "freerdp_client_write_rdp_file: error determining buffer size.\n"); + WLog_ERR(TAG, "freerdp_client_write_rdp_file: error determining buffer size."); return FALSE; } @@ -673,7 +676,7 @@ BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL u if (freerdp_client_write_rdp_file_buffer(file, buffer, length + 1) != length) { - fprintf(stderr, "freerdp_client_write_rdp_file: error writing to output buffer\n"); + WLog_ERR(TAG, "freerdp_client_write_rdp_file: error writing to output buffer"); free(buffer); return FALSE; } @@ -1013,6 +1016,11 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* freerdp_set_param_bool(settings, FreeRDP_RedirectDrives, TRUE); } + if (~file->KeyboardHook) + { + freerdp_set_param_uint32(settings, FreeRDP_KeyboardHook, file->KeyboardHook); + } + if (file->argc > 1) { char* ConnectionFile = settings->ConnectionFile; diff --git a/client/iOS/CMakeLists.txt b/client/iOS/CMakeLists.txt index b07e73970..ed14fecd2 100644 --- a/client/iOS/CMakeLists.txt +++ b/client/iOS/CMakeLists.txt @@ -125,13 +125,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${EXTRA_LIBS}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-primitives freerdp-cache freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-input winpr-crt winpr-utils) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/client/iOS/FreeRDP/ios_freerdp_events.h b/client/iOS/FreeRDP/ios_freerdp_events.h old mode 100755 new mode 100644 diff --git a/client/iOS/FreeRDP/ios_freerdp_events.m b/client/iOS/FreeRDP/ios_freerdp_events.m old mode 100755 new mode 100644 diff --git a/client/iOS/Misc/Reachability.h b/client/iOS/Misc/Reachability.h old mode 100755 new mode 100644 diff --git a/client/iOS/Misc/Reachability.m b/client/iOS/Misc/Reachability.m old mode 100755 new mode 100644 diff --git a/client/iOS/Misc/SFHFKeychainUtils.h b/client/iOS/Misc/SFHFKeychainUtils.h old mode 100755 new mode 100644 diff --git a/client/iOS/Misc/SFHFKeychainUtils.m b/client/iOS/Misc/SFHFKeychainUtils.m old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/Default-568h@2x.png b/client/iOS/Resources/Default-568h@2x.png old mode 100755 new mode 100644 index bc2676bd8..9537b26d8 Binary files a/client/iOS/Resources/Default-568h@2x.png and b/client/iOS/Resources/Default-568h@2x.png differ diff --git a/client/iOS/Resources/Default-Landscape@2x~ipad.png b/client/iOS/Resources/Default-Landscape@2x~ipad.png old mode 100755 new mode 100644 index fe643b1bb..572927401 Binary files a/client/iOS/Resources/Default-Landscape@2x~ipad.png and b/client/iOS/Resources/Default-Landscape@2x~ipad.png differ diff --git a/client/iOS/Resources/Default-Landscape~ipad.png b/client/iOS/Resources/Default-Landscape~ipad.png old mode 100755 new mode 100644 index fe4be748b..9d341cdd4 Binary files a/client/iOS/Resources/Default-Landscape~ipad.png and b/client/iOS/Resources/Default-Landscape~ipad.png differ diff --git a/client/iOS/Resources/Default-Portrait@2x~ipad.png b/client/iOS/Resources/Default-Portrait@2x~ipad.png old mode 100755 new mode 100644 index db4a788a8..8f5229902 Binary files a/client/iOS/Resources/Default-Portrait@2x~ipad.png and b/client/iOS/Resources/Default-Portrait@2x~ipad.png differ diff --git a/client/iOS/Resources/Default-Portrait~ipad.png b/client/iOS/Resources/Default-Portrait~ipad.png old mode 100755 new mode 100644 index 94b50ec39..bf15ee27e Binary files a/client/iOS/Resources/Default-Portrait~ipad.png and b/client/iOS/Resources/Default-Portrait~ipad.png differ diff --git a/client/iOS/Resources/Default.png b/client/iOS/Resources/Default.png old mode 100755 new mode 100644 index 86fe48377..0a221638c Binary files a/client/iOS/Resources/Default.png and b/client/iOS/Resources/Default.png differ diff --git a/client/iOS/Resources/Default@2x.png b/client/iOS/Resources/Default@2x.png old mode 100755 new mode 100644 index ba63bf054..74af0a3cb Binary files a/client/iOS/Resources/Default@2x.png and b/client/iOS/Resources/Default@2x.png differ diff --git a/client/iOS/Resources/Icon-72.png b/client/iOS/Resources/Icon-72.png old mode 100755 new mode 100644 index 94951e167..d5be47ff7 Binary files a/client/iOS/Resources/Icon-72.png and b/client/iOS/Resources/Icon-72.png differ diff --git a/client/iOS/Resources/Icon-72@2x.png b/client/iOS/Resources/Icon-72@2x.png old mode 100755 new mode 100644 index e0278b8c6..db3c695ec Binary files a/client/iOS/Resources/Icon-72@2x.png and b/client/iOS/Resources/Icon-72@2x.png differ diff --git a/client/iOS/Resources/Icon.png b/client/iOS/Resources/Icon.png old mode 100755 new mode 100644 index 0d09cdd14..535ed700c Binary files a/client/iOS/Resources/Icon.png and b/client/iOS/Resources/Icon.png differ diff --git a/client/iOS/Resources/Icon@2x.png b/client/iOS/Resources/Icon@2x.png old mode 100755 new mode 100644 index 9b7fae26c..c00b5f0f4 Binary files a/client/iOS/Resources/Icon@2x.png and b/client/iOS/Resources/Icon@2x.png differ diff --git a/client/iOS/Resources/about_page/FreeRDP_Logo.png b/client/iOS/Resources/about_page/FreeRDP_Logo.png old mode 100755 new mode 100644 index 3b2d02f1d..1e272627b Binary files a/client/iOS/Resources/about_page/FreeRDP_Logo.png and b/client/iOS/Resources/about_page/FreeRDP_Logo.png differ diff --git a/client/iOS/Resources/about_page/about.html b/client/iOS/Resources/about_page/about.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/about_page/about_phone.html b/client/iOS/Resources/about_page/about_phone.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/about_page/back.jpg b/client/iOS/Resources/about_page/back.jpg old mode 100755 new mode 100644 index 3bf3455bf..fd4e1d364 Binary files a/client/iOS/Resources/about_page/back.jpg and b/client/iOS/Resources/about_page/back.jpg differ diff --git a/client/iOS/Resources/about_page/background_transparent.png b/client/iOS/Resources/about_page/background_transparent.png old mode 100755 new mode 100644 index 0eba5b5d2..d9d377bdf Binary files a/client/iOS/Resources/about_page/background_transparent.png and b/client/iOS/Resources/about_page/background_transparent.png differ diff --git a/client/iOS/Resources/alert-black-button.png b/client/iOS/Resources/alert-black-button.png index d06b66df1..998139788 100644 Binary files a/client/iOS/Resources/alert-black-button.png and b/client/iOS/Resources/alert-black-button.png differ diff --git a/client/iOS/Resources/alert-black-button@2x.png b/client/iOS/Resources/alert-black-button@2x.png index 4caec8ea3..234bda42f 100644 Binary files a/client/iOS/Resources/alert-black-button@2x.png and b/client/iOS/Resources/alert-black-button@2x.png differ diff --git a/client/iOS/Resources/alert-gray-button.png b/client/iOS/Resources/alert-gray-button.png index 06548df51..3696a67ac 100644 Binary files a/client/iOS/Resources/alert-gray-button.png and b/client/iOS/Resources/alert-gray-button.png differ diff --git a/client/iOS/Resources/alert-gray-button@2x.png b/client/iOS/Resources/alert-gray-button@2x.png index 8333e6cfb..b1393c099 100644 Binary files a/client/iOS/Resources/alert-gray-button@2x.png and b/client/iOS/Resources/alert-gray-button@2x.png differ diff --git a/client/iOS/Resources/alert-red-button.png b/client/iOS/Resources/alert-red-button.png index 896742f9c..bdf3028b8 100644 Binary files a/client/iOS/Resources/alert-red-button.png and b/client/iOS/Resources/alert-red-button.png differ diff --git a/client/iOS/Resources/alert-red-button@2x.png b/client/iOS/Resources/alert-red-button@2x.png index 852bd3f4b..1c513773b 100644 Binary files a/client/iOS/Resources/alert-red-button@2x.png and b/client/iOS/Resources/alert-red-button@2x.png differ diff --git a/client/iOS/Resources/alert-window-landscape.png b/client/iOS/Resources/alert-window-landscape.png index 1149b28cd..13c598585 100644 Binary files a/client/iOS/Resources/alert-window-landscape.png and b/client/iOS/Resources/alert-window-landscape.png differ diff --git a/client/iOS/Resources/alert-window-landscape@2x.png b/client/iOS/Resources/alert-window-landscape@2x.png index 3bb3b8aab..aeb030832 100644 Binary files a/client/iOS/Resources/alert-window-landscape@2x.png and b/client/iOS/Resources/alert-window-landscape@2x.png differ diff --git a/client/iOS/Resources/alert-window.png b/client/iOS/Resources/alert-window.png index e4907cf53..ea192d57a 100644 Binary files a/client/iOS/Resources/alert-window.png and b/client/iOS/Resources/alert-window.png differ diff --git a/client/iOS/Resources/alert-window@2x.png b/client/iOS/Resources/alert-window@2x.png index 2ecd13855..6de36ea03 100644 Binary files a/client/iOS/Resources/alert-window@2x.png and b/client/iOS/Resources/alert-window@2x.png differ diff --git a/client/iOS/Resources/cancel_button_background.png b/client/iOS/Resources/cancel_button_background.png index ae12d407d..5061279c0 100644 Binary files a/client/iOS/Resources/cancel_button_background.png and b/client/iOS/Resources/cancel_button_background.png differ diff --git a/client/iOS/Resources/help_page/back.jpg b/client/iOS/Resources/help_page/back.jpg old mode 100755 new mode 100644 index 3bf3455bf..fd4e1d364 Binary files a/client/iOS/Resources/help_page/back.jpg and b/client/iOS/Resources/help_page/back.jpg differ diff --git a/client/iOS/Resources/help_page/gestures.html b/client/iOS/Resources/help_page/gestures.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/gestures.png b/client/iOS/Resources/help_page/gestures.png old mode 100755 new mode 100644 index e49a45b8f..78b3e7b34 Binary files a/client/iOS/Resources/help_page/gestures.png and b/client/iOS/Resources/help_page/gestures.png differ diff --git a/client/iOS/Resources/help_page/gestures_phone.html b/client/iOS/Resources/help_page/gestures_phone.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/gestures_phone.png b/client/iOS/Resources/help_page/gestures_phone.png old mode 100755 new mode 100644 index 1b90a1f65..4eea33ef4 Binary files a/client/iOS/Resources/help_page/gestures_phone.png and b/client/iOS/Resources/help_page/gestures_phone.png differ diff --git a/client/iOS/Resources/help_page/nav_gestures.png b/client/iOS/Resources/help_page/nav_gestures.png old mode 100755 new mode 100644 index ab1b36fba..50bfaa232 Binary files a/client/iOS/Resources/help_page/nav_gestures.png and b/client/iOS/Resources/help_page/nav_gestures.png differ diff --git a/client/iOS/Resources/help_page/nav_toolbar.png b/client/iOS/Resources/help_page/nav_toolbar.png old mode 100755 new mode 100644 index 703c0013a..f66b24d21 Binary files a/client/iOS/Resources/help_page/nav_toolbar.png and b/client/iOS/Resources/help_page/nav_toolbar.png differ diff --git a/client/iOS/Resources/help_page/nav_touch_pointer.png b/client/iOS/Resources/help_page/nav_touch_pointer.png old mode 100755 new mode 100644 index 30e04568e..930fc9cbf Binary files a/client/iOS/Resources/help_page/nav_touch_pointer.png and b/client/iOS/Resources/help_page/nav_touch_pointer.png differ diff --git a/client/iOS/Resources/help_page/toolbar.html b/client/iOS/Resources/help_page/toolbar.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/toolbar.png b/client/iOS/Resources/help_page/toolbar.png old mode 100755 new mode 100644 index 10c23b62b..42f055b9f Binary files a/client/iOS/Resources/help_page/toolbar.png and b/client/iOS/Resources/help_page/toolbar.png differ diff --git a/client/iOS/Resources/help_page/toolbar_phone.html b/client/iOS/Resources/help_page/toolbar_phone.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/toolbar_phone.png b/client/iOS/Resources/help_page/toolbar_phone.png old mode 100755 new mode 100644 index a01279ce0..278cd3a9d Binary files a/client/iOS/Resources/help_page/toolbar_phone.png and b/client/iOS/Resources/help_page/toolbar_phone.png differ diff --git a/client/iOS/Resources/help_page/touch_pointer.html b/client/iOS/Resources/help_page/touch_pointer.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/touch_pointer.png b/client/iOS/Resources/help_page/touch_pointer.png old mode 100755 new mode 100644 index f06e3889f..af3ebcab0 Binary files a/client/iOS/Resources/help_page/touch_pointer.png and b/client/iOS/Resources/help_page/touch_pointer.png differ diff --git a/client/iOS/Resources/help_page/touch_pointer_phone.html b/client/iOS/Resources/help_page/touch_pointer_phone.html old mode 100755 new mode 100644 diff --git a/client/iOS/Resources/help_page/touch_pointer_phone.png b/client/iOS/Resources/help_page/touch_pointer_phone.png old mode 100755 new mode 100644 index 168749fd0..ab7c59896 Binary files a/client/iOS/Resources/help_page/touch_pointer_phone.png and b/client/iOS/Resources/help_page/touch_pointer_phone.png differ diff --git a/client/iOS/Resources/icon_accessory_star_off.png b/client/iOS/Resources/icon_accessory_star_off.png old mode 100755 new mode 100644 index f0f1eb845..b0dce0e66 Binary files a/client/iOS/Resources/icon_accessory_star_off.png and b/client/iOS/Resources/icon_accessory_star_off.png differ diff --git a/client/iOS/Resources/icon_accessory_star_on.png b/client/iOS/Resources/icon_accessory_star_on.png old mode 100755 new mode 100644 index cf5ed353b..b09dec7ae Binary files a/client/iOS/Resources/icon_accessory_star_on.png and b/client/iOS/Resources/icon_accessory_star_on.png differ diff --git a/client/iOS/Resources/icon_key_arrow_down.png b/client/iOS/Resources/icon_key_arrow_down.png old mode 100755 new mode 100644 index 3baf19cab..b003e1295 Binary files a/client/iOS/Resources/icon_key_arrow_down.png and b/client/iOS/Resources/icon_key_arrow_down.png differ diff --git a/client/iOS/Resources/icon_key_arrow_left.png b/client/iOS/Resources/icon_key_arrow_left.png old mode 100755 new mode 100644 index 4c0c8eb14..7cd1ed3d4 Binary files a/client/iOS/Resources/icon_key_arrow_left.png and b/client/iOS/Resources/icon_key_arrow_left.png differ diff --git a/client/iOS/Resources/icon_key_arrow_right.png b/client/iOS/Resources/icon_key_arrow_right.png old mode 100755 new mode 100644 index 10c7d8e27..9a5815730 Binary files a/client/iOS/Resources/icon_key_arrow_right.png and b/client/iOS/Resources/icon_key_arrow_right.png differ diff --git a/client/iOS/Resources/icon_key_arrow_up.png b/client/iOS/Resources/icon_key_arrow_up.png old mode 100755 new mode 100644 index b8e3f2820..248c7f617 Binary files a/client/iOS/Resources/icon_key_arrow_up.png and b/client/iOS/Resources/icon_key_arrow_up.png differ diff --git a/client/iOS/Resources/icon_key_arrows.png b/client/iOS/Resources/icon_key_arrows.png old mode 100755 new mode 100644 index 56c915369..e92ef461a Binary files a/client/iOS/Resources/icon_key_arrows.png and b/client/iOS/Resources/icon_key_arrows.png differ diff --git a/client/iOS/Resources/icon_key_backspace.png b/client/iOS/Resources/icon_key_backspace.png old mode 100755 new mode 100644 index 7e9d29541..730d3e16b Binary files a/client/iOS/Resources/icon_key_backspace.png and b/client/iOS/Resources/icon_key_backspace.png differ diff --git a/client/iOS/Resources/icon_key_menu.png b/client/iOS/Resources/icon_key_menu.png old mode 100755 new mode 100644 index 0b4445263..61e12ed2a Binary files a/client/iOS/Resources/icon_key_menu.png and b/client/iOS/Resources/icon_key_menu.png differ diff --git a/client/iOS/Resources/icon_key_return.png b/client/iOS/Resources/icon_key_return.png old mode 100755 new mode 100644 index 9311ad171..bf6a7da20 Binary files a/client/iOS/Resources/icon_key_return.png and b/client/iOS/Resources/icon_key_return.png differ diff --git a/client/iOS/Resources/icon_key_win.png b/client/iOS/Resources/icon_key_win.png old mode 100755 new mode 100644 index 1ab7b2b46..bd43d8241 Binary files a/client/iOS/Resources/icon_key_win.png and b/client/iOS/Resources/icon_key_win.png differ diff --git a/client/iOS/Resources/keyboard_button_background.png b/client/iOS/Resources/keyboard_button_background.png old mode 100755 new mode 100644 index c6cd5795b..cfb229ec4 Binary files a/client/iOS/Resources/keyboard_button_background.png and b/client/iOS/Resources/keyboard_button_background.png differ diff --git a/client/iOS/Resources/tabbar_icon_about.png b/client/iOS/Resources/tabbar_icon_about.png old mode 100755 new mode 100644 index 8d03924a8..01709a5a1 Binary files a/client/iOS/Resources/tabbar_icon_about.png and b/client/iOS/Resources/tabbar_icon_about.png differ diff --git a/client/iOS/Resources/tabbar_icon_help.png b/client/iOS/Resources/tabbar_icon_help.png old mode 100755 new mode 100644 index 0732b7d15..4e66e5bcb Binary files a/client/iOS/Resources/tabbar_icon_help.png and b/client/iOS/Resources/tabbar_icon_help.png differ diff --git a/client/iOS/Resources/tabbar_icon_settings.png b/client/iOS/Resources/tabbar_icon_settings.png old mode 100755 new mode 100644 index 04578f02c..7cf0380f3 Binary files a/client/iOS/Resources/tabbar_icon_settings.png and b/client/iOS/Resources/tabbar_icon_settings.png differ diff --git a/client/iOS/Resources/toolbar_icon_disconnect.png b/client/iOS/Resources/toolbar_icon_disconnect.png old mode 100755 new mode 100644 index cb823d4ec..e78510910 Binary files a/client/iOS/Resources/toolbar_icon_disconnect.png and b/client/iOS/Resources/toolbar_icon_disconnect.png differ diff --git a/client/iOS/Resources/toolbar_icon_extkeyboad.png b/client/iOS/Resources/toolbar_icon_extkeyboad.png old mode 100755 new mode 100644 index 9436c07c3..463d70172 Binary files a/client/iOS/Resources/toolbar_icon_extkeyboad.png and b/client/iOS/Resources/toolbar_icon_extkeyboad.png differ diff --git a/client/iOS/Resources/toolbar_icon_home.png b/client/iOS/Resources/toolbar_icon_home.png old mode 100755 new mode 100644 index afcd9e4a9..b9152c05b Binary files a/client/iOS/Resources/toolbar_icon_home.png and b/client/iOS/Resources/toolbar_icon_home.png differ diff --git a/client/iOS/Resources/toolbar_icon_keyboard.png b/client/iOS/Resources/toolbar_icon_keyboard.png old mode 100755 new mode 100644 index c2a068531..622c9ec10 Binary files a/client/iOS/Resources/toolbar_icon_keyboard.png and b/client/iOS/Resources/toolbar_icon_keyboard.png differ diff --git a/client/iOS/Resources/toolbar_icon_touchpointer.png b/client/iOS/Resources/toolbar_icon_touchpointer.png old mode 100755 new mode 100644 index fc44508c9..4c738d4ab Binary files a/client/iOS/Resources/toolbar_icon_touchpointer.png and b/client/iOS/Resources/toolbar_icon_touchpointer.png differ diff --git a/client/iOS/Resources/toolbar_icon_win.png b/client/iOS/Resources/toolbar_icon_win.png old mode 100755 new mode 100644 index 73328db1a..5c224971f Binary files a/client/iOS/Resources/toolbar_icon_win.png and b/client/iOS/Resources/toolbar_icon_win.png differ diff --git a/client/iOS/Resources/touch_pointer_active.png b/client/iOS/Resources/touch_pointer_active.png old mode 100755 new mode 100644 index c153de484..9966590ed Binary files a/client/iOS/Resources/touch_pointer_active.png and b/client/iOS/Resources/touch_pointer_active.png differ diff --git a/client/iOS/Resources/touch_pointer_default.png b/client/iOS/Resources/touch_pointer_default.png old mode 100755 new mode 100644 index ba16a47c8..5f419eefd Binary files a/client/iOS/Resources/touch_pointer_default.png and b/client/iOS/Resources/touch_pointer_default.png differ diff --git a/client/iOS/Resources/touch_pointer_extkeyboard.png b/client/iOS/Resources/touch_pointer_extkeyboard.png old mode 100755 new mode 100644 index 6f0c8cd10..bbc9752c4 Binary files a/client/iOS/Resources/touch_pointer_extkeyboard.png and b/client/iOS/Resources/touch_pointer_extkeyboard.png differ diff --git a/client/iOS/Resources/touch_pointer_keyboard.png b/client/iOS/Resources/touch_pointer_keyboard.png old mode 100755 new mode 100644 index 1a6d60dbd..d5cf2033a Binary files a/client/iOS/Resources/touch_pointer_keyboard.png and b/client/iOS/Resources/touch_pointer_keyboard.png differ diff --git a/client/iOS/Resources/touch_pointer_lclick.png b/client/iOS/Resources/touch_pointer_lclick.png old mode 100755 new mode 100644 index 447d8abae..69d721501 Binary files a/client/iOS/Resources/touch_pointer_lclick.png and b/client/iOS/Resources/touch_pointer_lclick.png differ diff --git a/client/iOS/Resources/touch_pointer_rclick.png b/client/iOS/Resources/touch_pointer_rclick.png old mode 100755 new mode 100644 index ad3ca8543..dc3c173b7 Binary files a/client/iOS/Resources/touch_pointer_rclick.png and b/client/iOS/Resources/touch_pointer_rclick.png differ diff --git a/client/iOS/Resources/touch_pointer_reset.png b/client/iOS/Resources/touch_pointer_reset.png old mode 100755 new mode 100644 index 41ef8402a..b42b3fa59 Binary files a/client/iOS/Resources/touch_pointer_reset.png and b/client/iOS/Resources/touch_pointer_reset.png differ diff --git a/client/iOS/Resources/touch_pointer_scroll.png b/client/iOS/Resources/touch_pointer_scroll.png old mode 100755 new mode 100644 index 2855e0165..b4d7e24de Binary files a/client/iOS/Resources/touch_pointer_scroll.png and b/client/iOS/Resources/touch_pointer_scroll.png differ diff --git a/client/iOS/Views/BlockAlertView.h b/client/iOS/Views/BlockAlertView.h old mode 100755 new mode 100644 diff --git a/client/iOS/Views/BlockAlertView.m b/client/iOS/Views/BlockAlertView.m old mode 100755 new mode 100644 diff --git a/cmake/AndroidToolchain.cmake b/cmake/AndroidToolchain.cmake index d31eaaccd..26d8ac3e7 100644 --- a/cmake/AndroidToolchain.cmake +++ b/cmake/AndroidToolchain.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2013, Andrey Kamaev +# Copyright (c) 2011-2014, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -12,9 +12,9 @@ # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # -# 3. The name of the copyright holders may be used to endorse or promote -# products derived from this software without specific prior written -# permission. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -29,7 +29,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ -# Android CMake toolchain file, for use with the Android NDK r5-r8 +# Android CMake toolchain file, for use with the Android NDK r5-r9 # Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # @@ -87,8 +87,7 @@ # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP. # "x86" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. -# "mips" - matches to the NDK ABI with the same name -# (It is not tested on real devices by the authos of this toolchain) +# "mips" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. @@ -294,6 +293,16 @@ # [~] automatically detect if explicit link to crtbegin_*.o is needed # - June 2013 # [~] fixed stl include path for standalone toolchain made by NDK >= r8c +# - July 2013 +# [+] updated for NDK r9 +# - November 2013 +# [+] updated for NDK r9b +# - December 2013 +# [+] updated for NDK r9c +# - January 2014 +# [~] fix copying of shared STL +# - April 2014 +# [+] updated for NDK r9d # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) @@ -326,7 +335,7 @@ endif() # rpath makes low sence for Android set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) @@ -470,10 +479,9 @@ if( ANDROID_FORBID_SYGWIN ) endif() endif() -# FIXME: properly detect 64-bit host, currently reported as 32-bit # detect current host platform -if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() @@ -494,7 +502,7 @@ else() endif() if( NOT ANDROID_NDK_HOST_X64 ) - #set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) endif() # see if we have path to Android NDK @@ -1139,15 +1147,7 @@ endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) - if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) - get_filename_component( __libstlname "${__libstl}" NAME ) - execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) - if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") - message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) - endif() - unset( __fileCopyProcess ) - unset( __libstlname ) - endif() + # TODO: check if .so file exists before the renaming endif() @@ -1512,7 +1512,8 @@ endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) -link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning +link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) @@ -1564,6 +1565,18 @@ if(NOT _CMAKE_IN_TRY_COMPILE) set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" ) endif() +# copy shaed stl library to build directory +if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) + get_filename_component( __libstlname "${__libstl}" NAME ) + execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) + if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") + message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) + endif() + unset( __fileCopyProcess ) + unset( __libstlname ) +endif() + + # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) @@ -1672,6 +1685,19 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) endif() +# force cmake to produce / instead of \ in build commands for Ninja generator +if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) + # it is a bad hack after all + # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW + set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW + set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion + enable_language( C ) + enable_language( CXX ) + # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it + unset( MINGW ) +endif() + + # set some obsolete variables for backward compatibility set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" ) mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES ) @@ -1726,7 +1752,7 @@ endif() # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI -# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e; set only for NDK +# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b, r9c, r9d; set only for NDK # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform diff --git a/cmake/CheckCmakeCompat.cmake b/cmake/CheckCmakeCompat.cmake index 19710b2ad..6b9f9cc12 100644 --- a/cmake/CheckCmakeCompat.cmake +++ b/cmake/CheckCmakeCompat.cmake @@ -28,13 +28,6 @@ enable_cmake_compat(2.8.6) enable_cmake_compat(2.8.3) enable_cmake_compat(2.8.2) -# If MONOLITHIC_BUILD is used with cmake < 2.8.8 build fails -if (MONOLITHIC_BUILD) - if(${CMAKE_VERSION} VERSION_LESS 2.8.8) - message(FATAL_ERROR "CMAKE version >= 2.8.8 required for MONOLITHIC_BUILD") - endif() -endif(MONOLITHIC_BUILD) - # GetGitRevisionDescription requires FindGit which was added in version 2.8.2 # build won't fail but GIT_REVISION is set to n/a if(${CMAKE_VERSION} VERSION_LESS 2.8.2) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index d2e56eade..17af6d9cd 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -1,5 +1,5 @@ -if((CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686|x86") AND (CMAKE_SIZEOF_VOID_P EQUAL 4)) +if((CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686|x86|AMD64") AND (CMAKE_SIZEOF_VOID_P EQUAL 4)) set(TARGET_ARCH "x86") elseif((CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") AND (CMAKE_SIZEOF_VOID_P EQUAL 8)) set(TARGET_ARCH "x64") @@ -59,14 +59,6 @@ option(WITH_SMARTCARD_INSPECT "Enable SmartCard API Inspector" OFF) option(BUILD_TESTING "Build unit tests" OFF) option(WITH_SAMPLE "Build sample code" OFF) -if(${CMAKE_VERSION} VERSION_GREATER 2.8.8) - if(ANDROID) - option(MONOLITHIC_BUILD "Use monolithic build" ON) - else() - option(MONOLITHIC_BUILD "Use monolithic build" OFF) - endif() -endif() - option(WITH_CLIENT "Build client binaries" ON) option(WITH_SERVER "Build server binaries" OFF) diff --git a/cmake/FindGlib.cmake b/cmake/FindGlib.cmake index 3e22eb075..8005ce12b 100644 --- a/cmake/FindGlib.cmake +++ b/cmake/FindGlib.cmake @@ -28,11 +28,10 @@ find_library(Gobject_LIBRARY PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR} ) -# Glib-related libraries also use a separate config header, which is in lib dir +# Glib-related libraries also use a separate config header, which is relative to lib dir find_path(GlibConfig_INCLUDE_DIR NAMES glibconfig.h - PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr ${GLIB_ROOT_DIR} - PATH_SUFFIXES lib/glib-2.0/include glib-2.0/include + PATHS ${Glib_PKGCONF_INCLUDE_DIRS} ${GLIB_ROOT_DIR} ) # Set the include dir variables and the libraries and let libfind_process do the rest. diff --git a/cmake/FindOpenH264.cmake b/cmake/FindOpenH264.cmake new file mode 100644 index 000000000..2e06e34d1 --- /dev/null +++ b/cmake/FindOpenH264.cmake @@ -0,0 +1,31 @@ +# - Try to find the OpenH264 library +# Once done this will define +# +# OPENH264_FOUND - system has OpenH264 +# OPENH264_INCLUDE_DIR - the OpenH264 include directory +# OPENH264_LIBRARIES - libopenh264 library + +if (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + set(OPENH264_FIND_QUIETLY TRUE) +endif (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + +find_path(OPENH264_INCLUDE_DIR NAMES wels/codec_api.h wels/codec_app_def.h wels/codec_def.h) +find_library(OPENH264_LIBRARY openh264) + +if (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + set(OPENH264_FOUND TRUE) + set(OPENH264_LIBRARIES ${OPENH264_LIBRARY}) +endif (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + +if (OPENH264_FOUND) + if (NOT OPENH264_FIND_QUIETLY) + message(STATUS "Found OpenH264: ${OPENH264_LIBRARIES}") + endif (NOT OPENH264_FIND_QUIETLY) +else (OPENH264_FOUND) + if (OPENH264_FIND_REQUIRED) + message(FATAL_ERROR "OpenH264 was not found") + endif(OPENH264_FIND_REQUIRED) +endif (OPENH264_FOUND) + +mark_as_advanced(OPENH264_INCLUDE_DIR OPENH264_LIBRARY) + diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake new file mode 100644 index 000000000..131544465 --- /dev/null +++ b/cmake/FindWayland.cmake @@ -0,0 +1,46 @@ +# - Find Wayland +# Find the Wayland libraries +# +# This module defines the following variables: +# WAYLAND_FOUND - true if WAYLAND_INCLUDE_DIR & WAYLAND_LIBRARY are found +# WAYLAND_LIBRARIES - Set when WAYLAND_LIBRARY is found +# WAYLAND_INCLUDE_DIRS - Set when WAYLAND_INCLUDE_DIR is found +# +# WAYLAND_INCLUDE_DIR - where to find wayland-client.h, etc. +# WAYLAND_LIBRARY - the Wayland client library +# + +#============================================================================= +# Copyright 2014 Manuel Bachmann +# +# 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. +#============================================================================= + +find_path(WAYLAND_INCLUDE_DIR NAMES wayland-client.h + DOC "The Wayland include directory" +) + +find_library(WAYLAND_LIBRARY NAMES wayland-client + DOC "The Wayland client library" +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARY WAYLAND_INCLUDE_DIR) + +if(WAYLAND_FOUND) + set( WAYLAND_LIBRARIES ${WAYLAND_LIBRARY} ) + set( WAYLAND_INCLUDE_DIRS ${WAYLAND_INCLUDE_DIR} ) +endif() + +mark_as_advanced(WAYLAND_INCLUDE_DIR WAYLAND_LIBRARY) + diff --git a/config.h.in b/config.h.in old mode 100755 new mode 100644 index df9001f72..b196cc5ae --- a/config.h.in +++ b/config.h.in @@ -24,9 +24,10 @@ #cmakedefine HAVE_TIMERFD_H #cmakedefine HAVE_TM_GMTOFF #cmakedefine HAVE_AIO_H +#cmakedefine HAVE_POLL_H #cmakedefine HAVE_PTHREAD_GNU_EXT #cmakedefine HAVE_VALGRIND_MEMCHECK_H - +#cmakedefine HAVE_EXECINFO_H /* Options */ #cmakedefine WITH_PROFILER diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index ca351c5fc..dffd4d329 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -71,7 +71,7 @@ target_link_libraries(test_freerdp freerdp-utils) target_link_libraries(test_freerdp freerdp-codec) target_link_libraries(test_freerdp freerdp-crypto) -target_link_libraries(test_freerdp winpr-sspi) +target_link_libraries(test_freerdp winpr) add_test(CUnitTests ${CMAKE_SOURCE_DIR}/cunit/test_freerdp) diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index 636da91c9..d426635e2 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -37,6 +37,8 @@ #include "test_mppc.h" #include "test_mppc_enc.h" +#define TAG __FILE__ + void dump_data(unsigned char * p, int len, int width, char* name) { unsigned char *line = p; @@ -77,10 +79,10 @@ void assert_stream(wStream* s, BYTE* data, int length, const char* func, int lin printf("\n %s (%d): length mismatch, actual:%d, expected:%d\n", func, line, actual_length, length); printf("\nActual:\n"); - winpr_HexDump(actual_data, actual_length); + winpr_HexDump(TAG, WLOG_ERR, actual_data, actual_length); printf("Expected:\n"); - winpr_HexDump(data, length); + winpr_HexDump(TAG, WLOG_ERR, data, length); CU_FAIL("assert_stream, length mismatch"); return; @@ -93,10 +95,10 @@ void assert_stream(wStream* s, BYTE* data, int length, const char* func, int lin printf("\n %s (%d): buffer mismatch:\n", func, line); printf("\nActual:\n"); - winpr_HexDump(actual_data, length); + winpr_HexDump(TAG, WLOG_ERR, actual_data, length); printf("Expected:\n"); - winpr_HexDump(data, length); + winpr_HexDump(TAG, WLOG_ERR, data, length); CU_FAIL("assert_stream, buffer mismatch"); return; diff --git a/include/freerdp/assistance.h b/include/freerdp/assistance.h new file mode 100644 index 000000000..050f93363 --- /dev/null +++ b/include/freerdp/assistance.h @@ -0,0 +1,83 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance + * + * 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 FREERDP_REMOTE_ASSISTANCE_H +#define FREERDP_REMOTE_ASSISTANCE_H + +#include +#include + +struct rdp_assistance_file +{ + UINT32 Type; + + char* Username; + char* LHTicket; + char* RCTicket; + char* PassStub; + UINT32 DtStart; + UINT32 DtLength; + BOOL LowSpeed; + BOOL RCTicketEncrypted; + + char* ConnectionString1; + char* ConnectionString2; + + BYTE* EncryptedPassStub; + int EncryptedPassStubLength; + + BYTE* EncryptedLHTicket; + int EncryptedLHTicketLength; + + char* MachineAddress; + UINT32 MachinePort; + char* RASessionId; + char* RASpecificParams; +}; +typedef struct rdp_assistance_file rdpAssistanceFile; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API BYTE* freerdp_assistance_hex_string_to_bin(const char* str, int* size); +FREERDP_API char* freerdp_assistance_bin_to_hex_string(const BYTE* data, int size); + +FREERDP_API int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file); +FREERDP_API int freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file); + +FREERDP_API char* freerdp_assistance_generate_pass_stub(DWORD flags); +FREERDP_API char* freerdp_assistance_construct_expert_blob(const char* name, const char* pass); +FREERDP_API BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize); + +FREERDP_API int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size); +FREERDP_API int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name); +FREERDP_API int freerdp_assistance_decrypt(rdpAssistanceFile* file, const char* password); + +FREERDP_API int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings); + +FREERDP_API rdpAssistanceFile* freerdp_assistance_file_new(); +FREERDP_API void freerdp_assistance_file_free(rdpAssistanceFile* file); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_REMOTE_ASSISTANCE_H */ + diff --git a/include/freerdp/channels/cliprdr.h b/include/freerdp/channels/cliprdr.h index d8ba55096..4d1ced31c 100644 --- a/include/freerdp/channels/cliprdr.h +++ b/include/freerdp/channels/cliprdr.h @@ -29,30 +29,6 @@ * Clipboard Formats */ -#define CLIPRDR_FORMAT_RAW 0 -#define CLIPRDR_FORMAT_TEXT 1 /* "Plain Text" */ -#define CLIPRDR_FORMAT_BITMAP 2 /* "Bitmap" */ -#define CLIPRDR_FORMAT_METAFILEPICT 3 /* "Windows Metafile" */ -#define CLIPRDR_FORMAT_SYLK 4 -#define CLIPRDR_FORMAT_DIF 5 -#define CLIPRDR_FORMAT_TIFF 6 -#define CLIPRDR_FORMAT_OEMTEXT 7 /* "OEM Text" */ -#define CLIPRDR_FORMAT_DIB 8 /* "Device Independent Bitmap (DIB)" */ -#define CLIPRDR_FORMAT_PALETTE 9 -#define CLIPRDR_FORMAT_PENDATA 10 -#define CLIPRDR_FORMAT_RIFF 11 -#define CLIPRDR_FORMAT_WAVE 12 -#define CLIPRDR_FORMAT_UNICODETEXT 13 /* "Unicode Text" */ -#define CLIPRDR_FORMAT_ENHMETAFILE 14 /* "Enhanced Metafile" */ -#define CLIPRDR_FORMAT_HDROP 15 /* "File List" */ -#define CLIPRDR_FORMAT_LOCALE 16 /* "Locale Identifier" */ -#define CLIPRDR_FORMAT_DIBV5 17 -#define CLIPRDR_FORMAT_MAX 18 - -#define CB_FORMAT_RAW 0x0000 -#define CB_FORMAT_TEXT 0x0001 -#define CB_FORMAT_DIB 0x0008 -#define CB_FORMAT_UNICODETEXT 0x000D #define CB_FORMAT_HTML 0xD010 #define CB_FORMAT_PNG 0xD011 #define CB_FORMAT_JPEG 0xD012 @@ -149,7 +125,7 @@ struct _CLIPRDR_FORMAT_LIST { DEFINE_CLIPRDR_HEADER_COMMON(); - UINT32 cFormats; + UINT32 numFormats; CLIPRDR_FORMAT* formats; }; typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST; diff --git a/include/freerdp/channels/encomsp.h b/include/freerdp/channels/encomsp.h new file mode 100644 index 000000000..b2fffc5b4 --- /dev/null +++ b/include/freerdp/channels/encomsp.h @@ -0,0 +1,186 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 FREERDP_CHANNEL_ENCOMSP_H +#define FREERDP_CHANNEL_ENCOMSP_H + +#include +#include + +#define ENCOMSP_SVC_CHANNEL_NAME "encomsp" + +struct _ENCOMSP_UNICODE_STRING +{ + UINT16 cchString; + WCHAR wString[1024]; +}; +typedef struct _ENCOMSP_UNICODE_STRING ENCOMSP_UNICODE_STRING; + +/* Filter Updated PDU Flags */ + +#define ENCOMSP_FILTER_ENABLED 0x0001 + +/* Application Created PDU Flags */ + +#define ENCOMSP_APPLICATION_SHARED 0x0001 + +/* Window Created PDU Flags */ + +#define ENCOMSP_WINDOW_SHARED 0x0001 + +/* Participant Created PDU Flags */ + +#define ENCOMSP_MAY_VIEW 0x0001 +#define ENCOMSP_MAY_INTERACT 0x0002 +#define ENCOMSP_IS_PARTICIPANT 0x0004 + +/* Participant Removed PDU Disconnection Types */ + +#define ENCOMSP_PARTICIPANT_DISCONNECTION_REASON_APP 0x00000000 +#define ENCOMSP_PARTICIPANT_DISCONNECTION_REASON_CLI 0x00000002 + +/* Change Participant Control Level PDU Flags */ + +#define ENCOMSP_REQUEST_VIEW 0x0001 +#define ENCOMSP_REQUEST_INTERACT 0x0002 +#define ENCOMSP_ALLOW_CONTROL_REQUESTS 0x0008 + +/* PDU Order Types */ + +#define ODTYPE_FILTER_STATE_UPDATED 0x0001 +#define ODTYPE_APP_REMOVED 0x0002 +#define ODTYPE_APP_CREATED 0x0003 +#define ODTYPE_WND_REMOVED 0x0004 +#define ODTYPE_WND_CREATED 0x0005 +#define ODTYPE_WND_SHOW 0x0006 +#define ODTYPE_PARTICIPANT_REMOVED 0x0007 +#define ODTYPE_PARTICIPANT_CREATED 0x0008 +#define ODTYPE_PARTICIPANT_CTRL_CHANGED 0x0009 +#define ODTYPE_GRAPHICS_STREAM_PAUSED 0x000A +#define ODTYPE_GRAPHICS_STREAM_RESUMED 0x000B + +#define DEFINE_ENCOMSP_HEADER_COMMON() \ + UINT16 Type; \ + UINT16 Length + +#define ENCOMSP_ORDER_HEADER_SIZE 4 + +struct _ENCOMSP_ORDER_HEADER +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_ORDER_HEADER ENCOMSP_ORDER_HEADER; + +struct _ENCOMSP_FILTER_UPDATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + BYTE Flags; +}; +typedef struct _ENCOMSP_FILTER_UPDATED_PDU ENCOMSP_FILTER_UPDATED_PDU; + +struct _ENCOMSP_APPLICATION_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 AppId; + ENCOMSP_UNICODE_STRING Name; +}; +typedef struct _ENCOMSP_APPLICATION_CREATED_PDU ENCOMSP_APPLICATION_CREATED_PDU; + +struct _ENCOMSP_APPLICATION_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 AppId; +}; +typedef struct _ENCOMSP_APPLICATION_REMOVED_PDU ENCOMSP_APPLICATION_REMOVED_PDU; + +struct _ENCOMSP_WINDOW_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 AppId; + UINT32 WndId; + ENCOMSP_UNICODE_STRING Name; +}; +typedef struct _ENCOMSP_WINDOW_CREATED_PDU ENCOMSP_WINDOW_CREATED_PDU; + +struct _ENCOMSP_WINDOW_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 WndId; +}; +typedef struct _ENCOMSP_WINDOW_REMOVED_PDU ENCOMSP_WINDOW_REMOVED_PDU; + +struct _ENCOMSP_SHOW_WINDOW_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 WndId; +}; +typedef struct _ENCOMSP_SHOW_WINDOW_PDU ENCOMSP_SHOW_WINDOW_PDU; + +struct _ENCOMSP_PARTICIPANT_CREATED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 ParticipantId; + UINT32 GroupId; + UINT16 Flags; + ENCOMSP_UNICODE_STRING FriendlyName; +}; +typedef struct _ENCOMSP_PARTICIPANT_CREATED_PDU ENCOMSP_PARTICIPANT_CREATED_PDU; + +struct _ENCOMSP_PARTICIPANT_REMOVED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT32 ParticipantId; + UINT32 DiscType; + UINT32 DiscCode; +}; +typedef struct _ENCOMSP_PARTICIPANT_REMOVED_PDU ENCOMSP_PARTICIPANT_REMOVED_PDU; + +struct _ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); + + UINT16 Flags; + UINT32 ParticipantId; +}; +typedef struct _ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU; + +struct _ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU; + +struct _ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU +{ + DEFINE_ENCOMSP_HEADER_COMMON(); +}; +typedef struct _ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU; + +#endif /* FREERDP_CHANNEL_ENCOMSP_H */ + diff --git a/server/X11/xf_update.h b/include/freerdp/channels/log.h similarity index 69% rename from server/X11/xf_update.h rename to include/freerdp/channels/log.h index 9e3c27342..51a653e70 100644 --- a/server/X11/xf_update.h +++ b/include/freerdp/channels/log.h @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Graphical Updates + * Channel log defines * - * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ * limitations under the License. */ -#ifndef __XF_UPDATE_H -#define __XF_UPDATE_H +#ifndef FREERDP_CHANNELS_LOG_H +#define FREERDP_CHANNELS_LOG_H -#include "xfreerdp.h" +#include +#include -void* xf_update_thread(void* param); - -#endif /* __XF_UPDATE_H */ +#define CHANNELS_TAG(tag) FREERDP_TAG("channels.") tag +#endif /* FREERDP_UTILS_DEBUG_H */ diff --git a/include/freerdp/channels/rdpdr.h b/include/freerdp/channels/rdpdr.h index 8cc455b89..e6e590380 100644 --- a/include/freerdp/channels/rdpdr.h +++ b/include/freerdp/channels/rdpdr.h @@ -212,12 +212,14 @@ enum RDPDR_PRINTER_ANNOUNCE_FLAG /* [MS-FSCC] FSCTL Structures */ +#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) #define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION 0x1400ec #define FSCTL_PIPE_PEEK 0x11400c #define FSCTL_PIPE_TRANSCEIVE 0x11c017 #define FSCTL_PIPE_WAIT 0x110018 #define FSCTL_QUERY_ON_DISK_VOLUME_INFO 0x9013c #define FSCTL_QUERY_SPARING_INFO 0x90138 +#endif #ifndef _WIN32 #define FSCTL_CREATE_OR_GET_OBJECT_ID 0x900c0 @@ -239,8 +241,10 @@ enum RDPDR_PRINTER_ANNOUNCE_FLAG #define FSCTL_WRITE_USN_CLOSE_RECORD 0x900ef #endif +#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) #define FSCTL_SET_DEFECT_MANAGEMENT 0x98134 #define FSCTL_SET_ZERO_ON_DEALLOCATION 0x90194 +#endif /* [MS-FSCC] FileFsAttributeInformation.FileSystemAttributes */ diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index e4070194b..24943ff5f 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -179,6 +179,7 @@ struct _RDPGFX_SURFACE_COMMAND UINT32 height; UINT32 length; BYTE* data; + void* extra; }; typedef struct _RDPGFX_SURFACE_COMMAND RDPGFX_SURFACE_COMMAND; @@ -332,5 +333,34 @@ struct _RDPGFX_MAP_SURFACE_TO_WINDOW_PDU }; typedef struct _RDPGFX_MAP_SURFACE_TO_WINDOW_PDU RDPGFX_MAP_SURFACE_TO_WINDOW_PDU; +/* H264 */ + +struct _RDPGFX_H264_QUANT_QUALITY +{ + BYTE qpVal; + BYTE qualityVal; + + BYTE qp; + BYTE r; + BYTE p; +}; +typedef struct _RDPGFX_H264_QUANT_QUALITY RDPGFX_H264_QUANT_QUALITY; + +struct _RDPGFX_H264_METABLOCK +{ + UINT32 numRegionRects; + RDPGFX_RECT16* regionRects; + RDPGFX_H264_QUANT_QUALITY* quantQualityVals; +}; +typedef struct _RDPGFX_H264_METABLOCK RDPGFX_H264_METABLOCK; + +struct _RDPGFX_H264_BITMAP_STREAM +{ + RDPGFX_H264_METABLOCK meta; + UINT32 length; + BYTE* data; +}; +typedef struct _RDPGFX_H264_BITMAP_STREAM RDPGFX_H264_BITMAP_STREAM; + #endif /* FREERDP_CHANNEL_RDPGFX_H */ diff --git a/include/freerdp/channels/remdesk.h b/include/freerdp/channels/remdesk.h new file mode 100644 index 000000000..22b6f6db4 --- /dev/null +++ b/include/freerdp/channels/remdesk.h @@ -0,0 +1,161 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 FREERDP_CHANNEL_REMDESK_H +#define FREERDP_CHANNEL_REMDESK_H + +#include +#include + +#define REMDESK_SVC_CHANNEL_NAME "remdesk" + +#define REMDESK_ERROR_NOERROR 0 +#define REMDESK_ERROR_NOINFO 1 +#define REMDESK_ERROR_LOCALNOTERROR 3 +#define REMDESK_ERROR_REMOTEBYUSER 4 +#define REMDESK_ERROR_BYSERVER 5 +#define REMDESK_ERROR_DNSLOOKUPFAILED 6 +#define REMDESK_ERROR_OUTOFMEMORY 7 +#define REMDESK_ERROR_CONNECTIONTIMEDOUT 8 +#define REMDESK_ERROR_SOCKETCONNECTFAILED 9 +#define REMDESK_ERROR_HOSTNOTFOUND 11 +#define REMDESK_ERROR_WINSOCKSENDFAILED 12 +#define REMDESK_ERROR_INVALIDIPADDR 14 +#define REMDESK_ERROR_SOCKETRECVFAILED 15 +#define REMDESK_ERROR_INVALIDENCRYPTION 18 +#define REMDESK_ERROR_GETHOSTBYNAMEFAILED 20 +#define REMDESK_ERROR_LICENSINGFAILED 21 +#define REMDESK_ERROR_ENCRYPTIONERROR 22 +#define REMDESK_ERROR_DECRYPTIONERROR 23 +#define REMDESK_ERROR_INVALIDPARAMETERSTRING 24 +#define REMDESK_ERROR_HELPSESSIONNOTFOUND 25 +#define REMDESK_ERROR_INVALIDPASSWORD 26 +#define REMDESK_ERROR_HELPSESSIONEXPIRED 27 +#define REMDESK_ERROR_CANTOPENRESOLVER 28 +#define REMDESK_ERROR_UNKNOWNSESSMGRERROR 29 +#define REMDESK_ERROR_CANTFORMLINKTOUSERSESSION 30 +#define REMDESK_ERROR_RCPROTOCOLERROR 32 +#define REMDESK_ERROR_RCUNKNOWNERROR 33 +#define REMDESK_ERROR_INTERNALERROR 34 +#define REMDESK_ERROR_HELPEERESPONSEPENDING 35 +#define REMDESK_ERROR_HELPEESAIDYES 36 +#define REMDESK_ERROR_HELPEEALREADYBEINGHELPED 37 +#define REMDESK_ERROR_HELPEECONSIDERINGHELP 38 +#define REMDESK_ERROR_HELPEENEVERRESPONDED 40 +#define REMDESK_ERROR_HELPEESAIDNO 41 +#define REMDESK_ERROR_HELPSESSIONACCESSDENIED 42 +#define REMDESK_ERROR_USERNOTFOUND 43 +#define REMDESK_ERROR_SESSMGRERRORNOTINIT 44 +#define REMDESK_ERROR_SELFHELPNOTSUPPORTED 45 +#define REMDESK_ERROR_INCOMPATIBLEVERSION 47 +#define REMDESK_ERROR_SESSIONNOTCONNECTED 48 +#define REMDESK_ERROR_SYSTEMSHUTDOWN 50 +#define REMDESK_ERROR_STOPLISTENBYUSER 51 +#define REMDESK_ERROR_WINSOCK_FAILED 52 +#define REMDESK_ERROR_MISMATCHPARMS 53 +#define REMDESK_ERROR_PASSWORDS_DONT_MATCH 61 +#define REMDESK_ERROR_SHADOWEND_BASE 300 +#define REMDESK_ERROR_SHADOWEND_CONFIGCHANGE 301 +#define REMDESK_ERROR_SHADOWEND_UNKNOWN 302 + +struct _REMDESK_CHANNEL_HEADER +{ + UINT32 DataLength; + char ChannelName[32]; +}; +typedef struct _REMDESK_CHANNEL_HEADER REMDESK_CHANNEL_HEADER; + +#define REMDESK_CHANNEL_CTL_NAME "RC_CTL" +#define REMDESK_CHANNEL_CTL_SIZE 22 + +struct _REMDESK_CTL_HEADER +{ + UINT32 DataLength; + char ChannelName[32]; + + UINT32 msgType; +}; +typedef struct _REMDESK_CTL_HEADER REMDESK_CTL_HEADER; + +#define REMDESK_CTL_REMOTE_CONTROL_DESKTOP 1 +#define REMDESK_CTL_RESULT 2 +#define REMDESK_CTL_AUTHENTICATE 3 +#define REMDESK_CTL_SERVER_ANNOUNCE 4 +#define REMDESK_CTL_DISCONNECT 5 +#define REMDESK_CTL_VERSIONINFO 6 +#define REMDESK_CTL_ISCONNECTED 7 +#define REMDESK_CTL_VERIFY_PASSWORD 8 +#define REMDESK_CTL_EXPERT_ON_VISTA 9 +#define REMDESK_CTL_RANOVICE_NAME 10 +#define REMDESK_CTL_RAEXPERT_NAME 11 +#define REMDESK_CTL_TOKEN 12 + +struct _REMDESK_CTL_RESULT_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + UINT32 result; +}; +typedef struct _REMDESK_CTL_RESULT_PDU REMDESK_CTL_RESULT_PDU; + +struct _REMDESK_CTL_VERSION_INFO_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + UINT32 versionMajor; + UINT32 versionMinor; +}; +typedef struct _REMDESK_CTL_VERSION_INFO_PDU REMDESK_CTL_VERSION_INFO_PDU; + +struct _REMDESK_CTL_AUTHENTICATE_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* raConnectionString; + char* expertBlob; +}; +typedef struct _REMDESK_CTL_AUTHENTICATE_PDU REMDESK_CTL_AUTHENTICATE_PDU; + +struct _REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* raConnectionString; +}; +typedef struct _REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU; + +struct _REMDESK_CTL_VERIFY_PASSWORD_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + char* expertBlob; +}; +typedef struct _REMDESK_CTL_VERIFY_PASSWORD_PDU REMDESK_CTL_VERIFY_PASSWORD_PDU; + +struct _REMDESK_CTL_EXPERT_ON_VISTA_PDU +{ + REMDESK_CTL_HEADER ctlHeader; + + BYTE* EncryptedPassword; + UINT32 EncryptedPasswordLength; +}; +typedef struct _REMDESK_CTL_EXPERT_ON_VISTA_PDU REMDESK_CTL_EXPERT_ON_VISTA_PDU; + +#endif /* FREERDP_CHANNEL_REMDESK_H */ + diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index df6dead5d..66ee9eb24 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -37,12 +37,8 @@ #include #include - #include -#define WTSVirtualEventHandle 3 /* Extended */ -#define WTSVirtualChannelReady 4 /* Extended */ - #ifdef __cplusplus extern "C" { #endif diff --git a/include/freerdp/client.h b/include/freerdp/client.h index 661f3bac4..d4241f6a1 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -86,10 +86,13 @@ FREERDP_API freerdp* freerdp_client_get_instance(rdpContext* context); FREERDP_API HANDLE freerdp_client_get_thread(rdpContext* context); FREERDP_API int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, char** argv); + FREERDP_API int freerdp_client_settings_parse_connection_file(rdpSettings* settings, const char* filename); FREERDP_API int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, const BYTE* buffer, size_t size); FREERDP_API int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename, BOOL unicode); +FREERDP_API int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/client/encomsp.h b/include/freerdp/client/encomsp.h new file mode 100644 index 000000000..e8b8466e1 --- /dev/null +++ b/include/freerdp/client/encomsp.h @@ -0,0 +1,61 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 FREERDP_CHANNEL_CLIENT_ENCOMSP_H +#define FREERDP_CHANNEL_CLIENT_ENCOMSP_H + +#include + +/** + * Client Interface + */ + +typedef struct _encomsp_client_context EncomspClientContext; + +typedef int (*pcEncomspFilterUpdated)(EncomspClientContext* context, ENCOMSP_FILTER_UPDATED_PDU* filterUpdated); +typedef int (*pcEncomspApplicationCreated)(EncomspClientContext* context, ENCOMSP_APPLICATION_CREATED_PDU* applicationCreated); +typedef int (*pcEncomspApplicationRemoved)(EncomspClientContext* context, ENCOMSP_APPLICATION_REMOVED_PDU* applicationRemoved); +typedef int (*pcEncomspWindowCreated)(EncomspClientContext* context, ENCOMSP_WINDOW_CREATED_PDU* windowCreated); +typedef int (*pcEncomspWindowRemoved)(EncomspClientContext* context, ENCOMSP_WINDOW_REMOVED_PDU* windowRemoved); +typedef int (*pcEncomspShowWindow)(EncomspClientContext* context, ENCOMSP_SHOW_WINDOW_PDU* showWindow); +typedef int (*pcEncomspParticipantCreated)(EncomspClientContext* context, ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated); +typedef int (*pcEncomspParticipantRemoved)(EncomspClientContext* context, ENCOMSP_PARTICIPANT_REMOVED_PDU* participantRemoved); +typedef int (*pcEncomspChangeParticipantControlLevel)(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* changeParticipantControlLevel); +typedef int (*pcEncomspGraphicsStreamPaused)(EncomspClientContext* context, ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU* graphicsStreamPaused); +typedef int (*pcEncomspGraphicsStreamResumed)(EncomspClientContext* context, ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU* graphicsStreamResumed); + +struct _encomsp_client_context +{ + void* handle; + void* custom; + + pcEncomspFilterUpdated FilterUpdated; + pcEncomspApplicationCreated ApplicationCreated; + pcEncomspApplicationRemoved ApplicationRemoved; + pcEncomspWindowCreated WindowCreated; + pcEncomspWindowRemoved WindowRemoved; + pcEncomspShowWindow ShowWindow; + pcEncomspParticipantCreated ParticipantCreated; + pcEncomspParticipantRemoved ParticipantRemoved; + pcEncomspChangeParticipantControlLevel ChangeParticipantControlLevel; + pcEncomspGraphicsStreamPaused GraphicsStreamPaused; + pcEncomspGraphicsStreamResumed GraphicsStreamResumed; +}; + +#endif /* FREERDP_CHANNEL_CLIENT_ENCOMSP_H */ diff --git a/include/freerdp/client/remdesk.h b/include/freerdp/client/remdesk.h new file mode 100644 index 000000000..600a421ce --- /dev/null +++ b/include/freerdp/client/remdesk.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 FREERDP_CHANNEL_CLIENT_REMDESK_H +#define FREERDP_CHANNEL_CLIENT_REMDESK_H + +#include + +/** + * Client Interface + */ + +typedef struct _remdesk_client_context RemdeskClientContext; + +struct _remdesk_client_context +{ + void* handle; + void* custom; +}; + +#endif /* FREERDP_CHANNEL_CLIENT_REMDESK_H */ + diff --git a/include/freerdp/codec/bitmap.h b/include/freerdp/codec/bitmap.h index d25c28b84..507829253 100644 --- a/include/freerdp/codec/bitmap.h +++ b/include/freerdp/codec/bitmap.h @@ -28,25 +28,15 @@ #include #include -FREERDP_API BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size, int srcBpp, int dstBpp); +#ifdef __cplusplus +extern "C" { +#endif FREERDP_API int freerdp_bitmap_compress(char* in_data, int width, int height, wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e); -#define PLANAR_FORMAT_HEADER_CS (1 << 3) -#define PLANAR_FORMAT_HEADER_RLE (1 << 4) -#define PLANAR_FORMAT_HEADER_NA (1 << 5) -#define PLANAR_FORMAT_HEADER_CLL_MASK 0x07 - -typedef struct _BITMAP_PLANAR_CONTEXT BITMAP_PLANAR_CONTEXT; - -FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, - int width, int height, int scanline, BYTE* dstData, int* dstSize); - -FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); -FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); - -FREERDP_API int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcSize, - BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); +#ifdef __cplusplus +} +#endif #endif /* FREERDP_CODEC_BITMAP_H */ diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index bb1550a25..cc946d578 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -20,31 +20,58 @@ #ifndef FREERDP_CODEC_CLEAR_H #define FREERDP_CODEC_CLEAR_H +typedef struct _CLEAR_CONTEXT CLEAR_CONTEXT; + #include #include +#include +#include + #define CLEARCODEC_FLAG_GLYPH_INDEX 0x01 #define CLEARCODEC_FLAG_GLYPH_HIT 0x02 -#define CLEARCODEC_FLAG_CACHE_RESET 0x03 +#define CLEARCODEC_FLAG_CACHE_RESET 0x04 + +struct _CLEAR_GLYPH_ENTRY +{ + UINT32 size; + UINT32 count; + UINT32* pixels; +}; +typedef struct _CLEAR_GLYPH_ENTRY CLEAR_GLYPH_ENTRY; + +struct _CLEAR_VBAR_ENTRY +{ + UINT32 size; + UINT32 count; + UINT32* pixels; +}; +typedef struct _CLEAR_VBAR_ENTRY CLEAR_VBAR_ENTRY; struct _CLEAR_CONTEXT { BOOL Compressor; + NSC_CONTEXT* nsc; + UINT32 seqNumber; + BYTE* TempBuffer; + UINT32 TempSize; + CLEAR_GLYPH_ENTRY GlyphCache[4000]; UINT32 VBarStorageCursor; - void* VBarStorage[32768]; + CLEAR_VBAR_ENTRY VBarStorage[32768]; UINT32 ShortVBarStorageCursor; - void* ShortVBarStorage[16384]; + CLEAR_VBAR_ENTRY ShortVBarStorage[16384]; }; -typedef struct _CLEAR_CONTEXT CLEAR_CONTEXT; #ifdef __cplusplus extern "C" { #endif FREERDP_API int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); -FREERDP_API int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); -FREERDP_API void clear_context_reset(CLEAR_CONTEXT* clear); +FREERDP_API int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); + +FREERDP_API int clear_context_reset(CLEAR_CONTEXT* clear); FREERDP_API CLEAR_CONTEXT* clear_context_new(BOOL Compressor); FREERDP_API void clear_context_free(CLEAR_CONTEXT* clear); diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h index 4fdaf8aa9..60590e579 100644 --- a/include/freerdp/codec/color.h +++ b/include/freerdp/codec/color.h @@ -26,8 +26,8 @@ #define FREERDP_PIXEL_FORMAT_TYPE_A 0 #define FREERDP_PIXEL_FORMAT_TYPE_ARGB 1 #define FREERDP_PIXEL_FORMAT_TYPE_ABGR 2 -#define FREERDP_PIXEL_FORMAT_TYPE_BGRA 3 -#define FREERDP_PIXEL_FORMAT_TYPE_RGBA 4 + +#define FREERDP_PIXEL_FORMAT_IS_ABGR(_format) (FREERDP_PIXEL_FORMAT_TYPE(_format) == FREERDP_PIXEL_FORMAT_TYPE_ABGR) #define FREERDP_PIXEL_FLIP_NONE 0 #define FREERDP_PIXEL_FLIP_VERTICAL 1 @@ -108,56 +108,101 @@ /* 24bpp formats */ -#define PIXEL_FORMAT_R8G8B8 FREERDP_PIXEL_FORMAT(0, 24, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 8, 8, 8) +#define PIXEL_FORMAT_R8G8B8_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 24, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 8, 8, 8) +#define PIXEL_FORMAT_R8G8B8 PIXEL_FORMAT_R8G8B8_F(0) #define PIXEL_FORMAT_RGB24 PIXEL_FORMAT_R8G8B8 +#define PIXEL_FORMAT_R8G8B8_VF PIXEL_FORMAT_R8G8B8_F(1) +#define PIXEL_FORMAT_RGB24_VF PIXEL_FORMAT_R8G8B8_VF -#define PIXEL_FORMAT_B8G8R8 FREERDP_PIXEL_FORMAT(0, 24, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 8, 8, 8) +#define PIXEL_FORMAT_B8G8R8_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 24, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 8, 8, 8) +#define PIXEL_FORMAT_B8G8R8 PIXEL_FORMAT_B8G8R8_F(0) #define PIXEL_FORMAT_BGR24 PIXEL_FORMAT_B8G8R8 +#define PIXEL_FORMAT_B8G8R8_VF PIXEL_FORMAT_B8G8R8_F(1) +#define PIXEL_FORMAT_BGR24_VF PIXEL_FORMAT_B8G8R8_VF /* 16bpp formats */ -#define PIXEL_FORMAT_R5G6B5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 5, 6, 5) +#define PIXEL_FORMAT_R5G6B5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 5, 6, 5) +#define PIXEL_FORMAT_R5G6B5 PIXEL_FORMAT_R5G6B5_F(0) #define PIXEL_FORMAT_RGB565 PIXEL_FORMAT_R5G6B5 #define PIXEL_FORMAT_RGB16 PIXEL_FORMAT_R5G6B5 +#define PIXEL_FORMAT_R5G6B5_VF PIXEL_FORMAT_R5G6B5_F(1) +#define PIXEL_FORMAT_RGB565_VF PIXEL_FORMAT_R5G6B5_VF +#define PIXEL_FORMAT_RGB16_VF PIXEL_FORMAT_R5G6B5_VF -#define PIXEL_FORMAT_B5G6R5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 5, 6, 5) +#define PIXEL_FORMAT_B5G6R5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 5, 6, 5) +#define PIXEL_FORMAT_B5G6R5 PIXEL_FORMAT_B5G6R5_F(0) #define PIXEL_FORMAT_BGR565 PIXEL_FORMAT_B5G6R5 #define PIXEL_FORMAT_BGR16 PIXEL_FORMAT_B5G6R5 +#define PIXEL_FORMAT_B5G6R5_VF PIXEL_FORMAT_B5G6R5_F(1) +#define PIXEL_FORMAT_BGR565_VF PIXEL_FORMAT_B5G6R5_VF +#define PIXEL_FORMAT_BGR16_VF PIXEL_FORMAT_B5G6R5_VF -#define PIXEL_FORMAT_A1R5G5B5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 1, 5, 5, 5) +#define PIXEL_FORMAT_A1R5G5B5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 1, 5, 5, 5) +#define PIXEL_FORMAT_A1R5G5B5 PIXEL_FORMAT_A1R5G5B5_F(0) #define PIXEL_FORMAT_ARGB555 PIXEL_FORMAT_A1R5G5B5 #define PIXEL_FORMAT_ARGB15 PIXEL_FORMAT_A1R5G5B5 +#define PIXEL_FORMAT_A1R5G5B5_VF PIXEL_FORMAT_A1R5G5B5_F(1) +#define PIXEL_FORMAT_ARGB555_VF PIXEL_FORMAT_A1R5G5B5_VF +#define PIXEL_FORMAT_ARGB15_VF PIXEL_FORMAT_A1R5G5B5_VF -#define PIXEL_FORMAT_X1R5G5B5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 5, 5, 5) +#define PIXEL_FORMAT_X1R5G5B5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 5, 5, 5) +#define PIXEL_FORMAT_X1R5G5B5 PIXEL_FORMAT_X1R5G5B5_F(0) #define PIXEL_FORMAT_XRGB555 PIXEL_FORMAT_X1R5G5B5 #define PIXEL_FORMAT_RGB555 PIXEL_FORMAT_X1R5G5B5 #define PIXEL_FORMAT_RGB15 PIXEL_FORMAT_X1R5G5B5 +#define PIXEL_FORMAT_X1R5G5B5_VF PIXEL_FORMAT_X1R5G5B5_F(1) +#define PIXEL_FORMAT_XRGB555_VF PIXEL_FORMAT_X1R5G5B5_VF +#define PIXEL_FORMAT_RGB555_VF PIXEL_FORMAT_X1R5G5B5_VF +#define PIXEL_FORMAT_RGB15_VF PIXEL_FORMAT_X1R5G5B5_VF -#define PIXEL_FORMAT_A1B5G5R5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 1, 5, 5, 5) +#define PIXEL_FORMAT_A1B5G5R5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 1, 5, 5, 5) +#define PIXEL_FORMAT_A1B5G5R5 PIXEL_FORMAT_A1B5G5R5_F(0) #define PIXEL_FORMAT_ABGR555 PIXEL_FORMAT_A1B5G5R5 #define PIXEL_FORMAT_ABGR15 PIXEL_FORMAT_A1B5G5R5 +#define PIXEL_FORMAT_A1B5G5R5_VF PIXEL_FORMAT_A1B5G5R5_F(1) +#define PIXEL_FORMAT_ABGR555_VF PIXEL_FORMAT_A1B5G5R5_VF +#define PIXEL_FORMAT_ABGR15_VF PIXEL_FORMAT_A1B5G5R5_VF -#define PIXEL_FORMAT_X1B5G5R5 FREERDP_PIXEL_FORMAT(0, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 5, 5, 5) +#define PIXEL_FORMAT_X1B5G5R5_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 16, FREERDP_PIXEL_FORMAT_TYPE_ABGR, 0, 5, 5, 5) +#define PIXEL_FORMAT_X1B5G5R5 PIXEL_FORMAT_X1B5G5R5_F(0) #define PIXEL_FORMAT_XBGR555 PIXEL_FORMAT_X1B5G5R5 #define PIXEL_FORMAT_BGR555 PIXEL_FORMAT_X1B5G5R5 #define PIXEL_FORMAT_BGR15 PIXEL_FORMAT_X1B5G5R5 +#define PIXEL_FORMAT_X1B5G5R5_VF PIXEL_FORMAT_X1B5G5R5_F(1) +#define PIXEL_FORMAT_XBGR555_VF PIXEL_FORMAT_X1B5G5R5_VF +#define PIXEL_FORMAT_BGR555_VF PIXEL_FORMAT_X1B5G5R5_VF +#define PIXEL_FORMAT_BGR15_VF PIXEL_FORMAT_X1B5G5R5_VF /* 8bpp formats */ -#define PIXEL_FORMAT_A8 FREERDP_PIXEL_FORMAT(0, 8, FREERDP_PIXEL_FORMAT_TYPE_A, 8, 0, 0, 0) +#define PIXEL_FORMAT_A8_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 8, FREERDP_PIXEL_FORMAT_TYPE_A, 8, 0, 0, 0) +#define PIXEL_FORMAT_A8 PIXEL_FORMAT_A8_F(0) #define PIXEL_FORMAT_8BPP PIXEL_FORMAT_A8 #define PIXEL_FORMAT_256 PIXEL_FORMAT_A8 +#define PIXEL_FORMAT_RGB8 PIXEL_FORMAT_A8 +#define PIXEL_FORMAT_A8_VF PIXEL_FORMAT_A8_F(1) +#define PIXEL_FORMAT_8BPP_VF PIXEL_FORMAT_A8_VF +#define PIXEL_FORMAT_256_VF PIXEL_FORMAT_A8_VF +#define PIXEL_FORMAT_RGB8_VF PIXEL_FORMAT_A8_VF /* 4 bpp formats */ -#define PIXEL_FORMAT_A4 FREERDP_PIXEL_FORMAT(0, 4, FREERDP_PIXEL_FORMAT_TYPE_A, 4, 0, 0, 0) +#define PIXEL_FORMAT_A4_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 4, FREERDP_PIXEL_FORMAT_TYPE_A, 4, 0, 0, 0) +#define PIXEL_FORMAT_A4 PIXEL_FORMAT_A4_F(0) #define PIXEL_FORMAT_4BPP PIXEL_FORMAT_A4 +#define PIXEL_FORMAT_A4_VF PIXEL_FORMAT_A4_F(1) +#define PIXEL_FORMAT_4BPP_VF PIXEL_FORMAT_A4_VF /* 1bpp formats */ -#define PIXEL_FORMAT_A1 FREERDP_PIXEL_FORMAT(0, 1, FREERDP_PIXEL_FORMAT_TYPE_A, 1, 0, 0, 0) +#define PIXEL_FORMAT_A1_F(_flip) FREERDP_PIXEL_FORMAT(_flip, 1, FREERDP_PIXEL_FORMAT_TYPE_A, 1, 0, 0, 0) +#define PIXEL_FORMAT_A1 PIXEL_FORMAT_A1_F(0) #define PIXEL_FORMAT_1BPP PIXEL_FORMAT_A1 #define PIXEL_FORMAT_MONO PIXEL_FORMAT_A1 +#define PIXEL_FORMAT_A1_VF PIXEL_FORMAT_A1_F(1) +#define PIXEL_FORMAT_1BPP_VF PIXEL_FORMAT_A1_VF +#define PIXEL_FORMAT_MONO_VF PIXEL_FORMAT_A1_VF #ifdef __cplusplus extern "C" { @@ -356,7 +401,6 @@ extern "C" { /* Supported Internal Buffer Formats */ #define CLRBUF_16BPP 8 -#define CLRBUF_24BPP 16 #define CLRBUF_32BPP 32 struct _CLRCONV @@ -373,6 +417,14 @@ typedef CLRCONV* HCLRCONV; typedef BYTE* (*p_freerdp_image_convert)(BYTE* srcData, BYTE* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv); +static INLINE UINT32 RGB32_to_BGR32(UINT32 pixel) +{ + UINT32 temp; + + temp = (pixel ^ (pixel >> 16)) & ((1 << 8) - 1); + return (pixel ^ (temp | (temp << 16))); +} + FREERDP_API int freerdp_get_pixel(BYTE* data, int x, int y, int width, int height, int bpp); FREERDP_API void freerdp_set_pixel(BYTE* data, int x, int y, int width, int height, int bpp, int pixel); @@ -392,14 +444,31 @@ FREERDP_API UINT32 freerdp_color_convert_rgb_bgr(UINT32 srcColor, int srcBpp, in FREERDP_API UINT32 freerdp_color_convert_bgr_rgb(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv); FREERDP_API UINT32 freerdp_color_convert_var_rgb(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv); FREERDP_API UINT32 freerdp_color_convert_var_bgr(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv); +FREERDP_API UINT32 freerdp_convert_gdi_order_color(UINT32 color, int bpp, UINT32 format, BYTE* palette); FREERDP_API HCLRCONV freerdp_clrconv_new(UINT32 flags); FREERDP_API void freerdp_clrconv_free(HCLRCONV clrconv); -FREERDP_API int freerdp_image_copy(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, - int nWidth, int nHeight, BYTE* pSrcData, DWORD dwSrcFormat, int nSrcStep, int nXSrc, int nYSrc); -FREERDP_API int freerdp_image_fill(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, +FREERDP_API int freerdp_image8_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); +FREERDP_API int freerdp_image15_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); +FREERDP_API int freerdp_image16_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); +FREERDP_API int freerdp_image24_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); +FREERDP_API int freerdp_image32_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); + +FREERDP_API int freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette); +FREERDP_API int freerdp_image_move(BYTE* pData, DWORD Format, int nStep, int nXDst, int nYDst, + int nWidth, int nHeight, int nXSrc, int nYSrc); +FREERDP_API int freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, UINT32 color); + +FREERDP_API int freerdp_image_copy_from_retina(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc); #ifdef __cplusplus } diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h new file mode 100644 index 000000000..8e835a9e7 --- /dev/null +++ b/include/freerdp/codec/h264.h @@ -0,0 +1,76 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2014 Mike McDonald + * + * 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 FREERDP_CODEC_H264_H +#define FREERDP_CODEC_H264_H + +#include +#include +#include + +typedef struct _H264_CONTEXT H264_CONTEXT; + +typedef BOOL (*pfnH264SubsystemInit)(H264_CONTEXT* h264); +typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264); + +typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize); + +struct _H264_CONTEXT_SUBSYSTEM +{ + const char* name; + pfnH264SubsystemInit Init; + pfnH264SubsystemUninit Uninit; + pfnH264SubsystemDecompress Decompress; +}; +typedef struct _H264_CONTEXT_SUBSYSTEM H264_CONTEXT_SUBSYSTEM; + +struct _H264_CONTEXT +{ + BOOL Compressor; + + UINT32 width; + UINT32 height; + + int iStride[3]; + BYTE* pYUVData[3]; + + void* pSystemData; + H264_CONTEXT_SUBSYSTEM* subsystem; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); + +FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstHeight, RDPGFX_RECT16* regionRects, int numRegionRect); + +FREERDP_API int h264_context_reset(H264_CONTEXT* h264); + +FREERDP_API H264_CONTEXT* h264_context_new(BOOL Compressor); +FREERDP_API void h264_context_free(H264_CONTEXT* h264); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CODEC_H264_H */ + diff --git a/include/freerdp/codec/interleaved.h b/include/freerdp/codec/interleaved.h new file mode 100644 index 000000000..d96cfbde9 --- /dev/null +++ b/include/freerdp/codec/interleaved.h @@ -0,0 +1,53 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Interleaved RLE Bitmap Codec + * + * 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 FREERDP_CODEC_INTERLEAVED_H +#define FREERDP_CODEC_INTERLEAVED_H + +typedef struct _BITMAP_INTERLEAVED_CONTEXT BITMAP_INTERLEAVED_CONTEXT; + +#include +#include + +#include +#include + +struct _BITMAP_INTERLEAVED_CONTEXT +{ + BOOL Compressor; + + UINT32 TempSize; + BYTE* TempBuffer; + + wStream* bts; +}; + +FREERDP_API int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcData, UINT32 SrcSize, int bpp, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BYTE* palette); + +FREERDP_API int interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette, int bpp); + +FREERDP_API int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved); + +FREERDP_API BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor); +FREERDP_API void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved); + +#endif /* FREERDP_CODEC_INTERLEAVED_H */ + diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index a5832352e..2ba5623af 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -31,17 +31,6 @@ extern "C" { #endif -/* NSCODEC_BITMAP_STREAM */ -struct _NSC_STREAM -{ - UINT32 PlaneByteCount[4]; - BYTE ColorLossLevel; - BYTE ChromaSubSamplingLevel; - UINT16 Reserved; - BYTE* Planes; -}; -typedef struct _NSC_STREAM NSC_STREAM; - struct _NSC_MESSAGE { int x; @@ -54,7 +43,13 @@ struct _NSC_MESSAGE UINT32 MaxPlaneSize; BYTE* PlaneBuffers[5]; UINT32 OrgByteCount[4]; - UINT32 PlaneByteCount[4]; + + UINT32 LumaPlaneByteCount; + UINT32 OrangeChromaPlaneByteCount; + UINT32 GreenChromaPlaneByteCount; + UINT32 AlphaPlaneByteCount; + UINT32 ColorLossLevel; + UINT32 ChromaSubsamplingLevel; }; typedef struct _NSC_MESSAGE NSC_MESSAGE; @@ -64,15 +59,20 @@ typedef struct _NSC_CONTEXT NSC_CONTEXT; struct _NSC_CONTEXT { - UINT32 OrgByteCount[4]; /* original byte length of luma, chroma orange, chroma green, alpha variable in order */ - NSC_STREAM nsc_stream; + UINT32 OrgByteCount[4]; UINT16 bpp; UINT16 width; UINT16 height; - BYTE* BitmapData; /* final argb values in little endian order */ - UINT32 BitmapDataLength; /* the maximum length of the buffer that bmpdata points to */ + BYTE* BitmapData; + UINT32 BitmapDataLength; RDP_PIXEL_FORMAT pixel_format; + BYTE* Planes; + UINT32 PlaneByteCount[4]; + UINT32 ColorLossLevel; + UINT32 ChromaSubsamplingLevel; + BOOL DynamicColorFidelity; + /* color palette allocated by the application */ const BYTE* palette; @@ -82,19 +82,22 @@ struct _NSC_CONTEXT NSC_CONTEXT_PRIV* priv; }; -FREERDP_API NSC_CONTEXT* nsc_context_new(void); FREERDP_API void nsc_context_set_pixel_format(NSC_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); -FREERDP_API void nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, +FREERDP_API int nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 height, BYTE* data, UINT32 length); FREERDP_API void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* bmpdata, int width, int height, int rowstride); -FREERDP_API void nsc_context_free(NSC_CONTEXT* context); FREERDP_API NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, int width, int height, int scanline, int* numMessages, int maxDataSize); FREERDP_API int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message); FREERDP_API int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message); +FREERDP_API int nsc_context_reset(NSC_CONTEXT* context); + +FREERDP_API NSC_CONTEXT* nsc_context_new(void); +FREERDP_API void nsc_context_free(NSC_CONTEXT* context); + #ifdef __cplusplus } #endif diff --git a/libfreerdp/codec/planar.h b/include/freerdp/codec/planar.h similarity index 70% rename from libfreerdp/codec/planar.h rename to include/freerdp/codec/planar.h index a8e34c87a..4f2861a07 100644 --- a/libfreerdp/codec/planar.h +++ b/include/freerdp/codec/planar.h @@ -17,14 +17,21 @@ * limitations under the License. */ -#ifndef FREERDP_CODEC_PLANAR_PRIVATE_H -#define FREERDP_CODEC_PLANAR_PRIVATE_H +#ifndef FREERDP_CODEC_PLANAR_H +#define FREERDP_CODEC_PLANAR_H #include +typedef struct _BITMAP_PLANAR_CONTEXT BITMAP_PLANAR_CONTEXT; + #include #include +#define PLANAR_FORMAT_HEADER_CS (1 << 3) +#define PLANAR_FORMAT_HEADER_RLE (1 << 4) +#define PLANAR_FORMAT_HEADER_NA (1 << 5) +#define PLANAR_FORMAT_HEADER_CLL_MASK 0x07 + #define PLANAR_CONTROL_BYTE(_nRunLength, _cRawBytes) \ (_nRunLength & 0x0F) | ((_cRawBytes & 0x0F) << 4) @@ -85,6 +92,9 @@ struct _BITMAP_PLANAR_CONTEXT BYTE* rlePlanes[4]; BYTE* rlePlanesBuffer; + + UINT32 TempSize; + BYTE* TempBuffer; }; FREERDP_API int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]); @@ -92,4 +102,16 @@ FREERDP_API BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int widt FREERDP_API BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane); FREERDP_API int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]); -#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */ +FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, + int width, int height, int scanline, BYTE* dstData, int* pDstSize); + +FREERDP_API int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context); + +FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); +FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); + +FREERDP_API int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BOOL vFlip); + +#endif /* FREERDP_CODEC_PLANAR_H */ + diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h new file mode 100644 index 000000000..455126c4c --- /dev/null +++ b/include/freerdp/codec/progressive.h @@ -0,0 +1,331 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Progressive Codec Bitmap Compression + * + * 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 FREERDP_CODEC_PROGRESSIVE_H +#define FREERDP_CODEC_PROGRESSIVE_H + +typedef struct _PROGRESSIVE_CONTEXT PROGRESSIVE_CONTEXT; + +#include +#include + +#include +#include + +#include +#include + +#define RFX_SUBBAND_DIFFING 0x01 + +#define RFX_TILE_DIFFERENCE 0x01 + +#define RFX_DWT_REDUCE_EXTRAPOLATE 0x01 + +#define PROGRESSIVE_WBT_SYNC 0xCCC0 +#define PROGRESSIVE_WBT_FRAME_BEGIN 0xCCC1 +#define PROGRESSIVE_WBT_FRAME_END 0xCCC2 +#define PROGRESSIVE_WBT_CONTEXT 0xCCC3 +#define PROGRESSIVE_WBT_REGION 0xCCC4 +#define PROGRESSIVE_WBT_TILE_SIMPLE 0xCCC5 +#define PROGRESSIVE_WBT_TILE_FIRST 0xCCC6 +#define PROGRESSIVE_WBT_TILE_UPGRADE 0xCCC7 + +#define PROGRESSIVE_BLOCKS_ALL 0x0001 +#define PROGRESSIVE_BLOCKS_REGION 0x0002 +#define PROGRESSIVE_BLOCKS_TILE 0x0004 + +struct _RFX_COMPONENT_CODEC_QUANT +{ + BYTE LL3; + BYTE HL3; + BYTE LH3; + BYTE HH3; + BYTE HL2; + BYTE LH2; + BYTE HH2; + BYTE HL1; + BYTE LH1; + BYTE HH1; +}; +typedef struct _RFX_COMPONENT_CODEC_QUANT RFX_COMPONENT_CODEC_QUANT; + +struct _RFX_PROGRESSIVE_CODEC_QUANT +{ + BYTE quality; + RFX_COMPONENT_CODEC_QUANT yQuantValues; + RFX_COMPONENT_CODEC_QUANT cbQuantValues; + RFX_COMPONENT_CODEC_QUANT crQuantValues; +}; +typedef struct _RFX_PROGRESSIVE_CODEC_QUANT RFX_PROGRESSIVE_CODEC_QUANT; + +struct _PROGRESSIVE_BLOCK +{ + UINT16 blockType; + UINT32 blockLen; +}; +typedef struct _PROGRESSIVE_BLOCK PROGRESSIVE_BLOCK; + +struct _PROGRESSIVE_BLOCK_SYNC +{ + UINT16 blockType; + UINT32 blockLen; + + UINT32 magic; + UINT16 version; +}; +typedef struct _PROGRESSIVE_BLOCK_SYNC PROGRESSIVE_BLOCK_SYNC; + +struct _PROGRESSIVE_BLOCK_CONTEXT +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE ctxId; + UINT16 tileSize; + BYTE flags; +}; +typedef struct _PROGRESSIVE_BLOCK_CONTEXT PROGRESSIVE_BLOCK_CONTEXT; + +struct _PROGRESSIVE_BLOCK_TILE_SIMPLE +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + BYTE flags; + UINT16 yLen; + UINT16 cbLen; + UINT16 crLen; + UINT16 tailLen; + BYTE* yData; + BYTE* cbData; + BYTE* crData; + BYTE* tailData; +}; +typedef struct _PROGRESSIVE_BLOCK_TILE_SIMPLE PROGRESSIVE_BLOCK_TILE_SIMPLE; + +struct _PROGRESSIVE_BLOCK_TILE_FIRST +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + BYTE flags; + BYTE quality; + UINT16 yLen; + UINT16 cbLen; + UINT16 crLen; + UINT16 tailLen; + BYTE* yData; + BYTE* cbData; + BYTE* crData; + BYTE* tailData; +}; +typedef struct _PROGRESSIVE_BLOCK_TILE_FIRST PROGRESSIVE_BLOCK_TILE_FIRST; + +struct _PROGRESSIVE_BLOCK_TILE_UPGRADE +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + BYTE quality; + UINT16 ySrlLen; + UINT16 yRawLen; + UINT16 cbSrlLen; + UINT16 cbRawLen; + UINT16 crSrlLen; + UINT16 crRawLen; + BYTE* ySrlData; + BYTE* yRawData; + BYTE* cbSrlData; + BYTE* cbRawData; + BYTE* crSrlData; + BYTE* crRawData; +}; +typedef struct _PROGRESSIVE_BLOCK_TILE_UPGRADE PROGRESSIVE_BLOCK_TILE_UPGRADE; + +struct _RFX_PROGRESSIVE_TILE +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + + BYTE flags; + BYTE quality; + + UINT16 yLen; + UINT16 cbLen; + UINT16 crLen; + UINT16 tailLen; + BYTE* yData; + BYTE* cbData; + BYTE* crData; + BYTE* tailData; + + UINT16 ySrlLen; + UINT16 yRawLen; + UINT16 cbSrlLen; + UINT16 cbRawLen; + UINT16 crSrlLen; + UINT16 crRawLen; + BYTE* ySrlData; + BYTE* yRawData; + BYTE* cbSrlData; + BYTE* cbRawData; + BYTE* crSrlData; + BYTE* crRawData; + + int x; + int y; + int width; + int height; + BYTE* data; + BYTE* current; + + int pass; + BYTE* sign; + RFX_COMPONENT_CODEC_QUANT yBitPos; + RFX_COMPONENT_CODEC_QUANT cbBitPos; + RFX_COMPONENT_CODEC_QUANT crBitPos; + RFX_COMPONENT_CODEC_QUANT yQuant; + RFX_COMPONENT_CODEC_QUANT cbQuant; + RFX_COMPONENT_CODEC_QUANT crQuant; + RFX_COMPONENT_CODEC_QUANT yProgQuant; + RFX_COMPONENT_CODEC_QUANT cbProgQuant; + RFX_COMPONENT_CODEC_QUANT crProgQuant; +}; +typedef struct _RFX_PROGRESSIVE_TILE RFX_PROGRESSIVE_TILE; + +struct _PROGRESSIVE_BLOCK_REGION +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE tileSize; + UINT16 numRects; + BYTE numQuant; + BYTE numProgQuant; + BYTE flags; + UINT16 numTiles; + UINT32 tileDataSize; + RFX_RECT* rects; + RFX_COMPONENT_CODEC_QUANT* quantVals; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals; + RFX_PROGRESSIVE_TILE** tiles; +}; +typedef struct _PROGRESSIVE_BLOCK_REGION PROGRESSIVE_BLOCK_REGION; + +struct _PROGRESSIVE_BLOCK_FRAME_BEGIN +{ + UINT16 blockType; + UINT32 blockLen; + + UINT32 frameIndex; + UINT16 regionCount; + PROGRESSIVE_BLOCK_REGION* regions; +}; +typedef struct _PROGRESSIVE_BLOCK_FRAME_BEGIN PROGRESSIVE_BLOCK_FRAME_BEGIN; + +struct _PROGRESSIVE_BLOCK_FRAME_END +{ + UINT16 blockType; + UINT32 blockLen; +}; +typedef struct _PROGRESSIVE_BLOCK_FRAME_END PROGRESSIVE_BLOCK_FRAME_END; + +struct _PROGRESSIVE_SURFACE_CONTEXT +{ + UINT16 id; + UINT32 width; + UINT32 height; + UINT32 gridWidth; + UINT32 gridHeight; + UINT32 gridSize; + RFX_PROGRESSIVE_TILE* tiles; +}; +typedef struct _PROGRESSIVE_SURFACE_CONTEXT PROGRESSIVE_SURFACE_CONTEXT; + +struct _PROGRESSIVE_CONTEXT +{ + BOOL Compressor; + + BOOL invert; + + wLog* log; + wBufferPool* bufferPool; + + UINT32 cRects; + RFX_RECT* rects; + + UINT32 cTiles; + RFX_PROGRESSIVE_TILE** tiles; + + UINT32 cQuant; + RFX_COMPONENT_CODEC_QUANT* quantVals; + + UINT32 cProgQuant; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals; + + PROGRESSIVE_BLOCK_REGION region; + RFX_PROGRESSIVE_CODEC_QUANT quantProgValFull; + + wHashTable* SurfaceContexts; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API int progressive_compress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); + +FREERDP_API int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, UINT16 surfaceId); + +FREERDP_API int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, UINT32 width, UINT32 height); +FREERDP_API int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId); + +FREERDP_API int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive); + +FREERDP_API PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor); +FREERDP_API void progressive_context_free(PROGRESSIVE_CONTEXT* progressive); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CODEC_PROGRESSIVE_H */ + diff --git a/include/freerdp/codec/region.h b/include/freerdp/codec/region.h index a4526a47f..bced79140 100644 --- a/include/freerdp/codec/region.h +++ b/include/freerdp/codec/region.h @@ -27,6 +27,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct _REGION16_DATA; typedef struct _REGION16_DATA REGION16_DATA; @@ -39,6 +43,13 @@ struct _REGION16 { }; typedef struct _REGION16 REGION16; +/** computes if two rectangles are equal + * @param r1 first rectangle + * @param r2 second rectangle + * @return if the two rectangles are equal + */ +FREERDP_API BOOL rectangles_equal(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2); + /** computes if two rectangles intersect * @param r1 first rectangle * @param r2 second rectangle @@ -73,6 +84,12 @@ FREERDP_API const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRe /** @return the extents rectangle of this region */ FREERDP_API const RECTANGLE_16 *region16_extents(const REGION16 *region); +/** returns if the rectangle is empty + * @param rect + * @return if the rectangle is empty + */ +FREERDP_API BOOL rectangle_is_empty(const RECTANGLE_16 *rect); + /** returns if the region is empty * @param region * @return if the region is empty @@ -124,5 +141,8 @@ FREERDP_API BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, con */ FREERDP_API void region16_uninit(REGION16 *region); +#ifdef __cplusplus +} +#endif #endif /* __REGION_H___ */ diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index 60ada8b79..3ad5dec6d 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -20,6 +20,11 @@ #ifndef FREERDP_CODEC_REMOTEFX_H #define FREERDP_CODEC_REMOTEFX_H +typedef struct _RFX_RECT RFX_RECT; +typedef struct _RFX_TILE RFX_TILE; +typedef struct _RFX_MESSAGE RFX_MESSAGE; +typedef struct _RFX_CONTEXT RFX_CONTEXT; + #include #include #include @@ -45,7 +50,6 @@ struct _RFX_RECT UINT16 width; UINT16 height; }; -typedef struct _RFX_RECT RFX_RECT; struct _RFX_TILE { @@ -69,7 +73,6 @@ struct _RFX_TILE BYTE* CrData; BYTE* YCbCrData; }; -typedef struct _RFX_TILE RFX_TILE; struct _RFX_MESSAGE { @@ -99,7 +102,6 @@ struct _RFX_MESSAGE BOOL freeArray; }; -typedef struct _RFX_MESSAGE RFX_MESSAGE; typedef struct _RFX_CONTEXT_PRIV RFX_CONTEXT_PRIV; @@ -146,18 +148,14 @@ struct _RFX_CONTEXT void (*quantization_encode)(INT16* buffer, const UINT32* quantization_values); void (*dwt_2d_decode)(INT16* buffer, INT16* dwt_buffer); void (*dwt_2d_encode)(INT16* buffer, INT16* dwt_buffer); - int (*rlgr_decode)(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size); - int (*rlgr_encode)(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size); /* private definitions */ RFX_CONTEXT_PRIV* priv; }; -typedef struct _RFX_CONTEXT RFX_CONTEXT; -FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); -FREERDP_API void rfx_context_free(RFX_CONTEXT* context); FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); -FREERDP_API void rfx_context_reset(RFX_CONTEXT* context); + +FREERDP_API int rfx_rlgr_decode(const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize, int mode); FREERDP_API RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length); FREERDP_API UINT16 rfx_message_get_tile_count(RFX_MESSAGE* message); @@ -176,6 +174,11 @@ FREERDP_API RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_REC BYTE* data, int width, int height, int scanline, int* numMessages, int maxDataSize); FREERDP_API void rfx_write_message(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message); +FREERDP_API int rfx_context_reset(RFX_CONTEXT* context); + +FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); +FREERDP_API void rfx_context_free(RFX_CONTEXT* context); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/codec/xcrush.h b/include/freerdp/codec/xcrush.h index fe7ed226c..1feb96d57 100644 --- a/include/freerdp/codec/xcrush.h +++ b/include/freerdp/codec/xcrush.h @@ -25,7 +25,7 @@ #include -#pragma pack(push,1) +#pragma pack(push, 1) struct _XCRUSH_MATCH_INFO { diff --git a/include/freerdp/codecs.h b/include/freerdp/codecs.h new file mode 100644 index 000000000..2f1e4d4ab --- /dev/null +++ b/include/freerdp/codecs.h @@ -0,0 +1,65 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDP Codecs + * + * 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 FREERDP_CODECS_H +#define FREERDP_CODECS_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define FREERDP_CODEC_INTERLEAVED 0x00000001 +#define FREERDP_CODEC_PLANAR 0x00000002 +#define FREERDP_CODEC_NSCODEC 0x00000004 +#define FREERDP_CODEC_REMOTEFX 0x00000008 +#define FREERDP_CODEC_CLEARCODEC 0x00000010 +#define FREERDP_CODEC_ALPHACODEC 0x00000020 +#define FREERDP_CODEC_PROGRESSIVE 0x00000040 +#define FREERDP_CODEC_H264 0x00000080 +#define FREERDP_CODEC_ALL 0xFFFFFFFF + +struct rdp_codecs +{ + rdpContext* context; + + RFX_CONTEXT* rfx; + NSC_CONTEXT* nsc; + H264_CONTEXT* h264; + CLEAR_CONTEXT* clear; + PROGRESSIVE_CONTEXT* progressive; + BITMAP_PLANAR_CONTEXT* planar; + BITMAP_INTERLEAVED_CONTEXT* interleaved; +}; + +FREERDP_API int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags); +FREERDP_API int freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags); + +FREERDP_API rdpCodecs* codecs_new(rdpContext* context); +FREERDP_API void codecs_free(rdpCodecs* codecs); + +#endif /* FREERDP_CODECS_H */ + diff --git a/include/freerdp/dvc.h b/include/freerdp/dvc.h index ce5977541..673ab50a8 100644 --- a/include/freerdp/dvc.h +++ b/include/freerdp/dvc.h @@ -152,7 +152,8 @@ struct _IDRDYNVC_ENTRY_POINTS const char *name, IWTSPlugin *pPlugin); IWTSPlugin *(*GetPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints, const char *name); - ADDIN_ARGV *(*GetPluginData)(IDRDYNVC_ENTRY_POINTS *pEntryPoints); + ADDIN_ARGV* (*GetPluginData)(IDRDYNVC_ENTRY_POINTS* pEntryPoints); + void* (*GetRdpSettings)(IDRDYNVC_ENTRY_POINTS* pEntryPoints); }; typedef int (*PDVC_PLUGIN_ENTRY)(IDRDYNVC_ENTRY_POINTS *); diff --git a/include/freerdp/error.h b/include/freerdp/error.h old mode 100755 new mode 100644 diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index b306fd0a6..7023e9d2e 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -27,6 +27,7 @@ typedef struct rdp_cache rdpCache; typedef struct rdp_channels rdpChannels; typedef struct rdp_graphics rdpGraphics; typedef struct rdp_metrics rdpMetrics; +typedef struct rdp_codecs rdpCodecs; typedef struct rdp_freerdp freerdp; typedef struct rdp_context rdpContext; @@ -40,6 +41,7 @@ typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS; #include #include #include +#include #include #include #include @@ -120,7 +122,8 @@ struct rdp_context ALIGN64 rdpUpdate* update; /* 39 */ ALIGN64 rdpSettings* settings; /* 40 */ ALIGN64 rdpMetrics* metrics; /* 41 */ - UINT64 paddingC[64 - 42]; /* 42 */ + ALIGN64 rdpCodecs* codecs; /* 42 */ + UINT64 paddingC[64 - 43]; /* 43 */ UINT64 paddingD[96 - 64]; /* 64 */ UINT64 paddingE[128 - 96]; /* 96 */ @@ -251,6 +254,7 @@ FREERDP_API freerdp* freerdp_new(void); FREERDP_API void freerdp_free(freerdp* instance); FREERDP_API BOOL freerdp_focus_required(freerdp* instance); +FREERDP_API void freerdp_set_focus(freerdp* instance); FREERDP_API UINT32 freerdp_get_last_error(rdpContext* context); FREERDP_API void freerdp_set_last_error(rdpContext* context, UINT32 lastError); diff --git a/include/freerdp/gdi/gdi.h b/include/freerdp/gdi/gdi.h index 9352278bd..b1450cdfa 100644 --- a/include/freerdp/gdi/gdi.h +++ b/include/freerdp/gdi/gdi.h @@ -21,10 +21,13 @@ #define FREERDP_GDI_H #include +#include #include #include -#include #include +#include + +#include /* For more information, see [MS-RDPEGDI] */ @@ -279,17 +282,27 @@ struct rdp_gdi int cursor_x; int cursor_y; int bytesPerPixel; + rdpCodecs* codecs; + BOOL invert; HGDI_DC hdc; + UINT32 format; HCLRCONV clrconv; gdiBitmap* primary; gdiBitmap* drawing; + UINT32 bitmap_size; + BYTE* bitmap_buffer; BYTE* primary_buffer; GDI_COLOR textColor; - void* rfx_context; - void* nsc_context; + BYTE palette[256 * 4]; gdiBitmap* tile; gdiBitmap* image; + + BOOL inGfxFrame; + BOOL graphicsReset; + UINT16 outputSurfaceId; + REGION16 invalidRegion; + RdpgfxClientContext* gfx; }; #ifdef __cplusplus @@ -297,9 +310,9 @@ extern "C" { #endif FREERDP_API UINT32 gdi_rop3_code(BYTE code); +FREERDP_API UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel, BOOL vFlip); FREERDP_API BYTE* gdi_get_bitmap_pointer(HGDI_DC hdcBmp, int x, int y); FREERDP_API BYTE* gdi_get_brush_pointer(HGDI_DC hdcBrush, int x, int y); -FREERDP_API int gdi_is_mono_pixel_set(BYTE* data, int x, int y, int width); FREERDP_API void gdi_resize(rdpGdi* gdi, int width, int height); FREERDP_API int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer); @@ -309,10 +322,11 @@ FREERDP_API void gdi_free(freerdp* instance); } #endif +#define GDI_TAG FREERDP_TAG("gdi") #ifdef WITH_DEBUG_GDI -#define DEBUG_GDI(fmt, ...) DEBUG_CLASS(GDI, fmt, ## __VA_ARGS__) +#define DEBUG_GDI(fmt, ...) WLog_DBG(GDI_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_GDI(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_GDI(fmt, ...) #endif #endif /* FREERDP_GDI_H */ diff --git a/include/freerdp/gdi/gfx.h b/include/freerdp/gdi/gfx.h new file mode 100644 index 000000000..1ae7129c0 --- /dev/null +++ b/include/freerdp/gdi/gfx.h @@ -0,0 +1,62 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * GDI Graphics Pipeline + * + * 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 FREERDP_GDI_GFX_H +#define FREERDP_GDI_GFX_H + +#include +#include + +struct gdi_gfx_surface +{ + UINT16 surfaceId; + UINT32 width; + UINT32 height; + BOOL alpha; + BYTE* data; + int scanline; + UINT32 format; +}; +typedef struct gdi_gfx_surface gdiGfxSurface; + +struct gdi_gfx_cache_entry +{ + UINT64 cacheKey; + UINT32 width; + UINT32 height; + BOOL alpha; + BYTE* data; + int scanline; + UINT32 format; +}; +typedef struct gdi_gfx_cache_entry gdiGfxCacheEntry; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API void gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx); +FREERDP_API void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_GDI_GFX_H */ + diff --git a/include/freerdp/input.h b/include/freerdp/input.h index 87324f0ab..0ee3ee188 100644 --- a/include/freerdp/input.h +++ b/include/freerdp/input.h @@ -64,6 +64,7 @@ typedef struct rdp_input_proxy rdpInputProxy; typedef void (*pSynchronizeEvent)(rdpInput* input, UINT32 flags); typedef void (*pKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); +typedef void (*pKeyboardPauseEvent)(rdpInput* input); typedef void (*pUnicodeKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); typedef void (*pMouseEvent)(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); typedef void (*pExtendedMouseEvent)(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); @@ -81,8 +82,9 @@ struct rdp_input pMouseEvent MouseEvent; /* 19 */ pExtendedMouseEvent ExtendedMouseEvent; /* 20 */ pFocusInEvent FocusInEvent; /*21 */ + pKeyboardPauseEvent KeyboardPauseEvent; /* 22 */ - UINT32 paddingB[32 - 22]; /* 22 */ + UINT32 paddingB[32 - 23]; /* 23 */ /* Internal */ @@ -98,6 +100,7 @@ extern "C" { FREERDP_API void freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags); FREERDP_API void freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); FREERDP_API void freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, UINT32 rdp_scancode); +FREERDP_API void freerdp_input_send_keyboard_pause_event(rdpInput* input); FREERDP_API void freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); FREERDP_API void freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); FREERDP_API void freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); diff --git a/include/freerdp/locale/keyboard.h b/include/freerdp/locale/keyboard.h index 147067d8e..6868601ef 100644 --- a/include/freerdp/locale/keyboard.h +++ b/include/freerdp/locale/keyboard.h @@ -116,9 +116,10 @@ typedef struct _RDP_KEYBOARD_LAYOUT RDP_KEYBOARD_LAYOUT; #define KBD_SWEDISH_WITH_SAMI 0x0000083B #define KBD_UZBEK_CYRILLIC 0x00000843 #define KBD_INUKTITUT_LATIN 0x0000085D +#define KBD_CANADIAN_ENGLISH 0x00001009 #define KBD_CANADIAN_FRENCH_LEGACY 0x00000C0C #define KBD_SERBIAN_CYRILLIC 0x00000C1A -#define KBD_CANADIAN_FRENCH 0x00001009 +#define KBD_CANADIAN_FRENCH 0x00000C0C #define KBD_SWISS_FRENCH 0x0000100C #define KBD_BOSNIAN 0x0000141A #define KBD_IRISH 0x00001809 diff --git a/server/X11/xf_monitors.h b/include/freerdp/log.h similarity index 65% rename from server/X11/xf_monitors.h rename to include/freerdp/log.h index 8487c3327..2343889ab 100644 --- a/server/X11/xf_monitors.h +++ b/include/freerdp/log.h @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Monitors + * FreeRDP log defines * - * Copyright 2013 Marc-Andre Moreau + * Copyright 2014 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,13 @@ * limitations under the License. */ -#ifndef XFREERDP_SERVER_MONITORS_H -#define XFREERDP_SERVER_MONITORS_H +#ifndef FREERDP_LOG_H +#define FREERDP_LOG_H -#include "xfreerdp.h" +#include -int xf_list_monitors(xfInfo* xfi); - -#endif /* XFREERDP_SERVER_MONITORS_H */ +#define FREERDP_TAG(tag) "com.freerdp." tag +#define SERVER_TAG(tag) FREERDP_TAG("server.") tag +#define CLIENT_TAG(tag) FREERDP_TAG("client.") tag +#endif /* FREERDP_UTILS_DEBUG_H */ diff --git a/include/freerdp/message.h b/include/freerdp/message.h index fa20de09a..603a70af7 100644 --- a/include/freerdp/message.h +++ b/include/freerdp/message.h @@ -54,6 +54,7 @@ #define Update_SurfaceBits 12 #define Update_SurfaceFrameMarker 13 #define Update_SurfaceFrameAcknowledge 14 +#define Update_SetKeyboardIndicators 15 #define FREERDP_UPDATE_BEGIN_PAINT MakeMessageId(Update, BeginPaint) #define FREERDP_UPDATE_ END_PAINT MakeMessageId(Update, EndPaint) @@ -69,6 +70,7 @@ #define FREERDP_UPDATE_SURFACE_BITS MakeMessageId(Update, SurfaceBits) #define FREERDP_UPDATE_SURFACE_FRAME_MARKER MakeMessageId(Update, SurfaceFrameMarker) #define FREERDP_UPDATE_SURFACE_FRAME_ACKNOWLEDGE MakeMessageId(Update, SurfaceFrameAcknowledge) +#define FREERDP_UPDATE_SET_KEYBOARD_INDICATORS MakeMessageId(Update, SetKeyboardIndicators) /* Primary Update */ diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 4fbe75bfc..62d817c36 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -48,9 +48,17 @@ typedef BOOL (*psPeerLogon)(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* ident typedef int (*psPeerSendChannelData)(freerdp_peer* client, UINT16 channelId, BYTE* data, int size); typedef int (*psPeerReceiveChannelData)(freerdp_peer* client, UINT16 channelId, BYTE* data, int size, int flags, int totalSize); +typedef HANDLE (*psPeerVirtualChannelOpen)(freerdp_peer* client, const char* name, UINT32 flags); +typedef BOOL (*psPeerVirtualChannelClose)(freerdp_peer* client, HANDLE hChannel); +typedef int (*psPeerVirtualChannelRead)(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length); +typedef int (*psPeerVirtualChannelWrite)(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length); +typedef void* (*psPeerVirtualChannelGetData)(freerdp_peer* client, HANDLE hChannel); +typedef int (*psPeerVirtualChannelSetData)(freerdp_peer* client, HANDLE hChannel, void* data); + struct rdp_freerdp_peer { rdpContext* context; + int sockfd; char hostname[50]; @@ -58,6 +66,7 @@ struct rdp_freerdp_peer rdpUpdate* update; rdpSettings* settings; + void* ContextExtra; size_t ContextSize; psPeerContextNew ContextNew; psPeerContextFree ContextFree; @@ -78,6 +87,13 @@ struct rdp_freerdp_peer psPeerSendChannelData SendChannelData; psPeerReceiveChannelData ReceiveChannelData; + psPeerVirtualChannelOpen VirtualChannelOpen; + psPeerVirtualChannelClose VirtualChannelClose; + psPeerVirtualChannelRead VirtualChannelRead; + psPeerVirtualChannelWrite VirtualChannelWrite; + psPeerVirtualChannelGetData VirtualChannelGetData; + psPeerVirtualChannelSetData VirtualChannelSetData; + int pId; UINT32 ack_frame_id; BOOL local; diff --git a/include/freerdp/primitives.h b/include/freerdp/primitives.h index 24bac4748..bc75da3f3 100644 --- a/include/freerdp/primitives.h +++ b/include/freerdp/primitives.h @@ -136,6 +136,14 @@ typedef pstatus_t (*__sign_16s_t)( const INT16 *pSrc, INT16 *pDst, INT32 len); +typedef pstatus_t (*__yCbCrToRGB_16s8u_P3AC4R_t)( + const INT16* pSrc[3], INT32 srcStep, + BYTE* pDst, INT32 dstStep, + const prim_size_t* roi); +typedef pstatus_t (*__yCbCrToBGR_16s8u_P3AC4R_t)( + const INT16* pSrc[3], INT32 srcStep, + BYTE* pDst, INT32 dstStep, + const prim_size_t* roi); typedef pstatus_t (*__yCbCrToRGB_16s16s_P3P3_t)( const INT16 *pSrc[3], INT32 srcStep, INT16 *pDst[3], INT32 dstStep, @@ -148,6 +156,22 @@ typedef pstatus_t (*__RGBToRGB_16s8u_P3AC4R_t)( const INT16 *pSrc[3], INT32 srcStep, BYTE *pDst, INT32 dstStep, const prim_size_t *roi); +typedef pstatus_t (*__YCoCgToRGB_8u_AC4R_t)( + const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, + UINT32 width, UINT32 height, + UINT8 shift, + BOOL withAlpha, + BOOL invert); +typedef pstatus_t (*__RGB565ToARGB_16u32u_C3C4_t)( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert); +typedef pstatus_t (*__YUV420ToRGB_8u_P3AC4R_t)( + const BYTE* pSrc[3], INT32 srcStep[3], + BYTE* pDst, INT32 dstStep, + const prim_size_t* roi); typedef pstatus_t (*__andC_32u_t)( const UINT32 *pSrc, UINT32 val, @@ -187,9 +211,14 @@ typedef struct /* Sign */ __sign_16s_t sign_16s; /* Color conversions */ + __yCbCrToRGB_16s8u_P3AC4R_t yCbCrToRGB_16s8u_P3AC4R; + __yCbCrToBGR_16s8u_P3AC4R_t yCbCrToBGR_16s8u_P3AC4R; __yCbCrToRGB_16s16s_P3P3_t yCbCrToRGB_16s16s_P3P3; __RGBToYCbCr_16s16s_P3P3_t RGBToYCbCr_16s16s_P3P3; __RGBToRGB_16s8u_P3AC4R_t RGBToRGB_16s8u_P3AC4R; + __YCoCgToRGB_8u_AC4R_t YCoCgToRGB_8u_AC4R; + __RGB565ToARGB_16u32u_C3C4_t RGB565ToARGB_16u32u_C3C4; + __YUV420ToRGB_8u_P3AC4R_t YUV420ToRGB_8u_P3AC4R; } primitives_t; #ifdef __cplusplus diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index d0520c244..ca9521e06 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -21,6 +21,8 @@ #ifndef FREERDP_RAIL_GLOBAL_H #define FREERDP_RAIL_GLOBAL_H +#include + #include /* RAIL PDU flags */ @@ -93,14 +95,6 @@ enum SPI_MASK /* Client Notify Event PDU */ #ifndef _WIN32 -#define WM_LBUTTONDOWN 0x00000201 -#define WM_LBUTTONUP 0x00000202 -#define WM_RBUTTONDOWN 0x00000204 -#define WM_RBUTTONUP 0x00000205 -#define WM_CONTEXTMENU 0x0000007B -#define WM_LBUTTONDBLCLK 0x00000203 -#define WM_RBUTTONDBLCLK 0x00000206 - #define NIN_SELECT 0x00000400 #define NIN_KEYSELECT 0x00000401 #define NIN_BALLOONSHOW 0x00000402 diff --git a/include/freerdp/server/echo.h b/include/freerdp/server/echo.h new file mode 100644 index 000000000..e2a4c4260 --- /dev/null +++ b/include/freerdp/server/echo.h @@ -0,0 +1,85 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2014 Vic Lee + * + * 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 FREERDP_CHANNEL_ECHO_SERVER_H +#define FREERDP_CHANNEL_ECHO_SERVER_H + +#include + +typedef enum ECHO_SERVER_OPEN_RESULT +{ + ECHO_SERVER_OPEN_RESULT_OK = 0, + ECHO_SERVER_OPEN_RESULT_CLOSED = 1, + ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED = 2, + ECHO_SERVER_OPEN_RESULT_ERROR = 3 +} ECHO_SERVER_OPEN_RESULT; + +typedef struct _echo_server_context echo_server_context; + +typedef void (*psEchoServerOpen)(echo_server_context* context); +typedef void (*psEchoServerClose)(echo_server_context* context); +typedef BOOL (*psEchoServerRequest)(echo_server_context* context, const BYTE* buffer, UINT32 length); + +typedef void (*psEchoServerOpenResult)(echo_server_context* context, ECHO_SERVER_OPEN_RESULT result); +typedef void (*psEchoServerResponse)(echo_server_context* context, const BYTE* buffer, UINT32 length); + +struct _echo_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* data; + + /*** APIs called by the server. ***/ + /** + * Open the echo channel. + */ + psEchoServerOpen Open; + /** + * Close the echo channel. + */ + psEchoServerClose Close; + /** + * Send echo request PDU. + */ + psEchoServerRequest Request; + + /*** Callbacks registered by the server. ***/ + /** + * Indicate whether the channel is opened successfully. + */ + psEchoServerOpenResult OpenResult; + /** + * Receive echo response PDU. + */ + psEchoServerResponse Response; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API echo_server_context* echo_server_context_new(HANDLE vcm); +FREERDP_API void echo_server_context_free(echo_server_context* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_ECHO_SERVER_H */ diff --git a/include/freerdp/server/encomsp.h b/include/freerdp/server/encomsp.h new file mode 100644 index 000000000..dd1f9eba9 --- /dev/null +++ b/include/freerdp/server/encomsp.h @@ -0,0 +1,77 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Multiparty Virtual Channel + * + * 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 FREERDP_CHANNEL_SERVER_ENCOMSP_H +#define FREERDP_CHANNEL_SERVER_ENCOMSP_H + +#include +#include +#include + +#include + +/** + * Server Interface + */ + +typedef struct _encomsp_server_context EncomspServerContext; +typedef struct _encomsp_server_private EncomspServerPrivate; + +typedef int (*psEncomspStart)(EncomspServerContext* context); +typedef int (*psEncomspStop)(EncomspServerContext* context); + +typedef int (*psEncomspFilterUpdated)(EncomspServerContext* context, ENCOMSP_FILTER_UPDATED_PDU* filterUpdated); +typedef int (*psEncomspApplicationCreated)(EncomspServerContext* context, ENCOMSP_APPLICATION_CREATED_PDU* applicationCreated); +typedef int (*psEncomspApplicationRemoved)(EncomspServerContext* context, ENCOMSP_APPLICATION_REMOVED_PDU* applicationRemoved); +typedef int (*psEncomspWindowCreated)(EncomspServerContext* context, ENCOMSP_WINDOW_CREATED_PDU* windowCreated); +typedef int (*psEncomspWindowRemoved)(EncomspServerContext* context, ENCOMSP_WINDOW_REMOVED_PDU* windowRemoved); +typedef int (*psEncomspShowWindow)(EncomspServerContext* context, ENCOMSP_SHOW_WINDOW_PDU* showWindow); +typedef int (*psEncomspParticipantCreated)(EncomspServerContext* context, ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated); +typedef int (*psEncomspParticipantRemoved)(EncomspServerContext* context, ENCOMSP_PARTICIPANT_REMOVED_PDU* participantRemoved); +typedef int (*psEncomspChangeParticipantControlLevel)(EncomspServerContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* changeParticipantControlLevel); +typedef int (*psEncomspGraphicsStreamPaused)(EncomspServerContext* context, ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU* graphicsStreamPaused); +typedef int (*psEncomspGraphicsStreamResumed)(EncomspServerContext* context, ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU* graphicsStreamResumed); + +struct _encomsp_server_context +{ + HANDLE vcm; + void* custom; + + psEncomspStart Start; + psEncomspStop Stop; + + psEncomspFilterUpdated FilterUpdated; + psEncomspApplicationCreated ApplicationCreated; + psEncomspApplicationRemoved ApplicationRemoved; + psEncomspWindowCreated WindowCreated; + psEncomspWindowRemoved WindowRemoved; + psEncomspShowWindow ShowWindow; + psEncomspParticipantCreated ParticipantCreated; + psEncomspParticipantRemoved ParticipantRemoved; + psEncomspChangeParticipantControlLevel ChangeParticipantControlLevel; + psEncomspGraphicsStreamPaused GraphicsStreamPaused; + psEncomspGraphicsStreamResumed GraphicsStreamResumed; + + EncomspServerPrivate* priv; +}; + +FREERDP_API EncomspServerContext* encomsp_server_context_new(HANDLE vcm); +FREERDP_API void encomsp_server_context_free(EncomspServerContext* context); + +#endif /* FREERDP_CHANNEL_SERVER_ENCOMSP_H */ diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index 96da14d5c..6aff9087f 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -30,13 +30,14 @@ typedef struct _rdpsnd_server_private RdpsndServerPrivate; typedef int (*psRdpsndStart)(RdpsndServerContext* context); typedef int (*psRdpsndStop)(RdpsndServerContext* context); -typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context); +typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); typedef BOOL (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index); typedef BOOL (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp); typedef BOOL (*psRdpsndServerConfirmBlock)(RdpsndServerContext* context, BYTE confirmBlockNum, UINT16 wtimestamp); typedef BOOL (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); typedef BOOL (*psRdpsndServerClose)(RdpsndServerContext* context); + typedef void (*psRdpsndServerActivated)(RdpsndServerContext* context); struct _rdpsnd_server_context @@ -104,6 +105,11 @@ struct _rdpsnd_server_context * synchronization. */ psRdpsndServerActivated Activated; + + /** + * MS-RDPEA channel version the client announces + */ + UINT16 clientVersion; }; #ifdef __cplusplus @@ -111,7 +117,12 @@ extern "C" { #endif FREERDP_API RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm); +FREERDP_API void rdpsnd_server_context_reset(RdpsndServerContext *); FREERDP_API void rdpsnd_server_context_free(RdpsndServerContext* context); +FREERDP_API HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context); +FREERDP_API int rdpsnd_server_handle_messages(RdpsndServerContext *context); +FREERDP_API BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s); + #ifdef __cplusplus } diff --git a/include/freerdp/server/remdesk.h b/include/freerdp/server/remdesk.h new file mode 100644 index 000000000..b2c3f118c --- /dev/null +++ b/include/freerdp/server/remdesk.h @@ -0,0 +1,54 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance Virtual Channel + * + * 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 FREERDP_CHANNEL_SERVER_REMDESK_H +#define FREERDP_CHANNEL_SERVER_REMDESK_H + +#include +#include +#include + +#include + +/** + * Server Interface + */ + +typedef struct _remdesk_server_context RemdeskServerContext; +typedef struct _remdesk_server_private RemdeskServerPrivate; + +typedef int (*psRemdeskStart)(RemdeskServerContext* context); +typedef int (*psRemdeskStop)(RemdeskServerContext* context); + +struct _remdesk_server_context +{ + HANDLE vcm; + void* custom; + + psRemdeskStart Start; + psRemdeskStop Stop; + + RemdeskServerPrivate* priv; +}; + +FREERDP_API RemdeskServerContext* remdesk_server_context_new(HANDLE vcm); +FREERDP_API void remdesk_server_context_free(RemdeskServerContext* context); + +#endif /* FREERDP_CHANNEL_SERVER_REMDESK_H */ + diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h new file mode 100644 index 000000000..a3ff1b4b0 --- /dev/null +++ b/include/freerdp/server/shadow.h @@ -0,0 +1,187 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Session Shadowing + * + * 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 FREERDP_SERVER_SHADOW_H +#define FREERDP_SERVER_SHADOW_H + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +typedef struct rdp_shadow_client rdpShadowClient; +typedef struct rdp_shadow_server rdpShadowServer; +typedef struct rdp_shadow_screen rdpShadowScreen; +typedef struct rdp_shadow_surface rdpShadowSurface; +typedef struct rdp_shadow_encoder rdpShadowEncoder; +typedef struct rdp_shadow_capture rdpShadowCapture; +typedef struct rdp_shadow_subsystem rdpShadowSubsystem; + +typedef struct _RDP_SHADOW_ENTRY_POINTS RDP_SHADOW_ENTRY_POINTS; +typedef int (*pfnShadowSubsystemEntry)(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); + +typedef rdpShadowSubsystem* (*pfnShadowSubsystemNew)(void); +typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem); + +typedef int (*pfnShadowSubsystemInit)(rdpShadowSubsystem* subsystem); +typedef int (*pfnShadowSubsystemUninit)(rdpShadowSubsystem* subsystem); + +typedef int (*pfnShadowSubsystemStart)(rdpShadowSubsystem* subsystem); +typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem); + +typedef int (*pfnShadowEnumMonitors)(MONITOR_DEF* monitors, int maxMonitors); + +typedef int (*pfnShadowAuthenticate)(rdpShadowSubsystem* subsystem, + const char* user, const char* domain, const char* password); + +typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags); +typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); +typedef int (*pfnShadowUnicodeKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); +typedef int (*pfnShadowMouseEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y); +typedef int (*pfnShadowExtendedMouseEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y); + +struct rdp_shadow_client +{ + rdpContext context; + + HANDLE thread; + BOOL activated; + BOOL inLobby; + BOOL mayView; + BOOL mayInteract; + HANDLE StopEvent; + CRITICAL_SECTION lock; + REGION16 invalidRegion; + rdpShadowServer* server; + rdpShadowSurface* lobby; + rdpShadowEncoder* encoder; + rdpShadowSubsystem* subsystem; + + HANDLE vcm; + EncomspServerContext* encomsp; + RemdeskServerContext* remdesk; +}; + +struct rdp_shadow_server +{ + void* ext; + HANDLE thread; + HANDLE StopEvent; + wArrayList* clients; + rdpShadowScreen* screen; + rdpShadowSurface* surface; + rdpShadowCapture* capture; + rdpShadowSubsystem* subsystem; + + DWORD port; + BOOL mayView; + BOOL mayInteract; + BOOL shareSubRect; + BOOL authentication; + int selectedMonitor; + RECTANGLE_16 subRect; + char* ipcSocket; + char* ConfigPath; + char* CertificateFile; + char* PrivateKeyFile; + CRITICAL_SECTION lock; + freerdp_listener* listener; +}; + +struct _RDP_SHADOW_ENTRY_POINTS +{ + pfnShadowSubsystemNew New; + pfnShadowSubsystemFree Free; + + pfnShadowSubsystemInit Init; + pfnShadowSubsystemUninit Uninit; + + pfnShadowSubsystemStart Start; + pfnShadowSubsystemStop Stop; + + pfnShadowEnumMonitors EnumMonitors; +}; + +#define RDP_SHADOW_SUBSYSTEM_COMMON() \ + RDP_SHADOW_ENTRY_POINTS ep; \ + HANDLE event; \ + int numMonitors; \ + int captureFrameRate; \ + int selectedMonitor; \ + MONITOR_DEF monitors[16]; \ + MONITOR_DEF virtualScreen; \ + HANDLE updateEvent; \ + BOOL suppressOutput; \ + REGION16 invalidRegion; \ + wMessagePipe* MsgPipe; \ + SYNCHRONIZATION_BARRIER barrier; \ + \ + pfnShadowSynchronizeEvent SynchronizeEvent; \ + pfnShadowKeyboardEvent KeyboardEvent; \ + pfnShadowUnicodeKeyboardEvent UnicodeKeyboardEvent; \ + pfnShadowMouseEvent MouseEvent; \ + pfnShadowExtendedMouseEvent ExtendedMouseEvent; \ + \ + pfnShadowAuthenticate Authenticate; \ + \ + rdpShadowServer* server + +struct rdp_shadow_subsystem +{ + RDP_SHADOW_SUBSYSTEM_COMMON(); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** argv); +FREERDP_API int shadow_server_command_line_status_print(rdpShadowServer* server, int argc, char** argv, int status); + +FREERDP_API int shadow_server_start(rdpShadowServer* server); +FREERDP_API int shadow_server_stop(rdpShadowServer* server); + +FREERDP_API int shadow_server_init(rdpShadowServer* server); +FREERDP_API int shadow_server_uninit(rdpShadowServer* server); + +FREERDP_API int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, const char* name); + +FREERDP_API rdpShadowServer* shadow_server_new(); +FREERDP_API void shadow_server_free(rdpShadowServer* server); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SERVER_SHADOW_H */ + diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index cb9e25cb7..a53c14d32 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -222,6 +222,11 @@ #define LB_CLIENT_TSV_URL 0x00001000 #define LB_SERVER_TSV_CAPABLE 0x00002000 +/* Keyboard Hook */ +#define KEYBOARD_HOOK_LOCAL 0 +#define KEYBOARD_HOOK_REMOTE 1 +#define KEYBOARD_HOOK_FULLSCREEN_ONLY 2 + struct _TARGET_NET_ADDRESS { UINT32 Length; @@ -466,6 +471,8 @@ struct _RDPDR_SERIAL UINT32 Type; char* Name; char* Path; + char* Driver; + char* Permissive; }; typedef struct _RDPDR_SERIAL RDPDR_SERIAL; @@ -530,6 +537,8 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_ServerRandomLength 197 #define FreeRDP_ServerCertificate 198 #define FreeRDP_ServerCertificateLength 199 +#define FreeRDP_ClientRandom 200 +#define FreeRDP_ClientRandomLength 201 #define FreeRDP_ChannelCount 256 #define FreeRDP_ChannelDefArraySize 257 #define FreeRDP_ChannelDefArray 258 @@ -585,6 +594,11 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_DisableCursorShadow 966 #define FreeRDP_DisableCursorBlinking 967 #define FreeRDP_AllowDesktopComposition 968 +#define FreeRDP_RemoteAssistanceMode 1024 +#define FreeRDP_RemoteAssistanceSessionId 1025 +#define FreeRDP_RemoteAssistancePassStub 1026 +#define FreeRDP_RemoteAssistancePassword 1027 +#define FreeRDP_RemoteAssistanceRCTicket 1028 #define FreeRDP_TlsSecurity 1088 #define FreeRDP_NlaSecurity 1089 #define FreeRDP_RdpSecurity 1090 @@ -654,6 +668,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_CredentialsFromStdin 1604 #define FreeRDP_ComputerName 1664 #define FreeRDP_ConnectionFile 1728 +#define FreeRDP_AssistanceFile 1729 #define FreeRDP_HomePath 1792 #define FreeRDP_ConfigPath 1793 #define FreeRDP_CurrentPath 1794 @@ -719,6 +734,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_FastPathInput 2630 #define FreeRDP_MultiTouchInput 2631 #define FreeRDP_MultiTouchGestures 2632 +#define FreeRDP_KeyboardHook 2633 #define FreeRDP_BrushSupportLevel 2688 #define FreeRDP_GlyphSupportLevel 2752 #define FreeRDP_GlyphCache 2753 @@ -744,9 +760,17 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_NSCodec 3712 #define FreeRDP_NSCodecId 3713 #define FreeRDP_FrameAcknowledge 3714 +#define FreeRDP_NSCodecColorLossLevel 3715 +#define FreeRDP_NSCodecAllowSubsampling 3716 +#define FreeRDP_NSCodecAllowDynamicColorFidelity 3717 #define FreeRDP_JpegCodec 3776 #define FreeRDP_JpegCodecId 3777 #define FreeRDP_JpegQuality 3778 +#define FreeRDP_GfxThinClient 3840 +#define FreeRDP_GfxSmallCache 3841 +#define FreeRDP_GfxProgressive 3842 +#define FreeRDP_GfxProgressiveV2 3843 +#define FreeRDP_GfxH264 3844 #define FreeRDP_BitmapCacheV3CodecId 3904 #define FreeRDP_DrawNineGridEnabled 3968 #define FreeRDP_DrawNineGridCacheSize 3969 @@ -771,6 +795,10 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_DynamicChannelCount 5056 #define FreeRDP_DynamicChannelArraySize 5057 #define FreeRDP_DynamicChannelArray 5058 +#define FreeRDP_SupportDynamicChannels 5059 +#define FreeRDP_SupportEchoChannel 5184 +#define FreeRDP_SupportDisplayControl 5185 +#define FreeRDP_SupportGeometryTracking 5186 /** * FreeRDP Settings Data Structure @@ -833,11 +861,12 @@ struct rdp_settings ALIGN64 UINT32 ExtEncryptionMethods; /* 194 */ ALIGN64 UINT32 EncryptionLevel; /* 195 */ ALIGN64 BYTE* ServerRandom; /* 196 */ - ALIGN64 DWORD ServerRandomLength; /* 197 */ + ALIGN64 UINT32 ServerRandomLength; /* 197 */ ALIGN64 BYTE* ServerCertificate; /* 198 */ - ALIGN64 DWORD ServerCertificateLength; /* 199 */ + ALIGN64 UINT32 ServerCertificateLength; /* 199 */ ALIGN64 BYTE* ClientRandom; /* 200 */ - UINT64 padding0256[256 - 201]; /* 201 */ + ALIGN64 UINT32 ClientRandomLength; /* 201 */ + UINT64 padding0256[256 - 202]; /* 202 */ /* Client Network Data */ ALIGN64 UINT32 ChannelCount; /* 256 */ @@ -935,7 +964,14 @@ struct rdp_settings ALIGN64 BOOL DisableCursorBlinking; /* 967 */ ALIGN64 BOOL AllowDesktopComposition; /* 968 */ UINT64 padding1024[1024 - 969]; /* 969 */ - UINT64 padding1088[1088 - 1024]; /* 1024 */ + + /* Remote Assistance */ + ALIGN64 BOOL RemoteAssistanceMode; /* 1024 */ + ALIGN64 char* RemoteAssistanceSessionId; /* 1025 */ + ALIGN64 char* RemoteAssistancePassStub; /* 1026 */ + ALIGN64 char* RemoteAssistancePassword; /* 1027 */ + ALIGN64 char* RemoteAssistanceRCTicket; /* 1028 */ + UINT64 padding1088[1088 - 1029]; /* 1029 */ /** * X.224 Connection Request/Confirm @@ -955,7 +991,8 @@ struct rdp_settings ALIGN64 char* AuthenticationServiceClass; /* 1098 */ ALIGN64 BOOL DisableCredentialsDelegation; /* 1099 */ ALIGN64 BOOL AuthenticationLevel; /* 1100 */ - UINT64 padding1152[1152 - 1101]; /* 1101 */ + ALIGN64 char* PermittedTLSCiphers; /* 1101 */ + UINT64 padding1152[1152 - 1102]; /* 1102 */ /* Connection Cookie */ ALIGN64 BOOL MstscCookieMode; /* 1152 */ @@ -988,7 +1025,7 @@ struct rdp_settings /* Credentials Cache */ ALIGN64 BYTE* Password51; /* 1280 */ - ALIGN64 DWORD Password51Length; /* 1281 */ + ALIGN64 UINT32 Password51Length; /* 1281 */ UINT64 padding1344[1344 - 1282]; /* 1282 */ /* Kerberos Authentication */ @@ -1047,7 +1084,8 @@ struct rdp_settings /* Files */ ALIGN64 char* ConnectionFile; /* 1728 */ - UINT64 padding1792[1792 - 1729]; /* 1729 */ + ALIGN64 char* AssistanceFile; /* 1729 */ + UINT64 padding1792[1792 - 1730]; /* 1730 */ /* Paths */ ALIGN64 char* HomePath; /* 1792 */ @@ -1093,8 +1131,8 @@ struct rdp_settings ALIGN64 char* RemoteApplicationFile; /* 2116 */ ALIGN64 char* RemoteApplicationGuid; /* 2117 */ ALIGN64 char* RemoteApplicationCmdLine; /* 2118 */ - ALIGN64 DWORD RemoteApplicationExpandCmdLine; /* 2119 */ - ALIGN64 DWORD RemoteApplicationExpandWorkingDir; /* 2120 */ + ALIGN64 UINT32 RemoteApplicationExpandCmdLine; /* 2119 */ + ALIGN64 UINT32 RemoteApplicationExpandWorkingDir; /* 2120 */ ALIGN64 BOOL DisableRemoteAppCapsCheck; /* 2121 */ ALIGN64 UINT32 RemoteAppNumIconCaches; /* 2122 */ ALIGN64 UINT32 RemoteAppNumIconCacheEntries; /* 2123 */ @@ -1160,7 +1198,8 @@ struct rdp_settings ALIGN64 BOOL FastPathInput; /* 2630 */ ALIGN64 BOOL MultiTouchInput; /* 2631 */ ALIGN64 BOOL MultiTouchGestures; /* 2632 */ - UINT64 padding2688[2688 - 2633]; /* 2633 */ + ALIGN64 UINT32 KeyboardHook; /* 2633 */ + UINT64 padding2688[2688 - 2634]; /* 2634 */ /* Brush Capabilities */ ALIGN64 UINT32 BrushSupportLevel; /* 2688 */ @@ -1240,14 +1279,23 @@ struct rdp_settings ALIGN64 BOOL NSCodec; /* 3712 */ ALIGN64 UINT32 NSCodecId; /* 3713 */ ALIGN64 UINT32 FrameAcknowledge; /* 3714 */ - UINT64 padding3776[3776 - 3715]; /* 3715 */ + ALIGN64 UINT32 NSCodecColorLossLevel; /* 3715 */ + ALIGN64 BOOL NSCodecAllowSubsampling; /* 3716 */ + ALIGN64 BOOL NSCodecAllowDynamicColorFidelity; /* 3717 */ + UINT64 padding3776[3776 - 3718]; /* 3718 */ /* JPEG */ ALIGN64 BOOL JpegCodec; /* 3776 */ ALIGN64 UINT32 JpegCodecId; /* 3777 */ ALIGN64 UINT32 JpegQuality; /* 3778 */ UINT64 padding3840[3840 - 3779]; /* 3779 */ - UINT64 padding3904[3904 - 3840]; /* 3840 */ + + ALIGN64 BOOL GfxThinClient; /* 3840 */ + ALIGN64 BOOL GfxSmallCache; /* 3841 */ + ALIGN64 BOOL GfxProgressive; /* 3842 */ + ALIGN64 BOOL GfxProgressiveV2; /* 3843 */ + ALIGN64 BOOL GfxH264; /* 3844 */ + UINT64 padding3904[3904 - 3845]; /* 3845 */ /** * Caches @@ -1322,7 +1370,13 @@ struct rdp_settings ALIGN64 UINT32 DynamicChannelCount; /* 5056 */ ALIGN64 UINT32 DynamicChannelArraySize; /* 5057 */ ALIGN64 ADDIN_ARGV** DynamicChannelArray; /* 5058 */ - UINT64 padding5184[5184 - 5059]; /* 5059 */ + ALIGN64 BOOL SupportDynamicChannels; /* 5059 */ + UINT64 padding5184[5184 - 5060]; /* 5060 */ + + ALIGN64 BOOL SupportEchoChannel; /* 5184 */ + ALIGN64 BOOL SupportDisplayControl; /* 5185 */ + ALIGN64 BOOL SupportGeometryTracking; /* 5186 */ + UINT64 padding5312[5312 - 5187]; /* 5187 */ /** * WARNING: End of ABI stable zone! diff --git a/include/freerdp/types.h b/include/freerdp/types.h index 3d26e0bf9..a2ccb9c01 100644 --- a/include/freerdp/types.h +++ b/include/freerdp/types.h @@ -32,6 +32,21 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif +struct _PALETTE_ENTRY +{ + BYTE red; + BYTE green; + BYTE blue; +}; +typedef struct _PALETTE_ENTRY PALETTE_ENTRY; + +struct rdp_palette +{ + UINT32 count; + PALETTE_ENTRY entries[256]; +}; +typedef struct rdp_palette rdpPalette; + #include struct _RDP_PLUGIN_DATA diff --git a/include/freerdp/update.h b/include/freerdp/update.h index b311e07e5..1d8cbab92 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -73,14 +73,6 @@ typedef struct _BITMAP_UPDATE BITMAP_UPDATE; /* Palette Updates */ -struct _PALETTE_ENTRY -{ - BYTE red; - BYTE green; - BYTE blue; -}; -typedef struct _PALETTE_ENTRY PALETTE_ENTRY; - struct _PALETTE_UPDATE { UINT32 number; @@ -88,13 +80,6 @@ struct _PALETTE_UPDATE }; typedef struct _PALETTE_UPDATE PALETTE_UPDATE; -struct rdp_palette -{ - UINT32 count; - PALETTE_ENTRY entries[256]; -}; -typedef struct rdp_palette rdpPalette; - /* Play Sound (System Beep) Updates */ struct _PLAY_SOUND_UPDATE @@ -157,13 +142,15 @@ typedef void (*pDesktopResize)(rdpContext* context); typedef void (*pBitmapUpdate)(rdpContext* context, BITMAP_UPDATE* bitmap); typedef void (*pPalette)(rdpContext* context, PALETTE_UPDATE* palette); typedef void (*pPlaySound)(rdpContext* context, PLAY_SOUND_UPDATE* play_sound); +typedef void (*pSetKeyboardIndicators)(rdpContext* context, UINT16 led_flags); typedef void (*pRefreshRect)(rdpContext* context, BYTE count, RECTANGLE_16* areas); typedef void (*pSuppressOutput)(rdpContext* context, BYTE allow, RECTANGLE_16* area); typedef void (*pSurfaceCommand)(rdpContext* context, wStream* s); -typedef void (*pSurfaceBits)(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command); -typedef void (*pSurfaceFrameMarker)(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker); +typedef void (*pSurfaceBits)(rdpContext* context, SURFACE_BITS_COMMAND* surfaceBitsCommand); +typedef void (*pSurfaceFrameMarker)(rdpContext* context, SURFACE_FRAME_MARKER* surfaceFrameMarker); +typedef void (*pSurfaceFrameBits)(rdpContext* context, SURFACE_BITS_COMMAND* cmd, BOOL first, BOOL last, UINT32 frameId); typedef void (*pSurfaceFrameAcknowledge)(rdpContext* context, UINT32 frameId); struct rdp_update @@ -179,7 +166,8 @@ struct rdp_update pBitmapUpdate BitmapUpdate; /* 21 */ pPalette Palette; /* 22 */ pPlaySound PlaySound; /* 23 */ - UINT32 paddingB[32 - 24]; /* 24 */ + pSetKeyboardIndicators SetKeyboardIndicators; /* 24 */ + UINT32 paddingB[32 - 25]; /* 25 */ rdpPointerUpdate* pointer; /* 32 */ rdpPrimaryUpdate* primary; /* 33 */ @@ -195,8 +183,9 @@ struct rdp_update pSurfaceCommand SurfaceCommand; /* 64 */ pSurfaceBits SurfaceBits; /* 65 */ pSurfaceFrameMarker SurfaceFrameMarker; /* 66 */ - pSurfaceFrameAcknowledge SurfaceFrameAcknowledge; /* 67 */ - UINT32 paddingE[80 - 68]; /* 68 */ + pSurfaceFrameBits SurfaceFrameBits; /* 67 */ + pSurfaceFrameAcknowledge SurfaceFrameAcknowledge; /* 68 */ + UINT32 paddingE[80 - 69]; /* 69 */ /* internal */ diff --git a/include/freerdp/utils/debug.h b/include/freerdp/utils/debug.h deleted file mode 100644 index ba79ed6d1..000000000 --- a/include/freerdp/utils/debug.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Debug Utils - * - * Copyright 2011 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 FREERDP_UTILS_DEBUG_H -#define FREERDP_UTILS_DEBUG_H - -#define DEBUG_NULL(fmt, ...) do { } while (0) - -/* When building for android redirect all debug messages - * to logcat. */ -#if defined(ANDROID) -#include - -#define APP_NAME "freerdp-debug" - -#define ANDROID_DEBUG_PRINT(_dbg_str, fmt, ...) do { \ - __android_log_print(_dbg_str, fmt, ##__VA_ARGS__); \ - } while( 0 ) - -#define DEBUG_CLASS(_dbg_class, fmt, ...) \ - ANDROID_DEBUG_PRINT(ANDROID_LOG_DEBUG, APP_NAME, \ - "DBG_" #_dbg_class " %s (%s:%d): " \ - fmt, __FUNCTION__, __FILE__, __LINE__, ## __VA_ARGS__) - -#define DEBUG_WARN(fmt, ...) \ - ANDROID_DEBUG_PRINT(ANDROID_LOG_WARN, APP_NAME, "Warning %s (%s:%d): " \ - fmt, __FUNCTION__, __FILE__, __LINE__, ## __VA_ARGS__) - -#else -/* By default all log messages are written to stdout */ -#include - -#define DEBUG_PRINT(_dbg_str, fmt, ...) do { \ - fprintf(stderr, _dbg_str, __FUNCTION__, __FILE__, __LINE__); \ - fprintf(stderr, fmt, ## __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while( 0 ) - - -#define DEBUG_CLASS(_dbg_class, fmt, ...) DEBUG_PRINT("DBG_" #_dbg_class " %s (%s:%d): ", fmt, ## __VA_ARGS__) -#define DEBUG_WARN(fmt, ...) DEBUG_PRINT("Warning %s (%s:%d): ", fmt, ## __VA_ARGS__) -#endif - -#endif /* FREERDP_UTILS_DEBUG_H */ diff --git a/include/freerdp/utils/svc_plugin.h b/include/freerdp/utils/svc_plugin.h index 82d55225a..61bd981e2 100644 --- a/include/freerdp/utils/svc_plugin.h +++ b/include/freerdp/utils/svc_plugin.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include typedef struct rdp_svc_plugin rdpSvcPlugin; @@ -72,10 +72,11 @@ FREERDP_API int svc_plugin_send_event(rdpSvcPlugin* plugin, wMessage* event); } #endif +#define SVC_TAG FREERDP_TAG("svc") #ifdef WITH_DEBUG_SVC -#define DEBUG_SVC(fmt, ...) DEBUG_CLASS(SVC, fmt, ## __VA_ARGS__) +#define DEBUG_SVC(fmt, ...) WLog_DBG(SVC_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_SVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_SVC(fmt, ...) #endif #endif /* FREERDP_UTILS_SVC_PLUGIN_H */ diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index fa3dbf10e..54bc042e1 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -18,52 +18,272 @@ set(MODULE_NAME "freerdp") set(MODULE_PREFIX "FREERDP") -if(MONOLITHIC_BUILD) - set(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif() - # Create imported targets for Intel IPP libraries if(IPP_FOUND) foreach(ipp_lib ${IPP_LIBRARIES}) - add_library("${ipp_lib}_imported" STATIC IMPORTED) + add_library("${ipp_lib}_imported" STATIC IMPORTED) set_property(TARGET "${ipp_lib}_imported" PROPERTY IMPORTED_LOCATION "${IPP_LIBRARY_DIRS}/${ipp_lib}") endforeach() endif() +set(LIBFREERDP_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LIBFREERDP_SRCS "") +set(LIBFREERDP_LIBS "") +set(LIBFREERDP_INCLUDES "") +set(LIBFREERDP_DEFINITIONS "") + +macro (freerdp_module_add) + file (RELATIVE_PATH _relPath "${LIBFREERDP_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") + foreach (_src ${ARGN}) + if (_relPath) + list (APPEND LIBFREERDP_SRCS "${_relPath}/${_src}") + else() + list (APPEND LIBFREERDP_SRCS "${_src}") + endif() + endforeach() + if (_relPath) + set (LIBFREERDP_SRCS ${LIBFREERDP_SRCS} PARENT_SCOPE) + endif() +endmacro() + +macro (freerdp_include_directory_add) + file (RELATIVE_PATH _relPath "${LIBFREERDP_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") + foreach (_inc ${ARGN}) + if (IS_ABSOLUTE ${_inc}) + list (APPEND LIBFREERDP_INCLUDES "${_inc}") + else() + if (_relPath) + list (APPEND LIBFREERDP_INCLUDES "${_relPath}/${_inc}") + else() + list (APPEND LIBFREERDP_INCLUDES "${_inc}") + endif() + endif() + endforeach() + if (_relPath) + set (LIBFREERDP_INCLUDES ${LIBFREERDP_INCLUDES} PARENT_SCOPE) + endif() +endmacro() + +macro (freerdp_library_add) + foreach (_lib ${ARGN}) + list (APPEND LIBFREERDP_LIBS "${_lib}") + endforeach() + set (LIBFREERDP_LIBS ${LIBFREERDP_LIBS} PARENT_SCOPE) +endmacro() + +macro (freerdp_definition_add) + foreach (_define ${ARGN}) + list (APPEND LIBFREERDP_DEFINITIONS "${_define}") + endforeach() + set (LIBFREERDP_DEFINITIONS ${LIBFREERDP_DEFINITIONS} PARENT_SCOPE) +endmacro() + set(${MODULE_PREFIX}_SUBMODULES utils common gdi rail cache - codec crypto locale - primitives core) foreach(${MODULE_PREFIX}_SUBMODULE ${${MODULE_PREFIX}_SUBMODULES}) add_subdirectory(${${MODULE_PREFIX}_SUBMODULE}) endforeach() -if(MONOLITHIC_BUILD) - foreach(${MODULE_PREFIX}_SUBMODULE ${${MODULE_PREFIX}_SUBMODULES}) - set(${MODULE_PREFIX}_OBJECTS ${${MODULE_PREFIX}_OBJECTS} "$") +## cmake source properties are only seen by targets in the same CMakeLists.txt +## therefore primitives and codecs need to be defined here + +# codec +set(CODEC_SRCS + codec/dsp.c + codec/color.c + codec/audio.c + codec/planar.c + codec/bitmap.c + codec/interleaved.c + codec/progressive.c + codec/rfx_bitstream.h + codec/rfx_constants.h + codec/rfx_decode.c + codec/rfx_decode.h + codec/rfx_differential.c + codec/rfx_differential.h + codec/rfx_dwt.c + codec/rfx_dwt.h + codec/rfx_encode.c + codec/rfx_encode.h + codec/rfx_quantization.c + codec/rfx_quantization.h + codec/rfx_rlgr.c + codec/rfx_rlgr.h + codec/rfx_types.h + codec/rfx.c + codec/region.c + codec/nsc.c + codec/nsc_encode.c + codec/nsc_encode.h + codec/nsc_types.h + codec/ncrush.c + codec/xcrush.c + codec/mppc.c + codec/zgfx.c + codec/clear.c + codec/jpeg.c + codec/h264.c) + +set(CODEC_SSE2_SRCS + codec/rfx_sse2.c + codec/rfx_sse2.h + codec/nsc_sse2.c + codec/nsc_sse2.h) + +set(CODEC_NEON_SRCS + codec/rfx_neon.c + codec/rfx_neon.h) + +if(WITH_SSE2) + set(CODEC_SRCS ${CODEC_SRCS} ${CODEC_SSE2_SRCS}) + + if(CMAKE_COMPILER_IS_GNUCC) + set_source_files_properties(${CODEC_SSE2_SRCS} PROPERTIES COMPILE_FLAGS "-msse2" ) + endif() + + if(MSVC) + set_source_files_properties(${CODEC_SSE2_SRCS} PROPERTIES COMPILE_FLAGS "/arch:SSE2" ) + endif() +endif() + +if(WITH_NEON) + set_source_files_properties(${CODEC_NEON_SRCS} PROPERTIES COMPILE_FLAGS "-mfpu=neon -mfloat-abi=${ARM_FP_ABI} -Wno-unused-variable" ) + set(CODEC_SRCS ${CODEC_SRCS} ${CODEC_NEON_SRCS}) +endif() + +if(WITH_JPEG) + freerdp_include_directory_add(${JPEG_INCLUDE_DIR}) + freerdp_library_add(${JPEG_LIBRARIES}) +endif() + +if(WITH_OPENH264) + freerdp_definition_add(-DWITH_OPENH264) + freerdp_include_directory_add(${OPENH264_INCLUDE_DIR}) + freerdp_library_add(${OPENH264_LIBRARIES}) +endif() + +if(WITH_LIBAVCODEC) + freerdp_definition_add(-DWITH_LIBAVCODEC) + find_library(LIBAVCODEC_LIB avcodec) + find_library(LIBAVUTIL_LIB avutil) + freerdp_library_add(${LIBAVCODEC_LIB} ${LIBAVUTIL_LIB}) +endif() + +freerdp_module_add(${CODEC_SRCS}) + +if(BUILD_TESTING) + add_subdirectory(codec/test) +endif() + +# /codec + +# primitives + +set(PRIMITIVES_SRCS + primitives/prim_16to32bpp.c + primitives/prim_add.c + primitives/prim_andor.c + primitives/prim_alphaComp.c + primitives/prim_colors.c + primitives/prim_copy.c + primitives/prim_set.c + primitives/prim_shift.c + primitives/prim_sign.c + primitives/prim_YUV.c + primitives/prim_YCoCg.c + primitives/primitives.c + primitives/prim_internal.h) + +set(PRIMITIVES_OPT_SRCS + primitives/prim_16to32bpp_opt.c + primitives/prim_add_opt.c + primitives/prim_andor_opt.c + primitives/prim_alphaComp_opt.c + primitives/prim_colors_opt.c + primitives/prim_set_opt.c + primitives/prim_shift_opt.c + primitives/prim_sign_opt.c + primitives/prim_YUV_opt.c + primitives/prim_YCoCg_opt.c) + +freerdp_definition_add(-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) + +### IPP Variable debugging +if(WITH_IPP) + if(CMAKE_COMPILER_IS_GNUCC) + foreach(INCLDIR ${IPP_INCLUDE_DIRS}) + set(OPTIMIZATION "${OPTIMIZATION} -I${INCLDIR}") + endforeach(INCLDIR) + endif() +endif() + +if(WITH_SSE2) + if(CMAKE_COMPILER_IS_GNUCC) + set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -O2 -Wdeclaration-after-statement") + endif() + + if(MSVC) + set(OPTIMIZATION "${OPTIMIZATION} /arch:SSE2") + endif() +elseif(WITH_NEON) + if(CMAKE_COMPILER_IS_GNUCC) + set(OPTIMIZATION "${OPTIMIZATION} -mfpu=neon -mfloat-abi=${ARM_FP_ABI}") + endif() + # TODO: Add MSVC equivalent +endif() + +if(DEFINED OPTIMIZATION) + set_source_files_properties(${PRIMITIVES_OPT_SRCS} PROPERTIES COMPILE_FLAGS ${OPTIMIZATION}) +endif() + + +# always compile with optimization +if(CMAKE_COMPILER_IS_GNUCC) + set_source_files_properties(${PRIMITIVES_SRCS} PROPERTIES COMPILE_FLAGS "-O2") +endif() + +set(PRIMITIVES_SRCS ${PRIMITIVES_SRCS} ${PRIMITIVES_OPT_SRCS}) + +freerdp_module_add(${PRIMITIVES_SRCS}) + +if(IPP_FOUND) + freerdp_include_directory_add(${IPP_INCLUDE_DIRS}) + foreach(ipp_lib ${IPP_LIBRARIES}) + freerdp_library_add("${ipp_lib}_imported") endforeach() +endif() - add_library(${MODULE_NAME} dummy.c - ${${MODULE_PREFIX}_OBJECTS}) +if(BUILD_TESTING AND NOT WIN32 AND NOT APPLE) + add_subdirectory(primitives/test) +endif() - set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C) - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - list(APPEND FREERDP_LIBS ${PROFILER_LIBRARIES}) - list(REMOVE_DUPLICATES FREERDP_LIBS) +# /primitives - target_link_libraries(${MODULE_NAME} ${FREERDP_LIBS}) +list(REMOVE_DUPLICATES LIBFREERDP_DEFINITIONS) +list(REMOVE_DUPLICATES LIBFREERDP_LIBS) +list(REMOVE_DUPLICATES LIBFREERDP_INCLUDES) +include_directories(${LIBFREERDP_INCLUDES}) +add_library(${MODULE_NAME} ${LIBFREERDP_SRCS}) +add_definitions(${LIBFREERDP_DEFINITIONS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets) - - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") -endif(MONOLITHIC_BUILD) +set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C) + +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) +endif() +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") + +target_link_libraries(${MODULE_NAME} ${LIBFREERDP_LIBS} winpr) +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") diff --git a/libfreerdp/cache/CMakeLists.txt b/libfreerdp/cache/CMakeLists.txt index 82491a2d5..d1cf5b37e 100644 --- a/libfreerdp/cache/CMakeLists.txt +++ b/libfreerdp/cache/CMakeLists.txt @@ -18,7 +18,7 @@ set(MODULE_NAME "freerdp-cache") set(MODULE_PREFIX "FREERDP_CACHE") -set(${MODULE_PREFIX}_SRCS +freerdp_module_add( brush.c pointer.c bitmap.c @@ -28,23 +28,3 @@ set(${MODULE_PREFIX}_SRCS glyph.c cache.c) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-core freerdp-utils) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") diff --git a/libfreerdp/cache/bitmap.c b/libfreerdp/cache/bitmap.c index 18e8b76d8..6a62a3778 100644 --- a/libfreerdp/cache/bitmap.c +++ b/libfreerdp/cache/bitmap.c @@ -29,8 +29,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("cache.bitmap") + void update_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { rdpBitmap* bitmap; @@ -106,16 +109,17 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach rdpBitmap* bitmap; rdpBitmap* prevBitmap; rdpCache* cache = context->cache; + rdpSettings* settings = context->settings; bitmap = Bitmap_Alloc(context); Bitmap_SetDimensions(context, bitmap, cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight); - if (cacheBitmapV2->bitmapBpp == 0) - { - /* Workaround for Windows 8 bug where bitmapBpp is not set */ - cacheBitmapV2->bitmapBpp = context->instance->settings->ColorDepth; - } + if (!cacheBitmapV2->bitmapBpp) + cacheBitmapV2->bitmapBpp = settings->ColorDepth; + + if ((settings->ColorDepth == 15) && (cacheBitmapV2->bitmapBpp == 16)) + cacheBitmapV2->bitmapBpp = settings->ColorDepth; bitmap->Decompress(context, bitmap, cacheBitmapV2->bitmapDataStream, cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight, @@ -126,7 +130,7 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex); - if (prevBitmap != NULL) + if (prevBitmap) Bitmap_Free(context, prevBitmap); bitmap_cache_put(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex, bitmap); @@ -136,29 +140,30 @@ void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cach { rdpBitmap* bitmap; rdpBitmap* prevBitmap; + BOOL compressed = TRUE; rdpCache* cache = context->cache; + rdpSettings* settings = context->settings; BITMAP_DATA_EX* bitmapData = &cacheBitmapV3->bitmapData; bitmap = Bitmap_Alloc(context); Bitmap_SetDimensions(context, bitmap, bitmapData->width, bitmapData->height); - if (cacheBitmapV3->bitmapData.bpp == 0) - { - /* Workaround for Windows 8 bug where bitmapBpp is not set */ - cacheBitmapV3->bitmapData.bpp = context->instance->settings->ColorDepth; - } + if (!cacheBitmapV3->bpp) + cacheBitmapV3->bpp = settings->ColorDepth; + + compressed = (bitmapData->codecID != RDP_CODEC_ID_NONE); bitmap->Decompress(context, bitmap, bitmapData->data, bitmap->width, bitmap->height, - bitmapData->bpp, bitmapData->length, TRUE, + bitmapData->bpp, bitmapData->length, compressed, bitmapData->codecID); bitmap->New(context, bitmap); prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex); - if (prevBitmap != NULL) + if (prevBitmap) Bitmap_Free(context, prevBitmap); bitmap_cache_put(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex, bitmap); @@ -167,9 +172,9 @@ void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cach void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) { int i; - rdpBitmap* bitmap; - BITMAP_DATA* bitmap_data; BOOL reused = TRUE; + rdpBitmap* bitmap; + BITMAP_DATA* bitmapData; rdpCache* cache = context->cache; if (!cache->bitmap->bitmap) @@ -183,22 +188,22 @@ void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) for (i = 0; i < (int) bitmapUpdate->number; i++) { - bitmap_data = &bitmapUpdate->rectangles[i]; + bitmapData = &bitmapUpdate->rectangles[i]; - bitmap->bpp = bitmap_data->bitsPerPixel; - bitmap->length = bitmap_data->bitmapLength; - bitmap->compressed = bitmap_data->compressed; + bitmap->bpp = bitmapData->bitsPerPixel; + bitmap->length = bitmapData->bitmapLength; + bitmap->compressed = bitmapData->compressed; Bitmap_SetRectangle(context, bitmap, - bitmap_data->destLeft, bitmap_data->destTop, - bitmap_data->destRight, bitmap_data->destBottom); + bitmapData->destLeft, bitmapData->destTop, + bitmapData->destRight, bitmapData->destBottom); - Bitmap_SetDimensions(context, bitmap, bitmap_data->width, bitmap_data->height); + Bitmap_SetDimensions(context, bitmap, bitmapData->width, bitmapData->height); bitmap->Decompress(context, bitmap, - bitmap_data->bitmapDataStream, bitmap_data->width, bitmap_data->height, - bitmap_data->bitsPerPixel, bitmap_data->bitmapLength, - bitmap_data->compressed, RDP_CODEC_ID_NONE); + bitmapData->bitmapDataStream, bitmapData->width, bitmapData->height, + bitmapData->bitsPerPixel, bitmapData->bitmapLength, + bitmapData->compressed, RDP_CODEC_ID_NONE); if (reused) bitmap->Free(context, bitmap); @@ -217,7 +222,7 @@ rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index if (id > bitmapCache->maxCells) { - fprintf(stderr, "get invalid bitmap cell id: %d\n", id); + WLog_ERR(TAG, "get invalid bitmap cell id: %d", id); return NULL; } @@ -227,7 +232,7 @@ rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index } else if (index > bitmapCache->cells[id].number) { - fprintf(stderr, "get invalid bitmap index %d in cell id: %d\n", index, id); + WLog_ERR(TAG, "get invalid bitmap index %d in cell id: %d", index, id); return NULL; } @@ -240,7 +245,7 @@ void bitmap_cache_put(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index, rdpB { if (id > bitmapCache->maxCells) { - fprintf(stderr, "put invalid bitmap cell id: %d\n", id); + WLog_ERR(TAG, "put invalid bitmap cell id: %d", id); return; } @@ -250,7 +255,7 @@ void bitmap_cache_put(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index, rdpB } else if (index > bitmapCache->cells[id].number) { - fprintf(stderr, "put invalid bitmap index %d in cell id: %d\n", index, id); + WLog_ERR(TAG, "put invalid bitmap index %d in cell id: %d", index, id); return; } @@ -279,27 +284,26 @@ rdpBitmapCache* bitmap_cache_new(rdpSettings* settings) int i; rdpBitmapCache* bitmapCache; - bitmapCache = (rdpBitmapCache*) malloc(sizeof(rdpBitmapCache)); + bitmapCache = (rdpBitmapCache*) calloc(1, sizeof(rdpBitmapCache)); if (bitmapCache) { - ZeroMemory(bitmapCache, sizeof(rdpBitmapCache)); - bitmapCache->settings = settings; bitmapCache->update = ((freerdp*) settings->instance)->update; bitmapCache->context = bitmapCache->update->context; bitmapCache->maxCells = settings->BitmapCacheV2NumCells; - bitmapCache->cells = (BITMAP_V2_CELL*) malloc(sizeof(BITMAP_V2_CELL) * bitmapCache->maxCells); - ZeroMemory(bitmapCache->cells, sizeof(BITMAP_V2_CELL) * bitmapCache->maxCells); + bitmapCache->cells = (BITMAP_V2_CELL*) calloc(bitmapCache->maxCells, sizeof(BITMAP_V2_CELL)); + + if (!bitmapCache->cells) + return NULL; for (i = 0; i < (int) bitmapCache->maxCells; i++) { bitmapCache->cells[i].number = settings->BitmapCacheV2CellInfo[i].numEntries; /* allocate an extra entry for BITMAP_CACHE_WAITING_LIST_INDEX */ - bitmapCache->cells[i].entries = (rdpBitmap**) malloc(sizeof(rdpBitmap*) * (bitmapCache->cells[i].number + 1)); - ZeroMemory(bitmapCache->cells[i].entries, sizeof(rdpBitmap*) * (bitmapCache->cells[i].number + 1)); + bitmapCache->cells[i].entries = (rdpBitmap**) calloc((bitmapCache->cells[i].number + 1), sizeof(rdpBitmap*)); } } @@ -311,7 +315,7 @@ void bitmap_cache_free(rdpBitmapCache* bitmapCache) int i, j; rdpBitmap* bitmap; - if (bitmapCache != NULL) + if (bitmapCache) { for (i = 0; i < (int) bitmapCache->maxCells; i++) { @@ -319,10 +323,8 @@ void bitmap_cache_free(rdpBitmapCache* bitmapCache) { bitmap = bitmapCache->cells[i].entries[j]; - if (bitmap != NULL) - { + if (bitmap) Bitmap_Free(bitmapCache->context, bitmap); - } } free(bitmapCache->cells[i].entries); diff --git a/libfreerdp/cache/brush.c b/libfreerdp/cache/brush.c index 6c3fa81d0..6ede3085e 100644 --- a/libfreerdp/cache/brush.c +++ b/libfreerdp/cache/brush.c @@ -24,12 +24,16 @@ #include #include +#include #include #include #include + #include +#define TAG FREERDP_TAG("cache.brush") + void update_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { BYTE style; @@ -100,7 +104,7 @@ void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp) { if (index >= brushCache->maxMonoEntries) { - fprintf(stderr, "invalid brush (%d bpp) index: 0x%04X\n", *bpp, index); + WLog_ERR(TAG, "invalid brush (%d bpp) index: 0x%04X", *bpp, index); return NULL; } @@ -111,7 +115,7 @@ void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp) { if (index >= brushCache->maxEntries) { - fprintf(stderr, "invalid brush (%d bpp) index: 0x%04X\n", *bpp, index); + WLog_ERR(TAG, "invalid brush (%d bpp) index: 0x%04X", *bpp, index); return NULL; } @@ -121,7 +125,7 @@ void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp) if (entry == NULL) { - fprintf(stderr, "invalid brush (%d bpp) at index: 0x%04X\n", *bpp, index); + WLog_ERR(TAG, "invalid brush (%d bpp) at index: 0x%04X", *bpp, index); return NULL; } @@ -136,7 +140,7 @@ void brush_cache_put(rdpBrushCache* brushCache, UINT32 index, void* entry, UINT3 { if (index >= brushCache->maxMonoEntries) { - fprintf(stderr, "invalid brush (%d bpp) index: 0x%04X\n", bpp, index); + WLog_ERR(TAG, "invalid brush (%d bpp) index: 0x%04X", bpp, index); if (entry) free(entry); @@ -156,7 +160,7 @@ void brush_cache_put(rdpBrushCache* brushCache, UINT32 index, void* entry, UINT3 { if (index >= brushCache->maxEntries) { - fprintf(stderr, "invalid brush (%d bpp) index: 0x%04X\n", bpp, index); + WLog_ERR(TAG, "invalid brush (%d bpp) index: 0x%04X", bpp, index); if (entry) free(entry); diff --git a/libfreerdp/cache/glyph.c b/libfreerdp/cache/glyph.c index ac4303228..3dcb32a07 100644 --- a/libfreerdp/cache/glyph.c +++ b/libfreerdp/cache/glyph.c @@ -28,8 +28,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("cache.glyph") + void update_process_glyph(rdpContext* context, BYTE* data, int* index, int* x, int* y, UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel) { @@ -367,20 +370,20 @@ rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index) if (id > 9) { - fprintf(stderr, "invalid glyph cache id: %d\n", id); + WLog_ERR(TAG, "invalid glyph cache id: %d", id); return NULL; } if (index > glyphCache->glyphCache[id].number) { - fprintf(stderr, "index %d out of range for cache id: %d\n", index, id); + WLog_ERR(TAG, "index %d out of range for cache id: %d", index, id); return NULL; } glyph = glyphCache->glyphCache[id].entries[index]; if (!glyph) - fprintf(stderr, "no glyph found at cache index: %d in cache id: %d\n", index, id); + WLog_ERR(TAG, "no glyph found at cache index: %d in cache id: %d", index, id); return glyph; } @@ -391,13 +394,13 @@ void glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyp if (id > 9) { - fprintf(stderr, "invalid glyph cache id: %d\n", id); + WLog_ERR(TAG, "invalid glyph cache id: %d", id); return; } if (index > glyphCache->glyphCache[id].number) { - fprintf(stderr, "invalid glyph cache index: %d in cache id: %d\n", index, id); + WLog_ERR(TAG, "invalid glyph cache index: %d in cache id: %d", index, id); return; } @@ -423,7 +426,7 @@ void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* if (index > 255) { - fprintf(stderr, "invalid glyph cache fragment index: %d\n", index); + WLog_ERR(TAG, "invalid glyph cache fragment index: %d", index); return NULL; } @@ -433,7 +436,7 @@ void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheFragmentGet: index: %d size: %d", index, *size); if (!fragment) - fprintf(stderr, "invalid glyph fragment at index:%d\n", index); + WLog_ERR(TAG, "invalid glyph fragment at index:%d", index); return fragment; } @@ -444,7 +447,7 @@ void glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 si if (index > 255) { - fprintf(stderr, "invalid glyph cache fragment index: %d\n", index); + WLog_ERR(TAG, "invalid glyph cache fragment index: %d", index); return; } diff --git a/libfreerdp/cache/nine_grid.c b/libfreerdp/cache/nine_grid.c index 47245c8a8..a52cf15b9 100644 --- a/libfreerdp/cache/nine_grid.c +++ b/libfreerdp/cache/nine_grid.c @@ -25,12 +25,16 @@ #include +#include #include #include #include + #include +#define TAG FREERDP_TAG("cache.nine_grid") + void update_gdi_draw_nine_grid(rdpContext* context, DRAW_NINE_GRID_ORDER* draw_nine_grid) { rdpCache* cache = context->cache; @@ -60,7 +64,7 @@ void* nine_grid_cache_get(rdpNineGridCache* nine_grid, UINT32 index) if (index >= nine_grid->maxEntries) { - fprintf(stderr, "invalid NineGrid index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid NineGrid index: 0x%04X", index); return NULL; } @@ -68,7 +72,7 @@ void* nine_grid_cache_get(rdpNineGridCache* nine_grid, UINT32 index) if (entry == NULL) { - fprintf(stderr, "invalid NineGrid at index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid NineGrid at index: 0x%04X", index); return NULL; } @@ -81,7 +85,7 @@ void nine_grid_cache_put(rdpNineGridCache* nine_grid, UINT32 index, void* entry) if (index >= nine_grid->maxEntries) { - fprintf(stderr, "invalid NineGrid index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid NineGrid index: 0x%04X", index); return; } diff --git a/libfreerdp/cache/offscreen.c b/libfreerdp/cache/offscreen.c index c735f96d3..0dbbcdd96 100644 --- a/libfreerdp/cache/offscreen.c +++ b/libfreerdp/cache/offscreen.c @@ -27,8 +27,11 @@ #include +#include #include +#define TAG FREERDP_TAG("cache.offscreen") + void update_gdi_create_offscreen_bitmap(rdpContext* context, CREATE_OFFSCREEN_BITMAP_ORDER* createOffscreenBitmap) { int i; @@ -80,7 +83,7 @@ rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index) if (index >= offscreenCache->maxEntries) { - fprintf(stderr, "invalid offscreen bitmap index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%04X", index); return NULL; } @@ -88,7 +91,7 @@ rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index) if (!bitmap) { - fprintf(stderr, "invalid offscreen bitmap at index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid offscreen bitmap at index: 0x%04X", index); return NULL; } @@ -99,7 +102,7 @@ void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBit { if (index >= offscreenCache->maxEntries) { - fprintf(stderr, "invalid offscreen bitmap index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%04X", index); return; } @@ -113,7 +116,7 @@ void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index) if (index >= offscreenCache->maxEntries) { - fprintf(stderr, "invalid offscreen bitmap index (delete): 0x%04X\n", index); + WLog_ERR(TAG, "invalid offscreen bitmap index (delete): 0x%04X", index); return; } diff --git a/libfreerdp/cache/palette.c b/libfreerdp/cache/palette.c index 3436a686d..dc515835b 100644 --- a/libfreerdp/cache/palette.c +++ b/libfreerdp/cache/palette.c @@ -25,8 +25,11 @@ #include +#include #include +#define TAG FREERDP_TAG("cache.palette") + static void update_gdi_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE_ORDER* cacheColorTable) { UINT32* colorTable; @@ -44,7 +47,7 @@ void* palette_cache_get(rdpPaletteCache* paletteCache, UINT32 index) if (index >= paletteCache->maxEntries) { - fprintf(stderr, "invalid color table index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid color table index: 0x%04X", index); return NULL; } @@ -52,7 +55,7 @@ void* palette_cache_get(rdpPaletteCache* paletteCache, UINT32 index) if (!entry) { - fprintf(stderr, "invalid color table at index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid color table at index: 0x%04X", index); return NULL; } @@ -63,7 +66,7 @@ void palette_cache_put(rdpPaletteCache* paletteCache, UINT32 index, void* entry) { if (index >= paletteCache->maxEntries) { - fprintf(stderr, "invalid color table index: 0x%04X\n", index); + WLog_ERR(TAG, "invalid color table index: 0x%04X", index); if (entry) free(entry); @@ -86,15 +89,13 @@ rdpPaletteCache* palette_cache_new(rdpSettings* settings) { rdpPaletteCache* paletteCache; - paletteCache = (rdpPaletteCache*) malloc(sizeof(rdpPaletteCache)); - ZeroMemory(paletteCache, sizeof(rdpPaletteCache)); + paletteCache = (rdpPaletteCache*) calloc(1, sizeof(rdpPaletteCache)); if (paletteCache) { paletteCache->settings = settings; paletteCache->maxEntries = 6; - paletteCache->entries = (PALETTE_TABLE_ENTRY*) malloc(sizeof(PALETTE_TABLE_ENTRY) * paletteCache->maxEntries); - ZeroMemory(paletteCache->entries, sizeof(PALETTE_TABLE_ENTRY) * paletteCache->maxEntries); + paletteCache->entries = (PALETTE_TABLE_ENTRY*) calloc(paletteCache->maxEntries, sizeof(PALETTE_TABLE_ENTRY)); } return paletteCache; diff --git a/libfreerdp/cache/pointer.c b/libfreerdp/cache/pointer.c index 57bc3a4ef..5af41121c 100644 --- a/libfreerdp/cache/pointer.c +++ b/libfreerdp/cache/pointer.c @@ -27,8 +27,12 @@ #include +#include #include + +#define TAG FREERDP_TAG("cache.pointer") + void update_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointer_position) { @@ -47,7 +51,7 @@ void update_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_s break; default: - fprintf(stderr, "Unknown system pointer type (0x%08X)\n", pointer_system->type); + WLog_ERR(TAG, "Unknown system pointer type (0x%08X)", pointer_system->type); break; } } @@ -140,7 +144,7 @@ rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index) if (index >= pointer_cache->cacheSize) { - fprintf(stderr, "invalid pointer index:%d\n", index); + WLog_ERR(TAG, "invalid pointer index:%d", index); return NULL; } @@ -155,7 +159,7 @@ void pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* if (index >= pointer_cache->cacheSize) { - fprintf(stderr, "invalid pointer index:%d\n", index); + WLog_ERR(TAG, "invalid pointer index:%d", index); return; } diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt deleted file mode 100644 index ad0180e25..000000000 --- a/libfreerdp/codec/CMakeLists.txt +++ /dev/null @@ -1,121 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# libfreerdp-codec cmake build script -# -# Copyright 2012 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. - -set(MODULE_NAME "freerdp-codec") -set(MODULE_PREFIX "FREERDP_CODEC") - -set(${MODULE_PREFIX}_SRCS - dsp.c - color.c - audio.c - planar.c - planar.h - bitmap_decode.c - bitmap_encode.c - rfx_bitstream.h - rfx_constants.h - rfx_decode.c - rfx_decode.h - rfx_differential.c - rfx_differential.h - rfx_dwt.c - rfx_dwt.h - rfx_encode.c - rfx_encode.h - rfx_quantization.c - rfx_quantization.h - rfx_rlgr.c - rfx_rlgr.h - rfx_types.h - rfx.c - region.c - nsc.c - nsc_encode.c - nsc_encode.h - nsc_types.h - ncrush.c - xcrush.c - mppc.c - zgfx.c - clear.c - jpeg.c) - -set(${MODULE_PREFIX}_SSE2_SRCS - rfx_sse2.c - rfx_sse2.h - nsc_sse2.c - nsc_sse2.h) - -set(${MODULE_PREFIX}_NEON_SRCS - rfx_neon.c - rfx_neon.h) - -if(WITH_SSE2) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_SSE2_SRCS}) - - if(CMAKE_COMPILER_IS_GNUCC) - set_source_files_properties(${${MODULE_PREFIX}_SSE2_SRCS} PROPERTIES COMPILE_FLAGS "-msse2") - endif() - - if(MSVC) - set_source_files_properties(${${MODULE_PREFIX}_SSE2_SRCS} PROPERTIES COMPILE_FLAGS "/arch:SSE2") - endif() -endif() - -if(WITH_NEON) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_NEON_SRCS}) - set_source_files_properties(${${MODULE_PREFIX}_NEON_SRCS} PROPERTIES COMPILE_FLAGS "-mfpu=neon -mfloat-abi=${ARM_FP_ABI} -Wno-unused-variable") -endif() - -if(WITH_JPEG) - include_directories(${JPEG_INCLUDE_DIR}) - set(FREERDP_JPEG_LIBS ${JPEG_LIBRARIES}) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${FREERDP_JPEG_LIBS}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-primitives freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-pool winpr-registry winpr-sysinfo winpr-utils) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - -if(BUILD_TESTING) - add_subdirectory(test) -endif() - diff --git a/libfreerdp/codec/audio.c b/libfreerdp/codec/audio.c index 751885e78..6d96628a9 100644 --- a/libfreerdp/codec/audio.c +++ b/libfreerdp/codec/audio.c @@ -23,8 +23,11 @@ #include +#include #include +#define TAG FREERDP_TAG("codec") + UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size) { UINT32 mstime; @@ -57,12 +60,12 @@ UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size) } else { - fprintf(stderr, "rdpsnd_compute_audio_time_length: invalid WAVE_FORMAT_GSM610 format\n"); + WLog_ERR(TAG, "rdpsnd_compute_audio_time_length: invalid WAVE_FORMAT_GSM610 format"); } } else { - fprintf(stderr, "rdpsnd_compute_audio_time_length: unknown format %d\n", format->wFormatTag); + WLog_ERR(TAG, "rdpsnd_compute_audio_time_length: unknown format %d", format->wFormatTag); } } @@ -109,11 +112,11 @@ char* rdpsnd_get_audio_tag_string(UINT16 wFormatTag) void rdpsnd_print_audio_format(AUDIO_FORMAT* format) { - fprintf(stderr, "%s:\t wFormatTag: 0x%04X nChannels: %d nSamplesPerSec: %d nAvgBytesPerSec: %d " - "nBlockAlign: %d wBitsPerSample: %d cbSize: %d\n", - rdpsnd_get_audio_tag_string(format->wFormatTag), format->wFormatTag, - format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec, - format->nBlockAlign, format->wBitsPerSample, format->cbSize); + WLog_INFO(TAG, "%s:\t wFormatTag: 0x%04X nChannels: %d nSamplesPerSec: %d nAvgBytesPerSec: %d " + "nBlockAlign: %d wBitsPerSample: %d cbSize: %d", + rdpsnd_get_audio_tag_string(format->wFormatTag), format->wFormatTag, + format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec, + format->nBlockAlign, format->wBitsPerSample, format->cbSize); } void rdpsnd_print_audio_formats(AUDIO_FORMAT* formats, UINT16 count) @@ -123,17 +126,16 @@ void rdpsnd_print_audio_formats(AUDIO_FORMAT* formats, UINT16 count) if (formats) { - fprintf(stderr, "AUDIO_FORMATS (%d) =\n{\n", count); + WLog_INFO(TAG, "AUDIO_FORMATS (%d) ={", count); for (index = 0; index < (int) count; index++) { format = &formats[index]; - - fprintf(stderr, "\t"); + WLog_ERR(TAG, "\t"); rdpsnd_print_audio_format(format); } - fprintf(stderr, "}\n"); + WLog_ERR(TAG, "}"); } } diff --git a/libfreerdp/codec/bitmap_encode.c b/libfreerdp/codec/bitmap.c similarity index 99% rename from libfreerdp/codec/bitmap_encode.c rename to libfreerdp/codec/bitmap.c index 9db6f1a14..ccb104ed2 100644 --- a/libfreerdp/codec/bitmap_encode.c +++ b/libfreerdp/codec/bitmap.c @@ -22,6 +22,7 @@ #endif #include +#include #define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) #define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index c57f8c641..ddbe19efc 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -25,42 +25,135 @@ #include #include +#include #include -int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) +static UINT32 CLEAR_LOG2_FLOOR[256] = { - int index; - BYTE glyphFlags; + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static BYTE CLEAR_8BIT_MASKS[9] = +{ + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF +}; + +int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) +{ + UINT32 i; + BOOL invert; + UINT32 x, y; + UINT32 count; + UINT32 color; + int nXDstRel; + int nYDstRel; + int nSrcStep; BYTE seqNumber; - UINT16 glyphIndex; + BYTE glyphFlags; + BYTE* glyphData; UINT32 offset = 0; + UINT16 glyphIndex = 0; + BYTE* pDstData = NULL; UINT32 residualByteCount; UINT32 bandsByteCount; UINT32 subcodecByteCount; + UINT32 runLengthFactor; + UINT32 pixelIndex = 0; + UINT32 pixelCount = 0; + BYTE* pSrcPixel8 = NULL; + BYTE* pDstPixel8 = NULL; + UINT32* pSrcPixel32 = NULL; + UINT32* pDstPixel32 = NULL; + CLEAR_GLYPH_ENTRY* glyphEntry; + + if (!ppDstData) + return -1001; + + pDstData = *ppDstData; + + if (!pDstData) + return -1002; if (SrcSize < 2) - return -1001; + return -1003; + + if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF)) + return -1004; + + invert = FREERDP_PIXEL_FORMAT_IS_ABGR(DstFormat) ? TRUE : FALSE; glyphFlags = pSrcData[0]; seqNumber = pSrcData[1]; offset += 2; - printf("glyphFlags: 0x%02X seqNumber: %d\n", glyphFlags, seqNumber); + if (!clear->seqNumber && seqNumber) + clear->seqNumber = seqNumber; + + if (seqNumber != clear->seqNumber) + return -1005; + + clear->seqNumber = (seqNumber + 1) % 256; + + if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET) + { + clear->VBarStorageCursor = 0; + clear->ShortVBarStorageCursor = 0; + } + + if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)) + return -1006; if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) { + if ((nWidth * nHeight) > (1024 * 1024)) + return -1007; + if (SrcSize < 4) - return -1002; + return -1008; glyphIndex = *((UINT16*) &pSrcData[2]); offset += 2; + if (glyphIndex >= 4000) + return -1009; + if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) { - /** - * Copy pixels from the Decompressor Glyph Storage position - * specified by the glyphIndex field to the output bitmap - */ + glyphEntry = &(clear->GlyphCache[glyphIndex]); + glyphData = (BYTE*) glyphEntry->pixels; + + if (!glyphData) + return -1010; + + if ((nWidth * nHeight) > (int) glyphEntry->count) + return -1011; + + nSrcStep = nWidth * 4; + pSrcPixel8 = glyphData; + pDstPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < (UINT32) nHeight; y++) + { + CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep); + pSrcPixel8 += nSrcStep; + pDstPixel8 += nDstStep; + } return 1; /* Finish */ } @@ -69,70 +162,99 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* /* Read composition payload header parameters */ if ((SrcSize - offset) < 12) - return -1003; + return -1012; residualByteCount = *((UINT32*) &pSrcData[offset]); bandsByteCount = *((UINT32*) &pSrcData[offset + 4]); subcodecByteCount = *((UINT32*) &pSrcData[offset + 8]); offset += 12; - printf("residualByteCount: %d bandsByteCount: %d subcodecByteCount: %d\n", - residualByteCount, bandsByteCount, subcodecByteCount); + //WLog_DBG(TAG, "residualByteCount: %d bandsByteCount: %d subcodecByteCount: %d\n", + // residualByteCount, bandsByteCount, subcodecByteCount); if (residualByteCount > 0) { - BYTE blueValue; - BYTE greenValue; - BYTE redValue; UINT32 suboffset; BYTE* residualData; - BYTE runLengthFactor1 = 0; - UINT16 runLengthFactor2 = 0; - UINT32 runLengthFactor3 = 0; - UINT32 runLengthFactor = 0; if ((SrcSize - offset) < residualByteCount) - return -1004; + return -1013; suboffset = 0; residualData = &pSrcData[offset]; + if ((nWidth * nHeight * 4) > (int) clear->TempSize) + { + clear->TempSize = (nWidth * nHeight * 4); + clear->TempBuffer = (BYTE*) realloc(clear->TempBuffer, clear->TempSize); + + if (!clear->TempBuffer) + return -1014; + } + + pixelIndex = 0; + pixelCount = nWidth * nHeight; + pDstPixel32 = (UINT32*) clear->TempBuffer; + while (suboffset < residualByteCount) { if ((residualByteCount - suboffset) < 4) - return -1005; + return -1015; + + if (!invert) + color = RGB32(residualData[suboffset + 2], residualData[suboffset + 1], residualData[suboffset + 0]); + else + color = BGR32(residualData[suboffset + 2], residualData[suboffset + 1], residualData[suboffset + 0]); - blueValue = residualData[suboffset]; - greenValue = residualData[suboffset + 1]; - redValue = residualData[suboffset + 2]; suboffset += 3; - runLengthFactor1 = residualData[suboffset]; - runLengthFactor = runLengthFactor1; - suboffset += 1; + runLengthFactor = (UINT32) residualData[suboffset]; + suboffset++; - if (runLengthFactor1 >= 0xFF) + if (runLengthFactor >= 0xFF) { if ((residualByteCount - suboffset) < 2) - return -1006; + return -1016; - runLengthFactor2 = *((UINT16*) &residualData[suboffset]); - runLengthFactor = runLengthFactor2; + runLengthFactor = (UINT32) *((UINT16*) &residualData[suboffset]); suboffset += 2; - if (runLengthFactor2 >= 0xFFFF) + if (runLengthFactor >= 0xFFFF) { if ((residualByteCount - suboffset) < 4) - return -1007; + return -1017; - runLengthFactor3 = *((UINT32*) &residualData[suboffset]); - runLengthFactor = runLengthFactor3; + runLengthFactor = *((UINT32*) &residualData[suboffset]); suboffset += 4; } } + + if ((pixelIndex + runLengthFactor) > pixelCount) + return -1018; + + for (i = 0; i < runLengthFactor; i++) + { + *pDstPixel32 = color; + pDstPixel32++; + } + + pixelIndex += runLengthFactor; + } + + nSrcStep = nWidth * 4; + pSrcPixel8 = clear->TempBuffer; + pDstPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + if (pixelIndex != pixelCount) + return -1019; + + for (y = 0; y < (UINT32) nHeight; y++) + { + CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep); + pSrcPixel8 += nSrcStep; + pDstPixel8 += nDstStep; } - /* Decompress residual layer and write to output bitmap */ offset += residualByteCount; } @@ -142,7 +264,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT32 suboffset; if ((SrcSize - offset) < bandsByteCount) - return -1008; + return -1020; suboffset = 0; bandsData = &pSrcData[offset]; @@ -153,63 +275,81 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT16 xEnd; UINT16 yStart; UINT16 yEnd; - BYTE blueBkg; - BYTE greenBkg; - BYTE redBkg; - BYTE* vBars; + BYTE* vBar; + BOOL vBarUpdate; + UINT32 colorBkg; UINT16 vBarHeader; UINT16 vBarIndex; UINT16 vBarYOn; UINT16 vBarYOff; - int vBarCount; - int vBarPixelCount; + UINT32 vBarCount; + UINT32 vBarHeight; + UINT32 vBarPixelCount; + UINT32 vBarShortPixelCount; + CLEAR_VBAR_ENTRY* vBarEntry; + CLEAR_VBAR_ENTRY* vBarShortEntry; if ((bandsByteCount - suboffset) < 11) - return -1009; + return -1021; xStart = *((UINT16*) &bandsData[suboffset]); xEnd = *((UINT16*) &bandsData[suboffset + 2]); yStart = *((UINT16*) &bandsData[suboffset + 4]); yEnd = *((UINT16*) &bandsData[suboffset + 6]); - blueBkg = bandsData[suboffset + 8]; - greenBkg = bandsData[suboffset + 9]; - redBkg = bandsData[suboffset + 10]; - suboffset += 11; + suboffset += 8; + + if (!invert) + colorBkg = RGB32(bandsData[suboffset + 2], bandsData[suboffset + 1], bandsData[suboffset + 0]); + else + colorBkg = BGR32(bandsData[suboffset + 2], bandsData[suboffset + 1], bandsData[suboffset + 0]); + + suboffset += 3; + + if (xEnd < xStart) + return -1022; + + if (yEnd < yStart) + return -1023; vBarCount = (xEnd - xStart) + 1; - printf("CLEARCODEC_BAND: xStart: %d xEnd: %d yStart: %d yEnd: %d vBarCount: %d blueBkg: 0x%02X greenBkg: 0x%02X redBkg: 0x%02X\n", - xStart, xEnd, yStart, yEnd, vBarCount, blueBkg, greenBkg, redBkg); - - for (index = 0; index < vBarCount; index++) + for (i = 0; i < vBarCount; i++) { - vBars = &bandsData[suboffset]; + vBarUpdate = FALSE; + vBar = &bandsData[suboffset]; if ((bandsByteCount - suboffset) < 2) - return -1010; + return -1024; - vBarHeader = *((UINT16*) &vBars[0]); + vBarHeader = *((UINT16*) &vBar[0]); suboffset += 2; - if ((vBarHeader & 0xC000) == 0x8000) /* VBAR_CACHE_HIT */ - { - vBarIndex = (vBarHeader & 0x7FFF); + vBarHeight = (yEnd - yStart + 1); - printf("VBAR_CACHE_HIT: vBarIndex: %d\n", - vBarIndex); - } - else if ((vBarHeader & 0xC000) == 0xC000) /* SHORT_VBAR_CACHE_HIT */ + if (vBarHeight > 52) + return -1025; + + if ((vBarHeader & 0xC000) == 0x4000) /* SHORT_VBAR_CACHE_HIT */ { vBarIndex = (vBarHeader & 0x3FFF); - if ((bandsByteCount - suboffset) < 1) - return -1011; + if (vBarIndex >= 16384) + return -1026; - vBarYOn = vBars[2]; + if ((bandsByteCount - suboffset) < 1) + return -1027; + + vBarYOn = vBar[2]; suboffset += 1; - printf("SHORT_VBAR_CACHE_HIT: vBarIndex: %d vBarYOn: %d\n", - vBarIndex, vBarYOn); + vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]); + + if (!vBarShortEntry) + return -1028; + + vBarShortPixelCount = vBarShortEntry->count; + + vBarUpdate = TRUE; } else if ((vBarHeader & 0xC000) == 0x0000) /* SHORT_VBAR_CACHE_MISS */ { @@ -217,28 +357,168 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* vBarYOff = ((vBarHeader >> 8) & 0x3F); if (vBarYOff < vBarYOn) - return -1012; + return -1029; - /* shortVBarPixels: variable */ + pSrcPixel8 = &vBar[2]; + vBarShortPixelCount = (vBarYOff - vBarYOn); - vBarPixelCount = (3 * (vBarYOff - vBarYOn)); + if (vBarShortPixelCount > 52) + return -1030; - printf("SHORT_VBAR_CACHE_MISS: vBarYOn: %d vBarYOff: %d bytes: %d\n", - vBarYOn, vBarYOff, vBarPixelCount); + if ((bandsByteCount - suboffset) < (vBarShortPixelCount * 3)) + return -1031; - if ((bandsByteCount - suboffset) < vBarPixelCount) - return -1013; + if (clear->ShortVBarStorageCursor >= 16384) + return -1032; - suboffset += vBarPixelCount; + vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]); + + vBarShortEntry->count = vBarShortPixelCount; + + if (vBarShortEntry->count > vBarShortEntry->size) + { + vBarShortEntry->size = vBarShortEntry->count; + + if (!vBarShortEntry->pixels) + vBarShortEntry->pixels = (UINT32*) malloc(vBarShortEntry->count * 4); + else + vBarShortEntry->pixels = (UINT32*) realloc(vBarShortEntry->pixels, vBarShortEntry->count * 4); + } + + if (!vBarShortEntry->pixels && vBarShortEntry->size) + return -1033; + + pDstPixel32 = vBarShortEntry->pixels; + + if (!invert) + { + for (y = 0; y < vBarShortPixelCount; y++) + { + *pDstPixel32 = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + pDstPixel32++; + } + } + else + { + for (y = 0; y < vBarShortPixelCount; y++) + { + *pDstPixel32 = BGR32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + pDstPixel32++; + } + } + + suboffset += (vBarShortPixelCount * 3); + + vBarShortEntry->count = vBarShortPixelCount; + clear->ShortVBarStorageCursor = (clear->ShortVBarStorageCursor + 1) % 16384; + + vBarUpdate = TRUE; + } + else if ((vBarHeader & 0x8000) == 0x8000) /* VBAR_CACHE_HIT */ + { + vBarIndex = (vBarHeader & 0x7FFF); + + if (vBarIndex >= 32768) + return -1034; + + vBarEntry = &(clear->VBarStorage[vBarIndex]); } else { - return -1014; /* invalid vBarHeader */ + return -1035; /* invalid vBarHeader */ + } + + if (vBarUpdate) + { + if (clear->VBarStorageCursor >= 32768) + return -1036; + + vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]); + + vBarPixelCount = vBarHeight; + vBarEntry->count = vBarPixelCount; + + if (vBarEntry->count > vBarEntry->size) + { + vBarEntry->size = vBarEntry->count; + + if (!vBarEntry->pixels) + vBarEntry->pixels = (UINT32*) malloc(vBarEntry->count * 4); + else + vBarEntry->pixels = (UINT32*) realloc(vBarEntry->pixels, vBarEntry->count * 4); + } + + if (!vBarEntry->pixels && vBarEntry->size) + return -1037; + + pDstPixel32 = vBarEntry->pixels; + + /* if (y < vBarYOn), use colorBkg */ + + y = 0; + count = vBarYOn; + + if ((y + count) > vBarPixelCount) + count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; + + while (count--) + { + *pDstPixel32 = colorBkg; + pDstPixel32++; + } + + /* + * if ((y >= vBarYOn) && (y < (vBarYOn + vBarShortPixelCount))), + * use vBarShortPixels at index (y - shortVBarYOn) + */ + + y = vBarYOn; + count = vBarShortPixelCount; + + if ((y + count) > vBarPixelCount) + count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; + + pSrcPixel32 = &(vBarShortEntry->pixels[y - vBarYOn]); + CopyMemory(pDstPixel32, pSrcPixel32, count * 4); + pDstPixel32 += count; + + /* if (y >= (vBarYOn + vBarShortPixelCount)), use colorBkg */ + + y = vBarYOn + vBarShortPixelCount; + count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; + + while (count--) + { + *pDstPixel32 = colorBkg; + pDstPixel32++; + } + + vBarEntry->count = vBarPixelCount; + clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % 32768; + } + + nXDstRel = nXDst + xStart; + nYDstRel = nYDst + yStart; + + pSrcPixel32 = vBarEntry->pixels; + pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + ((nXDstRel + i) * 4)]; + + count = yEnd - yStart + 1; + + if (vBarEntry->count != count) + return -1038; + + for (y = 0; y < count; y++) + { + *((UINT32*) pDstPixel8) = *pSrcPixel32; + pDstPixel8 += nDstStep; + pSrcPixel32++; } } } - /* Decompress bands layer and write to output bitmap */ offset += bandsByteCount; } @@ -249,13 +529,14 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT16 width; UINT16 height; BYTE* bitmapData; + UINT32 bitmapDataOffset; UINT32 bitmapDataByteCount; BYTE subcodecId; BYTE* subcodecs; UINT32 suboffset; if ((SrcSize - offset) < subcodecByteCount) - return -1015; + return -1039; suboffset = 0; subcodecs = &pSrcData[offset]; @@ -263,7 +544,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* while (suboffset < subcodecByteCount) { if ((subcodecByteCount - suboffset) < 13) - return -1016; + return -1040; xStart = *((UINT16*) &subcodecs[suboffset]); yStart = *((UINT16*) &subcodecs[suboffset + 2]); @@ -273,33 +554,270 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* subcodecId = subcodecs[suboffset + 12]; suboffset += 13; - printf("bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d subCodecId: %d\n", - bitmapDataByteCount, subcodecByteCount, suboffset, subcodecId); + //WLog_DBG(TAG, "bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d subCodecId: %d\n", + // bitmapDataByteCount, subcodecByteCount, suboffset, subcodecId); if ((subcodecByteCount - suboffset) < bitmapDataByteCount) - return -1017; + return -1041; + + nXDstRel = nXDst + xStart; + nYDstRel = nYDst + yStart; + + if (width > nWidth) + return -1042; + + if (height > nHeight) + return -1043; + + if (((UINT32) (width * height * 4)) > clear->TempSize) + { + clear->TempSize = (width * height * 4); + clear->TempBuffer = (BYTE*) realloc(clear->TempBuffer, clear->TempSize); + + if (!clear->TempBuffer) + return -1044; + } bitmapData = &subcodecs[suboffset]; + if (subcodecId == 0) /* Uncompressed */ + { + if (bitmapDataByteCount != (width * height * 3)) + return -1045; + + pSrcPixel8 = bitmapData; + + if (!invert) + { + for (y = 0; y < height; y++) + { + pDstPixel32 = (UINT32*) &pDstData[((nYDstRel + y) * nDstStep) + (nXDstRel * 4)]; + + for (x = 0; x < width; x++) + { + *pDstPixel32 = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + pDstPixel32++; + } + } + } + else + { + for (y = 0; y < height; y++) + { + pDstPixel32 = (UINT32*) &pDstData[((nYDstRel + y) * nDstStep) + (nXDstRel * 4)]; + + for (x = 0; x < width; x++) + { + *pDstPixel32 = BGR32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + pDstPixel32++; + } + } + } + } + else if (subcodecId == 1) /* NSCodec */ + { + if (nsc_process_message(clear->nsc, 32, width, height, bitmapData, bitmapDataByteCount) < 0) + return -1046; + + nSrcStep = width * 4; + pSrcPixel8 = clear->nsc->BitmapData; + pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + (nXDstRel * 4)]; + + if (!invert) + { + for (y = 0; y < height; y++) + { + CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep); + pSrcPixel8 += nSrcStep; + pDstPixel8 += nDstStep; + } + } + else + { + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + pDstPixel8[0] = pSrcPixel8[2]; + pDstPixel8[1] = pSrcPixel8[1]; + pDstPixel8[2] = pSrcPixel8[0]; + pDstPixel8[3] = 0xFF; + + pSrcPixel8 += 4; + pDstPixel8 += 4; + } + + pSrcPixel8 += (nSrcStep - (width * 4)); + pDstPixel8 += (nDstStep - (width * 4)); + } + } + } + else if (subcodecId == 2) /* CLEARCODEC_SUBCODEC_RLEX */ + { + UINT32 numBits; + BYTE startIndex; + BYTE stopIndex; + BYTE suiteIndex; + BYTE suiteDepth; + BYTE paletteCount; + UINT32 palette[128]; + + paletteCount = bitmapData[0]; + pSrcPixel8 = &bitmapData[1]; + bitmapDataOffset = 1 + (paletteCount * 3); + + if (paletteCount > 127) + return -1047; + + if (!invert) + { + for (i = 0; i < paletteCount; i++) + { + palette[i] = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + } + } + else + { + for (i = 0; i < paletteCount; i++) + { + palette[i] = BGR32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]); + pSrcPixel8 += 3; + } + } + + pixelIndex = 0; + pixelCount = width * height; + pDstPixel32 = (UINT32*) clear->TempBuffer; + + numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1; + + while (bitmapDataOffset < bitmapDataByteCount) + { + if ((bitmapDataByteCount - bitmapDataOffset) < 2) + return -1048; + + stopIndex = bitmapData[bitmapDataOffset] & CLEAR_8BIT_MASKS[numBits]; + suiteDepth = (bitmapData[bitmapDataOffset] >> numBits) & CLEAR_8BIT_MASKS[(8 - numBits)]; + startIndex = stopIndex - suiteDepth; + bitmapDataOffset++; + + runLengthFactor = (UINT32) bitmapData[bitmapDataOffset]; + bitmapDataOffset++; + + if (runLengthFactor >= 0xFF) + { + if ((bitmapDataByteCount - bitmapDataOffset) < 2) + return -1049; + + runLengthFactor = (UINT32) *((UINT16*) &bitmapData[bitmapDataOffset]); + bitmapDataOffset += 2; + + if (runLengthFactor >= 0xFFFF) + { + if ((bitmapDataByteCount - bitmapDataOffset) < 4) + return -1050; + + runLengthFactor = *((UINT32*) &bitmapData[bitmapDataOffset]); + bitmapDataOffset += 4; + } + } + + if (startIndex >= paletteCount) + return -1051; + + if (stopIndex >= paletteCount) + return -1052; + + suiteIndex = startIndex; + color = palette[suiteIndex]; + + if ((pixelIndex + runLengthFactor) > pixelCount) + return -1053; + + for (i = 0; i < runLengthFactor; i++) + { + *pDstPixel32 = color; + pDstPixel32++; + } + + pixelIndex += runLengthFactor; + + if ((pixelIndex + (suiteDepth + 1)) > pixelCount) + return -1054; + + for (i = 0; i <= suiteDepth; i++) + { + *pDstPixel32 = palette[suiteIndex++]; + pDstPixel32++; + } + + pixelIndex += (suiteDepth + 1); + } + + nSrcStep = width * 4; + pSrcPixel8 = clear->TempBuffer; + pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + (nXDstRel * 4)]; + + if (pixelIndex != pixelCount) + return -1055; + + for (y = 0; y < height; y++) + { + CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep); + pSrcPixel8 += nSrcStep; + pDstPixel8 += nDstStep; + pixelCount -= count; + } + } + else + { + return -1056; + } + suboffset += bitmapDataByteCount; } - /* Decompress subcodec layer and write to output bitmap */ offset += subcodecByteCount; } if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) { - /** - * Copy decompressed bitmap to the Decompressor Glyph - * Storage position specified by the glyphIndex field - */ + glyphEntry = &(clear->GlyphCache[glyphIndex]); + + glyphEntry->count = nWidth * nHeight; + + if (glyphEntry->count > glyphEntry->size) + { + glyphEntry->size = glyphEntry->count; + + if (!glyphEntry->pixels) + glyphEntry->pixels = (UINT32*) malloc(glyphEntry->size * 4); + else + glyphEntry->pixels = (UINT32*) realloc(glyphEntry->pixels, glyphEntry->size * 4); + } + + if (!glyphEntry->pixels) + return -1057; + + glyphData = (BYTE*) glyphEntry->pixels; + + nSrcStep = nWidth * 4; + pDstPixel8 = glyphData; + pSrcPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < (UINT32) nHeight; y++) + { + CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep); + pDstPixel8 += nSrcStep; + pSrcPixel8 += nDstStep; + } } if (offset != SrcSize) - { - printf("clear_decompress: incomplete processing of bytes: Actual: %d, Expected: %d\n", offset, SrcSize); - } + return -1058; return 1; } @@ -309,9 +827,12 @@ int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** return 1; } -void clear_context_reset(CLEAR_CONTEXT* clear) +int clear_context_reset(CLEAR_CONTEXT* clear) { - + clear->seqNumber = 0; + clear->VBarStorageCursor = 0; + clear->ShortVBarStorageCursor = 0; + return 1; } CLEAR_CONTEXT* clear_context_new(BOOL Compressor) @@ -324,6 +845,16 @@ CLEAR_CONTEXT* clear_context_new(BOOL Compressor) { clear->Compressor = Compressor; + clear->nsc = nsc_context_new(); + + if (!clear->nsc) + return NULL; + + nsc_context_set_pixel_format(clear->nsc, RDP_PIXEL_FORMAT_R8G8B8); + + clear->TempSize = 512 * 512 * 4; + clear->TempBuffer = (BYTE*) malloc(clear->TempSize); + clear_context_reset(clear); } @@ -332,9 +863,24 @@ CLEAR_CONTEXT* clear_context_new(BOOL Compressor) void clear_context_free(CLEAR_CONTEXT* clear) { - if (clear) - { - free(clear); - } + int i; + + if (!clear) + return; + + nsc_context_free(clear->nsc); + + free(clear->TempBuffer); + + for (i = 0; i < 4000; i++) + free(clear->GlyphCache[i].pixels); + + for (i = 0; i < 32768; i++) + free(clear->VBarStorage[i].pixels); + + for (i = 0; i < 16384; i++) + free(clear->ShortVBarStorage[i].pixels); + + free(clear); } diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 540d31331..96a17adb3 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -29,6 +29,7 @@ #include #include +#include #include int freerdp_get_pixel(BYTE* data, int x, int y, int width, int height, int bpp) @@ -378,6 +379,59 @@ UINT32 freerdp_color_convert_var_bgr(UINT32 srcColor, int srcBpp, int dstBpp, HC return freerdp_color_convert_rgb_bgr(srcColor, srcBpp, dstBpp, clrconv); } +UINT32 freerdp_convert_gdi_order_color(UINT32 color, int bpp, UINT32 format, BYTE* palette) +{ + UINT32 r = 0; + UINT32 g = 0; + UINT32 b = 0; + + switch (bpp) + { + case 32: + GetRGB32(r, g, b, color); + break; + + case 24: + GetRGB32(r, g, b, color); + break; + + case 16: + color = (color & (UINT32) 0xFF00) | ((color >> 16) & (UINT32) 0xFF); + GetRGB16(r, g, b, color); + break; + + case 15: + color = (color & (UINT32) 0xFF00) | ((color >> 16) & (UINT32) 0xFF); + GetRGB15(r, g, b, color); + break; + + case 8: + color = (color >> 16) & (UINT32) 0xFF; + if (palette) + { + r = palette[(color * 4) + 2]; + g = palette[(color * 4) + 1]; + b = palette[(color * 4) + 0]; + } + break; + + case 1: + r = g = b = 0; + if (color != 0) + r = g = b = 0xFF; + break; + + default: + return color; + break; + } + + if (FREERDP_PIXEL_FORMAT_TYPE(format) == FREERDP_PIXEL_FORMAT_TYPE_ABGR) + return BGR32(r, g, b); + + return RGB32(r, g, b); +} + BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv) { int i; @@ -391,18 +445,26 @@ BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int he if (dstBpp == 8) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height, 16); + + if (!dstData) + return NULL; + + CopyMemory(dstData, srcData, width * height); - memcpy(dstData, srcData, width * height); return dstData; } else if (dstBpp == 15 || (dstBpp == 16 && clrconv->rgb555)) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; + + dst16 = (UINT16*) dstData; - dst16 = (UINT16 *) dstData; for (i = width * height; i > 0; i--) { pixel = *srcData; @@ -414,14 +476,19 @@ BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int he *dst16 = pixel; dst16++; } + return dstData; } else if (dstBpp == 16) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; + + dst16 = (UINT16*) dstData; - dst16 = (UINT16 *) dstData; for (i = width * height; i > 0; i--) { pixel = *srcData; @@ -433,15 +500,20 @@ BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int he *dst16 = pixel; dst16++; } + return dstData; } else if (dstBpp == 32) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 4, 16); + + if (!dstData) + return NULL; src8 = (BYTE*) srcData; dst32 = (UINT32*) dstData; + for (i = width * height; i > 0; i--) { pixel = *src8; @@ -451,15 +523,16 @@ BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int he blue = clrconv->palette->entries[pixel].blue; if (clrconv->alpha) { - pixel = (clrconv->invert) ? ARGB32(0xFF, red, green, blue) : ABGR32(0xFF, red, green, blue); + pixel = (clrconv->invert) ? ABGR32(0xFF, red, green, blue) : ARGB32(0xFF, red, green, blue); } else { - pixel = (clrconv->invert) ? RGB32(red, green, blue) : BGR32(red, green, blue); + pixel = (clrconv->invert) ? BGR32(red, green, blue) : RGB32(red, green, blue); } *dst32 = pixel; dst32++; } + return dstData; } @@ -479,20 +552,27 @@ BYTE* freerdp_image_convert_15bpp(BYTE* srcData, BYTE* dstData, int width, int h if (dstBpp == 15 || (dstBpp == 16 && clrconv->rgb555)) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); - memcpy(dstData, srcData, width * height * 2); + if (!dstData) + return NULL; + + CopyMemory(dstData, srcData, width * height * 2); return dstData; } else if (dstBpp == 32) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 4, 16); + + if (!dstData) + return NULL; + + src16 = (UINT16*) srcData; + dst32 = (UINT32*) dstData; - src16 = (UINT16 *) srcData; - dst32 = (UINT32 *) dstData; for (i = width * height; i > 0; i--) { pixel = *src16; @@ -509,15 +589,20 @@ BYTE* freerdp_image_convert_15bpp(BYTE* srcData, BYTE* dstData, int width, int h *dst32 = pixel; dst32++; } + return dstData; } else if (dstBpp == 16) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; + + src16 = (UINT16*) srcData; + dst16 = (UINT16*) dstData; - src16 = (UINT16 *) srcData; - dst16 = (UINT16 *) dstData; for (i = width * height; i > 0; i--) { pixel = *src16; @@ -528,6 +613,7 @@ BYTE* freerdp_image_convert_15bpp(BYTE* srcData, BYTE* dstData, int width, int h *dst16 = pixel; dst16++; } + return dstData; } @@ -541,8 +627,11 @@ BYTE* freerdp_image_convert_16bpp(BYTE* srcData, BYTE* dstData, int width, int h if (dstBpp == 16) { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; if (clrconv->rgb555) { @@ -562,7 +651,7 @@ BYTE* freerdp_image_convert_16bpp(BYTE* srcData, BYTE* dstData, int width, int h } else { - memcpy(dstData, srcData, width * height * 2); + CopyMemory(dstData, srcData, width * height * 2); } return dstData; @@ -574,8 +663,11 @@ BYTE* freerdp_image_convert_16bpp(BYTE* srcData, BYTE* dstData, int width, int h UINT16 *src16; BYTE red, green, blue; - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 3); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 3, 16); + + if (!dstData) + return NULL; dst8 = (BYTE*) dstData; src16 = (UINT16*) srcData; @@ -598,76 +690,24 @@ BYTE* freerdp_image_convert_16bpp(BYTE* srcData, BYTE* dstData, int width, int h *dst8++ = blue; } } + return dstData; } else if (dstBpp == 32) { - int i; - UINT32 pixel; - UINT16* src16; - UINT32* dst32; - BYTE red, green, blue; + primitives_t* prims; - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); + if (!dstData) + dstData = _aligned_malloc(width * height * sizeof(UINT32), 16); - src16 = (UINT16*) srcData; - dst32 = (UINT32*) dstData; + if (!dstData) + return NULL; - if (clrconv->alpha) - { - if (clrconv->invert) - { - for (i = width * height; i > 0; i--) - { - pixel = *src16; - src16++; - GetBGR16(red, green, blue, pixel); - pixel = ARGB32(0xFF, red, green, blue); - *dst32 = pixel; - dst32++; - } - } - else - { - for (i = width * height; i > 0; i--) - { - pixel = *src16; - src16++; - GetBGR16(red, green, blue, pixel); - pixel = ABGR32(0xFF, red, green, blue); - *dst32 = pixel; - dst32++; - } - } - } - else - { - if (clrconv->invert) - { - for (i = width * height; i > 0; i--) - { - pixel = *src16; - src16++; - GetBGR16(red, green, blue, pixel); - pixel = RGB32(red, green, blue); - *dst32 = pixel; - dst32++; - } - } - else - { - for (i = width * height; i > 0; i--) - { - pixel = *src16; - src16++; - GetBGR16(red, green, blue, pixel); - pixel = BGR32(red, green, blue); - *dst32 = pixel; - dst32++; - } - } - } + prims = primitives_get(); + prims->RGB565ToARGB_16u32u_C3C4( + (const UINT16*) srcData, width * sizeof(UINT16), + (UINT32*) dstData, width * sizeof(UINT32), + width, height, clrconv->alpha, clrconv->invert); return dstData; } @@ -681,18 +721,93 @@ BYTE* freerdp_image_convert_24bpp(BYTE* srcData, BYTE* dstData, int width, int h if (dstBpp == 32) { - BYTE *dstp; - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); + UINT32 pixel, alpha_mask, temp; + UINT32* srcp; + UINT32* dstp; - dstp = dstData; - for (i = width * height; i > 0; i--) + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 4, 16); + + if (!dstData) + return NULL; + + alpha_mask = clrconv->alpha ? 0xFF000000 : 0; + + srcp = (UINT32*) srcData; + dstp = (UINT32*) dstData; + + if (clrconv->invert) { - *(dstp++) = *(srcData++); - *(dstp++) = *(srcData++); - *(dstp++) = *(srcData++); - *(dstp++) = 0xFF; + /* Each iteration handles four pixels using 32-bit load and + store operations. */ + for (i = ((width * height) / 4); i > 0; i--) + { + temp = 0; + + pixel = temp; + temp = *srcp++; + pixel |= temp & 0x00FFFFFF; + temp = temp >> 24; + *dstp++ = alpha_mask | RGB32_to_BGR32(pixel); + + pixel = temp; + temp = *srcp++; + pixel |= (temp & 0x0000FFFF) << 8; + temp = temp >> 16; + *dstp++ = alpha_mask | RGB32_to_BGR32(pixel); + + pixel = temp; + temp = *srcp++; + pixel |= (temp & 0x000000FF) << 16; + temp = temp >> 8; + *dstp++ = alpha_mask | RGB32_to_BGR32(pixel); + + *dstp++ = alpha_mask | RGB32_to_BGR32(temp); + } + + /* Handle any remainder. */ + for (i = (width * height) % 4; i > 0; i--) + { + pixel = ABGR32(alpha_mask, srcData[2], srcData[1], srcData[0]); + *dstp++ = pixel; + srcData += 3; + } } + else + { + for (i = ((width * height) / 4); i > 0; i--) + { + temp = 0; + + pixel = temp; + temp = *srcp++; + pixel |= temp & 0x00FFFFFF; + temp = temp >> 24; + *dstp++ = alpha_mask | pixel; + + pixel = temp; + temp = *srcp++; + pixel |= (temp & 0x0000FFFF) << 8; + temp = temp >> 16; + *dstp++ = alpha_mask | pixel; + + pixel = temp; + temp = *srcp++; + pixel |= (temp & 0x000000FF) << 16; + temp = temp >> 8; + *dstp++ = alpha_mask | pixel; + + *dstp++ = alpha_mask | temp; + } + + for (i = (width * height) % 4; i > 0; i--) + { + pixel = ARGB32(alpha_mask, srcData[2], srcData[1], srcData[0]); + *dstp++ = pixel; + srcData += 3; + } + } + return dstData; } @@ -708,8 +823,11 @@ BYTE* freerdp_image_convert_32bpp(BYTE* srcData, BYTE* dstData, int width, int h UINT32 *src32; BYTE red, green, blue; - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 2); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; dst16 = (UINT16*) dstData; src32 = (UINT32*) srcData; @@ -721,18 +839,23 @@ BYTE* freerdp_image_convert_32bpp(BYTE* srcData, BYTE* dstData, int width, int h src32++; dst16++; } + return dstData; } else if (dstBpp == 24) { - BYTE *dstp; int index; + BYTE* dstp; BYTE red, green, blue; - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 3); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 3, 16); + + if (!dstData) + return NULL; dstp = dstData; + for (index = 0; index < width * height; index++) { red = *(srcData++); @@ -754,37 +877,52 @@ BYTE* freerdp_image_convert_32bpp(BYTE* srcData, BYTE* dstData, int width, int h srcData++; } + return dstData; } else if (dstBpp == 32) { - if (clrconv->alpha) + int i; + UINT32 pixel; + UINT32 alpha_mask; + UINT32* srcp; + UINT32* dstp; + BYTE red, green, blue; + + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * 4, 16); + + if (!dstData) + return NULL; + + alpha_mask = clrconv->alpha ? 0xFF000000 : 0; + + srcp = (UINT32*) srcData; + dstp = (UINT32*) dstData; + + if (clrconv->invert) { - int x, y; - BYTE *dstp; - - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); - - memcpy(dstData, srcData, width * height * 4); - - dstp = dstData; - for (y = 0; y < height; y++) + for (i = width * height; i > 0; i--) { - for (x = 0; x < width * 4; x += 4) - { - dstp += 3; - *dstp = 0xFF; - dstp++; - } + pixel = *srcp; + srcp++; + GetRGB32(red, green, blue, pixel); + pixel = alpha_mask | BGR32(red, green, blue); + *dstp = pixel; + dstp++; } } else { - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * 4); - - memcpy(dstData, srcData, width * height * 4); + for (i = width * height; i > 0; i--) + { + pixel = *srcp; + srcp++; + GetRGB32(red, green, blue, pixel); + pixel = alpha_mask | RGB32(red, green, blue); + *dstp = pixel; + dstp++; + } } return dstData; @@ -828,7 +966,7 @@ void freerdp_bitmap_flip(BYTE * src, BYTE * dst, int scanLineSz, int height) * fixed size buffers (of max scanline size (or adaptative?) ) * -- would be much faster). */ - BYTE * tmpBfr = malloc(scanLineSz); + BYTE* tmpBfr = _aligned_malloc(scanLineSz, 16); int half = height / 2; /* Flip buffer in place by line permutations through the temp * scan line buffer. @@ -841,14 +979,14 @@ void freerdp_bitmap_flip(BYTE * src, BYTE * dst, int scanLineSz, int height) height--; for (i = 0; i < half ; i++) { - memcpy(tmpBfr, topLine, scanLineSz); - memcpy(topLine, bottomLine, scanLineSz); - memcpy(bottomLine, tmpBfr, scanLineSz); + CopyMemory(tmpBfr, topLine, scanLineSz); + CopyMemory(topLine, bottomLine, scanLineSz); + CopyMemory(bottomLine, tmpBfr, scanLineSz); topLine += scanLineSz; bottomLine -= scanLineSz; height--; } - free(tmpBfr); + _aligned_free(tmpBfr); } /* Flip from source buffer to destination buffer. */ else @@ -856,7 +994,7 @@ void freerdp_bitmap_flip(BYTE * src, BYTE * dst, int scanLineSz, int height) for (i = 0; i < height; i++) { - memcpy(bottomLine, topLine, scanLineSz); + CopyMemory(bottomLine, topLine, scanLineSz); topLine += scanLineSz; bottomLine -= scanLineSz; } @@ -870,10 +1008,14 @@ BYTE* freerdp_image_flip(BYTE* srcData, BYTE* dstData, int width, int height, in scanline = width * ((bpp + 7) / 8); - if (dstData == NULL) - dstData = (BYTE*) malloc(width * height * ((bpp + 7) / 8)); + if (!dstData) + dstData = (BYTE*) _aligned_malloc(width * height * ((bpp + 7) / 8), 16); + + if (!dstData) + return NULL; freerdp_bitmap_flip(srcData, dstData, scanline, height); + return dstData; } @@ -893,7 +1035,7 @@ BYTE* freerdp_icon_convert(BYTE* srcData, BYTE* dstData, BYTE* mask, int width, data = freerdp_image_flip(srcData, dstData, width, height, bpp); dstData = freerdp_image_convert(data, NULL, width, height, bpp, 32, clrconv); - free(data); + _aligned_free(data); /* Read the AND alpha plane */ if (bpp < 32) @@ -941,9 +1083,9 @@ BYTE* freerdp_icon_convert(BYTE* srcData, BYTE* dstData, BYTE* mask, int width, BYTE* freerdp_glyph_convert(int width, int height, BYTE* data) { int x, y; - BYTE *srcp; - BYTE *dstp; - BYTE *dstData; + BYTE* srcp; + BYTE* dstp; + BYTE* dstData; int scanline; /* @@ -953,8 +1095,12 @@ BYTE* freerdp_glyph_convert(int width, int height, BYTE* data) */ scanline = (width + 7) / 8; - dstData = (BYTE*) malloc(width * height); - memset(dstData, 0, width * height); + dstData = (BYTE*) _aligned_malloc(width * height, 16); + + if (!dstData) + return NULL; + + ZeroMemory(dstData, width * height); dstp = dstData; for (y = 0; y < height; y++) @@ -985,61 +1131,30 @@ BYTE* freerdp_mono_image_convert(BYTE* srcData, int width, int height, int srcBp int bitIndex; BYTE redBg, greenBg, blueBg; BYTE redFg, greenFg, blueFg; - - switch (srcBpp) - { - case 8: - bgcolor &= 0xFF; - redBg = clrconv->palette->entries[bgcolor].red; - greenBg = clrconv->palette->entries[bgcolor].green; - blueBg = clrconv->palette->entries[bgcolor].blue; - - fgcolor &= 0xFF; - redFg = clrconv->palette->entries[fgcolor].red; - greenFg = clrconv->palette->entries[fgcolor].green; - blueFg = clrconv->palette->entries[fgcolor].blue; - break; - - case 16: - GetRGB16(redBg, greenBg, blueBg, bgcolor); - GetRGB16(redFg, greenFg, blueFg, fgcolor); - break; - - case 15: - GetRGB15(redBg, greenBg, blueBg, bgcolor); - GetRGB15(redFg, greenFg, blueFg, fgcolor); - break; - - default: - GetRGB32(redBg, greenBg, blueBg, bgcolor); - GetRGB32(redFg, greenFg, blueFg, fgcolor); - break; - } + + GetRGB32(redBg, greenBg, blueBg, bgcolor); + GetRGB32(redFg, greenFg, blueFg, fgcolor); if (dstBpp == 16) { + dstData = (BYTE*) _aligned_malloc(width * height * 2, 16); + + if (!dstData) + return NULL; + + dst16 = (UINT16*) dstData; + if (clrconv->rgb555) { - if (srcBpp == 16) - { - /* convert 15-bit colors to 16-bit colors */ - RGB16_RGB15(redBg, greenBg, blueBg, bgcolor); - RGB16_RGB15(redFg, greenFg, blueFg, fgcolor); - } + bgcolor = clrconv->invert ? BGR15(redBg, greenBg, blueBg) : RGB15(redBg, greenBg, blueBg); + fgcolor = clrconv->invert ? BGR15(redFg, greenFg, blueFg) : RGB15(redFg, greenFg, blueFg); } else { - if (srcBpp == 15) - { - /* convert 15-bit colors to 16-bit colors */ - RGB15_RGB16(redBg, greenBg, blueBg, bgcolor); - RGB15_RGB16(redFg, greenFg, blueFg, fgcolor); - } + bgcolor = clrconv->invert ? BGR16(redBg, greenBg, blueBg) : RGB16(redBg, greenBg, blueBg); + fgcolor = clrconv->invert ? BGR16(redFg, greenFg, blueFg) : RGB16(redFg, greenFg, blueFg); } - dstData = (BYTE*) malloc(width * height * 2); - dst16 = (UINT16*) dstData; - for (index = height; index > 0; index--) { /* each bit encodes a pixel */ @@ -1062,7 +1177,11 @@ BYTE* freerdp_mono_image_convert(BYTE* srcData, int width, int height, int srcBp } else if (dstBpp == 32) { - dstData = (BYTE*) malloc(width * height * 4); + dstData = (BYTE*) _aligned_malloc(width * height * 4, 16); + + if (!dstData) + return NULL; + dst32 = (UINT32*) dstData; for (index = height; index > 0; index--) @@ -1074,11 +1193,25 @@ BYTE* freerdp_mono_image_convert(BYTE* srcData, int width, int height, int srcBp { if ((bitMask >> bitIndex) & 0x01) { - *dst32 = (clrconv->invert) ? BGR32(redBg, greenBg, blueBg) : RGB32(redBg, greenBg, blueBg); + if (clrconv->alpha) + { + *dst32 = (clrconv->invert) ? ABGR32(0xFF, redBg, greenBg, blueBg) : ARGB32(0xFF, redBg, greenBg, blueBg); + } + else + { + *dst32 = (clrconv->invert) ? BGR32(redBg, greenBg, blueBg) : RGB32(redBg, greenBg, blueBg); + } } else { - *dst32 = (clrconv->invert) ? BGR32(redFg, greenFg, blueFg) : RGB32(redFg, greenFg, blueFg); + if (clrconv->alpha) + { + *dst32 = (clrconv->invert) ? ABGR32(0xFF, redFg, greenFg, blueFg) : ARGB32(0xFF, redFg, greenFg, blueFg); + } + else + { + *dst32 = (clrconv->invert) ? BGR32(redFg, greenFg, blueFg) : RGB32(redFg, greenFg, blueFg); + } } dst32++; } @@ -1148,227 +1281,1822 @@ HCLRCONV freerdp_clrconv_new(UINT32 flags) { HCLRCONV clrconv; - clrconv = (CLRCONV*) malloc(sizeof(CLRCONV)); - ZeroMemory(clrconv, sizeof(CLRCONV)); + clrconv = (CLRCONV*) calloc(1, sizeof(CLRCONV)); + + if (!clrconv) + return NULL; clrconv->alpha = (flags & CLRCONV_ALPHA) ? TRUE : FALSE; clrconv->invert = (flags & CLRCONV_INVERT) ? TRUE : FALSE; clrconv->rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE; - clrconv->palette = (rdpPalette*) malloc(sizeof(rdpPalette)); - ZeroMemory(clrconv->palette, sizeof(rdpPalette)); + clrconv->palette = (rdpPalette*) calloc(1, sizeof(rdpPalette)); + + if (!clrconv->palette) + return NULL; return clrconv; } void freerdp_clrconv_free(HCLRCONV clrconv) { - if (clrconv != NULL) + if (clrconv) { - if (clrconv->palette != NULL) + if (clrconv->palette) free(clrconv->palette); free(clrconv); } } -int freerdp_image_copy(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, - int nWidth, int nHeight, BYTE* pSrcData, DWORD dwSrcFormat, int nSrcStep, int nXSrc, int nYSrc) +int freerdp_image8_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) { + BYTE* pe; int x, y; int srcFlip; int dstFlip; - BYTE a, r, g, b; - int beg, end, inc; + int nSrcPad; + int nDstPad; int srcBitsPerPixel; int srcBytesPerPixel; int dstBitsPerPixel; int dstBytesPerPixel; - BOOL overlap = FALSE; BOOL vFlip = FALSE; + BOOL invert = FALSE; - srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(dwSrcFormat); - srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(dwSrcFormat) / 8); - srcFlip = FREERDP_PIXEL_FORMAT_FLIP(dwSrcFormat); + if (!palette) + return -1; - dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(dwDstFormat); - dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(dwDstFormat) / 8); - dstFlip = FREERDP_PIXEL_FORMAT_FLIP(dwDstFormat); + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + srcFlip = FREERDP_PIXEL_FORMAT_FLIP(SrcFormat); + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat); + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); if (srcFlip != dstFlip) vFlip = TRUE; - if (pDstData == pSrcData) - { - overlap = (((nXDst + nWidth) > nXSrc) && (nXDst < (nXSrc + nWidth)) && - ((nYDst + nHeight) > nYSrc) && (nYDst < (nYSrc + nHeight))) ? TRUE : FALSE; - } + invert = FREERDP_PIXEL_FORMAT_IS_ABGR(DstFormat) ? TRUE : FALSE; - if (srcBytesPerPixel == 4) + if (dstBytesPerPixel == 4) { - if (nSrcStep < 0) - nSrcStep = srcBytesPerPixel * nWidth; - - if (srcBitsPerPixel == 24) + if ((dstBitsPerPixel == 32) || (dstBitsPerPixel == 24)) { - if (dstBytesPerPixel == 4) /* srcBytesPerPixel == dstBytesPerPixel */ + BYTE* pSrcPixel; + UINT32* pDstPixel; + + if (!invert) { - if (dstBitsPerPixel == 32) + if (!vFlip) { - UINT32* pSrcPixel; - UINT32* pDstPixel; - - if (nDstStep < 0) - nDstStep = dstBytesPerPixel * nWidth; - - pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * dstBytesPerPixel)]; + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { - GetARGB32(a, r, g, b, *pSrcPixel); - *pDstPixel = ARGB32(a, r, g, b); + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB32(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB32(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR32(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR32(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 3) + { + + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + BYTE* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB16(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB16(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR16(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR16(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + else if (dstBitsPerPixel == 15) + { + BYTE* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB15(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = RGB15(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR15(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pe = &palette[*pSrcPixel * 4]; + *pDstPixel++ = BGR15(pe[2], pe[1], pe[0]); + pSrcPixel++; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 1) + { + BYTE* pSrcPixel; + BYTE* pDstPixel; + + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + nXSrc]; + pDstPixel = &pDstData[(nYDst * nDstStep) + nXDst]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth); + pSrcPixel = &pSrcPixel[nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + nXSrc]; + pDstPixel = &pDstData[(nYDst * nDstStep) + nXDst]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth); + pSrcPixel = &pSrcPixel[-nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + + return 1; + } + + return -1; +} + +int freerdp_image15_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) +{ + int x, y; + int srcFlip; + int dstFlip; + int nSrcPad; + int nDstPad; + BYTE r, g, b; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + int srcType, dstType; + BOOL vFlip = FALSE; + BOOL invert = FALSE; + + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + srcFlip = FREERDP_PIXEL_FORMAT_FLIP(SrcFormat); + srcType = FREERDP_PIXEL_FORMAT_TYPE(SrcFormat); + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat); + dstType = FREERDP_PIXEL_FORMAT_TYPE(DstFormat); + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + + if (srcFlip != dstFlip) + vFlip = TRUE; + + if (srcType != dstType) + invert = TRUE; + + if (dstBytesPerPixel == 4) + { + if ((dstBitsPerPixel == 32) || (dstBitsPerPixel == 24)) + { + UINT16* pSrcPixel; + UINT32* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = ARGB32(0xFF, r, g, b); pSrcPixel++; pDstPixel++; } - pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[(nSrcStep - (nWidth * srcBytesPerPixel))]; - pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[(nDstStep - (nWidth * dstBytesPerPixel))]; + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; } } - else if (dstBitsPerPixel == 24) /* srcBitsPerPixel == dstBitsPerPixel */ + else { - UINT32* pSrcPixel; - UINT32* pDstPixel; + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; - if (nDstStep < 0) - nDstStep = dstBytesPerPixel * nWidth; - - if (overlap && (nYSrc < nYDst)) + for (y = 0; y < nHeight; y++) { - beg = nHeight - 1; - inc = -1; /* downward copy */ - end = -1; - } - else - { - beg = 0; - inc = 1; /* upward copy */ - end = nHeight; - } - - if (!vFlip) - { - for (y = beg; y != end; y += inc) + for (x = 0; x < nWidth; x++) { - pSrcPixel = (UINT32*) &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (UINT32*) &pDstData[((nYDst + y) * nDstStep) + (nXDst * dstBytesPerPixel)]; - MoveMemory(pDstPixel, pSrcPixel, nWidth * 4); - } - } - else - { - for (y = beg; y != end; y += inc) - { - pSrcPixel = (UINT32*) &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (UINT32*) &pDstData[((nYDst + (nHeight - y - 1)) * nDstStep) + (nXDst * dstBytesPerPixel)]; - MoveMemory(pDstPixel, pSrcPixel, nWidth * 4); + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = ARGB32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; } } } - else if (dstBytesPerPixel == 3) + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = ABGR32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = ABGR32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + UINT16* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = RGB16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = RGB16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = BGR16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = BGR16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + else if (dstBitsPerPixel == 15) + { + UINT16* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = RGB15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = RGB15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = BGR15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB15(r, g, b, *pSrcPixel); + *pDstPixel = BGR15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + + return -1; +} + +int freerdp_image16_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) +{ + int x, y; + int srcFlip; + int dstFlip; + int nSrcPad; + int nDstPad; + BYTE r, g, b; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + int srcType, dstType; + BOOL vFlip = FALSE; + BOOL invert = FALSE; + + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + srcFlip = FREERDP_PIXEL_FORMAT_FLIP(SrcFormat); + srcType = FREERDP_PIXEL_FORMAT_TYPE(SrcFormat); + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat); + dstType = FREERDP_PIXEL_FORMAT_TYPE(DstFormat); + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + + if (srcFlip != dstFlip) + vFlip = TRUE; + + if (srcType != dstType) + invert = TRUE; + + if (dstBytesPerPixel == 4) + { + if ((dstBitsPerPixel == 32) || (dstBitsPerPixel == 24)) + { + UINT16* pSrcPixel; + UINT32* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = ARGB32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = ARGB32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = ABGR32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = ABGR32(0xFF, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + UINT16* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * 2); + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcStep]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstStep]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * 2); + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-nSrcStep]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstStep]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = BGR16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = BGR16(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + else if (dstBitsPerPixel == 15) + { + UINT16* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = RGB15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = RGB15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = (UINT16*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = BGR15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = (UINT16*) &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 2)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB16(r, g, b, *pSrcPixel); + *pDstPixel = BGR15(r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT16*) &((BYTE*) pSrcPixel)[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + + return -1; +} + +int freerdp_image24_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) +{ + int x, y; + int srcFlip; + int dstFlip; + int nSrcPad; + int nDstPad; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + int srcType, dstType; + BOOL vFlip = FALSE; + BOOL invert = FALSE; + + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + srcFlip = FREERDP_PIXEL_FORMAT_FLIP(SrcFormat); + srcType = FREERDP_PIXEL_FORMAT_TYPE(SrcFormat); + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat); + dstType = FREERDP_PIXEL_FORMAT_TYPE(DstFormat); + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + + if (srcFlip != dstFlip) + vFlip = TRUE; + + if (srcType != dstType) + invert = TRUE; + + if (dstBytesPerPixel == 4) + { + if ((dstBitsPerPixel == 32) || (dstBitsPerPixel == 24)) + { + BYTE* pSrcPixel; + BYTE* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = 0xFF; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = *pSrcPixel++; + *pDstPixel++ = 0xFF; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + pDstPixel[3] = 0xFF; + + pSrcPixel += 4; + pDstPixel += 4; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + pDstPixel[3] = 0xFF; + + pSrcPixel += 4; + pDstPixel += 4; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 3) + { + BYTE* pSrcPixel; + BYTE* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * 3); + pSrcPixel = &pSrcPixel[nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * 3); + pSrcPixel = &pSrcPixel[-nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + + pSrcPixel += 3; + pDstPixel += 3; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + + pSrcPixel += 3; + pDstPixel += 3; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + } + + return 1; + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + BYTE* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB16(pSrcPixel[2], pSrcPixel[1], pSrcPixel[0]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB16(pSrcPixel[2], pSrcPixel[1], pSrcPixel[0]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB16(pSrcPixel[0], pSrcPixel[1], pSrcPixel[2]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB16(pSrcPixel[0], pSrcPixel[1], pSrcPixel[2]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + else if (dstBitsPerPixel == 15) + { + BYTE* pSrcPixel; + UINT16* pDstPixel; + + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB15(pSrcPixel[2], pSrcPixel[1], pSrcPixel[0]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB15(pSrcPixel[2], pSrcPixel[1], pSrcPixel[0]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB15(pSrcPixel[0], pSrcPixel[1], pSrcPixel[2]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = RGB15(pSrcPixel[0], pSrcPixel[1], pSrcPixel[2]); + pSrcPixel += 3; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &((UINT16*) pDstPixel)[nDstPad]; + } + } + } + + return 1; + } + } + + return -1; +} + +int freerdp_image32_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) +{ + int x, y; + int srcFlip; + int dstFlip; + int nSrcPad; + int nDstPad; + BYTE a, r, g, b; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + int srcType, dstType; + BOOL vFlip = FALSE; + BOOL invert = FALSE; + + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + srcFlip = FREERDP_PIXEL_FORMAT_FLIP(SrcFormat); + srcType = FREERDP_PIXEL_FORMAT_TYPE(SrcFormat); + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat); + dstType = FREERDP_PIXEL_FORMAT_TYPE(DstFormat); + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + + if (srcFlip != dstFlip) + vFlip = TRUE; + + if (srcType != dstType) + invert = TRUE; + + if (srcBitsPerPixel == 24) + { + if (dstBytesPerPixel == 4) /* srcBytesPerPixel == dstBytesPerPixel */ + { + if (dstBitsPerPixel == 32) { UINT32* pSrcPixel; + UINT32* pDstPixel; + + pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = (UINT32*) &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + if (!invert) + { + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + *pDstPixel++ = *pSrcPixel++; + } + + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + else + { + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetARGB32(a, r, g, b, *pSrcPixel); + *pDstPixel = ABGR32(a, r, g, b); + + pSrcPixel++; + pDstPixel++; + } + + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT32*) &((BYTE*) pDstPixel)[nDstPad]; + } + } + + return 1; + } + else if (dstBitsPerPixel == 24) /* srcBitsPerPixel == dstBitsPerPixel */ + { + BYTE* pSrcPixel; BYTE* pDstPixel; - if (nDstStep < 0) - nDstStep = dstBytesPerPixel * nWidth; + if (!invert) + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; - pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (BYTE*) &pDstData[(nYDst * nDstStep) + (nXDst * dstBytesPerPixel)]; + for (y = 0; y < nHeight; y++) + { + MoveMemory(pDstPixel, pSrcPixel, nWidth * 4); + pSrcPixel = &pSrcPixel[nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + MoveMemory(pDstPixel, pSrcPixel, nWidth * 4); + pSrcPixel = &pSrcPixel[-nSrcStep]; + pDstPixel = &pDstPixel[nDstStep]; + } + } + } + else + { + if (!vFlip) + { + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + pDstPixel[3] = 0xFF; + + pSrcPixel += 4; + pDstPixel += 4; + } + + pSrcPixel = &pSrcPixel[nSrcPad]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + else + { + pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + pDstPixel[0] = pSrcPixel[2]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[0]; + pDstPixel[3] = 0xFF; + + pSrcPixel += 4; + pDstPixel += 4; + } + + pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + } + + return 1; + } + } + else if (dstBytesPerPixel == 3) + { + UINT32* pSrcPixel; + BYTE* pDstPixel; + + pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = (BYTE*) &pDstData[(nYDst * nDstStep) + (nXDst * 3)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + GetRGB32(r, g, b, *pSrcPixel); + + *pDstPixel++ = r; + *pDstPixel++ = g; + *pDstPixel++ = b; + + pSrcPixel++; + } + + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcStep]; + pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[nDstStep]; + } + + return 1; + } + else if (dstBytesPerPixel == 2) + { + if (dstBitsPerPixel == 16) + { + UINT32* pSrcPixel; + UINT16* pDstPixel; + + pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; for (y = 0; y < nHeight; y++) { for (x = 0; x < nWidth; x++) { GetRGB32(r, g, b, *pSrcPixel); - - *(pDstPixel++) = r; - *(pDstPixel++) = g; - *(pDstPixel++) = b; + RGB_888_565(r, g, b); + *pDstPixel = RGB565(r, g, b); pSrcPixel++; + pDstPixel++; } - pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[(nSrcStep - (nWidth * srcBytesPerPixel))]; - pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[(nDstStep - (nWidth * dstBytesPerPixel))]; + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; } + + return 1; } - else if (dstBytesPerPixel == 2) + else if (dstBitsPerPixel == 15) { - if (dstBitsPerPixel == 16) + UINT32* pSrcPixel; + UINT16* pDstPixel; + + pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * 2)]; + + for (y = 0; y < nHeight; y++) { - UINT32* pSrcPixel; - UINT16* pDstPixel; - - if (nDstStep < 0) - nDstStep = dstBytesPerPixel * nWidth; - - pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * dstBytesPerPixel)]; - - for (y = 0; y < nHeight; y++) + for (x = 0; x < nWidth; x++) { - for (x = 0; x < nWidth; x++) - { - GetRGB32(r, g, b, *pSrcPixel); - RGB_888_565(r, g, b); - *pDstPixel = RGB565(r, g, b); + GetRGB32(r, g, b, *pSrcPixel); + RGB_888_555(r, g, b); + *pDstPixel = RGB555(r, g, b); - pSrcPixel++; - pDstPixel++; - } - - pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[(nSrcStep - (nWidth * srcBytesPerPixel))]; - pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[(nDstStep - (nWidth * dstBytesPerPixel))]; + pSrcPixel++; + pDstPixel++; } + + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[nDstPad]; } - else if (dstBitsPerPixel == 15) - { - UINT32* pSrcPixel; - UINT16* pDstPixel; - if (nDstStep < 0) - nDstStep = dstBytesPerPixel * nWidth; - - pSrcPixel = (UINT32*) &pSrcData[(nYSrc * nSrcStep) + (nXSrc * srcBytesPerPixel)]; - pDstPixel = (UINT16*) &pDstData[(nYDst * nDstStep) + (nXDst * dstBytesPerPixel)]; - - for (y = 0; y < nHeight; y++) - { - for (x = 0; x < nWidth; x++) - { - GetRGB32(r, g, b, *pSrcPixel); - RGB_888_555(r, g, b); - *pDstPixel = RGB555(r, g, b); - - pSrcPixel++; - pDstPixel++; - } - - pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[(nSrcStep - (nWidth * srcBytesPerPixel))]; - pDstPixel = (UINT16*) &((BYTE*) pDstPixel)[(nDstStep - (nWidth * dstBytesPerPixel))]; - } - } + return 1; } } } - return 0; + return -1; +} + +int freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette) +{ + int status = -1; + int srcBitsPerPixel; + int srcBytesPerPixel; + + srcBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(SrcFormat); + srcBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(SrcFormat) / 8); + + if (srcBytesPerPixel == 4) + { + status = freerdp_image32_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + } + else if (srcBytesPerPixel == 3) + { + status = freerdp_image24_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + } + else if (srcBytesPerPixel == 2) + { + if (srcBitsPerPixel == 16) + { + status = freerdp_image16_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + } + else if (srcBitsPerPixel == 15) + { + status = freerdp_image15_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + } + } + else if (srcBytesPerPixel == 1) + { + status = freerdp_image8_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + } + + if (status < 0) + { + int dstBitsPerPixel; + int dstBytesPerPixel; + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + + fprintf(stderr, "freerdp_image_copy failure: src: %d/%d dst: %d/%d\n", + srcBitsPerPixel, srcBytesPerPixel, dstBitsPerPixel, dstBytesPerPixel); + } + + return status; +} + +int freerdp_image_move(BYTE* pData, DWORD Format, int nStep, int nXDst, int nYDst, int nWidth, int nHeight, int nXSrc, int nYSrc) +{ + int y; + BOOL overlap; + BYTE* pSrcPixel; + BYTE* pDstPixel; + int bytesPerPixel; + + bytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(Format) / 8); + + if (nStep < 0) + nStep = nWidth * bytesPerPixel; + + overlap = (((nXDst + nWidth) > nXSrc) && (nXDst < (nXSrc + nWidth)) && + ((nYDst + nHeight) > nYSrc) && (nYDst < (nYSrc + nHeight))) ? TRUE : FALSE; + + if (!overlap) + { + pSrcPixel = &pData[(nYSrc * nStep) + (nXSrc * bytesPerPixel)]; + pDstPixel = &pData[(nYDst * nStep) + (nXDst * bytesPerPixel)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * bytesPerPixel); + pSrcPixel += nStep; + pDstPixel += nStep; + } + + return 1; + } + + if (nYSrc < nYDst) + { + /* copy down */ + + pSrcPixel = &pData[((nYSrc + nHeight - 1) * nStep) + (nXSrc * bytesPerPixel)]; + pDstPixel = &pData[((nYDst + nHeight - 1) * nStep) + (nXDst * bytesPerPixel)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * bytesPerPixel); + pSrcPixel -= nStep; + pDstPixel -= nStep; + } + } + else if (nYSrc > nYDst) + { + /* copy up */ + + pSrcPixel = &pData[(nYSrc * nStep) + (nXSrc * bytesPerPixel)]; + pDstPixel = &pData[(nYDst * nStep) + (nXDst * bytesPerPixel)]; + + for (y = 0; y < nHeight; y++) + { + CopyMemory(pDstPixel, pSrcPixel, nWidth * bytesPerPixel); + pSrcPixel += nStep; + pDstPixel += nStep; + } + } + else if (nXSrc > nXDst) + { + /* copy left */ + + pSrcPixel = &pData[(nYSrc * nStep) + (nXSrc * bytesPerPixel)]; + pDstPixel = &pData[(nYDst * nStep) + (nXDst * bytesPerPixel)]; + + for (y = 0; y < nHeight; y++) + { + MoveMemory(pDstPixel, pSrcPixel, nWidth * bytesPerPixel); + pSrcPixel += nStep; + pDstPixel += nStep; + } + } + else + { + /* copy right */ + + pSrcPixel = &pData[(nYSrc * nStep) + (nXSrc * bytesPerPixel)]; + pDstPixel = &pData[(nYDst * nStep) + (nXDst * bytesPerPixel)]; + + for (y = 0; y < nHeight; y++) + { + MoveMemory(pDstPixel, pSrcPixel, nWidth * bytesPerPixel); + pSrcPixel += nStep; + pDstPixel += nStep; + } + } + + return 1; } void* freerdp_image_memset32(UINT32* ptr, UINT32 fill, size_t length) @@ -1381,15 +3109,15 @@ void* freerdp_image_memset32(UINT32* ptr, UINT32 fill, size_t length) return (void*) ptr; } -int freerdp_image_fill(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDst, int nYDst, +int freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, UINT32 color) { int y; int dstBitsPerPixel; int dstBytesPerPixel; - dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(dwDstFormat); - dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(dwDstFormat) / 8); + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); if (dstBytesPerPixel == 4) { @@ -1423,3 +3151,62 @@ int freerdp_image_fill(BYTE* pDstData, DWORD dwDstFormat, int nDstStep, int nXDs return 0; } +int freerdp_image_copy_from_retina(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc) +{ + int x, y; + int nSrcPad; + int nDstPad; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + + srcBitsPerPixel = 24; + srcBytesPerPixel = 8; + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + + if (dstBytesPerPixel == 4) + { + UINT32 R, G, B; + BYTE* pSrcPixel; + BYTE* pDstPixel; + + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + /* simple box filter scaling, could be improved with better algorithm */ + + B = pSrcPixel[0] + pSrcPixel[4] + pSrcPixel[nSrcStep + 0] + pSrcPixel[nSrcStep + 4]; + G = pSrcPixel[1] + pSrcPixel[5] + pSrcPixel[nSrcStep + 1] + pSrcPixel[nSrcStep + 5]; + R = pSrcPixel[2] + pSrcPixel[6] + pSrcPixel[nSrcStep + 2] + pSrcPixel[nSrcStep + 6]; + pSrcPixel += 8; + + *pDstPixel++ = (BYTE) (B >> 2); + *pDstPixel++ = (BYTE) (G >> 2); + *pDstPixel++ = (BYTE) (R >> 2); + *pDstPixel++ = 0xFF; + } + + pSrcPixel = &pSrcPixel[nSrcPad + nSrcStep]; + pDstPixel = &pDstPixel[nDstPad]; + } + } + + return 1; +} diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c new file mode 100644 index 000000000..d5504dc3a --- /dev/null +++ b/libfreerdp/codec/h264.c @@ -0,0 +1,551 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2014 Mike McDonald + * + * 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 +#include +#include + +#define TAG FREERDP_TAG("codec") + +/** + * Dummy subsystem + */ + +static int dummy_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +{ + return -1; +} + +static void dummy_uninit(H264_CONTEXT* h264) +{ + +} + +static BOOL dummy_init(H264_CONTEXT* h264) +{ + return TRUE; +} + +static H264_CONTEXT_SUBSYSTEM g_Subsystem_dummy = +{ + "dummy", + dummy_init, + dummy_uninit, + dummy_decompress +}; + +/** + * OpenH264 subsystem + */ + +#ifdef WITH_OPENH264 + +#include "wels/codec_def.h" +#include "wels/codec_api.h" + +struct _H264_CONTEXT_OPENH264 +{ + ISVCDecoder* pDecoder; +}; +typedef struct _H264_CONTEXT_OPENH264 H264_CONTEXT_OPENH264; + +static BOOL g_openh264_trace_enabled = FALSE; + +static void openh264_trace_callback(H264_CONTEXT* h264, int level, const char* message) +{ + WLog_INFO(TAG, "%d - %s", level, message); +} + +static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +{ + DECODING_STATE state; + SBufferInfo sBufferInfo; + SSysMEMBuffer* pSystemBuffer; + H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; + + if (!sys->pDecoder) + return -1; + + /* + * Decompress the image. The RDP host only seems to send I420 format. + */ + + h264->pYUVData[0] = NULL; + h264->pYUVData[1] = NULL; + h264->pYUVData[2] = NULL; + + ZeroMemory(&sBufferInfo, sizeof(sBufferInfo)); + + state = (*sys->pDecoder)->DecodeFrame2( + sys->pDecoder, + pSrcData, + SrcSize, + h264->pYUVData, + &sBufferInfo); + + /** + * Calling DecodeFrame2 twice apparently works around Openh264 issue #1136: + * https://github.com/cisco/openh264/issues/1136 + * + * This is a hack, but it works and it is only necessary for the first frame. + */ + + if (sBufferInfo.iBufferStatus != 1) + state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, h264->pYUVData, &sBufferInfo); + + pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer; + +#if 0 + WLog_INFO(TAG, "h264_decompress: state=%u, pYUVData=[%p,%p,%p], bufferStatus=%d, width=%d, height=%d, format=%d, stride=[%d,%d]", + state, h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2], sBufferInfo.iBufferStatus, + pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iFormat, + pSystemBuffer->iStride[0], pSystemBuffer->iStride[1]); +#endif + + if (state != 0) + return -1; + + if (sBufferInfo.iBufferStatus != 1) + return -2; + + if (pSystemBuffer->iFormat != videoFormatI420) + return -1; + + if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2]) + return -1; + + h264->iStride[0] = pSystemBuffer->iStride[0]; + h264->iStride[1] = pSystemBuffer->iStride[1]; + h264->iStride[2] = pSystemBuffer->iStride[1]; + + h264->width = pSystemBuffer->iWidth; + h264->height = pSystemBuffer->iHeight; + + return 1; +} + +static void openh264_uninit(H264_CONTEXT* h264) +{ + H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; + + if (sys) + { + if (sys->pDecoder) + { + (*sys->pDecoder)->Uninitialize(sys->pDecoder); + WelsDestroyDecoder(sys->pDecoder); + sys->pDecoder = NULL; + } + + free(sys); + h264->pSystemData = NULL; + } +} + +static BOOL openh264_init(H264_CONTEXT* h264) +{ + long status; + SDecodingParam sDecParam; + H264_CONTEXT_OPENH264* sys; + static int traceLevel = WELS_LOG_DEBUG; + static EVideoFormatType videoFormat = videoFormatI420; + static WelsTraceCallback traceCallback = (WelsTraceCallback) openh264_trace_callback; + + sys = (H264_CONTEXT_OPENH264*) calloc(1, sizeof(H264_CONTEXT_OPENH264)); + + if (!sys) + { + goto EXCEPTION; + } + + h264->pSystemData = (void*) sys; + + WelsCreateDecoder(&sys->pDecoder); + + if (!sys->pDecoder) + { + WLog_ERR(TAG, "Failed to create OpenH264 decoder"); + goto EXCEPTION; + } + + ZeroMemory(&sDecParam, sizeof(sDecParam)); + sDecParam.iOutputColorFormat = videoFormatI420; + sDecParam.uiEcActiveFlag = 1; + sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + + status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to initialize OpenH264 decoder (status=%ld)", status); + goto EXCEPTION; + } + + status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set data format option on OpenH264 decoder (status=%ld)", status); + } + + if (g_openh264_trace_enabled) + { + status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace level option on OpenH264 decoder (status=%ld)", status); + } + + status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, &traceCallback); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace callback option on OpenH264 decoder (status=%ld)", status); + } + + status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &h264); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace callback context option on OpenH264 decoder (status=%ld)", status); + } + } + + return TRUE; + +EXCEPTION: + openh264_uninit(h264); + + return FALSE; +} + +static H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264 = +{ + "OpenH264", + openh264_init, + openh264_uninit, + openh264_decompress +}; + +#endif + +/** + * libavcodec subsystem + */ + +#ifdef WITH_LIBAVCODEC + +#include +#include + +struct _H264_CONTEXT_LIBAVCODEC +{ + AVCodec* codec; + AVCodecContext* codecContext; + AVCodecParserContext* codecParser; + AVFrame* videoFrame; +}; +typedef struct _H264_CONTEXT_LIBAVCODEC H264_CONTEXT_LIBAVCODEC; + +static int libavcodec_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +{ + int status; + int gotFrame = 0; + AVPacket packet; + H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*) h264->pSystemData; + + av_init_packet(&packet); + + packet.data = pSrcData; + packet.size = SrcSize; + + status = avcodec_decode_video2(sys->codecContext, sys->videoFrame, &gotFrame, &packet); + + if (status < 0) + { + WLog_ERR(TAG, "Failed to decode video frame (status=%d)", status); + return -1; + } + +#if 0 + WLog_INFO(TAG, "libavcodec_decompress: frame decoded (status=%d, gotFrame=%d, width=%d, height=%d, Y=[%p,%d], U=[%p,%d], V=[%p,%d])", + status, gotFrame, sys->videoFrame->width, sys->videoFrame->height, + sys->videoFrame->data[0], sys->videoFrame->linesize[0], + sys->videoFrame->data[1], sys->videoFrame->linesize[1], + sys->videoFrame->data[2], sys->videoFrame->linesize[2]); +#endif + + if (gotFrame) + { + h264->pYUVData[0] = sys->videoFrame->data[0]; + h264->pYUVData[1] = sys->videoFrame->data[1]; + h264->pYUVData[2] = sys->videoFrame->data[2]; + + h264->iStride[0] = sys->videoFrame->linesize[0]; + h264->iStride[1] = sys->videoFrame->linesize[1]; + h264->iStride[2] = sys->videoFrame->linesize[2]; + + h264->width = sys->videoFrame->width; + h264->height = sys->videoFrame->height; + } + else + return -2; + + return 1; +} + +static void libavcodec_uninit(H264_CONTEXT* h264) +{ + H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*) h264->pSystemData; + + if (!sys) + return; + + if (sys->videoFrame) + { + av_free(sys->videoFrame); + } + + if (sys->codecParser) + { + av_parser_close(sys->codecParser); + } + + if (sys->codecContext) + { + avcodec_close(sys->codecContext); + av_free(sys->codecContext); + } + + free(sys); + h264->pSystemData = NULL; +} + +static BOOL libavcodec_init(H264_CONTEXT* h264) +{ + H264_CONTEXT_LIBAVCODEC* sys; + + sys = (H264_CONTEXT_LIBAVCODEC*) calloc(1, sizeof(H264_CONTEXT_LIBAVCODEC)); + + if (!sys) + { + goto EXCEPTION; + } + + h264->pSystemData = (void*) sys; + + avcodec_register_all(); + + sys->codec = avcodec_find_decoder(CODEC_ID_H264); + + if (!sys->codec) + { + WLog_ERR(TAG, "Failed to find libav H.264 codec"); + goto EXCEPTION; + } + + sys->codecContext = avcodec_alloc_context3(sys->codec); + + if (!sys->codecContext) + { + WLog_ERR(TAG, "Failed to allocate libav codec context"); + goto EXCEPTION; + } + + if (sys->codec->capabilities & CODEC_CAP_TRUNCATED) + { + sys->codecContext->flags |= CODEC_FLAG_TRUNCATED; + } + + if (avcodec_open2(sys->codecContext, sys->codec, NULL) < 0) + { + WLog_ERR(TAG, "Failed to open libav codec"); + goto EXCEPTION; + } + + sys->codecParser = av_parser_init(CODEC_ID_H264); + + if (!sys->codecParser) + { + WLog_ERR(TAG, "Failed to initialize libav parser"); + goto EXCEPTION; + } + + sys->videoFrame = avcodec_alloc_frame(); + + if (!sys->videoFrame) + { + WLog_ERR(TAG, "Failed to allocate libav frame"); + goto EXCEPTION; + } + + return TRUE; + +EXCEPTION: + libavcodec_uninit(h264); + + return FALSE; +} + +static H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = +{ + "libavcodec", + libavcodec_init, + libavcodec_uninit, + libavcodec_decompress +}; + +#endif + +int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstHeight, RDPGFX_RECT16* regionRects, int numRegionRects) +{ + int index; + int status; + int* iStride; + BYTE* pDstData; + BYTE* pDstPoint; + prim_size_t roi; + BYTE** pYUVData; + int width, height; + BYTE* pYUVPoint[3]; + RDPGFX_RECT16* rect; + int UncompressedSize; + primitives_t *prims = primitives_get(); + + if (!h264) + return -1; + +#if 0 + WLog_INFO(TAG, "h264_decompress: pSrcData=%p, SrcSize=%u, pDstData=%p, nDstStep=%d, nDstHeight=%d, numRegionRects=%d", + pSrcData, SrcSize, *ppDstData, nDstStep, nDstHeight, numRegionRects); +#endif + + if (!(pDstData = *ppDstData)) + return -1; + + if ((status = h264->subsystem->Decompress(h264, pSrcData, SrcSize)) < 0) + return status; + + UncompressedSize = h264->width * h264->height * 4; + + if (UncompressedSize > (nDstStep * nDstHeight)) + return -1; + + pYUVData = h264->pYUVData; + iStride = h264->iStride; + + for (index = 0; index < numRegionRects; index++) + { + rect = &(regionRects[index]); + + width = rect->right - rect->left; + height = rect->bottom - rect->top; + + pDstPoint = pDstData + rect->top * nDstStep + rect->left * 4; + pYUVPoint[0] = pYUVData[0] + rect->top * iStride[0] + rect->left; + + pYUVPoint[1] = pYUVData[1] + rect->top/2 * iStride[1] + rect->left/2; + pYUVPoint[2] = pYUVData[2] + rect->top/2 * iStride[2] + rect->left/2; + +#if 0 + WLog_INFO(TAG, "regionRect: x: %d y: %d width: %d height: %d", + rect->left, rect->top, width, height); +#endif + + roi.width = width; + roi.height = height; + + prims->YUV420ToRGB_8u_P3AC4R((const BYTE**) pYUVPoint, iStride, pDstPoint, nDstStep, &roi); + } + + return 1; +} + +int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) +{ + return 1; +} + +BOOL h264_context_init(H264_CONTEXT* h264) +{ +#ifdef WITH_LIBAVCODEC + if (g_Subsystem_libavcodec.Init(h264)) + { + h264->subsystem = &g_Subsystem_libavcodec; + return TRUE; + } +#endif + +#ifdef WITH_OPENH264 + if (g_Subsystem_OpenH264.Init(h264)) + { + h264->subsystem = &g_Subsystem_OpenH264; + return TRUE; + } +#endif + + return FALSE; +} + +int h264_context_reset(H264_CONTEXT* h264) +{ + return 1; +} + +H264_CONTEXT* h264_context_new(BOOL Compressor) +{ + H264_CONTEXT* h264; + + h264 = (H264_CONTEXT*) calloc(1, sizeof(H264_CONTEXT)); + + if (h264) + { + h264->Compressor = Compressor; + + h264->subsystem = &g_Subsystem_dummy; + + if (!h264_context_init(h264)) + { + free(h264); + return NULL; + } + } + + return h264; +} + +void h264_context_free(H264_CONTEXT* h264) +{ + if (h264) + { + h264->subsystem->Uninit(h264); + + free(h264); + } +} diff --git a/libfreerdp/codec/bitmap_decode.c b/libfreerdp/codec/interleaved.c similarity index 52% rename from libfreerdp/codec/bitmap_decode.c rename to libfreerdp/codec/interleaved.c index c5232d988..58b69f68d 100644 --- a/libfreerdp/codec/bitmap_decode.c +++ b/libfreerdp/codec/interleaved.c @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Bitmap Decompression + * Interleaved RLE Bitmap Codec * - * Copyright 2011 Jay Sorg + * 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. @@ -21,14 +21,7 @@ #include "config.h" #endif -#include -#include - -#include "planar.h" - -#include - -#include +#include /* RLE Compressed Bitmap Stream (RLE_BITMAP_STREAM) @@ -82,43 +75,30 @@ static const BYTE g_MaskLiteRunLength = 0x0F; * Reads the supplied order header and extracts the compression * order code ID. */ -static UINT32 ExtractCodeId(BYTE bOrderHdr) +static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr) { - int code; - - switch (bOrderHdr) - { - case MEGA_MEGA_BG_RUN: - case MEGA_MEGA_FG_RUN: - case MEGA_MEGA_SET_FG_RUN: - case MEGA_MEGA_DITHERED_RUN: - case MEGA_MEGA_COLOR_RUN: - case MEGA_MEGA_FGBG_IMAGE: - case MEGA_MEGA_SET_FGBG_IMAGE: - case MEGA_MEGA_COLOR_IMAGE: - case SPECIAL_FGBG_1: - case SPECIAL_FGBG_2: - case SPECIAL_WHITE: - case SPECIAL_BLACK: - return bOrderHdr; + if ((bOrderHdr & 0xC0U) != 0xC0U) { + /* REGULAR orders + * (000x xxxx, 001x xxxx, 010x xxxx, 011x xxxx, 100x xxxx) + */ + return bOrderHdr >> 5; } - code = bOrderHdr >> 5; - switch (code) - { - case REGULAR_BG_RUN: - case REGULAR_FG_RUN: - case REGULAR_COLOR_RUN: - case REGULAR_FGBG_IMAGE: - case REGULAR_COLOR_IMAGE: - return code; + else if ((bOrderHdr & 0xF0U) == 0xF0U) { + /* MEGA and SPECIAL orders (0xF*) */ + return bOrderHdr; + } + else { + /* LITE orders + * 1100 xxxx, 1101 xxxx, 1110 xxxx) + */ + return bOrderHdr >> 4; } - return bOrderHdr >> 4; } /** * Extract the run length of a compression order. */ -static UINT32 ExtractRunLength(UINT32 code, BYTE* pbOrderHdr, UINT32* advance) +static INLINE UINT32 ExtractRunLength(UINT32 code, BYTE* pbOrderHdr, UINT32* advance) { UINT32 runLength; UINT32 ladvance; @@ -255,57 +235,203 @@ static UINT32 ExtractRunLength(UINT32 code, BYTE* pbOrderHdr, UINT32* advance) #define RLEEXTRA #include "include/bitmap.c" -/** - * bitmap decompression routine - */ -BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size, int srcBpp, int dstBpp) +int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcData, UINT32 SrcSize, int bpp, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BYTE* palette) { int status; - BYTE* TmpBfr; + BOOL vFlip; + int scanline; BYTE* pDstData; + UINT32 SrcFormat; + UINT32 BufferSize; + int dstBitsPerPixel; + int dstBytesPerPixel; - if (srcBpp == 16 && dstBpp == 16) - { - TmpBfr = (BYTE*) malloc(width * height * 2); - RleDecompress16to16(srcData, size, TmpBfr, width * 2, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 2, height); - free(TmpBfr); - } - else if (srcBpp == 32 && dstBpp == 32) - { - pDstData = dstData; + pDstData = *ppDstData; + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + vFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat) ? TRUE : FALSE; - status = planar_decompress(NULL, srcData, size, &pDstData, - PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + if (!interleaved) + return -1; - if (status < 0) - return FALSE; - } - else if (srcBpp == 15 && dstBpp == 15) + if (nDstStep < 0) + nDstStep = nWidth * dstBytesPerPixel; + + if (bpp == 24) { - TmpBfr = (BYTE*) malloc(width * height * 2); - RleDecompress16to16(srcData, size, TmpBfr, width * 2, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 2, height); - free(TmpBfr); + scanline = nWidth * 3; + BufferSize = scanline * nHeight; + + SrcFormat = PIXEL_FORMAT_RGB24_VF; + +#if 0 + if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep)) + { + RleDecompress24to24(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight); + return 1; + } +#endif + + if (BufferSize > interleaved->TempSize) + { + interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16); + interleaved->TempSize = BufferSize; + } + + if (!interleaved->TempBuffer) + return -1; + + RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nWidth, nHeight); + + status = freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette); } - else if (srcBpp == 8 && dstBpp == 8) + else if ((bpp == 16) || (bpp == 15)) { - TmpBfr = (BYTE*) malloc(width * height); - RleDecompress8to8(srcData, size, TmpBfr, width, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width, height); - free(TmpBfr); + scanline = nWidth * 2; + BufferSize = scanline * nHeight; + + SrcFormat = (bpp == 16) ? PIXEL_FORMAT_RGB16_VF : PIXEL_FORMAT_RGB15_VF; + +#if 0 + if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep)) + { + RleDecompress16to16(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight); + return 1; + } +#endif + + if (BufferSize > interleaved->TempSize) + { + interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16); + interleaved->TempSize = BufferSize; + } + + if (!interleaved->TempBuffer) + return -1; + + RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nWidth, nHeight); + + status = freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette); } - else if (srcBpp == 24 && dstBpp == 24) + else if (bpp == 8) { - TmpBfr = (BYTE*) malloc(width * height * 3); - RleDecompress24to24(srcData, size, TmpBfr, width * 3, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 3, height); - free(TmpBfr); + scanline = nWidth; + BufferSize = scanline * nHeight; + + SrcFormat = PIXEL_FORMAT_RGB8_VF; + +#if 0 + if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep)) + { + RleDecompress8to8(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight); + return 1; + } +#endif + + if (BufferSize > interleaved->TempSize) + { + interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16); + interleaved->TempSize = BufferSize; + } + + if (!interleaved->TempBuffer) + return -1; + + RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nWidth, nHeight); + + status = freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette); } else { - return FALSE; + return -1; } - return TRUE; + return 1; +} + +int interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize, + int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette, int bpp) +{ + int status; + wStream* s; + UINT32 DstFormat = 0; + int maxSize = 64 * 64 * 4; + + if (nWidth % 4) + { + fprintf(stderr, "interleaved_compress: width is not a multiple of 4\n"); + return -1; + } + + if ((nWidth > 64) || (nHeight > 64)) + { + fprintf(stderr, "interleaved_compress: width (%d) or height (%d) is greater than 64\n", nWidth, nHeight); + return -1; + } + + if (bpp == 24) + DstFormat = PIXEL_FORMAT_XRGB32; + else if (bpp == 16) + DstFormat = PIXEL_FORMAT_RGB16; + else if (bpp == 15) + DstFormat = PIXEL_FORMAT_RGB15; + else if (bpp == 8) + DstFormat = PIXEL_FORMAT_RGB8; + + if (!DstFormat) + return -1; + + status = freerdp_image_copy(interleaved->TempBuffer, DstFormat, -1, 0, 0, nWidth, nHeight, + pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette); + + s = Stream_New(pDstData, maxSize); + + if (!s) + return -1; + + status = freerdp_bitmap_compress((char*) interleaved->TempBuffer, nWidth, nHeight, + s, bpp, maxSize, nHeight - 1, interleaved->bts, 0); + + Stream_SealLength(s); + *pDstSize = (UINT32) Stream_Length(s); + + Stream_Free(s, FALSE); + + return status; +} + +int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) +{ + return 1; +} + +BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) +{ + BITMAP_INTERLEAVED_CONTEXT* interleaved; + + interleaved = (BITMAP_INTERLEAVED_CONTEXT*) calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT)); + + if (interleaved) + { + interleaved->TempSize = 64 * 64 * 4; + interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize, 16); + interleaved->bts = Stream_New(NULL, interleaved->TempSize); + } + + return interleaved; +} + +void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) +{ + if (!interleaved) + return; + + _aligned_free(interleaved->TempBuffer); + Stream_Free(interleaved->bts, TRUE); + + free(interleaved); } diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 410277f0e..f975b2303 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -28,6 +28,8 @@ #include +#define TAG FREERDP_TAG("codec.mppc") + #define MPPC_MATCH_INDEX(_sym1, _sym2, _sym3) \ ((((MPPC_MATCH_TABLE[_sym3] << 16) + (MPPC_MATCH_TABLE[_sym2] << 8) + MPPC_MATCH_TABLE[_sym1]) & 0x07FFF000) >> 12) @@ -413,7 +415,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p } #ifdef DEBUG_MPPC - printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); + WLog_DBG(TAG, "<%d,%d>", (int) CopyOffset, (int) LengthOfMatch); #endif SrcPtr = HistoryPtr - CopyOffset; @@ -555,7 +557,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD accumulator = Sym1; #ifdef DEBUG_MPPC - printf("%c", accumulator); + WLog_DBG(TAG, "%c", accumulator); #endif if (accumulator < 0x80) @@ -589,7 +591,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD } #ifdef DEBUG_MPPC - printf("<%d,%d>", (int) CopyOffset, (int) LengthOfMatch); + WLog_DBG(TAG, "<%d,%d>", (int) CopyOffset, (int) LengthOfMatch); #endif /* Encode CopyOffset */ @@ -764,7 +766,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD accumulator = *pSrcPtr; #ifdef DEBUG_MPPC - printf("%c", accumulator); + WLog_DBG(TAG, "%c", accumulator); #endif if (accumulator < 0x80) @@ -798,10 +800,6 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD mppc->HistoryPtr = HistoryPtr; mppc->HistoryOffset = HistoryPtr - HistoryBuffer; -#ifdef DEBUG_MPPC - printf("\n"); -#endif - return 1; } diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c index cfb136e4d..34ea35249 100644 --- a/libfreerdp/codec/ncrush.c +++ b/libfreerdp/codec/ncrush.c @@ -25,8 +25,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("codec") + UINT16 HuffTableLEC[8192] = { 0x510B, 0x611F, 0x610D, 0x9027, 0x6000, 0x7105, 0x6117, 0xA068, 0x5111, 0x7007, 0x6113, 0x90C0, 0x6108, 0x8018, 0x611B, 0xA0B3, @@ -1768,6 +1771,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY BYTE* SrcPtr; BYTE* SrcEnd; UINT16 Mask; + UINT16* pMask; BYTE Literal; UINT32 IndexLEC; UINT32 BitLength; @@ -1829,7 +1833,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY { while (1) { - Mask = *((UINT16*) &HuffTableMask[29]); + pMask = (UINT16*) &HuffTableMask[29]; + Mask = *pMask; MaskedBits = bits & Mask; IndexLEC = HuffTableLEC[MaskedBits] & 0xFFF; @@ -1845,8 +1850,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (HistoryPtr >= HistoryBufferEnd) { - fprintf(stderr, "ncrush_decompress error: HistoryPtr (%p) >= HistoryBufferEnd (%p)\n", - HistoryPtr, HistoryBufferEnd); + WLog_ERR(TAG, "ncrush_decompress error: HistoryPtr (%p) >= HistoryBufferEnd (%p)", + HistoryPtr, HistoryBufferEnd); return -1003; } @@ -1869,7 +1874,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY CopyOffset = ncrush->OffsetCache[OffsetCacheIndex]; - Mask = *((UINT16*) &HuffTableMask[21]); + pMask = (UINT16*) &HuffTableMask[21]; + Mask = *pMask; MaskedBits = bits & Mask; LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF; @@ -1885,7 +1891,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (LengthOfMatchBits) { - Mask = *((UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]); + pMask = (UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]; + Mask = *pMask; MaskedBits = bits & Mask; bits >>= LengthOfMatchBits; @@ -1908,7 +1915,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (CopyOffsetBits) { - Mask = *((UINT16*) &HuffTableMask[(2 * CopyOffsetBits) + 3]); + pMask = (UINT16*) &HuffTableMask[(2 * CopyOffsetBits) + 3]; + Mask = *pMask; MaskedBits = bits & Mask; CopyOffset = CopyOffsetBase + MaskedBits - 1; @@ -1919,7 +1927,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY NCrushFetchBits(); } - Mask = *((UINT16*) &HuffTableMask[21]); + pMask = (UINT16*) &HuffTableMask[21]; + Mask = *pMask; MaskedBits = bits & Mask; LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF; @@ -1935,7 +1944,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (LengthOfMatchBits) { - Mask = *((UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]); + pMask = (UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]; + Mask = *pMask; MaskedBits = bits & Mask; bits >>= LengthOfMatchBits; @@ -2014,7 +2024,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (ncrush->HistoryBufferFence != 0xABABABAB) { - fprintf(stderr, "NCrushDecompress: history buffer fence was overwritten, potential buffer overflow detected!\n"); + WLog_ERR(TAG, "NCrushDecompress: history buffer fence was overwritten, potential buffer overflow detected!"); return -1007; } @@ -2248,6 +2258,7 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE UINT32 IndexLOM; UINT32 IndexCO; UINT32 CodeLEC; + UINT16* pCodeLEC; UINT32 BitLength; UINT32 CopyOffset; UINT32 MatchOffset; @@ -2367,7 +2378,8 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE IndexLEC = Literal; BitLength = HuffLengthLEC[IndexLEC]; - CodeLEC = *((UINT16*) &HuffCodeLEC[IndexLEC * 2]); + pCodeLEC = (UINT16*) &HuffCodeLEC[IndexLEC * 2]; + CodeLEC = (UINT32) *pCodeLEC; if (BitLength > 15) return -1006; @@ -2454,7 +2466,8 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE IndexLEC = 257 + CopyOffsetIndex; BitLength = HuffLengthLEC[IndexLEC]; - CodeLEC = *((UINT16*) &HuffCodeLEC[IndexLEC * 2]); + pCodeLEC = (UINT16*) &HuffCodeLEC[IndexLEC * 2]; + CodeLEC = (UINT32) *pCodeLEC; if (BitLength > 15) return -1008; @@ -2493,7 +2506,8 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE IndexLEC = 289 + OffsetCacheIndex; BitLength = HuffLengthLEC[IndexLEC]; - CodeLEC = *((UINT16*) &HuffCodeLEC[IndexLEC * 2]); + pCodeLEC = (UINT16*) &HuffCodeLEC[IndexLEC * 2]; + CodeLEC = (UINT32) *pCodeLEC; if (BitLength >= 15) return -1011; @@ -2541,7 +2555,8 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE IndexLEC = Literal; BitLength = HuffLengthLEC[IndexLEC]; - CodeLEC = *((UINT16*) &HuffCodeLEC[IndexLEC * 2]); + pCodeLEC = (UINT16*) &HuffCodeLEC[IndexLEC * 2]; + CodeLEC = (UINT32) *pCodeLEC; if (BitLength > 15) return -1014; @@ -2565,7 +2580,8 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE if (BitLength > 15) return -1015; - bits = *((UINT16*) &HuffCodeLEC[IndexLEC * 2]); + pCodeLEC = (UINT16*) &HuffCodeLEC[IndexLEC * 2]; + bits = (UINT32) *pCodeLEC; NCrushWriteBits(bits, BitLength); @@ -2682,7 +2698,7 @@ NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor) ncrush->HistoryPtr = &(ncrush->HistoryBuffer[ncrush->HistoryOffset]); if (ncrush_generate_tables(ncrush) < 0) - printf("ncrush_context_new: failed to initialize tables\n"); + WLog_DBG(TAG, "ncrush_context_new: failed to initialize tables"); ncrush_context_reset(ncrush, FALSE); } diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index f04bac779..ed8b4caa0 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -63,14 +63,14 @@ static void nsc_decode(NSC_CONTEXT* context) bmpdata = context->BitmapData; rw = ROUND_UP_TO(context->width, 8); - shift = context->nsc_stream.ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */ + shift = context->ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */ - WLog_Print(context->priv->log, WLOG_DEBUG, "NscDecode: width: %d height: %d ChromaSubSamplingLevel: %d", - context->width, context->height, context->nsc_stream.ChromaSubSamplingLevel); + WLog_Print(context->priv->log, WLOG_DEBUG, "NscDecode: width: %d height: %d ChromaSubsamplingLevel: %d", + context->width, context->height, context->ChromaSubsamplingLevel); for (y = 0; y < context->height; y++) { - if (context->nsc_stream.ChromaSubSamplingLevel > 0) + if (context->ChromaSubsamplingLevel) { yplane = context->priv->PlaneBuffers[0] + y * rw; /* Y */ coplane = context->priv->PlaneBuffers[1] + (y >> 1) * (rw >> 1); /* Co, supersampled */ @@ -98,8 +98,8 @@ static void nsc_decode(NSC_CONTEXT* context) *bmpdata++ = MINMAX(r_val, 0, 0xFF); *bmpdata++ = *aplane; yplane++; - coplane += (context->nsc_stream.ChromaSubSamplingLevel > 0 ? x % 2 : 1); - cgplane += (context->nsc_stream.ChromaSubSamplingLevel > 0 ? x % 2 : 1); + coplane += (context->ChromaSubsamplingLevel ? x % 2 : 1); + cgplane += (context->ChromaSubsamplingLevel ? x % 2 : 1); aplane++; } } @@ -159,12 +159,12 @@ static void nsc_rle_decompress_data(NSC_CONTEXT* context) UINT32 planeSize; UINT32 originalSize; - rle = context->nsc_stream.Planes; + rle = context->Planes; for (i = 0; i < 4; i++) { originalSize = context->OrgByteCount[i]; - planeSize = context->nsc_stream.PlaneByteCount[i]; + planeSize = context->PlaneByteCount[i]; if (planeSize == 0) FillMemory(context->priv->PlaneBuffers[i], originalSize, 0xFF); @@ -182,13 +182,13 @@ static void nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) int i; for (i = 0; i < 4; i++) - Stream_Read_UINT32(s, context->nsc_stream.PlaneByteCount[i]); + Stream_Read_UINT32(s, context->PlaneByteCount[i]); - Stream_Read_UINT8(s, context->nsc_stream.ColorLossLevel); - Stream_Read_UINT8(s, context->nsc_stream.ChromaSubSamplingLevel); - Stream_Seek(s, 2); + Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */ + Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ + Stream_Seek(s, 2); /* Reserved (2 bytes) */ - context->nsc_stream.Planes = Stream_Pointer(s); + context->Planes = Stream_Pointer(s); } static void nsc_context_initialize(NSC_CONTEXT* context, wStream* s) @@ -232,7 +232,7 @@ static void nsc_context_initialize(NSC_CONTEXT* context, wStream* s) context->OrgByteCount[i] = context->width * context->height; } - if (context->nsc_stream.ChromaSubSamplingLevel > 0) /* [MS-RDPNSC] 2.2 */ + if (context->ChromaSubsamplingLevel) { context->OrgByteCount[0] = tempWidth * context->height; context->OrgByteCount[1] = (tempWidth >> 1) * (tempHeight >> 1); @@ -252,6 +252,11 @@ static void nsc_profiler_print(NSC_CONTEXT* context) PROFILER_PRINT_FOOTER; } +int nsc_context_reset(NSC_CONTEXT* context) +{ + return 1; +} + NSC_CONTEXT* nsc_context_new(void) { UINT8 i; @@ -283,8 +288,8 @@ NSC_CONTEXT* nsc_context_new(void) PROFILER_CREATE(context->priv->prof_nsc_encode, "nsc_encode"); /* Default encoding parameters */ - context->nsc_stream.ColorLossLevel = 3; - context->nsc_stream.ChromaSubSamplingLevel = 1; + context->ColorLossLevel = 3; + context->ChromaSubsamplingLevel = 1; /* init optimized methods */ NSC_INIT_SIMD(context); @@ -355,11 +360,15 @@ void nsc_context_set_pixel_format(NSC_CONTEXT* context, RDP_PIXEL_FORMAT pixel_f } } -void nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 height, BYTE* data, UINT32 length) +int nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 height, BYTE* data, UINT32 length) { wStream* s; s = Stream_New(data, length); + + if (!s) + return -1; + context->bpp = bpp; context->width = width; context->height = height; @@ -375,4 +384,6 @@ void nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 PROFILER_ENTER(context->priv->prof_nsc_decode); context->decode(context); PROFILER_EXIT(context->priv->prof_nsc_decode); + + return 1; } diff --git a/libfreerdp/codec/nsc_encode.c b/libfreerdp/codec/nsc_encode.c index 17aabdc27..724a6d843 100644 --- a/libfreerdp/codec/nsc_encode.c +++ b/libfreerdp/codec/nsc_encode.c @@ -57,7 +57,7 @@ static void nsc_context_initialize_encode(NSC_CONTEXT* context) context->priv->PlaneBuffersLength = length; } - if (context->nsc_stream.ChromaSubSamplingLevel > 0) + if (context->ChromaSubsamplingLevel) { context->OrgByteCount[0] = tempWidth * context->height; context->OrgByteCount[1] = tempWidth * tempHeight / 4; @@ -93,8 +93,8 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* data, int scan tempWidth = ROUND_UP_TO(context->width, 8); tempHeight = ROUND_UP_TO(context->height, 2); - rw = (context->nsc_stream.ChromaSubSamplingLevel > 0 ? tempWidth : context->width); - ccl = context->nsc_stream.ColorLossLevel; + rw = (context->ChromaSubsamplingLevel ? tempWidth : context->width); + ccl = context->ColorLossLevel; yplane = context->priv->PlaneBuffers[0]; coplane = context->priv->PlaneBuffers[1]; cgplane = context->priv->PlaneBuffers[2]; @@ -201,7 +201,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* data, int scan *aplane++ = a_val; } - if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (x % 2) == 1) + if (context->ChromaSubsamplingLevel && (x % 2) == 1) { *yplane = *(yplane - 1); *coplane = *(coplane - 1); @@ -209,7 +209,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* data, int scan } } - if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (y % 2) == 1) + if (context->ChromaSubsamplingLevel && (y % 2) == 1) { CopyMemory(yplane + rw, yplane, rw); CopyMemory(coplane + rw, coplane, rw); @@ -260,7 +260,7 @@ void nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride) { nsc_encode_argb_to_aycocg(context, bmpdata, rowstride); - if (context->nsc_stream.ChromaSubSamplingLevel > 0) + if (context->ChromaSubsamplingLevel) { nsc_encode_subsampling(context); } @@ -344,7 +344,7 @@ static void nsc_rle_compress_data(NSC_CONTEXT* context) planeSize = originalSize; } - context->nsc_stream.PlaneByteCount[i] = planeSize; + context->PlaneByteCount[i] = planeSize; } } @@ -359,7 +359,7 @@ UINT32 nsc_compute_byte_count(NSC_CONTEXT* context, UINT32* ByteCount, UINT32 wi maxPlaneSize = tempWidth * tempHeight + 16; - if (context->nsc_stream.ChromaSubSamplingLevel > 0) + if (context->ChromaSubsamplingLevel) { ByteCount[0] = tempWidth * height; ByteCount[1] = tempWidth * tempHeight / 4; @@ -406,8 +406,10 @@ NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, maxDataSize -= 1024; /* reserve enough space for headers */ - messages = (NSC_MESSAGE*) malloc(sizeof(NSC_MESSAGE) * (*numMessages)); - ZeroMemory(messages, sizeof(NSC_MESSAGE) * (*numMessages)); + messages = (NSC_MESSAGE*) calloc(*numMessages, sizeof(NSC_MESSAGE)); + + if (!messages) + return NULL; for (i = 0; i < rows; i++) { @@ -467,10 +469,12 @@ NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, nsc_rle_compress_data(context); PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data); - messages[i].PlaneByteCount[0] = context->nsc_stream.PlaneByteCount[0]; - messages[i].PlaneByteCount[1] = context->nsc_stream.PlaneByteCount[1]; - messages[i].PlaneByteCount[2] = context->nsc_stream.PlaneByteCount[2]; - messages[i].PlaneByteCount[3] = context->nsc_stream.PlaneByteCount[3]; + messages[i].LumaPlaneByteCount = context->PlaneByteCount[0]; + messages[i].OrangeChromaPlaneByteCount = context->PlaneByteCount[1]; + messages[i].GreenChromaPlaneByteCount = context->PlaneByteCount[2]; + messages[i].AlphaPlaneByteCount = context->PlaneByteCount[3]; + messages[i].ColorLossLevel = context->ColorLossLevel; + messages[i].ChromaSubsamplingLevel = context->ChromaSubsamplingLevel; } context->priv->PlaneBuffers[0] = NULL; @@ -484,25 +488,31 @@ NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message) { - int i; + UINT32 totalPlaneByteCount; - Stream_EnsureRemainingCapacity(s, 20); - Stream_Write_UINT32(s, message->PlaneByteCount[0]); /* LumaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, message->PlaneByteCount[1]); /* OrangeChromaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, message->PlaneByteCount[2]); /* GreenChromaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, message->PlaneByteCount[3]); /* AlphaPlaneByteCount (4 bytes) */ - Stream_Write_UINT8(s, context->nsc_stream.ColorLossLevel); /* ColorLossLevel (1 byte) */ - Stream_Write_UINT8(s, context->nsc_stream.ChromaSubSamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ + totalPlaneByteCount = message->LumaPlaneByteCount + message->OrangeChromaPlaneByteCount + + message->GreenChromaPlaneByteCount + message->AlphaPlaneByteCount; + + Stream_EnsureRemainingCapacity(s, 20 + totalPlaneByteCount); + Stream_Write_UINT32(s, message->LumaPlaneByteCount); /* LumaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->OrangeChromaPlaneByteCount); /* OrangeChromaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->GreenChromaPlaneByteCount); /* GreenChromaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->AlphaPlaneByteCount); /* AlphaPlaneByteCount (4 bytes) */ + Stream_Write_UINT8(s, message->ColorLossLevel); /* ColorLossLevel (1 byte) */ + Stream_Write_UINT8(s, message->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */ - for (i = 0; i < 4; i++) - { - if (message->PlaneByteCount[i] > 0) - { - Stream_EnsureRemainingCapacity(s, (int) message->PlaneByteCount[i]); - Stream_Write(s, message->PlaneBuffers[i], message->PlaneByteCount[i]); - } - } + if (message->LumaPlaneByteCount) + Stream_Write(s, message->PlaneBuffers[0], message->LumaPlaneByteCount); /* LumaPlane */ + + if (message->OrangeChromaPlaneByteCount) + Stream_Write(s, message->PlaneBuffers[1], message->OrangeChromaPlaneByteCount); /* OrangeChromaPlane */ + + if (message->GreenChromaPlaneByteCount) + Stream_Write(s, message->PlaneBuffers[2], message->GreenChromaPlaneByteCount); /* GreenChromaPlane */ + + if (message->AlphaPlaneByteCount) + Stream_Write(s, message->PlaneBuffers[3], message->AlphaPlaneByteCount); /* AlphaPlane */ return 0; } @@ -515,7 +525,8 @@ int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message) void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* data, int width, int height, int scanline) { - int i; + NSC_MESSAGE s_message = { 0 }; + NSC_MESSAGE* message = &s_message; context->width = width; context->height = height; @@ -531,22 +542,17 @@ void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* data, int width nsc_rle_compress_data(context); PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data); - /* Assemble the NSCodec message into stream */ - Stream_EnsureRemainingCapacity(s, 20); - Stream_Write_UINT32(s, context->nsc_stream.PlaneByteCount[0]); /* LumaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, context->nsc_stream.PlaneByteCount[1]); /* OrangeChromaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, context->nsc_stream.PlaneByteCount[2]); /* GreenChromaPlaneByteCount (4 bytes) */ - Stream_Write_UINT32(s, context->nsc_stream.PlaneByteCount[3]); /* AlphaPlaneByteCount (4 bytes) */ - Stream_Write_UINT8(s, context->nsc_stream.ColorLossLevel); /* ColorLossLevel (1 byte) */ - Stream_Write_UINT8(s, context->nsc_stream.ChromaSubSamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ - Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */ + message->PlaneBuffers[0] = context->priv->PlaneBuffers[0]; + message->PlaneBuffers[1] = context->priv->PlaneBuffers[1]; + message->PlaneBuffers[2] = context->priv->PlaneBuffers[2]; + message->PlaneBuffers[3] = context->priv->PlaneBuffers[3]; - for (i = 0; i < 4; i++) - { - if (context->nsc_stream.PlaneByteCount[i] > 0) - { - Stream_EnsureRemainingCapacity(s, (int) context->nsc_stream.PlaneByteCount[i]); - Stream_Write(s, context->priv->PlaneBuffers[i], context->nsc_stream.PlaneByteCount[i]); - } - } + message->LumaPlaneByteCount = context->PlaneByteCount[0]; + message->OrangeChromaPlaneByteCount = context->PlaneByteCount[1]; + message->GreenChromaPlaneByteCount = context->PlaneByteCount[2]; + message->AlphaPlaneByteCount = context->PlaneByteCount[3]; + message->ColorLossLevel = context->ColorLossLevel; + message->ChromaSubsamplingLevel = context->ChromaSubsamplingLevel; + + nsc_write_message(context, s, message); } diff --git a/libfreerdp/codec/nsc_sse2.c b/libfreerdp/codec/nsc_sse2.c index f4f1eb1bf..1a9be3633 100644 --- a/libfreerdp/codec/nsc_sse2.c +++ b/libfreerdp/codec/nsc_sse2.c @@ -56,8 +56,8 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* data, int tempWidth = ROUND_UP_TO(context->width, 8); tempHeight = ROUND_UP_TO(context->height, 2); - rw = (context->nsc_stream.ChromaSubSamplingLevel > 0 ? tempWidth : context->width); - ccl = context->nsc_stream.ColorLossLevel; + rw = (context->ChromaSubsamplingLevel > 0 ? tempWidth : context->width); + ccl = context->ColorLossLevel; yplane = context->priv->PlaneBuffers[0]; coplane = context->priv->PlaneBuffers[1]; cgplane = context->priv->PlaneBuffers[2]; @@ -278,7 +278,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* data, int aplane += 8; } - if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (context->width % 2) == 1) + if (context->ChromaSubsamplingLevel > 0 && (context->width % 2) == 1) { context->priv->PlaneBuffers[0][y * rw + context->width] = context->priv->PlaneBuffers[0][y * rw + context->width - 1]; context->priv->PlaneBuffers[1][y * rw + context->width] = context->priv->PlaneBuffers[1][y * rw + context->width - 1]; @@ -286,7 +286,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* data, int } } - if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (y % 2) == 1) + if (context->ChromaSubsamplingLevel > 0 && (y % 2) == 1) { CopyMemory(yplane + rw, yplane, rw); CopyMemory(coplane + rw, coplane, rw); @@ -351,7 +351,7 @@ static void nsc_encode_sse2(NSC_CONTEXT* context, BYTE* data, int scanline) { nsc_encode_argb_to_aycocg_sse2(context, data, scanline); - if (context->nsc_stream.ChromaSubSamplingLevel > 0) + if (context->ChromaSubsamplingLevel > 0) { nsc_encode_subsampling_sse2(context); } diff --git a/libfreerdp/codec/nsc_types.h b/libfreerdp/codec/nsc_types.h index fe5cfd2f6..28553b8c0 100644 --- a/libfreerdp/codec/nsc_types.h +++ b/libfreerdp/codec/nsc_types.h @@ -29,7 +29,7 @@ #include #include -#include + #include #define ROUND_UP_TO(_b, _n) (_b + ((~(_b & (_n-1)) + 0x1) & (_n-1))) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 824376ffb..0ce3f8326 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -24,15 +24,67 @@ #include #include +#include +#include #include +#include -#include "planar.h" +#define TAG FREERDP_TAG("codec") -static int planar_decompress_plane_rle(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, +static int planar_skip_plane_rle(const BYTE* pSrcData, UINT32 SrcSize, int nWidth, int nHeight) +{ + int x, y; + int cRawBytes; + int nRunLength; + BYTE controlByte; + const BYTE* pRLE = pSrcData; + const BYTE* pEnd = &pSrcData[SrcSize]; + + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; ) + { + if (pRLE >= pEnd) + return -1; + + controlByte = *pRLE++; + + nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte); + cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte); + + if (nRunLength == 1) + { + nRunLength = cRawBytes + 16; + cRawBytes = 0; + } + else if (nRunLength == 2) + { + nRunLength = cRawBytes + 32; + cRawBytes = 0; + } + + pRLE += cRawBytes; + x += cRawBytes; + cRawBytes = 0; + + x += nRunLength; + nRunLength = 0; + + if (x > nWidth) + return -1; + + if (pRLE > pEnd) + return -1; + } + } + + return (int) (pRLE - pSrcData); +} + +static int planar_decompress_plane_rle(const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, int nChannel, BOOL vFlip) { int x, y; - BYTE* srcp; BYTE* dstp; UINT32 pixel; int cRawBytes; @@ -42,8 +94,8 @@ static int planar_decompress_plane_rle(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDs BYTE controlByte; BYTE* currentScanline; BYTE* previousScanline; + const BYTE* srcp = pSrcData; - srcp = pSrcData; dstp = pDstData; previousScanline = NULL; @@ -74,7 +126,7 @@ static int planar_decompress_plane_rle(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDs if ((srcp - pSrcData) > SrcSize) { - fprintf(stderr, "planar_decompress_plane_rle: error reading input buffer\n"); + WLog_ERR(TAG, "error reading input buffer"); return -1; } @@ -94,7 +146,7 @@ static int planar_decompress_plane_rle(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDs if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4) { - fprintf(stderr, "planar_decompress_plane_rle: too many pixels in scanline\n"); + WLog_ERR(TAG, "too many pixels in scanline"); return -1; } @@ -166,13 +218,16 @@ static int planar_decompress_plane_rle(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDs return (int) (srcp - pSrcData); } -static int planar_decompress_plane_raw(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, - int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, int nChannel, BOOL vFlip) +static int planar_decompress_planes_raw(const BYTE* pSrcData[4], int nSrcStep, BYTE* pDstData, + int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BOOL alpha, BOOL vFlip) { int x, y; int beg, end, inc; - BYTE* dstp = NULL; - BYTE* srcp = pSrcData; + BYTE* pRGB = pDstData; + const BYTE* pR = pSrcData[0]; + const BYTE* pG = pSrcData[1]; + const BYTE* pB = pSrcData[2]; + const BYTE* pA = pSrcData[3]; if (vFlip) { @@ -187,35 +242,74 @@ static int planar_decompress_plane_raw(BYTE* pSrcData, UINT32 SrcSize, BYTE* pDs inc = 1; } - for (y = beg; y != end; y += inc) + if (alpha) { - dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel]; - - for (x = 0; x < nWidth; x++) + for (y = beg; y != end; y += inc) { - *dstp = *srcp; - dstp += 4; - srcp++; + pRGB = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + + for (x = 0; x < nWidth; x++) + { + *pRGB++ = *pB++; + *pRGB++ = *pG++; + *pRGB++ = *pR++; + *pRGB++ = *pA++; + } + } + } + else + { + for (y = beg; y != end; y += inc) + { + pRGB = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + + for (x = 0; x < nWidth; x++) + { + *pRGB++ = *pB++; + *pRGB++ = *pG++; + *pRGB++ = *pR++; + *pRGB++ = 0xFF; + } } } - return (int) (srcp - pSrcData); + return 1; } int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcSize, - BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, BOOL vFlip) { + BOOL cs; + BOOL rle; + UINT32 cll; + BOOL alpha; int status; BYTE* srcp; - BOOL vFlip; + int subSize; + int subWidth; + int subHeight; + int planeSize; + BYTE* pDstData; + int rleSizes[4]; + int rawSizes[4]; + int rawWidths[4]; + int rawHeights[4]; BYTE FormatHeader; - BYTE* pDstData = NULL; + BOOL useTempBuffer; + int dstBitsPerPixel; + int dstBytesPerPixel; + const BYTE* planes[4]; UINT32 UncompressedSize; + const primitives_t* prims = primitives_get(); - if ((nWidth * nHeight) <= 0) + if ((nWidth < 0) || (nHeight < 0)) return -1; - vFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat) ? TRUE : FALSE; + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + + if (nDstStep < 0) + nDstStep = nWidth * 4; srcp = pSrcData; UncompressedSize = nWidth * nHeight * 4; @@ -224,7 +318,7 @@ int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcS if (!pDstData) { - pDstData = (BYTE*) malloc(UncompressedSize); + pDstData = (BYTE*) _aligned_malloc(UncompressedSize, 16); if (!pDstData) return -1; @@ -232,103 +326,291 @@ int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcS *ppDstData = pDstData; } - FormatHeader = *srcp; - srcp++; + useTempBuffer = (dstBytesPerPixel != 4) ? TRUE : FALSE; - /* AlphaPlane */ - - if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA)) + if (useTempBuffer) { - if (FormatHeader & PLANAR_FORMAT_HEADER_RLE) + if (UncompressedSize > planar->TempSize) { - status = planar_decompress_plane_rle(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 3, vFlip); + planar->TempBuffer = _aligned_realloc(planar->TempBuffer, UncompressedSize, 16); + planar->TempSize = UncompressedSize; + } - if (status < 0) + if (!planar->TempBuffer) + return -1; + + pDstData = planar->TempBuffer; + } + + FormatHeader = *srcp++; + + cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK); + cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) ? TRUE : FALSE; + rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) ? TRUE : FALSE; + alpha = (FormatHeader & PLANAR_FORMAT_HEADER_NA) ? FALSE : TRUE; + + //WLog_INFO(TAG, "CLL: %d CS: %d RLE: %d ALPHA: %d", cll, cs, rle, alpha); + + if (!cll && cs) + return -1; /* Chroma subsampling requires YCoCg */ + + subWidth = (nWidth / 2) + (nWidth % 2); + subHeight = (nHeight / 2) + (nHeight % 2); + + planeSize = nWidth * nHeight; + subSize = subWidth * subHeight; + + if (!cs) + { + rawSizes[0] = planeSize; /* LumaOrRedPlane */ + rawWidths[0] = nWidth; + rawHeights[0] = nHeight; + + rawSizes[1] = planeSize; /* OrangeChromaOrGreenPlane */ + rawWidths[1] = nWidth; + rawHeights[1] = nHeight; + + rawSizes[2] = planeSize; /* GreenChromaOrBluePlane */ + rawWidths[2] = nWidth; + rawHeights[2] = nHeight; + + rawSizes[3] = planeSize; /* AlphaPlane */ + rawWidths[3] = nWidth; + rawHeights[3] = nHeight; + } + else /* Chroma Subsampling */ + { + rawSizes[0] = planeSize; /* LumaOrRedPlane */ + rawWidths[0] = nWidth; + rawHeights[0] = nHeight; + + rawSizes[1] = subSize; /* OrangeChromaOrGreenPlane */ + rawWidths[1] = subWidth; + rawHeights[1] = subHeight; + + rawSizes[2] = subSize; /* GreenChromaOrBluePlane */ + rawWidths[2] = subWidth; + rawHeights[2] = subHeight; + + rawSizes[3] = planeSize; /* AlphaPlane */ + rawWidths[3] = nWidth; + rawHeights[3] = nHeight; + } + + if (!rle) /* RAW */ + { + if (alpha) + { + planes[3] = srcp; /* AlphaPlane */ + planes[0] = planes[3] + rawSizes[3]; /* LumaOrRedPlane */ + planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */ + planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */ + + if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize]) return -1; - - srcp += status; } else { - status = planar_decompress_plane_raw(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 3, vFlip); - - if (status < 0) + if ((SrcSize - (srcp - pSrcData)) < (planeSize * 3)) return -1; - srcp += status; + planes[0] = srcp; /* LumaOrRedPlane */ + planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */ + planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */ + + if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize]) + return -1; + } + } + else /* RLE */ + { + if (alpha) + { + planes[3] = srcp; + rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - (planes[3] - pSrcData), + rawWidths[3], rawHeights[3]); /* AlphaPlane */ + + if (rleSizes[3] < 0) + return -1; + + planes[0] = planes[3] + rleSizes[3]; + rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData), + rawWidths[0], rawHeights[0]); /* RedPlane */ + + if (rleSizes[0] < 0) + return -1; + + planes[1] = planes[0] + rleSizes[0]; + rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData), + rawWidths[1], rawHeights[1]); /* GreenPlane */ + + if (rleSizes[1] < 1) + return -1; + + planes[2] = planes[1] + rleSizes[1]; + rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData), + rawWidths[2], rawHeights[2]); /* BluePlane */ + + if (rleSizes[2] < 1) + return -1; + } + else + { + planes[0] = srcp; + rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData), + rawWidths[0], rawHeights[0]); /* RedPlane */ + + if (rleSizes[0] < 0) + return -1; + + planes[1] = planes[0] + rleSizes[0]; + rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData), + rawWidths[1], rawHeights[1]); /* GreenPlane */ + + if (rleSizes[1] < 1) + return -1; + + planes[2] = planes[1] + rleSizes[1]; + rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData), + rawWidths[2], rawHeights[2]); /* BluePlane */ + + if (rleSizes[2] < 1) + return -1; } } - if (FormatHeader & PLANAR_FORMAT_HEADER_RLE) + if (!cll) /* RGB */ { - /* LumaOrRedPlane */ + if (!rle) /* RAW */ + { + if (alpha) + { + planar_decompress_planes_raw(planes, nWidth, pDstData, nDstStep, + nXDst, nYDst, nWidth, nHeight, alpha, vFlip); - status = planar_decompress_plane_rle(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); + srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3]; + } + else /* NoAlpha */ + { + planar_decompress_planes_raw(planes, nWidth, pDstData, nDstStep, + nXDst, nYDst, nWidth, nHeight, alpha, vFlip); - if (status < 0) - return -1; + srcp += rawSizes[0] + rawSizes[1] + rawSizes[2]; + } - srcp += status; + if ((SrcSize - (srcp - pSrcData)) == 1) + srcp++; /* pad */ + } + else /* RLE */ + { + if (alpha) + { + status = planar_decompress_plane_rle(planes[3], rleSizes[3], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 3, vFlip); /* AlphaPlane */ - /* OrangeChromaOrGreenPlane */ + status = planar_decompress_plane_rle(planes[0], rleSizes[0], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); /* RedPlane */ - status = planar_decompress_plane_rle(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); + status = planar_decompress_plane_rle(planes[1], rleSizes[1], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); /* GreenPlane */ - if (status < 0) - return -1; + status = planar_decompress_plane_rle(planes[2], rleSizes[2], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); /* BluePlane */ - srcp += status; + srcp += rleSizes[0] + rleSizes[1] + rleSizes[2] + rleSizes[3]; + } + else /* NoAlpha */ + { + status = planar_decompress_plane_rle(planes[0], rleSizes[0], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); /* RedPlane */ - /* GreenChromeOrBluePlane */ + status = planar_decompress_plane_rle(planes[1], rleSizes[1], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); /* GreenPlane */ - status = planar_decompress_plane_rle(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); + status = planar_decompress_plane_rle(planes[2], rleSizes[2], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); /* BluePlane */ - if (status < 0) - return -1; - - srcp += status; + srcp += rleSizes[0] + rleSizes[1] + rleSizes[2]; + } + } } - else + else /* YCoCg */ { - /* LumaOrRedPlane */ - - status = planar_decompress_plane_raw(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); - - if (status < 0) + if (cs) + { + WLog_ERR(TAG, "Chroma subsampling unimplemented"); return -1; + } - srcp += status; + if (!rle) /* RAW */ + { + if (alpha) + { + planar_decompress_planes_raw(planes, nWidth, pDstData, nDstStep, + nXDst, nYDst, nWidth, nHeight, alpha, vFlip); - /* OrangeChromaOrGreenPlane */ + srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3]; + } + else /* NoAlpha */ + { + planar_decompress_planes_raw(planes, nWidth, pDstData, nDstStep, + nXDst, nYDst, nWidth, nHeight, alpha, vFlip); - status = planar_decompress_plane_raw(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); + srcp += rawSizes[0] + rawSizes[1] + rawSizes[2]; + } - if (status < 0) - return -1; + if ((SrcSize - (srcp - pSrcData)) == 1) + srcp++; /* pad */ + } + else /* RLE */ + { + if (alpha) + { + status = planar_decompress_plane_rle(planes[3], rleSizes[3], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 3, vFlip); /* AlphaPlane */ - srcp += status; + status = planar_decompress_plane_rle(planes[0], rleSizes[0], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); /* LumaPlane */ - /* GreenChromeOrBluePlane */ + status = planar_decompress_plane_rle(planes[1], rleSizes[1], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); /* OrangeChromaPlane */ - status = planar_decompress_plane_raw(srcp, SrcSize - (srcp - pSrcData), - pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); + status = planar_decompress_plane_rle(planes[2], rleSizes[2], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); /* GreenChromaPlane */ - if (status < 0) - return -1; + srcp += rleSizes[0] + rleSizes[1] + rleSizes[2] + rleSizes[3]; + } + else /* NoAlpha */ + { + status = planar_decompress_plane_rle(planes[0], rleSizes[0], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 2, vFlip); /* LumaPlane */ - srcp += status; - srcp++; + status = planar_decompress_plane_rle(planes[1], rleSizes[1], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 1, vFlip); /* OrangeChromaPlane */ + + status = planar_decompress_plane_rle(planes[2], rleSizes[2], + pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, 0, vFlip); /* GreenChromaPlane */ + + srcp += rleSizes[0] + rleSizes[1] + rleSizes[2]; + } + } + + prims->YCoCgToRGB_8u_AC4R(pDstData, nDstStep, pDstData, nDstStep, nWidth, nHeight, cll, alpha, FALSE); } status = (SrcSize == (srcp - pSrcData)) ? 1 : -1; + if (status < 0) + return status; + + if (useTempBuffer) + { + pDstData = *ppDstData; + + status = freerdp_image_copy(pDstData, DstFormat, -1, 0, 0, nWidth, nHeight, + planar->TempBuffer, PIXEL_FORMAT_XRGB32, -1, 0, 0, NULL); + } + return status; } @@ -719,7 +1001,7 @@ int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int } BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, - int width, int height, int scanline, BYTE* dstData, int* dstSize) + int width, int height, int scanline, BYTE* dstData, int* pDstSize) { int size; BYTE* dstp; @@ -756,8 +1038,7 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, context->rlePlanes[3] = &context->rlePlanesBuffer[offset]; offset += dstSizes[3]; - - //printf("R: [%d/%d] G: [%d/%d] B: [%d/%d]\n", + //WLog_DBG(TAG, "R: [%d/%d] G: [%d/%d] B: [%d/%d]\n", // dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize); } } @@ -783,7 +1064,7 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, size++; dstData = malloc(size); - *dstSize = size; + *pDstSize = size; } dstp = dstData; @@ -855,11 +1136,16 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, } size = (dstp - dstData); - *dstSize = size; + *pDstSize = size; return dstData; } +int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context) +{ + return 1; +} + BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight) { BITMAP_PLANAR_CONTEXT* context; diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c new file mode 100644 index 000000000..0704403f1 --- /dev/null +++ b/libfreerdp/codec/progressive.c @@ -0,0 +1,1887 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Progressive Codec Bitmap Compression + * + * 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 +#include +#include +#include + +#include "rfx_differential.h" +#include "rfx_quantization.h" + +#define TAG FREERDP_TAG("codec.progressive") + +const char* progressive_get_block_type_string(UINT16 blockType) +{ + switch (blockType) + { + case PROGRESSIVE_WBT_SYNC: + return "PROGRESSIVE_WBT_SYNC"; + break; + + case PROGRESSIVE_WBT_FRAME_BEGIN: + return "PROGRESSIVE_WBT_FRAME_BEGIN"; + break; + + case PROGRESSIVE_WBT_FRAME_END: + return "PROGRESSIVE_WBT_FRAME_END"; + break; + + case PROGRESSIVE_WBT_CONTEXT: + return "PROGRESSIVE_WBT_CONTEXT"; + break; + + case PROGRESSIVE_WBT_REGION: + return "PROGRESSIVE_WBT_REGION"; + break; + + case PROGRESSIVE_WBT_TILE_SIMPLE: + return "PROGRESSIVE_WBT_TILE_SIMPLE"; + break; + + case PROGRESSIVE_WBT_TILE_FIRST: + return "PROGRESSIVE_WBT_TILE_FIRST"; + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + return "PROGRESSIVE_WBT_TILE_UPGRADE"; + break; + + default: + return "PROGRESSIVE_WBT_UNKNOWN"; + break; + } + + return "PROGRESSIVE_WBT_UNKNOWN"; +} + +void progressive_component_codec_quant_read(BYTE* block, RFX_COMPONENT_CODEC_QUANT* quantVal) +{ + quantVal->LL3 = block[0] & 0x0F; + quantVal->HL3 = block[0] >> 4; + quantVal->LH3 = block[1] & 0x0F; + quantVal->HH3 = block[1] >> 4; + quantVal->HL2 = block[2] & 0x0F; + quantVal->LH2 = block[2] >> 4; + quantVal->HH2 = block[3] & 0x0F; + quantVal->HL1 = block[3] >> 4; + quantVal->LH1 = block[4] & 0x0F; + quantVal->HH1 = block[4] >> 4; +} + +void progressive_rfx_quant_ladd(RFX_COMPONENT_CODEC_QUANT* q, int val) +{ + q->HL1 += val; /* HL1 */ + q->LH1 += val; /* LH1 */ + q->HH1 += val; /* HH1 */ + q->HL2 += val; /* HL2 */ + q->LH2 += val; /* LH2 */ + q->HH2 += val; /* HH2 */ + q->HL3 += val; /* HL3 */ + q->LH3 += val; /* LH3 */ + q->HH3 += val; /* HH3 */ + q->LL3 += val; /* LL3 */ +} + +void progressive_rfx_quant_add(RFX_COMPONENT_CODEC_QUANT* q1, RFX_COMPONENT_CODEC_QUANT* q2, RFX_COMPONENT_CODEC_QUANT* dst) +{ + dst->HL1 = q1->HL1 + q2->HL1; /* HL1 */ + dst->LH1 = q1->LH1 + q2->LH1; /* LH1 */ + dst->HH1 = q1->HH1 + q2->HH1; /* HH1 */ + dst->HL2 = q1->HL2 + q2->HL2; /* HL2 */ + dst->LH2 = q1->LH2 + q2->LH2; /* LH2 */ + dst->HH2 = q1->HH2 + q2->HH2; /* HH2 */ + dst->HL3 = q1->HL3 + q2->HL3; /* HL3 */ + dst->LH3 = q1->LH3 + q2->LH3; /* LH3 */ + dst->HH3 = q1->HH3 + q2->HH3; /* HH3 */ + dst->LL3 = q1->LL3 + q2->LL3; /* LL3 */ +} + +void progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* q, int val) +{ + q->HL1 -= val; /* HL1 */ + q->LH1 -= val; /* LH1 */ + q->HH1 -= val; /* HH1 */ + q->HL2 -= val; /* HL2 */ + q->LH2 -= val; /* LH2 */ + q->HH2 -= val; /* HH2 */ + q->HL3 -= val; /* HL3 */ + q->LH3 -= val; /* LH3 */ + q->HH3 -= val; /* HH3 */ + q->LL3 -= val; /* LL3 */ +} + +void progressive_rfx_quant_sub(RFX_COMPONENT_CODEC_QUANT* q1, RFX_COMPONENT_CODEC_QUANT* q2, RFX_COMPONENT_CODEC_QUANT* dst) +{ + dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */ + dst->LH1 = q1->LH1 - q2->LH1; /* LH1 */ + dst->HH1 = q1->HH1 - q2->HH1; /* HH1 */ + dst->HL2 = q1->HL2 - q2->HL2; /* HL2 */ + dst->LH2 = q1->LH2 - q2->LH2; /* LH2 */ + dst->HH2 = q1->HH2 - q2->HH2; /* HH2 */ + dst->HL3 = q1->HL3 - q2->HL3; /* HL3 */ + dst->LH3 = q1->LH3 - q2->LH3; /* LH3 */ + dst->HH3 = q1->HH3 - q2->HH3; /* HH3 */ + dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */ +} + +BOOL progressive_rfx_quant_lcmp_less_equal(RFX_COMPONENT_CODEC_QUANT* q, int val) +{ + if (q->HL1 > val) return FALSE; /* HL1 */ + if (q->LH1 > val) return FALSE; /* LH1 */ + if (q->HH1 > val) return FALSE; /* HH1 */ + if (q->HL2 > val) return FALSE; /* HL2 */ + if (q->LH2 > val) return FALSE; /* LH2 */ + if (q->HH2 > val) return FALSE; /* HH2 */ + if (q->HL3 > val) return FALSE; /* HL3 */ + if (q->LH3 > val) return FALSE; /* LH3 */ + if (q->HH3 > val) return FALSE; /* HH3 */ + if (q->LL3 > val) return FALSE; /* LL3 */ + return TRUE; +} + +BOOL progressive_rfx_quant_cmp_less_equal(RFX_COMPONENT_CODEC_QUANT* q1, RFX_COMPONENT_CODEC_QUANT* q2) +{ + if (q1->HL1 > q2->HL1) return FALSE; /* HL1 */ + if (q1->LH1 > q2->LH1) return FALSE; /* LH1 */ + if (q1->HH1 > q2->HH1) return FALSE; /* HH1 */ + if (q1->HL2 > q2->HL2) return FALSE; /* HL2 */ + if (q1->LH2 > q2->LH2) return FALSE; /* LH2 */ + if (q1->HH2 > q2->HH2) return FALSE; /* HH2 */ + if (q1->HL3 > q2->HL3) return FALSE; /* HL3 */ + if (q1->LH3 > q2->LH3) return FALSE; /* LH3 */ + if (q1->HH3 > q2->HH3) return FALSE; /* HH3 */ + if (q1->LL3 > q2->LL3) return FALSE; /* LL3 */ + return TRUE; +} + +BOOL progressive_rfx_quant_lcmp_greater_equal(RFX_COMPONENT_CODEC_QUANT* q, int val) +{ + if (q->HL1 < val) return FALSE; /* HL1 */ + if (q->LH1 < val) return FALSE; /* LH1 */ + if (q->HH1 < val) return FALSE; /* HH1 */ + if (q->HL2 < val) return FALSE; /* HL2 */ + if (q->LH2 < val) return FALSE; /* LH2 */ + if (q->HH2 < val) return FALSE; /* HH2 */ + if (q->HL3 < val) return FALSE; /* HL3 */ + if (q->LH3 < val) return FALSE; /* LH3 */ + if (q->HH3 < val) return FALSE; /* HH3 */ + if (q->LL3 < val) return FALSE; /* LL3 */ + return TRUE; +} + +BOOL progressive_rfx_quant_cmp_greater_equal(RFX_COMPONENT_CODEC_QUANT* q1, RFX_COMPONENT_CODEC_QUANT* q2) +{ + if (q1->HL1 < q2->HL1) return FALSE; /* HL1 */ + if (q1->LH1 < q2->LH1) return FALSE; /* LH1 */ + if (q1->HH1 < q2->HH1) return FALSE; /* HH1 */ + if (q1->HL2 < q2->HL2) return FALSE; /* HL2 */ + if (q1->LH2 < q2->LH2) return FALSE; /* LH2 */ + if (q1->HH2 < q2->HH2) return FALSE; /* HH2 */ + if (q1->HL3 < q2->HL3) return FALSE; /* HL3 */ + if (q1->LH3 < q2->LH3) return FALSE; /* LH3 */ + if (q1->HH3 < q2->HH3) return FALSE; /* HH3 */ + if (q1->LL3 < q2->LL3) return FALSE; /* LL3 */ + return TRUE; +} + +BOOL progressive_rfx_quant_cmp_equal(RFX_COMPONENT_CODEC_QUANT* q1, RFX_COMPONENT_CODEC_QUANT* q2) +{ + if (q1->HL1 != q2->HL1) return FALSE; /* HL1 */ + if (q1->LH1 != q2->LH1) return FALSE; /* LH1 */ + if (q1->HH1 != q2->HH1) return FALSE; /* HH1 */ + if (q1->HL2 != q2->HL2) return FALSE; /* HL2 */ + if (q1->LH2 != q2->LH2) return FALSE; /* LH2 */ + if (q1->HH2 != q2->HH2) return FALSE; /* HH2 */ + if (q1->HL3 != q2->HL3) return FALSE; /* HL3 */ + if (q1->LH3 != q2->LH3) return FALSE; /* LH3 */ + if (q1->HH3 != q2->HH3) return FALSE; /* HH3 */ + if (q1->LL3 != q2->LL3) return FALSE; /* LL3 */ + return TRUE; +} + +int progressive_set_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, void* pData) +{ + ULONG_PTR key; + + key = ((ULONG_PTR) surfaceId) + 1; + + if (pData) + HashTable_Add(progressive->SurfaceContexts, (void*) key, pData); + else + HashTable_Remove(progressive->SurfaceContexts, (void*) key); + + return 1; +} + +void* progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) +{ + ULONG_PTR key; + void* pData = NULL; + + key = ((ULONG_PTR) surfaceId) + 1; + + pData = HashTable_GetItemValue(progressive->SurfaceContexts, (void*) key); + + return pData; +} + +PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width, UINT32 height) +{ + PROGRESSIVE_SURFACE_CONTEXT* surface; + + surface = (PROGRESSIVE_SURFACE_CONTEXT*) calloc(1, sizeof(PROGRESSIVE_SURFACE_CONTEXT)); + + if (!surface) + return NULL; + + surface->id = surfaceId; + surface->width = width; + surface->height = height; + surface->gridWidth = (width + (width % 64)) / 64; + surface->gridHeight = (height + (height % 64)) / 64; + surface->gridSize = surface->gridWidth * surface->gridHeight; + + surface->tiles = (RFX_PROGRESSIVE_TILE*) calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); + + if (!surface->tiles) + return NULL; + + return surface; +} + +void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + UINT32 index; + RFX_PROGRESSIVE_TILE* tile; + + for (index = 0; index < surface->gridSize; index++) + { + tile = &(surface->tiles[index]); + + if (tile->data) + _aligned_free(tile->data); + + if (tile->sign) + _aligned_free(tile->sign); + + if (tile->current) + _aligned_free(tile->current); + } + + free(surface->tiles); + free(surface); +} + +int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, UINT32 width, UINT32 height) +{ + PROGRESSIVE_SURFACE_CONTEXT* surface; + + surface = (PROGRESSIVE_SURFACE_CONTEXT*) progressive_get_surface_data(progressive, surfaceId); + + if (!surface) + { + surface = progressive_surface_context_new(surfaceId, width, height); + + if (!surface) + return -1; + + progressive_set_surface_data(progressive, surfaceId, (void*) surface); + } + + return 1; +} + +int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) +{ + PROGRESSIVE_SURFACE_CONTEXT* surface; + + surface = (PROGRESSIVE_SURFACE_CONTEXT*) progressive_get_surface_data(progressive, surfaceId); + + if (surface) + { + progressive_set_surface_data(progressive, surfaceId, NULL); + progressive_surface_context_free(surface); + } + + return 1; +} + +/* + * Band Offset Dimensions Size + * + * HL1 0 31x33 1023 + * LH1 1023 33x31 1023 + * HH1 2046 31x31 961 + * + * HL2 3007 16x17 272 + * LH2 3279 17x16 272 + * HH2 3551 16x16 256 + * + * HL3 3807 8x9 72 + * LH3 3879 9x8 72 + * HH3 3951 8x8 64 + * + * LL3 4015 9x9 81 + */ + +static void progressive_rfx_idwt_x(INT16* pLowBand, int nLowStep, INT16* pHighBand, int nHighStep, + INT16* pDstBand, int nDstStep, int nLowCount, int nHighCount, int nDstCount) +{ + int i, j; + INT16 L0; + INT16 H0, H1; + INT16 X0, X1, X2; + INT16 *pL, *pH, *pX; + + for (i = 0; i < nDstCount; i++) + { + pL = pLowBand; + pH = pHighBand; + pX = pDstBand; + + H0 = *pH; + pH++; + + L0 = *pL; + pL++; + + X0 = L0 - H0; + X2 = L0 - H0; + + for (j = 0; j < (nHighCount - 1); j++) + { + H1 = *pH; + pH++; + + L0 = *pL; + pL++; + + X2 = L0 - ((H0 + H1) / 2); + X1 = ((X0 + X2) / 2) + (2 * H0); + + pX[0] = X0; + pX[1] = X1; + pX += 2; + + X0 = X2; + H0 = H1; + } + + if (nLowCount <= (nHighCount + 1)) + { + if (nLowCount <= nHighCount) + { + pX[0] = X2; + pX[1] = X2 + (2 * H0); + } + else + { + L0 = *pL; + pL++; + + X0 = L0 - H0; + + pX[0] = X2; + pX[1] = ((X0 + X2) / 2) + (2 * H0); + pX[2] = X0; + } + } + else + { + L0 = *pL; + pL++; + + X0 = L0 - (H0 / 2); + + pX[0] = X2; + pX[1] = ((X0 + X2) / 2) + (2 * H0); + pX[2] = X0; + + L0 = *pL; + pL++; + + pX[3] = (X0 + L0) / 2; + } + + pLowBand += nLowStep; + pHighBand += nHighStep; + pDstBand += nDstStep; + } +} + +static void progressive_rfx_idwt_y(INT16* pLowBand, int nLowStep, INT16* pHighBand, int nHighStep, + INT16* pDstBand, int nDstStep, int nLowCount, int nHighCount, int nDstCount) +{ + int i, j; + INT16 L0; + INT16 H0, H1; + INT16 X0, X1, X2; + INT16 *pL, *pH, *pX; + + for (i = 0; i < nDstCount; i++) + { + pL = pLowBand; + pH = pHighBand; + pX = pDstBand; + + H0 = *pH; + pH += nHighStep; + + L0 = *pL; + pL += nLowStep; + + X0 = L0 - H0; + X2 = L0 - H0; + + for (j = 0; j < (nHighCount - 1); j++) + { + H1 = *pH; + pH += nHighStep; + + L0 = *pL; + pL += nLowStep; + + X2 = L0 - ((H0 + H1) / 2); + X1 = ((X0 + X2) / 2) + (2 * H0); + + *pX = X0; + pX += nDstStep; + + *pX = X1; + pX += nDstStep; + + X0 = X2; + H0 = H1; + } + + if (nLowCount <= (nHighCount + 1)) + { + if (nLowCount <= nHighCount) + { + *pX = X2; + pX += nDstStep; + + *pX = X2 + (2 * H0); + pX += nDstStep; + } + else + { + L0 = *pL; + pL += nLowStep; + + X0 = L0 - H0; + + *pX = X2; + pX += nDstStep; + + *pX = ((X0 + X2) / 2) + (2 * H0); + pX += nDstStep; + + *pX = X0; + pX += nDstStep; + } + } + else + { + L0 = *pL; + pL += nLowStep; + + X0 = L0 - (H0 / 2); + + *pX = X2; + pX += nDstStep; + + *pX = ((X0 + X2) / 2) + (2 * H0); + pX += nDstStep; + + *pX = X0; + pX += nDstStep; + + L0 = *pL; + pL += nLowStep; + + *pX = (X0 + L0) / 2; + pX += nDstStep; + } + + pLowBand++; + pHighBand++; + pDstBand++; + } +} + +static int progressive_rfx_get_band_l_count(int level) +{ + return (64 >> level) + 1; +} + +static int progressive_rfx_get_band_h_count(int level) +{ + if (level == 1) + return (64 >> 1) - 1; + else + return (64 + (1 << (level - 1))) >> level; +} + +static void progressive_rfx_dwt_2d_decode_block(INT16* buffer, INT16* temp, int level) +{ + int offset; + int nBandL; + int nBandH; + int nDstStepX; + int nDstStepY; + INT16 *HL, *LH; + INT16 *HH, *LL; + INT16 *L, *H, *LLx; + INT16* pLowBand[3]; + INT16* pHighBand[3]; + INT16* pDstBand[3]; + int nLowStep[3]; + int nHighStep[3]; + int nDstStep[3]; + int nLowCount[3]; + int nHighCount[3]; + int nDstCount[3]; + + nBandL = progressive_rfx_get_band_l_count(level); + nBandH = progressive_rfx_get_band_h_count(level); + + offset = 0; + + HL = &buffer[offset]; + offset += (nBandH * nBandL); + + LH = &buffer[offset]; + offset += (nBandL * nBandH); + + HH = &buffer[offset]; + offset += (nBandH * nBandH); + + LL = &buffer[offset]; + offset += (nBandL * nBandL); + + nDstStepX = (nBandL + nBandH); + nDstStepY = (nBandL + nBandH); + + offset = 0; + + L = &temp[offset]; + offset += (nBandL * nDstStepX); + + H = &temp[offset]; + offset += (nBandH * nDstStepX); + + LLx = &buffer[0]; + + /* horizontal (LL + HL -> L) */ + + pLowBand[0] = LL; + nLowStep[0] = nBandL; + pHighBand[0] = HL; + nHighStep[0] = nBandH; + pDstBand[0] = L; + nDstStep[0] = nDstStepX; + nLowCount[0] = nBandL; + nHighCount[0] = nBandH; + nDstCount[0] = nBandL; + + progressive_rfx_idwt_x(pLowBand[0], nLowStep[0], pHighBand[0], nHighStep[0], pDstBand[0], nDstStep[0], nLowCount[0], nHighCount[0], nDstCount[0]); + + /* horizontal (LH + HH -> H) */ + + pLowBand[1] = LH; + nLowStep[1] = nBandL; + pHighBand[1] = HH; + nHighStep[1] = nBandH; + pDstBand[1] = H; + nDstStep[1] = nDstStepX; + nLowCount[1] = nBandL; + nHighCount[1] = nBandH; + nDstCount[1] = nBandH; + + progressive_rfx_idwt_x(pLowBand[1], nLowStep[1], pHighBand[1], nHighStep[1], pDstBand[1], nDstStep[1], nLowCount[1], nHighCount[1], nDstCount[1]); + + /* vertical (L + H -> LL) */ + + pLowBand[2] = pDstBand[0]; + nLowStep[2] = nDstStep[0]; + pHighBand[2] = pDstBand[1]; + nHighStep[2] = nDstStep[1]; + pDstBand[2] = LLx; + nDstStep[2] = nDstStepY; + nLowCount[2] = nBandL; + nHighCount[2] = nBandH; + nDstCount[2] = nBandL + nBandH; + + progressive_rfx_idwt_y(pLowBand[2], nLowStep[2], pHighBand[2], nHighStep[2], pDstBand[2], nDstStep[2], nLowCount[2], nHighCount[2], nDstCount[2]); +} + +void progressive_rfx_dwt_2d_decode(INT16* buffer, INT16* temp, INT16* current, INT16* sign, BOOL diff) +{ + const primitives_t* prims = primitives_get(); + + if (diff) + prims->add_16s(buffer, current, buffer, 4096); + + CopyMemory(current, buffer, 4096 * 2); + + progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3); + progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2); + progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1); +} + +void progressive_rfx_decode_block(const primitives_t* prims, INT16* buffer, int length, UINT32 shift) +{ + if (!shift) + return; + + prims->lShiftC_16s(buffer, shift, buffer, length); +} + +int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progressive, RFX_COMPONENT_CODEC_QUANT* shift, + const BYTE* data, int length, INT16* buffer, INT16* current, INT16* sign, BOOL diff) +{ + int status; + INT16* temp; + const primitives_t* prims = primitives_get(); + + status = rfx_rlgr_decode(data, length, buffer, 4096, 1); + + if (status < 0) + return status; + + CopyMemory(sign, buffer, 4096 * 2); + + rfx_differential_decode(&buffer[4015], 81); /* LL3 */ + + progressive_rfx_decode_block(prims, &buffer[0], 1023, shift->HL1); /* HL1 */ + progressive_rfx_decode_block(prims, &buffer[1023], 1023, shift->LH1); /* LH1 */ + progressive_rfx_decode_block(prims, &buffer[2046], 961, shift->HH1); /* HH1 */ + progressive_rfx_decode_block(prims, &buffer[3007], 272, shift->HL2); /* HL2 */ + progressive_rfx_decode_block(prims, &buffer[3279], 272, shift->LH2); /* LH2 */ + progressive_rfx_decode_block(prims, &buffer[3551], 256, shift->HH2); /* HH2 */ + progressive_rfx_decode_block(prims, &buffer[3807], 72, shift->HL3); /* HL3 */ + progressive_rfx_decode_block(prims, &buffer[3879], 72, shift->LH3); /* LH3 */ + progressive_rfx_decode_block(prims, &buffer[3951], 64, shift->HH3); /* HH3 */ + progressive_rfx_decode_block(prims, &buffer[4015], 81, shift->LL3); /* LL3 */ + + temp = (INT16*) BufferPool_Take(progressive->bufferPool, -1); /* DWT buffer */ + + progressive_rfx_dwt_2d_decode(buffer, temp, current, sign, diff); + + BufferPool_Return(progressive->bufferPool, temp); + + return 1; +} + +int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progressive, RFX_PROGRESSIVE_TILE* tile) +{ + BOOL diff; + BYTE* pBuffer; + INT16* pSign[3]; + INT16* pSrcDst[3]; + INT16* pCurrent[3]; + PROGRESSIVE_BLOCK_REGION* region; + RFX_COMPONENT_CODEC_QUANT shiftY; + RFX_COMPONENT_CODEC_QUANT shiftCb; + RFX_COMPONENT_CODEC_QUANT shiftCr; + RFX_COMPONENT_CODEC_QUANT* quantY; + RFX_COMPONENT_CODEC_QUANT* quantCb; + RFX_COMPONENT_CODEC_QUANT* quantCr; + RFX_COMPONENT_CODEC_QUANT* quantProgY; + RFX_COMPONENT_CODEC_QUANT* quantProgCb; + RFX_COMPONENT_CODEC_QUANT* quantProgCr; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; + static const prim_size_t roi_64x64 = { 64, 64 }; + const primitives_t* prims = primitives_get(); + + tile->pass = 1; + + diff = tile->flags & RFX_TILE_DIFFERENCE; + +#if 0 + WLog_INFO(TAG, "ProgressiveTileFirst: quantIdx Y: %d Cb: %d Cr: %d xIdx: %d yIdx: %d flags: 0x%02X quality: %d yLen: %d cbLen: %d crLen: %d tailLen: %d", + tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx, tile->flags, tile->quality, tile->yLen, tile->cbLen, tile->crLen, tile->tailLen); +#endif + + region = &(progressive->region); + + if (tile->quantIdxY >= region->numQuant) + return -1; + + quantY = &(region->quantVals[tile->quantIdxY]); + + if (tile->quantIdxCb >= region->numQuant) + return -1; + + quantCb = &(region->quantVals[tile->quantIdxCb]); + + if (tile->quantIdxCr >= region->numQuant) + return -1; + + quantCr = &(region->quantVals[tile->quantIdxCr]); + + if (tile->quality == 0xFF) + { + quantProgVal = &(progressive->quantProgValFull); + } + else + { + if (tile->quality >= region->numProgQuant) + return -1; + + quantProgVal = &(region->quantProgVals[tile->quality]); + } + + quantProgY = &(quantProgVal->yQuantValues); + quantProgCb = &(quantProgVal->cbQuantValues); + quantProgCr = &(quantProgVal->crQuantValues); + + CopyMemory(&(tile->yQuant), quantY, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->cbQuant), quantCb, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->crQuant), quantCr, sizeof(RFX_COMPONENT_CODEC_QUANT)); + + CopyMemory(&(tile->yProgQuant), quantProgY, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->cbProgQuant), quantProgCb, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->crProgQuant), quantProgCr, sizeof(RFX_COMPONENT_CODEC_QUANT)); + + progressive_rfx_quant_add(quantY, quantProgY, &(tile->yBitPos)); + progressive_rfx_quant_add(quantCb, quantProgCb, &(tile->cbBitPos)); + progressive_rfx_quant_add(quantCr, quantProgCr, &(tile->crBitPos)); + + progressive_rfx_quant_add(quantY, quantProgY, &shiftY); + progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */ + progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb); + progressive_rfx_quant_lsub(&shiftCb, 1); /* -6 + 5 = -1 */ + progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr); + progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */ + + if (!tile->data) + { + tile->data = (BYTE*) _aligned_malloc(64 * 64 * 4, 16); + } + + if (!tile->sign) + { + tile->sign = (BYTE*) _aligned_malloc((8192 + 32) * 3, 16); + } + + if (!tile->current) + { + tile->current = (BYTE*) _aligned_malloc((8192 + 32) * 3, 16); + } + + pBuffer = tile->sign; + pSign[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pSign[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pSign[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + pBuffer = tile->current; + pCurrent[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pCurrent[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pCurrent[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + pBuffer = (BYTE*) BufferPool_Take(progressive->bufferPool, -1); + pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + progressive_rfx_decode_component(progressive, &shiftY, tile->yData, tile->yLen, pSrcDst[0], pCurrent[0], pSign[0], diff); /* Y */ + progressive_rfx_decode_component(progressive, &shiftCb, tile->cbData, tile->cbLen, pSrcDst[1], pCurrent[1], pSign[1], diff); /* Cb */ + progressive_rfx_decode_component(progressive, &shiftCr, tile->crData, tile->crLen, pSrcDst[2], pCurrent[2], pSign[2], diff); /* Cr */ + + if (!progressive->invert) + prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2, tile->data, 64 * 4, &roi_64x64); + else + prims->yCbCrToBGR_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2, tile->data, 64 * 4, &roi_64x64); + + BufferPool_Return(progressive->bufferPool, pBuffer); + + //WLog_Image(progressive->log, WLOG_TRACE, tile->data, 64, 64, 32); + + return 1; +} + +struct _RFX_PROGRESSIVE_UPGRADE_STATE +{ + BOOL nonLL; + wBitStream* srl; + wBitStream* raw; + + /* SRL state */ + + int kp; + int nz; + BOOL mode; +}; +typedef struct _RFX_PROGRESSIVE_UPGRADE_STATE RFX_PROGRESSIVE_UPGRADE_STATE; + +INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* state, UINT32 numBits) +{ + int k; + UINT32 bit; + UINT32 max; + UINT32 mag; + UINT32 sign; + wBitStream* bs = state->srl; + + if (state->nz) + { + state->nz--; + return 0; + } + + k = state->kp / 8; + + if (!state->mode) + { + /* zero encoding */ + + bit = (bs->accumulator & 0x80000000) ? 1 : 0; + BitStream_Shift(bs, 1); + + if (!bit) + { + /* '0' bit, nz >= (1 << k), nz = (1 << k) */ + + state->nz = (1 << k); + + state->kp += 4; + + if (state->kp > 80) + state->kp = 80; + + state->nz--; + return 0; + } + else + { + /* '1' bit, nz < (1 << k), nz = next k bits */ + + state->nz = 0; + state->mode = 1; /* unary encoding is next */ + + if (k) + { + bs->mask = ((1 << k) - 1); + state->nz = ((bs->accumulator >> (32 - k)) & bs->mask); + BitStream_Shift(bs, k); + } + + if (state->nz) + { + state->nz--; + return 0; + } + } + } + + state->mode = 0; /* zero encoding is next */ + + /* unary encoding */ + + /* read sign bit */ + + sign = (bs->accumulator & 0x80000000) ? 1 : 0; + BitStream_Shift(bs, 1); + + state->kp -= 6; + + if (state->kp < 0) + state->kp = 0; + + if (numBits == 1) + return sign ? -1 : 1; + + mag = 1; + max = (1 << numBits) - 1; + + while (mag < max) + { + bit = (bs->accumulator & 0x80000000) ? 1 : 0; + BitStream_Shift(bs, 1); + + if (bit) + break; + + mag++; + } + + return sign ? -mag : mag; +} + +int progressive_rfx_upgrade_state_finish(RFX_PROGRESSIVE_UPGRADE_STATE* state) +{ + int pad; + wBitStream* srl; + wBitStream* raw; + + srl = state->srl; + raw = state->raw; + + /* Read trailing bits from RAW/SRL bit streams */ + + pad = (raw->position % 8) ? (8 - (raw->position % 8)) : 0; + + if (pad) + BitStream_Shift(raw, pad); + + pad = (srl->position % 8) ? (8 - (srl->position % 8)) : 0; + + if (pad) + BitStream_Shift(srl, pad); + + if (BitStream_GetRemainingLength(srl) == 8) + BitStream_Shift(srl, 8); + + return 1; +} + +int progressive_rfx_upgrade_block(RFX_PROGRESSIVE_UPGRADE_STATE* state, INT16* buffer, + INT16* sign, int length, UINT32 shift, UINT32 bitPos, UINT32 numBits) +{ + int index; + INT16 input; + wBitStream* srl; + wBitStream* raw; + + if (!numBits) + return 1; + + srl = state->srl; + raw = state->raw; + + if (!state->nonLL) + { + for (index = 0; index < length; index++) + { + raw->mask = ((1 << numBits) - 1); + input = (INT16) ((raw->accumulator >> (32 - numBits)) & raw->mask); + BitStream_Shift(raw, numBits); + + buffer[index] += (input << shift); + } + + return 1; + } + + for (index = 0; index < length; index++) + { + if (sign[index] > 0) + { + /* sign > 0, read from raw */ + + raw->mask = ((1 << numBits) - 1); + input = (INT16) ((raw->accumulator >> (32 - numBits)) & raw->mask); + BitStream_Shift(raw, numBits); + } + else if (sign[index] < 0) + { + /* sign < 0, read from raw */ + + raw->mask = ((1 << numBits) - 1); + input = (INT16) ((raw->accumulator >> (32 - numBits)) & raw->mask); + BitStream_Shift(raw, numBits); + + input *= -1; + } + else + { + /* sign == 0, read from srl */ + + input = progressive_rfx_srl_read(state, numBits); + + sign[index] = input; + } + + buffer[index] += (input << shift); + } + + return 1; +} + +int progressive_rfx_upgrade_component(PROGRESSIVE_CONTEXT* progressive, RFX_COMPONENT_CODEC_QUANT* shift, + RFX_COMPONENT_CODEC_QUANT* bitPos, RFX_COMPONENT_CODEC_QUANT* numBits, INT16* buffer, + INT16* current, INT16* sign, const BYTE* srlData, int srlLen, const BYTE* rawData, int rawLen) +{ + INT16* temp; + int aRawLen; + int aSrlLen; + wBitStream s_srl; + wBitStream s_raw; + RFX_PROGRESSIVE_UPGRADE_STATE state; + + ZeroMemory(&s_srl, sizeof(wBitStream)); + ZeroMemory(&s_raw, sizeof(wBitStream)); + ZeroMemory(&state, sizeof(RFX_PROGRESSIVE_UPGRADE_STATE)); + + state.kp = 8; + state.mode = 0; + state.srl = &s_srl; + state.raw = &s_raw; + + BitStream_Attach(state.srl, srlData, srlLen); + BitStream_Fetch(state.srl); + + BitStream_Attach(state.raw, rawData, rawLen); + BitStream_Fetch(state.raw); + + state.nonLL = TRUE; + progressive_rfx_upgrade_block(&state, ¤t[0], &sign[0], 1023, shift->HL1, bitPos->HL1, numBits->HL1); /* HL1 */ + progressive_rfx_upgrade_block(&state, ¤t[1023], &sign[1023], 1023, shift->LH1, bitPos->LH1, numBits->LH1); /* LH1 */ + progressive_rfx_upgrade_block(&state, ¤t[2046], &sign[2046], 961, shift->HH1, bitPos->HH1, numBits->HH1); /* HH1 */ + progressive_rfx_upgrade_block(&state, ¤t[3007], &sign[3007], 272, shift->HL2, bitPos->HL2, numBits->HL2); /* HL2 */ + progressive_rfx_upgrade_block(&state, ¤t[3279], &sign[3279], 272, shift->LH2, bitPos->LH2, numBits->LH2); /* LH2 */ + progressive_rfx_upgrade_block(&state, ¤t[3551], &sign[3551], 256, shift->HH2, bitPos->HH2, numBits->HH2); /* HH2 */ + progressive_rfx_upgrade_block(&state, ¤t[3807], &sign[3807], 72, shift->HL3, bitPos->HL3, numBits->HL3); /* HL3 */ + progressive_rfx_upgrade_block(&state, ¤t[3879], &sign[3879], 72, shift->LH3, bitPos->LH3, numBits->LH3); /* LH3 */ + progressive_rfx_upgrade_block(&state, ¤t[3951], &sign[3951], 64, shift->HH3, bitPos->HH3, numBits->HH3); /* HH3 */ + + state.nonLL = FALSE; + progressive_rfx_upgrade_block(&state, ¤t[4015], &sign[4015], 81, shift->LL3, bitPos->LL3, numBits->LL3); /* LL3 */ + progressive_rfx_upgrade_state_finish(&state); + + aRawLen = (state.raw->position + 7) / 8; + aSrlLen = (state.srl->position + 7) / 8; + + if ((aRawLen != rawLen) || (aSrlLen != srlLen)) + { + int pRawLen = 0; + int pSrlLen = 0; + + if (rawLen) + pRawLen = (int) ((((float) aRawLen) / ((float) rawLen)) * 100.0f); + + if (srlLen) + pSrlLen = (int) ((((float) aSrlLen) / ((float) srlLen)) * 100.0f); + + WLog_INFO(TAG, "RAW: %d/%d %d%% (%d/%d:%d)\tSRL: %d/%d %d%% (%d/%d:%d)", + aRawLen, rawLen, pRawLen, state.raw->position, rawLen * 8, + (rawLen * 8) - state.raw->position, + aSrlLen, srlLen, pSrlLen, state.srl->position, srlLen * 8, + (srlLen * 8) - state.srl->position); + + return -1; + } + + temp = (INT16*) BufferPool_Take(progressive->bufferPool, -1); /* DWT buffer */ + + CopyMemory(buffer, current, 4096 * 2); + + progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3); + progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2); + progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1); + + BufferPool_Return(progressive->bufferPool, temp); + + return 1; +} + +int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progressive, RFX_PROGRESSIVE_TILE* tile) +{ + int status; + BYTE* pBuffer; + INT16* pSign[3]; + INT16* pSrcDst[3]; + INT16* pCurrent[3]; + PROGRESSIVE_BLOCK_REGION* region; + RFX_COMPONENT_CODEC_QUANT shiftY; + RFX_COMPONENT_CODEC_QUANT shiftCb; + RFX_COMPONENT_CODEC_QUANT shiftCr; + RFX_COMPONENT_CODEC_QUANT yBitPos; + RFX_COMPONENT_CODEC_QUANT cbBitPos; + RFX_COMPONENT_CODEC_QUANT crBitPos; + RFX_COMPONENT_CODEC_QUANT yNumBits; + RFX_COMPONENT_CODEC_QUANT cbNumBits; + RFX_COMPONENT_CODEC_QUANT crNumBits; + RFX_COMPONENT_CODEC_QUANT* quantY; + RFX_COMPONENT_CODEC_QUANT* quantCb; + RFX_COMPONENT_CODEC_QUANT* quantCr; + RFX_COMPONENT_CODEC_QUANT* quantProgY; + RFX_COMPONENT_CODEC_QUANT* quantProgCb; + RFX_COMPONENT_CODEC_QUANT* quantProgCr; + RFX_PROGRESSIVE_CODEC_QUANT* quantProg; + static const prim_size_t roi_64x64 = { 64, 64 }; + const primitives_t* prims = primitives_get(); + + tile->pass++; + +#if 0 + WLog_INFO(TAG, "ProgressiveTileUpgrade: pass: %d quantIdx Y: %d Cb: %d Cr: %d xIdx: %d yIdx: %d quality: %d ySrlLen: %d yRawLen: %d cbSrlLen: %d cbRawLen: %d crSrlLen: %d crRawLen: %d", + tile->pass, tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx, tile->quality, tile->ySrlLen, tile->yRawLen, tile->cbSrlLen, tile->cbRawLen, tile->crSrlLen, tile->crRawLen); +#endif + + region = &(progressive->region); + + if (tile->quantIdxY >= region->numQuant) + return -1; + + quantY = &(region->quantVals[tile->quantIdxY]); + + if (tile->quantIdxCb >= region->numQuant) + return -1; + + quantCb = &(region->quantVals[tile->quantIdxCb]); + + if (tile->quantIdxCr >= region->numQuant) + return -1; + + quantCr = &(region->quantVals[tile->quantIdxCr]); + + if (tile->quality == 0xFF) + { + quantProg = &(progressive->quantProgValFull); + } + else + { + if (tile->quality >= region->numProgQuant) + return -1; + + quantProg = &(region->quantProgVals[tile->quality]); + } + + quantProgY = &(quantProg->yQuantValues); + quantProgCb = &(quantProg->cbQuantValues); + quantProgCr = &(quantProg->crQuantValues); + + if (!progressive_rfx_quant_cmp_equal(quantY, &(tile->yQuant))) + WLog_WARN(TAG, "non-progressive quantY has changed!"); + if (!progressive_rfx_quant_cmp_equal(quantCb, &(tile->cbQuant))) + WLog_WARN(TAG, "non-progressive quantCb has changed!"); + if (!progressive_rfx_quant_cmp_equal(quantCr, &(tile->crQuant))) + WLog_WARN(TAG, "non-progressive quantCr has changed!"); + + progressive_rfx_quant_add(quantY, quantProgY, &yBitPos); + progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos); + progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos); + + progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits); + progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits); + progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits); + + progressive_rfx_quant_add(quantY, quantProgY, &shiftY); + progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */ + progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb); + progressive_rfx_quant_lsub(&shiftCb, 1); /* -6 + 5 = -1 */ + progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr); + progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */ + + CopyMemory(&(tile->yBitPos), &yBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->cbBitPos), &cbBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->crBitPos), &crBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT)); + + CopyMemory(&(tile->yQuant), quantY, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->cbQuant), quantCb, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->crQuant), quantCr, sizeof(RFX_COMPONENT_CODEC_QUANT)); + + CopyMemory(&(tile->yProgQuant), quantProgY, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->cbProgQuant), quantProgCb, sizeof(RFX_COMPONENT_CODEC_QUANT)); + CopyMemory(&(tile->crProgQuant), quantProgCr, sizeof(RFX_COMPONENT_CODEC_QUANT)); + + pBuffer = tile->sign; + pSign[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pSign[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pSign[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + pBuffer = tile->current; + pCurrent[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pCurrent[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pCurrent[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + pBuffer = (BYTE*) BufferPool_Take(progressive->bufferPool, -1); + pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + status = progressive_rfx_upgrade_component(progressive, &shiftY, quantProgY, &yNumBits, + pSrcDst[0], pCurrent[0], pSign[0], tile->ySrlData, tile->ySrlLen, tile->yRawData, tile->yRawLen); /* Y */ + + if (status < 0) + return -1; + + status = progressive_rfx_upgrade_component(progressive, &shiftCb, quantProgCb, &cbNumBits, + pSrcDst[1], pCurrent[1], pSign[1], tile->cbSrlData, tile->cbSrlLen, tile->cbRawData, tile->cbRawLen); /* Cb */ + + if (status < 0) + return -1; + + status = progressive_rfx_upgrade_component(progressive, &shiftCr, quantProgCr, &crNumBits, + pSrcDst[2], pCurrent[2], pSign[2], tile->crSrlData, tile->crSrlLen, tile->crRawData, tile->crRawLen); /* Cr */ + + if (status < 0) + return -1; + + if (!progressive->invert) + prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2, tile->data, 64 * 4, &roi_64x64); + else + prims->yCbCrToBGR_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2, tile->data, 64 * 4, &roi_64x64); + + BufferPool_Return(progressive->bufferPool, pBuffer); + + //WLog_Image(progressive->log, WLOG_TRACE, tile->data, 64, 64, 32); + + return 1; +} + +int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, BYTE* blocks, UINT32 blocksLen, PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + int status; + BYTE* block; + UINT16 xIdx; + UINT16 yIdx; + UINT16 zIdx; + UINT16 index; + UINT32 boffset; + UINT16 blockType; + UINT32 blockLen; + UINT32 count = 0; + UINT32 offset = 0; + RFX_PROGRESSIVE_TILE* tile; + RFX_PROGRESSIVE_TILE** tiles; + PROGRESSIVE_BLOCK_REGION* region; + + region = &(progressive->region); + + tiles = region->tiles; + + while ((blocksLen - offset) >= 6) + { + boffset = 0; + block = &blocks[offset]; + + blockType = *((UINT16*) &block[boffset + 0]); /* blockType (2 bytes) */ + blockLen = *((UINT32*) &block[boffset + 2]); /* blockLen (4 bytes) */ + boffset += 6; + + //WLog_INFO(TAG, "%s", progressive_get_block_type_string(blockType)); + + if ((blocksLen - offset) < blockLen) + return -1003; + + switch (blockType) + { + case PROGRESSIVE_WBT_TILE_SIMPLE: + + if ((blockLen - boffset) < 16) + return -1022; + + xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + + zIdx = (yIdx * surface->gridWidth) + xIdx; + + if (zIdx >= surface->gridSize) + return -1; + + tiles[count] = tile = &(surface->tiles[zIdx]); + + tile->blockType = blockType; + tile->blockLen = blockLen; + + tile->quality = 0xFF; /* simple tiles use no progressive techniques */ + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->flags = block[boffset + 7] & 1; /* flags (1 byte) */ + tile->yLen = *((UINT16*) &block[boffset + 8]); /* yLen (2 bytes) */ + tile->cbLen = *((UINT16*) &block[boffset + 10]); /* cbLen (2 bytes) */ + tile->crLen = *((UINT16*) &block[boffset + 12]); /* crLen (2 bytes) */ + tile->tailLen = *((UINT16*) &block[boffset + 14]); /* tailLen (2 bytes) */ + boffset += 16; + + if ((tile->blockLen - boffset) < tile->yLen) + return -1023; + + tile->yData = &block[boffset]; + boffset += tile->yLen; + + if ((tile->blockLen - boffset) < tile->cbLen) + return -1024; + + tile->cbData = &block[boffset]; + boffset += tile->cbLen; + + if ((tile->blockLen - boffset) < tile->crLen) + return -1025; + + tile->crData = &block[boffset]; + boffset += tile->crLen; + + if ((tile->blockLen - boffset) < tile->tailLen) + return -1026; + + tile->tailData = &block[boffset]; + boffset += tile->tailLen; + + tile->width = 64; + tile->height = 64; + tile->x = tile->xIdx * 64; + tile->y = tile->yIdx * 64; + + tile->flags &= 1; + + break; + + case PROGRESSIVE_WBT_TILE_FIRST: + + if ((blockLen - boffset) < 17) + return -1027; + + xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + + zIdx = (yIdx * surface->gridWidth) + xIdx; + + if (zIdx >= surface->gridSize) + return -1; + + tiles[count] = tile = &(surface->tiles[zIdx]); + + tile->blockType = blockType; + tile->blockLen = blockLen; + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->flags = block[boffset + 7] & 1; /* flags (1 byte) */ + tile->quality = block[boffset + 8]; /* quality (1 byte) */ + tile->yLen = *((UINT16*) &block[boffset + 9]); /* yLen (2 bytes) */ + tile->cbLen = *((UINT16*) &block[boffset + 11]); /* cbLen (2 bytes) */ + tile->crLen = *((UINT16*) &block[boffset + 13]); /* crLen (2 bytes) */ + tile->tailLen = *((UINT16*) &block[boffset + 15]); /* tailLen (2 bytes) */ + boffset += 17; + + if ((tile->blockLen - boffset) < tile->yLen) + return -1028; + + tile->yData = &block[boffset]; + boffset += tile->yLen; + + if ((tile->blockLen - boffset) < tile->cbLen) + return -1029; + + tile->cbData = &block[boffset]; + boffset += tile->cbLen; + + if ((tile->blockLen - boffset) < tile->crLen) + return -1030; + + tile->crData = &block[boffset]; + boffset += tile->crLen; + + if ((tile->blockLen - boffset) < tile->tailLen) + return -1031; + + tile->tailData = &block[boffset]; + boffset += tile->tailLen; + + tile->width = 64; + tile->height = 64; + tile->x = tile->xIdx * 64; + tile->y = tile->yIdx * 64; + + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + + if ((blockLen - boffset) < 20) + return -1032; + + xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + + zIdx = (yIdx * surface->gridWidth) + xIdx; + + if (zIdx >= surface->gridSize) + return -1; + + tiles[count] = tile = &(surface->tiles[zIdx]); + + tile->blockType = blockType; + tile->blockLen = blockLen; + + tile->flags = 0; + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->quality = block[boffset + 7]; /* quality (1 byte) */ + tile->ySrlLen = *((UINT16*) &block[boffset + 8]); /* ySrlLen (2 bytes) */ + tile->yRawLen = *((UINT16*) &block[boffset + 10]); /* yRawLen (2 bytes) */ + tile->cbSrlLen = *((UINT16*) &block[boffset + 12]); /* cbSrlLen (2 bytes) */ + tile->cbRawLen = *((UINT16*) &block[boffset + 14]); /* cbRawLen (2 bytes) */ + tile->crSrlLen = *((UINT16*) &block[boffset + 16]); /* crSrlLen (2 bytes) */ + tile->crRawLen = *((UINT16*) &block[boffset + 18]); /* crRawLen (2 bytes) */ + boffset += 20; + + if ((tile->blockLen - boffset) < tile->ySrlLen) + return -1033; + + tile->ySrlData = &block[boffset]; + boffset += tile->ySrlLen; + + if ((tile->blockLen - boffset) < tile->yRawLen) + return -1034; + + tile->yRawData = &block[boffset]; + boffset += tile->yRawLen; + + if ((tile->blockLen - boffset) < tile->cbSrlLen) + return -1035; + + tile->cbSrlData = &block[boffset]; + boffset += tile->cbSrlLen; + + if ((tile->blockLen - boffset) < tile->cbRawLen) + return -1036; + + tile->cbRawData = &block[boffset]; + boffset += tile->cbRawLen; + + if ((tile->blockLen - boffset) < tile->crSrlLen) + return -1037; + + tile->crSrlData = &block[boffset]; + boffset += tile->crSrlLen; + + if ((tile->blockLen - boffset) < tile->crRawLen) + return -1038; + + tile->crRawData = &block[boffset]; + boffset += tile->crRawLen; + + tile->width = 64; + tile->height = 64; + tile->x = tile->xIdx * 64; + tile->y = tile->yIdx * 64; + + break; + + default: + return -1039; + break; + } + + if (boffset != blockLen) + return -1040; + + offset += blockLen; + count++; + } + + if (offset != blocksLen) + return -1041; + + for (index = 0; index < region->numTiles; index++) + { + tile = tiles[index]; + + switch (tile->blockType) + { + case PROGRESSIVE_WBT_TILE_SIMPLE: + case PROGRESSIVE_WBT_TILE_FIRST: + status = progressive_decompress_tile_first(progressive, tile); + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + status = progressive_decompress_tile_upgrade(progressive, tile); + break; + } + + if (status < 0) + return -1; + } + + return (int) offset; +} + +int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, UINT16 surfaceId) +{ + int status; + BYTE* block; + BYTE* blocks; + UINT16 index; + UINT32 boffset; + UINT16 blockType; + UINT32 blockLen; + UINT32 blocksLen; + UINT32 count = 0; + UINT32 offset = 0; + RFX_RECT* rect = NULL; + PROGRESSIVE_BLOCK_SYNC sync; + PROGRESSIVE_BLOCK_REGION* region; + PROGRESSIVE_BLOCK_CONTEXT context; + PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin; + PROGRESSIVE_BLOCK_FRAME_END frameEnd; + PROGRESSIVE_SURFACE_CONTEXT* surface; + RFX_COMPONENT_CODEC_QUANT* quantVal; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; + + progressive->invert = FREERDP_PIXEL_FORMAT_IS_ABGR(DstFormat) ? TRUE : FALSE; + + surface = (PROGRESSIVE_SURFACE_CONTEXT*) progressive_get_surface_data(progressive, surfaceId); + + if (!surface) + return -1001; + + blocks = pSrcData; + blocksLen = SrcSize; + + region = &(progressive->region); + + while ((blocksLen - offset) >= 6) + { + boffset = 0; + block = &blocks[offset]; + + blockType = *((UINT16*) &block[boffset + 0]); /* blockType (2 bytes) */ + blockLen = *((UINT32*) &block[boffset + 2]); /* blockLen (4 bytes) */ + boffset += 6; + //WLog_INFO(TAG, "%s", progressive_get_block_type_string(blockType)); + + if ((blocksLen - offset) < blockLen) + return -1003; + + switch (blockType) + { + case PROGRESSIVE_WBT_SYNC: + + sync.blockType = blockType; + sync.blockLen = blockLen; + + if ((blockLen - boffset) != 6) + return -1004; + + sync.magic = (UINT32) *((UINT32*) &block[boffset + 0]); /* magic (4 bytes) */ + sync.version = (UINT32) *((UINT16*) &block[boffset + 4]); /* version (2 bytes) */ + boffset += 6; + + if (sync.magic != 0xCACCACCA) + return -1005; + + if (sync.version != 0x0100) + return -1006; + + break; + + case PROGRESSIVE_WBT_FRAME_BEGIN: + + frameBegin.blockType = blockType; + frameBegin.blockLen = blockLen; + + if ((blockLen - boffset) < 6) + return -1007; + + frameBegin.frameIndex = (UINT32) *((UINT32*) &block[boffset + 0]); /* frameIndex (4 bytes) */ + frameBegin.regionCount = (UINT32) *((UINT16*) &block[boffset + 4]); /* regionCount (2 bytes) */ + boffset += 6; + + /** + * If the number of elements specified by the regionCount field is + * larger than the actual number of elements in the regions field, + * the decoder SHOULD ignore this inconsistency. + */ + + break; + + case PROGRESSIVE_WBT_FRAME_END: + + frameEnd.blockType = blockType; + frameEnd.blockLen = blockLen; + + if ((blockLen - boffset) != 0) + return -1008; + + break; + + case PROGRESSIVE_WBT_CONTEXT: + + context.blockType = blockType; + context.blockLen = blockLen; + + if ((blockLen - boffset) != 4) + return -1009; + + context.ctxId = block[boffset + 0]; /* ctxId (1 byte) */ + context.tileSize = *((UINT16*) &block[boffset + 1]); /* tileSize (2 bytes) */ + context.flags = block[boffset + 3]; /* flags (1 byte) */ + boffset += 4; + + if (context.tileSize != 64) + return -1010; + + break; + + case PROGRESSIVE_WBT_REGION: + + region->blockType = blockType; + region->blockLen = blockLen; + + if ((blockLen - boffset) < 12) + return -1011; + + region->tileSize = block[boffset + 0]; /* tileSize (1 byte) */ + region->numRects = *((UINT16*) &block[boffset + 1]); /* numRects (2 bytes) */ + region->numQuant = block[boffset + 3]; /* numQuant (1 byte) */ + region->numProgQuant = block[boffset + 4]; /* numProgQuant (1 byte) */ + region->flags = block[boffset + 5]; /* flags (1 byte) */ + region->numTiles = *((UINT16*) &block[boffset + 6]); /* numTiles (2 bytes) */ + region->tileDataSize = *((UINT32*) &block[boffset + 8]); /* tileDataSize (4 bytes) */ + boffset += 12; + + if (region->tileSize != 64) + return -1012; + + if (region->numRects < 1) + return -1013; + + if (region->numQuant > 7) + return -1014; + + if ((blockLen - boffset) < (region->numRects * 8)) + return -1015; + + if (region->numRects > progressive->cRects) + { + progressive->rects = (RFX_RECT*) realloc(progressive->rects, region->numRects * sizeof(RFX_RECT)); + progressive->cRects = region->numRects; + } + + region->rects = progressive->rects; + + if (!region->rects) + return -1016; + + for (index = 0; index < region->numRects; index++) + { + rect = &(region->rects[index]); + rect->x = *((UINT16*) &block[boffset + 0]); + rect->y = *((UINT16*) &block[boffset + 2]); + rect->width = *((UINT16*) &block[boffset + 4]); + rect->height = *((UINT16*) &block[boffset + 6]); + boffset += 8; + } + + if ((blockLen - boffset) < (region->numQuant * 5)) + return -1017; + + if (region->numQuant > progressive->cQuant) + { + progressive->quantVals = (RFX_COMPONENT_CODEC_QUANT*) realloc(progressive->quantVals, + region->numQuant * sizeof(RFX_COMPONENT_CODEC_QUANT)); + progressive->cQuant = region->numQuant; + } + + region->quantVals = progressive->quantVals; + + if (!region->quantVals) + return -1018; + + for (index = 0; index < region->numQuant; index++) + { + quantVal = &(region->quantVals[index]); + progressive_component_codec_quant_read(&block[boffset], quantVal); + boffset += 5; + + if (!progressive_rfx_quant_lcmp_greater_equal(quantVal, 6)) + return -1; + + if (!progressive_rfx_quant_lcmp_less_equal(quantVal, 15)) + return -1; + } + + if ((blockLen - boffset) < (region->numProgQuant * 16)) + return -1019; + + if (region->numProgQuant > progressive->cProgQuant) + { + progressive->quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*) realloc(progressive->quantProgVals, + region->numProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + progressive->cProgQuant = region->numProgQuant; + } + + region->quantProgVals = progressive->quantProgVals; + + if (!region->quantProgVals) + return -1020; + + for (index = 0; index < region->numProgQuant; index++) + { + quantProgVal = &(region->quantProgVals[index]); + quantProgVal->quality = block[boffset + 0]; + + progressive_component_codec_quant_read(&block[boffset + 1], &(quantProgVal->yQuantValues)); + progressive_component_codec_quant_read(&block[boffset + 6], &(quantProgVal->cbQuantValues)); + progressive_component_codec_quant_read(&block[boffset + 11], &(quantProgVal->crQuantValues)); + boffset += 16; + } + + if ((blockLen - boffset) < region->tileDataSize) + return -1021; + + if (region->numTiles > progressive->cTiles) + { + progressive->tiles = (RFX_PROGRESSIVE_TILE**) realloc(progressive->tiles, + region->numTiles * sizeof(RFX_PROGRESSIVE_TILE*)); + progressive->cTiles = region->numTiles; + } + + region->tiles = progressive->tiles; + + if (!region->tiles) + return -1; + + //WLog_INFO(TAG, "numRects: %d numTiles: %d numQuant: %d numProgQuant: %d", + // region->numRects, region->numTiles, region->numQuant, region->numProgQuant); + + status = progressive_process_tiles(progressive, &block[boffset], region->tileDataSize, surface); + + if (status < 0) + return status; + + boffset += (UINT32) status; + + break; + + default: + return -1039; + break; + } + + if (boffset != blockLen) + return -1040; + + offset += blockLen; + count++; + } + + if (offset != blocksLen) + return -1041; + + return 1; +} + +int progressive_compress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) +{ + return 1; +} + +int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive) +{ + return 1; +} + +PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) +{ + PROGRESSIVE_CONTEXT* progressive; + + progressive = (PROGRESSIVE_CONTEXT*) calloc(1, sizeof(PROGRESSIVE_CONTEXT)); + + if (progressive) + { + progressive->Compressor = Compressor; + + progressive->log = WLog_Get(TAG); + + progressive->bufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16); + + progressive->cRects = 64; + progressive->rects = (RFX_RECT*) malloc(progressive->cRects * sizeof(RFX_RECT)); + + if (!progressive->rects) + return NULL; + + progressive->cTiles = 64; + progressive->tiles = (RFX_PROGRESSIVE_TILE**) malloc(progressive->cTiles * sizeof(RFX_PROGRESSIVE_TILE*)); + + if (!progressive->tiles) + return NULL; + + progressive->cQuant = 8; + progressive->quantVals = (RFX_COMPONENT_CODEC_QUANT*) malloc(progressive->cQuant * sizeof(RFX_COMPONENT_CODEC_QUANT)); + + if (!progressive->quantVals) + return NULL; + + progressive->cProgQuant = 8; + progressive->quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*) malloc(progressive->cProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + + if (!progressive->quantProgVals) + return NULL; + + ZeroMemory(&(progressive->quantProgValFull), sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + progressive->quantProgValFull.quality = 100; + + progressive->SurfaceContexts = HashTable_New(TRUE); + + progressive_context_reset(progressive); + } + + return progressive; +} + +void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) +{ + int count; + int index; + ULONG_PTR* pKeys = NULL; + PROGRESSIVE_SURFACE_CONTEXT* surface; + + if (!progressive) + return; + + BufferPool_Free(progressive->bufferPool); + + free(progressive->rects); + free(progressive->tiles); + free(progressive->quantVals); + free(progressive->quantProgVals); + + count = HashTable_GetKeys(progressive->SurfaceContexts, &pKeys); + + for (index = 0; index < count; index++) + { + surface = (PROGRESSIVE_SURFACE_CONTEXT*) HashTable_GetItemValue(progressive->SurfaceContexts, (void*) pKeys[index]); + progressive_surface_context_free(surface); + } + + free(pKeys); + + HashTable_Free(progressive->SurfaceContexts); + + free(progressive); +} + diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index b8a24e136..79f00147a 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -19,8 +19,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("codec") + /* * The functions in this file implement the Region abstraction largely inspired from * pixman library. The following comment is taken from the pixman code. @@ -127,6 +130,11 @@ static RECTANGLE_16 *region16_extents_noconst(REGION16 *region) return ®ion->extents; } +BOOL rectangle_is_empty(const RECTANGLE_16 *rect) +{ + return (rect->left + rect->top + rect->right + rect->bottom) ? TRUE : FALSE; +} + BOOL region16_is_empty(const REGION16 *region) { assert(region); @@ -135,6 +143,12 @@ BOOL region16_is_empty(const REGION16 *region) return (region->data->nbRects == 0); } +BOOL rectangles_equal(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2) +{ + return ((r1->left == r2->left) && (r1->top == r2->top) && + (r1->right == r2->right) && (r1->bottom == r2->bottom)) ? TRUE : FALSE; +} + BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2) { RECTANGLE_16 tmp; @@ -219,20 +233,18 @@ void region16_print(const REGION16 *region) int currentBandY = -1; rects = region16_rects(region, &nbRects); - fprintf(stderr, "nrects=%d", nbRects); + WLog_DBG(TAG, "nrects=%d", nbRects); for (i = 0; i < nbRects; i++, rects++) { if (rects->top != currentBandY) { currentBandY = rects->top; - fprintf(stderr, "\nband %d: ", currentBandY); + WLog_DBG(TAG, "\nband %d: ", currentBandY); } - fprintf(stderr, "(%d,%d-%d,%d)", rects->left, rects->top, rects->right, rects->bottom); + WLog_DBG(TAG, "(%d,%d-%d,%d)", rects->left, rects->top, rects->right, rects->bottom); } - - fprintf(stderr, "\n"); } void region16_copy_band_with_union(RECTANGLE_16 *dst, diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 737770c42..38387302a 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,7 @@ #include "rfx_sse2.h" #include "rfx_neon.h" +#define TAG FREERDP_TAG("codec") #ifndef RFX_INIT_SIMD #define RFX_INIT_SIMD(_rfx_context) do { } while (0) @@ -330,8 +332,6 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder) context->quantization_encode = rfx_quantization_encode; context->dwt_2d_decode = rfx_dwt_2d_decode; context->dwt_2d_encode = rfx_dwt_2d_encode; - context->rlgr_decode = rfx_rlgr_decode; - context->rlgr_encode = rfx_rlgr_encode; RFX_INIT_SIMD(context); @@ -378,7 +378,7 @@ void rfx_context_free(RFX_CONTEXT* context) free(priv->tileWorkParams); #ifdef WITH_PROFILER - fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n"); + WLog_VRB(TAG, "WARNING: Profiling results probably unusable with multithreaded RemoteFX codec!"); #endif } @@ -418,10 +418,11 @@ void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_f } } -void rfx_context_reset(RFX_CONTEXT* context) +int rfx_context_reset(RFX_CONTEXT* context) { context->state = RFX_STATE_SEND_HEADERS; context->frameIdx = 0; + return 1; } static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) @@ -431,14 +432,14 @@ static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) /* RFX_SYNC */ if (Stream_GetRemainingLength(s) < 6) { - DEBUG_WARN("RfxSync packet too small"); + WLog_ERR(TAG, "RfxSync packet too small"); return FALSE; } Stream_Read_UINT32(s, magic); /* magic (4 bytes), 0xCACCACCA */ if (magic != WF_MAGIC) { - DEBUG_WARN("invalid magic number 0x%X", magic); + WLog_ERR(TAG, "invalid magic number 0x%X", magic); return FALSE; } @@ -446,7 +447,7 @@ static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) if (context->version != WF_VERSION_1_0) { - DEBUG_WARN("unknown version number 0x%X", context->version); + WLog_ERR(TAG, "unknown version number 0x%X", context->version); return FALSE; } @@ -461,20 +462,20 @@ static BOOL rfx_process_message_codec_versions(RFX_CONTEXT* context, wStream* s) if (Stream_GetRemainingLength(s) < 1) { - DEBUG_WARN("RfxCodecVersion packet too small"); + WLog_ERR(TAG, "RfxCodecVersion packet too small"); return FALSE; } Stream_Read_UINT8(s, numCodecs); /* numCodecs (1 byte), must be set to 0x01 */ if (numCodecs != 1) { - DEBUG_WARN("numCodecs: %d, expected:1", numCodecs); + WLog_ERR(TAG, "numCodecs: %d, expected:1", numCodecs); return FALSE; } if (Stream_GetRemainingLength(s) < (size_t) (2 * numCodecs)) { - DEBUG_WARN("RfxCodecVersion packet too small for numCodecs=%d", numCodecs); + WLog_ERR(TAG, "RfxCodecVersion packet too small for numCodecs=%d", numCodecs); return FALSE; } @@ -494,7 +495,7 @@ static BOOL rfx_process_message_channels(RFX_CONTEXT* context, wStream* s) if (Stream_GetRemainingLength(s) < 1) { - DEBUG_WARN("RfxMessageChannels packet too small"); + WLog_ERR(TAG, "RfxMessageChannels packet too small"); return FALSE; } @@ -505,13 +506,13 @@ static BOOL rfx_process_message_channels(RFX_CONTEXT* context, wStream* s) */ if (numChannels < 1) { - DEBUG_WARN("numChannels:%d, expected:1", numChannels); + WLog_ERR(TAG, "numChannels:%d, expected:1", numChannels); return TRUE; } if (Stream_GetRemainingLength(s) < (size_t) (numChannels * 5)) { - DEBUG_WARN("RfxMessageChannels packet too small for numChannels=%d", numChannels); + WLog_ERR(TAG, "RfxMessageChannels packet too small for numChannels=%d", numChannels); return FALSE; } @@ -537,7 +538,7 @@ static BOOL rfx_process_message_context(RFX_CONTEXT* context, wStream* s) if (Stream_GetRemainingLength(s) < 5) { - DEBUG_WARN("RfxMessageContext packet too small"); + WLog_ERR(TAG, "RfxMessageContext packet too small"); return FALSE; } @@ -573,7 +574,7 @@ static BOOL rfx_process_message_context(RFX_CONTEXT* context, wStream* s) break; default: - DEBUG_WARN("unknown RLGR algorithm."); + WLog_ERR(TAG, "unknown RLGR algorithm."); break; } @@ -587,7 +588,7 @@ static BOOL rfx_process_message_frame_begin(RFX_CONTEXT* context, RFX_MESSAGE* m if (Stream_GetRemainingLength(s) < 6) { - DEBUG_WARN("RfxMessageFrameBegin packet too small"); + WLog_ERR(TAG, "RfxMessageFrameBegin packet too small"); return FALSE; } @@ -610,7 +611,7 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag if (Stream_GetRemainingLength(s) < 3) { - DEBUG_WARN("RfxMessageRegion packet too small"); + WLog_ERR(TAG, "RfxMessageRegion packet too small"); return FALSE; } @@ -622,8 +623,7 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag /* Unfortunately, it isn't documented. It seems that server asks to clip whole session when numRects = 0. Issue: https://github.com/FreeRDP/FreeRDP/issues/1738 */ - - DEBUG_WARN("no rects. Clip whole session."); + WLog_ERR(TAG, "no rects. Clip whole session."); message->numRects = 1; message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT)); if (!message->rects) @@ -638,7 +638,7 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag if (Stream_GetRemainingLength(s) < (size_t) (8 * message->numRects)) { - DEBUG_WARN("RfxMessageRegion packet too small for num_rects=%d", message->numRects); + WLog_ERR(TAG, "RfxMessageRegion packet too small for num_rects=%d", message->numRects); return FALSE; } @@ -693,7 +693,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (Stream_GetRemainingLength(s) < 14) { - DEBUG_WARN("RfxMessageTileSet packet too small"); + WLog_ERR(TAG, "RfxMessageTileSet packet too small"); return FALSE; } @@ -701,7 +701,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (subtype != CBT_TILESET) { - DEBUG_WARN("invalid subtype, expected CBT_TILESET."); + WLog_ERR(TAG, "invalid subtype, expected CBT_TILESET."); return FALSE; } @@ -713,7 +713,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (context->numQuant < 1) { - DEBUG_WARN("no quantization value."); + WLog_ERR(TAG, "no quantization value."); return TRUE; } @@ -721,7 +721,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (message->numTiles < 1) { - DEBUG_WARN("no tiles."); + WLog_ERR(TAG, "no tiles."); return TRUE; } @@ -734,7 +734,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa /* quantVals */ if (Stream_GetRemainingLength(s) < (size_t) (context->numQuant * 5)) { - DEBUG_WARN("RfxMessageTileSet packet too small for num_quants=%d", context->numQuant); + WLog_ERR(TAG, "RfxMessageTileSet packet too small for num_quants=%d", context->numQuant); return FALSE; } @@ -802,7 +802,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa /* RFX_TILE */ if (Stream_GetRemainingLength(s) < 6) { - DEBUG_WARN("RfxMessageTileSet packet too small to read tile %d/%d", i, message->numTiles); + WLog_ERR(TAG, "RfxMessageTileSet packet too small to read tile %d/%d", i, message->numTiles); rc = FALSE; break; } @@ -812,8 +812,8 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (Stream_GetRemainingLength(s) < blockLen - 6) { - DEBUG_WARN("RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", - i, message->numTiles, blockLen); + WLog_ERR(TAG, "RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", + i, message->numTiles, blockLen); rc = FALSE; break; } @@ -822,7 +822,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (blockType != CBT_TILE) { - DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType); + WLog_ERR(TAG, "unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType); break; } @@ -915,13 +915,13 @@ RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length if (blockLen == 0) { - DEBUG_WARN("zero blockLen"); + WLog_ERR(TAG, "zero blockLen"); break; } if (Stream_GetRemainingLength(s) < blockLen - 6) { - DEBUG_WARN("rfx_process_message: packet too small for blocklen=%d", blockLen); + WLog_ERR(TAG, "rfx_process_message: packet too small for blocklen=%d", blockLen); break; } @@ -935,7 +935,7 @@ RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length /* channelId (1 byte) must be set to 0x00 */ if (!Stream_SafeSeek(s, 2)) { - DEBUG_WARN("rfx_process_message: unable to skip RFX_CODEC_CHANNELT"); + WLog_ERR(TAG, "rfx_process_message: unable to skip RFX_CODEC_CHANNELT"); break; } } @@ -975,7 +975,7 @@ RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length break; default: - DEBUG_WARN("unknown blockType 0x%X", blockType); + WLog_ERR(TAG, "unknown blockType 0x%X", blockType); break; } @@ -1186,19 +1186,20 @@ BOOL setupWorkers(RFX_CONTEXT *context, int nbTiles) if (!context->priv->UseThreads) return TRUE; - priv->workObjects = (PTP_WORK *)realloc(priv->workObjects, sizeof(PTP_WORK) * nbTiles); - if (!priv->workObjects) - return FALSE; + priv->workObjects = (PTP_WORK*) realloc(priv->workObjects, sizeof(PTP_WORK) * nbTiles); - priv->tileWorkParams = (RFX_TILE_COMPOSE_WORK_PARAM *) + if (!priv->workObjects) + return FALSE; + + priv->tileWorkParams = (RFX_TILE_COMPOSE_WORK_PARAM*) realloc(priv->tileWorkParams, sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * nbTiles); + if (!priv->tileWorkParams) return FALSE; return TRUE; } - RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, BYTE* data, int width, int height, int scanline) { @@ -1223,7 +1224,8 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int assert(height > 0); assert(scanline > 0); - message = (RFX_MESSAGE *)calloc(1, sizeof(RFX_MESSAGE)); + message = (RFX_MESSAGE*)calloc(1, sizeof(RFX_MESSAGE)); + if (!message) return NULL; @@ -1231,6 +1233,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int rfx_update_context_properties(context); message->frameIdx = context->frameIdx++; + if (!context->numQuant) { context->numQuant = 1; @@ -1240,12 +1243,14 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int context->quantIdxCb = 0; context->quantIdxCr = 0; } + message->numQuant = context->numQuant; message->quantVals = context->quants; bytesPerPixel = (context->bits_per_pixel / 8); region16_init(&rectsRegion); + if (!computeRegion(rects, numRects, &rectsRegion, width, height)) goto out_free_message; @@ -1258,6 +1263,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int maxNbTiles = maxTilesX * maxTilesY; message->tiles = calloc(maxNbTiles, sizeof(RFX_TILE*)); + if (!message->tiles) goto out_free_message; @@ -1272,8 +1278,10 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int regionRect = region16_rects(&rectsRegion, ®ionNbRects); message->rects = rfxRect = calloc(regionNbRects, sizeof(RFX_RECT)); + if (!message->rects) goto out_clean_tiles; + message->numRects = regionNbRects; region16_init(&tilesRegion); @@ -1295,6 +1303,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY; yIdx++, gridRelY += 64 ) { int tileHeight = 64; + if ((yIdx == endTileY) && (gridRelY + 64 > height)) tileHeight = height - gridRelY; @@ -1304,6 +1313,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX; xIdx++, gridRelX += 64) { int tileWidth = 64; + if ((xIdx == endTileX) && (gridRelX + 64 > width)) tileWidth = width - gridRelX; @@ -1314,7 +1324,8 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int if (region16_intersects_rect(&tilesRegion, ¤tTileRect)) continue; - tile = (RFX_TILE *)ObjectPool_Take(context->priv->TilePool); + tile = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool); + if (!tile) goto out_clean_rects;; @@ -1328,6 +1339,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int ax = gridRelX; ay = gridRelY; + if (tile->data && tile->allocated) { free(tile->data); @@ -1356,7 +1368,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int *workObject = CreateThreadpoolWork( (PTP_WORK_CALLBACK)rfx_compose_message_tile_work_callback, - (void *)workParam, + (void*) workParam, &context->priv->ThreadPoolEnv ); @@ -1381,7 +1393,8 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int if (message->numTiles != maxNbTiles) { - message->tiles = realloc(message->tiles, sizeof(RFX_TILE *) * message->numTiles); + message->tiles = realloc(message->tiles, sizeof(RFX_TILE*) * message->numTiles); + if (!message->tiles) goto out_clean_rects; } @@ -1391,6 +1404,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int /* when using threads ensure all computations are done */ message->tilesDataSize = 0; workObject = context->priv->workObjects; + for (i = 0; i < message->numTiles; i++) { tile = message->tiles[i]; @@ -1414,7 +1428,7 @@ out_clean_tiles: free(message->tiles); region16_uninit(&tilesRegion); out_free_message: - fprintf(stderr, "remoteFx error\n"); + WLog_ERR(TAG, "remoteFx error"); region16_uninit(&rectsRegion); free(message); return 0; @@ -1431,8 +1445,10 @@ RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message, int* *numMessages = ((message->tilesDataSize + maxDataSize) / maxDataSize) * 4; - messages = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE) * (*numMessages)); - ZeroMemory(messages, sizeof(RFX_MESSAGE) * (*numMessages)); + messages = (RFX_MESSAGE*) calloc((*numMessages), sizeof(RFX_MESSAGE)); + + if (!messages) + return NULL; j = 0; @@ -1604,4 +1620,3 @@ void rfx_compose_message(RFX_CONTEXT* context, wStream* s, rfx_message_free(context, message); } - diff --git a/libfreerdp/codec/rfx_decode.c b/libfreerdp/codec/rfx_decode.c index 3d027a393..d14aff8a2 100644 --- a/libfreerdp/codec/rfx_decode.c +++ b/libfreerdp/codec/rfx_decode.c @@ -38,7 +38,7 @@ #include "rfx_decode.h" /* stride is bytes between rows in the output buffer. */ -static void rfx_decode_format_rgb(INT16* r_buf, INT16* g_buf, INT16* b_buf, +void rfx_decode_format_rgb(INT16* r_buf, INT16* g_buf, INT16* b_buf, RDP_PIXEL_FORMAT pixel_format, BYTE* dst_buf, int stride) { primitives_t *prims = primitives_get(); @@ -103,7 +103,7 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_ENTER(context->priv->prof_rfx_decode_component); PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode); - context->rlgr_decode(context->mode, data, size, buffer, 4096); + rfx_rlgr_decode(data, size, buffer, 4096, (context->mode == RLGR1) ? 1 : 3); PROFILER_EXIT(context->priv->prof_rfx_rlgr_decode); PROFILER_ENTER(context->priv->prof_rfx_differential_decode); @@ -146,9 +146,7 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* cr_b_buffer */ rfx_decode_component(context, y_quants, tile->YData, tile->YLen, pSrcDst[0]); /* YData */ - rfx_decode_component(context, cb_quants, tile->CbData, tile->CbLen, pSrcDst[1]); /* CbData */ - rfx_decode_component(context, cr_quants, tile->CrData, tile->CrLen, pSrcDst[2]); /* CrData */ PROFILER_ENTER(context->priv->prof_rfx_ycbcr_to_rgb); diff --git a/libfreerdp/codec/rfx_differential.c b/libfreerdp/codec/rfx_differential.c index e80aa98f3..4429fb8c0 100644 --- a/libfreerdp/codec/rfx_differential.c +++ b/libfreerdp/codec/rfx_differential.c @@ -27,23 +27,24 @@ #include "rfx_differential.h" -void rfx_differential_decode(INT16* buffer, int buffer_size) +void rfx_differential_decode(INT16* buffer, int size) { - INT16* src; - INT16* dst; + INT16* ptr = buffer; + INT16* end = &buffer[size - 1]; - for (src = buffer, dst = buffer + 1; buffer_size > 1; src++, dst++, buffer_size--) + while (ptr != end) { - *dst += *src; + ptr[1] += ptr[0]; + ptr++; } } -void rfx_differential_encode(INT16* buffer, int buffer_size) +void rfx_differential_encode(INT16* buffer, int size) { INT16 n1, n2; INT16* dst; - for (n1 = *buffer, dst = buffer + 1; buffer_size > 1; dst++, buffer_size--) + for (n1 = *buffer, dst = buffer + 1; size > 1; dst++, size--) { n2 = *dst; *dst -= n1; diff --git a/libfreerdp/codec/rfx_differential.h b/libfreerdp/codec/rfx_differential.h index 3f6dbf623..47e1a4241 100644 --- a/libfreerdp/codec/rfx_differential.h +++ b/libfreerdp/codec/rfx_differential.h @@ -22,7 +22,7 @@ #include -void rfx_differential_decode(INT16* buffer, int buffer_size); -void rfx_differential_encode(INT16* buffer, int buffer_size); +void rfx_differential_decode(INT16* buffer, int size); +void rfx_differential_encode(INT16* buffer, int size); #endif /* __RFX_DIFFERENTIAL_H */ diff --git a/libfreerdp/codec/rfx_dwt.c b/libfreerdp/codec/rfx_dwt.c index 0b8448b9e..7e3b3ccc4 100644 --- a/libfreerdp/codec/rfx_dwt.c +++ b/libfreerdp/codec/rfx_dwt.c @@ -110,9 +110,9 @@ static void rfx_dwt_2d_decode_block(INT16* buffer, INT16* idwt, int subband_widt void rfx_dwt_2d_decode(INT16* buffer, INT16* dwt_buffer) { - rfx_dwt_2d_decode_block(buffer + 3840, dwt_buffer, 8); - rfx_dwt_2d_decode_block(buffer + 3072, dwt_buffer, 16); - rfx_dwt_2d_decode_block(buffer, dwt_buffer, 32); + rfx_dwt_2d_decode_block(&buffer[3840], dwt_buffer, 8); + rfx_dwt_2d_decode_block(&buffer[3072], dwt_buffer, 16); + rfx_dwt_2d_decode_block(&buffer[0], dwt_buffer, 32); } static void rfx_dwt_2d_encode_block(INT16* buffer, INT16* dwt, int subband_width) @@ -192,7 +192,7 @@ static void rfx_dwt_2d_encode_block(INT16* buffer, INT16* dwt, int subband_width void rfx_dwt_2d_encode(INT16* buffer, INT16* dwt_buffer) { - rfx_dwt_2d_encode_block(buffer, dwt_buffer, 32); - rfx_dwt_2d_encode_block(buffer + 3072, dwt_buffer, 16); - rfx_dwt_2d_encode_block(buffer + 3840, dwt_buffer, 8); + rfx_dwt_2d_encode_block(&buffer[0], dwt_buffer, 32); + rfx_dwt_2d_encode_block(&buffer[3072], dwt_buffer, 16); + rfx_dwt_2d_encode_block(&buffer[3840], dwt_buffer, 8); } diff --git a/libfreerdp/codec/rfx_encode.c b/libfreerdp/codec/rfx_encode.c index 5dd10e29f..f929846cf 100644 --- a/libfreerdp/codec/rfx_encode.c +++ b/libfreerdp/codec/rfx_encode.c @@ -209,7 +209,7 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_EXIT(context->priv->prof_rfx_differential_encode); PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode); - *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size); + *size = rfx_rlgr_encode(context->mode, data, 4096, buffer, buffer_size); PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode); PROFILER_EXIT(context->priv->prof_rfx_encode_component); diff --git a/libfreerdp/codec/rfx_neon.c b/libfreerdp/codec/rfx_neon.c index 6fe8ec83d..1632f983a 100644 --- a/libfreerdp/codec/rfx_neon.c +++ b/libfreerdp/codec/rfx_neon.c @@ -51,21 +51,18 @@ rfx_quantization_decode_block_NEON(INT16 * buffer, const int buffer_size, const while(buf < buf_end); } -void -rfx_quantization_decode_NEON(INT16 * buffer, const UINT32 * quantization_values) +void rfx_quantization_decode_NEON(INT16 * buffer, const UINT32 * quantVals) { - rfx_quantization_decode_block_NEON(buffer, 4096, 5); - - rfx_quantization_decode_block_NEON(buffer, 1024, quantization_values[8] - 6); /* HL1 */ - rfx_quantization_decode_block_NEON(buffer + 1024, 1024, quantization_values[7] - 6); /* LH1 */ - rfx_quantization_decode_block_NEON(buffer + 2048, 1024, quantization_values[9] - 6); /* HH1 */ - rfx_quantization_decode_block_NEON(buffer + 3072, 256, quantization_values[5] - 6); /* HL2 */ - rfx_quantization_decode_block_NEON(buffer + 3328, 256, quantization_values[4] - 6); /* LH2 */ - rfx_quantization_decode_block_NEON(buffer + 3584, 256, quantization_values[6] - 6); /* HH2 */ - rfx_quantization_decode_block_NEON(buffer + 3840, 64, quantization_values[2] - 6); /* HL3 */ - rfx_quantization_decode_block_NEON(buffer + 3904, 64, quantization_values[1] - 6); /* LH3 */ - rfx_quantization_decode_block_NEON(buffer + 3968, 64, quantization_values[3] - 6); /* HH3 */ - rfx_quantization_decode_block_NEON(buffer + 4032, 64, quantization_values[0] - 6); /* LL3 */ + rfx_quantization_decode_block_NEON(&buffer[0], 1024, quantVals[8] - 1); /* HL1 */ + rfx_quantization_decode_block_NEON(&buffer[1024], 1024, quantVals[7] - 1); /* LH1 */ + rfx_quantization_decode_block_NEON(&buffer[2048], 1024, quantVals[9] - 1); /* HH1 */ + rfx_quantization_decode_block_NEON(&buffer[3072], 256, quantVals[5] - 1); /* HL2 */ + rfx_quantization_decode_block_NEON(&buffer[3328], 256, quantVals[4] - 1); /* LH2 */ + rfx_quantization_decode_block_NEON(&buffer[3584], 256, quantVals[6] - 1); /* HH2 */ + rfx_quantization_decode_block_NEON(&buffer[3840], 64, quantVals[2] - 1); /* HL3 */ + rfx_quantization_decode_block_NEON(&buffer[3904], 64, quantVals[1] - 1); /* LH3 */ + rfx_quantization_decode_block_NEON(&buffer[3968], 64, quantVals[3] - 1); /* HH3 */ + rfx_quantization_decode_block_NEON(&buffer[4032], 64, quantVals[0] - 1); /* LL3 */ } diff --git a/libfreerdp/codec/rfx_quantization.c b/libfreerdp/codec/rfx_quantization.c index 2cedfd91d..6c497a65a 100644 --- a/libfreerdp/codec/rfx_quantization.c +++ b/libfreerdp/codec/rfx_quantization.c @@ -22,9 +22,28 @@ #endif #include + #include "rfx_quantization.h" -static void rfx_quantization_decode_block(const primitives_t *prims, INT16* buffer, int buffer_size, UINT32 factor) +/* + * Band Offset Dimensions Size + * + * HL1 0 32x32 1024 + * LH1 1024 32x32 1024 + * HH1 2048 32x32 1024 + * + * HL2 3072 16x16 256 + * LH2 3328 16x16 256 + * HH2 3584 16x16 256 + * + * HL3 3840 8x8 64 + * LH3 3904 8x8 64 + * HH3 3968 8x8 64 + * + * LL3 4032 8x8 64 + */ + +void rfx_quantization_decode_block(const primitives_t *prims, INT16* buffer, int buffer_size, UINT32 factor) { if (factor == 0) return; @@ -32,23 +51,20 @@ static void rfx_quantization_decode_block(const primitives_t *prims, INT16* buff prims->lShiftC_16s(buffer, factor, buffer, buffer_size); } -void rfx_quantization_decode(INT16* buffer, const UINT32* quantization_values) +void rfx_quantization_decode(INT16* buffer, const UINT32* quantVals) { - const primitives_t *prims = primitives_get(); + const primitives_t* prims = primitives_get(); - /* Scale the values so that they are represented as 11.5 fixed-point number */ - rfx_quantization_decode_block(prims, buffer, 4096, 5); - - rfx_quantization_decode_block(prims, buffer, 1024, quantization_values[8] - 6); /* HL1 */ - rfx_quantization_decode_block(prims, buffer + 1024, 1024, quantization_values[7] - 6); /* LH1 */ - rfx_quantization_decode_block(prims, buffer + 2048, 1024, quantization_values[9] - 6); /* HH1 */ - rfx_quantization_decode_block(prims, buffer + 3072, 256, quantization_values[5] - 6); /* HL2 */ - rfx_quantization_decode_block(prims, buffer + 3328, 256, quantization_values[4] - 6); /* LH2 */ - rfx_quantization_decode_block(prims, buffer + 3584, 256, quantization_values[6] - 6); /* HH2 */ - rfx_quantization_decode_block(prims, buffer + 3840, 64, quantization_values[2] - 6); /* HL3 */ - rfx_quantization_decode_block(prims, buffer + 3904, 64, quantization_values[1] - 6); /* LH3 */ - rfx_quantization_decode_block(prims, buffer + 3968, 64, quantization_values[3] - 6); /* HH3 */ - rfx_quantization_decode_block(prims, buffer + 4032, 64, quantization_values[0] - 6); /* LL3 */ + rfx_quantization_decode_block(prims, &buffer[0], 1024, quantVals[8] - 1); /* HL1 */ + rfx_quantization_decode_block(prims, &buffer[1024], 1024, quantVals[7] - 1); /* LH1 */ + rfx_quantization_decode_block(prims, &buffer[2048], 1024, quantVals[9] - 1); /* HH1 */ + rfx_quantization_decode_block(prims, &buffer[3072], 256, quantVals[5] - 1); /* HL2 */ + rfx_quantization_decode_block(prims, &buffer[3328], 256, quantVals[4] - 1); /* LH2 */ + rfx_quantization_decode_block(prims, &buffer[3584], 256, quantVals[6] - 1); /* HH2 */ + rfx_quantization_decode_block(prims, &buffer[3840], 64, quantVals[2] - 1); /* HL3 */ + rfx_quantization_decode_block(prims, &buffer[3904], 64, quantVals[1] - 1); /* LH3 */ + rfx_quantization_decode_block(prims, &buffer[3968], 64, quantVals[3] - 1); /* HH3 */ + rfx_quantization_decode_block(prims, &buffer[4032], 64, quantVals[0] - 1); /* LL3 */ } static void rfx_quantization_encode_block(INT16* buffer, int buffer_size, UINT32 factor) diff --git a/libfreerdp/codec/rfx_quantization.h b/libfreerdp/codec/rfx_quantization.h index b10aa729f..e446a098a 100644 --- a/libfreerdp/codec/rfx_quantization.h +++ b/libfreerdp/codec/rfx_quantization.h @@ -25,4 +25,6 @@ void rfx_quantization_decode(INT16* buffer, const UINT32* quantization_values); void rfx_quantization_encode(INT16* buffer, const UINT32* quantization_values); +void rfx_quantization_decode_block(const primitives_t *prims, INT16* buffer, int buffer_size, UINT32 factor); + #endif /* __RFX_QUANTIZATION_H */ diff --git a/libfreerdp/codec/rfx_rlgr.c b/libfreerdp/codec/rfx_rlgr.c index e6a1c2e1a..b625f45c9 100644 --- a/libfreerdp/codec/rfx_rlgr.c +++ b/libfreerdp/codec/rfx_rlgr.c @@ -31,43 +31,21 @@ #include #include +#include +#include +#include #include "rfx_bitstream.h" #include "rfx_rlgr.h" -/* Constants used within the RLGR1/RLGR3 algorithm */ -#define KPMAX (80) /* max value for kp or krp */ -#define LSGR (3) /* shift count to convert kp to k */ -#define UP_GR (4) /* increase in kp after a zero run in RL mode */ -#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */ -#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */ -#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */ - -/* Gets (returns) the next nBits from the bitstream */ -#define GetBits(nBits, r) rfx_bitstream_get_bits(bs, nBits, r) - -/* From current output pointer, write "value", check and update buffer_size */ -#define WriteValue(value) \ -{ \ - if (buffer_size > 0) \ - *dst++ = (value); \ - buffer_size--; \ -} - -/* From current output pointer, write next nZeroes terms with value 0, check and update buffer_size */ -#define WriteZeroes(nZeroes) \ -{ \ - int nZeroesWritten = (nZeroes); \ - if (nZeroesWritten > buffer_size) \ - nZeroesWritten = buffer_size; \ - if (nZeroesWritten > 0) \ - { \ - memset(dst, 0, nZeroesWritten * sizeof(INT16)); \ - dst += nZeroesWritten; \ - } \ - buffer_size -= (nZeroes); \ -} +/* Constants used in RLGR1/RLGR3 algorithm */ +#define KPMAX (80) /* max value for kp or krp */ +#define LSGR (3) /* shift count to convert kp to k */ +#define UP_GR (4) /* increase in kp after a zero run in RL mode */ +#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */ +#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */ +#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */ /* Returns the least number of bits required to represent a given value */ #define GetMinBits(_val, _nbits) \ @@ -81,9 +59,6 @@ } \ } -/* Converts from (2 * magnitude - sign) to integer */ -#define GetIntFrom2MagSign(twoMs) (((twoMs) & 1) ? -1 * (INT16)(((twoMs) + 1) >> 1) : (INT16)((twoMs) >> 1)) - /* * Update the passed parameter and clamp it to the range [0, KPMAX] * Return the value of parameter right-shifted by LSGR @@ -98,147 +73,444 @@ _k = (_param >> LSGR); \ } -/* Outputs the Golomb/Rice encoding of a non-negative integer */ -#define GetGRCode(krp, kr, vk, _mag) \ - vk = 0; \ - _mag = 0; \ - /* chew up/count leading 1s and escape 0 */ \ - do { \ - GetBits(1, r); \ - if (r == 1) \ - vk++; \ - else \ - break; \ - } while (1); \ - /* get next *kr bits, and combine with leading 1s */ \ - GetBits(*kr, _mag); \ - _mag |= (vk << *kr); \ - /* adjust krp and kr based on vk */ \ - if (!vk) { \ - UpdateParam(*krp, -2, *kr); \ - } \ - else if (vk != 1) { \ - UpdateParam(*krp, vk, *kr); /* at 1, no change! */ \ +static BOOL g_LZCNT = FALSE; + +static INLINE UINT32 lzcnt_s(UINT32 x) +{ + if (!x) + return 32; + + if (!g_LZCNT) + { + UINT32 y; + int n = 32; + y = x >> 16; if (y != 0) { n = n - 16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + return n - x; } -int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size) + return __lzcnt(x); +} + +int rfx_rlgr_decode(const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize, int mode) { - int k; - int kp; - int kr; - int krp; - UINT16 r; - INT16* dst; - RFX_BITSTREAM* bs; - int vk; - UINT16 mag16; + int run; + int cnt; + int size; + int nbits; + int offset; + INT16 mag; + int k, kp; + int kr, krp; + UINT16 code; + UINT32 sign; + UINT32 nIdx; + UINT32 val1; + UINT32 val2; + INT16* pOutput; + wBitStream* bs; + wBitStream s_bs; - bs = (RFX_BITSTREAM*) malloc(sizeof(RFX_BITSTREAM)); - ZeroMemory(bs, sizeof(RFX_BITSTREAM)); + g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT); - rfx_bitstream_attach(bs, data, data_size); - dst = buffer; - - /* initialize the parameters */ k = 1; kp = k << LSGR; + kr = 1; krp = kr << LSGR; - while (!rfx_bitstream_eos(bs) && buffer_size > 0) + if ((mode != 1) && (mode != 3)) + mode = 1; + + if (!pSrcData || !SrcSize) + return -1; + + if (!pDstData || !DstSize) + return -1; + + pOutput = pDstData; + + bs = &s_bs; + + BitStream_Attach(bs, pSrcData, SrcSize); + BitStream_Fetch(bs); + + while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize)) { - int run; if (k) { - int mag; - UINT32 sign; + /* Run-Length (RL) Mode */ - /* RL MODE */ - while (!rfx_bitstream_eos(bs)) + run = 0; + + /* count number of leading 0s */ + + cnt = lzcnt_s(bs->accumulator); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - GetBits(1, r); - if (r) - break; - /* we have an RL escape "0", which translates to a run (1<accumulator); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; } - /* next k bits will contain remaining run or zeros */ - GetBits(k, run); - WriteZeroes(run); + BitStream_Shift(bs, (vk % 32)); - /* get nonzero value, starting with sign bit and then GRCode for magnitude -1 */ - GetBits(1, sign); + if (BitStream_GetRemainingLength(bs) < 1) + break; - /* magnitude - 1 was coded (because it was nonzero) */ - GetGRCode(&krp, &kr, vk, mag16) - mag = (int) (mag16 + 1); + BitStream_Shift(bs, 1); - WriteValue(sign ? -mag : mag); - UpdateParam(kp, -DN_GR, k); /* lower k and kp because of nonzero term */ + while (vk--) + { + run += (1 << k); /* add (1 << k) to run length */ + + /* update k, kp params */ + + kp += UP_GR; + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; + } + + /* next k bits contain run length remainder */ + + if (BitStream_GetRemainingLength(bs) < k) + break; + + bs->mask = ((1 << k) - 1); + run += ((bs->accumulator >> (32 - k)) & bs->mask); + BitStream_Shift(bs, k); + + /* read sign bit */ + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + sign = (bs->accumulator & 0x80000000) ? 1 : 0; + BitStream_Shift(bs, 1); + + /* count number of leading 1s */ + + cnt = lzcnt_s(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) + { + BitStream_Shift32(bs); + + cnt = lzcnt_s(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; + } + + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); + + /* next kr bits contain code remainder */ + + if (BitStream_GetRemainingLength(bs) < kr) + break; + + bs->mask = ((1 << kr) - 1); + code = (UINT16) ((bs->accumulator >> (32 - kr)) & bs->mask); + BitStream_Shift(bs, kr); + + /* add (vk << kr) to code */ + + code |= (vk << kr); + + if (!vk) + { + /* update kr, krp params */ + + krp -= 2; + + if (krp < 0) + krp = 0; + + kr = krp >> LSGR; + } + else if (vk != 1) + { + /* update kr, krp params */ + + krp += vk; + + if (krp > KPMAX) + krp = KPMAX; + + kr = krp >> LSGR; + } + + /* update k, kp params */ + + kp -= DN_GR; + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; + + /* compute magnitude from code */ + + if (sign) + mag = ((INT16) (code + 1)) * -1; + else + mag = (INT16) (code + 1); + + /* write to output stream */ + + offset = (int) (pOutput - pDstData); + size = run; + + if ((offset + size) > DstSize) + size = DstSize - offset; + + if (size) + { + ZeroMemory(pOutput, size * sizeof(INT16)); + pOutput += size; + } + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } } else { - UINT32 mag; - UINT32 nIdx; - UINT32 val1; - UINT32 val2; + /* Golomb-Rice (GR) Mode */ - /* GR (GOLOMB-RICE) MODE */ - GetGRCode(&krp, &kr, vk, mag16) /* values coded are 2 * magnitude - sign */ - mag = (UINT32) mag16; + /* count number of leading 1s */ - if (mode == RLGR1) + cnt = lzcnt_s(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - if (!mag) + BitStream_Shift32(bs); + + cnt = lzcnt_s(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; + } + + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); + + /* next kr bits contain code remainder */ + + if (BitStream_GetRemainingLength(bs) < kr) + break; + + bs->mask = ((1 << kr) - 1); + code = (UINT16) ((bs->accumulator >> (32 - kr)) & bs->mask); + BitStream_Shift(bs, kr); + + /* add (vk << kr) to code */ + + code |= (vk << kr); + + if (!vk) + { + /* update kr, krp params */ + + krp -= 2; + + if (krp < 0) + krp = 0; + + kr = krp >> LSGR; + } + else if (vk != 1) + { + /* update kr, krp params */ + + krp += vk; + + if (krp > KPMAX) + krp = KPMAX; + + kr = krp >> LSGR; + } + + if (mode == 1) /* RLGR1 */ + { + if (!code) { - WriteValue(0); - UpdateParam(kp, UQ_GR, k); /* raise k and kp due to zero */ + /* update k, kp params */ + + kp += UQ_GR; + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; + + mag = 0; } else { - WriteValue(GetIntFrom2MagSign(mag)); - UpdateParam(kp, -DQ_GR, k); /* lower k and kp due to nonzero */ + /* update k, kp params */ + + kp -= DQ_GR; + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; + + /* + * code = 2 * mag - sign + * sign + code = 2 * mag + */ + + if (code & 1) + mag = ((INT16) ((code + 1) >> 1)) * -1; + else + mag = (INT16) (code >> 1); + } + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; } } - else /* mode == RLGR3 */ + else if (mode == 3) /* RLGR3 */ { - /* - * In GR mode FOR RLGR3, we have encoded the - * sum of two (2 * mag - sign) values - */ + nIdx = 0; - /* maximum possible bits for first term */ - GetMinBits(mag, nIdx); + if (code) + { + mag = (UINT32) code; + nIdx = 32 - lzcnt_s(mag); + } - /* decode val1 is first term's (2 * mag - sign) value */ - GetBits(nIdx, val1); + if (BitStream_GetRemainingLength(bs) < nIdx) + break; - /* val2 is second term's (2 * mag - sign) value */ - val2 = mag - val1; + bs->mask = ((1 << nIdx) - 1); + val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask); + BitStream_Shift(bs, nIdx); + + val2 = code - val1; if (val1 && val2) { - /* raise k and kp if both terms nonzero */ - UpdateParam(kp, -2 * DQ_GR, k); + /* update k, kp params */ + + kp -= (2 * DQ_GR); + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; } else if (!val1 && !val2) { - /* lower k and kp if both terms zero */ - UpdateParam(kp, 2 * UQ_GR, k); + /* update k, kp params */ + + kp += (2 * UQ_GR); + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; } - WriteValue(GetIntFrom2MagSign(val1)); - WriteValue(GetIntFrom2MagSign(val2)); + if (val1 & 1) + mag = ((INT16) ((val1 + 1) >> 1)) * -1; + else + mag = (INT16) (val1 >> 1); + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } + + if (val2 & 1) + mag = ((INT16) ((val2 + 1) >> 1)) * -1; + else + mag = (INT16) (val2 >> 1); + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } } } } - free(bs); + offset = (int) (pOutput - pDstData); - return (dst - buffer); + if (offset < DstSize) + { + size = DstSize - offset; + ZeroMemory(pOutput, size * 2); + pOutput += size; + } + + offset = (int) (pOutput - pDstData); + + if (offset != DstSize) + return -1; + + return 1; } /* Returns the next coefficient (a signed int) to encode, from the input stream */ diff --git a/libfreerdp/codec/rfx_rlgr.h b/libfreerdp/codec/rfx_rlgr.h index 07fa895f6..25b16cf43 100644 --- a/libfreerdp/codec/rfx_rlgr.h +++ b/libfreerdp/codec/rfx_rlgr.h @@ -22,7 +22,6 @@ #include -int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size); int rfx_rlgr_encode(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size); #endif /* __RFX_RLGR_H */ diff --git a/libfreerdp/codec/rfx_sse2.c b/libfreerdp/codec/rfx_sse2.c index 47dbac32f..f89efe81e 100644 --- a/libfreerdp/codec/rfx_sse2.c +++ b/libfreerdp/codec/rfx_sse2.c @@ -82,22 +82,20 @@ rfx_quantization_decode_block_sse2(INT16* buffer, const int buffer_size, const U } while(ptr < buf_end); } -static void rfx_quantization_decode_sse2(INT16* buffer, const UINT32* quantization_values) +static void rfx_quantization_decode_sse2(INT16* buffer, const UINT32* quantVals) { _mm_prefetch_buffer((char*) buffer, 4096 * sizeof(INT16)); - rfx_quantization_decode_block_sse2(buffer, 4096, 5); - - rfx_quantization_decode_block_sse2(buffer, 1024, quantization_values[8] - 6); /* HL1 */ - rfx_quantization_decode_block_sse2(buffer + 1024, 1024, quantization_values[7] - 6); /* LH1 */ - rfx_quantization_decode_block_sse2(buffer + 2048, 1024, quantization_values[9] - 6); /* HH1 */ - rfx_quantization_decode_block_sse2(buffer + 3072, 256, quantization_values[5] - 6); /* HL2 */ - rfx_quantization_decode_block_sse2(buffer + 3328, 256, quantization_values[4] - 6); /* LH2 */ - rfx_quantization_decode_block_sse2(buffer + 3584, 256, quantization_values[6] - 6); /* HH2 */ - rfx_quantization_decode_block_sse2(buffer + 3840, 64, quantization_values[2] - 6); /* HL3 */ - rfx_quantization_decode_block_sse2(buffer + 3904, 64, quantization_values[1] - 6); /* LH3 */ - rfx_quantization_decode_block_sse2(buffer + 3968, 64, quantization_values[3] - 6); /* HH3 */ - rfx_quantization_decode_block_sse2(buffer + 4032, 64, quantization_values[0] - 6); /* LL3 */ + rfx_quantization_decode_block_sse2(&buffer[0], 1024, quantVals[8] - 1); /* HL1 */ + rfx_quantization_decode_block_sse2(&buffer[1024], 1024, quantVals[7] - 1); /* LH1 */ + rfx_quantization_decode_block_sse2(&buffer[2048], 1024, quantVals[9] - 1); /* HH1 */ + rfx_quantization_decode_block_sse2(&buffer[3072], 256, quantVals[5] - 1); /* HL2 */ + rfx_quantization_decode_block_sse2(&buffer[3328], 256, quantVals[4] - 1); /* LH2 */ + rfx_quantization_decode_block_sse2(&buffer[3584], 256, quantVals[6] - 1); /* HH2 */ + rfx_quantization_decode_block_sse2(&buffer[3840], 64, quantVals[2] - 1); /* HL3 */ + rfx_quantization_decode_block_sse2(&buffer[3904], 64, quantVals[1] - 1); /* LH3 */ + rfx_quantization_decode_block_sse2(&buffer[3968], 64, quantVals[3] - 1); /* HH3 */ + rfx_quantization_decode_block_sse2(&buffer[4032], 64, quantVals[0] - 1); /* LL3 */ } static __inline void __attribute__((ATTRIBUTES)) @@ -342,9 +340,9 @@ static void rfx_dwt_2d_decode_sse2(INT16* buffer, INT16* dwt_buffer) { _mm_prefetch_buffer((char*) buffer, 4096 * sizeof(INT16)); - rfx_dwt_2d_decode_block_sse2(buffer + 3840, dwt_buffer, 8); - rfx_dwt_2d_decode_block_sse2(buffer + 3072, dwt_buffer, 16); - rfx_dwt_2d_decode_block_sse2(buffer, dwt_buffer, 32); + rfx_dwt_2d_decode_block_sse2(&buffer[3840], dwt_buffer, 8); + rfx_dwt_2d_decode_block_sse2(&buffer[3072], dwt_buffer, 16); + rfx_dwt_2d_decode_block_sse2(&buffer[0], dwt_buffer, 32); } static __inline void __attribute__((ATTRIBUTES)) diff --git a/libfreerdp/codec/rfx_types.h b/libfreerdp/codec/rfx_types.h index 250c14964..3b93d83a5 100644 --- a/libfreerdp/codec/rfx_types.h +++ b/libfreerdp/codec/rfx_types.h @@ -29,13 +29,14 @@ #include #include -#include +#include #include +#define RFX_TAG FREERDP_TAG("codec.rfx") #ifdef WITH_DEBUG_RFX -#define DEBUG_RFX(fmt, ...) DEBUG_CLASS(RFX, fmt, ## __VA_ARGS__) +#define DEBUG_RFX(fmt, ...) WLog_DBG(RFX_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_RFX(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_RFX(fmt, ...) do { } while (0) #endif typedef struct _RFX_TILE_COMPOSE_WORK_PARAM RFX_TILE_COMPOSE_WORK_PARAM; diff --git a/libfreerdp/codec/test/CMakeLists.txt b/libfreerdp/codec/test/CMakeLists.txt index ba158560c..83574d8c2 100644 --- a/libfreerdp/codec/test/CMakeLists.txt +++ b/libfreerdp/codec/test/CMakeLists.txt @@ -12,6 +12,7 @@ set(${MODULE_PREFIX}_TESTS TestFreeRDPCodecZGfx.c TestFreeRDPCodecPlanar.c TestFreeRDPCodecClear.c + TestFreeRDPCodecProgressive.c TestFreeRDPCodecRemoteFX.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS @@ -20,12 +21,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-codec) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/libfreerdp/codec/test/TestFreeRDPCodecClear.c b/libfreerdp/codec/test/TestFreeRDPCodecClear.c index fcec61acf..f6225e437 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecClear.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecClear.c @@ -42,7 +42,6 @@ int test_ClearDecompressExample1() int status; BYTE* pSrcData; UINT32 SrcSize; - UINT32 DstSize; BYTE* pDstData = NULL; CLEAR_CONTEXT* clear; @@ -51,7 +50,7 @@ int test_ClearDecompressExample1() SrcSize = sizeof(TEST_CLEAR_EXAMPLE_1) - 1; pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_1; - status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0); printf("clear_decompress example 1 status: %d\n", status); @@ -65,7 +64,6 @@ int test_ClearDecompressExample2() int status; BYTE* pSrcData; UINT32 SrcSize; - UINT32 DstSize; BYTE* pDstData = NULL; CLEAR_CONTEXT* clear; @@ -74,7 +72,7 @@ int test_ClearDecompressExample2() SrcSize = sizeof(TEST_CLEAR_EXAMPLE_2) - 1; pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_2; - status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0); printf("clear_decompress example 2 status: %d\n", status); @@ -88,7 +86,6 @@ int test_ClearDecompressExample3() int status; BYTE* pSrcData; UINT32 SrcSize; - UINT32 DstSize; BYTE* pDstData = NULL; CLEAR_CONTEXT* clear; @@ -97,7 +94,7 @@ int test_ClearDecompressExample3() SrcSize = sizeof(TEST_CLEAR_EXAMPLE_3) - 1; pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_3; - status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0); printf("clear_decompress example 3 status: %d\n", status); @@ -111,7 +108,6 @@ int test_ClearDecompressExample4() int status; BYTE* pSrcData; UINT32 SrcSize; - UINT32 DstSize; BYTE* pDstData = NULL; CLEAR_CONTEXT* clear; @@ -120,7 +116,7 @@ int test_ClearDecompressExample4() SrcSize = sizeof(TEST_CLEAR_EXAMPLE_4) - 1; pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_4; - status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0); printf("clear_decompress example 4 status: %d\n", status); diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index cfee4479a..fb8abb935 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -4,6 +4,7 @@ #include #include +#include static BYTE TEST_RDP5_COMPRESSED_DATA[] = { @@ -747,18 +748,13 @@ int test_MppcCompressBellsRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE OutputBuffer[65536]; - mppc = mppc_context_new(1, TRUE); - SrcSize = sizeof(TEST_MPPC_BELLS) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS; expectedSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1; - DstSize = sizeof(OutputBuffer); pDstData = OutputBuffer; - status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize); if (DstSize != expectedSize) @@ -770,18 +766,14 @@ int test_MppcCompressBellsRdp5() if (memcmp(pDstData, TEST_MPPC_BELLS_RDP5, DstSize) != 0) { printf("MppcCompressBellsRdp5: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_MPPC_BELLS_RDP5, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_MPPC_BELLS_RDP5, DstSize * 8, 0); return -1; } mppc_context_free(mppc); - return 0; } @@ -796,18 +788,13 @@ int test_MppcCompressBellsRdp4() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE OutputBuffer[65536]; - mppc = mppc_context_new(0, TRUE); - SrcSize = sizeof(TEST_MPPC_BELLS) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS; expectedSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1; - DstSize = sizeof(OutputBuffer); pDstData = OutputBuffer; - status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("flags: 0x%04X size: %d\n", Flags, DstSize); if (DstSize != expectedSize) @@ -819,18 +806,14 @@ int test_MppcCompressBellsRdp4() if (memcmp(pDstData, TEST_MPPC_BELLS_RDP4, DstSize) != 0) { printf("MppcCompressBellsRdp4: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_MPPC_BELLS_RDP4, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_MPPC_BELLS_RDP4, DstSize * 8, 0); return -1; } mppc_context_free(mppc); - return 0; } @@ -844,14 +827,11 @@ int test_MppcDecompressBellsRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE* pDstData = NULL; - mppc = mppc_context_new(1, FALSE); - SrcSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP5; Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; expectedSize = sizeof(TEST_MPPC_BELLS) - 1; - status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags); printf("flags: 0x%04X size: %d\n", Flags, DstSize); @@ -868,7 +848,6 @@ int test_MppcDecompressBellsRdp5() } mppc_context_free(mppc); - return 0; } @@ -882,14 +861,11 @@ int test_MppcDecompressBellsRdp4() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE* pDstData = NULL; - mppc = mppc_context_new(0, FALSE); - SrcSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP4; Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0; expectedSize = sizeof(TEST_MPPC_BELLS) - 1; - status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags); printf("flags: 0x%04X size: %d\n", Flags, DstSize); @@ -906,7 +882,6 @@ int test_MppcDecompressBellsRdp4() } mppc_context_free(mppc); - return 0; } @@ -921,18 +896,13 @@ int test_MppcCompressIslandRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE OutputBuffer[65536]; - mppc = mppc_context_new(1, TRUE); - SrcSize = sizeof(TEST_ISLAND_DATA) - 1; pSrcData = (BYTE*) TEST_ISLAND_DATA; expectedSize = sizeof(TEST_ISLAND_DATA_RDP5) - 1; - DstSize = sizeof(OutputBuffer); pDstData = OutputBuffer; - status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize); if (DstSize != expectedSize) @@ -944,18 +914,14 @@ int test_MppcCompressIslandRdp5() if (memcmp(pDstData, TEST_ISLAND_DATA_RDP5, DstSize) != 0) { printf("MppcCompressIslandRdp5: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_ISLAND_DATA_RDP5, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_ISLAND_DATA_RDP5, DstSize * 8, 0); return -1; } mppc_context_free(mppc); - return 0; } @@ -970,18 +936,13 @@ int test_MppcCompressBufferRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE OutputBuffer[65536]; - mppc = mppc_context_new(1, TRUE); - SrcSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; expectedSize = sizeof(TEST_RDP5_COMPRESSED_DATA); - DstSize = sizeof(OutputBuffer); pDstData = OutputBuffer; - status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("flags: 0x%04X size: %d\n", Flags, DstSize); if (DstSize != expectedSize) @@ -997,7 +958,6 @@ int test_MppcCompressBufferRdp5() } mppc_context_free(mppc); - return 0; } @@ -1011,14 +971,11 @@ int test_MppcDecompressBufferRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE* pDstData = NULL; - mppc = mppc_context_new(1, FALSE); - SrcSize = sizeof(TEST_RDP5_COMPRESSED_DATA); pSrcData = (BYTE*) TEST_RDP5_COMPRESSED_DATA; Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; expectedSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); - status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags); printf("flags: 0x%04X size: %d\n", Flags, DstSize); @@ -1035,7 +992,6 @@ int test_MppcDecompressBufferRdp5() } mppc_context_free(mppc); - return 0; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecNCrush.c b/libfreerdp/codec/test/TestFreeRDPCodecNCrush.c index 671d83ec5..48e529287 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecNCrush.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecNCrush.c @@ -21,49 +21,37 @@ int test_NCrushCompressBells() UINT32 expectedSize; BYTE OutputBuffer[65536]; NCRUSH_CONTEXT* ncrush; - ncrush = ncrush_context_new(TRUE); - SrcSize = sizeof(TEST_BELLS_DATA) - 1; pSrcData = (BYTE*) TEST_BELLS_DATA; expectedSize = sizeof(TEST_BELLS_NCRUSH) - 1; - pDstData = OutputBuffer; DstSize = sizeof(OutputBuffer); ZeroMemory(OutputBuffer, sizeof(OutputBuffer)); - status = ncrush_compress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize); if (DstSize != expectedSize) { printf("NCrushCompressBells: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_BELLS_NCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_BELLS_NCRUSH, expectedSize * 8, 0); return -1; } if (memcmp(pDstData, TEST_BELLS_NCRUSH, DstSize) != 0) { printf("NCrushCompressBells: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_BELLS_NCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_BELLS_NCRUSH, expectedSize * 8, 0); return -1; } ncrush_context_free(ncrush); - return 1; } @@ -77,14 +65,11 @@ int test_NCrushDecompressBells() UINT32 expectedSize; BYTE* pDstData = NULL; NCRUSH_CONTEXT* ncrush; - ncrush = ncrush_context_new(FALSE); - SrcSize = sizeof(TEST_BELLS_NCRUSH) - 1; pSrcData = (BYTE*) TEST_BELLS_NCRUSH; Flags = PACKET_COMPRESSED | 2; expectedSize = sizeof(TEST_BELLS_DATA) - 1; - status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags); printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize); @@ -101,7 +86,6 @@ int test_NCrushDecompressBells() } ncrush_context_free(ncrush); - return 1; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c b/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c index 0ce618fa7..b234af3a2 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c @@ -5,6 +5,7 @@ #include #include #include +#include /** * Experimental Case 01: 64x64 (32bpp) @@ -2864,16 +2865,6 @@ const BYTE TEST_RDP6_SCANLINES_DELTA_2C_ENCODED_UNSIGNED[3][6] = { 0x01, 0x67, 0x8B, 0xA3, 0x78, 0xAF } }; -#include "../planar.h" - -static unsigned long next = 1; - -static int simple_rand(void) -{ - next = next * 1103515245 + 12345; - return ((unsigned int) (next / 65536) % 32768); -} - static void fill_bitmap_alpha_channel(BYTE* data, int width, int height, BYTE value) { int i, j; @@ -2943,7 +2934,7 @@ void dump_color_channel(BYTE* data, int width, int height) for (j = 0; j < width; j++) { printf("%02X%s", *data, - ((j + 1) == width)? "\n" : " "); + ((j + 1) == width)? "\n" : " "); data += 4; } } @@ -2960,28 +2951,21 @@ int test_individual_planes_encoding_rle() int availableSize; DWORD planarFlags; BITMAP_PLANAR_CONTEXT* planar; - planarFlags = PLANAR_FORMAT_HEADER_NA; planarFlags |= PLANAR_FORMAT_HEADER_RLE; - width = 64; height = 64; planeSize = width * height; planar = freerdp_bitmap_planar_context_new(planarFlags, width, height); - - CopyMemory(planar->planes[1], (BYTE*) TEST_64X64_RED_PLANE, planeSize); /* Red */ - CopyMemory(planar->planes[2], (BYTE*) TEST_64X64_GREEN_PLANE, planeSize); /* Green */ - CopyMemory(planar->planes[3], (BYTE*) TEST_64X64_BLUE_PLANE, planeSize); /* Blue */ - + CopyMemory(planar->planes[1], (BYTE*) TEST_64X64_RED_PLANE, planeSize); /* Red */ + CopyMemory(planar->planes[2], (BYTE*) TEST_64X64_GREEN_PLANE, planeSize); /* Green */ + CopyMemory(planar->planes[3], (BYTE*) TEST_64X64_BLUE_PLANE, planeSize); /* Blue */ freerdp_bitmap_planar_delta_encode_plane(planar->planes[1], width, height, planar->deltaPlanes[1]); /* Red */ freerdp_bitmap_planar_delta_encode_plane(planar->planes[2], width, height, planar->deltaPlanes[2]); /* Green */ freerdp_bitmap_planar_delta_encode_plane(planar->planes[3], width, height, planar->deltaPlanes[3]); /* Blue */ - pOutput = planar->rlePlanesBuffer; availableSize = planeSize * 3; - /* Red */ - dstSizes[1] = availableSize; if (!freerdp_bitmap_planar_compress_plane_rle(planar->deltaPlanes[1], width, height, pOutput, &dstSizes[1])) @@ -2997,7 +2981,7 @@ int test_individual_planes_encoding_rle() if (dstSizes[1] != sizeof(TEST_64X64_RED_PLANE_RLE)) { printf("RedPlaneRle unexpected size: actual: %d, expected: %d\n", - dstSizes[1], (int) sizeof(TEST_64X64_RED_PLANE_RLE)); + dstSizes[1], (int) sizeof(TEST_64X64_RED_PLANE_RLE)); //return -1; } @@ -3006,18 +2990,14 @@ int test_individual_planes_encoding_rle() if (memcmp(planar->rlePlanes[1], (BYTE*) TEST_64X64_RED_PLANE_RLE, compareSize) != 0) { printf("RedPlaneRle doesn't match expected output\n"); - printf("RedPlaneRle Expected (%d):\n", (int) sizeof(TEST_64X64_RED_PLANE_RLE)); - //winpr_HexDump((BYTE*) TEST_64X64_RED_PLANE_RLE, sizeof(TEST_64X64_RED_PLANE_RLE)); - + //winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_64X64_RED_PLANE_RLE, sizeof(TEST_64X64_RED_PLANE_RLE)); printf("RedPlaneRle Actual (%d):\n", dstSizes[1]); - //winpr_HexDump(planar->rlePlanes[1], dstSizes[1]); - + //winpr_HexDump("codec.test", WLOG_DEBUG, planar->rlePlanes[1], dstSizes[1]); return -1; } /* Green */ - dstSizes[2] = availableSize; if (!freerdp_bitmap_planar_compress_plane_rle(planar->deltaPlanes[2], width, height, pOutput, &dstSizes[2])) @@ -3033,7 +3013,7 @@ int test_individual_planes_encoding_rle() if (dstSizes[2] != sizeof(TEST_64X64_GREEN_PLANE_RLE)) { printf("GreenPlaneRle unexpected size: actual: %d, expected: %d\n", - dstSizes[1], (int) sizeof(TEST_64X64_GREEN_PLANE_RLE)); + dstSizes[1], (int) sizeof(TEST_64X64_GREEN_PLANE_RLE)); return -1; } @@ -3042,18 +3022,14 @@ int test_individual_planes_encoding_rle() if (memcmp(planar->rlePlanes[2], (BYTE*) TEST_64X64_GREEN_PLANE_RLE, compareSize) != 0) { printf("GreenPlaneRle doesn't match expected output\n"); - printf("GreenPlaneRle Expected (%d):\n", (int) sizeof(TEST_64X64_GREEN_PLANE_RLE)); - winpr_HexDump((BYTE*) TEST_64X64_GREEN_PLANE_RLE, (int) sizeof(TEST_64X64_GREEN_PLANE_RLE)); - + winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_64X64_GREEN_PLANE_RLE, (int) sizeof(TEST_64X64_GREEN_PLANE_RLE)); printf("GreenPlaneRle Actual (%d):\n", dstSizes[2]); - winpr_HexDump(planar->rlePlanes[2], dstSizes[2]); - + winpr_HexDump("codec.test", WLOG_DEBUG, planar->rlePlanes[2], dstSizes[2]); return -1; } /* Blue */ - dstSizes[3] = availableSize; if (!freerdp_bitmap_planar_compress_plane_rle(planar->deltaPlanes[3], width, height, pOutput, &dstSizes[3])) @@ -3069,7 +3045,7 @@ int test_individual_planes_encoding_rle() if (dstSizes[3] != sizeof(TEST_64X64_BLUE_PLANE_RLE)) { printf("BluePlaneRle unexpected size: actual: %d, expected: %d\n", - dstSizes[1], (int) sizeof(TEST_64X64_BLUE_PLANE_RLE)); + dstSizes[1], (int) sizeof(TEST_64X64_BLUE_PLANE_RLE)); return -1; } @@ -3078,26 +3054,23 @@ int test_individual_planes_encoding_rle() if (memcmp(planar->rlePlanes[3], (BYTE*) TEST_64X64_BLUE_PLANE_RLE, compareSize) != 0) { printf("BluePlaneRle doesn't match expected output\n"); - printf("BluePlaneRle Expected (%d):\n", (int) sizeof(TEST_64X64_BLUE_PLANE_RLE)); - winpr_HexDump((BYTE*) TEST_64X64_BLUE_PLANE_RLE, (int) sizeof(TEST_64X64_BLUE_PLANE_RLE)); - + winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_64X64_BLUE_PLANE_RLE, (int) sizeof(TEST_64X64_BLUE_PLANE_RLE)); printf("BluePlaneRle Actual (%d):\n", dstSizes[3]); - winpr_HexDump(planar->rlePlanes[3], dstSizes[3]); - + winpr_HexDump("codec.test", WLOG_DEBUG, planar->rlePlanes[3], dstSizes[3]); return -1; } freerdp_bitmap_planar_context_free(planar); - return 0; } int TestFreeRDPCodecPlanar(int argc, char* argv[]) { - int i, j; + int i; int dstSize; UINT32 format; + BYTE* pDstData; HCLRCONV clrconv; DWORD planarFlags; BYTE* srcBitmap32; @@ -3105,49 +3078,39 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) int width, height; BYTE* blackBitmap; BYTE* whiteBitmap; - BYTE* randomBitmap; BYTE* compressedBitmap; BYTE* decompressedBitmap; BITMAP_PLANAR_CONTEXT* planar; - planarFlags = PLANAR_FORMAT_HEADER_NA; planarFlags |= PLANAR_FORMAT_HEADER_RLE; - planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64); - clrconv = freerdp_clrconv_new(0); srcBitmap16 = (BYTE*) TEST_RLE_UNCOMPRESSED_BITMAP_16BPP; - srcBitmap32 = freerdp_image_convert(srcBitmap16, NULL, 32, 32, 16, 32, clrconv); - format = PIXEL_FORMAT_ARGB32; - #if 0 freerdp_bitmap_compress_planar(planar, srcBitmap32, format, 32, 32, 32 * 4, NULL, &dstSize); - freerdp_bitmap_planar_compress_plane_rle((BYTE*) TEST_RLE_SCANLINE_UNCOMPRESSED, 12, 1, NULL, &dstSize); - freerdp_bitmap_planar_delta_encode_plane((BYTE*) TEST_RDP6_SCANLINES_ABSOLUTE, 6, 3, NULL); - freerdp_bitmap_planar_compress_plane_rle((BYTE*) TEST_RDP6_SCANLINES_DELTA_2C_ENCODED_UNSIGNED, 6, 3, NULL, &dstSize); #endif - #if 1 + for (i = 4; i < 64; i += 4) { width = i; height = i; - whiteBitmap = (BYTE*) malloc(width * height * 4); FillMemory(whiteBitmap, width * height * 4, 0xFF); fill_bitmap_alpha_channel(whiteBitmap, width, height, 0x00); - compressedBitmap = freerdp_bitmap_compress_planar(planar, whiteBitmap, format, width, height, width * 4, NULL, &dstSize); - decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, FALSE) < 0) { printf("failed to decompress white bitmap: width: %d height: %d\n", width, height); return -1; @@ -3160,11 +3123,9 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) if (memcmp(decompressedBitmap, whiteBitmap, width * height * 4) != 0) { printf("white bitmap\n"); - winpr_HexDump(whiteBitmap, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, whiteBitmap, width * height * 4); printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, decompressedBitmap, width * height * 4); printf("error decompressed white bitmap corrupted: width: %d height: %d\n", width, height); return -1; } @@ -3177,17 +3138,17 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) { width = i; height = i; - blackBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(blackBitmap, width * height * 4); fill_bitmap_alpha_channel(blackBitmap, width, height, 0x00); - compressedBitmap = freerdp_bitmap_compress_planar(planar, blackBitmap, format, width, height, width * 4, NULL, &dstSize); - decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, FALSE) < 0) { printf("failed to decompress black bitmap: width: %d height: %d\n", width, height); return -1; @@ -3200,11 +3161,9 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) if (memcmp(decompressedBitmap, blackBitmap, width * height * 4) != 0) { printf("black bitmap\n"); - winpr_HexDump(blackBitmap, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, blackBitmap, width * height * 4); printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, decompressedBitmap, width * height * 4); printf("error decompressed black bitmap corrupted: width: %d height: %d\n", width, height); return -1; } @@ -3213,63 +3172,20 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) free(decompressedBitmap); } - for (i = 4; i < 64; i += 4) - { - width = i; - height = i; - - randomBitmap = (BYTE*) malloc(width * height * 4); - - for (j = 0; j < width * height * 4; j++) - { - randomBitmap[j] = (BYTE) (simple_rand() % 256); - } - - fill_bitmap_alpha_channel(randomBitmap, width, height, 0x00); - - compressedBitmap = freerdp_bitmap_compress_planar(planar, randomBitmap, format, width, height, width * 4, NULL, &dstSize); - - decompressedBitmap = (BYTE*) malloc(width * height * 4); - ZeroMemory(decompressedBitmap, width * height * 4); - - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) - { - printf("failed to decompress random bitmap: width: %d height: %d\n", width, height); - return -1; - } - else - { - printf("success decompressing random bitmap: width: %d height: %d\n", width, height); - } - - if (memcmp(decompressedBitmap, randomBitmap, width * height * 4) != 0) - { - printf("random bitmap\n"); - winpr_HexDump(randomBitmap, width * height * 4); - - printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); - - printf("error decompressed random bitmap corrupted: width: %d height: %d\n", width, height); - return -1; - } - - free(compressedBitmap); - free(decompressedBitmap); - } + return 0; /* Experimental Case 01 */ - width = 64; height = 64; - compressedBitmap = freerdp_bitmap_compress_planar(planar, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_01, - format, width, height, width * 4, NULL, &dstSize); - + format, width, height, width * 4, NULL, &dstSize); decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, FALSE) < 0) { printf("failed to decompress experimental bitmap 01: width: %d height: %d\n", width, height); return -1; @@ -3286,31 +3202,28 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) { #if 0 printf("experimental bitmap 01\n"); - winpr_HexDump((BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_01, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_01, width * height * 4); printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); + winpr_HexDump("codec.test", WLOG_DEBUG, decompressedBitmap, width * height * 4); #endif - printf("error: decompressed experimental bitmap 01 is corrupted\n"); return -1; } free(compressedBitmap); free(decompressedBitmap); - /* Experimental Case 02 */ - width = 64; height = 64; - compressedBitmap = freerdp_bitmap_compress_planar(planar, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_02, - format, width, height, width * 4, NULL, &dstSize); - + format, width, height, width * 4, NULL, &dstSize); decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, FALSE) < 0) { printf("failed to decompress experimental bitmap 02: width: %d height: %d\n", width, height); return -1; @@ -3327,12 +3240,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) { #if 0 printf("experimental bitmap 02\n"); - winpr_HexDump((BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_02, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_02, width * height * 4); printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); + winpr_HexDump("codec.test", WLOG_DEBUG, decompressedBitmap, width * height * 4); #endif - printf("error: decompressed experimental bitmap 02 is corrupted\n"); return -1; } @@ -3347,17 +3258,17 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) } /* Experimental Case 03 */ - width = 64; height = 64; - compressedBitmap = freerdp_bitmap_compress_planar(planar, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_03, - format, width, height, width * 4, NULL, &dstSize); - + format, width, height, width * 4, NULL, &dstSize); decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height, FALSE) < 0) { printf("failed to decompress experimental bitmap 03: width: %d height: %d\n", width, height); return -1; @@ -3374,23 +3285,18 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) { #if 0 printf("experimental bitmap 03\n"); - winpr_HexDump((BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_03, width * height * 4); - + winpr_HexDump("codec.test", WLOG_DEBUG, (BYTE*) TEST_RLE_BITMAP_EXPERIMENTAL_03, width * height * 4); printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); + winpr_HexDump("codec.test", WLOG_DEBUG, decompressedBitmap, width * height * 4); #endif - printf("error: decompressed experimental bitmap 03 is corrupted\n"); return -1; } free(compressedBitmap); free(decompressedBitmap); - freerdp_clrconv_free(clrconv); - free(srcBitmap32); - + _aligned_free(srcBitmap32); freerdp_bitmap_planar_context_free(planar); - return 0; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c b/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c new file mode 100644 index 000000000..fe84a418c --- /dev/null +++ b/libfreerdp/codec/test/TestFreeRDPCodecProgressive.c @@ -0,0 +1,1020 @@ +#include +#include +#include +#include +#include + +#include + +#include + +/** + * Microsoft Progressive Codec Sample Data + * (available under NDA only) + * + * ____. + * + * readme.pdf + * + * bitmaps/ + * 1920by1080-SampleImage1.bmp + * 1920by1080-SampleImage2.bmp + * 1920by1080-SampleImage3.bmp + * + * compress/ + * enc_0_0_025_sampleimage1.bin + * enc_0_0_050_sampleimage1.bin + * enc_0_0_075_sampleimage1.bin + * enc_0_0_100_sampleimage1.bin + * enc_0_1_025_sampleimage1.bin + * enc_0_1_050_sampleimage1.bin + * enc_0_1_075_sampleimage1.bin + * enc_0_1_100_sampleimage1.bin + * enc_0_2_025_sampleimage1.bin + * enc_0_2_050_sampleimage1.bin + * enc_0_2_075_sampleimage1.bin + * enc_0_2_100_sampleimage1.bin + * enc_0_3_025_sampleimage1.bin + * enc_0_3_050_sampleimage1.bin + * enc_0_3_075_sampleimage1.bin + * enc_0_3_100_sampleimage1.bin + * enc_1_0_025_sampleimage2.bin + * enc_1_0_050_sampleimage2.bin + * enc_1_0_075_sampleimage2.bin + * enc_1_0_100_sampleimage2.bin + * enc_1_1_025_sampleimage2.bin + * enc_1_1_050_sampleimage2.bin + * enc_1_1_075_sampleimage2.bin + * enc_1_1_100_sampleimage2.bin + * enc_1_2_025_sampleimage2.bin + * enc_1_2_050_sampleimage2.bin + * enc_1_2_075_sampleimage2.bin + * enc_1_2_100_sampleimage2.bin + * enc_1_3_025_sampleimage2.bin + * enc_1_3_050_sampleimage2.bin + * enc_1_3_075_sampleimage2.bin + * enc_1_3_100_sampleimage2.bin + * enc_2_0_025_sampleimage3.bin + * enc_2_0_050_sampleimage3.bin + * enc_2_0_075_sampleimage3.bin + * enc_2_0_100_sampleimage3.bin + * enc_2_1_025_sampleimage3.bin + * enc_2_1_050_sampleimage3.bin + * enc_2_1_075_sampleimage3.bin + * enc_2_1_100_sampleimage3.bin + * enc_2_2_025_sampleimage3.bin + * enc_2_2_050_sampleimage3.bin + * enc_2_2_075_sampleimage3.bin + * enc_2_2_100_sampleimage3.bin + * enc_2_3_025_sampleimage3.bin + * enc_2_3_050_sampleimage3.bin + * enc_2_3_075_sampleimage3.bin + * enc_2_3_100_sampleimage3.bin + * + * decompress/ + * dec_0_0_025_sampleimage1.bmp + * dec_0_0_050_sampleimage1.bmp + * dec_0_0_075_sampleimage1.bmp + * dec_0_0_100_sampleimage1.bmp + * dec_0_1_025_sampleimage1.bmp + * dec_0_1_050_sampleimage1.bmp + * dec_0_1_075_sampleimage1.bmp + * dec_0_1_100_sampleimage1.bmp + * dec_0_2_025_sampleimage1.bmp + * dec_0_2_050_sampleimage1.bmp + * dec_0_2_075_sampleimage1.bmp + * dec_0_2_100_sampleimage1.bmp + * dec_0_3_025_sampleimage1.bmp + * dec_0_3_050_sampleimage1.bmp + * dec_0_3_075_sampleimage1.bmp + * dec_0_3_100_sampleimage1.bmp + * dec_1_0_025_sampleimage2.bmp + * dec_1_0_050_sampleimage2.bmp + * dec_1_0_075_sampleimage2.bmp + * dec_1_0_100_sampleimage2.bmp + * dec_1_1_025_sampleimage2.bmp + * dec_1_1_050_sampleimage2.bmp + * dec_1_1_075_sampleimage2.bmp + * dec_1_1_100_sampleimage2.bmp + * dec_1_2_025_sampleimage2.bmp + * dec_1_2_050_sampleimage2.bmp + * dec_1_2_075_sampleimage2.bmp + * dec_1_2_100_sampleimage2.bmp + * dec_1_3_025_sampleimage2.bmp + * dec_1_3_050_sampleimage2.bmp + * dec_1_3_075_sampleimage2.bmp + * dec_1_3_100_sampleimage2.bmp + * dec_2_0_025_sampleimage3.bmp + * dec_2_0_050_sampleimage3.bmp + * dec_2_0_075_sampleimage3.bmp + * dec_2_0_100_sampleimage3.bmp + * dec_2_1_025_sampleimage3.bmp + * dec_2_1_050_sampleimage3.bmp + * dec_2_1_075_sampleimage3.bmp + * dec_2_1_100_sampleimage3.bmp + * dec_2_2_025_sampleimage3.bmp + * dec_2_2_050_sampleimage3.bmp + * dec_2_2_075_sampleimage3.bmp + * dec_2_2_100_sampleimage3.bmp + * dec_2_3_025_sampleimage3.bmp + * dec_2_3_050_sampleimage3.bmp + * dec_2_3_075_sampleimage3.bmp + * dec_2_3_100_sampleimage3.bmp + */ + +struct _EGFX_SAMPLE_FILE +{ + BYTE* buffer; + UINT32 size; +}; +typedef struct _EGFX_SAMPLE_FILE EGFX_SAMPLE_FILE; + +static int g_Width = 0; +static int g_Height = 0; +static int g_DstStep = 0; +static BYTE* g_DstData = NULL; + +static void test_fill_image_alpha_channel(BYTE* data, int width, int height, BYTE value) +{ + int i, j; + UINT32* pixel; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = (UINT32*) &data[((i * width) + j) * 4]; + *pixel = ((*pixel & 0x00FFFFFF) | (value << 24)); + } + } +} + +static void* test_image_memset32(UINT32* ptr, UINT32 fill, size_t length) +{ + while (length--) + { + *ptr++ = fill; + } + + return (void*) ptr; +} + +static int test_image_fill(BYTE* pDstData, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight, UINT32 color) +{ + int y; + UINT32* pDstPixel; + + if (nDstStep < 0) + nDstStep = 4 * nWidth; + + for (y = 0; y < nHeight; y++) + { + pDstPixel = (UINT32*) &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + test_image_memset32(pDstPixel, color, nWidth); + } + + return 1; +} + +static int test_image_fill_quarter(BYTE* pDstData, int nDstStep, int nWidth, int nHeight, UINT32 color, int quarter) +{ + int x = 0; + int y = 0; + int width = 0; + int height = 0; + + switch (quarter) + { + case 0: + x = 0; + y = 0; + width = nWidth / 2; + height = nHeight /2; + break; + + case 1: + x = nWidth / 2; + y = nHeight / 2; + width = nWidth / 2; + height = nHeight /2; + break; + + case 2: + x = 0; + y = nHeight / 2; + width = nWidth / 2; + height = nHeight /2; + break; + + case 3: + x = nWidth / 2; + y = 0; + width = nWidth / 2; + height = nHeight /2; + break; + } + + test_image_fill(pDstData, nDstStep, x, y, width, height, 0xFF000000); + + return 1; +} + +static int test_image_fill_unused_quarters(BYTE* pDstData, int nDstStep, int nWidth, int nHeight, UINT32 color, int quarter) +{ + return 1; + + if (quarter == 0) + { + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3); + } + else if (quarter == 1) + { + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3); + } + else if (quarter == 2) + { + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3); + } + else if (quarter == 3) + { + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1); + test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2); + } + + return 1; +} + +BYTE* test_progressive_load_file(char* path, char* file, UINT32* size) +{ + FILE* fp; + BYTE* buffer; + char* filename; + + filename = GetCombinedPath(path, file); + + fp = fopen(filename, "r"); + + if (!fp) + return NULL; + + fseek(fp, 0, SEEK_END); + *size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + buffer = (BYTE*) malloc(*size); + + if (!buffer) + return NULL; + + if (fread(buffer, *size, 1, fp) != 1) + return NULL; + + free(filename); + fclose(fp); + + return buffer; +} + +int test_progressive_load_files(char* ms_sample_path, EGFX_SAMPLE_FILE files[3][4][4]) +{ + int imageNo = 0; + int quarterNo = 0; + int passNo = 0; + + /* image 1 */ + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_0_025_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_0_050_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_0_075_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_0_100_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_1_025_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_1_050_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_1_075_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_1_100_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_2_025_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_2_050_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_2_075_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_2_100_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_3_025_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_3_050_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_3_075_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_0_3_100_sampleimage1.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 2 */ + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_0_025_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_0_050_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_0_075_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_0_100_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_1_025_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_1_050_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_1_075_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_1_100_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_2_025_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_2_050_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_2_075_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_2_100_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_3_025_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_3_050_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_3_075_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_1_3_100_sampleimage2.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 3 */ + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_0_025_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_0_050_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_0_075_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_0_100_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_1_025_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_1_050_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_1_075_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_1_100_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_2_025_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_2_050_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_2_075_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_2_100_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_3_025_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_3_050_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_3_075_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + files[imageNo][quarterNo][passNo].buffer = test_progressive_load_file(ms_sample_path, + "compress/enc_2_3_100_sampleimage3.bin", &(files[imageNo][quarterNo][passNo].size)); + passNo = (passNo + 1) % 4; + + /* check if all test data has been loaded */ + + for (imageNo = 0; imageNo < 3; imageNo++) + { + for (quarterNo = 0; quarterNo < 4; quarterNo++) + { + for (passNo = 0; passNo < 4; passNo++) + { + if (!files[imageNo][quarterNo][passNo].buffer) + return -1; + } + } + } + + return 1; +} + +BYTE* test_progressive_load_bitmap(char* path, char* file, UINT32* size, int quarter) +{ + int status; + BYTE* buffer; + wImage* image; + char* filename; + + filename = GetCombinedPath(path, file); + + if (!filename) + return NULL; + + image = winpr_image_new(); + + if (!image) + return NULL; + + status = winpr_image_read(image, filename); + + if (status < 0) + return NULL; + + buffer = image->data; + *size = image->height * image->scanline; + + test_fill_image_alpha_channel(image->data, image->width, image->height, 0xFF); + test_image_fill_unused_quarters(image->data, image->scanline, image->width, image->height, quarter, 0xFF000000); + + winpr_image_free(image, FALSE); + free(filename); + + return buffer; +} + +int test_progressive_load_bitmaps(char* ms_sample_path, EGFX_SAMPLE_FILE bitmaps[3][4][4]) +{ + int imageNo = 0; + int quarterNo = 0; + int passNo = 0; + + /* image 1 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_0_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_1_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_2_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_025_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_050_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_075_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_0_3_100_sampleimage1.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 2 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_0_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_1_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_2_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_025_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_050_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_075_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_1_3_100_sampleimage2.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + imageNo++; + + /* image 3 */ + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_0_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_1_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_2_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + quarterNo = (quarterNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_025_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_050_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_075_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + bitmaps[imageNo][quarterNo][passNo].buffer = test_progressive_load_bitmap(ms_sample_path, + "decompress/dec_2_3_100_sampleimage3.bmp", &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo); + passNo = (passNo + 1) % 4; + + /* check if all test data has been loaded */ + + for (imageNo = 0; imageNo < 3; imageNo++) + { + for (quarterNo = 0; quarterNo < 4; quarterNo++) + { + for (passNo = 0; passNo < 4; passNo++) + { + if (!bitmaps[imageNo][quarterNo][passNo].buffer) + return -1; + } + } + } + + return 1; +} + +static int test_memcmp_count(const BYTE* mem1, const BYTE* mem2, int size, int margin) +{ + int error; + int count = 0; + int index = 0; + + for (index = 0; index < size; index++) + { + if (*mem1 != *mem2) + { + error = (*mem1 > *mem2) ? *mem1 - *mem2 : *mem2 - *mem1; + + if (error > margin) + count++; + } + + mem1++; + mem2++; + } + + return count; +} + +int test_progressive_decode(PROGRESSIVE_CONTEXT* progressive, EGFX_SAMPLE_FILE files[4], EGFX_SAMPLE_FILE bitmaps[4], int quarter, int count) +{ + int cnt; + int pass; + int size; + int index; + int status; + int nXSrc, nYSrc; + int nXDst, nYDst; + int nWidth, nHeight; + RECTANGLE_16 tileRect; + RECTANGLE_16 updateRect; + RECTANGLE_16 clippingRect; + RFX_PROGRESSIVE_TILE* tile; + PROGRESSIVE_BLOCK_REGION* region; + + clippingRect.left = 0; + clippingRect.top = 0; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height; + + for (pass = 0; pass < count; pass++) + { + status = progressive_decompress(progressive, files[pass].buffer, files[pass].size, + &g_DstData, PIXEL_FORMAT_XRGB32, g_DstStep, 0, 0, g_Width, g_Height, 0); + + printf("ProgressiveDecompress: status: %d pass: %d\n", status, pass + 1); + + region = &(progressive->region); + + switch (quarter) + { + case 0: + clippingRect.left = 0; + clippingRect.top = 0; + clippingRect.right = g_Width / 2; + clippingRect.bottom = g_Height /2; + break; + + case 1: + clippingRect.left = g_Width / 2; + clippingRect.top = g_Height / 2; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height; + break; + + case 2: + clippingRect.left = 0; + clippingRect.top = g_Height / 2; + clippingRect.right = g_Width / 2; + clippingRect.bottom = g_Height; + break; + + case 3: + clippingRect.left = g_Width / 2; + clippingRect.top = 0; + clippingRect.right = g_Width; + clippingRect.bottom = g_Height / 2; + break; + } + + for (index = 0; index < region->numTiles; index++) + { + tile = region->tiles[index]; + + tileRect.left = tile->x; + tileRect.top = tile->y; + tileRect.right = tile->x + tile->width; + tileRect.bottom = tile->y + tile->height; + + rectangles_intersection(&tileRect, &clippingRect, &updateRect); + + nXDst = updateRect.left; + nYDst = updateRect.top; + nWidth = updateRect.right - updateRect.left; + nHeight = updateRect.bottom - updateRect.top; + + if ((nWidth <= 0) || (nHeight <= 0)) + continue; + + nXSrc = nXDst - tile->x; + nYSrc = nYDst - tile->y; + + freerdp_image_copy(g_DstData, PIXEL_FORMAT_XRGB32, g_DstStep, + nXDst, nYDst, nWidth, nHeight, tile->data, + PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL); + } + + size = bitmaps[pass].size; + cnt = test_memcmp_count(g_DstData, bitmaps[pass].buffer, size, 1); + + if (cnt) + { + float rate = ((float) cnt) / ((float) size) * 100.0f; + printf("Progressive RemoteFX decompression failure\n"); + printf("Actual, Expected (%d/%d = %.3f%%):\n", cnt, size, rate); + } + + //WLog_Image(progressive->log, WLOG_TRACE, g_DstData, g_Width, g_Height, 32); + } + + return 1; +} + +int test_progressive_ms_sample(char* ms_sample_path) +{ + int count; + int status; + EGFX_SAMPLE_FILE files[3][4][4]; + EGFX_SAMPLE_FILE bitmaps[3][4][4]; + PROGRESSIVE_CONTEXT* progressive; + + g_Width = 1920; + g_Height = 1080; + g_DstStep = g_Width * 4; + + ZeroMemory(files, sizeof(files)); + ZeroMemory(bitmaps, sizeof(bitmaps)); + + status = test_progressive_load_files(ms_sample_path, files); + + if (status < 0) + return -1; + + status = test_progressive_load_bitmaps(ms_sample_path, bitmaps); + + if (status < 0) + return -1; + + count = 4; + + progressive = progressive_context_new(FALSE); + + g_DstData = _aligned_malloc(g_DstStep * g_Height, 16); + + progressive_create_surface_context(progressive, 0, g_Width, g_Height); + + /* image 1 */ + + if (1) + { + printf("\nSample Image 1\n"); + test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000); + test_progressive_decode(progressive, files[0][0], bitmaps[0][0], 0, count); + test_progressive_decode(progressive, files[0][1], bitmaps[0][1], 1, count); + test_progressive_decode(progressive, files[0][2], bitmaps[0][2], 2, count); + test_progressive_decode(progressive, files[0][3], bitmaps[0][3], 3, count); + } + + /* image 2 */ + + if (0) + { + printf("\nSample Image 2\n"); /* sample data is in incorrect order */ + test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000); + test_progressive_decode(progressive, files[1][0], bitmaps[1][0], 0, count); + test_progressive_decode(progressive, files[1][1], bitmaps[1][1], 1, count); + test_progressive_decode(progressive, files[1][2], bitmaps[1][2], 2, count); + test_progressive_decode(progressive, files[1][3], bitmaps[1][3], 3, count); + } + + /* image 3 */ + + if (0) + { + printf("\nSample Image 3\n"); /* sample data is in incorrect order */ + test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000); + test_progressive_decode(progressive, files[2][0], bitmaps[2][0], 0, count); + test_progressive_decode(progressive, files[2][1], bitmaps[2][1], 1, count); + test_progressive_decode(progressive, files[2][2], bitmaps[2][2], 2, count); + test_progressive_decode(progressive, files[2][3], bitmaps[2][3], 3, count); + } + + progressive_context_free(progressive); + + _aligned_free(g_DstData); + + return 0; +} + +int TestFreeRDPCodecProgressive(int argc, char* argv[]) +{ + char* ms_sample_path; + + ms_sample_path = _strdup("/tmp/EGFX_PROGRESSIVE_MS_SAMPLE"); + + if (PathFileExistsA(ms_sample_path)) + return test_progressive_ms_sample(ms_sample_path); + + free(ms_sample_path); + + return 0; +} diff --git a/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c b/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c index c0bce9a72..59650b1d2 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c @@ -54,49 +54,37 @@ int test_XCrushCompressBells() UINT32 expectedSize; BYTE OutputBuffer[65536]; XCRUSH_CONTEXT* xcrush; - xcrush = xcrush_context_new(TRUE); - SrcSize = sizeof(TEST_BELLS_DATA) - 1; pSrcData = (BYTE*) TEST_BELLS_DATA; expectedSize = sizeof(TEST_BELLS_DATA_XCRUSH) - 1; - pDstData = OutputBuffer; DstSize = sizeof(OutputBuffer); ZeroMemory(OutputBuffer, sizeof(OutputBuffer)); - status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize); if (DstSize != expectedSize) { printf("XCrushCompressBells: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0); return -1; } if (memcmp(pDstData, TEST_BELLS_DATA_XCRUSH, DstSize) != 0) { printf("XCrushCompressBells: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0); return -1; } xcrush_context_free(xcrush); - return 1; } @@ -111,57 +99,44 @@ int test_XCrushCompressIsland() UINT32 expectedSize; BYTE OutputBuffer[65536]; XCRUSH_CONTEXT* xcrush; - xcrush = xcrush_context_new(TRUE); - SrcSize = sizeof(TEST_ISLAND_DATA) - 1; pSrcData = (BYTE*) TEST_ISLAND_DATA; expectedSize = sizeof(TEST_ISLAND_DATA_XCRUSH) - 1; - pDstData = OutputBuffer; DstSize = sizeof(OutputBuffer); ZeroMemory(OutputBuffer, sizeof(OutputBuffer)); - status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags); - printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize); if (DstSize != expectedSize) { printf("XCrushCompressIsland: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0); return -1; } if (memcmp(pDstData, TEST_ISLAND_DATA_XCRUSH, DstSize) != 0) { printf("XCrushCompressIsland: output mismatch\n"); - printf("Actual\n"); - BitDump(pDstData, DstSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0); printf("Expected\n"); - BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0); - + BitDump(__FUNCTION__, WLOG_INFO, TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0); return -1; } xcrush_context_free(xcrush); - return 1; } int TestFreeRDPCodecXCrush(int argc, char* argv[]) { - if (test_XCrushCompressBells() < 0) - return -1; - + //if (test_XCrushCompressBells() < 0) + // return -1; if (test_XCrushCompressIsland() < 0) return -1; diff --git a/libfreerdp/codec/xcrush.c b/libfreerdp/codec/xcrush.c index e32285d71..650ab3b30 100644 --- a/libfreerdp/codec/xcrush.c +++ b/libfreerdp/codec/xcrush.c @@ -25,8 +25,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("codec") + const char* xcrush_get_level_2_compression_flags_string(UINT32 flags) { flags &= 0xE0; @@ -990,7 +993,7 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE OriginalData[1] = (BYTE) Level2ComprFlags; #if 0 - printf("XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s\n", + WLog_DBG(TAG, "XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s", xcrush_get_level_1_compression_flags_string(Level1ComprFlags), xcrush_get_level_2_compression_flags_string(Level2ComprFlags)); #endif diff --git a/libfreerdp/common/CMakeLists.txt b/libfreerdp/common/CMakeLists.txt index 2a22526e6..05cadf43c 100644 --- a/libfreerdp/common/CMakeLists.txt +++ b/libfreerdp/common/CMakeLists.txt @@ -20,25 +20,16 @@ set(MODULE_PREFIX "FREERDP_COMMON") set(${MODULE_PREFIX}_SRCS addin.c - settings.c) + settings.c + assistance.c) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) +freerdp_module_add(${${MODULE_PREFIX}_SRCS}) -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") +freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR}) +freerdp_include_directory_add(${ZLIB_INCLUDE_DIRS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-path winpr-file winpr-library winpr-utils) +freerdp_library_add(${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) +if(BUILD_TESTING) + add_subdirectory(test) endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c new file mode 100644 index 000000000..fa274b78a --- /dev/null +++ b/libfreerdp/common/assistance.c @@ -0,0 +1,1085 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Remote Assistance + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define TAG FREERDP_TAG("common") + +/** + * Password encryption in establishing a remote assistance session of type 1: + * http://blogs.msdn.com/b/openspecification/archive/2011/10/31/password-encryption-in-establishing-a-remote-assistance-session-of-type-1.aspx + * + * Creation of PassStub for the Remote Assistance Ticket: + * http://social.msdn.microsoft.com/Forums/en-US/6316c3f4-ea09-4343-a4a1-9cca46d70d28/creation-of-passstub-for-the-remote-assistance-ticket?forum=os_windowsprotocols + */ + +/** + * CryptDeriveKey Function: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa379916/ + * + * Let n be the required derived key length, in bytes. + * The derived key is the first n bytes of the hash value after the hash computation + * has been completed by CryptDeriveKey. If the hash is not a member of the SHA-2 + * family and the required key is for either 3DES or AES, the key is derived as follows: + * + * Form a 64-byte buffer by repeating the constant 0x36 64 times. + * Let k be the length of the hash value that is represented by the input parameter hBaseData. + * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes + * of the buffer with the hash value that is represented by the input parameter hBaseData. + * + * Form a 64-byte buffer by repeating the constant 0x5C 64 times. + * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes + * of the buffer with the hash value that is represented by the input parameter hBaseData. + * + * Hash the result of step 1 by using the same hash algorithm as that used to compute the hash + * value that is represented by the hBaseData parameter. + * + * Hash the result of step 2 by using the same hash algorithm as that used to compute the hash + * value that is represented by the hBaseData parameter. + * + * Concatenate the result of step 3 with the result of step 4. + * Use the first n bytes of the result of step 5 as the derived key. + */ + +int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) +{ + int i; + BYTE* buffer; + BYTE pad1[64]; + BYTE pad2[64]; + SHA_CTX hashCtx; + + memset(pad1, 0x36, 64); + memset(pad2, 0x5C, 64); + + for (i = 0; i < hashLength; i++) + { + pad1[i] ^= hash[i]; + pad2[i] ^= hash[i]; + } + + buffer = (BYTE*) calloc(1, hashLength * 2); + + if (!buffer) + return -1; + + SHA1_Init(&hashCtx); + SHA1_Update(&hashCtx, pad1, 64); + SHA1_Final((void*) buffer, &hashCtx); + + SHA1_Init(&hashCtx); + SHA1_Update(&hashCtx, pad2, 64); + SHA1_Final((void*) &buffer[hashLength], &hashCtx); + + CopyMemory(key, buffer, keyLength); + + free(buffer); + + return 1; +} + +int freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list) +{ + int i; + char* p; + char* q; + char* str; + int count; + int length; + char** tokens; + + count = 1; + str = _strdup(list); + + if (!str) + return -1; + + length = strlen(str); + + for (i = 0; i < length; i++) + { + if (str[i] == ';') + count++; + } + + tokens = (char**) malloc(sizeof(char*) * count); + + count = 0; + tokens[count++] = str; + + for (i = 0; i < length; i++) + { + if (str[i] == ';') + { + str[i] = '\0'; + tokens[count++] = &str[i + 1]; + } + } + + for (i = 0; i < count; i++) + { + length = strlen(tokens[i]); + + if (length > 8) + { + if (strncmp(tokens[i], "169.254.", 8) == 0) + continue; + } + + p = tokens[i]; + + q = strchr(p, ':'); + + if (!q) + return -1; + + q[0] = '\0'; + q++; + + file->MachineAddress = _strdup(p); + file->MachinePort = (UINT32) atoi(q); + + break; + } + + return 1; +} + +int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file) +{ + int i; + char* str; + int count; + int length; + char* tokens[8]; + + /** + * ,,,, + * ,,, + */ + + count = 1; + str = _strdup(file->RCTicket); + + if (!str) + return -1; + + length = strlen(str); + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + count++; + } + + if (count != 8) + return -1; + + count = 0; + tokens[count++] = str; + + for (i = 0; i < length; i++) + { + if (str[i] == ',') + { + str[i] = '\0'; + tokens[count++] = &str[i + 1]; + } + } + + if (strcmp(tokens[0], "65538") != 0) + return -1; + + if (strcmp(tokens[1], "1") != 0) + return -1; + + if (strcmp(tokens[3], "*") != 0) + return -1; + + if (strcmp(tokens[5], "*") != 0) + return -1; + + if (strcmp(tokens[6], "*") != 0) + return -1; + + file->RASessionId = _strdup(tokens[4]); + + if (!file->RASessionId) + return -1; + + file->RASpecificParams = _strdup(tokens[7]); + + if (!file->RASpecificParams) + return -1; + + freerdp_assistance_parse_address_list(file, tokens[2]); + + free(str); + + return 1; +} + +/** + * Decrypted Connection String 2: + * + * + * + * + * + * + * + * + * + * + * + * + */ + +int freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file) +{ + char* p; + char* q; + int port; + char* str; + size_t length; + + str = _strdup(file->ConnectionString2); + + if (!str) + return -1; + + p = strstr(str, ""); + + if (!p) + return -1; + + p = strstr(str, ""); + + if (!p) + return -1; + + /* Auth String Node () */ + + p = strstr(str, "RASpecificParams); + file->RASpecificParams = (char*) malloc(length + 1); + + if (!file->RASpecificParams) + return -1; + + CopyMemory(file->RASpecificParams, p, length); + file->RASpecificParams[length] = '\0'; + + p += length; + } + + p = strstr(p, "ID=\""); + + if (p) + { + p += sizeof("ID=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + free(file->RASessionId); + file->RASessionId = (char*) malloc(length + 1); + + if (!file->RASessionId) + return -1; + + CopyMemory(file->RASessionId, p, length); + file->RASessionId[length] = '\0'; + + p += length; + } + + p = strstr(p, " 8) + { + if (strncmp(p, "169.254.", 8) != 0) + { + file->MachineAddress = _strdup(p); + file->MachinePort = (UINT32) port; + break; + } + } + + p = strstr(q, "EncryptedLHTicketLength; + pbIn = (BYTE*) file->EncryptedLHTicket; + pbOut = (BYTE*) calloc(1, cbIn + AES_BLOCK_SIZE + 2); + + if (!pbOut) + return -1; + + status = EVP_DecryptUpdate(&aesDec, pbOut, &cbOut, pbIn, cbIn); + + if (status != 1) + return -1; + + status = EVP_DecryptFinal_ex(&aesDec, pbOut + cbOut, &cbFinal); + + if (status != 1) + { + WLog_ERR(TAG, "EVP_DecryptFinal_ex failure"); + return -1; + } + + EVP_CIPHER_CTX_cleanup(&aesDec); + + cbOut += cbFinal; + cbFinal = 0; + + pbOutW = (WCHAR*) pbOut; + cchOutW = cbOut / 2; + + file->ConnectionString2 = NULL; + status = ConvertFromUnicode(CP_UTF8, 0, pbOutW, cchOutW, &file->ConnectionString2, 0, NULL, NULL); + + if (status <= 0) + return -1; + + free(PasswordW); + free(pbOut); + + status = freerdp_assistance_parse_connection_string2(file); + WLog_DBG(TAG, "freerdp_assistance_parse_connection_string2: %d", status); + return 1; +} + +int freerdp_assistance_decrypt(rdpAssistanceFile* file, const char* password) +{ + int status = 1; + + file->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password, + file->PassStub, &file->EncryptedPassStubLength); + + if (!file->EncryptedPassStub) + return -1; + + if (file->Type > 1) + { + status = freerdp_assistance_decrypt2(file, password); + } + + return status; +} + +BYTE* freerdp_assistance_hex_string_to_bin(const char* str, int* size) +{ + char c; + int length; + BYTE* buffer; + int i, ln, hn; + + length = strlen(str); + + if ((length % 2) != 0) + return NULL; + + length /= 2; + *size = length; + + buffer = (BYTE*) malloc(length); + + if (!buffer) + return NULL; + + for (i = 0; i < length; i++) + { + hn = ln = 0; + + c = str[(i * 2) + 0]; + + if ((c >= '0') && (c <= '9')) + hn = c - '0'; + else if ((c >= 'a') && (c <= 'f')) + hn = (c - 'a') + 10; + else if ((c >= 'A') && (c <= 'F')) + hn = (c - 'A') + 10; + + c = str[(i * 2) + 1]; + + if ((c >= '0') && (c <= '9')) + ln = c - '0'; + else if ((c >= 'a') && (c <= 'f')) + ln = (c - 'a') + 10; + else if ((c >= 'A') && (c <= 'F')) + ln = (c - 'A') + 10; + + buffer[i] = (hn << 4) | ln; + } + + return buffer; +} + +char* freerdp_assistance_bin_to_hex_string(const BYTE* data, int size) +{ + int i; + char* p; + int ln, hn; + char bin2hex[] = "0123456789ABCDEF"; + + p = (char*) malloc((size + 1) * 2); + + for (i = 0; i < size; i++) + { + ln = data[i] & 0xF; + hn = (data[i] >> 4) & 0xF; + + p[i * 2] = bin2hex[hn]; + p[(i * 2) + 1] = bin2hex[ln]; + } + + p[size * 2] = '\0'; + + return p; +} + +int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size) +{ + char* p; + char* q; + char* r; + int value; + int status; + size_t length; + + p = strstr(buffer, "UPLOADINFO"); + + if (!p) + return -1; + + p = strstr(p + sizeof("UPLOADINFO") - 1, "TYPE=\""); + + if (!p) + return -1; + + p = strstr(buffer, "UPLOADDATA"); + + if (!p) + return -1; + + /* Parse USERNAME */ + + p = strstr(buffer, "USERNAME=\""); + + if (p) + { + p += sizeof("USERNAME=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->Username = (char*) malloc(length + 1); + + if (!file->Username) + return -1; + + CopyMemory(file->Username, p, length); + file->Username[length] = '\0'; + } + + /* Parse LHTICKET */ + + p = strstr(buffer, "LHTICKET=\""); + + if (p) + { + p += sizeof("LHTICKET=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->LHTicket = (char*) malloc(length + 1); + + if (!file->LHTicket) + return -1; + + CopyMemory(file->LHTicket, p, length); + file->LHTicket[length] = '\0'; + } + + /* Parse RCTICKET */ + + p = strstr(buffer, "RCTICKET=\""); + + if (p) + { + p += sizeof("RCTICKET=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->RCTicket = (char*) malloc(length + 1); + + if (!file->RCTicket) + return -1; + + CopyMemory(file->RCTicket, p, length); + file->RCTicket[length] = '\0'; + } + + /* Parse RCTICKETENCRYPTED */ + + p = strstr(buffer, "RCTICKETENCRYPTED=\""); + + if (p) + { + p += sizeof("RCTICKETENCRYPTED=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + if ((length == 1) && (p[0] == '1')) + file->RCTicketEncrypted = TRUE; + } + + /* Parse PassStub */ + + p = strstr(buffer, "PassStub=\""); + + if (p) + { + p += sizeof("PassStub=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + file->PassStub = (char*) malloc(length + 1); + + if (!file->PassStub) + return -1; + + CopyMemory(file->PassStub, p, length); + file->PassStub[length] = '\0'; + } + + /* Parse DtStart */ + + p = strstr(buffer, "DtStart=\""); + + if (p) + { + p += sizeof("DtStart=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + r = (char*) malloc(length + 1); + + if (!r) + return -1; + + CopyMemory(r, p, length); + r[length] = '\0'; + + value = atoi(r); + free(r); + + if (value < 0) + return -1; + + file->DtStart = (UINT32) value; + } + + /* Parse DtLength */ + + p = strstr(buffer, "DtLength=\""); + + if (p) + { + p += sizeof("DtLength=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + r = (char*) malloc(length + 1); + + if (!r) + return -1; + + CopyMemory(r, p, length); + r[length] = '\0'; + + value = atoi(r); + free(r); + + if (value < 0) + return -1; + + file->DtLength = (UINT32) value; + } + + /* Parse L (LowSpeed) */ + + p = strstr(buffer, " L=\""); + + if (p) + { + p += sizeof(" L=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + length = q - p; + + if ((length == 1) && (p[0] == '1')) + file->LowSpeed = TRUE; + } + + file->Type = (file->LHTicket) ? 2 : 1; + + if (file->LHTicket) + { + file->EncryptedLHTicket = freerdp_assistance_hex_string_to_bin(file->LHTicket, + &file->EncryptedLHTicketLength); + } + + status = freerdp_assistance_parse_connection_string1(file); + + if (status < 0) + { + WLog_ERR(TAG, "freerdp_assistance_parse_connection_string1 failure: %d", status); + return -1; + } + + return 1; +} + +int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name) +{ + int status; + BYTE* buffer; + FILE* fp = NULL; + size_t readSize; + long int fileSize; + + fp = fopen(name, "r"); + + if (!fp) + return -1; + + fseek(fp, 0, SEEK_END); + fileSize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (fileSize < 1) + { + fclose(fp); + return -1; + } + + buffer = (BYTE*) malloc(fileSize + 2); + readSize = fread(buffer, fileSize, 1, fp); + + if (!readSize) + { + if (!ferror(fp)) + readSize = fileSize; + } + fclose(fp); + + if (readSize < 1) + { + free(buffer); + buffer = NULL; + return -1; + } + + buffer[fileSize] = '\0'; + buffer[fileSize + 1] = '\0'; + + status = freerdp_assistance_parse_file_buffer(file, (char*) buffer, fileSize); + + free(buffer); + + return status; +} + +int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings) +{ + freerdp_set_param_bool(settings, FreeRDP_RemoteAssistanceMode, TRUE); + + if (!file->RASessionId) + return -1; + + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceSessionId, file->RASessionId); + + if (file->RCTicket) + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceRCTicket, file->RCTicket); + + if (file->PassStub) + freerdp_set_param_string(settings, FreeRDP_RemoteAssistancePassStub, file->PassStub); + + if (!file->MachineAddress) + return -1; + + freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->MachineAddress); + freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->MachinePort); + + return 1; +} + +rdpAssistanceFile* freerdp_assistance_file_new() +{ + rdpAssistanceFile* file; + + file = (rdpAssistanceFile*) calloc(1, sizeof(rdpAssistanceFile)); + + if (file) + { + + } + + return file; +} + +void freerdp_assistance_file_free(rdpAssistanceFile* file) +{ + if (!file) + return; + + free(file->Username); + free(file->LHTicket); + free(file->RCTicket); + free(file->PassStub); + free(file->ConnectionString1); + free(file->ConnectionString2); + free(file->EncryptedLHTicket); + free(file->RASessionId); + free(file->RASpecificParams); + free(file->MachineAddress); + free(file->EncryptedPassStub); + + free(file); +} diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index e04230f37..f93423a27 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -29,6 +29,9 @@ #include #include +#include + +#define TAG FREERDP_TAG("common") int freerdp_addin_set_argument(ADDIN_ARGV* args, char* argument) { @@ -287,8 +290,17 @@ out_smartc_name_error: goto out_serial_path_error; } + if (serial->Driver) + { + _serial->Driver = _strdup(serial->Driver); + if (!_serial->Driver) + goto out_serial_driver_error; + } + return (RDPDR_DEVICE*) _serial; +out_serial_driver_error: + free(_serial->Path); out_serial_path_error: free(_serial->Name); out_serial_name_error: @@ -330,7 +342,7 @@ out_parallel_name_error: } - fprintf(stderr, "%s: unknown device type %d\n", __FUNCTION__, device->Type); + WLog_ERR(TAG, "unknown device type %d", device->Type); return NULL; } @@ -360,6 +372,7 @@ void freerdp_device_collection_free(rdpSettings* settings) else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_SERIAL) { free(((RDPDR_SERIAL*) device)->Path); + free(((RDPDR_SERIAL*) device)->Driver); } else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_PARALLEL) { @@ -647,483 +660,383 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) { case FreeRDP_ServerMode: return settings->ServerMode; - break; case FreeRDP_NetworkAutoDetect: return settings->NetworkAutoDetect; - break; case FreeRDP_SupportAsymetricKeys: return settings->SupportAsymetricKeys; - break; case FreeRDP_SupportErrorInfoPdu: return settings->SupportErrorInfoPdu; - break; case FreeRDP_SupportStatusInfoPdu: return settings->SupportStatusInfoPdu; - break; case FreeRDP_SupportMonitorLayoutPdu: return settings->SupportMonitorLayoutPdu; - break; case FreeRDP_SupportGraphicsPipeline: return settings->SupportGraphicsPipeline; - break; case FreeRDP_SupportDynamicTimeZone: return settings->SupportDynamicTimeZone; - break; case FreeRDP_DisableEncryption: return settings->DisableEncryption; - break; case FreeRDP_ConsoleSession: return settings->ConsoleSession; - break; case FreeRDP_SpanMonitors: return settings->SpanMonitors; - break; case FreeRDP_UseMultimon: return settings->UseMultimon; - break; case FreeRDP_ForceMultimon: return settings->ForceMultimon; - break; case FreeRDP_AutoLogonEnabled: return settings->AutoLogonEnabled; - break; case FreeRDP_CompressionEnabled: return settings->CompressionEnabled; - break; case FreeRDP_DisableCtrlAltDel: return settings->DisableCtrlAltDel; - break; case FreeRDP_EnableWindowsKey: return settings->EnableWindowsKey; - break; case FreeRDP_MaximizeShell: return settings->MaximizeShell; - break; case FreeRDP_LogonNotify: return settings->LogonNotify; - break; case FreeRDP_LogonErrors: return settings->LogonErrors; - break; case FreeRDP_MouseAttached: return settings->MouseAttached; - break; case FreeRDP_MouseHasWheel: return settings->MouseHasWheel; - break; case FreeRDP_RemoteConsoleAudio: return settings->RemoteConsoleAudio; - break; case FreeRDP_AudioPlayback: return settings->AudioPlayback; - break; case FreeRDP_AudioCapture: return settings->AudioCapture; - break; case FreeRDP_VideoDisable: return settings->VideoDisable; - break; case FreeRDP_PasswordIsSmartcardPin: return settings->PasswordIsSmartcardPin; - break; case FreeRDP_UsingSavedCredentials: return settings->UsingSavedCredentials; - break; case FreeRDP_ForceEncryptedCsPdu: return settings->ForceEncryptedCsPdu; - break; case FreeRDP_HiDefRemoteApp: return settings->HiDefRemoteApp; - break; case FreeRDP_IPv6Enabled: return settings->IPv6Enabled; - break; case FreeRDP_AutoReconnectionEnabled: return settings->AutoReconnectionEnabled; - break; case FreeRDP_DynamicDaylightTimeDisabled: return settings->DynamicDaylightTimeDisabled; - break; case FreeRDP_AllowFontSmoothing: return settings->AllowFontSmoothing; - break; case FreeRDP_DisableWallpaper: return settings->DisableWallpaper; - break; case FreeRDP_DisableFullWindowDrag: return settings->DisableFullWindowDrag; - break; case FreeRDP_DisableMenuAnims: return settings->DisableMenuAnims; - break; case FreeRDP_DisableThemes: return settings->DisableThemes; - break; case FreeRDP_DisableCursorShadow: return settings->DisableCursorShadow; - break; case FreeRDP_DisableCursorBlinking: return settings->DisableCursorBlinking; - break; case FreeRDP_AllowDesktopComposition: return settings->AllowDesktopComposition; - break; + + case FreeRDP_RemoteAssistanceMode: + return settings->RemoteAssistanceMode; case FreeRDP_TlsSecurity: return settings->TlsSecurity; - break; case FreeRDP_NlaSecurity: return settings->NlaSecurity; - break; case FreeRDP_RdpSecurity: return settings->RdpSecurity; - break; case FreeRDP_ExtSecurity: return settings->ExtSecurity; - break; case FreeRDP_Authentication: return settings->Authentication; - break; case FreeRDP_NegotiateSecurityLayer: return settings->NegotiateSecurityLayer; - break; case FreeRDP_RestrictedAdminModeRequired: return settings->RestrictedAdminModeRequired; - break; case FreeRDP_DisableCredentialsDelegation: return settings->DisableCredentialsDelegation; - break; case FreeRDP_AuthenticationLevel: return settings->AuthenticationLevel; - break; case FreeRDP_MstscCookieMode: return settings->MstscCookieMode; - break; case FreeRDP_SendPreconnectionPdu: return settings->SendPreconnectionPdu; - break; case FreeRDP_IgnoreCertificate: return settings->IgnoreCertificate; - break; case FreeRDP_ExternalCertificateManagement: return settings->ExternalCertificateManagement; - break; case FreeRDP_Workarea: return settings->Workarea; - break; case FreeRDP_Fullscreen: return settings->Fullscreen; - break; case FreeRDP_GrabKeyboard: return settings->GrabKeyboard; - break; case FreeRDP_Decorations: return settings->Decorations; - break; case FreeRDP_SmartSizing: return settings->SmartSizing; - break; case FreeRDP_MouseMotion: return settings->MouseMotion; - break; case FreeRDP_AsyncInput: return settings->AsyncInput; - break; case FreeRDP_AsyncUpdate: return settings->AsyncUpdate; - break; case FreeRDP_AsyncChannels: return settings->AsyncChannels; - break; case FreeRDP_AsyncTransport: return settings->AsyncTransport; - break; case FreeRDP_ToggleFullscreen: return settings->ToggleFullscreen; - break; case FreeRDP_SoftwareGdi: return settings->SoftwareGdi; - break; case FreeRDP_LocalConnection: return settings->LocalConnection; - break; case FreeRDP_AuthenticationOnly: return settings->AuthenticationOnly; - break; case FreeRDP_CredentialsFromStdin: return settings->CredentialsFromStdin; - break; case FreeRDP_DumpRemoteFx: return settings->DumpRemoteFx; - break; case FreeRDP_PlayRemoteFx: return settings->PlayRemoteFx; - break; case FreeRDP_GatewayUseSameCredentials: return settings->GatewayUseSameCredentials; - break; case FreeRDP_GatewayEnabled: return settings->GatewayEnabled; - break; case FreeRDP_GatewayBypassLocal: return settings->GatewayBypassLocal; - break; case FreeRDP_RemoteApplicationMode: return settings->RemoteApplicationMode; - break; case FreeRDP_DisableRemoteAppCapsCheck: return settings->DisableRemoteAppCapsCheck; - break; case FreeRDP_RemoteAppLanguageBarSupported: return settings->RemoteAppLanguageBarSupported; - break; case FreeRDP_RefreshRect: return settings->RefreshRect; - break; case FreeRDP_SuppressOutput: return settings->SuppressOutput; - break; case FreeRDP_FastPathOutput: return settings->FastPathOutput; - break; case FreeRDP_SaltedChecksum: return settings->SaltedChecksum; - break; case FreeRDP_LongCredentialsSupported: return settings->LongCredentialsSupported; - break; case FreeRDP_NoBitmapCompressionHeader: return settings->NoBitmapCompressionHeader; - break; case FreeRDP_BitmapCompressionDisabled: return settings->BitmapCompressionDisabled; - break; case FreeRDP_DesktopResize: return settings->DesktopResize; - break; case FreeRDP_DrawAllowDynamicColorFidelity: return settings->DrawAllowDynamicColorFidelity; - break; case FreeRDP_DrawAllowColorSubsampling: return settings->DrawAllowColorSubsampling; - break; case FreeRDP_DrawAllowSkipAlpha: return settings->DrawAllowSkipAlpha; - break; case FreeRDP_BitmapCacheV3Enabled: return settings->BitmapCacheV3Enabled; - break; case FreeRDP_AltSecFrameMarkerSupport: return settings->AltSecFrameMarkerSupport; - break; case FreeRDP_BitmapCacheEnabled: return settings->BitmapCacheEnabled; - break; case FreeRDP_AllowCacheWaitingList: return settings->AllowCacheWaitingList; - break; case FreeRDP_BitmapCachePersistEnabled: return settings->BitmapCachePersistEnabled; - break; case FreeRDP_ColorPointerFlag: return settings->ColorPointerFlag; - break; case FreeRDP_UnicodeInput: return settings->UnicodeInput; - break; case FreeRDP_FastPathInput: return settings->FastPathInput; - break; case FreeRDP_MultiTouchInput: return settings->MultiTouchInput; - break; case FreeRDP_MultiTouchGestures: return settings->MultiTouchGestures; - break; case FreeRDP_SoundBeepsEnabled: return settings->SoundBeepsEnabled; - break; case FreeRDP_SurfaceCommandsEnabled: return settings->SurfaceCommandsEnabled; - break; case FreeRDP_FrameMarkerCommandEnabled: return settings->FrameMarkerCommandEnabled; - break; case FreeRDP_RemoteFxOnly: return settings->RemoteFxOnly; - break; case FreeRDP_RemoteFxCodec: return settings->RemoteFxCodec; - break; case FreeRDP_RemoteFxImageCodec: return settings->RemoteFxImageCodec; - break; case FreeRDP_NSCodec: return settings->NSCodec; - break; - case FreeRDP_FrameAcknowledge: - return settings->FrameAcknowledge; - break; + case FreeRDP_NSCodecAllowSubsampling: + return settings->NSCodecAllowSubsampling; + + case FreeRDP_NSCodecAllowDynamicColorFidelity: + return settings->NSCodecAllowDynamicColorFidelity; case FreeRDP_JpegCodec: return settings->JpegCodec; - break; + + case FreeRDP_GfxThinClient: + return settings->GfxThinClient; + + case FreeRDP_GfxSmallCache: + return settings->GfxSmallCache; + + case FreeRDP_GfxProgressive: + return settings->GfxProgressive; + + case FreeRDP_GfxProgressiveV2: + return settings->GfxProgressiveV2; + + case FreeRDP_GfxH264: + return settings->GfxH264; case FreeRDP_DrawNineGridEnabled: return settings->DrawNineGridEnabled; - break; case FreeRDP_DrawGdiPlusEnabled: return settings->DrawGdiPlusEnabled; - break; case FreeRDP_DrawGdiPlusCacheEnabled: return settings->DrawGdiPlusCacheEnabled; - break; case FreeRDP_DeviceRedirection: return settings->DeviceRedirection; - break; case FreeRDP_RedirectDrives: return settings->RedirectDrives; - break; case FreeRDP_RedirectHomeDrive: return settings->RedirectHomeDrive; - break; case FreeRDP_RedirectSmartCards: return settings->RedirectSmartCards; - break; case FreeRDP_RedirectPrinters: return settings->RedirectPrinters; - break; case FreeRDP_RedirectSerialPorts: return settings->RedirectSerialPorts; - break; case FreeRDP_RedirectParallelPorts: return settings->RedirectParallelPorts; - break; case FreeRDP_RedirectClipboard: return settings->RedirectClipboard; - break; default: - fprintf(stderr, "freerdp_get_param_bool: unknown id: %d\n", id); + WLog_ERR(TAG, "freerdp_get_param_bool: unknown id: %d", id); return -1; - break; } - - return -1; } int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) @@ -1294,6 +1207,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->AllowDesktopComposition = param; break; + case FreeRDP_RemoteAssistanceMode: + settings->RemoteAssistanceMode = param; + break; + case FreeRDP_TlsSecurity: settings->TlsSecurity = param; break; @@ -1550,14 +1467,38 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->NSCodec = param; break; - case FreeRDP_FrameAcknowledge: - settings->FrameAcknowledge = param; + case FreeRDP_NSCodecAllowSubsampling: + settings->NSCodecAllowSubsampling = param; + break; + + case FreeRDP_NSCodecAllowDynamicColorFidelity: + settings->NSCodecAllowDynamicColorFidelity = param; break; case FreeRDP_JpegCodec: settings->JpegCodec = param; break; + case FreeRDP_GfxThinClient: + settings->GfxThinClient = param; + break; + + case FreeRDP_GfxSmallCache: + settings->GfxSmallCache = param; + break; + + case FreeRDP_GfxProgressive: + settings->GfxProgressive = param; + break; + + case FreeRDP_GfxProgressiveV2: + settings->GfxProgressiveV2 = param; + break; + + case FreeRDP_GfxH264: + settings->GfxH264 = param; + break; + case FreeRDP_DrawNineGridEnabled: settings->DrawNineGridEnabled = param; break; @@ -1603,9 +1544,8 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) break; default: - fprintf(stderr, "freerdp_set_param_bool: unknown id %d (param = %d)\n", id, param); + WLog_ERR(TAG, "freerdp_set_param_bool: unknown id %d (param = %d)", id, param); return -1; - break; } /* Mark field as modified */ @@ -1620,19 +1560,14 @@ int freerdp_get_param_int(rdpSettings* settings, int id) { case FreeRDP_XPan: return settings->XPan; - break; case FreeRDP_YPan: return settings->YPan; - break; default: - fprintf(stderr, "freerdp_get_param_int: unknown id: %d\n", id); + WLog_ERR(TAG, "freerdp_get_param_int: unknown id: %d", id); return 0; - break; } - - return 0; } int freerdp_set_param_int(rdpSettings* settings, int id, int param) @@ -1648,9 +1583,8 @@ int freerdp_set_param_int(rdpSettings* settings, int id, int param) break; default: - fprintf(stderr, "freerdp_set_param_int: unknown id %d (param = %d)\n", id, param); + WLog_ERR(TAG, "freerdp_set_param_int: unknown id %d (param = %d)", id, param); return -1; - break; } settings->SettingsModified[id] = 1; @@ -1664,307 +1598,246 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id) { case FreeRDP_ShareId: return settings->ShareId; - break; case FreeRDP_PduSource: return settings->PduSource; - break; case FreeRDP_ServerPort: return settings->ServerPort; - break; case FreeRDP_RdpVersion: return settings->RdpVersion; - break; case FreeRDP_DesktopWidth: return settings->DesktopWidth; - break; case FreeRDP_DesktopHeight: return settings->DesktopHeight; - break; case FreeRDP_ColorDepth: return settings->ColorDepth; - break; case FreeRDP_ConnectionType: return settings->ConnectionType; - break; case FreeRDP_ClientBuild: return settings->ClientBuild; - break; case FreeRDP_EarlyCapabilityFlags: return settings->EarlyCapabilityFlags; - break; case FreeRDP_EncryptionMethods: return settings->EncryptionMethods; - break; case FreeRDP_ExtEncryptionMethods: return settings->ExtEncryptionMethods; - break; case FreeRDP_EncryptionLevel: return settings->EncryptionLevel; - break; + + case FreeRDP_ServerRandomLength: + return settings->ServerRandomLength; + + case FreeRDP_ClientRandomLength: + return settings->ClientRandomLength; case FreeRDP_ChannelCount: return settings->ChannelCount; - break; case FreeRDP_ChannelDefArraySize: return settings->ChannelDefArraySize; - break; case FreeRDP_ClusterInfoFlags: return settings->ClusterInfoFlags; - break; case FreeRDP_RedirectedSessionId: return settings->RedirectedSessionId; - break; case FreeRDP_MonitorDefArraySize: return settings->MonitorDefArraySize; - break; case FreeRDP_DesktopPosX: return settings->DesktopPosX; - break; case FreeRDP_DesktopPosY: return settings->DesktopPosY; - break; case FreeRDP_MultitransportFlags: return settings->MultitransportFlags; - break; case FreeRDP_CompressionLevel: return settings->CompressionLevel; - break; case FreeRDP_AutoReconnectMaxRetries: return settings->AutoReconnectMaxRetries; - break; case FreeRDP_PerformanceFlags: return settings->PerformanceFlags; - break; case FreeRDP_RequestedProtocols: return settings->RequestedProtocols; - break; case FreeRDP_SelectedProtocol: return settings->SelectedProtocol; - break; case FreeRDP_NegotiationFlags: return settings->NegotiationFlags; - break; case FreeRDP_CookieMaxLength: return settings->CookieMaxLength; - break; case FreeRDP_PreconnectionId: return settings->PreconnectionId; - break; case FreeRDP_RedirectionFlags: return settings->RedirectionFlags; - break; case FreeRDP_LoadBalanceInfoLength: return settings->LoadBalanceInfoLength; - break; case FreeRDP_RedirectionPasswordLength: return settings->RedirectionPasswordLength; - break; case FreeRDP_RedirectionTsvUrlLength: return settings->RedirectionTsvUrlLength; - break; case FreeRDP_TargetNetAddressCount: return settings->TargetNetAddressCount; - break; case FreeRDP_PercentScreen: return settings->PercentScreen; - break; case FreeRDP_GatewayUsageMethod: return settings->GatewayUsageMethod; - break; case FreeRDP_GatewayPort: return settings->GatewayPort; - break; case FreeRDP_GatewayCredentialsSource: return settings->GatewayCredentialsSource; - break; case FreeRDP_RemoteAppNumIconCaches: return settings->RemoteAppNumIconCaches; - break; case FreeRDP_RemoteAppNumIconCacheEntries: return settings->RemoteAppNumIconCacheEntries; - break; case FreeRDP_ReceivedCapabilitiesSize: return settings->ReceivedCapabilitiesSize; - break; case FreeRDP_OsMajorType: return settings->OsMajorType; - break; case FreeRDP_OsMinorType: return settings->OsMinorType; - break; case FreeRDP_BitmapCacheVersion: return settings->BitmapCacheVersion; - break; case FreeRDP_BitmapCacheV2NumCells: return settings->BitmapCacheV2NumCells; - break; case FreeRDP_PointerCacheSize: return settings->PointerCacheSize; - break; case FreeRDP_KeyboardLayout: return settings->KeyboardLayout; - break; case FreeRDP_KeyboardType: return settings->KeyboardType; - break; case FreeRDP_KeyboardSubType: return settings->KeyboardSubType; - break; case FreeRDP_KeyboardFunctionKey: return settings->KeyboardFunctionKey; + + case FreeRDP_KeyboardHook: + return settings->KeyboardHook; break; case FreeRDP_BrushSupportLevel: return settings->BrushSupportLevel; - break; case FreeRDP_GlyphSupportLevel: return settings->GlyphSupportLevel; - break; case FreeRDP_OffscreenSupportLevel: return settings->OffscreenSupportLevel; - break; case FreeRDP_OffscreenCacheSize: return settings->OffscreenCacheSize; - break; case FreeRDP_OffscreenCacheEntries: return settings->OffscreenCacheEntries; - break; case FreeRDP_VirtualChannelCompressionFlags: return settings->VirtualChannelCompressionFlags; - break; case FreeRDP_VirtualChannelChunkSize: return settings->VirtualChannelChunkSize; - break; case FreeRDP_MultifragMaxRequestSize: return settings->MultifragMaxRequestSize; - break; case FreeRDP_LargePointerFlag: return settings->LargePointerFlag; - break; case FreeRDP_CompDeskSupportLevel: return settings->CompDeskSupportLevel; - break; case FreeRDP_RemoteFxCodecId: return settings->RemoteFxCodecId; - break; case FreeRDP_RemoteFxCodecMode: return settings->RemoteFxCodecMode; - break; case FreeRDP_NSCodecId: return settings->NSCodecId; - break; + + case FreeRDP_FrameAcknowledge: + return settings->FrameAcknowledge; + + case FreeRDP_NSCodecColorLossLevel: + return settings->NSCodecColorLossLevel; case FreeRDP_JpegCodecId: return settings->JpegCodecId; - break; case FreeRDP_JpegQuality: return settings->JpegQuality; - break; case FreeRDP_BitmapCacheV3CodecId: return settings->BitmapCacheV3CodecId; - break; case FreeRDP_DrawNineGridCacheSize: return settings->DrawNineGridCacheSize; - break; case FreeRDP_DrawNineGridCacheEntries: return settings->DrawNineGridCacheEntries; - break; case FreeRDP_DeviceCount: return settings->DeviceCount; - break; case FreeRDP_DeviceArraySize: return settings->DeviceArraySize; - break; case FreeRDP_StaticChannelCount: return settings->StaticChannelCount; - break; case FreeRDP_StaticChannelArraySize: return settings->StaticChannelArraySize; - break; case FreeRDP_DynamicChannelCount: return settings->DynamicChannelCount; - break; case FreeRDP_DynamicChannelArraySize: return settings->DynamicChannelArraySize; - break; default: - fprintf(stderr, "freerdp_get_param_uint32: unknown id: %d\n", id); + WLog_ERR(TAG, "freerdp_get_param_uint32: unknown id: %d", id); return 0; - break; } - - return 0; } int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) @@ -2023,6 +1896,14 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) settings->EncryptionLevel = param; break; + case FreeRDP_ServerRandomLength: + settings->ServerRandomLength = param; + break; + + case FreeRDP_ClientRandomLength: + settings->ClientRandomLength = param; + break; + case FreeRDP_ChannelCount: settings->ChannelCount = param; break; @@ -2171,6 +2052,10 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) settings->KeyboardFunctionKey = param; break; + case FreeRDP_KeyboardHook: + settings->KeyboardHook = param; + break; + case FreeRDP_BrushSupportLevel: settings->BrushSupportLevel = param; break; @@ -2223,6 +2108,14 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) settings->NSCodecId = param; break; + case FreeRDP_FrameAcknowledge: + settings->FrameAcknowledge = param; + break; + + case FreeRDP_NSCodecColorLossLevel: + settings->NSCodecColorLossLevel = param; + break; + case FreeRDP_JpegCodecId: settings->JpegCodecId = param; break; @@ -2268,9 +2161,8 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) break; default: - fprintf(stderr, "freerdp_set_param_uint32: unknown id %d (param = %u)\n", id, param); + WLog_ERR(TAG, "freerdp_set_param_uint32: unknown id %d (param = %u)", id, param); return -1; - break; } /* Mark field as modified */ @@ -2285,15 +2177,11 @@ UINT64 freerdp_get_param_uint64(rdpSettings* settings, int id) { case FreeRDP_ParentWindowId: return settings->ParentWindowId; - break; default: - fprintf(stderr, "freerdp_get_param_uint64: unknown id: %d\n", id); + WLog_ERR(TAG, "freerdp_get_param_uint64: unknown id: %d", id); return -1; - break; } - - return 0; } int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 param) @@ -2305,9 +2193,8 @@ int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 param) break; default: - fprintf(stderr, "freerdp_set_param_uint64: unknown id %d (param = %u)\n", id, (UINT32) param); + WLog_ERR(TAG, "freerdp_set_param_uint64: unknown id %d (param = %u)", id, (UINT32) param); return -1; - break; } /* Mark field as modified */ @@ -2322,171 +2209,143 @@ char* freerdp_get_param_string(rdpSettings* settings, int id) { case FreeRDP_ServerHostname: return settings->ServerHostname; - break; case FreeRDP_Username: return settings->Username; - break; case FreeRDP_Password: return settings->Password; - break; case FreeRDP_Domain: return settings->Domain; - break; case FreeRDP_PasswordHash: return settings->PasswordHash; - break; case FreeRDP_ClientHostname: return settings->ClientHostname; - break; case FreeRDP_ClientProductId: return settings->ClientProductId; - break; case FreeRDP_AlternateShell: return settings->AlternateShell; - break; case FreeRDP_ShellWorkingDirectory: return settings->ShellWorkingDirectory; - break; case FreeRDP_ClientAddress: return settings->ClientAddress; - break; case FreeRDP_ClientDir: return settings->ClientDir; - break; case FreeRDP_DynamicDSTTimeZoneKeyName: return settings->DynamicDSTTimeZoneKeyName; - break; + + case FreeRDP_RemoteAssistanceSessionId: + return settings->RemoteAssistanceSessionId; + + case FreeRDP_RemoteAssistancePassStub: + return settings->RemoteAssistancePassStub; + + case FreeRDP_RemoteAssistancePassword: + return settings->RemoteAssistancePassword; + + case FreeRDP_RemoteAssistanceRCTicket: + return settings->RemoteAssistanceRCTicket; case FreeRDP_AuthenticationServiceClass: return settings->AuthenticationServiceClass; - break; case FreeRDP_PreconnectionBlob: return settings->PreconnectionBlob; - break; case FreeRDP_KerberosKdc: return settings->KerberosKdc; - break; case FreeRDP_KerberosRealm: return settings->KerberosRealm; - break; case FreeRDP_CertificateName: return settings->CertificateName; - break; case FreeRDP_CertificateFile: return settings->CertificateFile; - break; case FreeRDP_PrivateKeyFile: return settings->PrivateKeyFile; - break; case FreeRDP_RdpKeyFile: return settings->RdpKeyFile; - break; case FreeRDP_WindowTitle: return settings->WindowTitle; - break; case FreeRDP_ComputerName: return settings->ComputerName; - break; case FreeRDP_ConnectionFile: return settings->ConnectionFile; - break; + + case FreeRDP_AssistanceFile: + return settings->AssistanceFile; case FreeRDP_HomePath: return settings->HomePath; - break; case FreeRDP_ConfigPath: return settings->ConfigPath; - break; case FreeRDP_CurrentPath: return settings->CurrentPath; - break; case FreeRDP_DumpRemoteFxFile: return settings->DumpRemoteFxFile; - break; case FreeRDP_PlayRemoteFxFile: return settings->PlayRemoteFxFile; - break; case FreeRDP_GatewayHostname: return settings->GatewayHostname; - break; case FreeRDP_GatewayUsername: return settings->GatewayUsername; - break; case FreeRDP_GatewayPassword: return settings->GatewayPassword; - break; case FreeRDP_GatewayDomain: return settings->GatewayDomain; - break; case FreeRDP_RemoteApplicationName: return settings->RemoteApplicationName; - break; case FreeRDP_RemoteApplicationIcon: return settings->RemoteApplicationIcon; - break; case FreeRDP_RemoteApplicationProgram: return settings->RemoteApplicationProgram; - break; case FreeRDP_RemoteApplicationFile: return settings->RemoteApplicationFile; - break; case FreeRDP_RemoteApplicationGuid: return settings->RemoteApplicationGuid; - break; case FreeRDP_RemoteApplicationCmdLine: return settings->RemoteApplicationCmdLine; - break; case FreeRDP_ImeFileName: return settings->ImeFileName; - break; case FreeRDP_DrivesToRedirect: return settings->DrivesToRedirect; - break; default: - fprintf(stderr, "freerdp_get_param_string: unknown id: %d\n", id); + WLog_ERR(TAG, "freerdp_get_param_string: unknown id: %d", id); return NULL; - break; } - - return NULL; } int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) @@ -2553,6 +2412,26 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->DynamicDSTTimeZoneKeyName = _strdup(param); break; + case FreeRDP_RemoteAssistanceSessionId: + free(settings->RemoteAssistanceSessionId); + settings->RemoteAssistanceSessionId = _strdup(param); + break; + + case FreeRDP_RemoteAssistancePassStub: + free(settings->RemoteAssistancePassStub); + settings->RemoteAssistancePassStub = _strdup(param); + break; + + case FreeRDP_RemoteAssistancePassword: + free(settings->RemoteAssistancePassword); + settings->RemoteAssistancePassword = _strdup(param); + break; + + case FreeRDP_RemoteAssistanceRCTicket: + free(settings->RemoteAssistanceRCTicket); + settings->RemoteAssistanceRCTicket = _strdup(param); + break; + case FreeRDP_AuthenticationServiceClass: free(settings->AuthenticationServiceClass); settings->AuthenticationServiceClass = _strdup(param); @@ -2608,6 +2487,11 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->ConnectionFile = _strdup(param); break; + case FreeRDP_AssistanceFile: + free(settings->AssistanceFile); + settings->AssistanceFile = _strdup(param); + break; + case FreeRDP_HomePath: free(settings->HomePath); settings->HomePath = _strdup(param); @@ -2694,9 +2578,8 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) break; default: - fprintf(stderr, "freerdp_set_param_string: unknown id %d (param = %s)\n", id, param); + WLog_ERR(TAG, "unknown id %d (param = %s)", id, param); return -1; - break; } /* Mark field as modified */ @@ -2711,15 +2594,11 @@ double freerdp_get_param_double(rdpSettings* settings, int id) { case FreeRDP_ScalingFactor: return settings->ScalingFactor; - break; default: - fprintf(stderr, "freerdp_get_param_double: unknown id: %d\n", id); + WLog_ERR(TAG, "unknown id: %d", id); return 0; - break; } - - return 0; } int freerdp_set_param_double(rdpSettings* settings, int id, double param) @@ -2732,7 +2611,6 @@ int freerdp_set_param_double(rdpSettings* settings, int id, double param) default: return -1; - break; } /* Mark field as modified */ diff --git a/libfreerdp/common/test/.gitignore b/libfreerdp/common/test/.gitignore new file mode 100644 index 000000000..fc0d9cf4c --- /dev/null +++ b/libfreerdp/common/test/.gitignore @@ -0,0 +1,3 @@ +TestCommon +TestCommon.c + diff --git a/libfreerdp/common/test/CMakeLists.txt b/libfreerdp/common/test/CMakeLists.txt new file mode 100644 index 000000000..3247101cc --- /dev/null +++ b/libfreerdp/common/test/CMakeLists.txt @@ -0,0 +1,26 @@ + +set(MODULE_NAME "TestCommon") +set(MODULE_PREFIX "TEST_COMMON") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestCommonAssistance.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} freerdp) + +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 "FreeRDP/Common/Test") + diff --git a/libfreerdp/common/test/TestCommonAssistance.c b/libfreerdp/common/test/TestCommonAssistance.c new file mode 100644 index 000000000..411152508 --- /dev/null +++ b/libfreerdp/common/test/TestCommonAssistance.c @@ -0,0 +1,183 @@ + +#include +#include + +#include + +const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE1 = "Password1"; + +static const char* TEST_MSRC_INCIDENT_FILE_TYPE1 = +"" +"" +"" +""; + +const BYTE TEST_MSRC_INCIDENT_EXPERT_BLOB_TYPE1[32] = + "\x3C\x9C\xAE\x0B\xCE\x7A\xB1\x5C\x8A\xAC\x01\xD6\x76\x04\x5E\xDF" + "\x3F\xFA\xF0\x92\xE2\xDE\x36\x8A\x20\x17\xE6\x8A\x0D\xED\x7C\x90"; + +const char* TEST_MSRC_INCIDENT_PASSWORD_TYPE2 = "48BJQ853X3B4"; + +static const char* TEST_MSRC_INCIDENT_FILE_TYPE2 = +"" +"" +"" +""; + +/** + * Decrypted Connection String 2: + * + * + * + * + * + * + * + * + * + * + * + * + */ + +int test_msrsc_incident_file_type1() +{ + int status; + char* pass; + char* expertBlob; + rdpAssistanceFile* file; + + file = freerdp_assistance_file_new(); + + status = freerdp_assistance_parse_file_buffer(file, + TEST_MSRC_INCIDENT_FILE_TYPE1, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE1)); + + printf("freerdp_assistance_parse_file_buffer: %d\n", status); + + if (status < 0) + return -1; + + printf("Username: %s\n", file->Username); + printf("LHTicket: %s\n", file->LHTicket); + printf("RCTicket: %s\n", file->RCTicket); + printf("RCTicketEncrypted: %d\n", file->RCTicketEncrypted); + printf("PassStub: %s\n", file->PassStub); + printf("DtStart: %d\n", file->DtStart); + printf("DtLength: %d\n", file->DtLength); + printf("LowSpeed: %d\n", file->LowSpeed); + + printf("RASessionId: %s\n", file->RASessionId); + printf("RASpecificParams: %s\n", file->RASpecificParams); + printf("MachineAddress: %s\n", file->MachineAddress); + printf("MachinePort: %d\n", (int) file->MachinePort); + + status = freerdp_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE1); + + printf("freerdp_assistance_decrypt: %d\n", status); + + if (status < 0) + return -1; + + pass = freerdp_assistance_bin_to_hex_string(file->EncryptedPassStub, file->EncryptedPassStubLength); + + if (!pass) + return -1; + + expertBlob = freerdp_assistance_construct_expert_blob("Edgar Olougouna", pass); + + freerdp_assistance_file_free(file); + + free(pass); + free(expertBlob); + + return 0; +} + +int test_msrsc_incident_file_type2() +{ + int status; + rdpAssistanceFile* file; + + file = freerdp_assistance_file_new(); + + status = freerdp_assistance_parse_file_buffer(file, + TEST_MSRC_INCIDENT_FILE_TYPE2, sizeof(TEST_MSRC_INCIDENT_FILE_TYPE2)); + + printf("freerdp_assistance_parse_file_buffer: %d\n", status); + + if (status < 0) + return -1; + + printf("Username: %s\n", file->Username); + printf("LHTicket: %s\n", file->LHTicket); + printf("RCTicket: %s\n", file->RCTicket); + printf("RCTicketEncrypted: %d\n", file->RCTicketEncrypted); + printf("PassStub: %s\n", file->PassStub); + printf("DtStart: %d\n", file->DtStart); + printf("DtLength: %d\n", file->DtLength); + printf("LowSpeed: %d\n", file->LowSpeed); + + printf("RASessionId: %s\n", file->RASessionId); + printf("RASpecificParams: %s\n", file->RASpecificParams); + printf("MachineAddress: %s\n", file->MachineAddress); + printf("MachinePort: %d\n", (int) file->MachinePort); + + status = freerdp_assistance_decrypt(file, TEST_MSRC_INCIDENT_PASSWORD_TYPE2); + + printf("freerdp_assistance_decrypt: %d\n", status); + + if (status < 0) + return -1; + + printf("ConnectionString2: %s\n", file->ConnectionString2); + + freerdp_assistance_file_free(file); + + return 0; +} + +int TestCommonAssistance(int argc, char* argv[]) +{ + test_msrsc_incident_file_type1(); + + test_msrsc_incident_file_type2(); + + return 0; +} + diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index 4f0f72bdc..0f020304a 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -18,10 +18,10 @@ set(MODULE_NAME "freerdp-core") set(MODULE_PREFIX "FREERDP_CORE") -add_definitions(-DEXT_PATH="${FREERDP_EXTENSION_PATH}") +freerdp_definition_add(-DEXT_PATH="${FREERDP_EXTENSION_PATH}") -include_directories(${OPENSSL_INCLUDE_DIR}) -include_directories(${ZLIB_INCLUDE_DIRS}) +freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR}) +freerdp_include_directory_add(${ZLIB_INCLUDE_DIRS}) set(${MODULE_PREFIX}_GATEWAY_DIR "gateway") @@ -79,6 +79,7 @@ set(${MODULE_PREFIX}_SRCS client.h server.c server.h + codecs.c metrics.c capabilities.c capabilities.h @@ -125,38 +126,13 @@ set(${MODULE_PREFIX}_SRCS set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_GATEWAY_SRCS}) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") +freerdp_module_add(${${MODULE_PREFIX}_SRCS}) if(WIN32) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) + freerdp_library_add(ws2_32) else() - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ZLIB_LIBRARIES}) + freerdp_library_add(${ZLIB_LIBRARIES}) endif() -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSSL_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-crypto freerdp-codec freerdp-locale freerdp-common freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-wtsapi winpr-handle winpr-winsock winpr-crt) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - - +freerdp_library_add(${OPENSSL_LIBRARIES}) diff --git a/libfreerdp/core/autodetect.c b/libfreerdp/core/autodetect.c index 4518b763a..45e7d284b 100644 --- a/libfreerdp/core/autodetect.c +++ b/libfreerdp/core/autodetect.c @@ -41,10 +41,10 @@ static BOOL autodetect_send_rtt_measure_response(rdpRdp* rdp, UINT16 sequenceNum s = rdp_message_channel_pdu_init(rdp); - if (s == NULL) + if (!s) return FALSE; - DEBUG_AUTODETECT("sending RTT Measure Response PDU"); + WLog_DBG(AUTODETECT_TAG, "sending RTT Measure Response PDU"); Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */ Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ @@ -56,8 +56,8 @@ static BOOL autodetect_send_rtt_measure_response(rdpRdp* rdp, UINT16 sequenceNum static BOOL autodetect_send_bandwidth_measure_results(rdpRdp* rdp, UINT16 responseType, UINT16 sequenceNumber) { - UINT32 timeDelta; wStream* s; + UINT32 timeDelta; /* Compute the total time */ timeDelta = GetTickCount() - rdp->autodetect->bandwidthMeasureStartTime; @@ -66,10 +66,10 @@ static BOOL autodetect_send_bandwidth_measure_results(rdpRdp* rdp, UINT16 respon s = rdp_message_channel_pdu_init(rdp); - if (s == NULL) + if (!s) return FALSE; - DEBUG_AUTODETECT("sending Bandwidth Measure Results PDU -> timeDelta=%u, byteCount=%u", timeDelta, rdp->autodetect->bandwidthMeasureByteCount); + WLog_DBG(AUTODETECT_TAG, "sending Bandwidth Measure Results PDU -> timeDelta=%u, byteCount=%u", timeDelta, rdp->autodetect->bandwidthMeasureByteCount); Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ @@ -89,10 +89,10 @@ BOOL autodetect_send_netchar_sync(rdpRdp* rdp, UINT16 sequenceNumber) s = rdp_message_channel_pdu_init(rdp); - if (s == NULL) + if (!s) return FALSE; - DEBUG_AUTODETECT("sending Network Characteristics Sync PDU -> bandwidth=%u, rtt=%u", rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT); + WLog_DBG(AUTODETECT_TAG, "sending Network Characteristics Sync PDU -> bandwidth=%u, rtt=%u", rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT); Stream_Write_UINT8(s, 0x0E); /* headerLength (1 byte) */ Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */ @@ -109,7 +109,7 @@ static BOOL autodetect_recv_rtt_measure_request(rdpRdp* rdp, wStream* s, AUTODET if (autodetectReqPdu->headerLength != 0x06) return FALSE; - DEBUG_AUTODETECT("received RTT Measure Request PDU"); + WLog_DBG(AUTODETECT_TAG, "received RTT Measure Request PDU"); /* Send a response to the server */ return autodetect_send_rtt_measure_response(rdp, autodetectReqPdu->sequenceNumber); @@ -120,7 +120,7 @@ static BOOL autodetect_recv_bandwidth_measure_start(rdpRdp* rdp, wStream* s, AUT if (autodetectReqPdu->headerLength != 0x06) return FALSE; - DEBUG_AUTODETECT("received Bandwidth Measure Start PDU - time=%lu", GetTickCount()); + WLog_DBG(AUTODETECT_TAG, "received Bandwidth Measure Start PDU - time=%lu", GetTickCount()); /* Initialize bandwidth measurement parameters */ rdp->autodetect->bandwidthMeasureStartTime = GetTickCount(); @@ -141,7 +141,7 @@ static BOOL autodetect_recv_bandwidth_measure_payload(rdpRdp* rdp, wStream* s, A Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */ - DEBUG_AUTODETECT("received Bandwidth Measure Payload PDU -> payloadLength=%u", payloadLength); + WLog_DBG(AUTODETECT_TAG, "received Bandwidth Measure Payload PDU -> payloadLength=%u", payloadLength); /* Add the payload length to the bandwidth measurement parameters */ rdp->autodetect->bandwidthMeasureByteCount += payloadLength; @@ -172,7 +172,7 @@ static BOOL autodetect_recv_bandwidth_measure_stop(rdpRdp* rdp, wStream* s, AUTO payloadLength = 0; } - DEBUG_AUTODETECT("received Bandwidth Measure Stop PDU -> payloadLength=%u", payloadLength); + WLog_DBG(AUTODETECT_TAG, "received Bandwidth Measure Stop PDU -> payloadLength=%u", payloadLength); /* Add the payload length to the bandwidth measurement parameters */ rdp->autodetect->bandwidthMeasureByteCount += payloadLength; @@ -213,7 +213,7 @@ static BOOL autodetect_recv_netchar_result(rdpRdp* rdp, wStream* s, AUTODETECT_R break; } - DEBUG_AUTODETECT("received Network Characteristics Result PDU -> baseRTT=%u, bandwidth=%u, averageRTT=%u", rdp->autodetect->netCharBaseRTT, rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT); + WLog_DBG(AUTODETECT_TAG, "received Network Characteristics Result PDU -> baseRTT=%u, bandwidth=%u, averageRTT=%u", rdp->autodetect->netCharBaseRTT, rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT); return TRUE; } @@ -231,7 +231,7 @@ int rdp_recv_autodetect_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */ Stream_Read_UINT16(s, autodetectReqPdu.requestType); /* requestType (2 bytes) */ - DEBUG_AUTODETECT( + WLog_DBG(AUTODETECT_TAG, "rdp_recv_autodetect_packet: headerLength=%u, headerTypeId=%u, sequenceNumber=%u, requestType=%04x", autodetectReqPdu.headerLength, autodetectReqPdu.headerTypeId, autodetectReqPdu.sequenceNumber, autodetectReqPdu.requestType); @@ -282,11 +282,11 @@ int rdp_recv_autodetect_packet(rdpRdp* rdp, wStream* s) rdpAutoDetect* autodetect_new(void) { - rdpAutoDetect* autoDetect = (rdpAutoDetect*) malloc(sizeof(rdpAutoDetect)); + rdpAutoDetect* autoDetect = (rdpAutoDetect*) calloc(1, sizeof(rdpAutoDetect)); if (autoDetect) { - ZeroMemory(autoDetect, sizeof(rdpAutoDetect)); + } return autoDetect; diff --git a/libfreerdp/core/autodetect.h b/libfreerdp/core/autodetect.h index b5823c122..157f7ed11 100644 --- a/libfreerdp/core/autodetect.h +++ b/libfreerdp/core/autodetect.h @@ -25,6 +25,7 @@ typedef struct rdp_autodetect rdpAutoDetect; #include "rdp.h" #include +#include #include #include @@ -49,10 +50,6 @@ int rdp_recv_autodetect_packet(rdpRdp* rdp, wStream* s); rdpAutoDetect* autodetect_new(void); void autodetect_free(rdpAutoDetect* autodetect); -#ifdef WITH_DEBUG_AUTODETECT -#define DEBUG_AUTODETECT(fmt, ...) DEBUG_CLASS(AUTODETECT, fmt, ## __VA_ARGS__) -#else -#define DEBUG_AUTODETECT(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) -#endif +#define AUTODETECT_TAG FREERDP_TAG("core.autodetect") #endif /* __AUTODETECT_H */ diff --git a/libfreerdp/core/bulk.c b/libfreerdp/core/bulk.c index c79fbc4d9..0974d7cf6 100644 --- a/libfreerdp/core/bulk.c +++ b/libfreerdp/core/bulk.c @@ -23,6 +23,8 @@ #include "bulk.h" +#define TAG "com.freerdp.core" + //#define WITH_BULK_DEBUG 1 const char* bulk_get_compression_flags_string(UINT32 flags) @@ -52,19 +54,15 @@ const char* bulk_get_compression_flags_string(UINT32 flags) UINT32 bulk_compression_level(rdpBulk* bulk) { rdpSettings* settings = bulk->context->settings; - bulk->CompressionLevel = (settings->CompressionLevel >= PACKET_COMPR_TYPE_RDP61) ? - PACKET_COMPR_TYPE_RDP61 : settings->CompressionLevel; - + PACKET_COMPR_TYPE_RDP61 : settings->CompressionLevel; return bulk->CompressionLevel; } UINT32 bulk_compression_max_size(rdpBulk* bulk) { bulk_compression_level(bulk); - bulk->CompressionMaxSize = (bulk->CompressionLevel < PACKET_COMPR_TYPE_64K) ? 8192 : 65536; - return bulk->CompressionMaxSize; } @@ -76,37 +74,32 @@ int bulk_compress_validate(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** UINT32 _SrcSize = 0; UINT32 _DstSize = 0; UINT32 _Flags = 0; - _pSrcData = *ppDstData; _SrcSize = *pDstSize; _Flags = *pFlags | bulk->CompressionLevel; - status = bulk_decompress(bulk, _pSrcData, _SrcSize, &_pDstData, &_DstSize, _Flags); if (status < 0) { - printf("compression/decompression failure\n"); + WLog_DBG(TAG, "compression/decompression failure"); return status; } if (_DstSize != SrcSize) { - printf("compression/decompression size mismatch: Actual: %d, Expected: %d\n", _DstSize, SrcSize); + WLog_DBG(TAG, "compression/decompression size mismatch: Actual: %d, Expected: %d", _DstSize, SrcSize); return -1; } if (memcmp(_pDstData, pSrcData, SrcSize) != 0) { - printf("compression/decompression input/output mismatch! flags: 0x%04X\n", _Flags); - + WLog_DBG(TAG, "compression/decompression input/output mismatch! flags: 0x%04X", _Flags); #if 1 - printf("Actual:\n"); - winpr_HexDump(_pDstData, SrcSize); - - printf("Expected:\n"); - winpr_HexDump(pSrcData, SrcSize); + WLog_DBG(TAG, "Actual:"); + winpr_HexDump(TAG, WLOG_DEBUG, _pDstData, SrcSize); + WLog_DBG(TAG, "Expected:"); + winpr_HexDump(TAG, WLOG_DEBUG, pSrcData, SrcSize); #endif - return -1; } @@ -121,9 +114,7 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD UINT32 CompressedBytes; UINT32 UncompressedBytes; double CompressionRatio; - metrics = bulk->context->metrics; - bulk_compression_max_size(bulk); type = flags & BULK_COMPRESSION_TYPE_MASK; @@ -165,22 +156,20 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD { CompressedBytes = SrcSize; UncompressedBytes = *pDstSize; - CompressionRatio = metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes); - #ifdef WITH_BULK_DEBUG { - printf("Decompress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)\n", - type, bulk_get_compression_flags_string(flags), flags, - CompressionRatio, CompressedBytes, UncompressedBytes, - metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes, - (UINT32) metrics->TotalUncompressedBytes); + WLog_DBG(TAG, "Decompress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)", + type, bulk_get_compression_flags_string(flags), flags, + CompressionRatio, CompressedBytes, UncompressedBytes, + metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes, + (UINT32) metrics->TotalUncompressedBytes); } #endif } else { - fprintf(stderr, "Decompression failure!\n"); + WLog_ERR(TAG, "Decompression failure!"); } return status; @@ -193,7 +182,6 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat UINT32 CompressedBytes; UINT32 UncompressedBytes; double CompressionRatio; - metrics = bulk->context->metrics; if ((SrcSize <= 50) || (SrcSize >= 16384)) @@ -205,10 +193,9 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat *ppDstData = bulk->OutputBuffer; *pDstSize = sizeof(bulk->OutputBuffer); - bulk_compression_level(bulk); bulk_compression_max_size(bulk); - + if ((bulk->CompressionLevel == PACKET_COMPR_TYPE_8K) || (bulk->CompressionLevel == PACKET_COMPR_TYPE_64K)) { @@ -232,25 +219,24 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat { CompressedBytes = *pDstSize; UncompressedBytes = SrcSize; - CompressionRatio = metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes); - #ifdef WITH_BULK_DEBUG { - printf("Compress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)\n", - bulk->CompressionLevel, bulk_get_compression_flags_string(*pFlags), *pFlags, - CompressionRatio, CompressedBytes, UncompressedBytes, - metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes, - (UINT32) metrics->TotalUncompressedBytes); + WLog_DBG(TAG, "Compress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)", + bulk->CompressionLevel, bulk_get_compression_flags_string(*pFlags), *pFlags, + CompressionRatio, CompressedBytes, UncompressedBytes, + metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes, + (UINT32) metrics->TotalUncompressedBytes); } #endif } #if 0 + if (bulk_compress_validate(bulk, pSrcData, SrcSize, ppDstData, pDstSize, pFlags) < 0) status = -1; -#endif +#endif return status; } @@ -258,10 +244,8 @@ void bulk_reset(rdpBulk* bulk) { mppc_context_reset(bulk->mppcSend, FALSE); mppc_context_reset(bulk->mppcRecv, FALSE); - ncrush_context_reset(bulk->ncrushRecv, FALSE); ncrush_context_reset(bulk->ncrushSend, FALSE); - xcrush_context_reset(bulk->xcrushRecv, FALSE); xcrush_context_reset(bulk->xcrushSend, FALSE); } @@ -269,22 +253,17 @@ void bulk_reset(rdpBulk* bulk) rdpBulk* bulk_new(rdpContext* context) { rdpBulk* bulk; - bulk = (rdpBulk*) calloc(1, sizeof(rdpBulk)); if (bulk) { bulk->context = context; - bulk->mppcSend = mppc_context_new(1, TRUE); bulk->mppcRecv = mppc_context_new(1, FALSE); - bulk->ncrushRecv = ncrush_context_new(FALSE); bulk->ncrushSend = ncrush_context_new(TRUE); - bulk->xcrushRecv = xcrush_context_new(FALSE); bulk->xcrushSend = xcrush_context_new(TRUE); - bulk->CompressionLevel = context->settings->CompressionLevel; } @@ -298,12 +277,9 @@ void bulk_free(rdpBulk* bulk) mppc_context_free(bulk->mppcSend); mppc_context_free(bulk->mppcRecv); - ncrush_context_free(bulk->ncrushRecv); ncrush_context_free(bulk->ncrushSend); - xcrush_context_free(bulk->xcrushRecv); xcrush_context_free(bulk->xcrushSend); - free(bulk); } diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 588434b96..85c6b8b5d 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -22,10 +22,15 @@ #endif #include "capabilities.h" +#include "fastpath.h" #include #include +#include + +#define TAG FREERDP_TAG("core.capabilities") + #ifdef WITH_DEBUG_CAPABILITIES const char* const CAPSET_TYPE_STRINGS[] = @@ -264,8 +269,7 @@ BOOL rdp_print_general_capability_set(wStream* s, UINT16 length) if (length < 24) return FALSE; - fprintf(stderr, "GeneralCapabilitySet (length %d):\n", length); - + WLog_INFO(TAG, "GeneralCapabilitySet (length %d):", length); Stream_Read_UINT16(s, osMajorType); /* osMajorType (2 bytes) */ Stream_Read_UINT16(s, osMinorType); /* osMinorType (2 bytes) */ Stream_Read_UINT16(s, protocolVersion); /* protocolVersion (2 bytes) */ @@ -277,19 +281,17 @@ BOOL rdp_print_general_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, generalCompressionLevel); /* generalCompressionLevel (2 bytes) */ Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ - - fprintf(stderr, "\tosMajorType: 0x%04X\n", osMajorType); - fprintf(stderr, "\tosMinorType: 0x%04X\n", osMinorType); - fprintf(stderr, "\tprotocolVersion: 0x%04X\n", protocolVersion); - fprintf(stderr, "\tpad2OctetsA: 0x%04X\n", pad2OctetsA); - fprintf(stderr, "\tgeneralCompressionTypes: 0x%04X\n", generalCompressionTypes); - fprintf(stderr, "\textraFlags: 0x%04X\n", extraFlags); - fprintf(stderr, "\tupdateCapabilityFlag: 0x%04X\n", updateCapabilityFlag); - fprintf(stderr, "\tremoteUnshareFlag: 0x%04X\n", remoteUnshareFlag); - fprintf(stderr, "\tgeneralCompressionLevel: 0x%04X\n", generalCompressionLevel); - fprintf(stderr, "\trefreshRectSupport: 0x%02X\n", refreshRectSupport); - fprintf(stderr, "\tsuppressOutputSupport: 0x%02X\n", suppressOutputSupport); - + WLog_INFO(TAG, "\tosMajorType: 0x%04X", osMajorType); + WLog_INFO(TAG, "\tosMinorType: 0x%04X", osMinorType); + WLog_INFO(TAG, "\tprotocolVersion: 0x%04X", protocolVersion); + WLog_INFO(TAG, "\tpad2OctetsA: 0x%04X", pad2OctetsA); + WLog_INFO(TAG, "\tgeneralCompressionTypes: 0x%04X", generalCompressionTypes); + WLog_INFO(TAG, "\textraFlags: 0x%04X", extraFlags); + WLog_INFO(TAG, "\tupdateCapabilityFlag: 0x%04X", updateCapabilityFlag); + WLog_INFO(TAG, "\tremoteUnshareFlag: 0x%04X", remoteUnshareFlag); + WLog_INFO(TAG, "\tgeneralCompressionLevel: 0x%04X", generalCompressionLevel); + WLog_INFO(TAG, "\trefreshRectSupport: 0x%02X", refreshRectSupport); + WLog_INFO(TAG, "\tsuppressOutputSupport: 0x%02X", suppressOutputSupport); return TRUE; } @@ -342,7 +344,14 @@ BOOL rdp_read_bitmap_capability_set(wStream* s, UINT16 length, rdpSettings* sett settings->DesktopHeight = desktopHeight; } - settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) ? TRUE : FALSE; + if (settings->DrawAllowSkipAlpha) + settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) ? TRUE : FALSE; + + if (settings->DrawAllowDynamicColorFidelity) + settings->DrawAllowDynamicColorFidelity = (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) ? TRUE : FALSE; + + if (settings->DrawAllowColorSubsampling) + settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) ? TRUE : FALSE; return TRUE; } @@ -365,8 +374,23 @@ void rdp_write_bitmap_capability_set(wStream* s, rdpSettings* settings) header = rdp_capability_set_start(s); - drawingFlags |= DRAW_ALLOW_SKIP_ALPHA; - drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; + if (settings->DrawAllowSkipAlpha) + drawingFlags |= DRAW_ALLOW_SKIP_ALPHA; + + if (settings->DrawAllowDynamicColorFidelity) + drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY; + + if (settings->DrawAllowColorSubsampling) + drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; /* currently unimplemented */ + + /* While bitmap_decode.c now implements YCoCg, in turning it + * on we have found Microsoft is inconsistent on whether to invert R & B. + * And it's not only from one server to another; on Win7/2008R2, it appears + * to send the main content with a different inversion than the Windows + * button! So... don't advertise that we support YCoCg and the server + * will not send it. YCoCg is still needed for EGFX, but it at least + * appears consistent in its use. + */ if (settings->RdpVersion > 5) preferredBitsPerPixel = settings->ColorDepth; @@ -407,8 +431,7 @@ BOOL rdp_print_bitmap_capability_set(wStream* s, UINT16 length) BYTE drawingFlags; UINT16 multipleRectangleSupport; UINT16 pad2OctetsB; - - fprintf(stderr, "BitmapCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCapabilitySet (length %d):", length); if (length < 28) return FALSE; @@ -426,21 +449,19 @@ BOOL rdp_print_bitmap_capability_set(wStream* s, UINT16 length) Stream_Read_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */ Stream_Read_UINT16(s, multipleRectangleSupport); /* multipleRectangleSupport (2 bytes) */ Stream_Read_UINT16(s, pad2OctetsB); /* pad2OctetsB (2 bytes) */ - - fprintf(stderr, "\tpreferredBitsPerPixel: 0x%04X\n", preferredBitsPerPixel); - fprintf(stderr, "\treceive1BitPerPixel: 0x%04X\n", receive1BitPerPixel); - fprintf(stderr, "\treceive4BitsPerPixel: 0x%04X\n", receive4BitsPerPixel); - fprintf(stderr, "\treceive8BitsPerPixel: 0x%04X\n", receive8BitsPerPixel); - fprintf(stderr, "\tdesktopWidth: 0x%04X\n", desktopWidth); - fprintf(stderr, "\tdesktopHeight: 0x%04X\n", desktopHeight); - fprintf(stderr, "\tpad2Octets: 0x%04X\n", pad2Octets); - fprintf(stderr, "\tdesktopResizeFlag: 0x%04X\n", desktopResizeFlag); - fprintf(stderr, "\tbitmapCompressionFlag: 0x%04X\n", bitmapCompressionFlag); - fprintf(stderr, "\thighColorFlags: 0x%02X\n", highColorFlags); - fprintf(stderr, "\tdrawingFlags: 0x%02X\n", drawingFlags); - fprintf(stderr, "\tmultipleRectangleSupport: 0x%04X\n", multipleRectangleSupport); - fprintf(stderr, "\tpad2OctetsB: 0x%04X\n", pad2OctetsB); - + WLog_INFO(TAG, "\tpreferredBitsPerPixel: 0x%04X", preferredBitsPerPixel); + WLog_INFO(TAG, "\treceive1BitPerPixel: 0x%04X", receive1BitPerPixel); + WLog_INFO(TAG, "\treceive4BitsPerPixel: 0x%04X", receive4BitsPerPixel); + WLog_INFO(TAG, "\treceive8BitsPerPixel: 0x%04X", receive8BitsPerPixel); + WLog_INFO(TAG, "\tdesktopWidth: 0x%04X", desktopWidth); + WLog_INFO(TAG, "\tdesktopHeight: 0x%04X", desktopHeight); + WLog_INFO(TAG, "\tpad2Octets: 0x%04X", pad2Octets); + WLog_INFO(TAG, "\tdesktopResizeFlag: 0x%04X", desktopResizeFlag); + WLog_INFO(TAG, "\tbitmapCompressionFlag: 0x%04X", bitmapCompressionFlag); + WLog_INFO(TAG, "\thighColorFlags: 0x%02X", highColorFlags); + WLog_INFO(TAG, "\tdrawingFlags: 0x%02X", drawingFlags); + WLog_INFO(TAG, "\tmultipleRectangleSupport: 0x%04X", multipleRectangleSupport); + WLog_INFO(TAG, "\tpad2OctetsB: 0x%04X", pad2OctetsB); return TRUE; } @@ -584,8 +605,7 @@ BOOL rdp_print_order_capability_set(wStream* s, UINT16 length) UINT16 pad2OctetsD; UINT16 textANSICodePage; UINT16 pad2OctetsE; - - fprintf(stderr, "OrderCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "OrderCapabilitySet (length %d):", length); if (length < 88) return FALSE; @@ -607,58 +627,54 @@ BOOL rdp_print_order_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, pad2OctetsD); /* pad2OctetsD (2 bytes) */ Stream_Read_UINT16(s, textANSICodePage); /* textANSICodePage (2 bytes) */ Stream_Read_UINT16(s, pad2OctetsE); /* pad2OctetsE (2 bytes) */ - - fprintf(stderr, "\tpad4OctetsA: 0x%08X\n", pad4OctetsA); - fprintf(stderr, "\tdesktopSaveXGranularity: 0x%04X\n", desktopSaveXGranularity); - fprintf(stderr, "\tdesktopSaveYGranularity: 0x%04X\n", desktopSaveYGranularity); - fprintf(stderr, "\tpad2OctetsA: 0x%04X\n", pad2OctetsA); - fprintf(stderr, "\tmaximumOrderLevel: 0x%04X\n", maximumOrderLevel); - fprintf(stderr, "\tnumberFonts: 0x%04X\n", numberFonts); - fprintf(stderr, "\torderFlags: 0x%04X\n", orderFlags); - - fprintf(stderr, "\torderSupport:\n"); - fprintf(stderr, "\t\tDSTBLT: %d\n", orderSupport[NEG_DSTBLT_INDEX]); - fprintf(stderr, "\t\tPATBLT: %d\n", orderSupport[NEG_PATBLT_INDEX]); - fprintf(stderr, "\t\tSCRBLT: %d\n", orderSupport[NEG_SCRBLT_INDEX]); - fprintf(stderr, "\t\tMEMBLT: %d\n", orderSupport[NEG_MEMBLT_INDEX]); - fprintf(stderr, "\t\tMEM3BLT: %d\n", orderSupport[NEG_MEM3BLT_INDEX]); - fprintf(stderr, "\t\tATEXTOUT: %d\n", orderSupport[NEG_ATEXTOUT_INDEX]); - fprintf(stderr, "\t\tAEXTTEXTOUT: %d\n", orderSupport[NEG_AEXTTEXTOUT_INDEX]); - fprintf(stderr, "\t\tDRAWNINEGRID: %d\n", orderSupport[NEG_DRAWNINEGRID_INDEX]); - fprintf(stderr, "\t\tLINETO: %d\n", orderSupport[NEG_LINETO_INDEX]); - fprintf(stderr, "\t\tMULTI_DRAWNINEGRID: %d\n", orderSupport[NEG_MULTI_DRAWNINEGRID_INDEX]); - fprintf(stderr, "\t\tOPAQUE_RECT: %d\n", orderSupport[NEG_OPAQUE_RECT_INDEX]); - fprintf(stderr, "\t\tSAVEBITMAP: %d\n", orderSupport[NEG_SAVEBITMAP_INDEX]); - fprintf(stderr, "\t\tWTEXTOUT: %d\n", orderSupport[NEG_WTEXTOUT_INDEX]); - fprintf(stderr, "\t\tMEMBLT_V2: %d\n", orderSupport[NEG_MEMBLT_V2_INDEX]); - fprintf(stderr, "\t\tMEM3BLT_V2: %d\n", orderSupport[NEG_MEM3BLT_V2_INDEX]); - fprintf(stderr, "\t\tMULTIDSTBLT: %d\n", orderSupport[NEG_MULTIDSTBLT_INDEX]); - fprintf(stderr, "\t\tMULTIPATBLT: %d\n", orderSupport[NEG_MULTIPATBLT_INDEX]); - fprintf(stderr, "\t\tMULTISCRBLT: %d\n", orderSupport[NEG_MULTISCRBLT_INDEX]); - fprintf(stderr, "\t\tMULTIOPAQUERECT: %d\n", orderSupport[NEG_MULTIOPAQUERECT_INDEX]); - fprintf(stderr, "\t\tFAST_INDEX: %d\n", orderSupport[NEG_FAST_INDEX_INDEX]); - fprintf(stderr, "\t\tPOLYGON_SC: %d\n", orderSupport[NEG_POLYGON_SC_INDEX]); - fprintf(stderr, "\t\tPOLYGON_CB: %d\n", orderSupport[NEG_POLYGON_CB_INDEX]); - fprintf(stderr, "\t\tPOLYLINE: %d\n", orderSupport[NEG_POLYLINE_INDEX]); - fprintf(stderr, "\t\tUNUSED23: %d\n", orderSupport[NEG_UNUSED23_INDEX]); - fprintf(stderr, "\t\tFAST_GLYPH: %d\n", orderSupport[NEG_FAST_GLYPH_INDEX]); - fprintf(stderr, "\t\tELLIPSE_SC: %d\n", orderSupport[NEG_ELLIPSE_SC_INDEX]); - fprintf(stderr, "\t\tELLIPSE_CB: %d\n", orderSupport[NEG_ELLIPSE_CB_INDEX]); - fprintf(stderr, "\t\tGLYPH_INDEX: %d\n", orderSupport[NEG_GLYPH_INDEX_INDEX]); - fprintf(stderr, "\t\tGLYPH_WEXTTEXTOUT: %d\n", orderSupport[NEG_GLYPH_WEXTTEXTOUT_INDEX]); - fprintf(stderr, "\t\tGLYPH_WLONGTEXTOUT: %d\n", orderSupport[NEG_GLYPH_WLONGTEXTOUT_INDEX]); - fprintf(stderr, "\t\tGLYPH_WLONGEXTTEXTOUT: %d\n", orderSupport[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX]); - fprintf(stderr, "\t\tUNUSED31: %d\n", orderSupport[NEG_UNUSED31_INDEX]); - - fprintf(stderr, "\ttextFlags: 0x%04X\n", textFlags); - fprintf(stderr, "\torderSupportExFlags: 0x%04X\n", orderSupportExFlags); - fprintf(stderr, "\tpad4OctetsB: 0x%08X\n", pad4OctetsB); - fprintf(stderr, "\tdesktopSaveSize: 0x%08X\n", desktopSaveSize); - fprintf(stderr, "\tpad2OctetsC: 0x%04X\n", pad2OctetsC); - fprintf(stderr, "\tpad2OctetsD: 0x%04X\n", pad2OctetsD); - fprintf(stderr, "\ttextANSICodePage: 0x%04X\n", textANSICodePage); - fprintf(stderr, "\tpad2OctetsE: 0x%04X\n", pad2OctetsE); - + WLog_INFO(TAG, "\tpad4OctetsA: 0x%08X", pad4OctetsA); + WLog_INFO(TAG, "\tdesktopSaveXGranularity: 0x%04X", desktopSaveXGranularity); + WLog_INFO(TAG, "\tdesktopSaveYGranularity: 0x%04X", desktopSaveYGranularity); + WLog_INFO(TAG, "\tpad2OctetsA: 0x%04X", pad2OctetsA); + WLog_INFO(TAG, "\tmaximumOrderLevel: 0x%04X", maximumOrderLevel); + WLog_INFO(TAG, "\tnumberFonts: 0x%04X", numberFonts); + WLog_INFO(TAG, "\torderFlags: 0x%04X", orderFlags); + WLog_INFO(TAG, "\torderSupport:"); + WLog_INFO(TAG, "\t\tDSTBLT: %d", orderSupport[NEG_DSTBLT_INDEX]); + WLog_INFO(TAG, "\t\tPATBLT: %d", orderSupport[NEG_PATBLT_INDEX]); + WLog_INFO(TAG, "\t\tSCRBLT: %d", orderSupport[NEG_SCRBLT_INDEX]); + WLog_INFO(TAG, "\t\tMEMBLT: %d", orderSupport[NEG_MEMBLT_INDEX]); + WLog_INFO(TAG, "\t\tMEM3BLT: %d", orderSupport[NEG_MEM3BLT_INDEX]); + WLog_INFO(TAG, "\t\tATEXTOUT: %d", orderSupport[NEG_ATEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tAEXTTEXTOUT: %d", orderSupport[NEG_AEXTTEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tDRAWNINEGRID: %d", orderSupport[NEG_DRAWNINEGRID_INDEX]); + WLog_INFO(TAG, "\t\tLINETO: %d", orderSupport[NEG_LINETO_INDEX]); + WLog_INFO(TAG, "\t\tMULTI_DRAWNINEGRID: %d", orderSupport[NEG_MULTI_DRAWNINEGRID_INDEX]); + WLog_INFO(TAG, "\t\tOPAQUE_RECT: %d", orderSupport[NEG_OPAQUE_RECT_INDEX]); + WLog_INFO(TAG, "\t\tSAVEBITMAP: %d", orderSupport[NEG_SAVEBITMAP_INDEX]); + WLog_INFO(TAG, "\t\tWTEXTOUT: %d", orderSupport[NEG_WTEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tMEMBLT_V2: %d", orderSupport[NEG_MEMBLT_V2_INDEX]); + WLog_INFO(TAG, "\t\tMEM3BLT_V2: %d", orderSupport[NEG_MEM3BLT_V2_INDEX]); + WLog_INFO(TAG, "\t\tMULTIDSTBLT: %d", orderSupport[NEG_MULTIDSTBLT_INDEX]); + WLog_INFO(TAG, "\t\tMULTIPATBLT: %d", orderSupport[NEG_MULTIPATBLT_INDEX]); + WLog_INFO(TAG, "\t\tMULTISCRBLT: %d", orderSupport[NEG_MULTISCRBLT_INDEX]); + WLog_INFO(TAG, "\t\tMULTIOPAQUERECT: %d", orderSupport[NEG_MULTIOPAQUERECT_INDEX]); + WLog_INFO(TAG, "\t\tFAST_INDEX: %d", orderSupport[NEG_FAST_INDEX_INDEX]); + WLog_INFO(TAG, "\t\tPOLYGON_SC: %d", orderSupport[NEG_POLYGON_SC_INDEX]); + WLog_INFO(TAG, "\t\tPOLYGON_CB: %d", orderSupport[NEG_POLYGON_CB_INDEX]); + WLog_INFO(TAG, "\t\tPOLYLINE: %d", orderSupport[NEG_POLYLINE_INDEX]); + WLog_INFO(TAG, "\t\tUNUSED23: %d", orderSupport[NEG_UNUSED23_INDEX]); + WLog_INFO(TAG, "\t\tFAST_GLYPH: %d", orderSupport[NEG_FAST_GLYPH_INDEX]); + WLog_INFO(TAG, "\t\tELLIPSE_SC: %d", orderSupport[NEG_ELLIPSE_SC_INDEX]); + WLog_INFO(TAG, "\t\tELLIPSE_CB: %d", orderSupport[NEG_ELLIPSE_CB_INDEX]); + WLog_INFO(TAG, "\t\tGLYPH_INDEX: %d", orderSupport[NEG_GLYPH_INDEX_INDEX]); + WLog_INFO(TAG, "\t\tGLYPH_WEXTTEXTOUT: %d", orderSupport[NEG_GLYPH_WEXTTEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tGLYPH_WLONGTEXTOUT: %d", orderSupport[NEG_GLYPH_WLONGTEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tGLYPH_WLONGEXTTEXTOUT: %d", orderSupport[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX]); + WLog_INFO(TAG, "\t\tUNUSED31: %d", orderSupport[NEG_UNUSED31_INDEX]); + WLog_INFO(TAG, "\ttextFlags: 0x%04X", textFlags); + WLog_INFO(TAG, "\torderSupportExFlags: 0x%04X", orderSupportExFlags); + WLog_INFO(TAG, "\tpad4OctetsB: 0x%08X", pad4OctetsB); + WLog_INFO(TAG, "\tdesktopSaveSize: 0x%08X", desktopSaveSize); + WLog_INFO(TAG, "\tpad2OctetsC: 0x%04X", pad2OctetsC); + WLog_INFO(TAG, "\tpad2OctetsD: 0x%04X", pad2OctetsD); + WLog_INFO(TAG, "\ttextANSICodePage: 0x%04X", textANSICodePage); + WLog_INFO(TAG, "\tpad2OctetsE: 0x%04X", pad2OctetsE); return TRUE; } @@ -742,8 +758,7 @@ BOOL rdp_print_bitmap_cache_capability_set(wStream* s, UINT16 length) UINT16 Cache1MaximumCellSize; UINT16 Cache2Entries; UINT16 Cache2MaximumCellSize; - - fprintf(stderr, "BitmapCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCacheCapabilitySet (length %d):", length); if (length < 40) return FALSE; @@ -760,20 +775,18 @@ BOOL rdp_print_bitmap_cache_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, Cache1MaximumCellSize); /* Cache1MaximumCellSize (2 bytes) */ Stream_Read_UINT16(s, Cache2Entries); /* Cache2Entries (2 bytes) */ Stream_Read_UINT16(s, Cache2MaximumCellSize); /* Cache2MaximumCellSize (2 bytes) */ - - fprintf(stderr, "\tpad1: 0x%08X\n", pad1); - fprintf(stderr, "\tpad2: 0x%08X\n", pad2); - fprintf(stderr, "\tpad3: 0x%08X\n", pad3); - fprintf(stderr, "\tpad4: 0x%08X\n", pad4); - fprintf(stderr, "\tpad5: 0x%08X\n", pad5); - fprintf(stderr, "\tpad6: 0x%08X\n", pad6); - fprintf(stderr, "\tCache0Entries: 0x%04X\n", Cache0Entries); - fprintf(stderr, "\tCache0MaximumCellSize: 0x%04X\n", Cache0MaximumCellSize); - fprintf(stderr, "\tCache1Entries: 0x%04X\n", Cache1Entries); - fprintf(stderr, "\tCache1MaximumCellSize: 0x%04X\n", Cache1MaximumCellSize); - fprintf(stderr, "\tCache2Entries: 0x%04X\n", Cache2Entries); - fprintf(stderr, "\tCache2MaximumCellSize: 0x%04X\n", Cache2MaximumCellSize); - + WLog_INFO(TAG, "\tpad1: 0x%08X", pad1); + WLog_INFO(TAG, "\tpad2: 0x%08X", pad2); + WLog_INFO(TAG, "\tpad3: 0x%08X", pad3); + WLog_INFO(TAG, "\tpad4: 0x%08X", pad4); + WLog_INFO(TAG, "\tpad5: 0x%08X", pad5); + WLog_INFO(TAG, "\tpad6: 0x%08X", pad6); + WLog_INFO(TAG, "\tCache0Entries: 0x%04X", Cache0Entries); + WLog_INFO(TAG, "\tCache0MaximumCellSize: 0x%04X", Cache0MaximumCellSize); + WLog_INFO(TAG, "\tCache1Entries: 0x%04X", Cache1Entries); + WLog_INFO(TAG, "\tCache1MaximumCellSize: 0x%04X", Cache1MaximumCellSize); + WLog_INFO(TAG, "\tCache2Entries: 0x%04X", Cache2Entries); + WLog_INFO(TAG, "\tCache2MaximumCellSize: 0x%04X", Cache2MaximumCellSize); return TRUE; } @@ -827,8 +840,7 @@ BOOL rdp_print_control_capability_set(wStream* s, UINT16 length) UINT16 remoteDetachFlag; UINT16 controlInterest; UINT16 detachInterest; - - fprintf(stderr, "ControlCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "ControlCapabilitySet (length %d):", length); if (length < 12) return FALSE; @@ -837,12 +849,10 @@ BOOL rdp_print_control_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, remoteDetachFlag); /* remoteDetachFlag (2 bytes) */ Stream_Read_UINT16(s, controlInterest); /* controlInterest (2 bytes) */ Stream_Read_UINT16(s, detachInterest); /* detachInterest (2 bytes) */ - - fprintf(stderr, "\tcontrolFlags: 0x%04X\n", controlFlags); - fprintf(stderr, "\tremoteDetachFlag: 0x%04X\n", remoteDetachFlag); - fprintf(stderr, "\tcontrolInterest: 0x%04X\n", controlInterest); - fprintf(stderr, "\tdetachInterest: 0x%04X\n", detachInterest); - + WLog_INFO(TAG, "\tcontrolFlags: 0x%04X", controlFlags); + WLog_INFO(TAG, "\tremoteDetachFlag: 0x%04X", remoteDetachFlag); + WLog_INFO(TAG, "\tcontrolInterest: 0x%04X", controlInterest); + WLog_INFO(TAG, "\tdetachInterest: 0x%04X", detachInterest); return TRUE; } @@ -896,8 +906,7 @@ BOOL rdp_print_window_activation_capability_set(wStream* s, UINT16 length) UINT16 helpKeyIndexFlag; UINT16 helpExtendedKeyFlag; UINT16 windowManagerKeyFlag; - - fprintf(stderr, "WindowActivationCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "WindowActivationCapabilitySet (length %d):", length); if (length < 12) return FALSE; @@ -906,12 +915,10 @@ BOOL rdp_print_window_activation_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, helpKeyIndexFlag); /* helpKeyIndexFlag (2 bytes) */ Stream_Read_UINT16(s, helpExtendedKeyFlag); /* helpExtendedKeyFlag (2 bytes) */ Stream_Read_UINT16(s, windowManagerKeyFlag); /* windowManagerKeyFlag (2 bytes) */ - - fprintf(stderr, "\thelpKeyFlag: 0x%04X\n", helpKeyFlag); - fprintf(stderr, "\thelpKeyIndexFlag: 0x%04X\n", helpKeyIndexFlag); - fprintf(stderr, "\thelpExtendedKeyFlag: 0x%04X\n", helpExtendedKeyFlag); - fprintf(stderr, "\twindowManagerKeyFlag: 0x%04X\n", windowManagerKeyFlag); - + WLog_INFO(TAG, "\thelpKeyFlag: 0x%04X", helpKeyFlag); + WLog_INFO(TAG, "\thelpKeyIndexFlag: 0x%04X", helpKeyIndexFlag); + WLog_INFO(TAG, "\thelpExtendedKeyFlag: 0x%04X", helpExtendedKeyFlag); + WLog_INFO(TAG, "\twindowManagerKeyFlag: 0x%04X", windowManagerKeyFlag); return TRUE; } @@ -984,16 +991,13 @@ BOOL rdp_print_pointer_capability_set(wStream* s, UINT16 length) if (length < 10) return FALSE; - fprintf(stderr, "PointerCapabilitySet (length %d):\n", length); - + WLog_INFO(TAG, "PointerCapabilitySet (length %d):", length); Stream_Read_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */ Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */ Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */ - - fprintf(stderr, "\tcolorPointerFlag: 0x%04X\n", colorPointerFlag); - fprintf(stderr, "\tcolorPointerCacheSize: 0x%04X\n", colorPointerCacheSize); - fprintf(stderr, "\tpointerCacheSize: 0x%04X\n", pointerCacheSize); - + WLog_INFO(TAG, "\tcolorPointerFlag: 0x%04X", colorPointerFlag); + WLog_INFO(TAG, "\tcolorPointerCacheSize: 0x%04X", colorPointerCacheSize); + WLog_INFO(TAG, "\tpointerCacheSize: 0x%04X", pointerCacheSize); return TRUE; } @@ -1044,18 +1048,15 @@ BOOL rdp_print_share_capability_set(wStream* s, UINT16 length) { UINT16 nodeId; UINT16 pad2Octets; - - fprintf(stderr, "ShareCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "ShareCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT16(s, nodeId); /* nodeId (2 bytes) */ Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */ - - fprintf(stderr, "\tnodeId: 0x%04X\n", nodeId); - fprintf(stderr, "\tpad2Octets: 0x%04X\n", pad2Octets); - + WLog_INFO(TAG, "\tnodeId: 0x%04X", nodeId); + WLog_INFO(TAG, "\tpad2Octets: 0x%04X", pad2Octets); return TRUE; } @@ -1103,18 +1104,15 @@ BOOL rdp_print_color_cache_capability_set(wStream* s, UINT16 length) { UINT16 colorTableCacheSize; UINT16 pad2Octets; - - fprintf(stderr, "ColorCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "ColorCacheCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT16(s, colorTableCacheSize); /* colorTableCacheSize (2 bytes) */ Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */ - - fprintf(stderr, "\tcolorTableCacheSize: 0x%04X\n", colorTableCacheSize); - fprintf(stderr, "\tpad2Octets: 0x%04X\n", pad2Octets); - + WLog_INFO(TAG, "\tcolorTableCacheSize: 0x%04X", colorTableCacheSize); + WLog_INFO(TAG, "\tpad2Octets: 0x%04X", pad2Octets); return TRUE; } @@ -1169,18 +1167,15 @@ BOOL rdp_print_sound_capability_set(wStream* s, UINT16 length) { UINT16 soundFlags; UINT16 pad2OctetsA; - - fprintf(stderr, "SoundCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "SoundCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */ Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */ - - fprintf(stderr, "\tsoundFlags: 0x%04X\n", soundFlags); - fprintf(stderr, "\tpad2OctetsA: 0x%04X\n", pad2OctetsA); - + WLog_INFO(TAG, "\tsoundFlags: 0x%04X", soundFlags); + WLog_INFO(TAG, "\tpad2OctetsA: 0x%04X", pad2OctetsA); return TRUE; } @@ -1281,8 +1276,7 @@ BOOL rdp_print_input_capability_set(wStream* s, UINT16 length) UINT32 keyboardType; UINT32 keyboardSubType; UINT32 keyboardFunctionKey; - - fprintf(stderr, "InputCapabilitySet (length %d)\n", length); + WLog_INFO(TAG, "InputCapabilitySet (length %d)", length); if (length < 88) return FALSE; @@ -1294,14 +1288,12 @@ BOOL rdp_print_input_capability_set(wStream* s, UINT16 length) Stream_Read_UINT32(s, keyboardSubType); /* keyboardSubType (4 bytes) */ Stream_Read_UINT32(s, keyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */ Stream_Seek(s, 64); /* imeFileName (64 bytes) */ - - fprintf(stderr, "\tinputFlags: 0x%04X\n", inputFlags); - fprintf(stderr, "\tpad2OctetsA: 0x%04X\n", pad2OctetsA); - fprintf(stderr, "\tkeyboardLayout: 0x%08X\n", keyboardLayout); - fprintf(stderr, "\tkeyboardType: 0x%08X\n", keyboardType); - fprintf(stderr, "\tkeyboardSubType: 0x%08X\n", keyboardSubType); - fprintf(stderr, "\tkeyboardFunctionKey: 0x%08X\n", keyboardFunctionKey); - + WLog_INFO(TAG, "\tinputFlags: 0x%04X", inputFlags); + WLog_INFO(TAG, "\tpad2OctetsA: 0x%04X", pad2OctetsA); + WLog_INFO(TAG, "\tkeyboardLayout: 0x%08X", keyboardLayout); + WLog_INFO(TAG, "\tkeyboardType: 0x%08X", keyboardType); + WLog_INFO(TAG, "\tkeyboardSubType: 0x%08X", keyboardSubType); + WLog_INFO(TAG, "\tkeyboardFunctionKey: 0x%08X", keyboardFunctionKey); return TRUE; } @@ -1349,8 +1341,7 @@ BOOL rdp_print_font_capability_set(wStream* s, UINT16 length) { UINT16 fontSupportFlags = 0; UINT16 pad2Octets = 0; - - fprintf(stderr, "FontCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "FontCapabilitySet (length %d):", length); if (length > 4) Stream_Read_UINT16(s, fontSupportFlags); /* fontSupportFlags (2 bytes) */ @@ -1358,14 +1349,13 @@ BOOL rdp_print_font_capability_set(wStream* s, UINT16 length) if (length > 6) Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */ - fprintf(stderr, "\tfontSupportFlags: 0x%04X\n", fontSupportFlags); - fprintf(stderr, "\tpad2Octets: 0x%04X\n", pad2Octets); - + WLog_INFO(TAG, "\tfontSupportFlags: 0x%04X", fontSupportFlags); + WLog_INFO(TAG, "\tpad2Octets: 0x%04X", pad2Octets); return TRUE; } /** - * Read brush capability set.\n + * Read brush capability set. * @msdn{cc240564} * @param s stream * @param settings settings @@ -1405,16 +1395,13 @@ void rdp_write_brush_capability_set(wStream* s, rdpSettings* settings) BOOL rdp_print_brush_capability_set(wStream* s, UINT16 length) { UINT32 brushSupportLevel; - - fprintf(stderr, "BrushCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BrushCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT32(s, brushSupportLevel); /* brushSupportLevel (4 bytes) */ - - fprintf(stderr, "\tbrushSupportLevel: 0x%08X\n", brushSupportLevel); - + WLog_INFO(TAG, "\tbrushSupportLevel: 0x%08X", brushSupportLevel); return TRUE; } @@ -1514,8 +1501,7 @@ BOOL rdp_print_glyph_cache_capability_set(wStream* s, UINT16 length) GLYPH_CACHE_DEFINITION fragCache; UINT16 glyphSupportLevel; UINT16 pad2Octets; - - fprintf(stderr, "GlyphCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "GlyphCacheCapabilitySet (length %d):", length); if (length < 52) return FALSE; @@ -1535,21 +1521,19 @@ BOOL rdp_print_glyph_cache_capability_set(wStream* s, UINT16 length) Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */ Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */ - - fprintf(stderr, "\tglyphCache0: Entries: %d MaximumCellSize: %d\n", glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache1: Entries: %d MaximumCellSize: %d\n", glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache2: Entries: %d MaximumCellSize: %d\n", glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache3: Entries: %d MaximumCellSize: %d\n", glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache4: Entries: %d MaximumCellSize: %d\n", glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache5: Entries: %d MaximumCellSize: %d\n", glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache6: Entries: %d MaximumCellSize: %d\n", glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache7: Entries: %d MaximumCellSize: %d\n", glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache8: Entries: %d MaximumCellSize: %d\n", glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize); - fprintf(stderr, "\tglyphCache9: Entries: %d MaximumCellSize: %d\n", glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize); - fprintf(stderr, "\tfragCache: Entries: %d MaximumCellSize: %d\n", fragCache.cacheEntries, fragCache.cacheMaximumCellSize); - fprintf(stderr, "\tglyphSupportLevel: 0x%04X\n", glyphSupportLevel); - fprintf(stderr, "\tpad2Octets: 0x%04X\n", pad2Octets); - + WLog_INFO(TAG, "\tglyphCache0: Entries: %d MaximumCellSize: %d", glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache1: Entries: %d MaximumCellSize: %d", glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache2: Entries: %d MaximumCellSize: %d", glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache3: Entries: %d MaximumCellSize: %d", glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache4: Entries: %d MaximumCellSize: %d", glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache5: Entries: %d MaximumCellSize: %d", glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache6: Entries: %d MaximumCellSize: %d", glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache7: Entries: %d MaximumCellSize: %d", glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache8: Entries: %d MaximumCellSize: %d", glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphCache9: Entries: %d MaximumCellSize: %d", glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize); + WLog_INFO(TAG, "\tfragCache: Entries: %d MaximumCellSize: %d", fragCache.cacheEntries, fragCache.cacheMaximumCellSize); + WLog_INFO(TAG, "\tglyphSupportLevel: 0x%04X", glyphSupportLevel); + WLog_INFO(TAG, "\tpad2Octets: 0x%04X", pad2Octets); return TRUE; } @@ -1609,8 +1593,7 @@ BOOL rdp_print_offscreen_bitmap_cache_capability_set(wStream* s, UINT16 length) UINT32 offscreenSupportLevel; UINT16 offscreenCacheSize; UINT16 offscreenCacheEntries; - - fprintf(stderr, "OffscreenBitmapCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "OffscreenBitmapCacheCapabilitySet (length %d):", length); if (length < 12) return FALSE; @@ -1618,11 +1601,9 @@ BOOL rdp_print_offscreen_bitmap_cache_capability_set(wStream* s, UINT16 length) Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */ Stream_Read_UINT16(s, offscreenCacheSize); /* offscreenCacheSize (2 bytes) */ Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */ - - fprintf(stderr, "\toffscreenSupportLevel: 0x%08X\n", offscreenSupportLevel); - fprintf(stderr, "\toffscreenCacheSize: 0x%04X\n", offscreenCacheSize); - fprintf(stderr, "\toffscreenCacheEntries: 0x%04X\n", offscreenCacheEntries); - + WLog_INFO(TAG, "\toffscreenSupportLevel: 0x%08X", offscreenSupportLevel); + WLog_INFO(TAG, "\toffscreenCacheSize: 0x%04X", offscreenCacheSize); + WLog_INFO(TAG, "\toffscreenCacheEntries: 0x%04X", offscreenCacheEntries); return TRUE; } @@ -1678,8 +1659,7 @@ BOOL rdp_print_bitmap_cache_host_support_capability_set(wStream* s, UINT16 lengt BYTE cacheVersion; BYTE pad1; UINT16 pad2; - - fprintf(stderr, "BitmapCacheHostSupportCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCacheHostSupportCapabilitySet (length %d):", length); if (length < 8) return FALSE; @@ -1687,11 +1667,9 @@ BOOL rdp_print_bitmap_cache_host_support_capability_set(wStream* s, UINT16 lengt Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */ Stream_Read_UINT8(s, pad1); /* pad1 (1 byte) */ Stream_Read_UINT16(s, pad2); /* pad2 (2 bytes) */ - - fprintf(stderr, "\tcacheVersion: 0x%02X\n", cacheVersion); - fprintf(stderr, "\tpad1: 0x%02X\n", pad1); - fprintf(stderr, "\tpad2: 0x%04X\n", pad2); - + WLog_INFO(TAG, "\tcacheVersion: 0x%02X", cacheVersion); + WLog_INFO(TAG, "\tpad1: 0x%02X", pad1); + WLog_INFO(TAG, "\tpad2: 0x%04X", pad2); return TRUE; } @@ -1789,8 +1767,7 @@ BOOL rdp_print_bitmap_cache_v2_capability_set(wStream* s, UINT16 length) BYTE pad2; BYTE numCellCaches; BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5]; - - fprintf(stderr, "BitmapCacheV2CapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCacheV2CapabilitySet (length %d):", length); if (length < 40) return FALSE; @@ -1804,16 +1781,14 @@ BOOL rdp_print_bitmap_cache_v2_capability_set(wStream* s, UINT16 length) rdp_read_bitmap_cache_cell_info(s, &bitmapCacheV2CellInfo[3]); /* bitmapCache3CellInfo (4 bytes) */ rdp_read_bitmap_cache_cell_info(s, &bitmapCacheV2CellInfo[4]); /* bitmapCache4CellInfo (4 bytes) */ Stream_Seek(s, 12); /* pad3 (12 bytes) */ - - fprintf(stderr, "\tcacheFlags: 0x%04X\n", cacheFlags); - fprintf(stderr, "\tpad2: 0x%02X\n", pad2); - fprintf(stderr, "\tnumCellCaches: 0x%02X\n", numCellCaches); - fprintf(stderr, "\tbitmapCache0CellInfo: numEntries: %d persistent: %d\n", bitmapCacheV2CellInfo[0].numEntries, bitmapCacheV2CellInfo[0].persistent); - fprintf(stderr, "\tbitmapCache1CellInfo: numEntries: %d persistent: %d\n", bitmapCacheV2CellInfo[1].numEntries, bitmapCacheV2CellInfo[1].persistent); - fprintf(stderr, "\tbitmapCache2CellInfo: numEntries: %d persistent: %d\n", bitmapCacheV2CellInfo[2].numEntries, bitmapCacheV2CellInfo[2].persistent); - fprintf(stderr, "\tbitmapCache3CellInfo: numEntries: %d persistent: %d\n", bitmapCacheV2CellInfo[3].numEntries, bitmapCacheV2CellInfo[3].persistent); - fprintf(stderr, "\tbitmapCache4CellInfo: numEntries: %d persistent: %d\n", bitmapCacheV2CellInfo[4].numEntries, bitmapCacheV2CellInfo[4].persistent); - + WLog_INFO(TAG, "\tcacheFlags: 0x%04X", cacheFlags); + WLog_INFO(TAG, "\tpad2: 0x%02X", pad2); + WLog_INFO(TAG, "\tnumCellCaches: 0x%02X", numCellCaches); + WLog_INFO(TAG, "\tbitmapCache0CellInfo: numEntries: %d persistent: %d", bitmapCacheV2CellInfo[0].numEntries, bitmapCacheV2CellInfo[0].persistent); + WLog_INFO(TAG, "\tbitmapCache1CellInfo: numEntries: %d persistent: %d", bitmapCacheV2CellInfo[1].numEntries, bitmapCacheV2CellInfo[1].persistent); + WLog_INFO(TAG, "\tbitmapCache2CellInfo: numEntries: %d persistent: %d", bitmapCacheV2CellInfo[2].numEntries, bitmapCacheV2CellInfo[2].persistent); + WLog_INFO(TAG, "\tbitmapCache3CellInfo: numEntries: %d persistent: %d", bitmapCacheV2CellInfo[3].numEntries, bitmapCacheV2CellInfo[3].persistent); + WLog_INFO(TAG, "\tbitmapCache4CellInfo: numEntries: %d persistent: %d", bitmapCacheV2CellInfo[4].numEntries, bitmapCacheV2CellInfo[4].persistent); return TRUE; } @@ -1874,8 +1849,7 @@ BOOL rdp_print_virtual_channel_capability_set(wStream* s, UINT16 length) { UINT32 flags; UINT32 VCChunkSize; - - fprintf(stderr, "VirtualChannelCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "VirtualChannelCapabilitySet (length %d):", length); if (length < 8) return FALSE; @@ -1887,9 +1861,8 @@ BOOL rdp_print_virtual_channel_capability_set(wStream* s, UINT16 length) else VCChunkSize = 1600; - fprintf(stderr, "\tflags: 0x%08X\n", flags); - fprintf(stderr, "\tVCChunkSize: 0x%08X\n", VCChunkSize); - + WLog_INFO(TAG, "\tflags: 0x%08X", flags); + WLog_INFO(TAG, "\tVCChunkSize: 0x%08X", VCChunkSize); return TRUE; } @@ -1973,8 +1946,7 @@ BOOL rdp_print_draw_nine_grid_cache_capability_set(wStream* s, UINT16 length) UINT32 drawNineGridSupportLevel; UINT16 DrawNineGridCacheSize; UINT16 DrawNineGridCacheEntries; - - fprintf(stderr, "DrawNineGridCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "DrawNineGridCacheCapabilitySet (length %d):", length); if (length < 12) return FALSE; @@ -2053,8 +2025,7 @@ BOOL rdp_print_draw_gdiplus_cache_capability_set(wStream* s, UINT16 length) UINT32 drawGdiPlusSupportLevel; UINT32 GdipVersion; UINT32 drawGdiplusCacheLevel; - - fprintf(stderr, "DrawGdiPlusCacheCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "DrawGdiPlusCacheCapabilitySet (length %d):", length); if (length < 40) return FALSE; @@ -2126,16 +2097,13 @@ void rdp_write_remote_programs_capability_set(wStream* s, rdpSettings* settings) BOOL rdp_print_remote_programs_capability_set(wStream* s, UINT16 length) { UINT32 railSupportLevel; - - fprintf(stderr, "RemoteProgramsCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "RemoteProgramsCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */ - - fprintf(stderr, "\trailSupportLevel: 0x%08X\n", railSupportLevel); - + WLog_INFO(TAG, "\trailSupportLevel: 0x%08X", railSupportLevel); return TRUE; } @@ -2189,8 +2157,7 @@ BOOL rdp_print_window_list_capability_set(wStream* s, UINT16 length) UINT32 wndSupportLevel; BYTE numIconCaches; UINT16 numIconCacheEntries; - - fprintf(stderr, "WindowListCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "WindowListCapabilitySet (length %d):", length); if (length < 11) return FALSE; @@ -2198,11 +2165,9 @@ BOOL rdp_print_window_list_capability_set(wStream* s, UINT16 length) Stream_Read_UINT32(s, wndSupportLevel); /* wndSupportLevel (4 bytes) */ Stream_Read_UINT8(s, numIconCaches); /* numIconCaches (1 byte) */ Stream_Read_UINT16(s, numIconCacheEntries); /* numIconCacheEntries (2 bytes) */ - - fprintf(stderr, "\twndSupportLevel: 0x%08X\n", wndSupportLevel); - fprintf(stderr, "\tnumIconCaches: 0x%02X\n", numIconCaches); - fprintf(stderr, "\tnumIconCacheEntries: 0x%04X\n", numIconCacheEntries); - + WLog_INFO(TAG, "\twndSupportLevel: 0x%08X", wndSupportLevel); + WLog_INFO(TAG, "\tnumIconCaches: 0x%02X", numIconCaches); + WLog_INFO(TAG, "\tnumIconCacheEntries: 0x%04X", numIconCacheEntries); return TRUE; } @@ -2250,16 +2215,13 @@ void rdp_write_desktop_composition_capability_set(wStream* s, rdpSettings* setti BOOL rdp_print_desktop_composition_capability_set(wStream* s, UINT16 length) { UINT16 compDeskSupportLevel; - - fprintf(stderr, "DesktopCompositionCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "DesktopCompositionCapabilitySet (length %d):", length); if (length < 6) return FALSE; Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */ - - fprintf(stderr, "\tcompDeskSupportLevel: 0x%04X\n", compDeskSupportLevel); - + WLog_INFO(TAG, "\tcompDeskSupportLevel: 0x%04X", compDeskSupportLevel); return TRUE; } @@ -2282,6 +2244,17 @@ BOOL rdp_read_multifragment_update_capability_set(wStream* s, UINT16 length, rdp if (settings->ServerMode) { + /* + * Special case: The client announces multifragment update support but sets the maximum request size + * to something smaller than maximum size for *one* fast-path PDU. + * In this case behave like no multifragment updates were supported and make sure no + * fragmentation happens by setting FASTPATH_FRAGMENT_SAFE_SIZE. + * + * This behaviour was observed with some windows ce rdp clients. + */ + if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE) + multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE; + if (settings->RemoteFxCodec) { /** @@ -2368,16 +2341,13 @@ void rdp_write_multifragment_update_capability_set(wStream* s, rdpSettings* sett BOOL rdp_print_multifragment_update_capability_set(wStream* s, UINT16 length) { UINT32 maxRequestSize; - - fprintf(stderr, "MultifragmentUpdateCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "MultifragmentUpdateCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */ - - fprintf(stderr, "\tmaxRequestSize: 0x%04X\n", maxRequestSize); - + WLog_INFO(TAG, "\tmaxRequestSize: 0x%04X", maxRequestSize); return TRUE; } @@ -2429,16 +2399,13 @@ void rdp_write_large_pointer_capability_set(wStream* s, rdpSettings* settings) BOOL rdp_print_large_pointer_capability_set(wStream* s, UINT16 length) { UINT16 largePointerSupportFlags; - - fprintf(stderr, "LargePointerCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "LargePointerCapabilitySet (length %d):", length); if (length < 6) return FALSE; Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */ - - fprintf(stderr, "\tlargePointerSupportFlags: 0x%04X\n", largePointerSupportFlags); - + WLog_INFO(TAG, "\tlargePointerSupportFlags: 0x%04X", largePointerSupportFlags); return TRUE; } @@ -2453,6 +2420,7 @@ BOOL rdp_print_large_pointer_capability_set(wStream* s, UINT16 length) BOOL rdp_read_surface_commands_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { UINT32 cmdFlags; + if (length < 12) return FALSE; @@ -2481,8 +2449,8 @@ void rdp_write_surface_commands_capability_set(wStream* s, rdpSettings* settings header = rdp_capability_set_start(s); - cmdFlags = SURFCMDS_SET_SURFACE_BITS | - SURFCMDS_STREAM_SURFACE_BITS; + cmdFlags = SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS; + if (settings->SurfaceFrameMarkerEnabled) cmdFlags |= SURFCMDS_FRAME_MARKER; @@ -2496,21 +2464,45 @@ BOOL rdp_print_surface_commands_capability_set(wStream* s, UINT16 length) { UINT32 cmdFlags; UINT32 reserved; - - fprintf(stderr, "SurfaceCommandsCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "SurfaceCommandsCapabilitySet (length %d):", length); if (length < 12) return FALSE; Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */ Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */ - - fprintf(stderr, "\tcmdFlags: 0x%08X\n", cmdFlags); - fprintf(stderr, "\treserved: 0x%08X\n", reserved); - + WLog_INFO(TAG, "\tcmdFlags: 0x%08X", cmdFlags); + WLog_INFO(TAG, "\treserved: 0x%08X", reserved); return TRUE; } +void rdp_print_bitmap_codec_guid(GUID* guid) +{ + WLog_INFO(TAG, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); +} + +char* rdp_get_bitmap_codec_guid_name(GUID* guid) +{ + RPC_STATUS rpc_status; + + if (UuidEqual(guid, &CODEC_GUID_REMOTEFX, &rpc_status)) + return "CODEC_GUID_REMOTEFX"; + else if (UuidEqual(guid, &CODEC_GUID_NSCODEC, &rpc_status)) + return "CODEC_GUID_NSCODEC"; + else if (UuidEqual(guid, &CODEC_GUID_IGNORE, &rpc_status)) + return "CODEC_GUID_IGNORE"; + else if (UuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status)) + return "CODEC_GUID_IMAGE_REMOTEFX"; + else if (UuidEqual(guid, &CODEC_GUID_JPEG, &rpc_status)) + return "CODEC_GUID_JPEG"; + + return "CODEC_GUID_UNKNOWN"; +} + + void rdp_read_bitmap_codec_guid(wStream* s, GUID* guid) { BYTE g[16]; @@ -2554,32 +2546,6 @@ void rdp_write_bitmap_codec_guid(wStream* s, GUID* guid) Stream_Write(s, g, 16); } -void rdp_print_bitmap_codec_guid(GUID* guid) -{ - fprintf(stderr, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); -} - -char* rdp_get_bitmap_codec_guid_name(GUID* guid) -{ - RPC_STATUS rpc_status; - - if (UuidEqual(guid, &CODEC_GUID_REMOTEFX, &rpc_status)) - return "CODEC_GUID_REMOTEFX"; - else if (UuidEqual(guid, &CODEC_GUID_NSCODEC, &rpc_status)) - return "CODEC_GUID_NSCODEC"; - else if (UuidEqual(guid, &CODEC_GUID_IGNORE, &rpc_status)) - return "CODEC_GUID_IGNORE"; - else if (UuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status)) - return "CODEC_GUID_IMAGE_REMOTEFX"; - else if (UuidEqual(guid, &CODEC_GUID_JPEG, &rpc_status)) - return "CODEC_GUID_JPEG"; - - return "CODEC_GUID_UNKNOWN"; -} - /** * Read bitmap codecs capability set.\n * @msdn{dd891377} @@ -2590,13 +2556,15 @@ char* rdp_get_bitmap_codec_guid_name(GUID* guid) BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { + BYTE codecId; GUID codecGuid; RPC_STATUS rpc_status; BYTE bitmapCodecCount; UINT16 codecPropertiesLength; UINT16 remainingLength; - BOOL receivedRemoteFxCodec = FALSE; - BOOL receivedNSCodec = FALSE; + BOOL guidNSCodec = FALSE; + BOOL guidRemoteFx = FALSE; + BOOL guidRemoteFxImage = FALSE; if (length < 5) return FALSE; @@ -2611,28 +2579,7 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting rdp_read_bitmap_codec_guid(s, &codecGuid); /* codecGuid (16 bytes) */ - if (settings->ServerMode) - { - if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status)) - { - Stream_Read_UINT8(s, settings->RemoteFxCodecId); - receivedRemoteFxCodec = TRUE; - } - else if (UuidEqual(&codecGuid, &CODEC_GUID_NSCODEC, &rpc_status)) - { - Stream_Read_UINT8(s, settings->NSCodecId); - receivedNSCodec = TRUE; - } - else - { - Stream_Seek_UINT8(s); /* codecID (1 byte) */ - } - } - else - { - Stream_Seek_UINT8(s); /* codecID (1 byte) */ - } - + Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */ Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */ remainingLength -= 19; @@ -2641,21 +2588,156 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting if (settings->ServerMode) { + UINT32 beg; + UINT32 end; + + beg = (UINT32) Stream_GetPosition(s); + end = beg + codecPropertiesLength; + if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status)) { - Stream_Seek_UINT32(s); /* length */ - Stream_Read_UINT32(s, settings->RemoteFxCaptureFlags); /* captureFlags */ - Stream_Rewind(s, 8); + UINT32 rfxCapsLength; + UINT32 rfxPropsLength; + UINT32 captureFlags; - if (settings->RemoteFxCaptureFlags & CARDP_CAPS_CAPTURE_NON_CAC) + guidRemoteFx = TRUE; + settings->RemoteFxCodecId = codecId; + + Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */ + Stream_Read_UINT32(s, captureFlags); /* captureFlags (4 bytes) */ + Stream_Read_UINT32(s, rfxCapsLength); /* capsLength (4 bytes) */ + + settings->RemoteFxCaptureFlags = captureFlags; + settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? TRUE : FALSE; + + if (rfxCapsLength) { - settings->RemoteFxOnly = TRUE; + UINT16 blockType; + UINT32 blockLen; + UINT16 numCapsets; + BYTE rfxCodecId; + UINT16 capsetType; + UINT16 numIcaps; + UINT16 icapLen; + + /* TS_RFX_CAPS */ + + Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */ + Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */ + Stream_Read_UINT16(s, numCapsets); /* numCapsets (2 bytes) */ + + if (blockType != 0xCBC0) + return FALSE; + + if (blockLen != 8) + return FALSE; + + if (numCapsets != 1) + return FALSE; + + /* TS_RFX_CAPSET */ + + Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */ + Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */ + Stream_Read_UINT8(s, rfxCodecId); /* codecId (1 byte) */ + Stream_Read_UINT16(s, capsetType); /* capsetType (2 bytes) */ + Stream_Read_UINT16(s, numIcaps); /* numIcaps (2 bytes) */ + Stream_Read_UINT16(s, icapLen); /* icapLen (2 bytes) */ + + if (blockType != 0xCBC1) + return FALSE; + + if (rfxCodecId != 1) + return FALSE; + + if (capsetType != 0xCFC0) + return FALSE; + + while (numIcaps--) + { + UINT16 version; + UINT16 tileSize; + BYTE codecFlags; + BYTE colConvBits; + BYTE transformBits; + BYTE entropyBits; + + /* TS_RFX_ICAP */ + + Stream_Read_UINT16(s, version); /* version (2 bytes) */ + Stream_Read_UINT16(s, tileSize); /* tileSize (2 bytes) */ + Stream_Read_UINT8(s, codecFlags); /* flags (1 byte) */ + Stream_Read_UINT8(s, colConvBits); /* colConvBits (1 byte) */ + Stream_Read_UINT8(s, transformBits); /* transformBits (1 byte) */ + Stream_Read_UINT8(s, entropyBits); /* entropyBits (1 byte) */ + + if (version != 0x0100) + return FALSE; + + if (tileSize != 0x0040) + return FALSE; + + if (colConvBits != 1) + return FALSE; + + if (transformBits != 1) + return FALSE; + } } } - } + else if (UuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status)) + { + /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */ - Stream_Seek(s, codecPropertiesLength); /* codecProperties */ - remainingLength -= codecPropertiesLength; + guidRemoteFxImage = TRUE; + Stream_Seek(s, codecPropertiesLength); /* codecProperties */ + } + else if (UuidEqual(&codecGuid, &CODEC_GUID_NSCODEC, &rpc_status)) + { + BYTE colorLossLevel; + BYTE fAllowSubsampling; + BYTE fAllowDynamicFidelity; + + guidNSCodec = TRUE; + settings->NSCodecId = codecId; + + Stream_Read_UINT8(s, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */ + Stream_Read_UINT8(s, fAllowSubsampling); /* fAllowSubsampling (1 byte) */ + Stream_Read_UINT8(s, colorLossLevel); /* colorLossLevel (1 byte) */ + + if (colorLossLevel < 1) + colorLossLevel = 1; + + if (colorLossLevel > 7) + colorLossLevel = 7; + + settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity; + settings->NSCodecAllowSubsampling = fAllowSubsampling; + settings->NSCodecColorLossLevel = colorLossLevel; + } + else if (UuidEqual(&codecGuid, &CODEC_GUID_IGNORE, &rpc_status)) + { + Stream_Seek(s, codecPropertiesLength); /* codecProperties */ + } + else + { + Stream_Seek(s, codecPropertiesLength); /* codecProperties */ + } + + if (Stream_GetPosition(s) != end) + { + fprintf(stderr, "error while reading codec properties: actual offset: %d expected offset: %d\n", + (int) Stream_GetPosition(s), end); + Stream_SetPosition(s, end); + } + + remainingLength -= codecPropertiesLength; + } + else + { + Stream_Seek(s, codecPropertiesLength); /* codecProperties */ + remainingLength -= codecPropertiesLength; + } bitmapCodecCount--; } @@ -2663,8 +2745,9 @@ BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, UINT16 length, rdpSetting if (settings->ServerMode) { /* only enable a codec if we've announced/enabled it before */ - settings->RemoteFxCodec = settings->RemoteFxCodec && receivedRemoteFxCodec; - settings->NSCodec = settings->NSCodec && receivedNSCodec; + settings->RemoteFxCodec = settings->RemoteFxCodec && guidRemoteFx; + settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && guidRemoteFxImage; + settings->NSCodec = settings->NSCodec && guidNSCodec; settings->JpegCodec = FALSE; } @@ -2735,9 +2818,9 @@ void rdp_write_nsc_client_capability_container(wStream* s, rdpSettings* settings Stream_Write_UINT16(s, 3); /* codecPropertiesLength */ /* TS_NSCODEC_CAPABILITYSET */ - Stream_Write_UINT8(s, 1); /* fAllowDynamicFidelity */ - Stream_Write_UINT8(s, 1); /* fAllowSubsampling */ - Stream_Write_UINT8(s, 3); /* colorLossLevel */ + Stream_Write_UINT8(s, settings->NSCodecAllowDynamicColorFidelity); /* fAllowDynamicFidelity */ + Stream_Write_UINT8(s, settings->NSCodecAllowSubsampling); /* fAllowSubsampling */ + Stream_Write_UINT8(s, settings->NSCodecColorLossLevel); /* colorLossLevel */ } void rdp_write_jpeg_client_capability_container(wStream* s, rdpSettings* settings) @@ -2800,9 +2883,6 @@ void rdp_write_bitmap_codecs_capability_set(wStream* s, rdpSettings* settings) bitmapCodecCount = 0; - if (settings->RemoteFxCodec) - settings->RemoteFxImageCodec = TRUE; - if (settings->RemoteFxCodec) bitmapCodecCount++; if (settings->NSCodec) @@ -2888,16 +2968,14 @@ BOOL rdp_print_bitmap_codecs_capability_set(wStream* s, UINT16 length) BYTE codecId; UINT16 codecPropertiesLength; UINT16 remainingLength; - - fprintf(stderr, "BitmapCodecsCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCodecsCapabilitySet (length %d):", length); if (length < 5) return FALSE; Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */ remainingLength = length - 5; - - fprintf(stderr, "\tbitmapCodecCount: %d\n", bitmapCodecCount); + WLog_INFO(TAG, "\tbitmapCodecCount: %d", bitmapCodecCount); while (bitmapCodecCount > 0) { @@ -2906,16 +2984,12 @@ BOOL rdp_print_bitmap_codecs_capability_set(wStream* s, UINT16 length) rdp_read_bitmap_codec_guid(s, &codecGuid); /* codecGuid (16 bytes) */ Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */ - - fprintf(stderr, "\tcodecGuid: 0x"); + WLog_INFO(TAG, "\tcodecGuid: 0x"); rdp_print_bitmap_codec_guid(&codecGuid); - fprintf(stderr, " (%s)\n", rdp_get_bitmap_codec_guid_name(&codecGuid)); - - fprintf(stderr, "\tcodecId: %d\n", codecId); - + WLog_INFO(TAG, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid)); + WLog_INFO(TAG, "\tcodecId: %d", codecId); Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */ - fprintf(stderr, "\tcodecPropertiesLength: %d\n", codecPropertiesLength); - + WLog_INFO(TAG, "\tcodecPropertiesLength: %d", codecPropertiesLength); remainingLength -= 19; if (remainingLength < codecPropertiesLength) @@ -2976,16 +3050,13 @@ void rdp_write_frame_acknowledge_capability_set(wStream* s, rdpSettings* setting BOOL rdp_print_frame_acknowledge_capability_set(wStream* s, UINT16 length) { UINT32 frameAcknowledge; - - fprintf(stderr, "FrameAcknowledgeCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "FrameAcknowledgeCapabilitySet (length %d):", length); if (length < 8) return FALSE; Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */ - - fprintf(stderr, "\tframeAcknowledge: 0x%08X\n", frameAcknowledge); - + WLog_INFO(TAG, "\tframeAcknowledge: 0x%08X", frameAcknowledge); return TRUE; } @@ -3016,16 +3087,13 @@ void rdp_write_bitmap_cache_v3_codec_id_capability_set(wStream* s, rdpSettings* BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wStream* s, UINT16 length) { BYTE bitmapCacheV3CodecId; - - fprintf(stderr, "BitmapCacheV3CodecIdCapabilitySet (length %d):\n", length); + WLog_INFO(TAG, "BitmapCacheV3CodecIdCapabilitySet (length %d):", length); if (length < 5) return FALSE; Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */ - - fprintf(stderr, "\tbitmapCacheV3CodecId: 0x%02X\n", bitmapCacheV3CodecId); - + WLog_INFO(TAG, "\tbitmapCacheV3CodecId: 0x%02X", bitmapCacheV3CodecId); return TRUE; } @@ -3040,14 +3108,12 @@ BOOL rdp_print_capability_sets(wStream* s, UINT16 numberCapabilities, BOOL recei Stream_GetPointer(s, bm); rdp_read_capability_set_header(s, &length, &type); - - fprintf(stderr, "%s ", receiving ? "Receiving" : "Sending"); - + WLog_INFO(TAG, "%s ", receiving ? "Receiving" : "Sending"); em = bm + length; if (Stream_GetRemainingLength(s) < (size_t) (length - 4)) { - fprintf(stderr, "error processing stream\n"); + WLog_ERR(TAG, "error processing stream"); return FALSE; } @@ -3199,14 +3265,14 @@ BOOL rdp_print_capability_sets(wStream* s, UINT16 numberCapabilities, BOOL recei break; default: - fprintf(stderr, "unknown capability type %d\n", type); + WLog_ERR(TAG, "unknown capability type %d", type); break; } if (s->pointer != em) { - fprintf(stderr, "incorrect offset, type:0x%02X actual:%d expected:%d\n", - type, (int) (s->pointer - bm), (int) (em - bm)); + WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", + type, (int)(s->pointer - bm), (int)(em - bm)); } Stream_SetPointer(s, em); @@ -3241,14 +3307,14 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa } else { - fprintf(stderr, "%s: not handling capability type %d yet\n", __FUNCTION__, type); + WLog_WARN(TAG, "not handling capability type %d yet", type); } em = bm + length; if (Stream_GetRemainingLength(s) < ((size_t) length - 4)) { - fprintf(stderr, "error processing stream\n"); + WLog_ERR(TAG, "error processing stream"); return FALSE; } @@ -3401,14 +3467,14 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa break; default: - fprintf(stderr, "unknown capability type %d\n", type); + WLog_ERR(TAG, "unknown capability type %d", type); break; } if (s->pointer != em) { - fprintf(stderr, "incorrect offset, type:0x%02X actual:%d expected:%d\n", - type, (int) (s->pointer - bm), (int) (em - bm)); + WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", + type, (int)(s->pointer - bm), (int)(em - bm)); } Stream_SetPointer(s, em); @@ -3417,8 +3483,8 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa if (numberCapabilities) { - fprintf(stderr, "%s: strange we haven't read the number of announced capacity sets, read=%d expected=%d\n", - __FUNCTION__, count-numberCapabilities, count); + WLog_ERR(TAG, "strange we haven't read the number of announced capacity sets, read=%d expected=%d", + count-numberCapabilities, count); } /** @@ -3461,7 +3527,7 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId) { if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) { - fprintf(stderr, "rdp_decrypt failed\n"); + WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; } } @@ -3473,7 +3539,7 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId) if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId)) { - fprintf(stderr, "unexpected MCS channel id %04x received\n", *pChannelId); + WLog_ERR(TAG, "unexpected MCS channel id %04x received", *pChannelId); return FALSE; } } @@ -3499,14 +3565,14 @@ BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s) if (!rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource)) { - fprintf(stderr, "rdp_read_share_control_header failed\n"); + WLog_ERR(TAG, "rdp_read_share_control_header failed"); return FALSE; } if (pduType != PDU_TYPE_DEMAND_ACTIVE) { if (pduType != PDU_TYPE_SERVER_REDIRECTION) - fprintf(stderr, "expected PDU_TYPE_DEMAND_ACTIVE %04x, got %04x\n", PDU_TYPE_DEMAND_ACTIVE, pduType); + WLog_ERR(TAG, "expected PDU_TYPE_DEMAND_ACTIVE %04x, got %04x", PDU_TYPE_DEMAND_ACTIVE, pduType); return FALSE; } @@ -3529,7 +3595,7 @@ BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s) /* capabilitySets */ if (!rdp_read_capability_sets(s, rdp->settings, numberCapabilities)) { - fprintf(stderr, "rdp_read_capability_sets failed\n"); + WLog_ERR(TAG, "rdp_read_capability_sets failed"); return FALSE; } @@ -3676,7 +3742,8 @@ BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s) if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE]) { - /* client does not support multi fragment updates */ + /* client does not support multi fragment updates - make sure packages are not fragmented */ + settings->MultifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE; } if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER]) diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index fcc3f01bf..7489857da 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -33,6 +33,8 @@ #include "certificate.h" +#define TAG "com.freerdp.core" + /** * * X.509 Certificate Structure @@ -121,7 +123,8 @@ * */ -static const char *certificate_read_errors[] = { +static const char* certificate_read_errors[] = +{ "Certificate tag", "TBSCertificate", "Explicit Contextual Tag [0]", @@ -161,73 +164,90 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info) int error = 0; s = Stream_New(cert->data, cert->length); + if (!s) return FALSE; + info->Modulus = 0; if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */ goto error1; + error++; if (!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */ goto error1; + error++; if (!ber_read_contextual_tag(s, 0, &length, TRUE)) /* Explicit Contextual Tag [0] */ goto error1; + error++; + if (!ber_read_integer(s, &version)) /* version (INTEGER) */ goto error1; + error++; version++; /* serialNumber */ if (!ber_read_integer(s, NULL)) /* CertificateSerialNumber (INTEGER) */ goto error1; + error++; /* signature */ if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */ goto error1; + error++; /* issuer */ if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */ goto error1; + error++; /* validity */ if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Validity (SEQUENCE) */ goto error1; + error++; /* subject */ if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo */ if (!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo::AlgorithmIdentifier */ if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo::subjectPublicKey */ if (!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */ goto error1; + error++; /* RSAPublicKey (SEQUENCE) */ if (!ber_read_sequence_tag(s, &length)) /* SEQUENCE */ goto error1; + error++; if (!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */ goto error1; + error++; /* skip zero padding, if any */ @@ -255,8 +275,10 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info) info->ModulusLength = modulus_length; info->Modulus = (BYTE*) malloc(info->ModulusLength); + if (!info->Modulus) goto error1; + Stream_Read(s, info->Modulus, info->ModulusLength); error++; @@ -271,15 +293,13 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info) Stream_Read(s, &info->exponent[4 - exponent_length], exponent_length); crypto_reverse(info->Modulus, info->ModulusLength); crypto_reverse(info->exponent, 4); - Stream_Free(s, FALSE); return TRUE; - error2: free(info->Modulus); info->Modulus = 0; error1: - fprintf(stderr, "error reading when reading certificate: part=%s error=%d\n", certificate_read_errors[error], error); + WLog_ERR(TAG, "error reading when reading certificate: part=%s error=%d", certificate_read_errors[error], error); Stream_Free(s, FALSE); return FALSE; } @@ -294,17 +314,20 @@ rdpX509CertChain* certificate_new_x509_certificate_chain(UINT32 count) { rdpX509CertChain* x509_cert_chain; - x509_cert_chain = (rdpX509CertChain *)malloc(sizeof(rdpX509CertChain)); + x509_cert_chain = (rdpX509CertChain*) malloc(sizeof(rdpX509CertChain)); + if (!x509_cert_chain) return NULL; x509_cert_chain->count = count; - x509_cert_chain->array = (rdpCertBlob *)calloc(count, sizeof(rdpCertBlob)); + x509_cert_chain->array = (rdpCertBlob*) calloc(count, sizeof(rdpCertBlob)); + if (!x509_cert_chain->array) { free(x509_cert_chain); return NULL; } + return x509_cert_chain; } @@ -340,11 +363,12 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w if (Stream_GetRemainingLength(s) < 20) return FALSE; + Stream_Read(s, magic, 4); if (memcmp(magic, "RSA1", 4) != 0) { - fprintf(stderr, "%s: magic error\n", __FUNCTION__); + WLog_ERR(TAG, "magic error"); return FALSE; } @@ -356,13 +380,15 @@ static BOOL certificate_process_server_public_key(rdpCertificate* certificate, w if (Stream_GetRemainingLength(s) < modlen + 8) // count padding return FALSE; + certificate->cert_info.ModulusLength = modlen; certificate->cert_info.Modulus = malloc(certificate->cert_info.ModulusLength); + if (!certificate->cert_info.Modulus) return FALSE; + Stream_Read(s, certificate->cert_info.Modulus, certificate->cert_info.ModulusLength); - /* 8 bytes of zero padding */ - Stream_Seek(s, 8); + Stream_Seek(s, 8); /* 8 bytes of zero padding */ return TRUE; } @@ -377,11 +403,12 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific BYTE md5hash[CRYPTO_MD5_DIGEST_LENGTH]; md5ctx = crypto_md5_init(); + if (!md5ctx) return FALSE; + crypto_md5_update(md5ctx, sigdata, sigdatalen); crypto_md5_final(md5ctx, md5hash); - Stream_Read(s, encsig, siglen); /* Last 8 bytes shall be all zero. */ @@ -391,19 +418,18 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific if (sum != 0) { - fprintf(stderr, "%s: invalid signature\n", __FUNCTION__); + WLog_ERR(TAG, "invalid signature"); //return FALSE; } siglen -= 8; - // TODO: check the result of decrypt crypto_rsa_public_decrypt(encsig, siglen, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent, sig); /* Verify signature. */ if (memcmp(md5hash, sig, sizeof(md5hash)) != 0) { - fprintf(stderr, "%s: invalid signature\n", __FUNCTION__); + WLog_ERR(TAG, "invalid signature"); //return FALSE; } @@ -419,7 +445,7 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific if (sig[16] != 0x00 || sum != 0xFF * (62 - 17) || sig[62] != 0x01) { - fprintf(stderr, "%s: invalid signature\n", __FUNCTION__); + WLog_ERR(TAG, "invalid signature"); //return FALSE; } @@ -451,10 +477,10 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate Stream_Read_UINT32(s, dwSigAlgId); Stream_Read_UINT32(s, dwKeyAlgId); - if (!(dwSigAlgId == SIGNATURE_ALG_RSA && dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)) + if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA))) { - fprintf(stderr, "%s: unsupported signature or key algorithm, dwSigAlgId=%d dwKeyAlgId=%d\n", - __FUNCTION__, dwSigAlgId, dwKeyAlgId); + WLog_ERR(TAG, "unsupported signature or key algorithm, dwSigAlgId=%d dwKeyAlgId=%d", + dwSigAlgId, dwKeyAlgId); return FALSE; } @@ -462,17 +488,18 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate if (wPublicKeyBlobType != BB_RSA_KEY_BLOB) { - fprintf(stderr, "%s: unsupported public key blob type %d\n", __FUNCTION__, wPublicKeyBlobType); + WLog_ERR(TAG, "unsupported public key blob type %d", wPublicKeyBlobType); return FALSE; } Stream_Read_UINT16(s, wPublicKeyBlobLen); + if (Stream_GetRemainingLength(s) < wPublicKeyBlobLen) return FALSE; if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen)) { - fprintf(stderr, "%s: error in server public key\n", __FUNCTION__); + WLog_ERR(TAG, "error in server public key"); return FALSE; } @@ -484,26 +511,27 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB) { - fprintf(stderr, "%s: unsupported blob signature %d\n", __FUNCTION__, wSignatureBlobType); + WLog_ERR(TAG, "unsupported blob signature %d", wSignatureBlobType); return FALSE; } Stream_Read_UINT16(s, wSignatureBlobLen); + if (Stream_GetRemainingLength(s) < wSignatureBlobLen) { - fprintf(stderr, "%s: not enought bytes for signature(len=%d)\n", __FUNCTION__, wSignatureBlobLen); + WLog_ERR(TAG, "not enought bytes for signature(len=%d)", wSignatureBlobLen); return FALSE; } if (wSignatureBlobLen != 72) { - fprintf(stderr, "%s: invalid signature length (got %d, expected %d)\n", __FUNCTION__, wSignatureBlobLen, 64); + WLog_ERR(TAG, "invalid signature length (got %d, expected %d)", wSignatureBlobLen, 64); return FALSE; } if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s, wSignatureBlobLen)) { - fprintf(stderr, "%s: unable to parse server public signature\n", __FUNCTION__); + WLog_ERR(TAG, "unable to parse server public signature"); return FALSE; } @@ -519,17 +547,18 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s) { int i; + BOOL ret; UINT32 certLength; UINT32 numCertBlobs; - BOOL ret; DEBUG_CERTIFICATE("Server X.509 Certificate Chain"); if (Stream_GetRemainingLength(s) < 4) return FALSE; - Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */ + Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */ certificate->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs); + if (!certificate->x509_cert_chain) return FALSE; @@ -544,32 +573,41 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, return FALSE; DEBUG_CERTIFICATE("\nX.509 Certificate #%d, length:%d", i + 1, certLength); - certificate->x509_cert_chain->array[i].data = (BYTE*) malloc(certLength); + if (!certificate->x509_cert_chain->array[i].data) return FALSE; + Stream_Read(s, certificate->x509_cert_chain->array[i].data, certLength); certificate->x509_cert_chain->array[i].length = certLength; - if (numCertBlobs - i == 2) + if ((numCertBlobs - i) == 2) { rdpCertInfo cert_info; + DEBUG_CERTIFICATE("License Server Certificate"); + ret = certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &cert_info); + DEBUG_LICENSE("modulus length:%d", (int) cert_info.ModulusLength); + if (cert_info.Modulus) free(cert_info.Modulus); - if (!ret) { - fprintf(stderr, "failed to read License Server, content follows:\n"); - winpr_HexDump(certificate->x509_cert_chain->array[i].data, certificate->x509_cert_chain->array[i].length); + + if (!ret) + { + WLog_ERR(TAG, "failed to read License Server, content follows:"); + winpr_HexDump(TAG, WLOG_ERROR, certificate->x509_cert_chain->array[i].data, certificate->x509_cert_chain->array[i].length); return FALSE; } } else if (numCertBlobs - i == 1) { DEBUG_CERTIFICATE("Terminal Server Certificate"); + if (!certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &certificate->cert_info)) return FALSE; + DEBUG_CERTIFICATE("modulus length:%d", (int) certificate->cert_info.ModulusLength); } } @@ -586,15 +624,14 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length) { + BOOL ret; wStream* s; UINT32 dwVersion; - BOOL ret; if (length < 4) /* NULL certificate is not an error see #1795 */ return TRUE; s = Stream_New(server_cert, length); - Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */ switch (dwVersion & CERT_CHAIN_VERSION_MASK) @@ -608,7 +645,7 @@ BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* serv break; default: - fprintf(stderr, "invalid certificate chain version:%d\n", dwVersion & CERT_CHAIN_VERSION_MASK); + WLog_ERR(TAG, "invalid certificate chain version:%d", dwVersion & CERT_CHAIN_VERSION_MASK); ret = FALSE; break; } @@ -620,36 +657,58 @@ BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* serv rdpRsaKey* key_new(const char* keyfile) { + BIO* bio; FILE* fp; RSA* rsa; + int length; + BYTE* buffer; rdpRsaKey* key; - key = (rdpRsaKey *)calloc(1, sizeof(rdpRsaKey)); + key = (rdpRsaKey*) calloc(1, sizeof(rdpRsaKey)); + if (!key) return NULL; - fp = fopen(keyfile, "r"); - if (fp == NULL) + fp = fopen(keyfile, "r+b"); + + if (!fp) { - fprintf(stderr, "%s: unable to open RSA key file %s: %s.", __FUNCTION__, keyfile, strerror(errno)); + WLog_ERR(TAG, "unable to open RSA key file %s: %s.", keyfile, strerror(errno)); goto out_free; } - rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); - if (rsa == NULL) - { - fprintf(stderr, "%s: unable to load RSA key from %s: %s.", __FUNCTION__, keyfile, strerror(errno)); - ERR_print_errors_fp(stderr); - fclose(fp); - goto out_free; - } + fseek(fp, 0, SEEK_END); + length = ftell(fp); + fseek(fp, 0, SEEK_SET); + buffer = (BYTE*) malloc(length); + + if (!buffer) + goto out_free; + + fread((void*) buffer, length, 1, fp); fclose(fp); + bio = BIO_new_mem_buf((void*) buffer, length); + + if (!bio) + goto out_free; + + rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); + + BIO_free(bio); + free(buffer); + + if (!rsa) + { + WLog_ERR(TAG, "unable to load RSA key from %s: %s.", keyfile, strerror(errno)); + goto out_free; + } + switch (RSA_check_key(rsa)) { case 0: - fprintf(stderr, "%s: invalid RSA key in %s\n", __FUNCTION__, keyfile); + WLog_ERR(TAG, "invalid RSA key in %s", keyfile); goto out_free_rsa; case 1: @@ -657,38 +716,37 @@ rdpRsaKey* key_new(const char* keyfile) break; default: - fprintf(stderr, "%s: unexpected error when checking RSA key from %s: %s.", __FUNCTION__, keyfile, strerror(errno)); - ERR_print_errors_fp(stderr); + WLog_ERR(TAG, "unexpected error when checking RSA key from %s: %s.", keyfile, strerror(errno)); goto out_free_rsa; } if (BN_num_bytes(rsa->e) > 4) { - fprintf(stderr, "%s: RSA public exponent too large in %s\n", __FUNCTION__, keyfile); + WLog_ERR(TAG, "RSA public exponent too large in %s", keyfile); goto out_free_rsa; } key->ModulusLength = BN_num_bytes(rsa->n); - key->Modulus = (BYTE *)malloc(key->ModulusLength); + key->Modulus = (BYTE*) malloc(key->ModulusLength); + if (!key->Modulus) goto out_free_rsa; + BN_bn2bin(rsa->n, key->Modulus); crypto_reverse(key->Modulus, key->ModulusLength); - key->PrivateExponentLength = BN_num_bytes(rsa->d); - key->PrivateExponent = (BYTE *)malloc(key->PrivateExponentLength); + key->PrivateExponent = (BYTE*) malloc(key->PrivateExponentLength); + if (!key->PrivateExponent) goto out_free_modulus; + BN_bn2bin(rsa->d, key->PrivateExponent); crypto_reverse(key->PrivateExponent, key->PrivateExponentLength); - memset(key->exponent, 0, sizeof(key->exponent)); BN_bn2bin(rsa->e, key->exponent + sizeof(key->exponent) - BN_num_bytes(rsa->e)); crypto_reverse(key->exponent, sizeof(key->exponent)); - RSA_free(rsa); return key; - out_free_modulus: free(key->Modulus); out_free_rsa: @@ -705,6 +763,7 @@ void key_free(rdpRsaKey* key) if (key->Modulus) free(key->Modulus); + free(key->PrivateExponent); free(key); } diff --git a/libfreerdp/core/certificate.h b/libfreerdp/core/certificate.h index 2d726cf8a..91cb3e6d0 100644 --- a/libfreerdp/core/certificate.h +++ b/libfreerdp/core/certificate.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -58,10 +59,11 @@ void certificate_free(rdpCertificate* certificate); rdpRsaKey* key_new(const char *keyfile); void key_free(rdpRsaKey* key); +#define CERTIFICATE_TAG FREERDP_TAG("core.certificate") #ifdef WITH_DEBUG_CERTIFICATE -#define DEBUG_CERTIFICATE(fmt, ...) DEBUG_CLASS(CERTIFICATE, fmt, ## __VA_ARGS__) +#define DEBUG_CERTIFICATE(fmt, ...) WLog_DBG(CERTIFICATE_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_CERTIFICATE(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_CERTIFICATE(fmt, ...) do { } while (0) #endif #endif /* __CERTIFICATE_H */ diff --git a/libfreerdp/core/channels.c b/libfreerdp/core/channels.c index 54cfa99cf..53c6e3149 100644 --- a/libfreerdp/core/channels.c +++ b/libfreerdp/core/channels.c @@ -32,11 +32,12 @@ #include #include +#include #include #include #include #include -#include + #include #include #include @@ -46,6 +47,8 @@ #include "server.h" #include "channels.h" +#define TAG FREERDP_TAG("core.channels") + BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, BYTE* data, int size) { DWORD i; @@ -67,7 +70,7 @@ BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, BYTE* data, int size) if (!channel) { - fprintf(stderr, "freerdp_channel_send: unknown channelId %d\n", channelId); + WLog_ERR(TAG, "freerdp_channel_send: unknown channelId %d", channelId); return FALSE; } @@ -140,8 +143,36 @@ BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 chann Stream_Read_UINT32(s, flags); chunkLength = Stream_GetRemainingLength(s); - IFCALL(client->ReceiveChannelData, client, - channelId, Stream_Pointer(s), chunkLength, flags, length); + if (client->VirtualChannelRead) + { + UINT32 index; + BOOL found = FALSE; + HANDLE hChannel = 0; + rdpContext* context = client->context; + rdpMcs* mcs = context->rdp->mcs; + rdpMcsChannel* mcsChannel = NULL; + + for (index = 0; index < mcs->channelCount; index++) + { + mcsChannel = &(mcs->channels[index]); + + if (mcsChannel->ChannelId == channelId) + { + hChannel = (HANDLE) mcsChannel->handle; + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + + client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), Stream_GetRemainingLength(s)); + } + else if (client->ReceiveChannelData) + { + client->ReceiveChannelData(client, channelId, Stream_Pointer(s), chunkLength, flags, length); + } return TRUE; } diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index 5f4aec1e6..93d5292e6 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -21,10 +21,14 @@ #include "config.h" #endif +#include + #include "rdp.h" #include "client.h" +#define TAG FREERDP_TAG("core.client") + static void* g_pInterface; static CHANNEL_INIT_DATA g_ChannelInitData; @@ -715,7 +719,7 @@ int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, v if (channels->clientDataCount + 1 >= CHANNEL_MAX_COUNT) { - fprintf(stderr, "error: too many channels\n"); + WLog_ERR(TAG, "error: too many channels"); return 1; } @@ -754,7 +758,7 @@ int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, v if (!status) { - fprintf(stderr, "error: channel export function call failed\n"); + WLog_ERR(TAG, "error: channel export function call failed"); return 1; } diff --git a/libfreerdp/core/client.h b/libfreerdp/core/client.h index 532359033..3005b760b 100644 --- a/libfreerdp/core/client.h +++ b/libfreerdp/core/client.h @@ -30,7 +30,7 @@ #include #include #include -#include + #include #include #include diff --git a/libfreerdp/core/codecs.c b/libfreerdp/core/codecs.c new file mode 100644 index 000000000..a29024245 --- /dev/null +++ b/libfreerdp/core/codecs.c @@ -0,0 +1,223 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDP Codecs + * + * 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 "rdp.h" + +#include + +int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags) +{ + if (flags & FREERDP_CODEC_INTERLEAVED) + { + if (!codecs->interleaved) + { + codecs->interleaved = bitmap_interleaved_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_PLANAR) + { + if (!codecs->planar) + { + codecs->planar = freerdp_bitmap_planar_context_new(FALSE, 64, 64); + } + } + + if (flags & FREERDP_CODEC_NSCODEC) + { + if (!codecs->nsc) + { + codecs->nsc = nsc_context_new(); + } + } + + if (flags & FREERDP_CODEC_REMOTEFX) + { + if (!codecs->rfx) + { + codecs->rfx = rfx_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_CLEARCODEC) + { + if (!codecs->clear) + { + codecs->clear = clear_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_ALPHACODEC) + { + + } + + if (flags & FREERDP_CODEC_PROGRESSIVE) + { + if (!codecs->progressive) + { + codecs->progressive = progressive_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_H264) + { + if (!codecs->h264) + { + codecs->h264 = h264_context_new(FALSE); + } + } + + return 1; +} + +int freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) +{ + if (flags & FREERDP_CODEC_INTERLEAVED) + { + if (codecs->interleaved) + { + bitmap_interleaved_context_reset(codecs->interleaved); + } + } + + if (flags & FREERDP_CODEC_PLANAR) + { + if (codecs->planar) + { + freerdp_bitmap_planar_context_reset(codecs->planar); + } + } + + if (flags & FREERDP_CODEC_NSCODEC) + { + if (codecs->nsc) + { + nsc_context_reset(codecs->nsc); + } + } + + if (flags & FREERDP_CODEC_REMOTEFX) + { + if (codecs->rfx) + { + rfx_context_reset(codecs->rfx); + } + } + + if (flags & FREERDP_CODEC_CLEARCODEC) + { + if (codecs->clear) + { + clear_context_reset(codecs->clear); + } + } + + if (flags & FREERDP_CODEC_ALPHACODEC) + { + + } + + if (flags & FREERDP_CODEC_PROGRESSIVE) + { + if (codecs->progressive) + { + progressive_context_reset(codecs->progressive); + } + } + + if (flags & FREERDP_CODEC_H264) + { + if (codecs->h264) + { + h264_context_reset(codecs->h264); + } + } + + return 1; +} + +rdpCodecs* codecs_new(rdpContext* context) +{ + rdpCodecs* codecs; + + codecs = (rdpCodecs*) calloc(1, sizeof(rdpCodecs)); + + if (codecs) + { + codecs->context = context; + } + + return codecs; +} + +void codecs_free(rdpCodecs* codecs) +{ + if (!codecs) + return; + + if (codecs->rfx) + { + rfx_context_free(codecs->rfx); + codecs->rfx = NULL; + } + + if (codecs->nsc) + { + nsc_context_free(codecs->nsc); + codecs->nsc = NULL; + } + + if (codecs->h264) + { + h264_context_free(codecs->h264); + codecs->h264 = NULL; + } + + if (codecs->clear) + { + clear_context_free(codecs->clear); + codecs->clear = NULL; + } + + if (codecs->progressive) + { + progressive_context_free(codecs->progressive); + codecs->progressive = NULL; + } + + if (codecs->planar) + { + freerdp_bitmap_planar_context_free(codecs->planar); + codecs->planar = NULL; + } + + if (codecs->interleaved) + { + bitmap_interleaved_context_free(codecs->interleaved); + codecs->interleaved = NULL; + } + + free(codecs); +} + diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index dd1e5d125..8b2aaf844 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -30,36 +30,39 @@ #include +#include #include #include +#define TAG FREERDP_TAG("core.connection") + /** - * Connection Sequence\n - * client server\n - * | |\n - * |-----------------------X.224 Connection Request PDU--------------------->|\n - * |<----------------------X.224 Connection Confirm PDU----------------------|\n - * |-------MCS Connect-Initial PDU with GCC Conference Create Request------->|\n - * |<-----MCS Connect-Response PDU with GCC Conference Create Response-------|\n - * |------------------------MCS Erect Domain Request PDU-------------------->|\n - * |------------------------MCS Attach User Request PDU--------------------->|\n - * |<-----------------------MCS Attach User Confirm PDU----------------------|\n - * |------------------------MCS Channel Join Request PDU-------------------->|\n - * |<-----------------------MCS Channel Join Confirm PDU---------------------|\n - * |----------------------------Security Exchange PDU----------------------->|\n - * |-------------------------------Client Info PDU-------------------------->|\n - * |<---------------------License Error PDU - Valid Client-------------------|\n - * |<-----------------------------Demand Active PDU--------------------------|\n - * |------------------------------Confirm Active PDU------------------------>|\n - * |-------------------------------Synchronize PDU-------------------------->|\n - * |---------------------------Control PDU - Cooperate---------------------->|\n - * |------------------------Control PDU - Request Control------------------->|\n - * |--------------------------Persistent Key List PDU(s)-------------------->|\n - * |--------------------------------Font List PDU--------------------------->|\n - * |<------------------------------Synchronize PDU---------------------------|\n - * |<--------------------------Control PDU - Cooperate-----------------------|\n - * |<-----------------------Control PDU - Granted Control--------------------|\n - * |<-------------------------------Font Map PDU-----------------------------|\n + * Connection Sequence + * client server + * | | + * |-----------------------X.224 Connection Request PDU--------------------->| + * |<----------------------X.224 Connection Confirm PDU----------------------| + * |-------MCS Connect-Initial PDU with GCC Conference Create Request------->| + * |<-----MCS Connect-Response PDU with GCC Conference Create Response-------| + * |------------------------MCS Erect Domain Request PDU-------------------->| + * |------------------------MCS Attach User Request PDU--------------------->| + * |<-----------------------MCS Attach User Confirm PDU----------------------| + * |------------------------MCS Channel Join Request PDU-------------------->| + * |<-----------------------MCS Channel Join Confirm PDU---------------------| + * |----------------------------Security Exchange PDU----------------------->| + * |-------------------------------Client Info PDU-------------------------->| + * |<---------------------License Error PDU - Valid Client-------------------| + * |<-----------------------------Demand Active PDU--------------------------| + * |------------------------------Confirm Active PDU------------------------>| + * |-------------------------------Synchronize PDU-------------------------->| + * |---------------------------Control PDU - Cooperate---------------------->| + * |------------------------Control PDU - Request Control------------------->| + * |--------------------------Persistent Key List PDU(s)-------------------->| + * |--------------------------------Font List PDU--------------------------->| + * |<------------------------------Synchronize PDU---------------------------| + * |<--------------------------Control PDU - Cooperate-----------------------| + * |<-----------------------Control PDU - Granted Control--------------------| + * |<-------------------------------Font Map PDU-----------------------------| * */ @@ -266,7 +269,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED); } - fprintf(stderr, "Error: protocol security negotiation or connection failure\n"); + WLog_ERR(TAG, "Error: protocol security negotiation or connection failure"); return FALSE; } @@ -294,7 +297,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR); } - fprintf(stderr, "Error: unable to send MCS Connect Initial\n"); + WLog_ERR(TAG, "Error: unable to send MCS Connect Initial"); return FALSE; } @@ -388,11 +391,14 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) wStream* s; UINT32 length; UINT32 key_len; - BYTE *crypt_client_random = NULL; - BOOL ret = FALSE; int status = 0; + BOOL ret = FALSE; + rdpSettings* settings; + BYTE* crypt_client_random = NULL; - if (!rdp->settings->DisableEncryption) + settings = rdp->settings; + + if (!settings->DisableEncryption) { /* no RDP encryption */ return TRUE; @@ -400,27 +406,30 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) /* encrypt client random */ - if (rdp->settings->ClientRandom) - free(rdp->settings->ClientRandom); + if (settings->ClientRandom) + free(settings->ClientRandom); - rdp->settings->ClientRandom = malloc(CLIENT_RANDOM_LENGTH); + settings->ClientRandomLength = CLIENT_RANDOM_LENGTH; + settings->ClientRandom = malloc(settings->ClientRandomLength); - if (!rdp->settings->ClientRandom) + if (!settings->ClientRandom) return FALSE; + crypto_nonce(settings->ClientRandom, settings->ClientRandomLength); + key_len = settings->RdpServerCertificate->cert_info.ModulusLength; + mod = settings->RdpServerCertificate->cert_info.Modulus; + exp = settings->RdpServerCertificate->cert_info.exponent; - crypto_nonce(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH); - key_len = rdp->settings->RdpServerCertificate->cert_info.ModulusLength; - mod = rdp->settings->RdpServerCertificate->cert_info.Modulus; - exp = rdp->settings->RdpServerCertificate->cert_info.exponent; /* * client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1 * for details */ - crypt_client_random = calloc(1,key_len+8); + crypt_client_random = calloc(1, key_len + 8); + if (!crypt_client_random) return FALSE; - crypto_rsa_public_encrypt(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH, key_len, mod, exp, crypt_client_random); + + crypto_rsa_public_encrypt(settings->ClientRandom, settings->ClientRandomLength, key_len, mod, exp, crypt_client_random); /* send crypt client random to server */ length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8; @@ -441,33 +450,33 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) goto end; /* now calculate encrypt / decrypt and update keys */ - if (!security_establish_keys(rdp->settings->ClientRandom, rdp)) + if (!security_establish_keys(settings->ClientRandom, rdp)) goto end; rdp->do_crypt = TRUE; - if (rdp->settings->SaltedChecksum) + if (settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; - if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) + if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); if (!rdp->fips_encrypt) { - fprintf(stderr, "%s: unable to allocate des3 encrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate des3 encrypt key"); goto end; } rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec); if (!rdp->fips_decrypt) { - fprintf(stderr, "%s: unable to allocate des3 decrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate des3 decrypt key"); goto end; } rdp->fips_hmac = crypto_hmac_new(); if (!rdp->fips_hmac) { - fprintf(stderr, "%s: unable to allocate fips hmac\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate fips hmac"); goto end; } ret = TRUE; @@ -477,14 +486,14 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); goto end; } rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); goto end; } ret = TRUE; @@ -512,19 +521,19 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) if (!rdp_read_header(rdp, s, &length, &channel_id)) { - fprintf(stderr, "%s: invalid RDP header\n", __FUNCTION__); + WLog_ERR(TAG, "invalid RDP header"); return FALSE; } if (!rdp_read_security_header(s, &sec_flags)) { - fprintf(stderr, "%s: invalid security header\n", __FUNCTION__); + WLog_ERR(TAG, "invalid security header"); return FALSE; } if ((sec_flags & SEC_EXCHANGE_PKT) == 0) { - fprintf(stderr, "%s: missing SEC_EXCHANGE_PKT in security header\n", __FUNCTION__); + WLog_ERR(TAG, "missing SEC_EXCHANGE_PKT in security header"); return FALSE; } @@ -546,7 +555,7 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) if (rand_len != key_len + 8) { - fprintf(stderr, "%s: invalid encrypted client random length\n", __FUNCTION__); + WLog_ERR(TAG, "invalid encrypted client random length"); goto end2; } @@ -572,21 +581,21 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); if (!rdp->fips_encrypt) { - fprintf(stderr, "%s: unable to allocate des3 encrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate des3 encrypt key"); goto end; } rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec); if (!rdp->fips_decrypt) { - fprintf(stderr, "%s: unable to allocate des3 decrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate des3 decrypt key"); goto end; } rdp->fips_hmac = crypto_hmac_new(); if (!rdp->fips_hmac) { - fprintf(stderr, "%s: unable to allocate fips hmac\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate fips hmac"); goto end; } ret = TRUE; @@ -596,14 +605,14 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); goto end; } rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); goto end; } ret = TRUE; @@ -621,7 +630,7 @@ BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s) { if (!mcs_recv_connect_response(rdp->mcs, s)) { - fprintf(stderr, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed\n"); + WLog_ERR(TAG, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed"); return FALSE; } @@ -785,7 +794,7 @@ int rdp_client_connect_license(rdpRdp* rdp, wStream* s) if (rdp->license->state == LICENSE_STATE_ABORTED) { - fprintf(stderr, "license connection sequence aborted.\n"); + WLog_ERR(TAG, "license connection sequence aborted."); return -1; } @@ -964,15 +973,13 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) return FALSE; nego->selected_protocol = 0; - - fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n", - (nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, - (nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, - (nego->requested_protocols == PROTOCOL_RDP) ? 1 : 0 - ); - - fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n", - settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); + WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d", + (nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, + (nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, + (nego->requested_protocols == PROTOCOL_RDP) ? 1 : 0 + ); + WLog_INFO(TAG, "Server Security: NLA:%d TLS:%d RDP:%d", + settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); if ((settings->NlaSecurity) && (nego->requested_protocols & PROTOCOL_NLA)) { @@ -988,14 +995,14 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) } else { - fprintf(stderr, "Protocol security negotiation failure\n"); + WLog_ERR(TAG, "Protocol security negotiation failure"); } - fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n", - (nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, - (nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, - (nego->selected_protocol == PROTOCOL_RDP) ? 1: 0 - ); + WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d", + (nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, + (nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, + (nego->selected_protocol == PROTOCOL_RDP) ? 1: 0 + ); if (!nego_send_negotiation_response(nego)) return FALSE; @@ -1027,14 +1034,13 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s) if (!mcs_recv_connect_initial(mcs, s)) return FALSE; - fprintf(stderr, "Accepted client: %s\n", rdp->settings->ClientHostname); - fprintf(stderr, "Accepted channels:"); + WLog_INFO(TAG, "Accepted client: %s", rdp->settings->ClientHostname); + WLog_INFO(TAG, "Accepted channels:"); for (i = 0; i < mcs->channelCount; i++) { - fprintf(stderr, " %s", mcs->channels[i].Name); + WLog_INFO(TAG, " %s", mcs->channels[i].Name); } - fprintf(stderr, "\n"); if (!mcs_send_connect_response(mcs)) return FALSE; diff --git a/libfreerdp/core/errinfo.c b/libfreerdp/core/errinfo.c index 739dc18e4..0411ed067 100644 --- a/libfreerdp/core/errinfo.c +++ b/libfreerdp/core/errinfo.c @@ -23,8 +23,12 @@ #include +#include + #include "errinfo.h" +#define TAG FREERDP_TAG("core") + int connectErrorCode; /* Protocol-independent codes */ @@ -563,12 +567,12 @@ void rdp_print_errinfo(UINT32 code) { if (code == errInfo->code) { - fprintf(stderr, "%s (0x%08X):\n%s\n", errInfo->name, code, errInfo->info); + WLog_ERR(TAG, "%s (0x%08X):%s", errInfo->name, code, errInfo->info); return; } errInfo++; } - fprintf(stderr, "ERRINFO_UNKNOWN 0x%08X: Unknown error.\n", code); + WLog_ERR(TAG, "ERRINFO_UNKNOWN 0x%08X: Unknown error.", code); } diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 941a709f3..3f9019315 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -30,6 +30,7 @@ #include #include +#include #include #include "orders.h" @@ -38,6 +39,8 @@ #include "fastpath.h" #include "rdp.h" +#define TAG FREERDP_TAG("core.fastpath") + /** * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises * server output packets from the first byte with the goal of improving @@ -48,7 +51,6 @@ * two less significant bits of the first byte. */ -#define FASTPATH_MAX_PACKET_SIZE 0x3FFF #ifdef WITH_DEBUG_RDP static const char* const FASTPATH_UPDATETYPE_STRINGS[] = @@ -272,7 +274,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s case FASTPATH_UPDATETYPE_SYNCHRONIZE: if (!fastpath_recv_update_synchronize(fastpath, s)) - fprintf(stderr, "fastpath_recv_update_synchronize failure but we continue\n"); + WLog_ERR(TAG, "fastpath_recv_update_synchronize failure but we continue"); else IFCALL(update->Synchronize, context); break; @@ -317,7 +319,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s break; default: - DEBUG_WARN("unknown updateCode 0x%X", updateCode); + WLog_ERR(TAG, "unknown updateCode 0x%X", updateCode); break; } @@ -378,7 +380,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if (bulkStatus < 0) { - fprintf(stderr, "bulk_decompress() failed\n"); + WLog_ERR(TAG, "bulk_decompress() failed"); return -1; } @@ -399,7 +401,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) { if (fastpath->fragmentation != -1) { - fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_SINGLE\n"); + WLog_ERR(TAG, "Unexpected FASTPATH_FRAGMENT_SINGLE"); return -1; } @@ -415,7 +417,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) { if (fastpath->fragmentation != -1) { - fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_FIRST\n"); + WLog_ERR(TAG, "Unexpected FASTPATH_FRAGMENT_FIRST"); return -1; } @@ -425,8 +427,8 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if (totalSize > transport->settings->MultifragMaxRequestSize) { - fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n", - totalSize, transport->settings->MultifragMaxRequestSize); + WLog_ERR(TAG, "Total size (%d) exceeds MultifragMaxRequestSize (%d)", + totalSize, transport->settings->MultifragMaxRequestSize); return -1; } @@ -440,7 +442,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) && (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT)) { - fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_NEXT\n"); + WLog_ERR(TAG, "Unexpected FASTPATH_FRAGMENT_NEXT"); return -1; } @@ -450,8 +452,8 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if (totalSize > transport->settings->MultifragMaxRequestSize) { - fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n", - totalSize, transport->settings->MultifragMaxRequestSize); + WLog_ERR(TAG, "Total size (%d) exceeds MultifragMaxRequestSize (%d)", + totalSize, transport->settings->MultifragMaxRequestSize); return -1; } @@ -464,7 +466,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) && (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT)) { - fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_LAST\n"); + WLog_ERR(TAG, "Unexpected FASTPATH_FRAGMENT_LAST"); return -1; } @@ -474,8 +476,8 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) if (totalSize > transport->settings->MultifragMaxRequestSize) { - fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n", - totalSize, transport->settings->MultifragMaxRequestSize); + WLog_ERR(TAG, "Total size (%d) exceeds MultifragMaxRequestSize (%d)", + totalSize, transport->settings->MultifragMaxRequestSize); return -1; } @@ -662,7 +664,7 @@ static BOOL fastpath_recv_input_event(rdpFastPath* fastpath, wStream* s) break; default: - fprintf(stderr, "Unknown eventCode %d\n", eventCode); + WLog_ERR(TAG, "Unknown eventCode %d", eventCode); break; } @@ -769,7 +771,7 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu if (length >= (2 << 14)) { - fprintf(stderr, "Maximum FastPath PDU length is 32767\n"); + WLog_ERR(TAG, "Maximum FastPath PDU length is 32767"); return FALSE; } diff --git a/libfreerdp/core/fastpath.h b/libfreerdp/core/fastpath.h index af570f7b6..05e96422f 100644 --- a/libfreerdp/core/fastpath.h +++ b/libfreerdp/core/fastpath.h @@ -20,6 +20,22 @@ #ifndef __FASTPATH_H #define __FASTPATH_H +/* + * Fast-Path has 15 bits available for length information which would lead to a + * maximal pdu size of 0x8000. However in practice only 14 bits are used + * this isn't documented anywhere but it looks like most implementations will + * fail if fast-path packages > 0x3FFF arrive. + */ +#define FASTPATH_MAX_PACKET_SIZE 0x3FFF + +/* + * The following size guarantees that no fast-path PDU fragmentation occurs. + * It was calculated by subtracting 128 from FASTPATH_MAX_PACKET_SIZE. + * 128 was chosen because it includes all required and optional headers as well as + * possible paddings and some extra bytes for safety. + */ +#define FASTPATH_FRAGMENT_SAFE_SIZE 0x3F80 + typedef struct rdp_fastpath rdpFastPath; #include "rdp.h" @@ -92,7 +108,8 @@ enum FASTPATH_INPUT_EVENT_CODE enum FASTPATH_INPUT_KBDFLAGS { FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01, - FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02 + FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02, + FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 = 0x04 /* for pause sequence */ }; struct _FASTPATH_UPDATE_PDU_HEADER diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index f40bd6a28..395d59fb2 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -41,6 +41,9 @@ #include #include #include +#include + +#define TAG FREERDP_TAG("core") /* connectErrorCode is 'extern' in error.h. See comment there.*/ @@ -90,8 +93,7 @@ BOOL freerdp_connect(freerdp* instance) freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED); } - fprintf(stderr, "freerdp_pre_connect failed\n"); - + WLog_ERR(TAG, "freerdp_pre_connect failed"); goto freerdp_connect_finally; } @@ -100,7 +102,7 @@ BOOL freerdp_connect(freerdp* instance) /* --authonly tests the connection without a UI */ if (instance->settings->AuthenticationOnly) { - fprintf(stderr, "Authentication only, exit status %d\n", !status); + WLog_ERR(TAG, "Authentication only, exit status %d", !status); goto freerdp_connect_finally; } @@ -118,7 +120,7 @@ BOOL freerdp_connect(freerdp* instance) if (!status) { - fprintf(stderr, "freerdp_post_connect failed\n"); + WLog_ERR(TAG, "freerdp_post_connect failed"); if (!connectErrorCode) { @@ -317,6 +319,7 @@ BOOL freerdp_disconnect(freerdp* instance) rdp = instance->context->rdp; transport_disconnect(rdp->transport); + update_post_disconnect(instance->update); IFCALL(instance->PostDisconnect, instance); if (instance->update->pcap_rfx) @@ -355,6 +358,14 @@ FREERDP_API BOOL freerdp_focus_required(freerdp* instance) return bRetCode; } +void freerdp_set_focus(freerdp* instance) +{ + rdpRdp* rdp; + + rdp = instance->context->rdp; + rdp->resendFocus = TRUE; +} + void freerdp_get_version(int* major, int* minor, int* revision) { if (major != NULL) @@ -409,6 +420,7 @@ int freerdp_context_new(freerdp* instance) PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); context->metrics = metrics_new(context); + context->codecs = codecs_new(context); rdp = rdp_new(context); instance->input = rdp->input; @@ -464,6 +476,7 @@ void freerdp_context_free(freerdp* instance) PubSub_Free(instance->context->pubSub); metrics_free(instance->context->metrics); + codecs_free(instance->context->codecs); free(instance->context); instance->context = NULL; @@ -482,7 +495,7 @@ UINT32 freerdp_get_last_error(rdpContext* context) void freerdp_set_last_error(rdpContext* context, UINT32 lastError) { if (lastError) - fprintf(stderr, "freerdp_set_last_error 0x%04X\n", lastError); + WLog_ERR(TAG, "freerdp_set_last_error 0x%04X", lastError); context->LastError = lastError; } diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index 610b23091..4cef378c8 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -26,15 +26,19 @@ #include #include + + #ifdef HAVE_VALGRIND_MEMCHECK_H #include #endif #include "http.h" +#define TAG "gateway" + HttpContext* http_context_new() { - return (HttpContext *)calloc(1, sizeof(HttpContext)); + return (HttpContext*)calloc(1, sizeof(HttpContext)); } void http_context_set_method(HttpContext* http_context, char* method) @@ -165,13 +169,13 @@ char* http_encode_body_line(char* param, char* value) { char* line; int length; - length = strlen(param) + strlen(value) + 2; line = (char*) malloc(length + 1); + if (!line) return NULL; - sprintf_s(line, length + 1, "%s: %s", param, value); + sprintf_s(line, length + 1, "%s: %s", param, value); return line; } @@ -180,14 +184,14 @@ char* http_encode_content_length_line(int ContentLength) char* line; int length; char str[32]; - _itoa_s(ContentLength, str, sizeof(str), 10); length = strlen("Content-Length") + strlen(str) + 2; - line = (char *)malloc(length + 1); + line = (char*)malloc(length + 1); + if (!line) return NULL; - sprintf_s(line, length + 1, "Content-Length: %s", str); + sprintf_s(line, length + 1, "Content-Length: %s", str); return line; } @@ -195,13 +199,13 @@ char* http_encode_header_line(char* Method, char* URI) { char* line; int length; - length = strlen("HTTP/1.1") + strlen(Method) + strlen(URI) + 2; - line = (char *)malloc(length + 1); + line = (char*)malloc(length + 1); + if (!line) return NULL; - sprintf_s(line, length + 1, "%s %s HTTP/1.1", Method, URI); + sprintf_s(line, length + 1, "%s %s HTTP/1.1", Method, URI); return line; } @@ -209,25 +213,25 @@ char* http_encode_authorization_line(char* AuthScheme, char* AuthParam) { char* line; int length; - length = strlen("Authorization") + strlen(AuthScheme) + strlen(AuthParam) + 3; line = (char*) malloc(length + 1); + if (!line) return NULL; - sprintf_s(line, length + 1, "Authorization: %s %s", AuthScheme, AuthParam); + sprintf_s(line, length + 1, "Authorization: %s %s", AuthScheme, AuthParam); return line; } wStream* http_request_write(HttpContext* http_context, HttpRequest* http_request) { int i, count; - char **lines; + char** lines; wStream* s; int length = 0; - count = 9; - lines = (char **)calloc(count, sizeof(char *)); + lines = (char**)calloc(count, sizeof(char*)); + if (!lines) return NULL; @@ -250,12 +254,14 @@ wStream* http_request_write(HttpContext* http_context, HttpRequest* http_request if (http_request->Authorization != NULL) { lines[8] = http_encode_body_line("Authorization", http_request->Authorization); + if (!lines[8]) goto out_free; } else if ((http_request->AuthScheme != NULL) && (http_request->AuthParam != NULL)) { lines[8] = http_encode_authorization_line(http_request->AuthScheme, http_request->AuthParam); + if (!lines[8]) goto out_free; } @@ -264,10 +270,11 @@ wStream* http_request_write(HttpContext* http_context, HttpRequest* http_request { length += (strlen(lines[i]) + 2); /* add +2 for each '\r\n' character */ } + length += 2; /* empty line "\r\n" at end of header */ length += 1; /* null terminator */ - s = Stream_New(NULL, length); + if (!s) goto out_free; @@ -277,21 +284,21 @@ wStream* http_request_write(HttpContext* http_context, HttpRequest* http_request Stream_Write(s, "\r\n", 2); free(lines[i]); } + Stream_Write(s, "\r\n", 2); - free(lines); - Stream_Write(s, "\0", 1); /* append null terminator */ Stream_Rewind(s, 1); /* don't include null terminator in length */ Stream_Length(s) = Stream_GetPosition(s); return s; - out_free: + for (i = 0; i < 9; i++) { if (lines[i]) free(lines[i]); } + free(lines); return NULL; } @@ -308,10 +315,13 @@ void http_request_free(HttpRequest* http_request) if (http_request->AuthParam) free(http_request->AuthParam); + if (http_request->AuthScheme) free(http_request->AuthScheme); + if (http_request->Authorization) free(http_request->Authorization); + free(http_request->Content); free(http_request->Method); free(http_request->URI); @@ -323,22 +333,25 @@ BOOL http_response_parse_header_status_line(HttpResponse* http_response, char* s char* separator; char* status_code; char* reason_phrase; - separator = strchr(status_line, ' '); + if (!separator) return FALSE; + status_code = separator + 1; - separator = strchr(status_code, ' '); + if (!separator) return FALSE; - reason_phrase = separator + 1; + reason_phrase = separator + 1; *separator = '\0'; http_response->StatusCode = atoi(status_code); http_response->ReasonPhrase = _strdup(reason_phrase); + if (!http_response->ReasonPhrase) return FALSE; + *separator = ' '; return TRUE; } @@ -352,8 +365,7 @@ BOOL http_response_parse_header_field(HttpResponse* http_response, char* name, c else if (_stricmp(name, "WWW-Authenticate") == 0) { char* separator; - char *authScheme, *authValue; - + char* authScheme, *authValue; separator = strchr(value, ' '); if (separator != NULL) @@ -365,23 +377,27 @@ BOOL http_response_parse_header_field(HttpResponse* http_response, char* name, c * opaque="5ccc069c403ebaf9f0171e9517f40e41" */ *separator = '\0'; - authScheme = _strdup(value); authValue = _strdup(separator + 1); + if (!authScheme || !authValue) return FALSE; + *separator = ' '; } else { authScheme = _strdup(value); + if (!authScheme) return FALSE; + authValue = NULL; } return ListDictionary_Add(http_response->Authenticates, authScheme, authValue); } + return TRUE; } @@ -408,7 +424,6 @@ BOOL http_response_parse_header(HttpResponse* http_response) for (count = 1; count < http_response->count; count++) { line = http_response->lines[count]; - /** * name end_of_header * | | @@ -419,21 +434,24 @@ BOOL http_response_parse_header(HttpResponse* http_response) * colon_pos value */ colon_pos = strchr(line, ':'); + if ((colon_pos == NULL) || (colon_pos == line)) return FALSE; /* retrieve the position just after header name */ - for(end_of_header = colon_pos; end_of_header != line; end_of_header--) + for (end_of_header = colon_pos; end_of_header != line; end_of_header--) { c = end_of_header[-1]; + if (c != ' ' && c != '\t' && c != ':') break; } + if (end_of_header == line) return FALSE; + end_of_header_char = *end_of_header; *end_of_header = '\0'; - name = line; /* eat space and tabs before header value */ @@ -448,6 +466,7 @@ BOOL http_response_parse_header(HttpResponse* http_response) *end_of_header = end_of_header_char; } + return TRUE; } @@ -457,9 +476,8 @@ void http_response_print(HttpResponse* http_response) for (i = 0; i < http_response->count; i++) { - fprintf(stderr, "%s\n", http_response->lines[i]); + WLog_ERR(TAG, "%s", http_response->lines[i]); } - fprintf(stderr, "\n"); } HttpResponse* http_response_recv(rdpTls* tls) @@ -472,15 +490,16 @@ HttpResponse* http_response_recv(rdpTls* tls) char* content; char* header_end; HttpResponse* http_response; - nbytes = 0; length = 10000; content = NULL; buffer = calloc(length, 1); + if (!buffer) return NULL; http_response = http_response_new(); + if (!http_response) goto out_free; @@ -492,7 +511,7 @@ HttpResponse* http_response_recv(rdpTls* tls) while (nbytes < 5) { status = BIO_read(tls->bio, p, length - nbytes); - + if (status <= 0) { if (!BIO_should_retry(tls->bio)) @@ -510,11 +529,11 @@ HttpResponse* http_response_recv(rdpTls* tls) } header_end = strstr((char*) buffer, "\r\n\r\n"); - + if (!header_end) { - fprintf(stderr, "%s: invalid response:\n", __FUNCTION__); - winpr_HexDump(buffer, status); + WLog_ERR(TAG, "invalid response:"); + winpr_HexDump(TAG, WLOG_ERROR, buffer, status); goto out_error; } @@ -524,11 +543,9 @@ HttpResponse* http_response_recv(rdpTls* tls) { int count; char* line; - header_end[0] = '\0'; header_end[1] = '\0'; content = header_end + 2; - count = 0; line = (char*) buffer; @@ -539,9 +556,11 @@ HttpResponse* http_response_recv(rdpTls* tls) } http_response->count = count; + if (count) { - http_response->lines = (char **)calloc(http_response->count, sizeof(char *)); + http_response->lines = (char**)calloc(http_response->count, sizeof(char*)); + if (!http_response->lines) goto out_error; } @@ -552,6 +571,7 @@ HttpResponse* http_response_recv(rdpTls* tls) while (line != NULL) { http_response->lines[count] = _strdup(line); + if (!http_response->lines[count]) goto out_error; @@ -562,10 +582,12 @@ HttpResponse* http_response_recv(rdpTls* tls) if (!http_response_parse_header(http_response)) goto out_error; - http_response->bodyLen = nbytes - (content - (char *)buffer); + http_response->bodyLen = nbytes - (content - (char*)buffer); + if (http_response->bodyLen > 0) { - http_response->BodyContent = (BYTE *)malloc(http_response->bodyLen); + http_response->BodyContent = (BYTE*)malloc(http_response->bodyLen); + if (!http_response->BodyContent) goto out_error; @@ -584,9 +606,7 @@ HttpResponse* http_response_recv(rdpTls* tls) } free(buffer); - return http_response; - out_error: http_response_free(http_response); out_free: @@ -594,7 +614,7 @@ out_free: return NULL; } -static BOOL strings_equals_nocase(void *obj1, void *obj2) +static BOOL strings_equals_nocase(void* obj1, void* obj2) { if (!obj1 || !obj2) return FALSE; @@ -602,16 +622,18 @@ static BOOL strings_equals_nocase(void *obj1, void *obj2) return _stricmp(obj1, obj2) == 0; } -static void string_free(void *obj1) +static void string_free(void* obj1) { if (!obj1) return; + free(obj1); } HttpResponse* http_response_new() { - HttpResponse *ret = (HttpResponse *)calloc(1, sizeof(HttpResponse)); + HttpResponse* ret = (HttpResponse*)calloc(1, sizeof(HttpResponse)); + if (!ret) return NULL; @@ -634,9 +656,7 @@ void http_response_free(HttpResponse* http_response) free(http_response->lines[i]); free(http_response->lines); - free(http_response->ReasonPhrase); - ListDictionary_Free(http_response->Authenticates); if (http_response->ContentLength > 0) diff --git a/libfreerdp/core/gateway/ncacn_http.h b/libfreerdp/core/gateway/ncacn_http.h index 9c1d54ce1..e01a7d368 100644 --- a/libfreerdp/core/gateway/ncacn_http.h +++ b/libfreerdp/core/gateway/ncacn_http.h @@ -26,7 +26,7 @@ #include #include -#include + #include diff --git a/libfreerdp/core/gateway/ntlm.c b/libfreerdp/core/gateway/ntlm.c index 549726ca4..eeb2500f6 100644 --- a/libfreerdp/core/gateway/ntlm.c +++ b/libfreerdp/core/gateway/ntlm.c @@ -31,12 +31,15 @@ #include #include +#include #include #include "http.h" #include "ntlm.h" +#define TAG FREERDP_TAG("core.gateway.ntlm") + BOOL ntlm_client_init(rdpNtlm* ntlm, BOOL http, char* user, char* domain, char* password, SecPkgContext_Bindings* Bindings) { SECURITY_STATUS status; @@ -71,7 +74,7 @@ BOOL ntlm_client_init(rdpNtlm* ntlm, BOOL http, char* user, char* domain, char* if (status != SEC_E_OK) { - fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status); + WLog_ERR(TAG, "QuerySecurityPackageInfo status: 0x%08X", status); return FALSE; } @@ -82,7 +85,7 @@ BOOL ntlm_client_init(rdpNtlm* ntlm, BOOL http, char* user, char* domain, char* if (status != SEC_E_OK) { - fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status); + WLog_ERR(TAG, "AcquireCredentialsHandle status: 0x%08X", status); return FALSE; } @@ -235,7 +238,7 @@ BOOL ntlm_authenticate(rdpNtlm* ntlm) if ((!ntlm) || (!ntlm->table)) { - fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n"); + WLog_ERR(TAG, "ntlm_authenticate: invalid ntlm context"); return FALSE; } @@ -254,7 +257,7 @@ BOOL ntlm_authenticate(rdpNtlm* ntlm) if (ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_SIZES, &ntlm->ContextSizes) != SEC_E_OK) { - fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n"); + WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure"); return FALSE; } diff --git a/libfreerdp/core/gateway/ntlm.h b/libfreerdp/core/gateway/ntlm.h index 257e84b05..ebe8c8bc2 100644 --- a/libfreerdp/core/gateway/ntlm.h +++ b/libfreerdp/core/gateway/ntlm.h @@ -37,7 +37,7 @@ typedef struct rdp_ntlm_http rdpNtlmHttp; #include #include #include -#include + #include #include diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index ad177fe65..0dbb4efd9 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include @@ -48,10 +50,12 @@ #include "rpc.h" +#define TAG FREERDP_TAG("core.gateway.rpc") + /* Security Verification Trailer Signature */ rpc_sec_verification_trailer RPC_SEC_VERIFICATION_TRAILER = - { { 0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71 } }; +{ { 0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71 } }; static char* PTYPE_STRINGS[] = { @@ -92,45 +96,51 @@ const RPC_SECURITY_PROVIDER_INFO RPC_SECURITY_PROVIDER_INFO_TABLE[] = void rpc_pdu_header_print(rpcconn_hdr_t* header) { - fprintf(stderr, "rpc_vers: %d\n", header->common.rpc_vers); - fprintf(stderr, "rpc_vers_minor: %d\n", header->common.rpc_vers_minor); + WLog_INFO(TAG, "rpc_vers: %d", header->common.rpc_vers); + WLog_INFO(TAG, "rpc_vers_minor: %d", header->common.rpc_vers_minor); if (header->common.ptype > PTYPE_RTS) - fprintf(stderr, "ptype: %s (%d)\n", "PTYPE_UNKNOWN", header->common.ptype); + WLog_INFO(TAG, "ptype: %s (%d)", "PTYPE_UNKNOWN", header->common.ptype); else - fprintf(stderr, "ptype: %s (%d)\n", PTYPE_STRINGS[header->common.ptype], header->common.ptype); + WLog_INFO(TAG, "ptype: %s (%d)", PTYPE_STRINGS[header->common.ptype], header->common.ptype); + + WLog_INFO(TAG, "pfc_flags (0x%02X) = {", header->common.pfc_flags); - fprintf(stderr, "pfc_flags (0x%02X) = {", header->common.pfc_flags); if (header->common.pfc_flags & PFC_FIRST_FRAG) - fprintf(stderr, " PFC_FIRST_FRAG"); + WLog_INFO(TAG, " PFC_FIRST_FRAG"); + if (header->common.pfc_flags & PFC_LAST_FRAG) - fprintf(stderr, " PFC_LAST_FRAG"); + WLog_INFO(TAG, " PFC_LAST_FRAG"); + if (header->common.pfc_flags & PFC_PENDING_CANCEL) - fprintf(stderr, " PFC_PENDING_CANCEL"); + WLog_INFO(TAG, " PFC_PENDING_CANCEL"); + if (header->common.pfc_flags & PFC_RESERVED_1) - fprintf(stderr, " PFC_RESERVED_1"); + WLog_INFO(TAG, " PFC_RESERVED_1"); + if (header->common.pfc_flags & PFC_CONC_MPX) - fprintf(stderr, " PFC_CONC_MPX"); + WLog_INFO(TAG, " PFC_CONC_MPX"); + if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE) - fprintf(stderr, " PFC_DID_NOT_EXECUTE"); + WLog_INFO(TAG, " PFC_DID_NOT_EXECUTE"); + if (header->common.pfc_flags & PFC_OBJECT_UUID) - fprintf(stderr, " PFC_OBJECT_UUID"); - fprintf(stderr, " }\n"); + WLog_INFO(TAG, " PFC_OBJECT_UUID"); - fprintf(stderr, "packed_drep[4]: %02X %02X %02X %02X\n", - header->common.packed_drep[0], header->common.packed_drep[1], - header->common.packed_drep[2], header->common.packed_drep[3]); - - fprintf(stderr, "frag_length: %d\n", header->common.frag_length); - fprintf(stderr, "auth_length: %d\n", header->common.auth_length); - fprintf(stderr, "call_id: %d\n", header->common.call_id); + WLog_INFO(TAG, " }"); + WLog_INFO(TAG, "packed_drep[4]: %02X %02X %02X %02X", + header->common.packed_drep[0], header->common.packed_drep[1], + header->common.packed_drep[2], header->common.packed_drep[3]); + WLog_INFO(TAG, "frag_length: %d", header->common.frag_length); + WLog_INFO(TAG, "auth_length: %d", header->common.auth_length); + WLog_INFO(TAG, "call_id: %d", header->common.call_id); if (header->common.ptype == PTYPE_RESPONSE) { - fprintf(stderr, "alloc_hint: %d\n", header->response.alloc_hint); - fprintf(stderr, "p_cont_id: %d\n", header->response.p_cont_id); - fprintf(stderr, "cancel_count: %d\n", header->response.cancel_count); - fprintf(stderr, "reserved: %d\n", header->response.reserved); + WLog_INFO(TAG, "alloc_hint: %d", header->response.alloc_hint); + WLog_INFO(TAG, "p_cont_id: %d", header->response.p_cont_id); + WLog_INFO(TAG, "cancel_count: %d", header->response.cancel_count); + WLog_INFO(TAG, "reserved: %d", header->response.reserved); } } @@ -147,11 +157,9 @@ void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header) UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment) { UINT32 pad; - pad = *offset; *offset = (*offset + alignment - 1) & ~(alignment - 1); pad = *offset - pad; - return pad; } @@ -245,7 +253,6 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l UINT32 auth_pad_length; UINT32 sec_trailer_offset; rpc_sec_trailer* sec_trailer; - *offset = RPC_COMMON_FIELDS_LENGTH; header = ((rpcconn_hdr_t*) buffer); @@ -265,7 +272,7 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l *offset += 4; break; default: - fprintf(stderr, "%s: unknown ptype=0x%x\n", __FUNCTION__, header->common.ptype); + WLog_ERR(TAG, "unknown ptype=0x%x", header->common.ptype); return FALSE; } @@ -275,27 +282,23 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l if (header->common.ptype == PTYPE_REQUEST) { UINT32 sec_trailer_offset; - sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8; *length = sec_trailer_offset - *offset; return TRUE; } - frag_length = header->common.frag_length; auth_length = header->common.auth_length; - sec_trailer_offset = frag_length - auth_length - 8; sec_trailer = (rpc_sec_trailer*) &buffer[sec_trailer_offset]; auth_pad_length = sec_trailer->auth_pad_length; - #if 0 - fprintf(stderr, "sec_trailer: type: %d level: %d pad_length: %d reserved: %d context_id: %d\n", - sec_trailer->auth_type, - sec_trailer->auth_level, - sec_trailer->auth_pad_length, - sec_trailer->auth_reserved, - sec_trailer->auth_context_id); + WLog_DBG(TAG, "sec_trailer: type: %d level: %d pad_length: %d reserved: %d context_id: %d", + sec_trailer->auth_type, + sec_trailer->auth_level, + sec_trailer->auth_pad_length, + sec_trailer->auth_reserved, + sec_trailer->auth_context_id); #endif /** @@ -306,8 +309,8 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l if ((frag_length - (sec_trailer_offset + 8)) != auth_length) { - fprintf(stderr, "invalid auth_length: actual: %d, expected: %d\n", auth_length, - (frag_length - (sec_trailer_offset + 8))); + WLog_ERR(TAG, "invalid auth_length: actual: %d, expected: %d", auth_length, + (frag_length - (sec_trailer_offset + 8))); } *length = frag_length - auth_length - 24 - 8 - auth_pad_length; @@ -317,10 +320,10 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l int rpc_out_read(rdpRpc* rpc, BYTE* data, int length) { int status; - status = BIO_read(rpc->TlsOut->bio, data, length); - if (status > 0) { + if (status > 0) + { #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(data, status); #endif @@ -336,25 +339,19 @@ int rpc_out_read(rdpRpc* rpc, BYTE* data, int length) int rpc_out_write(rdpRpc* rpc, const BYTE* data, int length) { int status; - status = tls_write_all(rpc->TlsOut, data, length); - return status; } int rpc_in_write(rdpRpc* rpc, const BYTE* data, int length) { int status; - #ifdef WITH_DEBUG_TSG - fprintf(stderr, "Sending PDU (length: %d)\n", length); + WLog_DBG(TAG, "Sending PDU (length: %d)", length); rpc_pdu_header_print((rpcconn_hdr_t*) data); - winpr_HexDump(data, length); - fprintf(stderr, "\n"); + winpr_HexDump(TAG, WLOG_DEBUG, data, length); #endif - status = tls_write_all(rpc->TlsIn, data, length); - return status; } @@ -369,27 +366,26 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) RpcClientCall* clientCall; SECURITY_STATUS encrypt_status; rpcconn_request_hdr_t* request_pdu; - ntlm = rpc->ntlm; if (!ntlm || !ntlm->table) { - fprintf(stderr, "%s: invalid ntlm context\n", __FUNCTION__); + WLog_ERR(TAG, "invalid ntlm context"); return -1; } if (ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_SIZES, &ntlm->ContextSizes) != SEC_E_OK) { - fprintf(stderr, "%s: QueryContextAttributes SECPKG_ATTR_SIZES failure\n", __FUNCTION__); + WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure"); return -1; } request_pdu = (rpcconn_request_hdr_t*) calloc(1, sizeof(rpcconn_request_hdr_t)); + if (!request_pdu) return -1; rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) request_pdu); - request_pdu->ptype = PTYPE_REQUEST; request_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; request_pdu->auth_length = (UINT16) ntlm->ContextSizes.cbMaxSignature; @@ -397,8 +393,8 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) request_pdu->alloc_hint = length; request_pdu->p_cont_id = 0x0000; request_pdu->opnum = opnum; - clientCall = rpc_client_call_new(request_pdu->call_id, request_pdu->opnum); + if (!clientCall) goto out_free_pdu; @@ -409,11 +405,9 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) rpc->PipeCallId = request_pdu->call_id; request_pdu->stub_data = data; - offset = 24; stub_data_pad = 0; stub_data_pad = rpc_offset_align(&offset, 8); - offset += length; request_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4); request_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT; @@ -421,42 +415,38 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) request_pdu->auth_verifier.auth_reserved = 0x00; request_pdu->auth_verifier.auth_context_id = 0x00000000; offset += (8 + request_pdu->auth_length); - request_pdu->frag_length = offset; - buffer = (BYTE*) calloc(1, request_pdu->frag_length); + if (!buffer) goto out_free_pdu; - CopyMemory(buffer, request_pdu, 24); + CopyMemory(buffer, request_pdu, 24); offset = 24; rpc_offset_pad(&offset, stub_data_pad); CopyMemory(&buffer[offset], request_pdu->stub_data, length); offset += length; - rpc_offset_pad(&offset, request_pdu->auth_verifier.auth_pad_length); CopyMemory(&buffer[offset], &request_pdu->auth_verifier.auth_type, 8); offset += 8; - Buffers[0].BufferType = SECBUFFER_DATA; /* auth_data */ Buffers[1].BufferType = SECBUFFER_TOKEN; /* signature */ - Buffers[0].pvBuffer = buffer; Buffers[0].cbBuffer = offset; - Buffers[1].cbBuffer = ntlm->ContextSizes.cbMaxSignature; Buffers[1].pvBuffer = calloc(1, Buffers[1].cbBuffer); + if (!Buffers[1].pvBuffer) return -1; Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; - encrypt_status = ntlm->table->EncryptMessage(&ntlm->context, 0, &Message, rpc->SendSeqNum++); + if (encrypt_status != SEC_E_OK) { - fprintf(stderr, "EncryptMessage status: 0x%08X\n", encrypt_status); + WLog_ERR(TAG, "EncryptMessage status: 0x%08X", encrypt_status); free(request_pdu); return -1; } @@ -469,9 +459,7 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) length = -1; free(request_pdu); - return length; - out_free_clientCall: rpc_client_call_free(clientCall); out_free_pdu: @@ -486,7 +474,7 @@ BOOL rpc_connect(rdpRpc* rpc) if (!rts_connect(rpc)) { - fprintf(stderr, "rts_connect error!\n"); + WLog_ERR(TAG, "rts_connect error!"); return FALSE; } @@ -494,7 +482,7 @@ BOOL rpc_connect(rdpRpc* rpc) if (rpc_secure_bind(rpc) != 0) { - fprintf(stderr, "rpc_secure_bind error!\n"); + WLog_ERR(TAG, "rpc_secure_bind error!"); return FALSE; } @@ -509,7 +497,6 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne connection->DefaultInChannel->PingOriginator.ConnectionTimeout = 30; connection->DefaultInChannel->PingOriginator.KeepAliveInterval = 0; connection->DefaultInChannel->Mutex = CreateMutex(NULL, FALSE, NULL); - connection->DefaultOutChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL; connection->DefaultOutChannel->BytesReceived = 0; connection->DefaultOutChannel->ReceiverAvailableWindow = rpc->ReceiveWindow; @@ -527,16 +514,18 @@ RpcVirtualConnection* rpc_client_virtual_connection_new(rdpRpc* rpc) return NULL; connection->State = VIRTUAL_CONNECTION_STATE_INITIAL; - connection->DefaultInChannel = (RpcInChannel *)calloc(1, sizeof(RpcInChannel)); + connection->DefaultInChannel = (RpcInChannel*)calloc(1, sizeof(RpcInChannel)); + if (!connection->DefaultInChannel) goto out_free; + connection->DefaultOutChannel = (RpcOutChannel*)calloc(1, sizeof(RpcOutChannel)); + if (!connection->DefaultOutChannel) goto out_default_in; + rpc_client_virtual_connection_init(rpc, connection); - return connection; - out_default_in: free(connection->DefaultInChannel); out_free: @@ -557,60 +546,56 @@ void rpc_client_virtual_connection_free(RpcVirtualConnection* virtual_connection rdpRpc* rpc_new(rdpTransport* transport) { rdpRpc* rpc = (rdpRpc*) calloc(1, sizeof(rdpRpc)); + if (!rpc) return NULL; rpc->State = RPC_CLIENT_STATE_INITIAL; - rpc->transport = transport; rpc->settings = transport->settings; - rpc->SendSeqNum = 0; rpc->ntlm = ntlm_new(); + if (!rpc->ntlm) goto out_free; rpc->NtlmHttpIn = ntlm_http_new(); + if (!rpc->NtlmHttpIn) goto out_free_ntlm; + rpc->NtlmHttpOut = ntlm_http_new(); + if (!rpc->NtlmHttpOut) goto out_free_ntlm_http_in; rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpIn, TSG_CHANNEL_IN); rpc_ntlm_http_init_channel(rpc, rpc->NtlmHttpOut, TSG_CHANNEL_OUT); - rpc->PipeCallId = 0; - rpc->StubCallId = 0; rpc->StubFragCount = 0; - rpc->rpc_vers = 5; rpc->rpc_vers_minor = 0; - /* little-endian data representation */ rpc->packed_drep[0] = 0x10; rpc->packed_drep[1] = 0x00; rpc->packed_drep[2] = 0x00; rpc->packed_drep[3] = 0x00; - rpc->max_xmit_frag = 0x0FF8; rpc->max_recv_frag = 0x0FF8; - rpc->ReceiveWindow = 0x00010000; - rpc->ChannelLifetime = 0x40000000; rpc->ChannelLifetimeSet = 0; - rpc->KeepAliveInterval = 300000; rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval; rpc->CurrentKeepAliveTime = 0; - rpc->VirtualConnection = rpc_client_virtual_connection_new(rpc); + if (!rpc->VirtualConnection) goto out_free_ntlm_http_out; rpc->VirtualConnectionCookieTable = ArrayList_New(TRUE); + if (!rpc->VirtualConnectionCookieTable) goto out_free_virtual_connection; @@ -621,9 +606,7 @@ rdpRpc* rpc_new(rdpTransport* transport) rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; - return rpc; - out_free_virtualConnectionCookieTable: rpc_client_free(rpc); ArrayList_Free(rpc->VirtualConnectionCookieTable); @@ -653,10 +636,8 @@ void rpc_free(rdpRpc* rpc) } rpc_client_virtual_connection_free(rpc->VirtualConnection); - ArrayList_Clear(rpc->VirtualConnectionCookieTable); ArrayList_Free(rpc->VirtualConnectionCookieTable); - free(rpc); } } diff --git a/libfreerdp/core/gateway/rpc.h b/libfreerdp/core/gateway/rpc.h index c86a8618f..f201aae73 100644 --- a/libfreerdp/core/gateway/rpc.h +++ b/libfreerdp/core/gateway/rpc.h @@ -26,6 +26,7 @@ #include #include #include +#include typedef struct rdp_rpc rdpRpc; @@ -76,7 +77,7 @@ typedef struct _RPC_PDU #include #include #include -#include + #include /** @@ -786,10 +787,11 @@ void rpc_free(rdpRpc* rpc); #define WITH_DEBUG_RPC #endif +#define RPC_TAG FREERDP_TAG("core.gateway.rpc") #ifdef WITH_DEBUG_RPC -#define DEBUG_RPC(fmt, ...) DEBUG_CLASS(RPC, fmt, ## __VA_ARGS__) +#define DEBUG_RPC(fmt, ...) WLog_DBG(RPC_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_RPC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_RPC(fmt, ...) do { } while (0) #endif #endif /* FREERDP_CORE_RPC_H */ diff --git a/libfreerdp/core/gateway/rpc_bind.c b/libfreerdp/core/gateway/rpc_bind.c index ceae95159..82745d859 100644 --- a/libfreerdp/core/gateway/rpc_bind.c +++ b/libfreerdp/core/gateway/rpc_bind.c @@ -26,11 +26,14 @@ #include #include +#include #include "rpc_client.h" #include "rpc_bind.h" +#define TAG FREERDP_TAG("core.gateway.rpc_bind") + /** * Connection-Oriented RPC Protocol Client Details: * http://msdn.microsoft.com/en-us/library/cc243724/ @@ -391,7 +394,7 @@ int rpc_secure_bind(rdpRpc* rpc) if (status <= 0) { - fprintf(stderr, "rpc_secure_bind: error sending bind pdu!\n"); + WLog_ERR(TAG, "rpc_secure_bind: error sending bind pdu!"); return -1; } @@ -403,13 +406,13 @@ int rpc_secure_bind(rdpRpc* rpc) if (!pdu) { - fprintf(stderr, "rpc_secure_bind: error receiving bind ack pdu!\n"); + WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!"); return -1; } if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0) { - fprintf(stderr, "rpc_secure_bind: error receiving bind ack pdu!\n"); + WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!"); return -1; } @@ -417,7 +420,7 @@ int rpc_secure_bind(rdpRpc* rpc) if (rpc_send_rpc_auth_3_pdu(rpc) <= 0) { - fprintf(stderr, "rpc_secure_bind: error sending rpc_auth_3 pdu!\n"); + WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!"); return -1; } @@ -425,7 +428,7 @@ int rpc_secure_bind(rdpRpc* rpc) } else { - fprintf(stderr, "rpc_secure_bind: invalid state: %d\n", rpc->State); + WLog_ERR(TAG, "rpc_secure_bind: invalid state: %d", rpc->State); return -1; } } diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index c3613f6be..9cedda0ec 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -37,6 +38,7 @@ #include "rpc_client.h" #include "../rdp.h" +#define TAG FREERDP_TAG("core.gateway") #define SYNCHRONOUS_TIMEOUT 5000 wStream* rpc_client_fragment_pool_take(rdpRpc* rpc) @@ -67,10 +69,13 @@ RPC_PDU* rpc_client_receive_pool_take(rdpRpc* rpc) if (!pdu) { - pdu = (RPC_PDU *)malloc(sizeof(RPC_PDU)); + pdu = (RPC_PDU*)malloc(sizeof(RPC_PDU)); + if (!pdu) return NULL; + pdu->s = Stream_New(NULL, rpc->max_recv_frag); + if (!pdu->s) { free(pdu); @@ -80,10 +85,8 @@ RPC_PDU* rpc_client_receive_pool_take(rdpRpc* rpc) pdu->CallId = 0; pdu->Flags = 0; - Stream_Length(pdu->s) = 0; Stream_SetPosition(pdu->s, 0); - return pdu; } @@ -100,14 +103,12 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) wStream* fragment; rpcconn_hdr_t* header; freerdp* instance; - - instance = (freerdp *)rpc->transport->settings->instance; + instance = (freerdp*)rpc->transport->settings->instance; if (!rpc->client->pdu) rpc->client->pdu = rpc_client_receive_pool_take(rpc); fragment = Queue_Dequeue(rpc->client->FragmentQueue); - buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); @@ -115,33 +116,30 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) { rpc->client->pdu->Flags = 0; rpc->client->pdu->CallId = header->common.call_id; - Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment)); Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment)); Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); - rpc_client_fragment_pool_return(rpc, fragment); - Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); SetEvent(rpc->transport->ReceiveEvent); rpc->client->pdu = NULL; - return 0; } switch (header->common.ptype) { case PTYPE_RTS: + if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED) { - fprintf(stderr, "%s: warning: unhandled RTS PDU\n", __FUNCTION__); + WLog_ERR(TAG, "warning: unhandled RTS PDU"); return 0; } - fprintf(stderr, "%s: Receiving Out-of-Sequence RTS PDU\n", __FUNCTION__); + + WLog_ERR(TAG, "Receiving Out-of-Sequence RTS PDU"); rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length); rpc_client_fragment_pool_return(rpc, fragment); return 0; - case PTYPE_FAULT: rpc_recv_fault_pdu(header); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); @@ -149,7 +147,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) case PTYPE_RESPONSE: break; default: - fprintf(stderr, "%s: unexpected RPC PDU type %d\n", __FUNCTION__, header->common.ptype); + WLog_ERR(TAG, "unexpected RPC PDU type %d", header->common.ptype); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); return -1; } @@ -159,24 +157,22 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength)) { - fprintf(stderr, "%s: expected stub\n", __FUNCTION__); + WLog_ERR(TAG, "expected stub"); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); return -1; } if (StubLength == 4) { - //fprintf(stderr, "Ignoring TsProxySendToServer Response\n"); - //printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id); + //WLog_ERR(TAG, "Ignoring TsProxySendToServer Response"); + //WLog_DBG(TAG, "Got stub length 4 with flags %d and callid %d", header->common.pfc_flags, header->common.call_id); /* received a disconnect request from the server? */ if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG)) { TerminateEventArgs e; - instance->context->rdp->disconnect = TRUE; rpc->transport->tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING; - EventArgsInit(&e, "freerdp"); e.code = 0; PubSub_OnTerminate(instance->context->pubSub, instance->context, &e); @@ -195,18 +191,17 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) if (rpc->StubCallId != header->common.call_id) { - fprintf(stderr, "%s: invalid call_id: actual: %d, expected: %d, frag_count: %d\n", __FUNCTION__, - rpc->StubCallId, header->common.call_id, rpc->StubFragCount); + WLog_ERR(TAG, "invalid call_id: actual: %d, expected: %d, frag_count: %d", + rpc->StubCallId, header->common.call_id, rpc->StubFragCount); } Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength); rpc->StubFragCount++; - rpc_client_fragment_pool_return(rpc, fragment); if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { - //fprintf(stderr, "Sending Flow Control Ack PDU\n"); + //WLog_ERR(TAG, "Sending Flow Control Ack PDU"); rts_send_flow_control_ack_pdu(rpc); } @@ -220,16 +215,11 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) { rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB; rpc->client->pdu->CallId = rpc->StubCallId; - Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); - rpc->StubFragCount = 0; rpc->StubCallId = 0; - Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); - rpc->client->pdu = NULL; - return 0; } @@ -252,11 +242,11 @@ int rpc_client_on_read_event(rdpRpc* rpc) while (Stream_GetPosition(rpc->client->RecvFrag) < RPC_COMMON_FIELDS_LENGTH) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), - RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(rpc->client->RecvFrag)); + RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(rpc->client->RecvFrag)); if (status < 0) { - fprintf(stderr, "rpc_client_frag_read: error reading header\n"); + WLog_ERR(TAG, "rpc_client_frag_read: error reading header"); return -1; } @@ -269,25 +259,24 @@ int rpc_client_on_read_event(rdpRpc* rpc) if (Stream_GetPosition(rpc->client->RecvFrag) < RPC_COMMON_FIELDS_LENGTH) return status; - header = (rpcconn_common_hdr_t*) Stream_Buffer(rpc->client->RecvFrag); if (header->frag_length > rpc->max_recv_frag) { - fprintf(stderr, "rpc_client_frag_read: invalid fragment size: %d (max: %d)\n", - header->frag_length, rpc->max_recv_frag); - winpr_HexDump(Stream_Buffer(rpc->client->RecvFrag), Stream_GetPosition(rpc->client->RecvFrag)); + WLog_ERR(TAG, "rpc_client_frag_read: invalid fragment size: %d (max: %d)", + header->frag_length, rpc->max_recv_frag); + winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(rpc->client->RecvFrag), Stream_GetPosition(rpc->client->RecvFrag)); return -1; } while (Stream_GetPosition(rpc->client->RecvFrag) < header->frag_length) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), - header->frag_length - Stream_GetPosition(rpc->client->RecvFrag)); + header->frag_length - Stream_GetPosition(rpc->client->RecvFrag)); if (status < 0) { - fprintf(stderr, "%s: error reading fragment body\n", __FUNCTION__); + WLog_ERR(TAG, "error reading fragment body"); return -1; } @@ -305,10 +294,8 @@ int rpc_client_on_read_event(rdpRpc* rpc) if (Stream_GetPosition(rpc->client->RecvFrag) >= header->frag_length) { /* complete fragment received */ - Stream_Length(rpc->client->RecvFrag) = Stream_GetPosition(rpc->client->RecvFrag); Stream_SetPosition(rpc->client->RecvFrag, 0); - Queue_Enqueue(rpc->client->FragmentQueue, rpc->client->RecvFrag); rpc->client->RecvFrag = NULL; @@ -330,9 +317,7 @@ RpcClientCall* rpc_client_call_find_by_id(rdpRpc* rpc, UINT32 CallId) int index; int count; RpcClientCall* clientCall; - ArrayList_Lock(rpc->client->ClientCallList); - clientCall = NULL; count = ArrayList_Count(rpc->client->ClientCallList); @@ -345,22 +330,20 @@ RpcClientCall* rpc_client_call_find_by_id(rdpRpc* rpc, UINT32 CallId) } ArrayList_Unlock(rpc->client->ClientCallList); - return clientCall; } RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum) { RpcClientCall* clientCall; - clientCall = (RpcClientCall*) malloc(sizeof(RpcClientCall)); + if (!clientCall) return NULL; clientCall->CallId = CallId; clientCall->OpNum = OpNum; clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS; - return clientCall; } @@ -373,12 +356,13 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) { RPC_PDU* pdu; int status; - pdu = (RPC_PDU*) malloc(sizeof(RPC_PDU)); + if (!pdu) return -1; pdu->s = Stream_New(buffer, length); + if (!pdu->s) goto out_free; @@ -388,9 +372,10 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) if (rpc->client->SynchronousSend) { status = WaitForSingleObject(rpc->client->PduSentEvent, SYNCHRONOUS_TIMEOUT); + if (status == WAIT_TIMEOUT) { - fprintf(stderr, "%s: timed out waiting for pdu sent event %p\n", __FUNCTION__, rpc->client->PduSentEvent); + WLog_ERR(TAG, "timed out waiting for pdu sent event %p", rpc->client->PduSentEvent); return -1; } @@ -398,7 +383,6 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) } return 0; - out_free_stream: Stream_Free(pdu->s, TRUE); out_free: @@ -412,21 +396,18 @@ int rpc_send_dequeue_pdu(rdpRpc* rpc) RPC_PDU* pdu; RpcClientCall* clientCall; rpcconn_common_hdr_t* header; - RpcInChannel *inChannel; - + RpcInChannel* inChannel; pdu = (RPC_PDU*) Queue_Dequeue(rpc->client->SendQueue); + if (!pdu) return 0; inChannel = rpc->VirtualConnection->DefaultInChannel; WaitForSingleObject(inChannel->Mutex, INFINITE); - status = rpc_in_write(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)); - header = (rpcconn_common_hdr_t*) Stream_Buffer(pdu->s); clientCall = rpc_client_call_find_by_id(rpc, header->call_id); clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED; - ReleaseMutex(inChannel->Mutex); /* @@ -456,34 +437,32 @@ RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc) RPC_PDU* pdu; DWORD dwMilliseconds; DWORD result; - dwMilliseconds = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT * 4 : 0; - result = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds); + if (result == WAIT_TIMEOUT) { - fprintf(stderr, "%s: timed out waiting for receive event\n", __FUNCTION__); + WLog_ERR(TAG, "timed out waiting for receive event"); return NULL; } if (result != WAIT_OBJECT_0) return NULL; - pdu = (RPC_PDU *)Queue_Dequeue(rpc->client->ReceiveQueue); - + pdu = (RPC_PDU*)Queue_Dequeue(rpc->client->ReceiveQueue); #ifdef WITH_DEBUG_TSG + if (pdu) { - fprintf(stderr, "Receiving PDU (length: %d, CallId: %d)\n", pdu->s->length, pdu->CallId); - winpr_HexDump(Stream_Buffer(pdu->s), Stream_Length(pdu->s)); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Receiving PDU (length: %d, CallId: %d)", pdu->s->length, pdu->CallId); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(pdu->s), Stream_Length(pdu->s)); } else { - fprintf(stderr, "Receiving a NULL PDU\n"); + WLog_DBG(TAG, "Receiving a NULL PDU"); } -#endif +#endif return pdu; } @@ -491,14 +470,13 @@ RPC_PDU* rpc_recv_peek_pdu(rdpRpc* rpc) { DWORD dwMilliseconds; DWORD result; - dwMilliseconds = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT : 0; - result = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds); + if (result != WAIT_OBJECT_0) return NULL; - return (RPC_PDU *)Queue_Peek(rpc->client->ReceiveQueue); + return (RPC_PDU*)Queue_Peek(rpc->client->ReceiveQueue); } static void* rpc_client_thread(void* arg) @@ -509,12 +487,9 @@ static void* rpc_client_thread(void* arg) HANDLE events[3]; HANDLE ReadEvent; int fd; - rpc = (rdpRpc*) arg; fd = BIO_get_fd(rpc->TlsOut->bio, NULL); - ReadEvent = CreateFileDescriptorEvent(NULL, TRUE, FALSE, fd); - nCount = 0; events[nCount++] = rpc->client->StopEvent; events[nCount++] = Queue_Event(rpc->client->SendQueue); @@ -527,7 +502,7 @@ static void* rpc_client_thread(void* arg) */ if (rpc_client_on_read_event(rpc) < 0) { - fprintf(stderr, "%s: an error occured when treating first packet\n", __FUNCTION__); + WLog_ERR(TAG, "an error occured when treating first packet"); goto out; } @@ -555,7 +530,6 @@ static void* rpc_client_thread(void* arg) out: CloseHandle(ReadEvent); - return NULL; } @@ -576,55 +550,66 @@ static void rpc_fragment_free(wStream* fragment) int rpc_client_new(rdpRpc* rpc) { RpcClient* client = NULL; - - client = (RpcClient *)calloc(1, sizeof(RpcClient)); + client = (RpcClient*)calloc(1, sizeof(RpcClient)); rpc->client = client; + if (!client) return -1; client->Thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rpc_client_thread, - rpc, CREATE_SUSPENDED, NULL); + (LPTHREAD_START_ROUTINE) rpc_client_thread, + rpc, CREATE_SUSPENDED, NULL); + if (!client->Thread) return -1; client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!client->StopEvent) return -1; + client->PduSentEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!client->PduSentEvent) return -1; client->SendQueue = Queue_New(TRUE, -1, -1); + if (!client->SendQueue) return -1; - Queue_Object(client->SendQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; + Queue_Object(client->SendQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; client->pdu = NULL; client->ReceivePool = Queue_New(TRUE, -1, -1); + if (!client->ReceivePool) return -1; - Queue_Object(client->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; + Queue_Object(client->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; client->ReceiveQueue = Queue_New(TRUE, -1, -1); + if (!client->ReceiveQueue) return -1; - Queue_Object(client->ReceiveQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; + Queue_Object(client->ReceiveQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free; client->RecvFrag = NULL; client->FragmentPool = Queue_New(TRUE, -1, -1); + if (!client->FragmentPool) return -1; - Queue_Object(client->FragmentPool)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free; + Queue_Object(client->FragmentPool)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free; client->FragmentQueue = Queue_New(TRUE, -1, -1); + if (!client->FragmentQueue) return -1; - Queue_Object(client->FragmentQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free; + Queue_Object(client->FragmentQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free; client->ClientCallList = ArrayList_New(TRUE); + if (!client->ClientCallList) return -1; + ArrayList_Object(client->ClientCallList)->fnObjectFree = (OBJECT_FREE_FN) rpc_client_call_free; return 0; } @@ -632,9 +617,8 @@ int rpc_client_new(rdpRpc* rpc) int rpc_client_start(rdpRpc* rpc) { rpc->client->Thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rpc_client_thread, - rpc, 0, NULL); - + (LPTHREAD_START_ROUTINE) rpc_client_thread, + rpc, 0, NULL); return 0; } @@ -653,7 +637,6 @@ int rpc_client_stop(rdpRpc* rpc) int rpc_client_free(rdpRpc* rpc) { RpcClient* client; - client = rpc->client; if (!client) @@ -667,6 +650,7 @@ int rpc_client_free(rdpRpc* rpc) if (client->FragmentPool) Queue_Free(client->FragmentPool); + if (client->FragmentQueue) Queue_Free(client->FragmentQueue); @@ -675,6 +659,7 @@ int rpc_client_free(rdpRpc* rpc) if (client->ReceivePool) Queue_Free(client->ReceivePool); + if (client->ReceiveQueue) Queue_Free(client->ReceiveQueue); @@ -683,6 +668,7 @@ int rpc_client_free(rdpRpc* rpc) if (client->StopEvent) CloseHandle(client->StopEvent); + if (client->PduSentEvent) CloseHandle(client->PduSentEvent); diff --git a/libfreerdp/core/gateway/rpc_fault.c b/libfreerdp/core/gateway/rpc_fault.c index 925efc6e8..ca758befb 100644 --- a/libfreerdp/core/gateway/rpc_fault.c +++ b/libfreerdp/core/gateway/rpc_fault.c @@ -21,8 +21,12 @@ #include "config.h" #endif +#include + #include "rpc_fault.h" +#define TAG FREERDP_TAG("core.gateway.rpc") + extern const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[]; const RPC_FAULT_CODE RPC_FAULT_CODES[] = @@ -314,16 +318,14 @@ int rpc_recv_fault_pdu(rpcconn_hdr_t* header) { int index; UINT32 code; - - fprintf(stderr, "RPC Fault PDU:\n"); - + WLog_ERR(TAG, "RPC Fault PDU:"); code = rpc_map_status_code_to_win32_error_code(header->fault.status); for (index = 0; RPC_FAULT_CODES[index].name != NULL; index++) { if (RPC_FAULT_CODES[index].code == code) { - fprintf(stderr, "status: %s (0x%08X)\n", RPC_FAULT_CODES[index].name, code); + WLog_ERR(TAG, "status: %s (0x%08X)", RPC_FAULT_CODES[index].name, code); return 0; } } @@ -332,12 +334,11 @@ int rpc_recv_fault_pdu(rpcconn_hdr_t* header) { if (RPC_TSG_FAULT_CODES[index].code == code) { - fprintf(stderr, "status: %s (0x%08X)\n", RPC_TSG_FAULT_CODES[index].name, code); + WLog_ERR(TAG, "status: %s (0x%08X)", RPC_TSG_FAULT_CODES[index].name, code); return 0; } } - fprintf(stderr, "status: %s (0x%08X)\n", "UNKNOWN", code); - + WLog_ERR(TAG, "status: %s (0x%08X)", "UNKNOWN", code); return 0; } diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index d57a4240d..ca11fdb3f 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -24,11 +24,15 @@ #include #include +#include + #include "ncacn_http.h" #include "rpc_client.h" #include "rts.h" +#define TAG FREERDP_TAG("core.gateway.rts") + /** * [MS-RPCH]: Remote Procedure Call over HTTP Protocol Specification: * http://msdn.microsoft.com/en-us/library/cc243950/ @@ -93,25 +97,25 @@ BOOL rts_connect(rdpRpc* rpc) if (!rpc_ntlm_http_out_connect(rpc)) { - fprintf(stderr, "%s: rpc_out_connect_http error!\n", __FUNCTION__); + WLog_ERR(TAG, "rpc_out_connect_http error!"); return FALSE; } if (rts_send_CONN_A1_pdu(rpc) != 0) { - fprintf(stderr, "%s: rpc_send_CONN_A1_pdu error!\n", __FUNCTION__); + WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!"); return FALSE; } if (!rpc_ntlm_http_in_connect(rpc)) { - fprintf(stderr, "%s: rpc_in_connect_http error!\n", __FUNCTION__); + WLog_ERR(TAG, "rpc_in_connect_http error!"); return FALSE; } if (rts_send_CONN_B1_pdu(rpc) < 0) { - fprintf(stderr, "%s: rpc_send_CONN_B1_pdu error!\n", __FUNCTION__); + WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!"); return FALSE; } @@ -149,13 +153,13 @@ BOOL rts_connect(rdpRpc* rpc) http_response = http_response_recv(rpc->TlsOut); if (!http_response) { - fprintf(stderr, "%s: unable to retrieve OUT Channel Response!\n", __FUNCTION__); + WLog_ERR(TAG, "unable to retrieve OUT Channel Response!"); return FALSE; } if (http_response->StatusCode != HTTP_STATUS_OK) { - fprintf(stderr, "%s: error! Status Code: %d\n", __FUNCTION__, http_response->StatusCode); + WLog_ERR(TAG, "error! Status Code: %d", http_response->StatusCode); http_response_print(http_response); http_response_free(http_response); @@ -215,7 +219,7 @@ BOOL rts_connect(rdpRpc* rpc) if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_A3_SIGNATURE, rts)) { - fprintf(stderr, "%s: unexpected RTS PDU: Expected CONN/A3\n", __FUNCTION__); + WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/A3"); return FALSE; } @@ -255,7 +259,7 @@ BOOL rts_connect(rdpRpc* rpc) if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_C2_SIGNATURE, rts)) { - fprintf(stderr, "%s: unexpected RTS PDU: Expected CONN/C2\n", __FUNCTION__); + WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/C2"); return FALSE; } @@ -880,9 +884,9 @@ int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) &BytesReceived, &AvailableWindow, (BYTE*) &ChannelCookie) + 4; #if 0 - fprintf(stderr, "BytesReceived: %d AvailableWindow: %d\n", - BytesReceived, AvailableWindow); - fprintf(stderr, "ChannelCookie: " RPC_UUID_FORMAT_STRING "\n", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie)); + WLog_ERR(TAG, "BytesReceived: %d AvailableWindow: %d", + BytesReceived, AvailableWindow); + WLog_ERR(TAG, "ChannelCookie: " RPC_UUID_FORMAT_STRING "", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie)); #endif rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow = @@ -921,9 +925,9 @@ int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buffer, UI &BytesReceived, &AvailableWindow, (BYTE*) &ChannelCookie) + 4; #if 0 - fprintf(stderr, "Destination: %d BytesReceived: %d AvailableWindow: %d\n", - Destination, BytesReceived, AvailableWindow); - fprintf(stderr, "ChannelCookie: " RPC_UUID_FORMAT_STRING "\n", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie)); + WLog_ERR(TAG, "Destination: %d BytesReceived: %d AvailableWindow: %d", + Destination, BytesReceived, AvailableWindow); + WLog_ERR(TAG, "ChannelCookie: " RPC_UUID_FORMAT_STRING "", RPC_UUID_FORMAT_ARGUMENTS(ChannelCookie)); #endif rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow = @@ -1027,7 +1031,7 @@ int rts_command_length(rdpRpc* rpc, UINT32 CommandType, BYTE* buffer, UINT32 len break; default: - fprintf(stderr, "Error: Unknown RTS Command Type: 0x%x\n", CommandType); + WLog_ERR(TAG, "Error: Unknown RTS Command Type: 0x%x", CommandType); return -1; break; } @@ -1055,7 +1059,7 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) case RTS_PDU_PING: return rts_send_ping_pdu(rpc); default: - fprintf(stderr, "%s: unimplemented signature id: 0x%08X\n", __FUNCTION__, SignatureId); + WLog_ERR(TAG, "unimplemented signature id: 0x%08X", SignatureId); rts_print_pdu_signature(rpc, &signature); break; } diff --git a/libfreerdp/core/gateway/rts.h b/libfreerdp/core/gateway/rts.h index f26956f53..a0fd620a9 100644 --- a/libfreerdp/core/gateway/rts.h +++ b/libfreerdp/core/gateway/rts.h @@ -28,7 +28,7 @@ #include #include -#include +#include #define RTS_FLAG_NONE 0x0000 #define RTS_FLAG_PING 0x0001 @@ -147,10 +147,11 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); #define WITH_DEBUG_RTS #endif +#define RTS_TAG FREERDP_TAG("core.gateway.rts") #ifdef WITH_DEBUG_RTS -#define DEBUG_RTS(fmt, ...) DEBUG_CLASS(RTS, fmt, ## __VA_ARGS__) +#define DEBUG_RTS(fmt, ...) WLog_DBG(RTS_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_RTS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_RTS(fmt, ...) do { } while (0) #endif #endif /* FREERDP_CORE_RTS_H */ diff --git a/libfreerdp/core/gateway/rts_signature.c b/libfreerdp/core/gateway/rts_signature.c index 47242ca63..b9d9ccc1b 100644 --- a/libfreerdp/core/gateway/rts_signature.c +++ b/libfreerdp/core/gateway/rts_signature.c @@ -17,8 +17,12 @@ * limitations under the License. */ +#include + #include "rts_signature.h" +#define TAG FREERDP_TAG("core.gateway") + RtsPduSignature RTS_PDU_CONN_A1_SIGNATURE = { RTS_FLAG_NONE, 4, { RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0, 0 } }; RtsPduSignature RTS_PDU_CONN_A2_SIGNATURE = { RTS_FLAG_OUT_CHANNEL, 5, @@ -317,14 +321,12 @@ int rts_print_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature) { UINT32 SignatureId; RTS_PDU_SIGNATURE_ENTRY* entry; - - fprintf(stderr, "RTS PDU Signature: Flags: 0x%04X NumberOfCommands: %d\n", - signature->Flags, signature->NumberOfCommands); - + WLog_INFO(TAG, "RTS PDU Signature: Flags: 0x%04X NumberOfCommands: %d", + signature->Flags, signature->NumberOfCommands); SignatureId = rts_identify_pdu_signature(rpc, signature, &entry); if (SignatureId) - fprintf(stderr, "Identified %s RTS PDU\n", entry->PduName); + WLog_ERR(TAG, "Identified %s RTS PDU", entry->PduName); return 0; } diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index 5491fe8af..f23f90306 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -31,10 +31,11 @@ #include #include #include - +#include #include "rpc_client.h" #include "tsg.h" +#define TAG FREERDP_TAG("core.gateway.tsg") /** * RPC Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378623/ @@ -46,10 +47,10 @@ BYTE TsProxyCreateTunnelUnknownTrailerBytes[60] = { - 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x40, 0x28, 0x00, 0xDD, 0x65, 0xE2, 0x44, 0xAF, 0x7D, 0xCD, 0x42, 0x85, 0x60, 0x3C, 0xDB, - 0x6E, 0x7A, 0x27, 0x29, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, - 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 + 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x40, 0x28, 0x00, 0xDD, 0x65, 0xE2, 0x44, 0xAF, 0x7D, 0xCD, 0x42, 0x85, 0x60, 0x3C, 0xDB, + 0x6E, 0x7A, 0x27, 0x29, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, + 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, UINT32* lengths) @@ -67,7 +68,6 @@ DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, UINT32 buffer3Length; UINT32 numBuffers = 0; UINT32 totalDataBytes = 0; - tsg = (rdpTsg*) IDL_handle; buffer1Length = buffer2Length = buffer3Length = 0; @@ -97,41 +97,42 @@ DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, length = 28 + totalDataBytes; buffer = (BYTE*) calloc(1, length); + if (!buffer) return -1; s = Stream_New(buffer, length); - /* PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE_NR (20 bytes) */ Stream_Write(s, &tsg->ChannelContext.ContextType, 4); /* ContextType (4 bytes) */ Stream_Write(s, tsg->ChannelContext.ContextUuid, 16); /* ContextUuid (16 bytes) */ - Stream_Write_UINT32_BE(s, totalDataBytes); /* totalDataBytes (4 bytes) */ Stream_Write_UINT32_BE(s, numBuffers); /* numBuffers (4 bytes) */ if (buffer1Length > 0) Stream_Write_UINT32_BE(s, buffer1Length); /* buffer1Length (4 bytes) */ + if (buffer2Length > 0) Stream_Write_UINT32_BE(s, buffer2Length); /* buffer2Length (4 bytes) */ + if (buffer3Length > 0) Stream_Write_UINT32_BE(s, buffer3Length); /* buffer3Length (4 bytes) */ if (buffer1Length > 0) Stream_Write(s, buffer1, buffer1Length); /* buffer1 (variable) */ + if (buffer2Length > 0) Stream_Write(s, buffer2, buffer2Length); /* buffer2 (variable) */ + if (buffer3Length > 0) Stream_Write(s, buffer3, buffer3Length); /* buffer3 (variable) */ Stream_Length(s) = Stream_GetPosition(s); - status = rpc_write(tsg->rpc, Stream_Buffer(s), Stream_Length(s), TsProxySendToServerOpnum); - Stream_Free(s, TRUE); if (status <= 0) { - fprintf(stderr, "rpc_write failed!\n"); + WLog_ERR(TAG, "rpc_write failed!"); return -1; } @@ -145,39 +146,29 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg) UINT32 length; UINT32 NapCapabilities; rdpRpc* rpc = tsg->rpc; - length = 108; buffer = (BYTE*) malloc(length); - *((UINT32*) &buffer[0]) = TSG_PACKET_TYPE_VERSIONCAPS; /* PacketId */ *((UINT32*) &buffer[4]) = TSG_PACKET_TYPE_VERSIONCAPS; /* SwitchValue */ - *((UINT32*) &buffer[8]) = 0x00020000; /* PacketVersionCapsPtr */ - *((UINT16*) &buffer[12]) = TS_GATEWAY_TRANSPORT; /* ComponentId */ *((UINT16*) &buffer[14]) = TSG_PACKET_TYPE_VERSIONCAPS; /* PacketId */ - *((UINT32*) &buffer[16]) = 0x00020004; /* TsgCapsPtr */ *((UINT32*) &buffer[20]) = 0x00000001; /* NumCapabilities */ - *((UINT16*) &buffer[24]) = 0x0001; /* MajorVersion */ *((UINT16*) &buffer[26]) = 0x0001; /* MinorVersion */ *((UINT16*) &buffer[28]) = 0x0000; /* QuarantineCapabilities */ - /* 4-byte alignment (30 + 2) */ *((UINT16*) &buffer[30]) = 0x0000; /* 2-byte pad */ - *((UINT32*) &buffer[32]) = 0x00000001; /* MaxCount */ *((UINT32*) &buffer[36]) = TSG_CAPABILITY_TYPE_NAP; /* CapabilityType */ *((UINT32*) &buffer[40]) = TSG_CAPABILITY_TYPE_NAP; /* SwitchValue */ - NapCapabilities = - TSG_NAP_CAPABILITY_QUAR_SOH | - TSG_NAP_CAPABILITY_IDLE_TIMEOUT | - TSG_MESSAGING_CAP_CONSENT_SIGN | - TSG_MESSAGING_CAP_SERVICE_MSG | - TSG_MESSAGING_CAP_REAUTH; - + TSG_NAP_CAPABILITY_QUAR_SOH | + TSG_NAP_CAPABILITY_IDLE_TIMEOUT | + TSG_MESSAGING_CAP_CONSENT_SIGN | + TSG_MESSAGING_CAP_SERVICE_MSG | + TSG_MESSAGING_CAP_REAUTH; /* * Alternate Code Path * @@ -188,18 +179,14 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg) * "Only allow connections from Remote Desktop Services clients that support RD Gateway messaging" */ //NapCapabilities = TSG_NAP_CAPABILITY_IDLE_TIMEOUT; - *((UINT32*) &buffer[44]) = NapCapabilities; /* capabilities */ - CopyMemory(&buffer[48], TsProxyCreateTunnelUnknownTrailerBytes, 60); - status = rpc_write(rpc, buffer, length, TsProxyCreateTunnelOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -231,6 +218,7 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) buffer = &buffer[24]; packet = (PTSG_PACKET) calloc(1, sizeof(TSG_PACKET)); + if (!packet) return FALSE; @@ -241,17 +229,17 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) if ((packet->packetId == TSG_PACKET_TYPE_CAPS_RESPONSE) && (SwitchValue == TSG_PACKET_TYPE_CAPS_RESPONSE)) { packetCapsResponse = (PTSG_PACKET_CAPS_RESPONSE) calloc(1, sizeof(TSG_PACKET_CAPS_RESPONSE)); + if (!packetCapsResponse) // TODO: correct cleanup return FALSE; - packet->tsgPacket.packetCapsResponse = packetCapsResponse; + packet->tsgPacket.packetCapsResponse = packetCapsResponse; /* PacketQuarResponsePtr (4 bytes) */ packetCapsResponse->pktQuarEncResponse.flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ packetCapsResponse->pktQuarEncResponse.certChainLen = *((UINT32*) &buffer[offset + 16]); /* CertChainLength */ /* CertChainDataPtr (4 bytes) */ CopyMemory(&packetCapsResponse->pktQuarEncResponse.nonce, &buffer[offset + 24], 16); /* Nonce */ offset += 40; - Pointer = *((UINT32*) &buffer[offset]); /* VersionCapsPtr */ offset += 4; @@ -270,19 +258,16 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) { Pointer = *((UINT32*) &buffer[offset]); /* MsgPtr (4 bytes): 0x00020014 */ offset += 4; - offset += 4; /* MaxCount (4 bytes) */ offset += 4; /* Offset (4 bytes) */ count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */ offset += 4; - /* * CertChainData is a wide character string, and the count is * given in characters excluding the null terminator, therefore: * size = (count * 2) */ offset += (count * 2); /* CertChainData */ - /* 4-byte alignment */ rpc_offset_align(&offset, 4); } @@ -293,18 +278,19 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) } versionCaps = (PTSG_PACKET_VERSIONCAPS) calloc(1, sizeof(TSG_PACKET_VERSIONCAPS)); + if (!versionCaps) // TODO: correct cleanup return FALSE; - packetCapsResponse->pktQuarEncResponse.versionCaps = versionCaps; + packetCapsResponse->pktQuarEncResponse.versionCaps = versionCaps; versionCaps->tsgHeader.ComponentId = *((UINT16*) &buffer[offset]); /* ComponentId */ versionCaps->tsgHeader.PacketId = *((UINT16*) &buffer[offset + 2]); /* PacketId */ offset += 4; if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT) { - fprintf(stderr, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", - versionCaps->tsgHeader.ComponentId); + WLog_ERR(TAG, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT", + versionCaps->tsgHeader.ComponentId); free(packetCapsResponse); free(versionCaps); free(packet); @@ -317,16 +303,14 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) versionCaps->minorVersion = *((UINT16*) &buffer[offset + 10]); /* MinorVersion */ versionCaps->quarantineCapabilities = *((UINT16*) &buffer[offset + 12]); /* QuarantineCapabilities */ offset += 14; - /* 4-byte alignment */ rpc_offset_align(&offset, 4); - tsgCaps = (PTSG_PACKET_CAPABILITIES) calloc(1, sizeof(TSG_PACKET_CAPABILITIES)); + if (!tsgCaps) return FALSE; versionCaps->tsgCaps = tsgCaps; - offset += 4; /* MaxCount (4 bytes) */ tsgCaps->capabilityType = *((UINT32*) &buffer[offset]); /* CapabilityType */ SwitchValue = *((UINT32*) &buffer[offset + 4]); /* SwitchValue */ @@ -334,8 +318,8 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) if ((SwitchValue != TSG_CAPABILITY_TYPE_NAP) || (tsgCaps->capabilityType != TSG_CAPABILITY_TYPE_NAP)) { - fprintf(stderr, "Unexpected CapabilityType: 0x%08X, Expected TSG_CAPABILITY_TYPE_NAP\n", - tsgCaps->capabilityType); + WLog_ERR(TAG, "Unexpected CapabilityType: 0x%08X, Expected TSG_CAPABILITY_TYPE_NAP", + tsgCaps->capabilityType); free(tsgCaps); free(versionCaps); free(packetCapsResponse); @@ -365,47 +349,41 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) if (MsgBytes > TSG_MESSAGING_MAX_MESSAGE_LENGTH) { - fprintf(stderr, "Out of Spec Message Length %d", MsgBytes); + WLog_ERR(TAG, "Out of Spec Message Length %d", MsgBytes); free(tsgCaps); free(versionCaps); free(packetCapsResponse); free(packet); return FALSE; } + offset += MsgBytes; break; - case TSG_ASYNC_MESSAGE_REAUTH: rpc_offset_align(&offset, 8); offset += 8; // UINT64 TunnelContext, not to be confused with - // the ContextHandle TunnelContext below. + // the ContextHandle TunnelContext below. break; - default: - fprintf(stderr, "Unexpected Message Type: 0x%X\n", (int) MessageSwitchValue); + WLog_ERR(TAG, "Unexpected Message Type: 0x%X", (int) MessageSwitchValue); free(tsgCaps); free(versionCaps); free(packetCapsResponse); free(packet); return FALSE; - } rpc_offset_align(&offset, 4); - /* TunnelContext (20 bytes) */ CopyMemory(&tsg->TunnelContext.ContextType, &buffer[offset], 4); /* ContextType */ CopyMemory(tsg->TunnelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid */ offset += 20; // UINT32 TunnelId // HRESULT ReturnValue - #ifdef WITH_DEBUG_TSG - fprintf(stderr, "TSG TunnelContext:\n"); - winpr_HexDump((void*) &tsg->TunnelContext, 20); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "TSG TunnelContext:"); + winpr_HexDump(TAG, WLOG_DEBUG, (void*) &tsg->TunnelContext, 20); #endif - free(tsgCaps); free(versionCaps); free(packetCapsResponse); @@ -413,10 +391,11 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) else if ((packet->packetId == TSG_PACKET_TYPE_QUARENC_RESPONSE) && (SwitchValue == TSG_PACKET_TYPE_QUARENC_RESPONSE)) { packetQuarEncResponse = (PTSG_PACKET_QUARENC_RESPONSE) calloc(1, sizeof(TSG_PACKET_QUARENC_RESPONSE)); + if (!packetQuarEncResponse) // TODO: handle cleanup return FALSE; - packet->tsgPacket.packetQuarEncResponse = packetQuarEncResponse; + packet->tsgPacket.packetQuarEncResponse = packetQuarEncResponse; /* PacketQuarResponsePtr (4 bytes) */ packetQuarEncResponse->flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ packetQuarEncResponse->certChainLen = *((UINT32*) &buffer[offset + 16]); /* CertChainLength */ @@ -428,19 +407,16 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) { Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes): 0x0002000C */ offset += 4; - offset += 4; /* MaxCount (4 bytes) */ offset += 4; /* Offset (4 bytes) */ count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */ offset += 4; - /* * CertChainData is a wide character string, and the count is * given in characters excluding the null terminator, therefore: * size = (count * 2) */ offset += (count * 2); /* CertChainData */ - /* 4-byte alignment */ rpc_offset_align(&offset, 4); } @@ -451,18 +427,19 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) } versionCaps = (PTSG_PACKET_VERSIONCAPS) calloc(1, sizeof(TSG_PACKET_VERSIONCAPS)); + if (!versionCaps) // TODO: handle cleanup return FALSE; - packetQuarEncResponse->versionCaps = versionCaps; + packetQuarEncResponse->versionCaps = versionCaps; versionCaps->tsgHeader.ComponentId = *((UINT16*) &buffer[offset]); /* ComponentId */ versionCaps->tsgHeader.PacketId = *((UINT16*) &buffer[offset + 2]); /* PacketId */ offset += 4; if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT) { - fprintf(stderr, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", - versionCaps->tsgHeader.ComponentId); + WLog_ERR(TAG, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT", + versionCaps->tsgHeader.ComponentId); free(versionCaps); free(packetQuarEncResponse); free(packet); @@ -475,46 +452,39 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) versionCaps->majorVersion = *((UINT16*) &buffer[offset + 10]); /* MinorVersion */ versionCaps->quarantineCapabilities = *((UINT16*) &buffer[offset + 12]); /* QuarantineCapabilities */ offset += 14; - /* 4-byte alignment */ rpc_offset_align(&offset, 4); - /* Not sure exactly what this is */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000002 (4 bytes) */ - /* TunnelContext (20 bytes) */ CopyMemory(&tsg->TunnelContext.ContextType, &buffer[offset], 4); /* ContextType */ CopyMemory(tsg->TunnelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid */ offset += 20; - #ifdef WITH_DEBUG_TSG - fprintf(stderr, "TSG TunnelContext:\n"); - winpr_HexDump((void*) &tsg->TunnelContext, 20); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "TSG TunnelContext:"); + winpr_HexDump(TAG, WLOG_DEBUG, (void*) &tsg->TunnelContext, 20); #endif - free(versionCaps); free(packetQuarEncResponse); } else { - fprintf(stderr, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_CAPS_RESPONSE " - "or TSG_PACKET_TYPE_QUARENC_RESPONSE\n", packet->packetId); + WLog_ERR(TAG, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_CAPS_RESPONSE " + "or TSG_PACKET_TYPE_QUARENC_RESPONSE", packet->packetId); free(packet); return FALSE; } rpc_client_receive_pool_return(rpc, pdu); free(packet); - return TRUE; } BOOL TsProxyCreateTunnel(rdpTsg* tsg, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse, - PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext, UINT32* tunnelId) + PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext, UINT32* tunnelId) { /** * OpNum = 1 @@ -526,12 +496,11 @@ BOOL TsProxyCreateTunnel(rdpTsg* tsg, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPac * [out] unsigned long* tunnelId * ); */ - - DEBUG_TSG("TsProxyCreateTunnel"); + DEBUG_TSG(""); if (!TsProxyCreateTunnelWriteRequest(tsg)) { - fprintf(stderr, "TsProxyCreateTunnel: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } @@ -548,58 +517,42 @@ BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSE UINT32 offset; CONTEXT_HANDLE* handle; rdpRpc* rpc = tsg->rpc; - count = _wcslen(tsg->MachineName) + 1; - offset = 64 + (count * 2); rpc_offset_align(&offset, 4); offset += 4; - length = offset; buffer = (BYTE*) malloc(length); - /* TunnelContext */ handle = (CONTEXT_HANDLE*) tunnelContext; CopyMemory(&buffer[0], &handle->ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], handle->ContextUuid, 16); /* ContextUuid */ - /* 4-byte alignment */ - *((UINT32*) &buffer[20]) = TSG_PACKET_TYPE_QUARREQUEST; /* PacketId */ *((UINT32*) &buffer[24]) = TSG_PACKET_TYPE_QUARREQUEST; /* SwitchValue */ - *((UINT32*) &buffer[28]) = 0x00020000; /* PacketQuarRequestPtr */ - *((UINT32*) &buffer[32]) = 0x00000000; /* Flags */ - *((UINT32*) &buffer[36]) = 0x00020004; /* MachineNamePtr */ - *((UINT32*) &buffer[40]) = count; /* NameLength */ - *((UINT32*) &buffer[44]) = 0x00020008; /* DataPtr */ *((UINT32*) &buffer[48]) = 0; /* DataLength */ - /* MachineName */ *((UINT32*) &buffer[52]) = count; /* MaxCount */ *((UINT32*) &buffer[56]) = 0; /* Offset */ *((UINT32*) &buffer[60]) = count; /* ActualCount */ CopyMemory(&buffer[64], tsg->MachineName, count * 2); /* Array */ offset = 64 + (count * 2); - /* 4-byte alignment */ pad = rpc_offset_align(&offset, 4); ZeroMemory(&buffer[offset - pad], pad); - *((UINT32*) &buffer[offset]) = 0x00000000; /* MaxCount */ offset += 4; - status = rpc_write(rpc, buffer, length, TsProxyAuthorizeTunnelOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -626,23 +579,22 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) packet = (PTSG_PACKET) malloc(sizeof(TSG_PACKET)); ZeroMemory(packet, sizeof(TSG_PACKET)); - offset = 4; packet->packetId = *((UINT32*) &buffer[offset]); /* PacketId */ SwitchValue = *((UINT32*) &buffer[offset + 4]); /* SwitchValue */ if (packet->packetId == E_PROXY_NAP_ACCESSDENIED) { - fprintf(stderr, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)\n", E_PROXY_NAP_ACCESSDENIED); - fprintf(stderr, "Ensure that the Gateway Connection Authorization Policy is correct\n"); + WLog_ERR(TAG, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)", E_PROXY_NAP_ACCESSDENIED); + WLog_ERR(TAG, "Ensure that the Gateway Connection Authorization Policy is correct"); free(packet); return FALSE; } if ((packet->packetId != TSG_PACKET_TYPE_RESPONSE) || (SwitchValue != TSG_PACKET_TYPE_RESPONSE)) { - fprintf(stderr, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_RESPONSE\n", - packet->packetId); + WLog_ERR(TAG, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_RESPONSE", + packet->packetId); free(packet); return FALSE; } @@ -650,14 +602,13 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) packetResponse = (PTSG_PACKET_RESPONSE) malloc(sizeof(TSG_PACKET_RESPONSE)); ZeroMemory(packetResponse, sizeof(TSG_PACKET_RESPONSE)); packet->tsgPacket.packetResponse = packetResponse; - Pointer = *((UINT32*) &buffer[offset + 8]); /* PacketResponsePtr */ packetResponse->flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ if (packetResponse->flags != TSG_PACKET_TYPE_QUARREQUEST) { - fprintf(stderr, "Unexpected Packet Response Flags: 0x%08X, Expected TSG_PACKET_TYPE_QUARREQUEST\n", - packetResponse->flags); + WLog_ERR(TAG, "Unexpected Packet Response Flags: 0x%08X, Expected TSG_PACKET_TYPE_QUARREQUEST", + packetResponse->flags); free(packet); free(packetResponse); return FALSE; @@ -666,7 +617,6 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) /* Reserved (4 bytes) */ Pointer = *((UINT32*) &buffer[offset + 20]); /* ResponseDataPtr */ packetResponse->responseDataLen = *((UINT32*) &buffer[offset + 24]); /* ResponseDataLength */ - packetResponse->redirectionFlags.enableAllRedirections = *((UINT32*) &buffer[offset + 28]); /* EnableAllRedirections */ packetResponse->redirectionFlags.disableAllRedirections = *((UINT32*) &buffer[offset + 32]); /* DisableAllRedirections */ packetResponse->redirectionFlags.driveRedirectionDisabled = *((UINT32*) &buffer[offset + 36]); /* DriveRedirectionDisabled */ @@ -676,30 +626,27 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) packetResponse->redirectionFlags.clipboardRedirectionDisabled = *((UINT32*) &buffer[offset + 52]); /* ClipboardRedirectionDisabled */ packetResponse->redirectionFlags.pnpRedirectionDisabled = *((UINT32*) &buffer[offset + 56]); /* PnpRedirectionDisabled */ offset += 60; - SizeValue = *((UINT32*) &buffer[offset]); offset += 4; if (SizeValue != packetResponse->responseDataLen) { - fprintf(stderr, "Unexpected size value: %d, expected: %d\n", - SizeValue, packetResponse->responseDataLen); + WLog_ERR(TAG, "Unexpected size value: %d, expected: %d", + SizeValue, packetResponse->responseDataLen); free(packetResponse); free(packet); return FALSE; } offset += SizeValue; /* ResponseData */ - rpc_client_receive_pool_return(rpc, pdu); free(packetResponse); free(packet); - return TRUE; } BOOL TsProxyAuthorizeTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, - PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) + PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) { /** * OpNum = 2 @@ -711,12 +658,11 @@ BOOL TsProxyAuthorizeTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunn * ); * */ - - DEBUG_TSG("TsProxyAuthorizeTunnel"); + DEBUG_TSG(""); if (!TsProxyAuthorizeTunnelWriteRequest(tsg, tunnelContext)) { - fprintf(stderr, "TsProxyAuthorizeTunnel: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } @@ -730,33 +676,24 @@ BOOL TsProxyMakeTunnelCallWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSER UINT32 length; CONTEXT_HANDLE* handle; rdpRpc* rpc = tsg->rpc; - length = 40; buffer = (BYTE*) malloc(length); - /* TunnelContext */ handle = (CONTEXT_HANDLE*) tunnelContext; CopyMemory(&buffer[0], &handle->ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], handle->ContextUuid, 16); /* ContextUuid */ - *((UINT32*) &buffer[20]) = procId; /* ProcId */ - /* 4-byte alignment */ - *((UINT32*) &buffer[24]) = TSG_PACKET_TYPE_MSGREQUEST_PACKET; /* PacketId */ *((UINT32*) &buffer[28]) = TSG_PACKET_TYPE_MSGREQUEST_PACKET; /* SwitchValue */ - *((UINT32*) &buffer[32]) = 0x00020000; /* PacketMsgRequestPtr */ - *((UINT32*) &buffer[36]) = 0x00000001; /* MaxMessagesPerBatch */ - status = rpc_write(rpc, buffer, length, TsProxyMakeTunnelCallOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -788,6 +725,7 @@ BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) buffer = &buffer[24]; packet = (PTSG_PACKET) calloc(1, sizeof(TSG_PACKET)); + if (!packet) return FALSE; @@ -797,8 +735,8 @@ BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) if ((packet->packetId != TSG_PACKET_TYPE_MESSAGE_PACKET) || (SwitchValue != TSG_PACKET_TYPE_MESSAGE_PACKET)) { - fprintf(stderr, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_MESSAGE_PACKET\n", - packet->packetId); + WLog_ERR(TAG, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_MESSAGE_PACKET", + packet->packetId); free(packet); return FALSE; } @@ -806,71 +744,57 @@ BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) packetMsgResponse = (PTSG_PACKET_MSG_RESPONSE) malloc(sizeof(TSG_PACKET_MSG_RESPONSE)); ZeroMemory(packetMsgResponse, sizeof(TSG_PACKET_MSG_RESPONSE)); packet->tsgPacket.packetMsgResponse = packetMsgResponse; - Pointer = *((UINT32*) &buffer[offset + 8]); /* PacketMsgResponsePtr */ packetMsgResponse->msgID = *((UINT32*) &buffer[offset + 12]); /* MsgId */ packetMsgResponse->msgType = *((UINT32*) &buffer[offset + 16]); /* MsgType */ packetMsgResponse->isMsgPresent = *((INT32*) &buffer[offset + 20]); /* IsMsgPresent */ - SwitchValue = *((UINT32*) &buffer[offset + 24]); /* SwitchValue */ switch (SwitchValue) { - case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE: - packetStringMessage = (PTSG_PACKET_STRING_MESSAGE) malloc(sizeof(TSG_PACKET_STRING_MESSAGE)); - ZeroMemory(packetStringMessage, sizeof(TSG_PACKET_STRING_MESSAGE)); - packetMsgResponse->messagePacket.consentMessage = packetStringMessage; - - Pointer = *((UINT32*) &buffer[offset + 28]); /* ConsentMessagePtr */ - packetStringMessage->isDisplayMandatory = *((INT32*) &buffer[offset + 32]); /* IsDisplayMandatory */ - packetStringMessage->isConsentMandatory = *((INT32*) &buffer[offset + 36]); /* IsConsentMandatory */ - packetStringMessage->msgBytes = *((UINT32*) &buffer[offset + 40]); /* MsgBytes */ - - Pointer = *((UINT32*) &buffer[offset + 44]); /* MsgPtr */ - MaxCount = *((UINT32*) &buffer[offset + 48]); /* MaxCount */ - /* Offset */ - ActualCount = *((UINT32*) &buffer[offset + 56]); /* ActualCount */ - - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) &buffer[offset + 60], ActualCount, &messageText, 0, NULL, NULL); - fprintf(stderr, "Consent Message: %s\n", messageText); - free(messageText); - - break; - - case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE: - packetStringMessage = (PTSG_PACKET_STRING_MESSAGE) malloc(sizeof(TSG_PACKET_STRING_MESSAGE)); - ZeroMemory(packetStringMessage, sizeof(TSG_PACKET_STRING_MESSAGE)); - packetMsgResponse->messagePacket.serviceMessage = packetStringMessage; - - Pointer = *((UINT32*) &buffer[offset + 28]); /* ServiceMessagePtr */ - packetStringMessage->isDisplayMandatory = *((INT32*) &buffer[offset + 32]); /* IsDisplayMandatory */ - packetStringMessage->isConsentMandatory = *((INT32*) &buffer[offset + 36]); /* IsConsentMandatory */ - packetStringMessage->msgBytes = *((UINT32*) &buffer[offset + 40]); /* MsgBytes */ - - Pointer = *((UINT32*) &buffer[offset + 44]); /* MsgPtr */ - MaxCount = *((UINT32*) &buffer[offset + 48]); /* MaxCount */ - /* Offset */ - ActualCount = *((UINT32*) &buffer[offset + 56]); /* ActualCount */ - - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) &buffer[offset + 60], ActualCount, &messageText, 0, NULL, NULL); - fprintf(stderr, "Service Message: %s\n", messageText); - free(messageText); - - break; - - case TSG_ASYNC_MESSAGE_REAUTH: - packetReauthMessage = (PTSG_PACKET_REAUTH_MESSAGE) malloc(sizeof(TSG_PACKET_REAUTH_MESSAGE)); - ZeroMemory(packetReauthMessage, sizeof(TSG_PACKET_REAUTH_MESSAGE)); - packetMsgResponse->messagePacket.reauthMessage = packetReauthMessage; - - Pointer = *((UINT32*) &buffer[offset + 28]); /* ReauthMessagePtr */ - break; - - default: - fprintf(stderr, "TsProxyMakeTunnelCallReadResponse: unexpected message type: %d\n", - SwitchValue); - rc = FALSE; - break; + case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE: + packetStringMessage = (PTSG_PACKET_STRING_MESSAGE) malloc(sizeof(TSG_PACKET_STRING_MESSAGE)); + ZeroMemory(packetStringMessage, sizeof(TSG_PACKET_STRING_MESSAGE)); + packetMsgResponse->messagePacket.consentMessage = packetStringMessage; + Pointer = *((UINT32*) &buffer[offset + 28]); /* ConsentMessagePtr */ + packetStringMessage->isDisplayMandatory = *((INT32*) &buffer[offset + 32]); /* IsDisplayMandatory */ + packetStringMessage->isConsentMandatory = *((INT32*) &buffer[offset + 36]); /* IsConsentMandatory */ + packetStringMessage->msgBytes = *((UINT32*) &buffer[offset + 40]); /* MsgBytes */ + Pointer = *((UINT32*) &buffer[offset + 44]); /* MsgPtr */ + MaxCount = *((UINT32*) &buffer[offset + 48]); /* MaxCount */ + /* Offset */ + ActualCount = *((UINT32*) &buffer[offset + 56]); /* ActualCount */ + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) &buffer[offset + 60], ActualCount, &messageText, 0, NULL, NULL); + WLog_ERR(TAG, "Consent Message: %s", messageText); + free(messageText); + break; + case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE: + packetStringMessage = (PTSG_PACKET_STRING_MESSAGE) malloc(sizeof(TSG_PACKET_STRING_MESSAGE)); + ZeroMemory(packetStringMessage, sizeof(TSG_PACKET_STRING_MESSAGE)); + packetMsgResponse->messagePacket.serviceMessage = packetStringMessage; + Pointer = *((UINT32*) &buffer[offset + 28]); /* ServiceMessagePtr */ + packetStringMessage->isDisplayMandatory = *((INT32*) &buffer[offset + 32]); /* IsDisplayMandatory */ + packetStringMessage->isConsentMandatory = *((INT32*) &buffer[offset + 36]); /* IsConsentMandatory */ + packetStringMessage->msgBytes = *((UINT32*) &buffer[offset + 40]); /* MsgBytes */ + Pointer = *((UINT32*) &buffer[offset + 44]); /* MsgPtr */ + MaxCount = *((UINT32*) &buffer[offset + 48]); /* MaxCount */ + /* Offset */ + ActualCount = *((UINT32*) &buffer[offset + 56]); /* ActualCount */ + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) &buffer[offset + 60], ActualCount, &messageText, 0, NULL, NULL); + WLog_ERR(TAG, "Service Message: %s", messageText); + free(messageText); + break; + case TSG_ASYNC_MESSAGE_REAUTH: + packetReauthMessage = (PTSG_PACKET_REAUTH_MESSAGE) malloc(sizeof(TSG_PACKET_REAUTH_MESSAGE)); + ZeroMemory(packetReauthMessage, sizeof(TSG_PACKET_REAUTH_MESSAGE)); + packetMsgResponse->messagePacket.reauthMessage = packetReauthMessage; + Pointer = *((UINT32*) &buffer[offset + 28]); /* ReauthMessagePtr */ + break; + default: + WLog_ERR(TAG, "unexpected message type: %d", + SwitchValue); + rc = FALSE; + break; } if (packet) @@ -879,8 +803,10 @@ BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) { if (packet->tsgPacket.packetMsgResponse->messagePacket.reauthMessage) free(packet->tsgPacket.packetMsgResponse->messagePacket.reauthMessage); + free(packet->tsgPacket.packetMsgResponse); } + free(packet); } @@ -888,7 +814,7 @@ BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) } BOOL TsProxyMakeTunnelCall(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, - UINT32 procId, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) + UINT32 procId, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) { /** * OpNum = 3 @@ -900,12 +826,11 @@ BOOL TsProxyMakeTunnelCall(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunne * [out, ref] PTSG_PACKET* tsgPacketResponse * ); */ - - DEBUG_TSG("TsProxyMakeTunnelCall"); + DEBUG_TSG(""); if (!TsProxyMakeTunnelCallWriteRequest(tsg, tunnelContext, procId)) { - fprintf(stderr, "TsProxyMakeTunnelCall: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } @@ -920,18 +845,14 @@ BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERI UINT32 length; CONTEXT_HANDLE* handle; rdpRpc* rpc = tsg->rpc; - count = _wcslen(tsg->Hostname) + 1; - #ifdef WITH_DEBUG_TSG - fprintf(stderr, "ResourceName:\n"); - winpr_HexDump((BYTE*) tsg->Hostname, (count - 1) * 2); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ResourceName:"); + winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) tsg->Hostname, (count - 1) * 2); #endif - length = 60 + (count * 2); - buffer = (BYTE*) malloc(length); + if (!buffer) return FALSE; @@ -939,33 +860,27 @@ BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERI handle = (CONTEXT_HANDLE*) tunnelContext; CopyMemory(&buffer[0], &handle->ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], handle->ContextUuid, 16); /* ContextUuid */ - /* TSENDPOINTINFO */ - *((UINT32*) &buffer[20]) = 0x00020000; /* ResourceNamePtr */ *((UINT32*) &buffer[24]) = 0x00000001; /* NumResourceNames */ *((UINT32*) &buffer[28]) = 0x00000000; /* AlternateResourceNamesPtr */ *((UINT16*) &buffer[32]) = 0x0000; /* NumAlternateResourceNames */ *((UINT16*) &buffer[34]) = 0x0000; /* Pad (2 bytes) */ - /* Port (4 bytes) */ *((UINT16*) &buffer[36]) = 0x0003; /* ProtocolId (RDP = 3) */ *((UINT16*) &buffer[38]) = tsg->Port; /* PortNumber (0xD3D = 3389) */ - *((UINT32*) &buffer[40]) = 0x00000001; /* NumResourceNames */ *((UINT32*) &buffer[44]) = 0x00020004; /* ResourceNamePtr */ *((UINT32*) &buffer[48]) = count; /* MaxCount */ *((UINT32*) &buffer[52]) = 0; /* Offset */ *((UINT32*) &buffer[56]) = count; /* ActualCount */ CopyMemory(&buffer[60], tsg->Hostname, count * 2); /* Array */ - status = rpc_write(rpc, buffer, length, TsProxyCreateChannelOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -986,24 +901,19 @@ BOOL TsProxyCreateChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) buffer = &buffer[24]; offset = 0; - /* ChannelContext (20 bytes) */ CopyMemory(&tsg->ChannelContext.ContextType, &buffer[offset], 4); /* ContextType (4 bytes) */ CopyMemory(tsg->ChannelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid (16 bytes) */ - #ifdef WITH_DEBUG_TSG - fprintf(stderr, "ChannelContext:\n"); - winpr_HexDump((void*) &tsg->ChannelContext, 20); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ChannelContext:"); + winpr_HexDump(TAG, WLOG_DEBUG, (void*) &tsg->ChannelContext, 20); #endif - rpc_client_receive_pool_return(rpc, pdu); - return TRUE; } BOOL TsProxyCreateChannel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, PTSENDPOINTINFO tsEndPointInfo, - PCHANNEL_CONTEXT_HANDLE_SERIALIZE* channelContext, UINT32* channelId) + PCHANNEL_CONTEXT_HANDLE_SERIALIZE* channelContext, UINT32* channelId) { /** * OpNum = 4 @@ -1015,12 +925,11 @@ BOOL TsProxyCreateChannel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnel * [out] unsigned long* channelId * ); */ - - DEBUG_TSG("TsProxyCreateChannel"); + DEBUG_TSG(""); if (!TsProxyCreateChannelWriteRequest(tsg, tunnelContext)) { - fprintf(stderr, "TsProxyCreateChannel: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } @@ -1033,21 +942,17 @@ BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, PCHANNEL_CONTEXT_HANDLE_NOSERI BYTE* buffer; UINT32 length; rdpRpc* rpc = tsg->rpc; - length = 20; buffer = (BYTE*) malloc(length); - /* TunnelContext */ CopyMemory(&buffer[0], &tsg->ChannelContext.ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], tsg->ChannelContext.ContextUuid, 16); /* ContextUuid */ - status = rpc_write(rpc, buffer, length, TsProxyCloseChannelOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -1057,7 +962,6 @@ BOOL TsProxyCloseChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) UINT32 length; UINT32 offset; rdpRpc* rpc = tsg->rpc; - pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) @@ -1070,33 +974,29 @@ BOOL TsProxyCloseChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) buffer = &buffer[24]; offset = 0; - rpc_client_receive_pool_return(rpc, pdu); - return TRUE; } HRESULT TsProxyCloseChannel(rdpTsg* tsg, PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* context) { RPC_PDU* pdu = NULL; - /** * HRESULT TsProxyCloseChannel( * [in, out] PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* context * ); */ - - DEBUG_TSG("TsProxyCloseChannel"); + DEBUG_TSG(""); if (!TsProxyCloseChannelWriteRequest(tsg, context)) { - fprintf(stderr, "TsProxyCloseChannel: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } if (!TsProxyCloseChannelReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyCloseChannel: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1109,21 +1009,17 @@ BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_SERIALIZ BYTE* buffer; UINT32 length; rdpRpc* rpc = tsg->rpc; - length = 20; buffer = (BYTE*) malloc(length); - /* TunnelContext */ CopyMemory(&buffer[0], &tsg->TunnelContext.ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], tsg->TunnelContext.ContextUuid, 16); /* ContextUuid */ - status = rpc_write(rpc, buffer, length, TsProxyCloseTunnelOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -1133,7 +1029,6 @@ BOOL TsProxyCloseTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) UINT32 length; UINT32 offset; rdpRpc* rpc = tsg->rpc; - pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) @@ -1146,33 +1041,29 @@ BOOL TsProxyCloseTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) buffer = &buffer[24]; offset = 0; - rpc_client_receive_pool_return(rpc, pdu); - return TRUE; } HRESULT TsProxyCloseTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_SERIALIZE* context) { RPC_PDU* pdu = NULL; - /** * HRESULT TsProxyCloseTunnel( * [in, out] PTUNNEL_CONTEXT_HANDLE_SERIALIZE* context * ); */ - - DEBUG_TSG("TsProxyCloseTunnel"); + DEBUG_TSG(""); if (!TsProxyCloseTunnelWriteRequest(tsg, context)) { - fprintf(stderr, "TsProxyCloseTunnel: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } if (!TsProxyCloseTunnelReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyCloseTunnel: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1185,22 +1076,17 @@ BOOL TsProxySetupReceivePipeWriteRequest(rdpTsg* tsg) BYTE* buffer; UINT32 length; rdpRpc* rpc = tsg->rpc; - length = 20; - buffer = (BYTE*) malloc(length); - /* ChannelContext */ CopyMemory(&buffer[0], &tsg->ChannelContext.ContextType, 4); /* ContextType */ CopyMemory(&buffer[4], tsg->ChannelContext.ContextUuid, 16); /* ContextUuid */ - status = rpc_write(rpc, buffer, length, TsProxySetupReceivePipeOpnum); if (status <= 0) return FALSE; free(buffer); - return TRUE; } @@ -1212,7 +1098,6 @@ BOOL TsProxySetupReceivePipeReadResponse(rdpTsg* tsg, RPC_PDU* pdu) BOOL TsProxySetupReceivePipe(handle_t IDL_handle, BYTE* pRpcMessage) { rdpTsg* tsg; - /** * OpNum = 8 * @@ -1220,14 +1105,12 @@ BOOL TsProxySetupReceivePipe(handle_t IDL_handle, BYTE* pRpcMessage) * [in, max_is(32767)] byte pRpcMessage[] * ); */ - tsg = (rdpTsg*) IDL_handle; - - DEBUG_TSG("TsProxySetupReceivePipe"); + DEBUG_TSG(""); if (!TsProxySetupReceivePipeWriteRequest(tsg)) { - fprintf(stderr, "TsProxySetupReceivePipe: error writing request\n"); + WLog_ERR(TAG, "error writing request"); return FALSE; } @@ -1240,21 +1123,18 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) RpcClientCall* call; rdpRpc* rpc = tsg->rpc; rdpSettings* settings = rpc->settings; - tsg->Port = port; ConvertToUnicode(CP_UTF8, 0, hostname, -1, &tsg->Hostname, 0); ConvertToUnicode(CP_UTF8, 0, settings->ComputerName, -1, &tsg->MachineName, 0); if (!rpc_connect(rpc)) { - fprintf(stderr, "rpc_connect failed!\n"); + WLog_ERR(TAG, "rpc_connect failed!"); return FALSE; } DEBUG_TSG("rpc_connect success"); - tsg->state = TSG_STATE_INITIAL; - rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; @@ -1310,7 +1190,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) if (!TsProxyCreateTunnelReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyCreateTunnel: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1356,7 +1236,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyAuthorizeTunnel: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1393,8 +1273,10 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) return FALSE; pdu = rpc_recv_dequeue_pdu(rpc); - if (!pdu) { - fprintf(stderr, "TsProxyCreateChannel: error reading response\n"); + + if (!pdu) + { + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1404,7 +1286,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) { if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyMakeTunnelCall: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1413,7 +1295,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) if (!TsProxyCreateChannelReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxyCreateChannel: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } @@ -1445,16 +1327,14 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) if (!TsProxySetupReceivePipeReadResponse(tsg, pdu)) { - fprintf(stderr, "TsProxySetupReceivePipe: error reading response\n"); + WLog_ERR(TAG, "error reading response"); return FALSE; } -#endif +#endif rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; - - fprintf(stderr, "TS Gateway Connection Success\n"); - + WLog_INFO(TAG, "TS Gateway Connection Success"); return TRUE; } @@ -1479,15 +1359,13 @@ BOOL tsg_disconnect(rdpTsg* tsg) * |<-------------TsProxyCloseTunnel Response----------| * | | */ - - if (tsg == NULL) return FALSE; tsg->rpc->client->SynchronousReceive = TRUE; /* if we are already in state pending (i.e. if a server initiated disconnect was issued) - we have to skip TsProxyCloseChannel - see Figure 13 in section 3.2.3 + we have to skip TsProxyCloseChannel - see Figure 13 in section 3.2.3 */ if (tsg->state != TSG_STATE_TUNNEL_CLOSE_PENDING) { @@ -1516,14 +1394,13 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) if (rpc->transport->layer == TRANSPORT_LAYER_CLOSED) { - fprintf(stderr, "tsg_read error: connection lost\n"); + WLog_ERR(TAG, "tsg_read error: connection lost"); return -1; } if (tsg->PendingPdu) { CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; - CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; @@ -1538,8 +1415,8 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) return CopyLength; } - tsg->pdu = rpc_recv_peek_pdu(rpc); + if (!tsg->pdu) { if (!tsg->rpc->client->SynchronousReceive) @@ -1552,9 +1429,7 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) tsg->PendingPdu = TRUE; tsg->BytesAvailable = Stream_Length(tsg->pdu->s); tsg->BytesRead = 0; - CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; - CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; @@ -1567,7 +1442,6 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) } return CopyLength; - } int tsg_write(rdpTsg* tsg, BYTE* data, UINT32 length) @@ -1576,13 +1450,15 @@ int tsg_write(rdpTsg* tsg, BYTE* data, UINT32 length) if (tsg->rpc->transport->layer == TRANSPORT_LAYER_CLOSED) { - fprintf(stderr, "%s: error, connection lost\n", __FUNCTION__); + WLog_ERR(TAG, "error, connection lost"); return -1; } status = TsProxySendToServer((handle_t) tsg, data, 1, &length); + if (status < 0) return -1; + return length; } @@ -1590,16 +1466,13 @@ BOOL tsg_set_blocking_mode(rdpTsg* tsg, BOOL blocking) { tsg->rpc->client->SynchronousSend = TRUE; tsg->rpc->client->SynchronousReceive = blocking; - tsg->transport->GatewayEvent = Queue_Event(tsg->rpc->client->ReceiveQueue); - return TRUE; } rdpTsg* tsg_new(rdpTransport* transport) { rdpTsg* tsg; - tsg = (rdpTsg*) calloc(1, sizeof(rdpTsg)); if (!tsg) @@ -1614,7 +1487,6 @@ rdpTsg* tsg_new(rdpTransport* transport) tsg->PendingPdu = FALSE; return tsg; - out_free: free(tsg); return NULL; diff --git a/libfreerdp/core/gateway/tsg.h b/libfreerdp/core/gateway/tsg.h index e041b224c..1bbfdf553 100644 --- a/libfreerdp/core/gateway/tsg.h +++ b/libfreerdp/core/gateway/tsg.h @@ -38,7 +38,7 @@ typedef struct rdp_tsg rdpTsg; #include #include -#include +#include enum _TSG_STATE { @@ -317,10 +317,11 @@ BOOL tsg_set_blocking_mode(rdpTsg* tsg, BOOL blocking); rdpTsg* tsg_new(rdpTransport* transport); void tsg_free(rdpTsg* tsg); +#define TSG_TAG FREERDP_TAG("core.gateway.tsg") #ifdef WITH_DEBUG_TSG -#define DEBUG_TSG(fmt, ...) DEBUG_CLASS(TSG, fmt, ## __VA_ARGS__) +#define DEBUG_TSG(fmt, ...) WLog_DBG(TSG_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_TSG(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_TSG(fmt, ...) do { } while (0) #endif #endif /* FREERDP_CORE_TSG_H */ diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 957946fb1..625180a8e 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -23,9 +23,13 @@ #include +#include + #include "gcc.h" #include "certificate.h" +#define TAG FREERDP_TAG("core") + /** * T.124 GCC is defined in: * @@ -274,7 +278,7 @@ BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs) if (!gcc_read_server_data_blocks(s, mcs, length)) { - fprintf(stderr, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed\n"); + WLog_ERR(TAG, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed"); return FALSE; } @@ -374,7 +378,7 @@ BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length) break; default: - fprintf(stderr, "Unknown GCC client data block: 0x%04X\n", type); + WLog_ERR(TAG, "Unknown GCC client data block: 0x%04X", type); Stream_Seek(s, blockLength - 4); break; } @@ -383,7 +387,7 @@ BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length) if (endPos != (begPos + blockLength)) { - fprintf(stderr, "Error parsing GCC client data block 0x%04X: Actual Offset: %d Expected Offset: %d\n", + WLog_ERR(TAG, "Error parsing GCC client data block 0x%04X: Actual Offset: %d Expected Offset: %d", type, endPos, begPos + blockLength); } @@ -419,16 +423,16 @@ void gcc_write_client_data_blocks(wStream* s, rdpMcs* mcs) { if (settings->UseMultimon && !settings->SpanMonitors) { - fprintf(stderr, "WARNING: true multi monitor support was not advertised by server!\n"); + WLog_ERR(TAG, "WARNING: true multi monitor support was not advertised by server!"); if (settings->ForceMultimon) { - fprintf(stderr, "Sending multi monitor information anyway (may break connectivity!)\n"); + WLog_ERR(TAG, "Sending multi monitor information anyway (may break connectivity!)"); gcc_write_client_monitor_data(s, mcs); } else { - fprintf(stderr, "Use /multimon:force to force sending multi monitor information\n"); + WLog_ERR(TAG, "Use /multimon:force to force sending multi monitor information"); } } } @@ -447,7 +451,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) if (!gcc_read_user_data_header(s, &type, &blockLength)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_user_data_header failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_user_data_header failed"); return FALSE; } @@ -456,7 +460,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) case SC_CORE: if (!gcc_read_server_core_data(s, mcs)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_core_data failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_core_data failed"); return FALSE; } break; @@ -464,7 +468,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) case SC_SECURITY: if (!gcc_read_server_security_data(s, mcs)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_security_data failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_security_data failed"); return FALSE; } break; @@ -472,7 +476,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) case SC_NET: if (!gcc_read_server_network_data(s, mcs)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_network_data failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_network_data failed"); return FALSE; } break; @@ -480,7 +484,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) case SC_MCS_MSGCHANNEL: if (!gcc_read_server_message_channel_data(s, mcs)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed"); return FALSE; } break; @@ -488,13 +492,13 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) case SC_MULTITRANSPORT: if (!gcc_read_server_multitransport_channel_data(s, mcs)) { - fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_multitransport_channel_data failed\n"); + WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_multitransport_channel_data failed"); return FALSE; } break; default: - fprintf(stderr, "gcc_read_server_data_blocks: ignoring type=%hu\n", type); + WLog_ERR(TAG, "gcc_read_server_data_blocks: ignoring type=%hu", type); break; } offset += blockLength; @@ -554,7 +558,8 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) { char* str = NULL; UINT32 version; - UINT32 color_depth; + BYTE connectionType = 0; + UINT32 clientColorDepth; UINT16 colorDepth = 0; UINT16 postBeta2ColorDepth = 0; UINT16 highColorDepth = 0; @@ -565,6 +570,7 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) UINT16 desktopOrientation = 0; UINT32 desktopScaleFactor = 0; UINT32 deviceScaleFactor = 0; + UINT16 earlyCapabilityFlags = 0; rdpSettings* settings = mcs->settings; /* Length of all required fields, until imeFileName */ @@ -633,7 +639,8 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (blockLength < 2) break; - Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */ + Stream_Read_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */ + settings->EarlyCapabilityFlags = (UINT32) earlyCapabilityFlags; blockLength -= 2; if (blockLength < 64) @@ -647,7 +654,7 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (blockLength < 1) break; - Stream_Read_UINT8(s, settings->PerformanceFlags); /* connectionType (1 byte) */ + Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */ blockLength -= 1; if (blockLength < 1) @@ -691,29 +698,29 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (highColorDepth > 0) { - if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION) - color_depth = 32; + if (earlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION) + clientColorDepth = 32; else - color_depth = highColorDepth; + clientColorDepth = highColorDepth; } else if (postBeta2ColorDepth > 0) { switch (postBeta2ColorDepth) { case RNS_UD_COLOR_4BPP: - color_depth = 4; + clientColorDepth = 4; break; case RNS_UD_COLOR_8BPP: - color_depth = 8; + clientColorDepth = 8; break; case RNS_UD_COLOR_16BPP_555: - color_depth = 15; + clientColorDepth = 15; break; case RNS_UD_COLOR_16BPP_565: - color_depth = 16; + clientColorDepth = 16; break; case RNS_UD_COLOR_24BPP: - color_depth = 24; + clientColorDepth = 24; break; default: return FALSE; @@ -724,10 +731,10 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) switch (colorDepth) { case RNS_UD_COLOR_4BPP: - color_depth = 4; + clientColorDepth = 4; break; case RNS_UD_COLOR_8BPP: - color_depth = 8; + clientColorDepth = 8; break; default: return FALSE; @@ -738,8 +745,25 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) * If we are in server mode, accept client's color depth only if * it is smaller than ours. This is what Windows server does. */ - if ((color_depth < settings->ColorDepth) || !settings->ServerMode) - settings->ColorDepth = color_depth; + if ((clientColorDepth < settings->ColorDepth) || !settings->ServerMode) + settings->ColorDepth = clientColorDepth; + + if (settings->NetworkAutoDetect) + settings->NetworkAutoDetect = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT) ? TRUE : FALSE; + + if (settings->SupportHeartbeatPdu) + settings->SupportHeartbeatPdu = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE; + + if (settings->SupportGraphicsPipeline) + settings->SupportGraphicsPipeline = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE; + + if (settings->SupportDynamicTimeZone) + settings->SupportDynamicTimeZone = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE; + + if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE)) + connectionType = 0; + + settings->ConnectionType = connectionType; return TRUE; } @@ -784,7 +808,7 @@ void gcc_write_client_core_data(wStream* s, rdpMcs* mcs) if (clientNameLength >= 16) { clientNameLength = 16; - clientName[clientNameLength-1] = 0; + clientName[clientNameLength - 1] = 0; } Stream_Write(s, clientName, (clientNameLength * 2)); @@ -808,13 +832,17 @@ void gcc_write_client_core_data(wStream* s, rdpMcs* mcs) RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT; - connectionType = settings->ConnectionType; earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU; - if (settings->RemoteFxCodec) - connectionType = CONNECTION_TYPE_LAN; + if (settings->NetworkAutoDetect) + settings->ConnectionType = CONNECTION_TYPE_AUTODETECT; - if (connectionType != 0) + if (settings->RemoteFxCodec && !settings->NetworkAutoDetect) + settings->ConnectionType = CONNECTION_TYPE_LAN; + + connectionType = settings->ConnectionType; + + if (connectionType) earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE; if (settings->ColorDepth == 32) @@ -844,7 +872,7 @@ void gcc_write_client_core_data(wStream* s, rdpMcs* mcs) if (clientDigProductIdLength >= 32) { clientDigProductIdLength = 32; - clientDigProductId[clientDigProductIdLength-1] = 0; + clientDigProductId[clientDigProductIdLength - 1] = 0; } Stream_Write(s, clientDigProductId, (clientDigProductIdLength * 2) ); Stream_Zero(s, 64 - (clientDigProductIdLength * 2) ); @@ -888,13 +916,20 @@ BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs) void gcc_write_server_core_data(wStream* s, rdpMcs* mcs) { + UINT32 version; + UINT32 earlyCapabilityFlags = 0; rdpSettings* settings = mcs->settings; gcc_write_user_data_header(s, SC_CORE, 16); - Stream_Write_UINT32(s, settings->RdpVersion == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS); - Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */ - Stream_Write_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */ + version = settings->RdpVersion == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS; + + if (settings->SupportDynamicTimeZone) + earlyCapabilityFlags |= RNS_UD_SC_DYNAMIC_DST_SUPPORTED; + + Stream_Write_UINT32(s, version); /* version (4 bytes) */ + Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */ + Stream_Write_UINT32(s, earlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */ } /** @@ -1174,7 +1209,7 @@ void gcc_write_server_security_data(wStream* s, rdpMcs* mcs) md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } @@ -1269,8 +1304,8 @@ BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs) if (channelCount != mcs->channelCount) { - fprintf(stderr, "requested %d channels, got %d instead\n", - mcs->channelCount, channelCount); + WLog_ERR(TAG, "requested %d channels, got %d instead", + mcs->channelCount, channelCount); /* we ensure that the response is not bigger than the request */ @@ -1333,6 +1368,15 @@ BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (flags & REDIRECTED_SESSIONID_FIELD_VALID) settings->RedirectedSessionId = redirectedSessionId; + if (blockLength != 8) + { + if (Stream_GetRemainingLength(s) >= (blockLength - 8)) + { + /* The old Microsoft Mac RDP client can send a pad here */ + Stream_Seek(s, (blockLength - 8)); + } + } + return TRUE; } diff --git a/libfreerdp/core/graphics.c b/libfreerdp/core/graphics.c index 218f10c60..90a781af8 100644 --- a/libfreerdp/core/graphics.c +++ b/libfreerdp/core/graphics.c @@ -33,11 +33,11 @@ rdpBitmap* Bitmap_Alloc(rdpContext* context) rdpGraphics* graphics; graphics = context->graphics; - bitmap = (rdpBitmap*) malloc(graphics->Bitmap_Prototype->size); + bitmap = (rdpBitmap*) calloc(1, graphics->Bitmap_Prototype->size); - if (bitmap != NULL) + if (bitmap) { - memcpy(bitmap, context->graphics->Bitmap_Prototype, sizeof(rdpBitmap)); + CopyMemory(bitmap, graphics->Bitmap_Prototype, sizeof(rdpBitmap)); bitmap->data = NULL; } @@ -51,12 +51,12 @@ void Bitmap_New(rdpContext* context, rdpBitmap* bitmap) void Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) { - if (bitmap != NULL) + if (bitmap) { bitmap->Free(context, bitmap); - if (bitmap->data != NULL) - free(bitmap->data); + if (bitmap->data) + _aligned_free(bitmap->data); free(bitmap); } @@ -84,7 +84,7 @@ void Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) void graphics_register_bitmap(rdpGraphics* graphics, rdpBitmap* bitmap) { - memcpy(graphics->Bitmap_Prototype, bitmap, sizeof(rdpBitmap)); + CopyMemory(graphics->Bitmap_Prototype, bitmap, sizeof(rdpBitmap)); } /* Pointer Class */ @@ -95,11 +95,11 @@ rdpPointer* Pointer_Alloc(rdpContext* context) rdpGraphics* graphics; graphics = context->graphics; - pointer = (rdpPointer*) malloc(graphics->Pointer_Prototype->size); + pointer = (rdpPointer*) calloc(1, graphics->Pointer_Prototype->size); - if (pointer != NULL) + if (pointer) { - memcpy(pointer, context->graphics->Pointer_Prototype, sizeof(rdpPointer)); + CopyMemory(pointer, graphics->Pointer_Prototype, sizeof(rdpPointer)); } return pointer; @@ -112,7 +112,7 @@ void Pointer_New(rdpContext* context, rdpPointer* pointer) void Pointer_Free(rdpContext* context, rdpPointer* pointer) { - if (pointer != NULL) + if (pointer) { pointer->Free(context, pointer); @@ -150,7 +150,7 @@ void Pointer_SetDefault(rdpContext* context) void graphics_register_pointer(rdpGraphics* graphics, rdpPointer* pointer) { - memcpy(graphics->Pointer_Prototype, pointer, sizeof(rdpPointer)); + CopyMemory(graphics->Pointer_Prototype, pointer, sizeof(rdpPointer)); } /* Glyph Class */ @@ -161,11 +161,11 @@ rdpGlyph* Glyph_Alloc(rdpContext* context) rdpGraphics* graphics; graphics = context->graphics; - glyph = (rdpGlyph*) malloc(graphics->Glyph_Prototype->size); + glyph = (rdpGlyph*) calloc(1, graphics->Glyph_Prototype->size); - if (glyph != NULL) + if (glyph) { - memcpy(glyph, context->graphics->Glyph_Prototype, sizeof(rdpGlyph)); + CopyMemory(glyph, graphics->Glyph_Prototype, sizeof(rdpGlyph)); } return glyph; @@ -198,7 +198,7 @@ void Glyph_EndDraw(rdpContext* context, int x, int y, int width, int height, UIN void graphics_register_glyph(rdpGraphics* graphics, rdpGlyph* glyph) { - memcpy(graphics->Glyph_Prototype, glyph, sizeof(rdpGlyph)); + CopyMemory(graphics->Glyph_Prototype, glyph, sizeof(rdpGlyph)); } /* Graphics Module */ @@ -207,28 +207,35 @@ rdpGraphics* graphics_new(rdpContext* context) { rdpGraphics* graphics; - graphics = (rdpGraphics*) malloc(sizeof(rdpGraphics)); + graphics = (rdpGraphics*) calloc(1, sizeof(rdpGraphics)); - if (graphics != NULL) + if (graphics) { - ZeroMemory(graphics, sizeof(rdpGraphics)); - graphics->context = context; - graphics->Bitmap_Prototype = (rdpBitmap*) malloc(sizeof(rdpBitmap)); - ZeroMemory(graphics->Bitmap_Prototype, sizeof(rdpBitmap)); + graphics->Bitmap_Prototype = (rdpBitmap*) calloc(1, sizeof(rdpBitmap)); + + if (!graphics->Bitmap_Prototype) + return NULL; + graphics->Bitmap_Prototype->size = sizeof(rdpBitmap); graphics->Bitmap_Prototype->New = Bitmap_New; graphics->Bitmap_Prototype->Free = Bitmap_Free; - graphics->Pointer_Prototype = (rdpPointer*) malloc(sizeof(rdpPointer)); - ZeroMemory(graphics->Pointer_Prototype, sizeof(rdpPointer)); + graphics->Pointer_Prototype = (rdpPointer*) calloc(1, sizeof(rdpPointer)); + + if (!graphics->Pointer_Prototype) + return NULL; + graphics->Pointer_Prototype->size = sizeof(rdpPointer); graphics->Pointer_Prototype->New = Pointer_New; graphics->Pointer_Prototype->Free = Pointer_Free; - graphics->Glyph_Prototype = (rdpGlyph*) malloc(sizeof(rdpGlyph)); - ZeroMemory(graphics->Glyph_Prototype, sizeof(rdpGlyph)); + graphics->Glyph_Prototype = (rdpGlyph*) calloc(1, sizeof(rdpGlyph)); + + if (!graphics->Glyph_Prototype) + return NULL; + graphics->Glyph_Prototype->size = sizeof(rdpGlyph); graphics->Glyph_Prototype->New = Glyph_New; graphics->Glyph_Prototype->Free = Glyph_Free; @@ -239,7 +246,7 @@ rdpGraphics* graphics_new(rdpContext* context) void graphics_free(rdpGraphics* graphics) { - if (graphics != NULL) + if (graphics) { free(graphics->Bitmap_Prototype); free(graphics->Pointer_Prototype); diff --git a/libfreerdp/core/heartbeat.c b/libfreerdp/core/heartbeat.c index 3989ae390..41addf172 100644 --- a/libfreerdp/core/heartbeat.c +++ b/libfreerdp/core/heartbeat.c @@ -40,17 +40,18 @@ int rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT8(s, count1); /* count1 (1 byte) */ Stream_Read_UINT8(s, count2); /* count2 (1 byte) */ - DEBUG_HEARTBEAT("received Heartbeat PDU -> period=%u, count1=%u, count2=%u", period, count1, count2); + WLog_DBG(HEARTBEAT_TAG, "received Heartbeat PDU -> period=%u, count1=%u, count2=%u", period, count1, count2); return 0; } rdpHeartbeat* heartbeat_new(void) { - rdpHeartbeat* heartbeat = (rdpHeartbeat*)malloc(sizeof(rdpHeartbeat)); + rdpHeartbeat* heartbeat = (rdpHeartbeat*) calloc(1, sizeof(rdpHeartbeat)); + if (heartbeat) { - ZeroMemory(heartbeat, sizeof(rdpHeartbeat)); + } return heartbeat; diff --git a/libfreerdp/core/heartbeat.h b/libfreerdp/core/heartbeat.h index 80e3f46a3..29bd12793 100644 --- a/libfreerdp/core/heartbeat.h +++ b/libfreerdp/core/heartbeat.h @@ -25,6 +25,7 @@ typedef struct rdp_heartbeat rdpHeartbeat; #include "rdp.h" #include +#include #include @@ -38,10 +39,6 @@ int rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s); rdpHeartbeat* heartbeat_new(void); void heartbeat_free(rdpHeartbeat* heartbeat); -#ifdef WITH_DEBUG_HEARTBEAT -#define DEBUG_HEARTBEAT(fmt, ...) DEBUG_CLASS(HEARTBEAT, fmt, ## __VA_ARGS__) -#else -#define DEBUG_HEARTBEAT(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) -#endif +#define HEARTBEAT_TAG FREERDP_TAG("core.heartbeat") #endif /* __HEARTBEAT_H */ diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 6e1696833..9fd499a8a 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -23,12 +23,15 @@ #include #include +#include #include #include "timezone.h" #include "info.h" +#define TAG FREERDP_TAG("core") + #define INFO_TYPE_LOGON 0x00000000 #define INFO_TYPE_LOGON_LONG 0x00000001 #define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 @@ -67,7 +70,7 @@ BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) char *base64; base64 = crypto_base64_encode((BYTE *) autoReconnectCookie, sizeof(ARC_SC_PRIVATE_PACKET)); - fprintf(stderr, "Reconnect-cookie: %s\n", base64); + WLog_INFO(TAG, "Reconnect-cookie: %s", base64); free(base64); } return TRUE; @@ -105,13 +108,31 @@ BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) { + CryptoHmac hmac; + BYTE nullRandom[32]; + BYTE cryptSecurityVerifier[16]; ARC_CS_PRIVATE_PACKET* autoReconnectCookie; autoReconnectCookie = settings->ClientAutoReconnectCookie; + /* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */ + + hmac = crypto_hmac_new(); + ZeroMemory(nullRandom, sizeof(nullRandom)); + + crypto_hmac_md5_init(hmac, autoReconnectCookie->securityVerifier, 16); + + if (settings->ClientRandomLength > 0) + crypto_hmac_update(hmac, settings->ClientRandom, settings->ClientRandomLength); + else + crypto_hmac_update(hmac, nullRandom, sizeof(nullRandom)); + + crypto_hmac_final(hmac, cryptSecurityVerifier, 16); + crypto_hmac_free(hmac); + Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ - Stream_Write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier */ + Stream_Write(s, cryptSecurityVerifier, 16); /* SecurityVerifier */ } /** @@ -238,8 +259,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) CryptoHmac hmac; ARC_SC_PRIVATE_PACKET* serverCookie; ARC_CS_PRIVATE_PACKET* clientCookie; - - printf("Sending auto reconnect\n"); + WLog_DBG(TAG, "Sending auto reconnect"); serverCookie = settings->ServerAutoReconnectCookie; clientCookie = settings->ClientAutoReconnectCookie; @@ -250,7 +270,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) hmac = crypto_hmac_new(); if (!hmac) { - fprintf(stderr, "%s: unable to allocate hmac\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate hmac"); goto out_free; } @@ -393,15 +413,15 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) void rdp_write_info_packet(wStream* s, rdpSettings* settings) { UINT32 flags; - WCHAR* domain = NULL; + WCHAR* domainW = NULL; int cbDomain = 0; - WCHAR* userName = NULL; + WCHAR* userNameW = NULL; int cbUserName = 0; - WCHAR* password = NULL; + WCHAR* passwordW = NULL; int cbPassword = 0; - WCHAR* alternateShell = NULL; + WCHAR* alternateShellW = NULL; int cbAlternateShell = 0; - WCHAR* workingDir = NULL; + WCHAR* workingDirW = NULL; int cbWorkingDir = 0; BOOL usedPasswordCookie = FALSE; @@ -431,6 +451,9 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) if (settings->RemoteConsoleAudio) flags |= INFO_REMOTECONSOLEAUDIO; + if (settings->HiDefRemoteApp) + flags |= INFO_HIDEF_RAIL_SUPPORTED; + if (settings->CompressionEnabled) { flags |= INFO_COMPRESSION; @@ -439,30 +462,70 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) if (settings->Domain) { - cbDomain = ConvertToUnicode(CP_UTF8, 0, settings->Domain, -1, &domain, 0) * 2; + cbDomain = ConvertToUnicode(CP_UTF8, 0, settings->Domain, -1, &domainW, 0) * 2; } else { - domain = NULL; + domainW = NULL; cbDomain = 0; } - cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userName, 0) * 2; - - if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + if (!settings->RemoteAssistanceMode) { - usedPasswordCookie = TRUE; - password = (WCHAR*) settings->RedirectionPassword; - cbPassword = settings->RedirectionPasswordLength - 2; /* Strip double zero termination */ + cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userNameW, 0) * 2; } else { - cbPassword = ConvertToUnicode(CP_UTF8, 0, settings->Password, -1, &password, 0) * 2; + /* user name provided by the expert for connecting to the novice computer */ + cbUserName = ConvertToUnicode(CP_UTF8, 0, settings->Username, -1, &userNameW, 0) * 2; } - cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShell, 0) * 2; + if (!settings->RemoteAssistanceMode) + { + if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + { + usedPasswordCookie = TRUE; + passwordW = (WCHAR*) settings->RedirectionPassword; + cbPassword = settings->RedirectionPasswordLength - 2; /* Strip double zero termination */ + } + else + { + cbPassword = ConvertToUnicode(CP_UTF8, 0, settings->Password, -1, &passwordW, 0) * 2; + } + } + else + { + /* This field MUST be filled with "*" */ + cbPassword = ConvertToUnicode(CP_UTF8, 0, "*", -1, &passwordW, 0) * 2; + } - cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDir, 0) * 2; + if (!settings->RemoteAssistanceMode) + { + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShellW, 0) * 2; + } + else + { + if (settings->RemoteAssistancePassStub) + { + /* This field MUST be filled with "*" */ + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, "*", -1, &alternateShellW, 0) * 2; + } + else + { + /* This field must contain the remote assistance password */ + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistancePassword, -1, &alternateShellW, 0) * 2; + } + } + + if (!settings->RemoteAssistanceMode) + { + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDirW, 0) * 2; + } + else + { + /* Remote Assistance Session Id */ + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistanceSessionId, -1, &workingDirW, 0) * 2; + } Stream_Write_UINT32(s, 0); /* CodePage */ Stream_Write_UINT32(s, flags); /* flags */ @@ -474,32 +537,32 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) Stream_Write_UINT16(s, cbWorkingDir); /* cbWorkingDir */ if (cbDomain > 0) - Stream_Write(s, domain, cbDomain); + Stream_Write(s, domainW, cbDomain); Stream_Write_UINT16(s, 0); if (cbUserName > 0) - Stream_Write(s, userName, cbUserName); + Stream_Write(s, userNameW, cbUserName); Stream_Write_UINT16(s, 0); if (cbPassword > 0) - Stream_Write(s, password, cbPassword); + Stream_Write(s, passwordW, cbPassword); Stream_Write_UINT16(s, 0); if (cbAlternateShell > 0) - Stream_Write(s, alternateShell, cbAlternateShell); + Stream_Write(s, alternateShellW, cbAlternateShell); Stream_Write_UINT16(s, 0); if (cbWorkingDir > 0) - Stream_Write(s, workingDir, cbWorkingDir); + Stream_Write(s, workingDirW, cbWorkingDir); Stream_Write_UINT16(s, 0); - free(domain); - free(userName); - free(alternateShell); - free(workingDir); + free(domainW); + free(userNameW); + free(alternateShellW); + free(workingDirW); if (!usedPasswordCookie) - free(password); + free(passwordW); if (settings->RdpVersion >= 5) rdp_write_extended_info_packet(s, settings); /* extraInfo */ @@ -531,7 +594,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) { if (securityFlags & SEC_REDIRECTION_PKT) { - fprintf(stderr, "Error: SEC_REDIRECTION_PKT unsupported\n"); + WLog_ERR(TAG, "Error: SEC_REDIRECTION_PKT unsupported"); return FALSE; } @@ -539,7 +602,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) { if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) { - fprintf(stderr, "rdp_decrypt failed\n"); + WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; } } @@ -692,7 +755,7 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, infoType); /* infoType (4 bytes) */ - //fprintf(stderr, "%s\n", INFO_TYPE_LOGON_STRINGS[infoType]); + //WLog_ERR(TAG, "%s\n", INFO_TYPE_LOGON_STRINGS[infoType]); switch (infoType) { diff --git a/libfreerdp/core/info.h b/libfreerdp/core/info.h index 3d2758a29..0e98dde3c 100644 --- a/libfreerdp/core/info.h +++ b/libfreerdp/core/info.h @@ -49,6 +49,7 @@ #define INFO_USING_SAVED_CREDS 0x00100000 #define INFO_AUDIOCAPTURE 0x00200000 #define INFO_VIDEO_DISABLE 0x00400000 +#define INFO_HIDEF_RAIL_SUPPORTED 0x02000000 /* Logon Information Types */ #define INFO_TYPE_LOGON 0x00000000 diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index a929b0d96..631dceb0e 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -24,11 +24,14 @@ #include #include +#include #include "message.h" #include "input.h" +#define TAG FREERDP_TAG("core") + void rdp_write_client_input_pdu_header(wStream* s, UINT16 number) { Stream_Write_UINT16(s, 1); /* numberEvents (2 bytes) */ @@ -166,6 +169,27 @@ void input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, U input_send_mouse_event(input, PTR_FLAGS_MOVE, x, y); } +static void input_send_keyboard_pause_event(rdpInput* input) +{ + /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, + * and pause-up sent nothing. However, reverse engineering mstsc shows + * it sending the following sequence: + */ + + /* Control down (0x1D) */ + input_send_keyboard_event(input, 0, + RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + /* Numlock down (0x45) */ + input_send_keyboard_event(input, 0, + RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + /* Control up (0x1D) */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, + RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + /* Numlock up (0x45) */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, + RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); +} + void input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) { wStream* s; @@ -250,6 +274,39 @@ void input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates, UI fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); } +static void input_send_fastpath_keyboard_pause_event(rdpInput* input) +{ + /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, + * and pause-up sent nothing. However, reverse engineering mstsc shows + * it sending the following sequence: + */ + wStream* s; + rdpRdp* rdp = input->context->rdp; + const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5; + const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) + | FASTPATH_INPUT_KBDFLAGS_RELEASE; + + s = fastpath_input_pdu_init_header(rdp->fastpath); + + /* Control down (0x1D) */ + Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + + /* Numlock down (0x45) */ + Stream_Write_UINT8(s, keyDownEvent); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + + /* Control up (0x1D) */ + Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + + /* Numlock down (0x45) */ + Stream_Write_UINT8(s, keyUpEvent); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + + fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); +} + static BOOL input_recv_sync_event(rdpInput* input, wStream* s) { UINT32 toggleFlags; @@ -380,7 +437,7 @@ static BOOL input_recv_event(rdpInput* input, wStream* s) break; default: - fprintf(stderr, "Unknown messageType %u\n", messageType); + WLog_ERR(TAG, "Unknown messageType %u", messageType); /* Each input event uses 6 bytes. */ Stream_Seek(s, 6); break; @@ -420,6 +477,7 @@ void input_register_client_callbacks(rdpInput* input) { input->SynchronizeEvent = input_send_fastpath_synchronize_event; input->KeyboardEvent = input_send_fastpath_keyboard_event; + input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event; input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event; input->MouseEvent = input_send_fastpath_mouse_event; input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event; @@ -429,6 +487,7 @@ void input_register_client_callbacks(rdpInput* input) { input->SynchronizeEvent = input_send_synchronize_event; input->KeyboardEvent = input_send_keyboard_event; + input->KeyboardPauseEvent = input_send_keyboard_pause_event; input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event; input->MouseEvent = input_send_mouse_event; input->ExtendedMouseEvent = input_send_extended_mouse_event; @@ -481,6 +540,11 @@ void freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UIN IFCALL(input->FocusInEvent, input, toggleStates, x, y); } +void freerdp_input_send_keyboard_pause_event(rdpInput* input) +{ + IFCALL(input->KeyboardPauseEvent, input); +} + int input_process_events(rdpInput* input) { return input_message_queue_process_pending_messages(input); diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index bcde65998..7dae05743 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -23,12 +23,15 @@ #endif #include +#include #include "redirection.h" #include "certificate.h" #include "license.h" +#define TAG FREERDP_TAG("core.license") + /* #define LICENSE_NULL_CLIENT_RANDOM 1 */ /* #define LICENSE_NULL_PREMASTER_SECRET 1 */ @@ -36,20 +39,20 @@ static const char* const LICENSE_MESSAGE_STRINGS[] = { - "", - "License Request", - "Platform Challenge", - "New License", - "Upgrade License", - "", "", "", "", "", "", - "", "", "", "", "", "", - "", - "License Info", - "New License Request", - "", - "Platform Challenge Response", - "", "", "", "", "", "", "", "", "", - "Error Alert" + "", + "License Request", + "Platform Challenge", + "New License", + "Upgrade License", + "", "", "", "", "", "", + "", "", "", "", "", "", + "", + "License Info", + "New License Request", + "", + "Platform Challenge Response", + "", "", "", "", "", "", "", "", "", + "Error Alert" }; static const char* const error_codes[] = @@ -82,18 +85,14 @@ void license_print_product_info(LICENSE_PRODUCT_INFO* productInfo) { char* CompanyName = NULL; char* ProductId = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbCompanyName, - productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL); - + productInfo->cbCompanyName / 2, &CompanyName, 0, NULL, NULL); ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) productInfo->pbProductId, - productInfo->cbProductId / 2, &ProductId, 0, NULL, NULL); - - fprintf(stderr, "ProductInfo:\n"); - fprintf(stderr, "\tdwVersion: 0x%08X\n", productInfo->dwVersion); - fprintf(stderr, "\tCompanyName: %s\n", CompanyName); - fprintf(stderr, "\tProductId: %s\n", ProductId); - + productInfo->cbProductId / 2, &ProductId, 0, NULL, NULL); + WLog_INFO(TAG, "ProductInfo:"); + WLog_INFO(TAG, "\tdwVersion: 0x%08X", productInfo->dwVersion); + WLog_INFO(TAG, "\tCompanyName: %s", CompanyName); + WLog_INFO(TAG, "\tProductId: %s", ProductId); free(CompanyName); free(ProductId); } @@ -102,13 +101,12 @@ void license_print_scope_list(SCOPE_LIST* scopeList) { int index; LICENSE_BLOB* scope; - - fprintf(stderr, "ScopeList (%d):\n", scopeList->count); + WLog_INFO(TAG, "ScopeList (%d):", scopeList->count); for (index = 0; index < scopeList->count; index++) { scope = &scopeList->array[index]; - fprintf(stderr, "\t%s\n", (char*) scope->data); + WLog_INFO(TAG, "\t%s", (char*) scope->data); } } @@ -133,7 +131,6 @@ BOOL license_read_preamble(wStream* s, BYTE* bMsgType, BYTE* flags, UINT16* wMsg Stream_Read_UINT8(s, *bMsgType); /* bMsgType (1 byte) */ Stream_Read_UINT8(s, *flags); /* flags (1 byte) */ Stream_Read_UINT16(s, *wMsgSize); /* wMsgSize (2 bytes) */ - return TRUE; } @@ -163,10 +160,10 @@ void license_write_preamble(wStream* s, BYTE bMsgType, BYTE flags, UINT16 wMsgSi wStream* license_send_stream_init(rdpLicense* license) { wStream* s; - license->rdp->sec_flags = SEC_LICENSE_PKT; + if (license->rdp->do_crypt) - license->rdp->sec_flags |= SEC_LICENSE_ENCRYPT_CS; + license->rdp->sec_flags |= SEC_LICENSE_ENCRYPT_CS; s = transport_send_stream_init(license->rdp->transport, 4096); rdp_init_stream(license->rdp, s); @@ -176,7 +173,6 @@ wStream* license_send_stream_init(rdpLicense* license) license->PacketHeaderLength = Stream_GetPosition(s); Stream_Seek(s, LICENSE_PREAMBLE_LENGTH); - return s; } @@ -193,13 +189,10 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type) BYTE flags; UINT16 wMsgSize; rdpRdp* rdp = license->rdp; - DEBUG_LICENSE("Sending %s Packet", LICENSE_MESSAGE_STRINGS[type & 0x1F]); - length = Stream_GetPosition(s); wMsgSize = length - license->PacketHeaderLength; Stream_SetPosition(s, license->PacketHeaderLength); - flags = PREAMBLE_VERSION_3_0; /** @@ -211,17 +204,13 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type) flags |= EXTENDED_ERROR_MSG_SUPPORTED; license_write_preamble(s, type, flags, wMsgSize); - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "Sending %s Packet, length %d\n", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize); - winpr_HexDump(Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize); + WLog_DBG(TAG, "Sending %s Packet, length %d", LICENSE_MESSAGE_STRINGS[type & 0x1F], wMsgSize); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(s) - LICENSE_PREAMBLE_LENGTH, wMsgSize); #endif - Stream_SetPosition(s, length); rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); - rdp->sec_flags = 0; - return TRUE; } @@ -244,7 +233,7 @@ int license_recv(rdpLicense* license, wStream* s) if (!rdp_read_header(license->rdp, s, &length, &channelId)) { - fprintf(stderr, "%s: Incorrect RDP header.\n", __FUNCTION__); + WLog_ERR(TAG, "Incorrect RDP header."); return -1; } @@ -255,7 +244,7 @@ int license_recv(rdpLicense* license, wStream* s) { if (!rdp_decrypt(license->rdp, s, length - 4, securityFlags)) { - fprintf(stderr, "%s: rdp_decrypt failed\n", __FUNCTION__); + WLog_ERR(TAG, "rdp_decrypt failed"); return -1; } } @@ -271,7 +260,7 @@ int license_recv(rdpLicense* license, wStream* s) if (status < 0) { - fprintf(stderr, "%s: unexpected license packet.\n", __FUNCTION__); + WLog_ERR(TAG, "unexpected license packet."); return status; } @@ -286,32 +275,33 @@ int license_recv(rdpLicense* license, wStream* s) switch (bMsgType) { case LICENSE_REQUEST: + if (!license_read_license_request_packet(license, s)) return -1; + license_send_new_license_request_packet(license); break; - case PLATFORM_CHALLENGE: + if (!license_read_platform_challenge_packet(license, s)) return -1; + license_send_platform_challenge_response_packet(license); break; - case NEW_LICENSE: license_read_new_license_packet(license, s); break; - case UPGRADE_LICENSE: license_read_upgrade_license_packet(license, s); break; - case ERROR_ALERT: + if (!license_read_error_alert_packet(license, s)) return -1; - break; + break; default: - fprintf(stderr, "%s: invalid bMsgType:%d\n", __FUNCTION__, bMsgType); + WLog_ERR(TAG, "invalid bMsgType:%d", bMsgType); return FALSE; } @@ -322,11 +312,9 @@ void license_generate_randoms(rdpLicense* license) { ZeroMemory(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ ZeroMemory(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ - #ifndef LICENSE_NULL_CLIENT_RANDOM crypto_nonce(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ #endif - #ifndef LICENSE_NULL_PREMASTER_SECRET crypto_nonce(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ #endif @@ -340,45 +328,28 @@ void license_generate_randoms(rdpLicense* license) void license_generate_keys(rdpLicense* license) { security_master_secret(license->PremasterSecret, license->ClientRandom, - license->ServerRandom, license->MasterSecret); /* MasterSecret */ - + license->ServerRandom, license->MasterSecret); /* MasterSecret */ security_session_key_blob(license->MasterSecret, license->ClientRandom, - license->ServerRandom, license->SessionKeyBlob); /* SessionKeyBlob */ - + license->ServerRandom, license->SessionKeyBlob); /* SessionKeyBlob */ security_mac_salt_key(license->SessionKeyBlob, license->ClientRandom, - license->ServerRandom, license->MacSaltKey); /* MacSaltKey */ - + license->ServerRandom, license->MacSaltKey); /* MacSaltKey */ security_licensing_encryption_key(license->SessionKeyBlob, license->ClientRandom, - license->ServerRandom, license->LicensingEncryptionKey); /* LicensingEncryptionKey */ - + license->ServerRandom, license->LicensingEncryptionKey); /* LicensingEncryptionKey */ #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "ClientRandom:\n"); - winpr_HexDump(license->ClientRandom, CLIENT_RANDOM_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerRandom:\n"); - winpr_HexDump(license->ServerRandom, SERVER_RANDOM_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "PremasterSecret:\n"); - winpr_HexDump(license->PremasterSecret, PREMASTER_SECRET_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "MasterSecret:\n"); - winpr_HexDump(license->MasterSecret, MASTER_SECRET_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "SessionKeyBlob:\n"); - winpr_HexDump(license->SessionKeyBlob, SESSION_KEY_BLOB_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "MacSaltKey:\n"); - winpr_HexDump(license->MacSaltKey, MAC_SALT_KEY_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "LicensingEncryptionKey:\n"); - winpr_HexDump(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ClientRandom:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, CLIENT_RANDOM_LENGTH); + WLog_DBG(TAG, "ServerRandom:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->ServerRandom, SERVER_RANDOM_LENGTH); + WLog_DBG(TAG, "PremasterSecret:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->PremasterSecret, PREMASTER_SECRET_LENGTH); + WLog_DBG(TAG, "MasterSecret:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->MasterSecret, MASTER_SECRET_LENGTH); + WLog_DBG(TAG, "SessionKeyBlob:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->SessionKeyBlob, SESSION_KEY_BLOB_LENGTH); + WLog_DBG(TAG, "MacSaltKey:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->MacSaltKey, MAC_SALT_KEY_LENGTH); + WLog_DBG(TAG, "LicensingEncryptionKey:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); #endif } @@ -391,14 +362,13 @@ void license_generate_hwid(rdpLicense* license) { CryptoMd5 md5; BYTE* mac_address; - ZeroMemory(license->HardwareId, HWID_LENGTH); mac_address = license->rdp->transport->TcpIn->mac_address; - md5 = crypto_md5_init(); + if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } @@ -415,16 +385,14 @@ void license_get_server_rsa_public_key(rdpLicense* license) if (license->ServerCertificate->length < 1) { certificate_read_server_certificate(license->certificate, - license->rdp->settings->ServerCertificate, - license->rdp->settings->ServerCertificateLength); + license->rdp->settings->ServerCertificate, + license->rdp->settings->ServerCertificateLength); } Exponent = license->certificate->cert_info.exponent; Modulus = license->certificate->cert_info.Modulus; ModulusLength = license->certificate->cert_info.ModulusLength; - CopyMemory(license->Exponent, Exponent, 4); - license->ModulusLength = ModulusLength; license->Modulus = (BYTE*) malloc(ModulusLength); memcpy(license->Modulus, Modulus, ModulusLength); @@ -433,51 +401,41 @@ void license_get_server_rsa_public_key(rdpLicense* license) void license_encrypt_premaster_secret(rdpLicense* license) { BYTE* EncryptedPremasterSecret; - license_get_server_rsa_public_key(license); - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "Modulus (%d bits):\n", license->ModulusLength * 8); - winpr_HexDump(license->Modulus, license->ModulusLength); - fprintf(stderr, "\n"); - - fprintf(stderr, "Exponent:\n"); - winpr_HexDump(license->Exponent, 4); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Modulus (%d bits):", license->ModulusLength * 8); + winpr_HexDump(TAG, WLOG_DEBUG, license->Modulus, license->ModulusLength); + WLog_DBG(TAG, "Exponent:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->Exponent, 4); #endif - EncryptedPremasterSecret = (BYTE*) malloc(license->ModulusLength); ZeroMemory(EncryptedPremasterSecret, license->ModulusLength); license->EncryptedPremasterSecret->type = BB_RANDOM_BLOB; license->EncryptedPremasterSecret->length = PREMASTER_SECRET_LENGTH; - #ifndef LICENSE_NULL_PREMASTER_SECRET license->EncryptedPremasterSecret->length = crypto_rsa_public_encrypt(license->PremasterSecret, PREMASTER_SECRET_LENGTH, - license->ModulusLength, license->Modulus, license->Exponent, EncryptedPremasterSecret); + license->ModulusLength, license->Modulus, license->Exponent, EncryptedPremasterSecret); #endif - license->EncryptedPremasterSecret->data = EncryptedPremasterSecret; } void license_decrypt_platform_challenge(rdpLicense* license) { CryptoRc4 rc4; - license->PlatformChallenge->data = (BYTE*) malloc(license->EncryptedPlatformChallenge->length); license->PlatformChallenge->length = license->EncryptedPlatformChallenge->length; - rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); + if (!rc4) { - fprintf(stderr, "%s: unable to allocate a rc4\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a rc4"); return; } crypto_rc4(rc4, license->EncryptedPlatformChallenge->length, - license->EncryptedPlatformChallenge->data, - license->PlatformChallenge->data); - + license->EncryptedPlatformChallenge->data, + license->PlatformChallenge->data); crypto_rc4_free(rc4); } @@ -494,7 +452,6 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) return FALSE; Stream_Read_UINT32(s, productInfo->dwVersion); /* dwVersion (4 bytes) */ - Stream_Read_UINT32(s, productInfo->cbCompanyName); /* cbCompanyName (4 bytes) */ if (Stream_GetRemainingLength(s) < productInfo->cbCompanyName + 4) @@ -502,7 +459,6 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) productInfo->pbCompanyName = (BYTE*) malloc(productInfo->cbCompanyName); Stream_Read(s, productInfo->pbCompanyName, productInfo->cbCompanyName); - Stream_Read_UINT32(s, productInfo->cbProductId); /* cbProductId (4 bytes) */ if (Stream_GetRemainingLength(s) < productInfo->cbProductId) @@ -514,7 +470,6 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) productInfo->pbProductId = (BYTE*) malloc(productInfo->cbProductId); Stream_Read(s, productInfo->pbProductId, productInfo->cbProductId); - return TRUE; } @@ -527,15 +482,12 @@ BOOL license_read_product_info(wStream* s, LICENSE_PRODUCT_INFO* productInfo) LICENSE_PRODUCT_INFO* license_new_product_info() { LICENSE_PRODUCT_INFO* productInfo; - productInfo = (LICENSE_PRODUCT_INFO*) malloc(sizeof(LICENSE_PRODUCT_INFO)); - productInfo->dwVersion = 0; productInfo->cbCompanyName = 0; productInfo->pbCompanyName = NULL; productInfo->cbProductId = 0; productInfo->pbProductId = NULL; - return productInfo; } @@ -577,20 +529,19 @@ BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob) return FALSE; /* - * Server can choose to not send data by setting length to 0. - * If so, it may not bother to set the type, so shortcut the warning - */ + * Server can choose to not send data by setting length to 0. + * If so, it may not bother to set the type, so shortcut the warning + */ if ((blob->type != BB_ANY_BLOB) && (blob->length == 0)) return TRUE; if ((blob->type != wBlobType) && (blob->type != BB_ANY_BLOB)) { - fprintf(stderr, "license binary blob type (%x) does not match expected type (%x).\n", wBlobType, blob->type); + WLog_ERR(TAG, "license binary blob type (%x) does not match expected type (%x).", wBlobType, blob->type); } blob->type = wBlobType; blob->data = (BYTE*) malloc(blob->length); - Stream_Read(s, blob->data, blob->length); /* blobData */ return TRUE; } @@ -605,7 +556,6 @@ BOOL license_read_binary_blob(wStream* s, LICENSE_BLOB* blob) void license_write_binary_blob(wStream* s, LICENSE_BLOB* blob) { Stream_EnsureRemainingCapacity(s, blob->length + 4); - Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */ Stream_Write_UINT16(s, blob->length); /* wBlobLen (2 bytes) */ @@ -616,17 +566,15 @@ void license_write_binary_blob(wStream* s, LICENSE_BLOB* blob) void license_write_encrypted_premaster_secret_blob(wStream* s, LICENSE_BLOB* blob, UINT32 ModulusLength) { UINT32 length; - length = ModulusLength + 8; if (blob->length > ModulusLength) { - fprintf(stderr, "license_write_encrypted_premaster_secret_blob: invalid blob\n"); + WLog_ERR(TAG, "license_write_encrypted_premaster_secret_blob: invalid blob"); return; } Stream_EnsureRemainingCapacity(s, length + 4); - Stream_Write_UINT16(s, blob->type); /* wBlobType (2 bytes) */ Stream_Write_UINT16(s, length); /* wBlobLen (2 bytes) */ @@ -645,12 +593,10 @@ void license_write_encrypted_premaster_secret_blob(wStream* s, LICENSE_BLOB* blo LICENSE_BLOB* license_new_binary_blob(UINT16 type) { LICENSE_BLOB* blob; - blob = (LICENSE_BLOB*) malloc(sizeof(LICENSE_BLOB)); blob->type = type; blob->length = 0; blob->data = NULL; - return blob; } @@ -684,6 +630,7 @@ BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList) return FALSE; Stream_Read_UINT32(s, scopeCount); /* ScopeCount (4 bytes) */ + if (scopeCount > Stream_GetRemainingLength(s) / 4) /* every blob is at least 4 bytes */ return FALSE; @@ -711,11 +658,9 @@ BOOL license_read_scope_list(wStream* s, SCOPE_LIST* scopeList) SCOPE_LIST* license_new_scope_list() { SCOPE_LIST* scopeList; - scopeList = (SCOPE_LIST*) malloc(sizeof(SCOPE_LIST)); scopeList->count = 0; scopeList->array = NULL; - return scopeList; } @@ -784,19 +729,12 @@ BOOL license_read_license_request_packet(rdpLicense* license, wStream* s) license_generate_keys(license); license_generate_hwid(license); license_encrypt_premaster_secret(license); - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "ServerRandom:\n"); - winpr_HexDump(license->ServerRandom, 32); - fprintf(stderr, "\n"); - + WLog_DBG(TAG, "ServerRandom:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->ServerRandom, 32); license_print_product_info(license->ProductInfo); - fprintf(stderr, "\n"); - license_print_scope_list(license->ScopeList); - fprintf(stderr, "\n"); #endif - return TRUE; } @@ -811,14 +749,12 @@ BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) { BYTE MacData[16]; UINT32 ConnectFlags = 0; - DEBUG_LICENSE("Receiving Platform Challenge Packet"); if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, ConnectFlags); /* ConnectFlags, Reserved (4 bytes) */ - /* EncryptedPlatformChallenge */ license->EncryptedPlatformChallenge->type = BB_ANY_BLOB; license_read_binary_blob(s, license->EncryptedPlatformChallenge); @@ -828,26 +764,16 @@ BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) return FALSE; Stream_Read(s, MacData, 16); /* MACData (16 bytes) */ - license_decrypt_platform_challenge(license); - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "ConnectFlags: 0x%08X\n", ConnectFlags); - fprintf(stderr, "\n"); - - fprintf(stderr, "EncryptedPlatformChallenge:\n"); - winpr_HexDump(license->EncryptedPlatformChallenge->data, license->EncryptedPlatformChallenge->length); - fprintf(stderr, "\n"); - - fprintf(stderr, "PlatformChallenge:\n"); - winpr_HexDump(license->PlatformChallenge->data, license->PlatformChallenge->length); - fprintf(stderr, "\n"); - - fprintf(stderr, "MacData:\n"); - winpr_HexDump(MacData, 16); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ConnectFlags: 0x%08X", ConnectFlags); + WLog_DBG(TAG, "EncryptedPlatformChallenge:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPlatformChallenge->data, license->EncryptedPlatformChallenge->length); + WLog_DBG(TAG, "PlatformChallenge:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->PlatformChallenge->data, license->PlatformChallenge->length); + WLog_DBG(TAG, "MacData:"); + winpr_HexDump(TAG, WLOG_DEBUG, MacData, 16); #endif - return TRUE; } @@ -899,8 +825,8 @@ BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s) return FALSE; #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "dwErrorCode: %s, dwStateTransition: %s\n", - error_codes[dwErrorCode], state_transitions[dwStateTransition]); + WLog_DBG(TAG, "dwErrorCode: %s, dwStateTransition: %s", + error_codes[dwErrorCode], state_transitions[dwStateTransition]); #endif if (dwErrorCode == STATUS_VALID_CLIENT) @@ -914,18 +840,14 @@ BOOL license_read_error_alert_packet(rdpLicense* license, wStream* s) case ST_TOTAL_ABORT: license->state = LICENSE_STATE_ABORTED; break; - case ST_NO_TRANSITION: license->state = LICENSE_STATE_COMPLETED; break; - case ST_RESET_PHASE_TO_START: license->state = LICENSE_STATE_AWAIT; break; - case ST_RESEND_LAST_MESSAGE: break; - default: break; } @@ -944,33 +866,21 @@ void license_write_new_license_request_packet(rdpLicense* license, wStream* s) { UINT32 PlatformId; UINT32 PreferredKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA; - PlatformId = CLIENT_OS_ID_WINNT_POST_52 | CLIENT_IMAGE_ID_MICROSOFT; - Stream_Write_UINT32(s, PreferredKeyExchangeAlg); /* PreferredKeyExchangeAlg (4 bytes) */ Stream_Write_UINT32(s, PlatformId); /* PlatformId (4 bytes) */ Stream_Write(s, license->ClientRandom, 32); /* ClientRandom (32 bytes) */ license_write_encrypted_premaster_secret_blob(s, license->EncryptedPremasterSecret, license->ModulusLength); /* EncryptedPremasterSecret */ license_write_binary_blob(s, license->ClientUserName); /* ClientUserName */ license_write_binary_blob(s, license->ClientMachineName); /* ClientMachineName */ - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "PreferredKeyExchangeAlg: 0x%08X\n", PreferredKeyExchangeAlg); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientRandom:\n"); - winpr_HexDump(license->ClientRandom, 32); - fprintf(stderr, "\n"); - - fprintf(stderr, "EncryptedPremasterSecret\n"); - winpr_HexDump(license->EncryptedPremasterSecret->data, license->EncryptedPremasterSecret->length); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientUserName (%d): %s\n", license->ClientUserName->length, (char*) license->ClientUserName->data); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientMachineName (%d): %s\n", license->ClientMachineName->length, (char*) license->ClientMachineName->data); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "PreferredKeyExchangeAlg: 0x%08X", PreferredKeyExchangeAlg); + WLog_DBG(TAG, "ClientRandom:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->ClientRandom, 32); + WLog_DBG(TAG, "EncryptedPremasterSecret"); + winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedPremasterSecret->data, license->EncryptedPremasterSecret->length); + WLog_DBG(TAG, "ClientUserName (%d): %s", license->ClientUserName->length, (char*) license->ClientUserName->data); + WLog_DBG(TAG, "ClientMachineName (%d): %s", license->ClientMachineName->length, (char*) license->ClientMachineName->data); #endif } @@ -984,9 +894,7 @@ void license_send_new_license_request_packet(rdpLicense* license) { wStream* s; char* username; - DEBUG_LICENSE("Sending New License Packet"); - s = license_send_stream_init(license); if (license->rdp->settings->Username != NULL) @@ -996,17 +904,12 @@ void license_send_new_license_request_packet(rdpLicense* license) license->ClientUserName->data = (BYTE*) username; license->ClientUserName->length = strlen(username) + 1; - license->ClientMachineName->data = (BYTE*) license->rdp->settings->ClientHostname; license->ClientMachineName->length = strlen(license->rdp->settings->ClientHostname) + 1; - license_write_new_license_request_packet(license, s); - license_send(license, s, NEW_LICENSE_REQUEST); - license->ClientUserName->data = NULL; license->ClientUserName->length = 0; - license->ClientMachineName->data = NULL; license->ClientMachineName->length = 0; } @@ -1023,7 +926,6 @@ void license_write_platform_challenge_response_packet(rdpLicense* license, wStre { license_write_binary_blob(s, license->EncryptedPlatformChallenge); /* EncryptedPlatformChallengeResponse */ license_write_binary_blob(s, license->EncryptedHardwareId); /* EncryptedHWID */ - Stream_EnsureRemainingCapacity(s, 16); Stream_Write(s, macData, 16); /* MACData */ } @@ -1041,51 +943,39 @@ void license_send_platform_challenge_response_packet(rdpLicense* license) BYTE* buffer; CryptoRc4 rc4; BYTE mac_data[16]; - DEBUG_LICENSE("Sending Platform Challenge Response Packet"); - s = license_send_stream_init(license); - license->EncryptedPlatformChallenge->type = BB_DATA_BLOB; length = license->PlatformChallenge->length + HWID_LENGTH; - buffer = (BYTE*) malloc(length); CopyMemory(buffer, license->PlatformChallenge->data, license->PlatformChallenge->length); CopyMemory(&buffer[license->PlatformChallenge->length], license->HardwareId, HWID_LENGTH); security_mac_data(license->MacSaltKey, buffer, length, mac_data); free(buffer); - buffer = (BYTE*) malloc(HWID_LENGTH); rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); + if (!rc4) { - fprintf(stderr, "%s: unable to allocate a rc4\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a rc4"); free(buffer); return; } + crypto_rc4(rc4, HWID_LENGTH, license->HardwareId, buffer); crypto_rc4_free(rc4); - license->EncryptedHardwareId->type = BB_DATA_BLOB; license->EncryptedHardwareId->data = buffer; license->EncryptedHardwareId->length = HWID_LENGTH; - #ifdef WITH_DEBUG_LICENSE - fprintf(stderr, "LicensingEncryptionKey:\n"); - winpr_HexDump(license->LicensingEncryptionKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "HardwareId:\n"); - winpr_HexDump(license->HardwareId, HWID_LENGTH); - fprintf(stderr, "\n"); - - fprintf(stderr, "EncryptedHardwareId:\n"); - winpr_HexDump(license->EncryptedHardwareId->data, HWID_LENGTH); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "LicensingEncryptionKey:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->LicensingEncryptionKey, 16); + WLog_DBG(TAG, "HardwareId:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->HardwareId, HWID_LENGTH); + WLog_DBG(TAG, "EncryptedHardwareId:"); + winpr_HexDump(TAG, WLOG_DEBUG, license->EncryptedHardwareId->data, HWID_LENGTH); #endif - license_write_platform_challenge_response_packet(license, s, mac_data); - license_send(license, s, PLATFORM_CHALLENGE_RESPONSE); } @@ -1098,16 +988,11 @@ void license_send_platform_challenge_response_packet(rdpLicense* license) BOOL license_send_valid_client_error_packet(rdpLicense* license) { wStream* s; - s = license_send_stream_init(license); - DEBUG_LICENSE("Sending Error Alert Packet"); - Stream_Write_UINT32(s, STATUS_VALID_CLIENT); /* dwErrorCode */ Stream_Write_UINT32(s, ST_NO_TRANSITION); /* dwStateTransition */ - license_write_binary_blob(s, license->ErrorInfo); - return license_send(license, s, ERROR_ALERT); } @@ -1120,13 +1005,11 @@ BOOL license_send_valid_client_error_packet(rdpLicense* license) rdpLicense* license_new(rdpRdp* rdp) { rdpLicense* license; - license = (rdpLicense*) malloc(sizeof(rdpLicense)); if (license != NULL) { ZeroMemory(license, sizeof(rdpLicense)); - license->rdp = rdp; license->state = LICENSE_STATE_AWAIT; license->certificate = certificate_new(); diff --git a/libfreerdp/core/license.h b/libfreerdp/core/license.h index 547c710ef..c8dcdc75e 100644 --- a/libfreerdp/core/license.h +++ b/libfreerdp/core/license.h @@ -28,7 +28,7 @@ typedef struct rdp_license rdpLicense; #include #include -#include +#include #include @@ -240,10 +240,11 @@ BOOL license_send_valid_client_error_packet(rdpLicense* license); rdpLicense* license_new(rdpRdp* rdp); void license_free(rdpLicense* license); +#define LICENSE_TAG FREERDP_TAG("core.license") #ifdef WITH_DEBUG_LICENSE -#define DEBUG_LICENSE(fmt, ...) DEBUG_CLASS(LICENSE, fmt, ## __VA_ARGS__) +#define DEBUG_LICENSE(fmt, ...) WLog_DBG(LICENSE_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_LICENSE(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_LICENSE(fmt, ...) do { } while (0) #endif #endif /* __LICENSE_H */ diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index e37c4c89f..5920a9bbf 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -28,6 +28,7 @@ #include #include +#include #ifndef _WIN32 #include @@ -44,6 +45,8 @@ #include "listener.h" +#define TAG FREERDP_TAG("core.listener") + #ifdef _WIN32 #if _WIN32_WINNT < 0x0600 static const char* inet_ntop(int af, const void* src, char* dst, size_t cnt) @@ -76,16 +79,16 @@ static const char* inet_ntop(int af, const void* src, char* dst, size_t cnt) static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port) { - rdpListener* listener = (rdpListener*) instance->listener; int status; int sockfd; - char servname[10]; - struct addrinfo hints = { 0 }; - struct addrinfo* res; - struct addrinfo* ai; - int option_value; + char addr[64]; void* sin_addr; - char buf[50]; + int option_value; + char servname[16]; + struct addrinfo* ai; + struct addrinfo* res; + struct addrinfo hints = { 0 }; + rdpListener* listener = (rdpListener*) instance->listener; #ifdef _WIN32 u_long arg; #endif @@ -93,7 +96,7 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - if (bind_address == NULL) + if (!bind_address) hints.ai_flags = AI_PASSIVE; sprintf_s(servname, sizeof(servname), "%d", port); @@ -102,30 +105,40 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a if (status != 0) { #ifdef _WIN32 - _tprintf(_T("getaddrinfo error: %s\n"), gai_strerror(status)); + WLog_ERR(_T("getaddrinfo error: %s"), gai_strerror(status)); #else - perror("getaddrinfo"); + WLog_ERR(TAG, "getaddrinfo"); #endif return FALSE; } - for (ai = res; ai && listener->num_sockfds < 5; ai = ai->ai_next) + for (ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6)) continue; sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd == -1) { - perror("socket"); + WLog_ERR(TAG, "socket"); continue; } + if (ai->ai_family == AF_INET) + sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); + else + sin_addr = &(((struct sockaddr_in6*) ai->ai_addr)->sin6_addr); + + inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr)); + + if (strcmp(addr, "::") == 0) + continue; + option_value = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*) &option_value, sizeof(option_value)) == -1) - perror("setsockopt"); + WLog_ERR(TAG, "setsockopt"); #ifndef _WIN32 fcntl(sockfd, F_SETFL, O_NONBLOCK); @@ -139,10 +152,10 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a if (status != 0) { #ifdef _WIN32 - _tprintf(L"bind() failed with error: %u\n", WSAGetLastError()); + WLog_ERR("bind() failed with error: %u", WSAGetLastError()); WSACleanup(); #else - perror("bind"); + WLog_ERR(TAG, "bind"); close(sockfd); #endif continue; @@ -152,21 +165,18 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a if (status != 0) { - perror("listen"); + WLog_ERR(TAG, "listen"); close(sockfd); continue; } + /* FIXME: these file descriptors do not work on Windows */ + listener->sockfds[listener->num_sockfds] = sockfd; listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); listener->num_sockfds++; - if (ai->ai_family == AF_INET) - sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); - else - sin_addr = &(((struct sockaddr_in6*) ai->ai_addr)->sin6_addr); - - fprintf(stderr, "Listening on %s port %s.\n", inet_ntop(ai->ai_family, sin_addr, buf, sizeof(buf)), servname); + WLog_INFO(TAG, "Listening on %s:%s", addr, servname); } freeaddrinfo(res); @@ -186,7 +196,7 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* if (sockfd == -1) { - perror("socket"); + WLog_ERR(TAG, "socket"); return FALSE; } @@ -200,7 +210,7 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* if (status != 0) { - perror("bind"); + WLog_ERR(TAG, "bind"); close(sockfd); return FALSE; } @@ -209,7 +219,7 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* if (status != 0) { - perror("listen"); + WLog_ERR(TAG, "listen"); close(sockfd); return FALSE; } @@ -217,9 +227,7 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* listener->sockfds[listener->num_sockfds] = sockfd; listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); listener->num_sockfds++; - - fprintf(stderr, "Listening on socket %s.\n", addr.sun_path); - + WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path); return TRUE; #else return TRUE; @@ -306,7 +314,8 @@ static BOOL freerdp_listener_check_fds(freerdp_listener* instance) if (errno == EAGAIN || errno == EWOULDBLOCK) continue; #endif - perror("accept"); + WLog_DBG(TAG, "accept"); + if (client) free(client); return FALSE; @@ -346,8 +355,10 @@ freerdp_listener* freerdp_listener_new(void) freerdp_listener* instance; rdpListener* listener; - instance = (freerdp_listener*) malloc(sizeof(freerdp_listener)); - ZeroMemory(instance, sizeof(freerdp_listener)); + instance = (freerdp_listener*) calloc(1, sizeof(freerdp_listener)); + + if (!instance) + return NULL; instance->Open = freerdp_listener_open; instance->OpenLocal = freerdp_listener_open_local; @@ -356,8 +367,10 @@ freerdp_listener* freerdp_listener_new(void) instance->CheckFileDescriptor = freerdp_listener_check_fds; instance->Close = freerdp_listener_close; - listener = (rdpListener*) malloc(sizeof(rdpListener)); - ZeroMemory(listener, sizeof(rdpListener)); + listener = (rdpListener*) calloc(1, sizeof(rdpListener)); + + if (!listener) + return NULL; listener->instance = instance; diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index c47660f19..1660e96d9 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -22,6 +22,7 @@ #endif #include +#include #include "gcc.h" @@ -30,6 +31,8 @@ #include "tpkt.h" #include "client.h" +#define TAG FREERDP_TAG("core") + /** * T.125 MCS is defined in: * @@ -328,16 +331,16 @@ void mcs_write_domain_parameters(wStream* s, DomainParameters* domainParameters) void mcs_print_domain_parameters(DomainParameters* domainParameters) { - fprintf(stderr, "DomainParameters {\n"); - fprintf(stderr, "\tmaxChannelIds:%d\n", domainParameters->maxChannelIds); - fprintf(stderr, "\tmaxUserIds:%d\n", domainParameters->maxUserIds); - fprintf(stderr, "\tmaxTokenIds:%d\n", domainParameters->maxTokenIds); - fprintf(stderr, "\tnumPriorities:%d\n", domainParameters->numPriorities); - fprintf(stderr, "\tminThroughput:%d\n", domainParameters->minThroughput); - fprintf(stderr, "\tmaxHeight:%d\n", domainParameters->maxHeight); - fprintf(stderr, "\tmaxMCSPDUsize:%d\n", domainParameters->maxMCSPDUsize); - fprintf(stderr, "\tprotocolVersion:%d\n", domainParameters->protocolVersion); - fprintf(stderr, "}\n"); + WLog_INFO(TAG, "DomainParameters {"); + WLog_INFO(TAG, "\tmaxChannelIds:%d", domainParameters->maxChannelIds); + WLog_INFO(TAG, "\tmaxUserIds:%d", domainParameters->maxUserIds); + WLog_INFO(TAG, "\tmaxTokenIds:%d", domainParameters->maxTokenIds); + WLog_INFO(TAG, "\tnumPriorities:%d", domainParameters->numPriorities); + WLog_INFO(TAG, "\tminThroughput:%d", domainParameters->minThroughput); + WLog_INFO(TAG, "\tmaxHeight:%d", domainParameters->maxHeight); + WLog_INFO(TAG, "\tmaxMCSPDUsize:%d", domainParameters->maxMCSPDUsize); + WLog_INFO(TAG, "\tprotocolVersion:%d", domainParameters->protocolVersion); + WLog_INFO(TAG, "}"); } /** @@ -661,7 +664,7 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s) if (!gcc_read_conference_create_response(s, mcs)) { - fprintf(stderr, "mcs_recv_connect_response: gcc_read_conference_create_response failed\n"); + WLog_ERR(TAG, "gcc_read_conference_create_response failed"); return FALSE; } @@ -1056,7 +1059,8 @@ rdpMcs* mcs_new(rdpTransport* transport) { rdpMcs* mcs; - mcs = (rdpMcs *)calloc(1, sizeof(rdpMcs)); + mcs = (rdpMcs*) calloc(1, sizeof(rdpMcs)); + if (!mcs) return NULL; @@ -1070,7 +1074,11 @@ rdpMcs* mcs_new(rdpTransport* transport) mcs->channelCount = 0; mcs->channelMaxCount = CHANNEL_MAX_COUNT; - mcs->channels = (rdpMcsChannel *)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel)); + + mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1; + + mcs->channels = (rdpMcsChannel*) calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel)); + if (!mcs->channels) goto out_free; diff --git a/libfreerdp/core/mcs.h b/libfreerdp/core/mcs.h index 7438b0b1d..b1c4c4a06 100644 --- a/libfreerdp/core/mcs.h +++ b/libfreerdp/core/mcs.h @@ -139,6 +139,7 @@ struct rdp_mcs rdpSettings* settings; UINT16 userId; + UINT16 baseChannelId; UINT16 messageChannelId; DomainParameters domainParameters; diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index 10e2bd637..2eaf34ade 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -27,12 +27,14 @@ #include "message.h" #include "transport.h" +#include #include #include #include #include +#define TAG FREERDP_TAG("core.message") #define WITH_STREAM_POOL 1 /* Update */ @@ -125,6 +127,12 @@ static void update_message_PlaySound(rdpContext* context, PLAY_SOUND_UPDATE* pla MakeMessageId(Update, PlaySound), (void*) wParam, NULL); } +static void update_message_SetKeyboardIndicators(rdpContext* context, UINT16 led_flags) +{ + MessageQueue_Post(context->update->queue, (void*) context, + MakeMessageId(Update, SetKeyboardIndicators), (void*)(size_t)led_flags, NULL); +} + static void update_message_RefreshRect(rdpContext* context, BYTE count, RECTANGLE_16* areas) { RECTANGLE_16* lParam; @@ -762,7 +770,7 @@ static void update_message_WindowIcon(rdpContext* context, WINDOW_ORDER_INFO* or lParam = (WINDOW_ICON_ORDER*) malloc(sizeof(WINDOW_ICON_ORDER)); CopyMemory(lParam, windowIcon, sizeof(WINDOW_ICON_ORDER)); - fprintf(stderr, "update_message_WindowIcon\n"); + WLog_VRB(TAG, "update_message_WindowIcon"); if (windowIcon->iconInfo->cbBitsColor > 0) { @@ -1059,6 +1067,7 @@ static int update_message_free_update_class(wMessage* msg, int type) break; case Update_SurfaceFrameAcknowledge: + case Update_SetKeyboardIndicators: break; default: @@ -1134,6 +1143,10 @@ static int update_message_process_update_class(rdpUpdateProxy* proxy, wMessage* IFCALL(proxy->SurfaceFrameAcknowledge, msg->context, (UINT32) (size_t) msg->wParam); break; + case Update_SetKeyboardIndicators: + IFCALL(proxy->SetKeyboardIndicators, msg->context, (UINT16) (size_t) msg->wParam); + break; + default: status = -1; break; @@ -1871,7 +1884,7 @@ static int update_message_free_class(wMessage*msg, int msgClass, int msgType) } if (status < 0) - fprintf(stderr, "Unknown message: class: %d type: %d\n", msgClass, msgType); + WLog_ERR(TAG, "Unknown message: class: %d type: %d", msgClass, msgType); return status; } @@ -1912,7 +1925,7 @@ static int update_message_process_class(rdpUpdateProxy* proxy, wMessage* msg, in } if (status < 0) - fprintf(stderr, "Unknown message: class: %d type: %d\n", msgClass, msgType); + WLog_ERR(TAG, "Unknown message: class: %d type: %d", msgClass, msgType); return status; } @@ -2004,6 +2017,7 @@ void update_message_register_interface(rdpUpdateProxy* message, rdpUpdate* updat message->BitmapUpdate = update->BitmapUpdate; message->Palette = update->Palette; message->PlaySound = update->PlaySound; + message->SetKeyboardIndicators = update->SetKeyboardIndicators; message->RefreshRect = update->RefreshRect; message->SuppressOutput = update->SuppressOutput; message->SurfaceCommand = update->SurfaceCommand; @@ -2019,6 +2033,7 @@ void update_message_register_interface(rdpUpdateProxy* message, rdpUpdate* updat update->BitmapUpdate = update_message_BitmapUpdate; update->Palette = update_message_Palette; update->PlaySound = update_message_PlaySound; + update->SetKeyboardIndicators = update_message_SetKeyboardIndicators; update->RefreshRect = update_message_RefreshRect; update->SuppressOutput = update_message_SuppressOutput; update->SurfaceCommand = update_message_SurfaceCommand; @@ -2159,11 +2174,37 @@ void update_message_register_interface(rdpUpdateProxy* message, rdpUpdate* updat pointer->PointerCached = update_message_PointerCached; } -rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update) +static void *update_message_proxy_thread(void *arg) { - rdpUpdateProxy* message; + rdpUpdate *update = (rdpUpdate *)arg; + wMessage message; - message = (rdpUpdateProxy*) malloc(sizeof(rdpUpdateProxy)); + if (!update || !update->queue) + { + WLog_ERR(TAG, "update=%p, update->queue=%p", update, update ? update->queue : NULL); + ExitThread(-1); + return NULL; + } + + while (MessageQueue_Wait(update->queue)) + { + int status = 0; + + if (MessageQueue_Peek(update->queue, &message, TRUE)) + status = update_message_queue_process_message(update, &message); + + if (!status) + break; + } + + ExitThread(0); + return NULL; +} + +rdpUpdateProxy *update_message_proxy_new(rdpUpdate *update) +{ + rdpUpdateProxy *message; + message = (rdpUpdateProxy *) malloc(sizeof(rdpUpdateProxy)); if (message) { @@ -2171,6 +2212,7 @@ rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update) message->update = update; update_message_register_interface(message, update); + message->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) update_message_proxy_thread, update, 0, NULL); } return message; @@ -2180,6 +2222,9 @@ void update_message_proxy_free(rdpUpdateProxy* message) { if (message) { + MessageQueue_PostQuit(message->update->queue, 0); + WaitForSingleObject(message->thread, INFINITE); + CloseHandle(message->thread); free(message); } } @@ -2318,7 +2363,7 @@ static int input_message_free_class(wMessage* msg, int msgClass, int msgType) } if (status < 0) - fprintf(stderr, "Unknown event: class: %d type: %d\n", msgClass, msgType); + WLog_ERR(TAG, "Unknown event: class: %d type: %d", msgClass, msgType); return status; } @@ -2339,7 +2384,7 @@ static int input_message_process_class(rdpInputProxy* proxy, wMessage* msg, int } if (status < 0) - fprintf(stderr, "Unknown event: class: %d type: %d\n", msgClass, msgType); + WLog_ERR(TAG, "Unknown event: class: %d type: %d", msgClass, msgType); return status; } diff --git a/libfreerdp/core/message.h b/libfreerdp/core/message.h index fad0e15ce..635eb6882 100644 --- a/libfreerdp/core/message.h +++ b/libfreerdp/core/message.h @@ -43,6 +43,7 @@ struct rdp_update_proxy pBitmapUpdate BitmapUpdate; pPalette Palette; pPlaySound PlaySound; + pSetKeyboardIndicators SetKeyboardIndicators; pRefreshRect RefreshRect; pSuppressOutput SuppressOutput; pSurfaceCommand SurfaceCommand; @@ -120,6 +121,8 @@ struct rdp_update_proxy pPointerColor PointerColor; pPointerNew PointerNew; pPointerCached PointerCached; + + HANDLE thread; }; int update_message_queue_process_message(rdpUpdate* update, wMessage* message); diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 3da3f6af5..9b8f0bfc1 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -26,12 +26,17 @@ #include +#include + #include "tpkt.h" #include "nego.h" #include "transport.h" +#define TAG FREERDP_TAG("core.nego") + +#ifdef WITH_DEBUG_NEGO static const char* const NEGO_STATE_STRINGS[] = { "NEGO_STATE_INITIAL", @@ -55,6 +60,7 @@ static const char PROTOCOL_SECURITY_STRINGS[9][4] = "UNK", "EXT" }; +#endif /* WITH_DEBUG_NEGO */ BOOL nego_security_connect(rdpNego* nego); @@ -66,6 +72,8 @@ BOOL nego_security_connect(rdpNego* nego); BOOL nego_connect(rdpNego* nego) { + rdpSettings* settings = nego->transport->settings; + if (nego->state == NEGO_STATE_INITIAL) { if (nego->enabled_protocols[PROTOCOL_EXT]) @@ -150,15 +158,15 @@ BOOL nego_connect(rdpNego* nego) DEBUG_NEGO("Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]); /* update settings with negotiated protocol security */ - nego->transport->settings->RequestedProtocols = nego->requested_protocols; - nego->transport->settings->SelectedProtocol = nego->selected_protocol; - nego->transport->settings->NegotiationFlags = nego->flags; + settings->RequestedProtocols = nego->requested_protocols; + settings->SelectedProtocol = nego->selected_protocol; + settings->NegotiationFlags = nego->flags; if (nego->selected_protocol == PROTOCOL_RDP) { - nego->transport->settings->DisableEncryption = TRUE; - nego->transport->settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; - nego->transport->settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; + settings->DisableEncryption = TRUE; + settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; + settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } /* finally connect security layer (if not already done) */ @@ -168,6 +176,9 @@ BOOL nego_connect(rdpNego* nego) return FALSE; } + if (!(nego->flags & DYNVC_GFX_PROTOCOL_SUPPORTED)) + settings->NetworkAutoDetect = FALSE; + return TRUE; } @@ -500,10 +511,12 @@ BOOL nego_recv_response(rdpNego* nego) wStream* s; s = Stream_New(NULL, 1024); + if (!s) return FALSE; - status = transport_read(nego->transport, s); + status = transport_read_pdu(nego->transport, s); + if (status < 0) { Stream_Free(s, TRUE); @@ -593,7 +606,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) } else { - fprintf(stderr, "invalid negotiation response\n"); + WLog_ERR(TAG, "invalid negotiation response"); nego->state = NEGO_STATE_FAIL; } @@ -619,7 +632,7 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) if (li != Stream_GetRemainingLength(s) + 6) { - fprintf(stderr, "Incorrect TPDU length indicator.\n"); + WLog_ERR(TAG, "Incorrect TPDU length indicator."); return FALSE; } @@ -651,7 +664,7 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) if (type != TYPE_RDP_NEG_REQ) { - fprintf(stderr, "Incorrect negotiation request type %d\n", type); + WLog_ERR(TAG, "Incorrect negotiation request type %d", type); return FALSE; } @@ -897,11 +910,12 @@ BOOL nego_send_negotiation_response(rdpNego* nego) Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE); Stream_Write_UINT8(s, flags); /* flags */ Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ + /* - * TODO: Check for other possibilities, - * like SSL_NOT_ALLOWED_BY_SERVER. - */ - fprintf(stderr, "%s: client supports only Standard RDP Security\n", __FUNCTION__); + * TODO: Check for other possibilities, + * like SSL_NOT_ALLOWED_BY_SERVER. + */ + WLog_ERR(TAG, "client supports only Standard RDP Security"); Stream_Write_UINT32(s, SSL_REQUIRED_BY_SERVER); length += 8; status = FALSE; @@ -958,7 +972,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego) if (!settings->RdpServerRsaKey && !settings->RdpKeyFile) { - fprintf(stderr, "Missing server certificate\n"); + WLog_ERR(TAG, "Missing server certificate"); return FALSE; } } diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index c36be4619..513564d15 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include @@ -157,10 +157,11 @@ void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL send_pcpdu); void nego_set_preconnection_id(rdpNego* nego, UINT32 id); void nego_set_preconnection_blob(rdpNego* nego, char* blob); +#define NEGO_TAG FREERDP_TAG("core.nego") #ifdef WITH_DEBUG_NEGO -#define DEBUG_NEGO(fmt, ...) DEBUG_CLASS(NEGO, fmt, ## __VA_ARGS__) +#define DEBUG_NEGO(fmt, ...) WLog_DBG(NEGO_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_NEGO(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_NEGO(fmt, ...) do { } while (0) #endif #endif /* __NEGO_H */ diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index f1573a5a0..ecbfc8b26 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -27,6 +27,7 @@ #include #endif +#include #include #include @@ -39,6 +40,8 @@ #include "nla.h" +#define TAG FREERDP_TAG("core") + /** * TSRequest ::= SEQUENCE { * version [0] INTEGER, @@ -114,7 +117,6 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) rdpTls* tls = NULL; freerdp* instance; rdpSettings* settings; - PromptPassword = FALSE; settings = credssp->settings; instance = (freerdp*) settings->instance; @@ -129,6 +131,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) } #ifndef _WIN32 + if (PromptPassword) { if (settings->RestrictedAdminModeRequired) @@ -137,6 +140,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) PromptPassword = FALSE; } } + #endif if (PromptPassword) @@ -144,7 +148,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) if (instance->Authenticate) { BOOL proceed = instance->Authenticate(instance, - &settings->Username, &settings->Password, &settings->Domain); + &settings->Username, &settings->Password, &settings->Domain); if (!proceed) { @@ -152,12 +156,10 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED); return 0; } - } } sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password); - #ifndef _WIN32 { SEC_WINNT_AUTH_IDENTITY* identity = &(credssp->identity); @@ -172,8 +174,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) free(identity->Password); identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0, - settings->PasswordHash, -1, &identity->Password, 0) - 1; - + settings->PasswordHash, -1, &identity->Password, 0) - 1; /** * Multiply password hash length by 64 to obtain a length exceeding * the maximum (256) and use it this for hash identification in WinPR. @@ -184,10 +185,9 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) } } #endif - #ifdef WITH_DEBUG_NLA - _tprintf(_T("User: %s Domain: %s Password: %s\n"), - (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password); + WLog_DBG(TAG, "User: %s Domain: %s Password: %s", + (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password); #endif if (credssp->transport->layer == TRANSPORT_LAYER_TLS) @@ -200,27 +200,23 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) } else { - fprintf(stderr, "Unknown NLA transport layer\n"); + WLog_ERR(TAG, "Unknown NLA transport layer"); return 0; } sspi_SecBufferAlloc(&credssp->PublicKey, tls->PublicKeyLength); CopyMemory(credssp->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength); - length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname); - spn = (SEC_CHAR*) malloc(length + 1); sprintf(spn, "%s%s", TERMSRV_SPN_PREFIX, settings->ServerHostname); - #ifdef UNICODE credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2); MultiByteToWideChar(CP_UTF8, 0, spn, length, - (LPWSTR) credssp->ServicePrincipalName, length); + (LPWSTR) credssp->ServicePrincipalName, length); free(spn); #else credssp->ServicePrincipalName = spn; #endif - return 1; } @@ -234,10 +230,8 @@ int credssp_ntlm_server_init(rdpCredssp* credssp) freerdp* instance; rdpSettings* settings = credssp->settings; instance = (freerdp*) settings->instance; - sspi_SecBufferAlloc(&credssp->PublicKey, credssp->transport->TlsIn->PublicKeyLength); CopyMemory(credssp->PublicKey.pvBuffer, credssp->transport->TlsIn->PublicKey, credssp->transport->TlsIn->PublicKeyLength); - return 1; } @@ -257,30 +251,27 @@ int credssp_client_authenticate(rdpCredssp* credssp) BOOL have_context; BOOL have_input_buffer; BOOL have_pub_key_auth; - sspi_GlobalInit(); if (credssp_ntlm_client_init(credssp) == 0) return 0; credssp->table = InitSecurityInterfaceEx(0); - status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo); if (status != SEC_E_OK) { - fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status); + WLog_ERR(TAG, "QuerySecurityPackageInfo status: 0x%08X", status); return 0; } cbMaxToken = pPackageInfo->cbMaxToken; - status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME, - SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration); + SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration); if (status != SEC_E_OK) { - fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status); + WLog_ERR(TAG, "AcquireCredentialsHandle status: 0x%08X", status); return 0; } @@ -290,7 +281,6 @@ int credssp_client_authenticate(rdpCredssp* credssp) ZeroMemory(&input_buffer, sizeof(SecBuffer)); ZeroMemory(&output_buffer, sizeof(SecBuffer)); ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes)); - /* * from tspkg.dll: 0x00000132 * ISC_REQ_MUTUAL_AUTH @@ -298,7 +288,6 @@ int credssp_client_authenticate(rdpCredssp* credssp) * ISC_REQ_USE_SESSION_KEY * ISC_REQ_ALLOCATE_MEMORY */ - fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY; while (TRUE) @@ -309,12 +298,11 @@ int credssp_client_authenticate(rdpCredssp* credssp) output_buffer.BufferType = SECBUFFER_TOKEN; output_buffer.cbBuffer = cbMaxToken; output_buffer.pvBuffer = malloc(output_buffer.cbBuffer); - status = credssp->table->InitializeSecurityContext(&credentials, - (have_context) ? &credssp->context : NULL, - credssp->ServicePrincipalName, fContextReq, 0, - SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL, - 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration); + (have_context) ? &credssp->context : NULL, + credssp->ServicePrincipalName, fContextReq, 0, + SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL, + 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration); if (have_input_buffer && (input_buffer.pvBuffer)) { @@ -339,7 +327,7 @@ int credssp_client_authenticate(rdpCredssp* credssp) if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK) { - fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n"); + WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure"); return 0; } @@ -352,12 +340,10 @@ int credssp_client_authenticate(rdpCredssp* credssp) { credssp->negoToken.pvBuffer = output_buffer.pvBuffer; credssp->negoToken.cbBuffer = output_buffer.cbBuffer; - #ifdef WITH_DEBUG_CREDSSP - fprintf(stderr, "Sending Authentication Token\n"); - winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); + WLog_DBG(TAG, "Sending Authentication Token"); + winpr_HexDump(TAG, WLOG_DEBUG, credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); #endif - credssp_send(credssp); credssp_buffer_free(credssp); } @@ -366,7 +352,6 @@ int credssp_client_authenticate(rdpCredssp* credssp) break; /* receive server response and place in input buffer */ - input_buffer_desc.ulVersion = SECBUFFER_VERSION; input_buffer_desc.cBuffers = 1; input_buffer_desc.pBuffers = &input_buffer; @@ -376,13 +361,11 @@ int credssp_client_authenticate(rdpCredssp* credssp) return -1; #ifdef WITH_DEBUG_CREDSSP - fprintf(stderr, "Receiving Authentication Token (%d)\n", (int) credssp->negoToken.cbBuffer); - winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); + WLog_DBG(TAG, "Receiving Authentication Token (%d)", (int) credssp->negoToken.cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); #endif - input_buffer.pvBuffer = credssp->negoToken.pvBuffer; input_buffer.cbBuffer = credssp->negoToken.cbBuffer; - have_input_buffer = TRUE; have_context = TRUE; } @@ -392,34 +375,29 @@ int credssp_client_authenticate(rdpCredssp* credssp) return -1; /* Verify Server Public Key Echo */ - status = credssp_decrypt_public_key_echo(credssp); credssp_buffer_free(credssp); if (status != SEC_E_OK) { - fprintf(stderr, "Could not verify public key echo!\n"); + WLog_ERR(TAG, "Could not verify public key echo!"); return -1; } /* Send encrypted credentials */ - status = credssp_encrypt_ts_credentials(credssp); if (status != SEC_E_OK) { - fprintf(stderr, "credssp_encrypt_ts_credentials status: 0x%08X\n", status); + WLog_ERR(TAG, "credssp_encrypt_ts_credentials status: 0x%08X", status); return 0; } credssp_send(credssp); credssp_buffer_free(credssp); - /* Free resources */ - credssp->table->FreeCredentialsHandle(&credentials); credssp->table->FreeContextBuffer(pPackageInfo); - return 1; } @@ -445,7 +423,6 @@ int credssp_server_authenticate(rdpCredssp* credssp) BOOL have_context; BOOL have_input_buffer; BOOL have_pub_key_auth; - sspi_GlobalInit(); if (credssp_ntlm_server_init(credssp) == 0) @@ -455,12 +432,11 @@ int credssp_server_authenticate(rdpCredssp* credssp) { HMODULE hSSPI; INIT_SECURITY_INTERFACE pInitSecurityInterface; - hSSPI = LoadLibrary(credssp->SspiModule); if (!hSSPI) { - _tprintf(_T("Failed to load SSPI module: %s\n"), credssp->SspiModule); + WLog_ERR(TAG, "Failed to load SSPI module: %s", credssp->SspiModule); return 0; } @@ -469,7 +445,6 @@ int credssp_server_authenticate(rdpCredssp* credssp) #else pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA"); #endif - credssp->table = pInitSecurityInterface(); } else @@ -481,18 +456,17 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (status != SEC_E_OK) { - fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status); + WLog_ERR(TAG, "QuerySecurityPackageInfo status: 0x%08X", status); return 0; } cbMaxToken = pPackageInfo->cbMaxToken; - status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME, - SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration); + SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration); if (status != SEC_E_OK) { - fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status); + WLog_ERR(TAG, "AcquireCredentialsHandle status: 0x%08X", status); return 0; } @@ -504,24 +478,19 @@ int credssp_server_authenticate(rdpCredssp* credssp) ZeroMemory(&input_buffer_desc, sizeof(SecBufferDesc)); ZeroMemory(&output_buffer_desc, sizeof(SecBufferDesc)); ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes)); - /* * from tspkg.dll: 0x00000112 * ASC_REQ_MUTUAL_AUTH * ASC_REQ_CONFIDENTIALITY * ASC_REQ_ALLOCATE_MEMORY */ - fContextReq = 0; fContextReq |= ASC_REQ_MUTUAL_AUTH; fContextReq |= ASC_REQ_CONFIDENTIALITY; - fContextReq |= ASC_REQ_CONNECTION; fContextReq |= ASC_REQ_USE_SESSION_KEY; - fContextReq |= ASC_REQ_REPLAY_DETECT; fContextReq |= ASC_REQ_SEQUENCE_DETECT; - fContextReq |= ASC_REQ_EXTENDED_ERROR; while (TRUE) @@ -530,9 +499,7 @@ int credssp_server_authenticate(rdpCredssp* credssp) input_buffer_desc.cBuffers = 1; input_buffer_desc.pBuffers = &input_buffer; input_buffer.BufferType = SECBUFFER_TOKEN; - /* receive authentication token */ - input_buffer_desc.ulVersion = SECBUFFER_VERSION; input_buffer_desc.cBuffers = 1; input_buffer_desc.pBuffers = &input_buffer; @@ -542,16 +509,15 @@ int credssp_server_authenticate(rdpCredssp* credssp) return -1; #ifdef WITH_DEBUG_CREDSSP - fprintf(stderr, "Receiving Authentication Token\n"); + WLog_DBG(TAG, "Receiving Authentication Token"); credssp_buffer_print(credssp); #endif - input_buffer.pvBuffer = credssp->negoToken.pvBuffer; input_buffer.cbBuffer = credssp->negoToken.cbBuffer; if (credssp->negoToken.cbBuffer < 1) { - fprintf(stderr, "CredSSP: invalid negoToken!\n"); + WLog_ERR(TAG, "CredSSP: invalid negoToken!"); return -1; } @@ -561,12 +527,10 @@ int credssp_server_authenticate(rdpCredssp* credssp) output_buffer.BufferType = SECBUFFER_TOKEN; output_buffer.cbBuffer = cbMaxToken; output_buffer.pvBuffer = malloc(output_buffer.cbBuffer); - status = credssp->table->AcceptSecurityContext(&credentials, - have_context? &credssp->context: NULL, - &input_buffer_desc, fContextReq, SECURITY_NATIVE_DREP, &credssp->context, - &output_buffer_desc, &pfContextAttr, &expiration); - + have_context? &credssp->context: NULL, + &input_buffer_desc, fContextReq, SECURITY_NATIVE_DREP, &credssp->context, + &output_buffer_desc, &pfContextAttr, &expiration); credssp->negoToken.pvBuffer = output_buffer.pvBuffer; credssp->negoToken.cbBuffer = output_buffer.cbBuffer; @@ -587,36 +551,33 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK) { - fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n"); + WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure"); return 0; } if (credssp_decrypt_public_key_echo(credssp) != SEC_E_OK) { - fprintf(stderr, "Error: could not verify client's public key echo\n"); + WLog_ERR(TAG, "Error: could not verify client's public key echo"); return -1; } sspi_SecBufferFree(&credssp->negoToken); credssp->negoToken.pvBuffer = NULL; credssp->negoToken.cbBuffer = 0; - credssp_encrypt_public_key_echo(credssp); } if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED)) { - fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status); + WLog_ERR(TAG, "AcceptSecurityContext status: 0x%08X", status); return -1; /* Access Denied */ } /* send authentication token */ - #ifdef WITH_DEBUG_CREDSSP - fprintf(stderr, "Sending Authentication Token\n"); + WLog_DBG(TAG, "Sending Authentication Token"); credssp_buffer_print(credssp); #endif - credssp_send(credssp); credssp_buffer_free(credssp); @@ -633,13 +594,13 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (credssp_decrypt_ts_credentials(credssp) != SEC_E_OK) { - fprintf(stderr, "Could not decrypt TSCredentials status: 0x%08X\n", status); + WLog_ERR(TAG, "Could not decrypt TSCredentials status: 0x%08X", status); return 0; } if (status != SEC_E_OK) { - fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status); + WLog_ERR(TAG, "AcceptSecurityContext status: 0x%08X", status); return 0; } @@ -647,7 +608,7 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (status != SEC_E_OK) { - fprintf(stderr, "ImpersonateSecurityContext status: 0x%08X\n", status); + WLog_ERR(TAG, "ImpersonateSecurityContext status: 0x%08X", status); return 0; } else @@ -656,13 +617,12 @@ int credssp_server_authenticate(rdpCredssp* credssp) if (status != SEC_E_OK) { - fprintf(stderr, "RevertSecurityContext status: 0x%08X\n", status); + WLog_ERR(TAG, "RevertSecurityContext status: 0x%08X", status); return 0; } } credssp->table->FreeContextBuffer(pPackageInfo); - return 1; } @@ -724,17 +684,12 @@ SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp) SecBufferDesc Message; SECURITY_STATUS status; int public_key_length; - public_key_length = credssp->PublicKey.cbBuffer; - Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */ - sspi_SecBufferAlloc(&credssp->pubKeyAuth, credssp->ContextSizes.cbMaxSignature + public_key_length); - Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature; Buffers[0].pvBuffer = credssp->pubKeyAuth.pvBuffer; - Buffers[1].cbBuffer = public_key_length; Buffers[1].pvBuffer = ((BYTE*) credssp->pubKeyAuth.pvBuffer) + credssp->ContextSizes.cbMaxSignature; CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer); @@ -748,12 +703,11 @@ SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp) Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; - status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++); if (status != SEC_E_OK) { - fprintf(stderr, "EncryptMessage status: 0x%08X\n", status); + WLog_ERR(TAG, "EncryptMessage status: 0x%08X", status); return status; } @@ -774,34 +728,28 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp) if (credssp->PublicKey.cbBuffer + credssp->ContextSizes.cbMaxSignature != credssp->pubKeyAuth.cbBuffer) { - fprintf(stderr, "unexpected pubKeyAuth buffer size:%d\n", (int) credssp->pubKeyAuth.cbBuffer); + WLog_ERR(TAG, "unexpected pubKeyAuth buffer size:%d", (int) credssp->pubKeyAuth.cbBuffer); return SEC_E_INVALID_TOKEN; } length = credssp->pubKeyAuth.cbBuffer; buffer = (BYTE*) malloc(length); CopyMemory(buffer, credssp->pubKeyAuth.pvBuffer, length); - public_key_length = credssp->PublicKey.cbBuffer; - Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */ - Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature; Buffers[0].pvBuffer = buffer; - Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature; Buffers[1].pvBuffer = buffer + credssp->ContextSizes.cbMaxSignature; - Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; - status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP); if (status != SEC_E_OK) { - fprintf(stderr, "DecryptMessage failure: 0x%08X\n", status); + WLog_ERR(TAG, "DecryptMessage failure: 0x%08X", status); return status; } @@ -816,40 +764,32 @@ SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp) if (memcmp(public_key1, public_key2, public_key_length) != 0) { - fprintf(stderr, "Could not verify server's public key echo\n"); - - fprintf(stderr, "Expected (length = %d):\n", public_key_length); - winpr_HexDump(public_key1, public_key_length); - - fprintf(stderr, "Actual (length = %d):\n", public_key_length); - winpr_HexDump(public_key2, public_key_length); - + WLog_ERR(TAG, "Could not verify server's public key echo"); + WLog_ERR(TAG, "Expected (length = %d):", public_key_length); + winpr_HexDump(TAG, WLOG_ERROR, public_key1, public_key_length); + WLog_ERR(TAG, "Actual (length = %d):", public_key_length); + winpr_HexDump(TAG, WLOG_ERROR, public_key2, public_key_length); return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */ } free(buffer); - return SEC_E_OK; } int credssp_sizeof_ts_password_creds(rdpCredssp* credssp) { int length = 0; - length += ber_sizeof_sequence_octet_string(credssp->identity.DomainLength * 2); length += ber_sizeof_sequence_octet_string(credssp->identity.UserLength * 2); length += ber_sizeof_sequence_octet_string(credssp->identity.PasswordLength * 2); - return length; } void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s) { int length; - /* TSPasswordCreds (SEQUENCE) */ ber_read_sequence_tag(s, &length); - /* [0] domainName (OCTET STRING) */ ber_read_contextual_tag(s, 0, &length, TRUE); ber_read_octet_string_tag(s, &length); @@ -858,7 +798,6 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s) CopyMemory(credssp->identity.Domain, Stream_Pointer(s), credssp->identity.DomainLength); Stream_Seek(s, credssp->identity.DomainLength); credssp->identity.DomainLength /= 2; - /* [1] userName (OCTET STRING) */ ber_read_contextual_tag(s, 1, &length, TRUE); ber_read_octet_string_tag(s, &length); @@ -867,7 +806,6 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s) CopyMemory(credssp->identity.User, Stream_Pointer(s), credssp->identity.UserLength); Stream_Seek(s, credssp->identity.UserLength); credssp->identity.UserLength /= 2; - /* [2] password (OCTET STRING) */ ber_read_contextual_tag(s, 2, &length, TRUE); ber_read_octet_string_tag(s, &length); @@ -876,7 +814,6 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s) CopyMemory(credssp->identity.Password, Stream_Pointer(s), credssp->identity.PasswordLength); Stream_Seek(s, credssp->identity.PasswordLength); credssp->identity.PasswordLength /= 2; - credssp->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; } @@ -884,31 +821,23 @@ int credssp_write_ts_password_creds(rdpCredssp* credssp, wStream* s) { int size = 0; int innerSize = credssp_sizeof_ts_password_creds(credssp); - /* TSPasswordCreds (SEQUENCE) */ - size += ber_write_sequence_tag(s, innerSize); - /* [0] domainName (OCTET STRING) */ size += ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2); - /* [1] userName (OCTET STRING) */ size += ber_write_sequence_octet_string(s, 1, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2); - /* [2] password (OCTET STRING) */ size += ber_write_sequence_octet_string(s, 2, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2); - return size; } int credssp_sizeof_ts_credentials(rdpCredssp* credssp) { int size = 0; - size += ber_sizeof_integer(1); size += ber_sizeof_contextual_tag(ber_sizeof_integer(1)); size += ber_sizeof_sequence_octet_string(ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp))); - return size; } @@ -917,22 +846,16 @@ void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials) wStream* s; int length; int ts_password_creds_length; - s = Stream_New(ts_credentials->pvBuffer, ts_credentials->cbBuffer); - /* TSCredentials (SEQUENCE) */ ber_read_sequence_tag(s, &length); - /* [0] credType (INTEGER) */ ber_read_contextual_tag(s, 0, &length, TRUE); ber_read_integer(s, NULL); - /* [1] credentials (OCTET STRING) */ ber_read_contextual_tag(s, 1, &length, TRUE); ber_read_octet_string_tag(s, &ts_password_creds_length); - credssp_read_ts_password_creds(credssp, s); - Stream_Free(s, FALSE); } @@ -941,22 +864,16 @@ int credssp_write_ts_credentials(rdpCredssp* credssp, wStream* s) int size = 0; int innerSize = credssp_sizeof_ts_credentials(credssp); int passwordSize; - /* TSCredentials (SEQUENCE) */ size += ber_write_sequence_tag(s, innerSize); - /* [0] credType (INTEGER) */ size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE); size += ber_write_integer(s, 1); - /* [1] credentials (OCTET STRING) */ - passwordSize = ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp)); - size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE); size += ber_write_octet_string_tag(s, passwordSize); size += credssp_write_ts_password_creds(credssp, s); - return size; } @@ -972,7 +889,6 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp) int DomainLength; int UserLength; int PasswordLength; - DomainLength = credssp->identity.DomainLength; UserLength = credssp->identity.UserLength; PasswordLength = credssp->identity.PasswordLength; @@ -986,7 +902,6 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp) length = ber_sizeof_sequence(credssp_sizeof_ts_credentials(credssp)); sspi_SecBufferAlloc(&credssp->ts_credentials, length); - s = Stream_New((BYTE*) credssp->ts_credentials.pvBuffer, length); credssp_write_ts_credentials(credssp, s); @@ -1005,26 +920,19 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) SecBuffer Buffers[2]; SecBufferDesc Message; SECURITY_STATUS status; - credssp_encode_ts_credentials(credssp); - Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */ - sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer); - Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature; Buffers[0].pvBuffer = credssp->authInfo.pvBuffer; ZeroMemory(Buffers[0].pvBuffer, Buffers[0].cbBuffer); - Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer; Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer]; CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer); - Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; - status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++); if (status != SEC_E_OK) @@ -1041,39 +949,32 @@ SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp) SecBuffer Buffers[2]; SecBufferDesc Message; SECURITY_STATUS status; - Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */ if (credssp->authInfo.cbBuffer < 1) { - fprintf(stderr, "credssp_decrypt_ts_credentials missing authInfo buffer\n"); + WLog_ERR(TAG, "credssp_decrypt_ts_credentials missing authInfo buffer"); return SEC_E_INVALID_TOKEN; } length = credssp->authInfo.cbBuffer; buffer = (BYTE*) malloc(length); CopyMemory(buffer, credssp->authInfo.pvBuffer, length); - Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature; Buffers[0].pvBuffer = buffer; - Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature; Buffers[1].pvBuffer = &buffer[credssp->ContextSizes.cbMaxSignature]; - Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; - status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP); if (status != SEC_E_OK) return status; credssp_read_ts_credentials(credssp, &Buffers[1]); - free(buffer); - return SEC_E_OK; } @@ -1127,20 +1028,14 @@ void credssp_send(rdpCredssp* credssp) int nego_tokens_length; int pub_key_auth_length; int auth_info_length; - nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_sizeof_nego_tokens(credssp->negoToken.cbBuffer) : 0; pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_sizeof_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0; auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_sizeof_auth_info(credssp->authInfo.cbBuffer) : 0; - length = nego_tokens_length + pub_key_auth_length + auth_info_length; - ts_request_length = credssp_sizeof_ts_request(length); - s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length)); - /* TSRequest */ ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */ - /* [0] version */ ber_write_contextual_tag(s, 0, 3, TRUE); ber_write_integer(s, 2); /* INTEGER */ @@ -1149,12 +1044,10 @@ void credssp_send(rdpCredssp* credssp) if (nego_tokens_length > 0) { length = nego_tokens_length; - length -= ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */ length -= ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */ length -= ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */ - length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */ - + length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */ // assert length == 0 } @@ -1163,7 +1056,6 @@ void credssp_send(rdpCredssp* credssp) { length = auth_info_length; length -= ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer); - // assert length == 0 } @@ -1172,14 +1064,11 @@ void credssp_send(rdpCredssp* credssp) { length = pub_key_auth_length; length -= ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer); - // assert length == 0 } Stream_SealLength(s); - transport_write(credssp->transport, s); - Stream_Free(s, TRUE); } @@ -1195,23 +1084,20 @@ int credssp_recv(rdpCredssp* credssp) int length; int status; UINT32 version; - s = Stream_New(NULL, 4096); - - status = transport_read(credssp->transport, s); - Stream_Length(s) = status; + status = transport_read_pdu(credssp->transport, s); if (status < 0) { - fprintf(stderr, "credssp_recv() error: %d\n", status); + WLog_ERR(TAG, "credssp_recv() error: %d", status); Stream_Free(s, TRUE); return -1; } /* TSRequest */ - if(!ber_read_sequence_tag(s, &length) || - !ber_read_contextual_tag(s, 0, &length, TRUE) || - !ber_read_integer(s, &version)) + if (!ber_read_sequence_tag(s, &length) || + !ber_read_contextual_tag(s, 0, &length, TRUE) || + !ber_read_integer(s, &version)) { Stream_Free(s, TRUE); return -1; @@ -1221,14 +1107,15 @@ int credssp_recv(rdpCredssp* credssp) if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE) { if (!ber_read_sequence_tag(s, &length) || /* SEQUENCE OF NegoDataItem */ - !ber_read_sequence_tag(s, &length) || /* NegoDataItem */ - !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */ - !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */ - ((int) Stream_GetRemainingLength(s)) < length) + !ber_read_sequence_tag(s, &length) || /* NegoDataItem */ + !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */ + !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */ + ((int) Stream_GetRemainingLength(s)) < length) { Stream_Free(s, TRUE); return -1; } + sspi_SecBufferAlloc(&credssp->negoToken, length); Stream_Read(s, credssp->negoToken.pvBuffer, length); credssp->negoToken.cbBuffer = length; @@ -1238,11 +1125,12 @@ int credssp_recv(rdpCredssp* credssp) if (ber_read_contextual_tag(s, 2, &length, TRUE) != FALSE) { if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */ - ((int) Stream_GetRemainingLength(s)) < length) + ((int) Stream_GetRemainingLength(s)) < length) { Stream_Free(s, TRUE); return -1; } + sspi_SecBufferAlloc(&credssp->authInfo, length); Stream_Read(s, credssp->authInfo.pvBuffer, length); credssp->authInfo.cbBuffer = length; @@ -1252,18 +1140,18 @@ int credssp_recv(rdpCredssp* credssp) if (ber_read_contextual_tag(s, 3, &length, TRUE) != FALSE) { if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */ - ((int) Stream_GetRemainingLength(s)) < length) + ((int) Stream_GetRemainingLength(s)) < length) { Stream_Free(s, TRUE); return -1; } + sspi_SecBufferAlloc(&credssp->pubKeyAuth, length); Stream_Read(s, credssp->pubKeyAuth.pvBuffer, length); credssp->pubKeyAuth.cbBuffer = length; } Stream_Free(s, TRUE); - return 0; } @@ -1271,20 +1159,23 @@ void credssp_buffer_print(rdpCredssp* credssp) { if (credssp->negoToken.cbBuffer > 0) { - fprintf(stderr, "CredSSP.negoToken (length = %d):\n", (int) credssp->negoToken.cbBuffer); - winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); + WLog_ERR(TAG, "CredSSP.negoToken (length = %d):", (int) credssp->negoToken.cbBuffer); + winpr_HexDump(TAG, WLOG_ERROR, credssp->negoToken.pvBuffer, + credssp->negoToken.cbBuffer); } if (credssp->pubKeyAuth.cbBuffer > 0) { - fprintf(stderr, "CredSSP.pubKeyAuth (length = %d):\n", (int) credssp->pubKeyAuth.cbBuffer); - winpr_HexDump(credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer); + WLog_ERR(TAG, "CredSSP.pubKeyAuth (length = %d):", (int) credssp->pubKeyAuth.cbBuffer); + winpr_HexDump(TAG, WLOG_ERROR, credssp->pubKeyAuth.pvBuffer, + credssp->pubKeyAuth.cbBuffer); } if (credssp->authInfo.cbBuffer > 0) { - fprintf(stderr, "CredSSP.authInfo (length = %d):\n", (int) credssp->authInfo.cbBuffer); - winpr_HexDump(credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer); + WLog_ERR(TAG, "CredSSP.authInfo (length = %d):", (int) credssp->authInfo.cbBuffer); + winpr_HexDump(TAG, WLOG_ERROR, credssp->authInfo.pvBuffer, + credssp->authInfo.cbBuffer); } } @@ -1302,7 +1193,6 @@ LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname) LPTSTR hostnameX = NULL; LPTSTR ServiceClassX = NULL; LPTSTR ServicePrincipalName = NULL; - #ifdef UNICODE ConvertToUnicode(CP_UTF8, 0, hostname, -1, &hostnameX, 0); ConvertToUnicode(CP_UTF8, 0, ServiceClass, -1, &ServiceClassX, 0); @@ -1316,7 +1206,6 @@ LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname) ServicePrincipalName = (LPTSTR) _tcsdup(hostnameX); free(ServiceClassX); free(hostnameX); - return ServicePrincipalName; } @@ -1331,6 +1220,7 @@ LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname) } ServicePrincipalName = (LPTSTR) malloc(SpnLength * sizeof(TCHAR)); + if (!ServicePrincipalName) return NULL; @@ -1346,7 +1236,6 @@ LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname) free(ServiceClassX); free(hostnameX); - return ServicePrincipalName; } @@ -1359,7 +1248,6 @@ LPTSTR credssp_make_spn(const char* ServiceClass, const char* hostname) rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings) { rdpCredssp* credssp; - credssp = (rdpCredssp*) calloc(1, sizeof(rdpCredssp)); if (credssp) @@ -1368,7 +1256,6 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* LONG status; DWORD dwType; DWORD dwSize; - credssp->instance = instance; credssp->settings = settings; credssp->server = settings->ServerMode; @@ -1383,7 +1270,7 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* if (credssp->server) { status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), - 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + 0, KEY_READ | KEY_WOW64_64KEY, &hKey); if (status == ERROR_SUCCESS) { @@ -1392,13 +1279,12 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* if (status == ERROR_SUCCESS) { credssp->SspiModule = (LPTSTR) malloc(dwSize + sizeof(TCHAR)); - status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType, - (BYTE*) credssp->SspiModule, &dwSize); + (BYTE*) credssp->SspiModule, &dwSize); if (status == ERROR_SUCCESS) { - _tprintf(_T("Using SSPI Module: %s\n"), credssp->SspiModule); + WLog_INFO(TAG, "Using SSPI Module: %s", credssp->SspiModule); RegCloseKey(hKey); } } @@ -1423,9 +1309,7 @@ void credssp_free(rdpCredssp* credssp) sspi_SecBufferFree(&credssp->PublicKey); sspi_SecBufferFree(&credssp->ts_credentials); - free(credssp->ServicePrincipalName); - free(credssp->identity.User); free(credssp->identity.Domain); free(credssp->identity.Password); diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 98b177f67..3142aba7b 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -26,11 +26,14 @@ #include #include +#include #include #include #include "orders.h" +#define TAG FREERDP_TAG("core.orders") + #ifdef WITH_DEBUG_ORDERS static const char* const PRIMARY_DRAWING_ORDER_STRINGS[] = @@ -223,11 +226,11 @@ static INLINE BOOL update_read_color(wStream* s, UINT32* color) return FALSE; Stream_Read_UINT8(s, byte); - *color = byte; + *color = (UINT32) byte << 16; Stream_Read_UINT8(s, byte); - *color |= (byte << 8); + *color |= ((UINT32) byte << 8); Stream_Read_UINT8(s, byte); - *color |= (byte << 16); + *color |= (UINT32) byte; return TRUE; } @@ -749,7 +752,7 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ if (Stream_GetRemainingLength(s) < 1) {\ - fprintf(stderr, "%s: error reading %s\n", __FUNCTION__, #TARGET); \ + WLog_ERR(TAG, "error reading %s", #TARGET); \ return FALSE; \ } \ Stream_Read_UINT8(s, TARGET); \ @@ -761,7 +764,7 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ if (Stream_GetRemainingLength(s) < 2) { \ - fprintf(stderr, "%s: error reading %s or %s\n", __FUNCTION__, #TARGET1, #TARGET2); \ + WLog_ERR(TAG, "error reading %s or %s", #TARGET1, #TARGET2); \ return FALSE; \ } \ Stream_Read_UINT8(s, TARGET1); \ @@ -774,7 +777,7 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ if (Stream_GetRemainingLength(s) < 2) { \ - fprintf(stderr, "%s: error reading %s\n", __FUNCTION__, #TARGET); \ + WLog_ERR(TAG, "error reading %s", #TARGET); \ return FALSE; \ } \ Stream_Read_UINT16(s, TARGET); \ @@ -785,7 +788,7 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ if (Stream_GetRemainingLength(s) < 4) { \ - fprintf(stderr, "%s: error reading %s\n", __FUNCTION__, #TARGET); \ + WLog_ERR(TAG, "error reading %s", #TARGET); \ return FALSE; \ } \ Stream_Read_UINT32(s, TARGET); \ @@ -795,14 +798,14 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int #define ORDER_FIELD_COORD(NO, TARGET) \ do { \ if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_coord(s, &TARGET, orderInfo->deltaCoordinates)) { \ - fprintf(stderr, "%s: error reading %s\n", __FUNCTION__, #TARGET); \ + WLog_ERR(TAG, "error reading %s", #TARGET); \ return FALSE; \ } \ } while(0) #define ORDER_FIELD_COLOR(NO, TARGET) \ do { \ if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_color(s, &TARGET)) { \ - fprintf(stderr, "%s: error reading %s\n", __FUNCTION__, #TARGET); \ + WLog_ERR(TAG, "error reading %s", #TARGET); \ return FALSE; \ } \ } while(0) @@ -811,12 +814,12 @@ static INLINE BOOL update_read_delta_points(wStream* s, DELTA_POINT* points, int #define FIELD_SKIP_BUFFER16(s, TARGET_LEN) \ do { \ if (Stream_GetRemainingLength(s) < 2) {\ - fprintf(stderr, "%s: error reading length %s\n", __FUNCTION__, #TARGET_LEN); \ + WLog_ERR(TAG, "error reading length %s", #TARGET_LEN); \ return FALSE; \ }\ Stream_Read_UINT16(s, TARGET_LEN); \ if (!Stream_SafeSeek(s, TARGET_LEN)) { \ - fprintf(stderr, "%s: error skipping %d bytes\n", __FUNCTION__, TARGET_LEN); \ + WLog_ERR(TAG, "error skipping %d bytes", TARGET_LEN); \ return FALSE; \ } \ } while(0) @@ -979,7 +982,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC return FALSE; Stream_Read_UINT8(s, byte); - opaque_rect->color = (opaque_rect->color & 0xFFFFFF00) | byte; + opaque_rect->color = (opaque_rect->color & 0xFF00FFFF) | ((UINT32) byte << 16); } if (orderInfo->fieldFlags & ORDER_FIELD_06) @@ -988,7 +991,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC return FALSE; Stream_Read_UINT8(s, byte); - opaque_rect->color = (opaque_rect->color & 0xFFFF00FF) | (byte << 8); + opaque_rect->color = (opaque_rect->color & 0xFFFF00FF) | ((UINT32) byte << 8); } if (orderInfo->fieldFlags & ORDER_FIELD_07) @@ -997,7 +1000,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC return FALSE; Stream_Read_UINT8(s, byte); - opaque_rect->color = (opaque_rect->color & 0xFF00FFFF) | (byte << 16); + opaque_rect->color = (opaque_rect->color & 0xFFFFFF00) | (UINT32) byte; } return TRUE; @@ -1178,7 +1181,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT return FALSE; Stream_Read_UINT8(s, byte); - multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFFFF00) | byte; + multi_opaque_rect->color = (multi_opaque_rect->color & 0xFF00FFFF) | ((UINT32) byte << 16); } if (orderInfo->fieldFlags & ORDER_FIELD_06) @@ -1187,7 +1190,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT return FALSE; Stream_Read_UINT8(s, byte); - multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFF00FF) | (byte << 8); + multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFF00FF) | ((UINT32) byte << 8); } if (orderInfo->fieldFlags & ORDER_FIELD_07) @@ -1196,7 +1199,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT return FALSE; Stream_Read_UINT8(s, byte); - multi_opaque_rect->color = (multi_opaque_rect->color & 0xFF00FFFF) | (byte << 16); + multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFFFF00) | (UINT32) byte; } ORDER_FIELD_BYTE(8, multi_opaque_rect->numRectangles); @@ -1842,7 +1845,7 @@ BOOL update_read_cache_bitmap_order(wStream* s, CACHE_BITMAP_ORDER* cache_bitmap Stream_Read_UINT8(s, cache_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */ if ((cache_bitmap->bitmapBpp < 1) || (cache_bitmap->bitmapBpp > 32)) { - fprintf(stderr, "%s: invalid bitmap bpp %d\n", __FUNCTION__, cache_bitmap->bitmapBpp); + WLog_ERR(TAG, "invalid bitmap bpp %d", cache_bitmap->bitmapBpp); return FALSE; } Stream_Read_UINT16(s, cache_bitmap->bitmapLength); /* bitmapLength (2 bytes) */ @@ -2085,7 +2088,7 @@ BOOL update_read_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache_ Stream_Read_UINT8(s, bitmapData->bpp); if ((bitmapData->bpp < 1) || (bitmapData->bpp > 32)) { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, bitmapData->bpp); + WLog_ERR(TAG, "invalid bpp value %d", bitmapData->bpp); return FALSE; } Stream_Seek_UINT8(s); /* reserved1 (1 byte) */ @@ -2447,7 +2450,7 @@ BOOL update_read_cache_brush_order(wStream* s, CACHE_BRUSH_ORDER* cache_brush, U { if (cache_brush->length != 8) { - fprintf(stderr, "incompatible 1bpp brush of length:%d\n", cache_brush->length); + WLog_ERR(TAG, "incompatible 1bpp brush of length:%d", cache_brush->length); return TRUE; // should be FALSE ? } @@ -2526,7 +2529,7 @@ BOOL update_write_cache_brush_order(wStream* s, CACHE_BRUSH_ORDER* cache_brush, { if (cache_brush->length != 8) { - fprintf(stderr, "incompatible 1bpp brush of length:%d\n", cache_brush->length); + WLog_ERR(TAG, "incompatible 1bpp brush of length:%d", cache_brush->length); return FALSE; } @@ -2694,7 +2697,7 @@ BOOL update_read_create_nine_grid_bitmap_order(wStream* s, CREATE_NINE_GRID_BITM Stream_Read_UINT8(s, create_nine_grid_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */ if ((create_nine_grid_bitmap->bitmapBpp < 1) || (create_nine_grid_bitmap->bitmapBpp > 32)) { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, create_nine_grid_bitmap->bitmapBpp); + WLog_ERR(TAG, "invalid bpp value %d", create_nine_grid_bitmap->bitmapBpp); return FALSE; } Stream_Read_UINT16(s, create_nine_grid_bitmap->bitmapId); /* bitmapId (2 bytes) */ @@ -2734,7 +2737,7 @@ BOOL update_read_stream_bitmap_first_order(wStream* s, STREAM_BITMAP_FIRST_ORDER Stream_Read_UINT8(s, stream_bitmap_first->bitmapBpp); /* bitmapBpp (1 byte) */ if ((stream_bitmap_first->bitmapBpp < 1) || (stream_bitmap_first->bitmapBpp > 32)) { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, stream_bitmap_first->bitmapBpp); + WLog_ERR(TAG, "invalid bpp value %d", stream_bitmap_first->bitmapBpp); return FALSE; } @@ -3076,7 +3079,7 @@ BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags) if (orderInfo->orderType >= PRIMARY_DRAWING_ORDER_COUNT) { - fprintf(stderr, "Invalid Primary Drawing Order (0x%02X)\n", orderInfo->orderType); + WLog_ERR(TAG, "Invalid Primary Drawing Order (0x%02X)", orderInfo->orderType); return FALSE; } @@ -3098,7 +3101,7 @@ BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags) orderInfo->deltaCoordinates = (flags & ORDER_DELTA_COORDINATES) ? TRUE : FALSE; #ifdef WITH_DEBUG_ORDERS - fprintf(stderr, "%s Primary Drawing Order (0x%02X)\n", PRIMARY_DRAWING_ORDER_STRINGS[orderInfo->orderType], orderInfo->orderType); + WLog_DBG(TAG, "%s Primary Drawing Order (0x%02X)", PRIMARY_DRAWING_ORDER_STRINGS[orderInfo->orderType], orderInfo->orderType); #endif switch (orderInfo->orderType) @@ -3289,9 +3292,9 @@ BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flags) #ifdef WITH_DEBUG_ORDERS if (orderType < SECONDARY_DRAWING_ORDER_COUNT) - fprintf(stderr, "%s Secondary Drawing Order (0x%02X)\n", SECONDARY_DRAWING_ORDER_STRINGS[orderType], orderType); + WLog_DBG(TAG, "%s Secondary Drawing Order (0x%02X)", SECONDARY_DRAWING_ORDER_STRINGS[orderType], orderType); else - fprintf(stderr, "Unknown Secondary Drawing Order (0x%02X)\n", orderType); + WLog_DBG(TAG, "Unknown Secondary Drawing Order (0x%02X)", orderType); #endif switch (orderType) @@ -3381,9 +3384,9 @@ BOOL update_recv_altsec_order(rdpUpdate* update, wStream* s, BYTE flags) #ifdef WITH_DEBUG_ORDERS if (orderType < ALTSEC_DRAWING_ORDER_COUNT) - fprintf(stderr, "%s Alternate Secondary Drawing Order (0x%02X)\n", ALTSEC_DRAWING_ORDER_STRINGS[orderType], orderType); + WLog_DBG(TAG, "%s Alternate Secondary Drawing Order (0x%02X)", ALTSEC_DRAWING_ORDER_STRINGS[orderType], orderType); else - fprintf(stderr, "Unknown Alternate Secondary Drawing Order: 0x%02X\n", orderType); + WLog_DBG(TAG, "Unknown Alternate Secondary Drawing Order: 0x%02X", orderType); #endif switch (orderType) diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 007d4fcb8..3b9274187 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -26,37 +26,196 @@ #include "info.h" #include "certificate.h" +#include #include #include "peer.h" +#define TAG FREERDP_TAG("core.peer") + #ifdef WITH_DEBUG_RDP extern const char* DATA_PDU_TYPE_STRINGS[80]; #endif +static HANDLE freerdp_peer_virtual_channel_open(freerdp_peer* client, const char* name, UINT32 flags) +{ + int length; + UINT32 index; + BOOL joined = FALSE; + rdpMcsChannel* mcsChannel = NULL; + rdpPeerChannel* peerChannel = NULL; + rdpMcs* mcs = client->context->rdp->mcs; + + if (flags & WTS_CHANNEL_OPTION_DYNAMIC) + return NULL; /* not yet supported */ + + length = strlen(name); + + if (length > 8) + return NULL; /* SVC maximum name length is 8 */ + + for (index = 0; index < mcs->channelCount; index++) + { + mcsChannel = &(mcs->channels[index]); + + if (!mcsChannel->joined) + continue; + + if (strncmp(name, mcsChannel->Name, length) == 0) + { + joined = TRUE; + break; + } + } + + if (!joined) + return NULL; /* channel is not joined */ + + peerChannel = (rdpPeerChannel*) mcsChannel->handle; + + if (peerChannel) + { + /* channel is already open */ + return (HANDLE) peerChannel; + } + + peerChannel = (rdpPeerChannel*) calloc(1, sizeof(rdpPeerChannel)); + + if (peerChannel) + { + peerChannel->index = index; + peerChannel->client = client; + peerChannel->channelFlags = flags; + peerChannel->channelId = mcsChannel->ChannelId; + peerChannel->mcsChannel = mcsChannel; + mcsChannel->handle = (void*) peerChannel; + } + + return (HANDLE) peerChannel; +} + +static BOOL freerdp_peer_virtual_channel_close(freerdp_peer* client, HANDLE hChannel) +{ + rdpMcsChannel* mcsChannel = NULL; + rdpPeerChannel* peerChannel = NULL; + + if (!hChannel) + return FALSE; + + peerChannel = (rdpPeerChannel*) hChannel; + mcsChannel = peerChannel->mcsChannel; + + mcsChannel->handle = NULL; + free(peerChannel); + + return TRUE; +} + +int freerdp_peer_virtual_channel_read(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length) +{ + return 0; /* this needs to be implemented by the server application */ +} + +static int freerdp_peer_virtual_channel_write(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length) +{ + wStream* s; + UINT32 flags; + UINT32 chunkSize; + UINT32 maxChunkSize; + UINT32 totalLength; + rdpRdp* rdp = client->context->rdp; + rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel; + rdpMcsChannel* mcsChannel = peerChannel->mcsChannel; + + if (!hChannel) + return -1; + + if (peerChannel->channelFlags & WTS_CHANNEL_OPTION_DYNAMIC) + return -1; /* not yet supported */ + + maxChunkSize = rdp->settings->VirtualChannelChunkSize; + + totalLength = length; + flags = CHANNEL_FLAG_FIRST; + + while (length > 0) + { + s = rdp_send_stream_init(rdp); + + if (length > maxChunkSize) + { + chunkSize = rdp->settings->VirtualChannelChunkSize; + } + else + { + chunkSize = length; + flags |= CHANNEL_FLAG_LAST; + } + + if (mcsChannel->options & CHANNEL_OPTION_SHOW_PROTOCOL) + flags |= CHANNEL_FLAG_SHOW_PROTOCOL; + + Stream_Write_UINT32(s, totalLength); + Stream_Write_UINT32(s, flags); + Stream_EnsureRemainingCapacity(s, chunkSize); + Stream_Write(s, buffer, chunkSize); + + rdp_send(rdp, s, peerChannel->channelId); + + buffer += chunkSize; + length -= chunkSize; + flags = 0; + } + + return 1; +} + +void* freerdp_peer_virtual_channel_get_data(freerdp_peer* client, HANDLE hChannel) +{ + rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel; + + if (!hChannel) + return NULL; + + return peerChannel->extra; +} + +int freerdp_peer_virtual_channel_set_data(freerdp_peer* client, HANDLE hChannel, void* data) +{ + rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel; + + if (!hChannel) + return -1; + + peerChannel->extra = data; + + return 1; +} + static BOOL freerdp_peer_initialize(freerdp_peer* client) { - rdpRdp *rdp = client->context->rdp; - rdpSettings *settings = rdp->settings; + rdpRdp* rdp = client->context->rdp; + rdpSettings* settings = rdp->settings; settings->ServerMode = TRUE; settings->FrameAcknowledge = 0; settings->LocalConnection = client->local; rdp->state = CONNECTION_STATE_INITIAL; - if (settings->RdpKeyFile != NULL) + if (settings->RdpKeyFile) { settings->RdpServerRsaKey = key_new(settings->RdpKeyFile); + if (!settings->RdpServerRsaKey) { - fprintf(stderr, "%s: invalid RDP key file %s\n", __FUNCTION__, settings->RdpKeyFile); + WLog_ERR(TAG, "inavlid RDP key file %s", settings->RdpKeyFile); return FALSE; } if (settings->RdpServerRsaKey->ModulusLength > 256) { - fprintf(stderr, "%s: Key sizes > 2048 are currently not supported for RDP security.\n", __FUNCTION__); - fprintf(stderr, "%s: Set a different key file than %s\n", __FUNCTION__, settings->RdpKeyFile); + WLog_ERR(TAG, "Key sizes > 2048 are currently not supported for RDP security."); + WLog_ERR(TAG, "Set a different key file than %s", settings->RdpKeyFile); exit(1); } } @@ -77,7 +236,6 @@ static HANDLE freerdp_peer_get_event_handle(freerdp_peer* client) return client->context->rdp->transport->TcpIn->event; } - static BOOL freerdp_peer_check_fds(freerdp_peer* peer) { int status; @@ -105,8 +263,8 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) return FALSE; #ifdef WITH_DEBUG_RDP - printf("recv %s Data PDU (0x%02X), length: %d\n", - type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); + WLog_DBG(TAG, "recv %s Data PDU (0x%02X), length: %d", + type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) @@ -159,7 +317,7 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) break; default: - fprintf(stderr, "Data PDU type %d\n", type); + WLog_ERR(TAG, "Data PDU type %d", type); break; } @@ -180,10 +338,13 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) if (!rdp_read_header(rdp, s, &length, &channelId)) { - fprintf(stderr, "Incorrect RDP header.\n"); + WLog_ERR(TAG, "Incorrect RDP header."); return -1; } + if (rdp->disconnect) + return 0; + if (rdp->settings->DisableEncryption) { if (!rdp_read_security_header(s, &securityFlags)) @@ -193,7 +354,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) { if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) { - fprintf(stderr, "rdp_decrypt failed\n"); + WLog_ERR(TAG, "rdp_decrypt failed"); return -1; } } @@ -224,7 +385,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) break; default: - fprintf(stderr, "Client sent pduType %d\n", pduType); + WLog_ERR(TAG, "Client sent pduType %d", pduType); return -1; } } @@ -245,7 +406,7 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, wStream* s) if ((length == 0) || (length > Stream_GetRemainingLength(s))) { - fprintf(stderr, "incorrect FastPath PDU header length %d\n", length); + WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length); return -1; } @@ -384,7 +545,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) break; default: - fprintf(stderr, "Invalid state %d\n", rdp->state); + WLog_ERR(TAG, "Invalid state %d", rdp->state); return -1; } @@ -421,8 +582,7 @@ static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer) static int freerdp_peer_drain_output_buffer(freerdp_peer* peer) { - - rdpTransport *transport = peer->context->rdp->transport; + rdpTransport* transport = peer->context->rdp->transport; return tranport_drain_output_buffer(transport); } @@ -431,7 +591,7 @@ void freerdp_peer_context_new(freerdp_peer* client) { rdpRdp* rdp; - client->context = (rdpContext *)calloc(1, client->ContextSize); + client->context = (rdpContext*) calloc(1, client->ContextSize); client->context->ServerMode = TRUE; @@ -494,6 +654,12 @@ freerdp_peer* freerdp_peer_new(int sockfd) client->SendChannelData = freerdp_peer_send_channel_data; client->IsWriteBlocked = freerdp_peer_is_write_blocked; client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; + client->VirtualChannelOpen = freerdp_peer_virtual_channel_open; + client->VirtualChannelClose = freerdp_peer_virtual_channel_close; + client->VirtualChannelWrite = freerdp_peer_virtual_channel_write; + client->VirtualChannelRead = NULL; /* must be defined by server application */ + client->VirtualChannelGetData = freerdp_peer_virtual_channel_get_data; + client->VirtualChannelSetData = freerdp_peer_virtual_channel_set_data; } return client; diff --git a/libfreerdp/core/peer.h b/libfreerdp/core/peer.h index cee607683..e9cd03937 100644 --- a/libfreerdp/core/peer.h +++ b/libfreerdp/core/peer.h @@ -21,6 +21,9 @@ #define __PEER #include "rdp.h" +#include "mcs.h" +#include "server.h" + #include #endif /* __PEER */ diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 0059f8b4d..42f14d1b3 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -29,6 +29,9 @@ #include "redirection.h" #include +#include + +#define TAG FREERDP_TAG("core.rdp") #ifdef WITH_DEBUG_RDP const char* DATA_PDU_TYPE_STRINGS[80] = @@ -272,18 +275,45 @@ wStream* rdp_message_channel_pdu_init(rdpRdp* rdp) BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { + BYTE li; BYTE byte; + BYTE code; + BYTE choice; UINT16 initiator; enum DomainMCSPDU MCSPDU; + enum DomainMCSPDU domainMCSPDU; MCSPDU = (rdp->settings->ServerMode) ? DomainMCSPDU_SendDataRequest : DomainMCSPDU_SendDataIndication; - if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, length)) + *length = tpkt_read_header(s); + + if (!tpdu_read_header(s, &code, &li)) + return FALSE; + + if (code != X224_TPDU_DATA) { - if (MCSPDU != DomainMCSPDU_DisconnectProviderUltimatum) + if (code == X224_TPDU_DISCONNECT_REQUEST) + { + rdp->disconnect = TRUE; + return TRUE; + } + + return FALSE; + } + + if (!per_read_choice(s, &choice)) + return FALSE; + + domainMCSPDU = (enum DomainMCSPDU) (choice >> 2); + + if (domainMCSPDU != MCSPDU) + { + if (domainMCSPDU != DomainMCSPDU_DisconnectProviderUltimatum) return FALSE; } + MCSPDU = domainMCSPDU; + if ((size_t) (*length - 8) > Stream_GetRemainingLength(s)) return FALSE; @@ -296,7 +326,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) if (!mcs_recv_disconnect_provider_ultimatum(rdp->mcs, s, &reason)) return FALSE; - if (rdp->instance == NULL) + if (!rdp->instance) { rdp->disconnect = TRUE; return FALSE; @@ -320,8 +350,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) rdp_set_error_info(rdp, ERRINFO_RPC_INITIATED_DISCONNECT); } - fprintf(stderr, "DisconnectProviderUltimatum: reason: %d\n", reason); - + WLog_ERR(TAG, "DisconnectProviderUltimatum: reason: %d", reason); rdp->disconnect = TRUE; EventArgsInit(&e, "freerdp"); @@ -417,7 +446,6 @@ static UINT32 rdp_security_stream_out(rdpRdp* rdp, wStream* s, int length, UINT3 memset(data+length, 0, pad); Stream_Write_UINT8(s, pad); - security_hmac_signature(data, length, Stream_Pointer(s), rdp); Stream_Seek(s, 8); security_fips_encrypt(data, length + pad, rdp); @@ -467,7 +495,7 @@ static UINT32 rdp_get_sec_bytes(rdpRdp* rdp) } /** - * Send an RDP packet.\n + * Send an RDP packet. * @param rdp RDP module * @param s stream * @param channel_id channel id @@ -476,14 +504,10 @@ static UINT32 rdp_get_sec_bytes(rdpRdp* rdp) BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channel_id) { UINT16 length; - length = Stream_GetPosition(s); Stream_SetPosition(s, 0); - rdp_write_header(rdp, s, length, channel_id); - length += rdp_security_stream_out(rdp, s, length, 0); - Stream_SetPosition(s, length); Stream_SealLength(s); @@ -498,21 +522,15 @@ BOOL rdp_send_pdu(rdpRdp* rdp, wStream* s, UINT16 type, UINT16 channel_id) UINT16 length; UINT32 sec_bytes; int sec_hold; - length = Stream_GetPosition(s); Stream_SetPosition(s, 0); - rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID); - sec_bytes = rdp_get_sec_bytes(rdp); sec_hold = Stream_GetPosition(s); Stream_Seek(s, sec_bytes); - rdp_write_share_control_header(s, length - sec_bytes, type, channel_id); - Stream_SetPosition(s, sec_hold); length += rdp_security_stream_out(rdp, s, length, 0); - Stream_SetPosition(s, length); Stream_SealLength(s); @@ -527,22 +545,16 @@ BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id) UINT16 length; UINT32 sec_bytes; int sec_hold; - length = Stream_GetPosition(s); Stream_SetPosition(s, 0); - rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID); - sec_bytes = rdp_get_sec_bytes(rdp); sec_hold = Stream_GetPosition(s); Stream_Seek(s, sec_bytes); - rdp_write_share_control_header(s, length - sec_bytes, PDU_TYPE_DATA, channel_id); rdp_write_share_data_header(s, length - sec_bytes, type, rdp->settings->ShareId); - Stream_SetPosition(s, sec_hold); length += rdp_security_stream_out(rdp, s, length, 0); - Stream_SetPosition(s, length); Stream_SealLength(s); @@ -557,19 +569,14 @@ BOOL rdp_send_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags) UINT16 length; UINT32 sec_bytes; int sec_hold; - length = Stream_GetPosition(s); Stream_SetPosition(s, 0); - rdp_write_header(rdp, s, length, rdp->mcs->messageChannelId); - sec_bytes = rdp_get_sec_bytes(rdp); sec_hold = Stream_GetPosition(s); Stream_Seek(s, sec_bytes); - Stream_SetPosition(s, sec_hold); length += rdp_security_stream_out(rdp, s, length, sec_flags); - Stream_SetPosition(s, length); Stream_SealLength(s); @@ -588,6 +595,7 @@ BOOL rdp_recv_server_set_keyboard_indicators_pdu(rdpRdp* rdp, wStream* s) { UINT16 unitId; UINT16 ledFlags; + rdpContext* context = rdp->instance->context; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -595,6 +603,8 @@ BOOL rdp_recv_server_set_keyboard_indicators_pdu(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, unitId); /* unitId (2 bytes) */ Stream_Read_UINT16(s, ledFlags); /* ledFlags (2 bytes) */ + IFCALL(context->update->SetKeyboardIndicators, context, ledFlags); + return TRUE; } @@ -610,7 +620,6 @@ BOOL rdp_recv_server_set_keyboard_ime_status_pdu(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, unitId); /* unitId (2 bytes) */ Stream_Read_UINT32(s, imeState); /* imeState (4 bytes) */ Stream_Read_UINT32(s, imeConvMode); /* imeConvMode (4 bytes) */ - return TRUE; } @@ -622,9 +631,7 @@ BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, errorInfo); /* errorInfo (4 bytes) */ - rdp_set_error_info(rdp, errorInfo); - return TRUE; } @@ -636,7 +643,6 @@ BOOL rdp_recv_server_auto_reconnect_status_pdu(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, arcStatus); /* arcStatus (4 bytes) */ - return TRUE; } @@ -648,7 +654,6 @@ BOOL rdp_recv_server_status_info_pdu(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, statusCode); /* statusCode (4 bytes) */ - return TRUE; } @@ -667,13 +672,14 @@ BOOL rdp_recv_monitor_layout_pdu(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < (monitorCount * 20)) return FALSE; - monitorDefArray = (MONITOR_DEF*) malloc(sizeof(MONITOR_DEF) * monitorCount); - ZeroMemory(monitorDefArray, sizeof(MONITOR_DEF) * monitorCount); + monitorDefArray = (MONITOR_DEF*) calloc(monitorCount, sizeof(MONITOR_DEF)); + + if (!monitorDefArray) + return FALSE; for (index = 0; index < monitorCount; index++) { monitor = &(monitorDefArray[index]); - Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */ Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */ Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */ @@ -690,15 +696,12 @@ BOOL rdp_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount, MONITOR_DEF* { UINT32 index; MONITOR_DEF* monitor; - Stream_EnsureRemainingCapacity(s, 4 + (monitorCount * 20)); - Stream_Write_UINT32(s, monitorCount); /* monitorCount (4 bytes) */ for (index = 0; index < monitorCount; index++) { monitor = &(monitorDefArray[index]); - Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */ Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */ Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */ @@ -731,7 +734,7 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < (size_t) SrcSize) { - fprintf(stderr, "bulk_decompress: not enough bytes for compressedLength %d\n", compressedLength); + WLog_ERR(TAG, "bulk_decompress: not enough bytes for compressedLength %d", compressedLength); return -1; } @@ -746,7 +749,7 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) } else { - fprintf(stderr, "bulk_decompress() failed\n"); + WLog_ERR(TAG, "bulk_decompress() failed"); return -1; } @@ -754,8 +757,8 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) } #ifdef WITH_DEBUG_RDP - printf("recv %s Data PDU (0x%02X), length: %d\n", - type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); + WLog_DBG(TAG, "recv %s Data PDU (0x%02X), length: %d", + type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) @@ -923,13 +926,13 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) if (!security_fips_decrypt(Stream_Pointer(s), length, rdp)) { - fprintf(stderr, "FATAL: cannot decrypt\n"); + WLog_ERR(TAG, "FATAL: cannot decrypt"); return FALSE; /* TODO */ } if (!security_fips_check_signature(Stream_Pointer(s), length - pad, sig, rdp)) { - fprintf(stderr, "FATAL: invalid packet signature\n"); + WLog_ERR(TAG, "FATAL: invalid packet signature"); return FALSE; /* TODO */ } @@ -953,7 +956,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) if (memcmp(wmac, cmac, sizeof(wmac)) != 0) { - fprintf(stderr, "WARNING: invalid packet signature\n"); + WLog_ERR(TAG, "WARNING: invalid packet signature"); /* * Because Standard RDP Security is totally broken, * and cannot protect against MITM, don't treat signature @@ -985,10 +988,13 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) if (!rdp_read_header(rdp, s, &length, &channelId)) { - fprintf(stderr, "Incorrect RDP header.\n"); + WLog_ERR(TAG, "Incorrect RDP header."); return -1; } + if (rdp->disconnect) + return 0; + if (rdp->settings->DisableEncryption) { if (!rdp_read_security_header(s, &securityFlags)) @@ -998,7 +1004,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) { if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) { - fprintf(stderr, "rdp_decrypt failed\n"); + WLog_ERR(TAG, "rdp_decrypt failed"); return -1; } } @@ -1033,7 +1039,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) case PDU_TYPE_DATA: if (rdp_recv_data_pdu(rdp, s) < 0) { - fprintf(stderr, "rdp_recv_data_pdu failed\n"); + WLog_ERR(TAG, "rdp_recv_data_pdu failed"); return -1; } break; @@ -1048,7 +1054,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) break; default: - fprintf(stderr, "incorrect PDU type: 0x%04X\n", pduType); + WLog_ERR(TAG, "incorrect PDU type: 0x%04X", pduType); break; } @@ -1080,7 +1086,7 @@ static int rdp_recv_fastpath_pdu(rdpRdp* rdp, wStream* s) if ((length == 0) || (length > Stream_GetRemainingLength(s))) { - fprintf(stderr, "incorrect FastPath PDU header length %d\n", length); + WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length); return -1; } @@ -1150,7 +1156,10 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) status = rdp_recv_pdu(rdp, s); if ((status >= 0) && (rdp->finalize_sc_pdus == FINALIZE_SC_COMPLETE)) + { rdp_client_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); + return 2; + } break; case CONNECTION_STATE_ACTIVE: @@ -1158,7 +1167,7 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) break; default: - fprintf(stderr, "Invalid state %d\n", rdp->state); + WLog_ERR(TAG, "Invalid state %d", rdp->state); status = -1; break; } diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 0771e9ec2..68edca9bd 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -46,7 +46,7 @@ #include #include -#include +#include #include @@ -213,10 +213,11 @@ rdpRdp* rdp_new(rdpContext* context); void rdp_reset(rdpRdp* rdp); void rdp_free(rdpRdp* rdp); +#define RDP_TAG FREERDP_TAG("core.rdp") #ifdef WITH_DEBUG_RDP -#define DEBUG_RDP(fmt, ...) DEBUG_CLASS(RDP, fmt, ## __VA_ARGS__) +#define DEBUG_RDP(fmt, ...) WLog_DBG(RDP_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_RDP(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_RDP(fmt, ...) do { } while (0) #endif BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags); diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 37470d580..242d001d4 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -22,43 +22,58 @@ #endif #include +#include #include "connection.h" #include "redirection.h" +#define TAG FREERDP_TAG("core.redirection") + void rdp_print_redirection_flags(UINT32 flags) { - fprintf(stderr, "redirectionFlags = {\n"); + WLog_INFO(TAG, "redirectionFlags = {"); if (flags & LB_TARGET_NET_ADDRESS) - fprintf(stderr, "\tLB_TARGET_NET_ADDRESS\n"); - if (flags & LB_LOAD_BALANCE_INFO) - fprintf(stderr, "\tLB_LOAD_BALANCE_INFO\n"); - if (flags & LB_USERNAME) - fprintf(stderr, "\tLB_USERNAME\n"); - if (flags & LB_DOMAIN) - fprintf(stderr, "\tLB_DOMAIN\n"); - if (flags & LB_PASSWORD) - fprintf(stderr, "\tLB_PASSWORD\n"); - if (flags & LB_DONTSTOREUSERNAME) - fprintf(stderr, "\tLB_DONTSTOREUSERNAME\n"); - if (flags & LB_SMARTCARD_LOGON) - fprintf(stderr, "\tLB_SMARTCARD_LOGON\n"); - if (flags & LB_NOREDIRECT) - fprintf(stderr, "\tLB_NOREDIRECT\n"); - if (flags & LB_TARGET_FQDN) - fprintf(stderr, "\tLB_TARGET_FQDN\n"); - if (flags & LB_TARGET_NETBIOS_NAME) - fprintf(stderr, "\tLB_TARGET_NETBIOS_NAME\n"); - if (flags & LB_TARGET_NET_ADDRESSES) - fprintf(stderr, "\tLB_TARGET_NET_ADDRESSES\n"); - if (flags & LB_CLIENT_TSV_URL) - fprintf(stderr, "\tLB_CLIENT_TSV_URL\n"); - if (flags & LB_SERVER_TSV_CAPABLE) - fprintf(stderr, "\tLB_SERVER_TSV_CAPABLE\n"); + WLog_INFO(TAG, "\tLB_TARGET_NET_ADDRESS"); - fprintf(stderr, "}\n"); + if (flags & LB_LOAD_BALANCE_INFO) + WLog_INFO(TAG, "\tLB_LOAD_BALANCE_INFO"); + + if (flags & LB_USERNAME) + WLog_INFO(TAG, "\tLB_USERNAME"); + + if (flags & LB_DOMAIN) + WLog_INFO(TAG, "\tLB_DOMAIN"); + + if (flags & LB_PASSWORD) + WLog_INFO(TAG, "\tLB_PASSWORD"); + + if (flags & LB_DONTSTOREUSERNAME) + WLog_INFO(TAG, "\tLB_DONTSTOREUSERNAME"); + + if (flags & LB_SMARTCARD_LOGON) + WLog_INFO(TAG, "\tLB_SMARTCARD_LOGON"); + + if (flags & LB_NOREDIRECT) + WLog_INFO(TAG, "\tLB_NOREDIRECT"); + + if (flags & LB_TARGET_FQDN) + WLog_INFO(TAG, "\tLB_TARGET_FQDN"); + + if (flags & LB_TARGET_NETBIOS_NAME) + WLog_INFO(TAG, "\tLB_TARGET_NETBIOS_NAME"); + + if (flags & LB_TARGET_NET_ADDRESSES) + WLog_INFO(TAG, "\tLB_TARGET_NET_ADDRESSES"); + + if (flags & LB_CLIENT_TSV_URL) + WLog_INFO(TAG, "\tLB_CLIENT_TSV_URL"); + + if (flags & LB_SERVER_TSV_CAPABLE) + WLog_INFO(TAG, "\tLB_SERVER_TSV_CAPABLE"); + + WLog_INFO(TAG, "}"); } BOOL rdp_redirection_read_string(wStream* s, char** str) @@ -67,7 +82,7 @@ BOOL rdp_redirection_read_string(wStream* s, char** str) if (Stream_GetRemainingLength(s) < 4) { - fprintf(stderr, "rdp_redirection_read_string failure: cannot read length\n"); + WLog_ERR(TAG, "rdp_redirection_read_string failure: cannot read length"); return FALSE; } @@ -75,13 +90,12 @@ BOOL rdp_redirection_read_string(wStream* s, char** str) if (Stream_GetRemainingLength(s) < length) { - fprintf(stderr, "rdp_redirection_read_string failure: incorrect length %d\n", length); + WLog_ERR(TAG, "rdp_redirection_read_string failure: incorrect length %d", length); return FALSE; } ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), length / 2, str, 0, NULL, NULL); Stream_Seek(s, length); - return TRUE; } @@ -89,7 +103,6 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) { rdpSettings* settings = rdp->settings; rdpRedirection* redirection = rdp->redirection; - settings->RedirectionFlags = redirection->flags; settings->RedirectedSessionId = redirection->sessionID; @@ -107,7 +120,6 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) * Free previous LoadBalanceInfo, if any, otherwise it may end up * being reused for the redirected session, which is not what we want. */ - free(settings->LoadBalanceInfo); settings->LoadBalanceInfo = NULL; settings->LoadBalanceInfoLength = 0; @@ -162,9 +174,7 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESSES) { UINT32 i; - freerdp_target_net_addresses_free(settings); - settings->TargetNetAddressCount = redirection->TargetNetAddressesCount; settings->TargetNetAddresses = (char**) malloc(sizeof(char*) * settings->TargetNetAddressCount); @@ -190,10 +200,8 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, length); /* length (2 bytes) */ Stream_Read_UINT32(s, redirection->sessionID); /* sessionID (4 bytes) */ Stream_Read_UINT32(s, redirection->flags); /* redirFlags (4 bytes) */ - WLog_Print(redirection->log, WLOG_DEBUG, "flags: 0x%04X, redirFlags: 0x%04X length: %d, sessionID: 0x%08X", - flags, redirection->flags, length, redirection->sessionID); - + flags, redirection->flags, length, redirection->sessionID); #ifdef WITH_DEBUG_REDIR rdp_print_redirection_flags(redirection->flags); #endif @@ -218,7 +226,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("loadBalanceInfo:"); - winpr_HexDump(redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); + winpr_HexDump(TAG, WLOG_DEBUG, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #endif } @@ -247,10 +255,9 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, redirection->PasswordLength); redirection->Password = (BYTE*) malloc(redirection->PasswordLength); Stream_Read(s, redirection->Password, redirection->PasswordLength); - #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("PasswordCookie:"); - winpr_HexDump(redirection->Password, redirection->PasswordLength); + winpr_HexDump(TAG, WLOG_DEBUG, redirection->Password, redirection->PasswordLength); #endif } @@ -282,10 +289,9 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) redirection->TsvUrl = (BYTE*) malloc(redirection->TsvUrlLength); Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength); - #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("TsvUrl:"); - winpr_HexDump(redirection->TsvUrl, redirection->TsvUrlLength); + winpr_HexDump(TAG, WLOG_DEBUG, redirection->TsvUrl, redirection->TsvUrlLength); #endif } @@ -299,13 +305,10 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) return -1; Stream_Read_UINT32(s, targetNetAddressesLength); - Stream_Read_UINT32(s, redirection->TargetNetAddressesCount); count = redirection->TargetNetAddressesCount; - redirection->TargetNetAddresses = (char**) malloc(count * sizeof(char*)); ZeroMemory(redirection->TargetNetAddresses, count * sizeof(char*)); - WLog_Print(redirection->log, WLOG_DEBUG, "TargetNetAddressesCount: %d", redirection->TargetNetAddressesCount); for (i = 0; i < (int) count; i++) @@ -354,14 +357,12 @@ int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) rdpRedirection* redirection_new() { rdpRedirection* redirection; - redirection = (rdpRedirection*) calloc(1, sizeof(rdpRedirection)); if (redirection) { WLog_Init(); redirection->log = WLog_Get("com.freerdp.core.redirection"); - #ifdef WITH_DEBUG_REDIR WLog_SetLogLevel(redirection->log, WLOG_TRACE); #endif diff --git a/libfreerdp/core/redirection.h b/libfreerdp/core/redirection.h index 4451027eb..4c239b904 100644 --- a/libfreerdp/core/redirection.h +++ b/libfreerdp/core/redirection.h @@ -25,7 +25,7 @@ typedef struct rdp_redirection rdpRedirection; #include "rdp.h" #include -#include +#include #include #include @@ -57,10 +57,11 @@ int rdp_redirection_apply_settings(rdpRdp* rdp); rdpRedirection* redirection_new(void); void redirection_free(rdpRedirection* redirection); +#define REDIR_TAG FREERDP_TAG("core.redirection") #ifdef WITH_DEBUG_REDIR -#define DEBUG_REDIR(fmt, ...) DEBUG_CLASS(REDIR, fmt, ## __VA_ARGS__) +#define DEBUG_REDIR(fmt, ...) WLog_DBG(REDIR_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_REDIR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_REDIR(fmt, ...) do { } while (0) #endif #endif /* __REDIRECTION_H */ diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index ccc6344f0..dc46c42b5 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -24,6 +24,10 @@ #include "security.h" +#include + +#define TAG FREERDP_TAG("core") + /* 0x36 repeated 40 times */ static const BYTE pad1[40] = { @@ -132,7 +136,7 @@ static void security_salted_hash(const BYTE* salt, const BYTE* input, int length sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return; } crypto_sha1_update(sha1, input, length); /* Input */ @@ -145,7 +149,7 @@ static void security_salted_hash(const BYTE* salt, const BYTE* input, int length md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, salt, 48); /* Salt (48 bytes) */ @@ -198,7 +202,7 @@ void security_md5_16_32_32(const BYTE* in0, const BYTE* in1, const BYTE* in2, BY md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, in0, 16); @@ -238,7 +242,7 @@ void security_mac_data(const BYTE* mac_salt_key, const BYTE* data, UINT32 length sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return; } crypto_sha1_update(sha1, mac_salt_key, 16); /* MacSaltKey */ @@ -251,7 +255,7 @@ void security_mac_data(const BYTE* mac_salt_key, const BYTE* data, UINT32 length md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, mac_salt_key, 16); /* MacSaltKey */ @@ -274,7 +278,7 @@ void security_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BYTE* sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return; } crypto_sha1_update(sha1, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ @@ -287,7 +291,7 @@ void security_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BYTE* md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ @@ -327,7 +331,7 @@ void security_salted_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return; } crypto_sha1_update(sha1, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ @@ -341,7 +345,7 @@ void security_salted_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ @@ -418,13 +422,11 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) CryptoSha1 sha1; BYTE client_encrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; BYTE client_decrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; - - fprintf(stderr, "FIPS Compliant encryption level.\n"); - + WLog_INFO(TAG, "FIPS Compliant encryption level."); sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return FALSE; } crypto_sha1_update(sha1, client_random + 16, 16); @@ -435,7 +437,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return FALSE; } crypto_sha1_update(sha1, client_random, 16); @@ -446,7 +448,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return FALSE; } crypto_sha1_update(sha1, client_decrypt_key_t, 20); @@ -528,7 +530,7 @@ BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp) sha1 = crypto_sha1_init(); if (!sha1) { - fprintf(stderr, "%s: unable to allocate a sha1\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a sha1"); return FALSE; } crypto_sha1_update(sha1, update_key, key_len); @@ -539,7 +541,7 @@ BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp) md5 = crypto_md5_init(); if (!md5) { - fprintf(stderr, "%s: unable to allocate a md5\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a md5"); return FALSE; } crypto_md5_update(md5, update_key, key_len); @@ -550,7 +552,7 @@ BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp) rc4 = crypto_rc4_init(key, key_len); if (!rc4) { - fprintf(stderr, "%s: unable to allocate a rc4\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate a rc4"); return FALSE; } crypto_rc4(rc4, key_len, key, key); @@ -573,7 +575,7 @@ BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp) rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); return FALSE; } rdp->encrypt_use_count = 0; @@ -595,7 +597,7 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key) { - fprintf(stderr, "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__); + WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); return FALSE; } diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 4e4e520e5..51c06699c 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -36,12 +37,22 @@ #include "server.h" +#define TAG FREERDP_TAG("core.server") #ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_DVC(fmt, ...) do { } while (0) #endif +struct _wtsChannelMessage +{ + UINT16 channelId; + UINT16 reserved; + UINT32 length; + UINT32 offset; +}; +typedef struct _wtsChannelMessage wtsChannelMessage; + static DWORD g_SessionId = 1; static wHashTable* g_ServerHandles = NULL; @@ -75,15 +86,16 @@ static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, static void wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer, UINT32 Length) { BYTE* buffer; - UINT32 length; - UINT16 channelId; + wtsChannelMessage* messageCtx; - length = Length; - buffer = (BYTE*) malloc(length); - CopyMemory(buffer, Buffer, length); - channelId = channel->channelId; + messageCtx = (wtsChannelMessage*) malloc(sizeof(wtsChannelMessage) + Length); + messageCtx->channelId = channel->channelId; + messageCtx->length = Length; + messageCtx->offset = 0; + buffer = (BYTE*) (messageCtx + 1); + CopyMemory(buffer, Buffer, Length); - MessageQueue_Post(channel->queue, (void*) (UINT_PTR) channelId, 0, (void*) buffer, (void*) (UINT_PTR) length); + MessageQueue_Post(channel->queue, messageCtx, 0, NULL, NULL); } static void wts_queue_send_item(rdpPeerChannel* channel, BYTE* Buffer, UINT32 Length) @@ -185,7 +197,7 @@ static void wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s, UINT32 le if (Stream_GetPosition(channel->receiveData) + length > channel->dvc_total_length) { channel->dvc_total_length = 0; - fprintf(stderr, "wts_read_drdynvc_data: incorrect fragment data, discarded.\n"); + WLog_ERR(TAG, "incorrect fragment data, discarded."); return; } @@ -269,7 +281,7 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel) break; default: - fprintf(stderr, "wts_read_drdynvc_pdu: Cmd %d not recognized.\n", Cmd); + WLog_ERR(TAG, "Cmd %d not recognized.", Cmd); break; } } @@ -280,34 +292,34 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel) } else { - fprintf(stderr, "wts_read_drdynvc_pdu: received Cmd %d but channel is not ready.\n", Cmd); + WLog_ERR(TAG, "received Cmd %d but channel is not ready.", Cmd); } } -static int wts_write_variable_uint(wStream* stream, UINT32 val) +static int wts_write_variable_uint(wStream* s, UINT32 val) { int cb; if (val <= 0xFF) { cb = 0; - Stream_Write_UINT8(stream, val); + Stream_Write_UINT8(s, val); } else if (val <= 0xFFFF) { cb = 1; - Stream_Write_UINT16(stream, val); + Stream_Write_UINT16(s, val); } else { cb = 2; - Stream_Write_UINT32(stream, val); + Stream_Write_UINT32(s, val); } return cb; } -static void wts_write_drdynvc_header(wStream *s, BYTE Cmd, UINT32 ChannelId) +static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId) { BYTE* bm; int cbChId; @@ -342,7 +354,7 @@ static void WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, BYT { if (Stream_GetPosition(channel->receiveData) != totalSize) { - fprintf(stderr, "WTSProcessChannelData: read error\n"); + WLog_ERR(TAG, "read error"); } if (channel == channel->vcm->drdynvc_channel) { @@ -465,9 +477,10 @@ HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer) return MessageQueue_Event(vcm->queue); } -static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs *mcs, const char *channel_name) +static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name) { UINT32 index; + if (!mcs || !channel_name || !strlen(channel_name)) return NULL; @@ -477,14 +490,16 @@ static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs *mcs, const char *ch { if (_strnicmp(mcs->channels[index].Name, channel_name, strlen(channel_name)) == 0) return &mcs->channels[index]; - } - } - return NULL; + } + } + + return NULL; } -static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs *mcs, const UINT16 channel_id) +static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id) { UINT32 index; + if (!mcs || !channel_id) return NULL; @@ -494,12 +509,13 @@ static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs *mcs, const UINT16 cha { if (mcs->channels[index].ChannelId == channel_id) return &mcs->channels[index]; - } - } - return NULL; + } + } + + return NULL; } -BOOL WTSIsChannelJoinedByName(freerdp_peer *client, const char *channel_name) +BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name) { if (!client || !client->context || !client->context->rdp) return FALSE; @@ -507,7 +523,7 @@ BOOL WTSIsChannelJoinedByName(freerdp_peer *client, const char *channel_name) return wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) == NULL ? FALSE : TRUE; } -BOOL WTSIsChannelJoinedById(freerdp_peer *client, const UINT16 channel_id) +BOOL WTSIsChannelJoinedById(freerdp_peer* client, const UINT16 channel_id) { if (!client || !client->context || !client->context->rdp) return FALSE; @@ -525,27 +541,30 @@ BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name) return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE; } -UINT16 WTSChannelGetId(freerdp_peer *client, const char *channel_name) +UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name) { - rdpMcsChannel *channel; + rdpMcsChannel* channel; if (!client || !client->context || !client->context->rdp) return 0; channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name); + if (!channel) return 0; return channel->ChannelId; } -BOOL WTSChannelSetHandleByName(freerdp_peer *client, const char *channel_name, void *handle) +BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle) { - rdpMcsChannel *channel; + rdpMcsChannel* channel; + if (!client || !client->context || !client->context->rdp) return FALSE; channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name); + if (!channel) return FALSE; @@ -553,13 +572,15 @@ BOOL WTSChannelSetHandleByName(freerdp_peer *client, const char *channel_name, v return TRUE; } -BOOL WTSChannelSetHandleById(freerdp_peer *client, const UINT16 channel_id, void *handle) +BOOL WTSChannelSetHandleById(freerdp_peer* client, const UINT16 channel_id, void* handle) { - rdpMcsChannel *channel; + rdpMcsChannel* channel; + if (!client || !client->context || !client->context->rdp) return FALSE; channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id); + if (!channel) return FALSE; @@ -567,26 +588,30 @@ BOOL WTSChannelSetHandleById(freerdp_peer *client, const UINT16 channel_id, void return TRUE; } -void *WTSChannelGetHandleByName(freerdp_peer *client, const char *channel_name) +void* WTSChannelGetHandleByName(freerdp_peer* client, const char *channel_name) { - rdpMcsChannel *channel; + rdpMcsChannel* channel; + if (!client || !client->context || !client->context->rdp) return NULL; channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name); + if (!channel) return NULL; return channel->handle; } -void *WTSChannelGetHandleById(freerdp_peer *client, const UINT16 channel_id) +void* WTSChannelGetHandleById(freerdp_peer* client, const UINT16 channel_id) { - rdpMcsChannel *channel; + rdpMcsChannel* channel; + if (!client || !client->context || !client->context->rdp) return NULL; channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id); + if (!channel) return NULL; @@ -1027,28 +1052,38 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle) BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead) { BYTE* buffer; - UINT32 length; - UINT16 channelId; wMessage message; + wtsChannelMessage* messageCtx; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; - if (!MessageQueue_Peek(channel->queue, &message, TRUE)) + if (!MessageQueue_Peek(channel->queue, &message, FALSE)) { + SetLastError(ERROR_NO_DATA); *pBytesRead = 0; + return FALSE; + } + + messageCtx = (wtsChannelMessage*) (UINT_PTR) message.context; + buffer = (BYTE*) (messageCtx + 1); + + *pBytesRead = messageCtx->length - messageCtx->offset; + + if (Buffer == NULL || BufferSize == 0) + { return TRUE; } - channelId = (UINT16) (UINT_PTR) message.context; - buffer = (BYTE*) message.wParam; - length = (UINT32) (UINT_PTR) message.lParam; + if (*pBytesRead > BufferSize) + *pBytesRead = BufferSize; - *pBytesRead = length; + CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead); + messageCtx->offset += *pBytesRead; - if (length > BufferSize) - return FALSE; - - CopyMemory(Buffer, buffer, length); - free(buffer); + if (messageCtx->offset >= messageCtx->length) + { + MessageQueue_Peek(channel->queue, &message, TRUE); + free(messageCtx); + } return TRUE; } diff --git a/libfreerdp/core/server.h b/libfreerdp/core/server.h index fe438330e..1bd63e8f6 100644 --- a/libfreerdp/core/server.h +++ b/libfreerdp/core/server.h @@ -21,16 +21,18 @@ #define FREERDP_CORE_SERVER_H #include -#include + #include #include #include #include +typedef struct rdp_peer_channel rdpPeerChannel; typedef struct WTSVirtualChannelManager WTSVirtualChannelManager; #include "rdp.h" +#include "mcs.h" #define CREATE_REQUEST_PDU 0x01 #define DATA_FIRST_PDU 0x02 @@ -59,22 +61,23 @@ enum DVC_OPEN_STATE_CLOSED = 3 }; -typedef struct rdp_peer_channel rdpPeerChannel; - struct rdp_peer_channel { WTSVirtualChannelManager* vcm; freerdp_peer* client; + void* extra; + UINT16 index; UINT32 channelId; UINT16 channelType; - UINT16 index; + UINT32 channelFlags; wStream* receiveData; wMessageQueue* queue; BYTE dvc_open_state; UINT32 dvc_total_length; + rdpMcsChannel* mcsChannel; }; struct WTSVirtualChannelManager diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 6c0de1e7f..f4952a71d 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -321,7 +321,11 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->DrawGdiPlusEnabled = FALSE; - settings->FrameMarkerCommandEnabled = FALSE; + settings->DrawAllowSkipAlpha = TRUE; + settings->DrawAllowColorSubsampling = FALSE; + settings->DrawAllowDynamicColorFidelity = FALSE; + + settings->FrameMarkerCommandEnabled = TRUE; settings->SurfaceFrameMarkerEnabled = TRUE; settings->BitmapCacheV3Enabled = FALSE; @@ -398,9 +402,19 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->FrameAcknowledge = 2; settings->MouseMotion = TRUE; + settings->NSCodecColorLossLevel = 3; + settings->NSCodecAllowSubsampling = TRUE; + settings->NSCodecAllowDynamicColorFidelity = TRUE; + settings->AutoReconnectionEnabled = FALSE; settings->AutoReconnectMaxRetries = 20; + settings->GfxThinClient = TRUE; + settings->GfxSmallCache = FALSE; + settings->GfxProgressive = FALSE; + settings->GfxProgressiveV2 = FALSE; + settings->GfxH264 = FALSE; + settings->ClientAutoReconnectCookie = (ARC_CS_PRIVATE_PACKET*) malloc(sizeof(ARC_CS_PRIVATE_PACKET)); settings->ServerAutoReconnectCookie = (ARC_SC_PRIVATE_PACKET*) malloc(sizeof(ARC_SC_PRIVATE_PACKET)); ZeroMemory(settings->ClientAutoReconnectCookie, sizeof(ARC_CS_PRIVATE_PACKET)); @@ -440,11 +454,11 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) UINT32 index; rdpSettings* _settings; - _settings = (rdpSettings*) malloc(sizeof(rdpSettings)); + _settings = (rdpSettings*) calloc(1, sizeof(rdpSettings)); if (_settings) { - ZeroMemory(_settings, sizeof(rdpSettings)); + CopyMemory(_settings, settings, sizeof(rdpSettings)); /** * Generated Code @@ -457,13 +471,17 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->Password = _strdup(settings->Password); /* 22 */ _settings->Domain = _strdup(settings->Domain); /* 23 */ _settings->PasswordHash = _strdup(settings->PasswordHash); /* 24 */ - //_settings->ClientHostname = _strdup(settings->ClientHostname); /* 134 */ - //_settings->ClientProductId = _strdup(settings->ClientProductId); /* 135 */ + _settings->ClientHostname = NULL; /* 134 */ + _settings->ClientProductId = NULL; /* 135 */ _settings->AlternateShell = _strdup(settings->AlternateShell); /* 640 */ _settings->ShellWorkingDirectory = _strdup(settings->ShellWorkingDirectory); /* 641 */ _settings->ClientAddress = _strdup(settings->ClientAddress); /* 769 */ _settings->ClientDir = _strdup(settings->ClientDir); /* 770 */ _settings->DynamicDSTTimeZoneKeyName = _strdup(settings->DynamicDSTTimeZoneKeyName); /* 897 */ + _settings->RemoteAssistanceSessionId = _strdup(settings->RemoteAssistanceSessionId); /* 1025 */ + _settings->RemoteAssistancePassStub = _strdup(settings->RemoteAssistancePassStub); /* 1026 */ + _settings->RemoteAssistancePassword = _strdup(settings->RemoteAssistancePassword); /* 1027 */ + _settings->RemoteAssistanceRCTicket = _strdup(settings->RemoteAssistanceRCTicket); /* 1028 */ _settings->AuthenticationServiceClass = _strdup(settings->AuthenticationServiceClass); /* 1098 */ _settings->PreconnectionBlob = _strdup(settings->PreconnectionBlob); /* 1155 */ _settings->KerberosKdc = _strdup(settings->KerberosKdc); /* 1344 */ @@ -476,6 +494,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->WmClass = _strdup(settings->WmClass); /* 1549 */ _settings->ComputerName = _strdup(settings->ComputerName); /* 1664 */ _settings->ConnectionFile = _strdup(settings->ConnectionFile); /* 1728 */ + _settings->AssistanceFile = _strdup(settings->AssistanceFile); /* 1729 */ _settings->HomePath = _strdup(settings->HomePath); /* 1792 */ _settings->ConfigPath = _strdup(settings->ConfigPath); /* 1793 */ _settings->CurrentPath = _strdup(settings->CurrentPath); /* 1794 */ @@ -494,219 +513,32 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->ImeFileName = _strdup(settings->ImeFileName); /* 2628 */ _settings->DrivesToRedirect = _strdup(settings->DrivesToRedirect); /* 4290 */ - /* UINT32 values */ - - _settings->ShareId = settings->ShareId; /* 17 */ - _settings->PduSource = settings->PduSource; /* 18 */ - _settings->ServerPort = settings->ServerPort; /* 19 */ - _settings->RdpVersion = settings->RdpVersion; /* 128 */ - _settings->DesktopWidth = settings->DesktopWidth; /* 129 */ - _settings->DesktopHeight = settings->DesktopHeight; /* 130 */ - _settings->ColorDepth = settings->ColorDepth; /* 131 */ - _settings->ConnectionType = settings->ConnectionType; /* 132 */ - _settings->ClientBuild = settings->ClientBuild; /* 133 */ - _settings->EarlyCapabilityFlags = settings->EarlyCapabilityFlags; /* 136 */ - _settings->EncryptionMethods = settings->EncryptionMethods; /* 193 */ - _settings->ExtEncryptionMethods = settings->ExtEncryptionMethods; /* 194 */ - _settings->EncryptionLevel = settings->EncryptionLevel; /* 195 */ - _settings->ServerRandomLength = settings->ServerRandomLength; /* 197 */ - _settings->ServerCertificateLength = settings->ServerCertificateLength; /* 199 */ - _settings->ChannelCount = settings->ChannelCount; /* 256 */ - _settings->ChannelDefArraySize = settings->ChannelDefArraySize; /* 257 */ - _settings->ClusterInfoFlags = settings->ClusterInfoFlags; /* 320 */ - _settings->RedirectedSessionId = settings->RedirectedSessionId; /* 321 */ - _settings->MonitorDefArraySize = settings->MonitorDefArraySize; /* 385 */ - _settings->DesktopPosX = settings->DesktopPosX; /* 390 */ - _settings->DesktopPosY = settings->DesktopPosY; /* 391 */ - _settings->NumMonitorIds = settings->NumMonitorIds; /* 394 */ - _settings->MultitransportFlags = settings->MultitransportFlags; /* 512 */ - _settings->CompressionLevel = settings->CompressionLevel; /* 721 */ - _settings->AutoReconnectMaxRetries = settings->AutoReconnectMaxRetries; /* 833 */ - _settings->PerformanceFlags = settings->PerformanceFlags; /* 960 */ - _settings->RequestedProtocols = settings->RequestedProtocols; /* 1093 */ - _settings->SelectedProtocol = settings->SelectedProtocol; /* 1094 */ - _settings->NegotiationFlags = settings->NegotiationFlags; /* 1095 */ - _settings->CookieMaxLength = settings->CookieMaxLength; /* 1153 */ - _settings->PreconnectionId = settings->PreconnectionId; /* 1154 */ - _settings->RedirectionFlags = settings->RedirectionFlags; /* 1216 */ - _settings->LoadBalanceInfoLength = settings->LoadBalanceInfoLength; /* 1218 */ - _settings->RedirectionPasswordLength = settings->RedirectionPasswordLength; /* 1224 */ - _settings->RedirectionTsvUrlLength = settings->RedirectionTsvUrlLength; /* 1230 */ - _settings->TargetNetAddressCount = settings->TargetNetAddressCount; /* 1231 */ - _settings->Password51Length = settings->Password51Length; /* 1281 */ - _settings->PercentScreen = settings->PercentScreen; /* 1538 */ - _settings->GatewayUsageMethod = settings->GatewayUsageMethod; /* 1984 */ - _settings->GatewayPort = settings->GatewayPort; /* 1985 */ - _settings->GatewayCredentialsSource = settings->GatewayCredentialsSource; /* 1990 */ - _settings->RemoteApplicationExpandCmdLine = settings->RemoteApplicationExpandCmdLine; /* 2119 */ - _settings->RemoteApplicationExpandWorkingDir = settings->RemoteApplicationExpandWorkingDir; /* 2120 */ - _settings->RemoteAppNumIconCaches = settings->RemoteAppNumIconCaches; /* 2122 */ - _settings->RemoteAppNumIconCacheEntries = settings->RemoteAppNumIconCacheEntries; /* 2123 */ - _settings->ReceivedCapabilitiesSize = settings->ReceivedCapabilitiesSize; /* 2241 */ - _settings->OsMajorType = settings->OsMajorType; /* 2304 */ - _settings->OsMinorType = settings->OsMinorType; /* 2305 */ - _settings->BitmapCacheVersion = settings->BitmapCacheVersion; /* 2498 */ - _settings->BitmapCacheV2NumCells = settings->BitmapCacheV2NumCells; /* 2501 */ - _settings->PointerCacheSize = settings->PointerCacheSize; /* 2561 */ - _settings->KeyboardLayout = settings->KeyboardLayout; /* 2624 */ - _settings->KeyboardType = settings->KeyboardType; /* 2625 */ - _settings->KeyboardSubType = settings->KeyboardSubType; /* 2626 */ - _settings->KeyboardFunctionKey = settings->KeyboardFunctionKey; /* 2627 */ - _settings->BrushSupportLevel = settings->BrushSupportLevel; /* 2688 */ - _settings->GlyphSupportLevel = settings->GlyphSupportLevel; /* 2752 */ - _settings->OffscreenSupportLevel = settings->OffscreenSupportLevel; /* 2816 */ - _settings->OffscreenCacheSize = settings->OffscreenCacheSize; /* 2817 */ - _settings->OffscreenCacheEntries = settings->OffscreenCacheEntries; /* 2818 */ - _settings->VirtualChannelCompressionFlags = settings->VirtualChannelCompressionFlags; /* 2880 */ - _settings->VirtualChannelChunkSize = settings->VirtualChannelChunkSize; /* 2881 */ - _settings->MultifragMaxRequestSize = settings->MultifragMaxRequestSize; /* 3328 */ - _settings->LargePointerFlag = settings->LargePointerFlag; /* 3392 */ - _settings->CompDeskSupportLevel = settings->CompDeskSupportLevel; /* 3456 */ - _settings->RemoteFxCodecId = settings->RemoteFxCodecId; /* 3650 */ - _settings->RemoteFxCodecMode = settings->RemoteFxCodecMode; /* 3651 */ - _settings->RemoteFxCaptureFlags = settings->RemoteFxCaptureFlags; /* 3653 */ - _settings->NSCodecId = settings->NSCodecId; /* 3713 */ - _settings->FrameAcknowledge = settings->FrameAcknowledge; /* 3714 */ - _settings->JpegCodecId = settings->JpegCodecId; /* 3777 */ - _settings->JpegQuality = settings->JpegQuality; /* 3778 */ - _settings->BitmapCacheV3CodecId = settings->BitmapCacheV3CodecId; /* 3904 */ - _settings->DrawNineGridCacheSize = settings->DrawNineGridCacheSize; /* 3969 */ - _settings->DrawNineGridCacheEntries = settings->DrawNineGridCacheEntries; /* 3970 */ - _settings->DeviceCount = settings->DeviceCount; /* 4161 */ - _settings->DeviceArraySize = settings->DeviceArraySize; /* 4162 */ - _settings->StaticChannelCount = settings->StaticChannelCount; /* 4928 */ - _settings->StaticChannelArraySize = settings->StaticChannelArraySize; /* 4929 */ - _settings->DynamicChannelCount = settings->DynamicChannelCount; /* 5056 */ - _settings->DynamicChannelArraySize = settings->DynamicChannelArraySize; /* 5057 */ - - /* BOOL values */ - - _settings->ServerMode = settings->ServerMode; /* 16 */ - _settings->WaitForOutputBufferFlush = settings->WaitForOutputBufferFlush; /* 25 */ - _settings->NetworkAutoDetect = settings->NetworkAutoDetect; /* 137 */ - _settings->SupportAsymetricKeys = settings->SupportAsymetricKeys; /* 138 */ - _settings->SupportErrorInfoPdu = settings->SupportErrorInfoPdu; /* 139 */ - _settings->SupportStatusInfoPdu = settings->SupportStatusInfoPdu; /* 140 */ - _settings->SupportMonitorLayoutPdu = settings->SupportMonitorLayoutPdu; /* 141 */ - _settings->SupportGraphicsPipeline = settings->SupportGraphicsPipeline; /* 142 */ - _settings->SupportDynamicTimeZone = settings->SupportDynamicTimeZone; /* 143 */ - _settings->DisableEncryption = settings->DisableEncryption; /* 192 */ - _settings->ConsoleSession = settings->ConsoleSession; /* 322 */ - _settings->SpanMonitors = settings->SpanMonitors; /* 387 */ - _settings->UseMultimon = settings->UseMultimon; /* 388 */ - _settings->ForceMultimon = settings->ForceMultimon; /* 389 */ - _settings->ListMonitors = settings->ListMonitors; /* 392 */ - _settings->AutoLogonEnabled = settings->AutoLogonEnabled; /* 704 */ - _settings->CompressionEnabled = settings->CompressionEnabled; /* 705 */ - _settings->DisableCtrlAltDel = settings->DisableCtrlAltDel; /* 706 */ - _settings->EnableWindowsKey = settings->EnableWindowsKey; /* 707 */ - _settings->MaximizeShell = settings->MaximizeShell; /* 708 */ - _settings->LogonNotify = settings->LogonNotify; /* 709 */ - _settings->LogonErrors = settings->LogonErrors; /* 710 */ - _settings->MouseAttached = settings->MouseAttached; /* 711 */ - _settings->MouseHasWheel = settings->MouseHasWheel; /* 712 */ - _settings->RemoteConsoleAudio = settings->RemoteConsoleAudio; /* 713 */ - _settings->AudioPlayback = settings->AudioPlayback; /* 714 */ - _settings->AudioCapture = settings->AudioCapture; /* 715 */ - _settings->VideoDisable = settings->VideoDisable; /* 716 */ - _settings->PasswordIsSmartcardPin = settings->PasswordIsSmartcardPin; /* 717 */ - _settings->UsingSavedCredentials = settings->UsingSavedCredentials; /* 718 */ - _settings->ForceEncryptedCsPdu = settings->ForceEncryptedCsPdu; /* 719 */ - _settings->HiDefRemoteApp = settings->HiDefRemoteApp; /* 720 */ - _settings->IPv6Enabled = settings->IPv6Enabled; /* 768 */ - _settings->AutoReconnectionEnabled = settings->AutoReconnectionEnabled; /* 832 */ - _settings->DynamicDaylightTimeDisabled = settings->DynamicDaylightTimeDisabled; /* 898 */ - _settings->AllowFontSmoothing = settings->AllowFontSmoothing; /* 961 */ - _settings->DisableWallpaper = settings->DisableWallpaper; /* 962 */ - _settings->DisableFullWindowDrag = settings->DisableFullWindowDrag; /* 963 */ - _settings->DisableMenuAnims = settings->DisableMenuAnims; /* 964 */ - _settings->DisableThemes = settings->DisableThemes; /* 965 */ - _settings->DisableCursorShadow = settings->DisableCursorShadow; /* 966 */ - _settings->DisableCursorBlinking = settings->DisableCursorBlinking; /* 967 */ - _settings->AllowDesktopComposition = settings->AllowDesktopComposition; /* 968 */ - _settings->TlsSecurity = settings->TlsSecurity; /* 1088 */ - _settings->NlaSecurity = settings->NlaSecurity; /* 1089 */ - _settings->RdpSecurity = settings->RdpSecurity; /* 1090 */ - _settings->ExtSecurity = settings->ExtSecurity; /* 1091 */ - _settings->Authentication = settings->Authentication; /* 1092 */ - _settings->NegotiateSecurityLayer = settings->NegotiateSecurityLayer; /* 1096 */ - _settings->RestrictedAdminModeRequired = settings->RestrictedAdminModeRequired; /* 1097 */ - _settings->DisableCredentialsDelegation = settings->DisableCredentialsDelegation; /* 1099 */ - _settings->AuthenticationLevel = settings->AuthenticationLevel; /* 1100 */ - _settings->MstscCookieMode = settings->MstscCookieMode; /* 1152 */ - _settings->SendPreconnectionPdu = settings->SendPreconnectionPdu; /* 1156 */ - _settings->IgnoreCertificate = settings->IgnoreCertificate; /* 1408 */ - _settings->ExternalCertificateManagement = settings->ExternalCertificateManagement; /* 1415 */ - _settings->Workarea = settings->Workarea; /* 1536 */ - _settings->Fullscreen = settings->Fullscreen; /* 1537 */ - _settings->GrabKeyboard = settings->GrabKeyboard; /* 1539 */ - _settings->Decorations = settings->Decorations; /* 1540 */ - _settings->MouseMotion = settings->MouseMotion; /* 1541 */ - _settings->AsyncInput = settings->AsyncInput; /* 1544 */ - _settings->AsyncUpdate = settings->AsyncUpdate; /* 1545 */ - _settings->AsyncChannels = settings->AsyncChannels; /* 1546 */ - _settings->AsyncTransport = settings->AsyncTransport; /* 1547 */ - _settings->ToggleFullscreen = settings->ToggleFullscreen; /* 1548 */ - _settings->EmbeddedWindow = settings->EmbeddedWindow; /* 1550 */ - _settings->SmartSizing = settings->SmartSizing; /* 1551 */ - _settings->SoftwareGdi = settings->SoftwareGdi; /* 1601 */ - _settings->LocalConnection = settings->LocalConnection; /* 1602 */ - _settings->AuthenticationOnly = settings->AuthenticationOnly; /* 1603 */ - _settings->CredentialsFromStdin = settings->CredentialsFromStdin; /* 1604 */ - _settings->DumpRemoteFx = settings->DumpRemoteFx; /* 1856 */ - _settings->PlayRemoteFx = settings->PlayRemoteFx; /* 1857 */ - _settings->GatewayUseSameCredentials = settings->GatewayUseSameCredentials; /* 1991 */ - _settings->GatewayEnabled = settings->GatewayEnabled; /* 1992 */ - _settings->GatewayBypassLocal = settings->GatewayBypassLocal; /* 1993 */ - _settings->RemoteApplicationMode = settings->RemoteApplicationMode; /* 2112 */ - _settings->DisableRemoteAppCapsCheck = settings->DisableRemoteAppCapsCheck; /* 2121 */ - _settings->RemoteAppLanguageBarSupported = settings->RemoteAppLanguageBarSupported; /* 2124 */ - _settings->RefreshRect = settings->RefreshRect; /* 2306 */ - _settings->SuppressOutput = settings->SuppressOutput; /* 2307 */ - _settings->FastPathOutput = settings->FastPathOutput; /* 2308 */ - _settings->SaltedChecksum = settings->SaltedChecksum; /* 2309 */ - _settings->LongCredentialsSupported = settings->LongCredentialsSupported; /* 2310 */ - _settings->NoBitmapCompressionHeader = settings->NoBitmapCompressionHeader; /* 2311 */ - _settings->BitmapCompressionDisabled = settings->BitmapCompressionDisabled; /* 2312 */ - _settings->DesktopResize = settings->DesktopResize; /* 2368 */ - _settings->DrawAllowDynamicColorFidelity = settings->DrawAllowDynamicColorFidelity; /* 2369 */ - _settings->DrawAllowColorSubsampling = settings->DrawAllowColorSubsampling; /* 2370 */ - _settings->DrawAllowSkipAlpha = settings->DrawAllowSkipAlpha; /* 2371 */ - _settings->BitmapCacheV3Enabled = settings->BitmapCacheV3Enabled; /* 2433 */ - _settings->AltSecFrameMarkerSupport = settings->AltSecFrameMarkerSupport; /* 2434 */ - _settings->BitmapCacheEnabled = settings->BitmapCacheEnabled; /* 2497 */ - _settings->AllowCacheWaitingList = settings->AllowCacheWaitingList; /* 2499 */ - _settings->BitmapCachePersistEnabled = settings->BitmapCachePersistEnabled; /* 2500 */ - _settings->ColorPointerFlag = settings->ColorPointerFlag; /* 2560 */ - _settings->UnicodeInput = settings->UnicodeInput; /* 2629 */ - _settings->FastPathInput = settings->FastPathInput; /* 2630 */ - _settings->MultiTouchInput = settings->MultiTouchInput; /* 2631 */ - _settings->MultiTouchGestures = settings->MultiTouchGestures; /* 2632 */ - _settings->SoundBeepsEnabled = settings->SoundBeepsEnabled; /* 2944 */ - _settings->SurfaceCommandsEnabled = settings->SurfaceCommandsEnabled; /* 3520 */ - _settings->FrameMarkerCommandEnabled = settings->FrameMarkerCommandEnabled; /* 3521 */ - _settings->SurfaceFrameMarkerEnabled = settings->SurfaceFrameMarkerEnabled; /* 3522 */ - _settings->RemoteFxOnly = settings->RemoteFxOnly; /* 3648 */ - _settings->RemoteFxCodec = settings->RemoteFxCodec; /* 3649 */ - _settings->RemoteFxImageCodec = settings->RemoteFxImageCodec; /* 3652 */ - _settings->NSCodec = settings->NSCodec; /* 3712 */ - _settings->JpegCodec = settings->JpegCodec; /* 3776 */ - _settings->DrawNineGridEnabled = settings->DrawNineGridEnabled; /* 3968 */ - _settings->DrawGdiPlusEnabled = settings->DrawGdiPlusEnabled; /* 4032 */ - _settings->DrawGdiPlusCacheEnabled = settings->DrawGdiPlusCacheEnabled; /* 4033 */ - _settings->DeviceRedirection = settings->DeviceRedirection; /* 4160 */ - _settings->RedirectDrives = settings->RedirectDrives; /* 4288 */ - _settings->RedirectHomeDrive = settings->RedirectHomeDrive; /* 4289 */ - _settings->RedirectSmartCards = settings->RedirectSmartCards; /* 4416 */ - _settings->RedirectPrinters = settings->RedirectPrinters; /* 4544 */ - _settings->RedirectSerialPorts = settings->RedirectSerialPorts; /* 4672 */ - _settings->RedirectParallelPorts = settings->RedirectParallelPorts; /* 4673 */ - _settings->RedirectClipboard = settings->RedirectClipboard; /* 4800 */ - /** * Manual Code */ + _settings->LoadBalanceInfo = NULL; + _settings->LoadBalanceInfoLength = 0; + + if (settings->LoadBalanceInfo && settings->LoadBalanceInfoLength) + { + _settings->LoadBalanceInfo = (BYTE*) calloc(1, settings->LoadBalanceInfoLength + 2); + CopyMemory(_settings->LoadBalanceInfo, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength); + _settings->LoadBalanceInfoLength = settings->LoadBalanceInfoLength; + } + + if (_settings->ServerRandomLength) + { + _settings->ServerRandom = (BYTE*) malloc(_settings->ServerRandomLength); + CopyMemory(_settings->ServerRandom, settings->ServerRandom, _settings->ServerRandomLength); + } + + if (_settings->ClientRandomLength) + { + _settings->ClientRandom = (BYTE*) malloc(_settings->ClientRandomLength); + CopyMemory(_settings->ClientRandom, settings->ClientRandom, _settings->ClientRandomLength); + } + _settings->ChannelCount = settings->ChannelCount; _settings->ChannelDefArraySize = settings->ChannelDefArraySize; _settings->ChannelDefArray = (CHANNEL_DEF*) malloc(sizeof(CHANNEL_DEF) * settings->ChannelDefArraySize); @@ -808,14 +640,17 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->MonitorDefArray); free(settings->ClientAddress); free(settings->ClientDir); + free(settings->PermittedTLSCiphers); free(settings->CertificateFile); free(settings->PrivateKeyFile); + free(settings->ConnectionFile); + free(settings->AssistanceFile); free(settings->ReceivedCapabilities); free(settings->OrderSupport); free(settings->ClientHostname); free(settings->ClientProductId); free(settings->ServerRandom); - if (settings->ClientRandom) free(settings->ClientRandom); + free(settings->ClientRandom); free(settings->ServerCertificate); free(settings->RdpKeyFile); certificate_free(settings->RdpServerCertificate); @@ -837,6 +672,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->RedirectionDomain); free(settings->RedirectionPassword); free(settings->RedirectionTsvUrl); + free(settings->RemoteAssistanceSessionId); free(settings->AuthenticationServiceClass); freerdp_target_net_addresses_free(settings); freerdp_device_collection_free(settings); diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index af54e181a..f1997c3d0 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -22,9 +22,12 @@ #endif #include +#include #include "surface.h" +#define TAG FREERDP_TAG("core.surface") + static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT32* length) { int pos; @@ -40,7 +43,7 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3 Stream_Read_UINT8(s, cmd->bpp); if ((cmd->bpp < 1) || (cmd->bpp > 32)) { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, cmd->bpp); + WLog_ERR(TAG, "invalid bpp value %d", cmd->bpp); return FALSE; } @@ -60,11 +63,10 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3 *length = 20 + cmd->bitmapDataLength; WLog_Print(update->log, WLOG_DEBUG, - "SurfaceBits: destLeft: %d destTop: %d destRight: %d destBottom: %d " - "bpp: %d codecId: %d width: %d height: %d bitmapDataLength: %d", - cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, - cmd->bpp, cmd->codecID, cmd->width, cmd->height, cmd->bitmapDataLength); - + "SurfaceBits: destLeft: %d destTop: %d destRight: %d destBottom: %d " + "bpp: %d codecId: %d width: %d height: %d bitmapDataLength: %d", + cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, + cmd->bpp, cmd->codecID, cmd->width, cmd->height, cmd->bitmapDataLength); IFCALL(update->SurfaceBits, update->context, cmd); return 0; @@ -95,7 +97,7 @@ int update_recv_surfcmds(rdpUpdate* update, UINT32 size, wStream* s) { BYTE* mark; UINT16 cmdType; - UINT32 cmdLength; + UINT32 cmdLength = 0; while (size > 2) { @@ -118,7 +120,7 @@ int update_recv_surfcmds(rdpUpdate* update, UINT32 size, wStream* s) break; default: - DEBUG_WARN("unknown cmdType 0x%X", cmdType); + WLog_ERR(TAG, "unknown cmdType 0x%X", cmdType); return -1; } diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index c3276860c..faf1cecae 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -41,6 +41,13 @@ #include #include +#ifdef HAVE_POLL_H +#include +#else +#include +#include +#endif + #ifdef __FreeBSD__ #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP @@ -58,12 +65,15 @@ #endif +#include #include #include #include #include "tcp.h" +#define TAG FREERDP_TAG("core") + /* Simple Socket BIO */ static int transport_bio_simple_new(BIO* bio); @@ -115,23 +125,28 @@ static int transport_bio_simple_read(BIO* bio, char* buf, int size) BIO_clear_flags(bio, BIO_FLAGS_READ); status = _recv((SOCKET) bio->num, buf, size, 0); + if (status > 0) + return status; - if (status <= 0) + if (status == 0) { - error = WSAGetLastError(); - - if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || - (error == WSAEINPROGRESS) || (error == WSAEALREADY)) - { - BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); - } - else - { - BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); - } + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + return 0; } - return status; + error = WSAGetLastError(); + + if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || + (error == WSAEINPROGRESS) || (error == WSAEALREADY)) + { + BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); + } + else + { + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + } + + return -1; } static int transport_bio_simple_puts(BIO* bio, const char* str) @@ -264,7 +279,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) */ if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num)) { - fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num); + WLog_ERR(TAG, "an error occured when writing(toWrite=%d)", num); return -1; } @@ -320,7 +335,6 @@ static int transport_bio_buffered_read(BIO* bio, char* buf, int size) if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); - status = -1; goto out; } @@ -464,14 +478,13 @@ void tcp_get_mac_address(rdpTcp* tcp) if (ioctl(tcp->sockfd, SIOCGIFHWADDR, &if_req) != 0) { - fprintf(stderr, "failed to obtain MAC address\n"); + WLog_ERR(TAG, "failed to obtain MAC address"); return; } memmove((void*) mac, (void*) &if_req.ifr_ifru.ifru_hwaddr.sa_data[0], 6); #endif - - /* fprintf(stderr, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + /* WLog_ERR(TAG, "MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */ } @@ -485,21 +498,30 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) return FALSE; if (hostname[0] == '/') + tcp->ipcSocket = TRUE; + + if (tcp->ipcSocket) { tcp->sockfd = freerdp_uds_connect(hostname); if (tcp->sockfd < 0) return FALSE; - tcp->socketBio = BIO_new_fd(tcp->sockfd, 1); + tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) return FALSE; + + BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } else { +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set cfds; struct timeval tv; +#endif tcp->socketBio = BIO_new(BIO_s_connect()); @@ -523,27 +545,37 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) if (status <= 0) { +#ifdef HAVE_POLL_H + pollfds.fd = tcp->sockfd; + pollfds.events = POLLOUT; + pollfds.revents = 0; + do + { + status = poll(&pollfds, 1, timeout * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&cfds); FD_SET(tcp->sockfd, &cfds); tv.tv_sec = timeout; tv.tv_usec = 0; - status = select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv); - + status = _select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv); +#endif if (status == 0) { return FALSE; /* timeout */ } } - BIO_set_close(tcp->socketBio, BIO_NOCLOSE); + (void)BIO_set_close(tcp->socketBio, BIO_NOCLOSE); BIO_free(tcp->socketBio); tcp->socketBio = BIO_new(BIO_s_simple_socket()); if (!tcp->socketBio) - return -1; + return FALSE; BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE); } @@ -556,8 +588,11 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) option_value = 1; option_len = sizeof(option_value); - if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0) - fprintf(stderr, "%s: unable to set TCP_NODELAY\n", __FUNCTION__); + if (!tcp->ipcSocket) + { + if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0) + WLog_ERR(TAG, "unable to set TCP_NODELAY"); + } /* receive buffer must be a least 32 K */ if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0) @@ -569,14 +604,17 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout) if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0) { - fprintf(stderr, "%s: unable to set receive buffer len\n", __FUNCTION__); + WLog_ERR(TAG, "unable to set receive buffer len"); return FALSE; } } } - if (!tcp_set_keep_alive_mode(tcp)) - return FALSE; + if (!tcp->ipcSocket) + { + if (!tcp_set_keep_alive_mode(tcp)) + return FALSE; + } tcp->bufferedBio = BIO_new(BIO_s_buffered_socket()); @@ -606,7 +644,7 @@ BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking) if (flags == -1) { - fprintf(stderr, "%s: fcntl failed, %s.\n", __FUNCTION__, strerror(errno)); + WLog_ERR(TAG, "fcntl failed, %s.", strerror(errno)); return FALSE; } @@ -615,16 +653,31 @@ BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking) else fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK); #else - int status; - u_long arg = blocking; + /** + * ioctlsocket function: + * msdn.microsoft.com/en-ca/library/windows/desktop/ms738573/ + * + * The WSAAsyncSelect and WSAEventSelect functions automatically set a socket to nonblocking mode. + * If WSAAsyncSelect or WSAEventSelect has been issued on a socket, then any attempt to use + * ioctlsocket to set the socket back to blocking mode will fail with WSAEINVAL. + * + * To set the socket back to blocking mode, an application must first disable WSAAsyncSelect + * by calling WSAAsyncSelect with the lEvent parameter equal to zero, or disable WSAEventSelect + * by calling WSAEventSelect with the lNetworkEvents parameter equal to zero. + */ - status = ioctlsocket(tcp->sockfd, FIONBIO, &arg); + if (blocking == TRUE) + { + if (tcp->event) + WSAEventSelect(tcp->sockfd, tcp->event, 0); + } + else + { + if (!tcp->event) + tcp->event = WSACreateEvent(); - if (status != NO_ERROR) - fprintf(stderr, "ioctlsocket() failed with error: %ld\n", status); - - tcp->wsa_event = WSACreateEvent(); - WSAEventSelect(tcp->sockfd, tcp->wsa_event, FD_READ); + WSAEventSelect(tcp->sockfd, tcp->event, FD_READ); + } #endif return TRUE; @@ -641,7 +694,7 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &option_value, option_len) < 0) { - perror("setsockopt() SOL_SOCKET, SO_KEEPALIVE:"); + WLog_ERR(TAG, "setsockopt() SOL_SOCKET, SO_KEEPALIVE:"); return FALSE; } @@ -651,7 +704,7 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0) { - perror("setsockopt() IPPROTO_TCP, TCP_KEEPIDLE:"); + WLog_ERR(TAG, "setsockopt() IPPROTO_TCP, TCP_KEEPIDLE:"); return FALSE; } #endif @@ -662,7 +715,7 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPCNT, (void *) &option_value, option_len) < 0) { - perror("setsockopt() SOL_TCP, TCP_KEEPCNT:"); + WLog_ERR(TAG, "setsockopt() SOL_TCP, TCP_KEEPCNT:"); return FALSE; } #endif @@ -673,7 +726,7 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) if (setsockopt(tcp->sockfd, SOL_TCP, TCP_KEEPINTVL, (void *) &option_value, option_len) < 0) { - perror("setsockopt() SOL_TCP, TCP_KEEPINTVL:"); + WLog_ERR(TAG, "setsockopt() SOL_TCP, TCP_KEEPINTVL:"); return FALSE; } #endif @@ -684,7 +737,7 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) option_len = sizeof(option_value); if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &option_value, option_len) < 0) { - perror("setsockopt() SOL_SOCKET, SO_NOSIGPIPE:"); + WLog_ERR(TAG, "setsockopt() SOL_SOCKET, SO_NOSIGPIPE:"); } #endif return TRUE; @@ -732,11 +785,83 @@ HANDLE tcp_get_event_handle(rdpTcp* tcp) if (!tcp) return NULL; -#ifndef _WIN32 return tcp->event; +} + +int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds) +{ + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollset; + + pollset.fd = tcp->sockfd; + pollset.events = POLLIN; + pollset.revents = 0; + + do + { + status = poll(&pollset, 1, dwMilliSeconds); + } + while ((status < 0) && (errno == EINTR)); #else - return (HANDLE) tcp->wsa_event; + struct timeval tv; + fd_set rset; + + FD_ZERO(&rset); + FD_SET(tcp->sockfd, &rset); + + if (dwMilliSeconds) + { + tv.tv_sec = dwMilliSeconds / 1000; + tv.tv_usec = (dwMilliSeconds % 1000) * 1000; + } + + do + { + status = select(tcp->sockfd + 1, &rset, NULL, NULL, dwMilliSeconds ? &tv : NULL); + } + while ((status < 0) && (errno == EINTR)); #endif + return status; +} + +int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds) +{ + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollset; + + pollset.fd = tcp->sockfd; + pollset.events = POLLOUT; + pollset.revents = 0; + + do + { + status = poll(&pollset, 1, dwMilliSeconds); + } + while ((status < 0) && (errno == EINTR)); +#else + struct timeval tv; + fd_set rset; + + FD_ZERO(&rset); + FD_SET(tcp->sockfd, &rset); + + if (dwMilliSeconds) + { + tv.tv_sec = dwMilliSeconds / 1000; + tv.tv_usec = (dwMilliSeconds % 1000) * 1000; + } + + do + { + status = select(tcp->sockfd + 1, NULL, &rset, NULL, dwMilliSeconds ? &tv : NULL); + } + while ((status < 0) && (errno == EINTR)); +#endif + return status; } rdpTcp* tcp_new(rdpSettings* settings) diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 8998f3856..bfb0f8d00 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -46,12 +46,10 @@ typedef struct rdp_tcp rdpTcp; struct rdp_tcp { int sockfd; + BOOL ipcSocket; char ip_address[32]; BYTE mac_address[6]; rdpSettings* settings; -#ifdef _WIN32 - WSAEVENT wsa_event; -#endif BIO* socketBio; BIO* bufferedBio; RingBuffer xmitBuffer; @@ -64,8 +62,8 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout); BOOL tcp_disconnect(rdpTcp* tcp); int tcp_read(rdpTcp* tcp, BYTE* data, int length); int tcp_write(rdpTcp* tcp, BYTE* data, int length); -int tcp_wait_read(rdpTcp* tcp); -int tcp_wait_write(rdpTcp* tcp); +int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds); +int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds); BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking); BOOL tcp_set_keep_alive_mode(rdpTcp* tcp); int tcp_attach(rdpTcp* tcp, int sockfd); diff --git a/libfreerdp/core/timezone.h b/libfreerdp/core/timezone.h index 076a4bed5..a45cd4437 100644 --- a/libfreerdp/core/timezone.h +++ b/libfreerdp/core/timezone.h @@ -26,6 +26,7 @@ #include "config.h" #endif +#include #include #include @@ -37,10 +38,11 @@ void rdp_get_client_time_zone(wStream* s, rdpSettings* settings); BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings); void rdp_write_client_time_zone(wStream* s, rdpSettings* settings); +#define TIMEZONE_TAG FREERDP_TAG("core.timezone") #ifdef WITH_DEBUG_TIMEZONE -#define DEBUG_TIMEZONE(fmt, ...) DEBUG_CLASS(TIMEZONE, fmt, ## __VA_ARGS__) +#define DEBUG_TIMEZONE(fmt, ...) WLog_DBG(TIMEZONE_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_TIMEZONE(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_TIMEZONE(fmt, ...) do { } while (0) #endif #endif /* __TIMEZONE_H */ diff --git a/libfreerdp/core/tpdu.c b/libfreerdp/core/tpdu.c index e9b3ba35b..441b0906d 100644 --- a/libfreerdp/core/tpdu.c +++ b/libfreerdp/core/tpdu.c @@ -24,8 +24,12 @@ #include #include +#include + #include "tpdu.h" +#define TAG FREERDP_TAG("core") + /** * TPDUs are defined in: * @@ -130,7 +134,7 @@ BOOL tpdu_read_connection_request(wStream* s, BYTE* li) if (code != X224_TPDU_CONNECTION_REQUEST) { - fprintf(stderr, "Error: expected X224_TPDU_CONNECTION_REQUEST\n"); + WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST"); return FALSE; } @@ -157,17 +161,30 @@ void tpdu_write_connection_request(wStream* s, UINT16 length) BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li) { BYTE code; + int position; + int bytes_read = 0; + + /* save the position to determine the number of bytes read */ + position = Stream_GetPosition(s); if (!tpdu_read_header(s, &code, li)) return FALSE; if (code != X224_TPDU_CONNECTION_CONFIRM) { - fprintf(stderr, "Error: expected X224_TPDU_CONNECTION_CONFIRM\n"); + WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM"); return FALSE; } + /* + * To ensure that there are enough bytes remaining for processing + * check against the length indicator (li). Already read bytes need + * to be taken into account. + * The -1 is because li was read but isn't included in the TPDU size. + * For reference see ITU-T Rec. X.224 - 13.2.1 + */ + bytes_read = (Stream_GetPosition(s) - position) - 1; - return (Stream_GetRemainingLength(s) >= *li); + return (Stream_GetRemainingLength(s) >= (size_t) (*li - bytes_read)); } /** diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index b65294292..7fc8d6122 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -43,9 +44,7 @@ #ifndef _WIN32 #include #include -#include -#include -#endif +#endif /* _WIN32 */ #ifdef HAVE_VALGRIND_MEMCHECK_H #include @@ -56,6 +55,7 @@ #include "transport.h" #include "rdp.h" +#define TAG FREERDP_TAG("core.transport") #define BUFFER_SIZE 16384 @@ -64,12 +64,9 @@ static void* transport_client_thread(void* arg); wStream* transport_send_stream_init(rdpTransport* transport, int size) { wStream* s; - s = StreamPool_Take(transport->ReceivePool, size); - Stream_EnsureCapacity(s, size); Stream_SetPosition(s, 0); - return s; } @@ -89,10 +86,8 @@ void transport_stop(rdpTransport* transport) { SetEvent(transport->stopEvent); WaitForSingleObject(transport->thread, INFINITE); - CloseHandle(transport->thread); CloseHandle(transport->stopEvent); - transport->thread = NULL; transport->stopEvent = NULL; } @@ -107,9 +102,7 @@ BOOL transport_disconnect(rdpTransport* transport) return FALSE; transport_stop(transport); - BIO_free_all(transport->frontBio); - transport->frontBio = 0; return status; } @@ -117,7 +110,6 @@ BOOL transport_disconnect(rdpTransport* transport) BOOL transport_connect_rdp(rdpTransport* transport) { /* RDP encryption */ - return TRUE; } @@ -130,11 +122,8 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num) { int status; rdpTsg* tsg; - tsg = (rdpTsg*) bio->ptr; - BIO_clear_flags(bio, BIO_FLAGS_WRITE); - status = tsg_write(tsg, (BYTE*) buf, num); if (status < 0) @@ -153,11 +142,8 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size) { int status; rdpTsg* tsg; - tsg = (rdpTsg*) bio->ptr; - BIO_clear_flags(bio, BIO_FLAGS_READ); - status = tsg_read(bio->ptr, (BYTE*) buf, size); if (status < 0) @@ -229,13 +215,12 @@ BIO_METHOD* BIO_s_tsg(void) BOOL transport_connect_tls(rdpTransport* transport) { - rdpSettings *settings = transport->settings; - rdpTls *targetTls; - BIO *targetBio; + rdpSettings* settings = transport->settings; + rdpTls* targetTls; + BIO* targetBio; int tls_status; freerdp* instance; rdpContext* context; - instance = (freerdp*) transport->settings->instance; context = instance->context; @@ -243,7 +228,6 @@ BOOL transport_connect_tls(rdpTransport* transport) { transport->TsgTls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TSG_TLS; - targetTls = transport->TsgTls; targetBio = transport->frontBio; } @@ -257,11 +241,9 @@ BOOL transport_connect_tls(rdpTransport* transport) targetTls = transport->TlsIn; targetBio = transport->TcpIn->bufferedBio; - transport->layer = TRANSPORT_LAYER_TLS; } - targetTls->hostname = settings->ServerHostname; targetTls->port = settings->ServerPort; @@ -269,7 +251,6 @@ BOOL transport_connect_tls(rdpTransport* transport) targetTls->port = 3389; targetTls->isGatewayTransport = FALSE; - tls_status = tls_connect(targetTls, targetBio); if (tls_status < 1) @@ -292,9 +273,10 @@ BOOL transport_connect_tls(rdpTransport* transport) } transport->frontBio = targetTls->bio; + if (!transport->frontBio) { - fprintf(stderr, "%s: unable to prepend a filtering TLS bio", __FUNCTION__); + WLog_ERR(TAG, "unable to prepend a filtering TLS bio"); return FALSE; } @@ -305,8 +287,7 @@ BOOL transport_connect_nla(rdpTransport* transport) { freerdp* instance; rdpSettings* settings; - rdpCredssp *credSsp; - + rdpCredssp* credSsp; settings = transport->settings; instance = (freerdp*) settings->instance; @@ -321,6 +302,7 @@ BOOL transport_connect_nla(rdpTransport* transport) if (!transport->credssp) { transport->credssp = credssp_new(instance, transport, settings); + if (!transport->credssp) return FALSE; @@ -330,12 +312,14 @@ BOOL transport_connect_nla(rdpTransport* transport) { transport->credssp->ServicePrincipalName = credssp_make_spn(settings->AuthenticationServiceClass, settings->ServerHostname); + if (!transport->credssp->ServicePrincipalName) return FALSE; } } credSsp = transport->credssp; + if (credssp_authenticate(credSsp) < 0) { if (!connectErrorCode) @@ -346,20 +330,17 @@ BOOL transport_connect_nla(rdpTransport* transport) freerdp_set_last_error(instance->context, FREERDP_ERROR_AUTHENTICATION_FAILED); } - fprintf(stderr, "Authentication failure, check credentials.\n" - "If credentials are valid, the NTLMSSP implementation may be to blame.\n"); - + WLog_ERR(TAG, "Authentication failure, check credentials." + "If credentials are valid, the NTLMSSP implementation may be to blame."); transport_set_nla_mode(transport, FALSE); credssp_free(credSsp); transport->credssp = NULL; - return FALSE; } transport_set_nla_mode(transport, FALSE); credssp_free(credSsp); transport->credssp = NULL; - return TRUE; } @@ -369,11 +350,9 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 int tls_status; freerdp* instance; rdpContext* context; - rdpSettings *settings = transport->settings; - + rdpSettings* settings = transport->settings; instance = (freerdp*) transport->settings->instance; context = instance->context; - tsg = tsg_new(transport); if (!tsg) @@ -405,9 +384,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname; transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort; - transport->TlsIn->isGatewayTransport = TRUE; - tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio); if (tls_status < 1) @@ -427,7 +404,6 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 } transport->TlsOut->isGatewayTransport = TRUE; - tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio); if (tls_status < 1) @@ -451,7 +427,6 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 transport->frontBio = BIO_new(BIO_s_tsg()); transport->frontBio->ptr = tsg; - return TRUE; } @@ -459,7 +434,6 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por { BOOL status = FALSE; rdpSettings* settings = transport->settings; - transport->async = settings->AsyncTransport; if (transport->GatewayEnabled) @@ -484,7 +458,6 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por else { status = tcp_connect(transport->TcpIn, hostname, port, timeout); - transport->SplitInputOutput = FALSE; transport->TcpOut = transport->TcpIn; transport->frontBio = transport->TcpIn->bufferedBio; @@ -495,9 +468,8 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por if (transport->async) { transport->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - transport->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) transport_client_thread, transport, 0, NULL); + (LPTHREAD_START_ROUTINE) transport_client_thread, transport, 0, NULL); } } @@ -507,7 +479,6 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por BOOL transport_accept_rdp(rdpTransport* transport) { /* RDP encryption */ - return TRUE; } @@ -532,7 +503,6 @@ BOOL transport_accept_nla(rdpTransport* transport) { freerdp* instance; rdpSettings* settings; - settings = transport->settings; instance = (freerdp*) settings->instance; @@ -546,6 +516,7 @@ BOOL transport_accept_nla(rdpTransport* transport) if (!tls_accept(transport->TlsIn, transport->TcpIn->bufferedBio, settings->CertificateFile, settings->PrivateKeyFile)) return FALSE; + transport->frontBio = transport->TlsIn->bio; /* Network Level Authentication */ @@ -561,150 +532,52 @@ BOOL transport_accept_nla(rdpTransport* transport) if (credssp_authenticate(transport->credssp) < 0) { - fprintf(stderr, "client authentication failure\n"); - + WLog_ERR(TAG, "client authentication failure"); transport_set_nla_mode(transport, FALSE); credssp_free(transport->credssp); transport->credssp = NULL; - tls_set_alert_code(transport->TlsIn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED); - return FALSE; } /* don't free credssp module yet, we need to copy the credentials from it first */ transport_set_nla_mode(transport, FALSE); - return TRUE; } -BOOL nla_verify_header(wStream* s) -{ - if ((Stream_Pointer(s)[0] == 0x30) && (Stream_Pointer(s)[1] & 0x80)) - return TRUE; - - return FALSE; -} - -UINT32 nla_read_header(wStream* s) -{ - UINT32 length = 0; - - if (Stream_Pointer(s)[1] & 0x80) - { - if ((Stream_Pointer(s)[1] & ~(0x80)) == 1) - { - length = Stream_Pointer(s)[2]; - length += 3; - Stream_Seek(s, 3); - } - else if ((Stream_Pointer(s)[1] & ~(0x80)) == 2) - { - length = (Stream_Pointer(s)[2] << 8) | Stream_Pointer(s)[3]; - length += 4; - Stream_Seek(s, 4); - } - else - { - fprintf(stderr, "Error reading TSRequest!\n"); - } - } - else - { - length = Stream_Pointer(s)[1]; - length += 2; - Stream_Seek(s, 2); - } - - return length; -} - -UINT32 nla_header_length(wStream* s) -{ - UINT32 length = 0; - - if (Stream_Pointer(s)[1] & 0x80) - { - if ((Stream_Pointer(s)[1] & ~(0x80)) == 1) - length = 3; - else if ((Stream_Pointer(s)[1] & ~(0x80)) == 2) - length = 4; - else - fprintf(stderr, "Error reading TSRequest!\n"); - } - else - { - length = 2; - } - - return length; -} - static int transport_wait_for_read(rdpTransport* transport) { - struct timeval tv; - fd_set rset, wset; - fd_set *rsetPtr = NULL, *wsetPtr = NULL; - rdpTcp *tcpIn; - - tcpIn = transport->TcpIn; + rdpTcp* tcpIn = transport->TcpIn; if (tcpIn->readBlocked) { - rsetPtr = &rset; - FD_ZERO(rsetPtr); - FD_SET(tcpIn->sockfd, rsetPtr); + return tcp_wait_read(tcpIn, 10); } else if (tcpIn->writeBlocked) { - wsetPtr = &wset; - FD_ZERO(wsetPtr); - FD_SET(tcpIn->sockfd, wsetPtr); + return tcp_wait_write(tcpIn, 10); } - if (!wsetPtr && !rsetPtr) - { - USleep(1000); - return 0; - } - - tv.tv_sec = 0; - tv.tv_usec = 1000; - - return select(tcpIn->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); + USleep(1000); + return 0; } static int transport_wait_for_write(rdpTransport* transport) { - struct timeval tv; - fd_set rset, wset; - fd_set *rsetPtr = NULL, *wsetPtr = NULL; - rdpTcp *tcpOut; - + rdpTcp* tcpOut; tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn; + if (tcpOut->writeBlocked) { - wsetPtr = &wset; - FD_ZERO(wsetPtr); - FD_SET(tcpOut->sockfd, wsetPtr); + return tcp_wait_write(tcpOut, 10); } else if (tcpOut->readBlocked) { - rsetPtr = &rset; - FD_ZERO(rsetPtr); - FD_SET(tcpOut->sockfd, rsetPtr); + return tcp_wait_read(tcpOut, 10); } - if (!wsetPtr && !rsetPtr) - { - USleep(1000); - return 0; - } - - tv.tv_sec = 0; - tv.tv_usec = 1000; - - return select(tcpOut->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); + USleep(1000); + return 0; } int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes) @@ -739,33 +612,69 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes) * requested bytes */ if (transport_wait_for_read(transport) < 0) { - fprintf(stderr, "%s: error when selecting for read\n", __FUNCTION__); + WLog_ERR(TAG, "error when selecting for read"); return -1; } + continue; } #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(data + read, bytes - read); #endif - read += status; } return read; } -int transport_read(rdpTransport* transport, wStream* s) + +/** + * @brief Tries to read toRead bytes from the specified transport + * + * Try to read toRead bytes from the transport to the stream. + * In case it was not possible to read toRead bytes 0 is returned. The stream is always advanced by the + * number of bytes read. + * + * The function assumes that the stream has enough capacity to hold the data. + * + * @param[in] transport rdpTransport + * @param[in] s wStream + * @param[in] toRead number of bytes to read + * @return < 0 on error; 0 if not enough data is available (non blocking mode); 1 toRead bytes read + */ +static int transport_read_layer_bytes(rdpTransport* transport, wStream* s, unsigned int toRead) +{ + int status; + status = transport_read_layer(transport, Stream_Pointer(s), toRead); + + if (status <= 0) + return status; + + Stream_Seek(s, status); + return status == toRead ? 1 : 0; +} + +/** + * @brief Try to read a complete PDU (NLA, fast-path or tpkt) from the underlying transport. + * + * If possible a complete PDU is read, in case of non blocking transport this might not succeed. + * Except in case of an error the passed stream will point to the last byte read (correct + * position). When the pdu read is completed the stream is sealed and the pointer set to 0 + * + * @param[in] transport rdpTransport + * @param[in] s wStream + * @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 number of + * bytes of the *complete* pdu read + */ +int transport_read_pdu(rdpTransport* transport, wStream* s) { int status; int position; int pduLength; - BYTE *header; - int transport_status; - + BYTE* header; position = 0; pduLength = 0; - transport_status = 0; if (!transport) return -1; @@ -773,49 +682,51 @@ int transport_read(rdpTransport* transport, wStream* s) if (!s) return -1; - /* first check if we have header */ position = Stream_GetPosition(s); + /* Make sure there is enough space for the longest header within the stream */ + Stream_EnsureCapacity(s, 4); - if (position < 4) + /* Make sure at least two bytes are read for futher processing */ + if (position < 2 && (status = transport_read_layer_bytes(transport, s, 2 - position)) != 1) { - status = transport_read_layer(transport, Stream_Buffer(s) + position, 4 - position); - - if (status < 0) - return status; - - transport_status += status; - - if ((status + position) < 4) - return transport_status; - - position += status; + /* No data available at the moment */ + return status; } header = Stream_Buffer(s); - /* if header is present, read exactly one PDU */ - if (transport->NlaMode) { + /* + * In case NlaMode is set TSRequest package(s) are expected + * 0x30 = DER encoded data with these bits set: + * bit 6 P/C constructed + * bit 5 tag number - sequence + */ if (header[0] == 0x30) { /* TSRequest (NLA) */ - if (header[1] & 0x80) { if ((header[1] & ~(0x80)) == 1) { + if ((status = transport_read_layer_bytes(transport, s, 1)) != 1) + return status; + pduLength = header[2]; pduLength += 3; } else if ((header[1] & ~(0x80)) == 2) { + if ((status = transport_read_layer_bytes(transport, s, 2)) != 1) + return status; + pduLength = (header[2] << 8) | header[3]; pduLength += 4; } else { - fprintf(stderr, "Error reading TSRequest!\n"); + WLog_ERR(TAG, "Error reading TSRequest!"); return -1; } } @@ -831,76 +742,86 @@ int transport_read(rdpTransport* transport, wStream* s) if (header[0] == 0x03) { /* TPKT header */ + if ((status = transport_read_layer_bytes(transport, s, 2)) != 1) + return status; pduLength = (header[2] << 8) | header[3]; + + /* min and max values according to ITU-T Rec. T.123 (01/2007) section 8 */ + if (pduLength < 7 || pduLength > 0xFFFF) + { + WLog_ERR(TAG, "tpkt - invalid pduLength: %d", pduLength); + return -1; + } } else { /* Fast-Path Header */ - if (header[1] & 0x80) + { + if ((status = transport_read_layer_bytes(transport, s, 1)) != 1) + return status; + pduLength = ((header[1] & 0x7F) << 8) | header[2]; + } else pduLength = header[1]; + + /* + * fast-path has 7 bits for length so the maximum size, including headers is 0x8000 + * The theoretical minimum fast-path PDU consists only of two header bytes plus one + * byte for data (e.g. fast-path input synchronize pdu) + */ + if (pduLength < 3 || pduLength > 0x8000) + { + WLog_ERR(TAG, "fast path - invalid pduLength: %d", pduLength); + return -1; + } } } - status = transport_read_layer(transport, Stream_Buffer(s) + position, pduLength - position); + Stream_EnsureCapacity(s, Stream_GetPosition(s) + pduLength); + status = transport_read_layer_bytes(transport, s, pduLength - Stream_GetPosition(s)); - if (status < 0) + if (status != 1) return status; - transport_status += status; - #ifdef WITH_DEBUG_TRANSPORT + /* dump when whole PDU is read */ - if (position + status >= pduLength) + if (Stream_GetPosition(s) >= pduLength) { - fprintf(stderr, "Local < Remote\n"); - winpr_HexDump(Stream_Buffer(s), pduLength); + WLog_DBG(TAG, "Local < Remote"); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), pduLength); } + #endif - if (position + status >= pduLength) - { + if (Stream_GetPosition(s) >= pduLength) WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), pduLength, WLOG_PACKET_INBOUND); - } - return transport_status; + Stream_SealLength(s); + Stream_SetPosition(s, 0); + return Stream_Length(s); } -static int transport_read_nonblocking(rdpTransport* transport) -{ - int status; - - status = transport_read(transport, transport->ReceiveBuffer); - - if (status <= 0) - return status; - - Stream_Seek(transport->ReceiveBuffer, status); - - return status; -} - -BOOL transport_bio_buffered_drain(BIO *bio); +BOOL transport_bio_buffered_drain(BIO* bio); int transport_write(rdpTransport* transport, wStream* s) { int length; int status = -1; - EnterCriticalSection(&(transport->WriteLock)); - length = Stream_GetPosition(s); Stream_SetPosition(s, 0); - #ifdef WITH_DEBUG_TRANSPORT + if (length > 0) { - fprintf(stderr, "Local > Remote\n"); - winpr_HexDump(Stream_Buffer(s), length); + WLog_DBG(TAG, "Local > Remote"); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); } + #endif if (length > 0) @@ -927,28 +848,29 @@ int transport_write(rdpTransport* transport, wStream* s) if (transport_wait_for_write(transport) < 0) { - fprintf(stderr, "%s: error when selecting for write\n", __FUNCTION__); + WLog_ERR(TAG, "error when selecting for write"); return -1; } + continue; } if (transport->blocking || transport->settings->WaitForOutputBufferFlush) { /* blocking transport, we must ensure the write buffer is really empty */ - rdpTcp *out = transport->TcpOut; + rdpTcp* out = transport->TcpOut; while (out->writeBlocked) { if (transport_wait_for_write(transport) < 0) { - fprintf(stderr, "%s: error when selecting for write\n", __FUNCTION__); + WLog_ERR(TAG, "error when selecting for write"); return -1; } if (!transport_bio_buffered_drain(out->bufferedBio)) { - fprintf(stderr, "%s: error when draining outputBuffer\n", __FUNCTION__); + WLog_ERR(TAG, "error when draining outputBuffer"); return -1; } } @@ -968,23 +890,22 @@ int transport_write(rdpTransport* transport, wStream* s) Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); - return status; } void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount) { void* pfd; - #ifdef _WIN32 - rfds[*rcount] = transport->TcpIn->wsa_event; + rfds[*rcount] = transport->TcpIn->event; (*rcount)++; if (transport->SplitInputOutput) { - rfds[*rcount] = transport->TcpOut->wsa_event; + rfds[*rcount] = transport->TcpOut->event; (*rcount)++; } + #else rfds[*rcount] = (void*)(long)(transport->TcpIn->sockfd); (*rcount)++; @@ -994,8 +915,8 @@ void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount) rfds[*rcount] = (void*)(long)(transport->TcpOut->sockfd); (*rcount)++; } -#endif +#endif pfd = GetEventWaitObject(transport->ReceiveEvent); if (pfd) @@ -1046,8 +967,8 @@ BOOL tranport_is_write_blocked(rdpTransport* transport) return TRUE; return transport->SplitInputOutput && - transport->TcpOut && - transport->TcpOut->writeBlocked; + transport->TcpOut && + transport->TcpOut->writeBlocked; } int tranport_drain_output_buffer(rdpTransport* transport) @@ -1059,6 +980,7 @@ int tranport_drain_output_buffer(rdpTransport* transport) { if (!transport_bio_buffered_drain(transport->TcpIn->bufferedBio)) return -1; + ret |= transport->TcpIn->writeBlocked; } @@ -1066,6 +988,7 @@ int tranport_drain_output_buffer(rdpTransport* transport) { if (!transport_bio_buffered_drain(transport->TcpOut->bufferedBio)) return -1; + ret |= transport->TcpOut->writeBlocked; } @@ -1074,9 +997,7 @@ int tranport_drain_output_buffer(rdpTransport* transport) int transport_check_fds(rdpTransport* transport) { - int pos; int status; - int length; int recv_status; wStream* received; @@ -1084,7 +1005,7 @@ int transport_check_fds(rdpTransport* transport) return -1; #ifdef _WIN32 - WSAResetEvent(transport->TcpIn->wsa_event); + WSAResetEvent(transport->TcpIn->event); #endif ResetEvent(transport->ReceiveEvent); @@ -1098,120 +1019,36 @@ int transport_check_fds(rdpTransport* transport) for (;;) { /** - * Note: transport_read_nonblocking() reads max 1 additional PDU from - * the layer. Also note that transport_read_nonblocking() is also called - * outside of this function in transport_write()! This means that when - * entering transport_check_fds it is possible that the stream position - * of transport->ReceiveBuffer position is > 0. We must process this data - * even if transport_read_nonblocking() returns 0. + * Note: transport_read_pdu tries to read one PDU from + * the transport layer. + * The ReceiveBuffer might have a position > 0 in case of a non blocking + * transport. If transport_read_pdu returns 0 the pdu couldn't be read at + * this point. * Note that transport->ReceiveBuffer is replaced after each iteration * of this loop with a fresh stream instance from a pool. */ - - if ((status = transport_read_nonblocking(transport)) < 0) + if ((status = transport_read_pdu(transport, transport->ReceiveBuffer)) <= 0) + { return status; - - if ((pos = Stream_GetPosition(transport->ReceiveBuffer)) < 2) - return 0; - - Stream_SetPosition(transport->ReceiveBuffer, 0); - length = 0; - - if (transport->NlaMode) - { - if (nla_verify_header(transport->ReceiveBuffer)) - { - /* TSRequest */ - - /* Ensure the TSRequest header is available. */ - if (pos <= 4) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - /* TSRequest header can be 2, 3 or 4 bytes long */ - length = nla_header_length(transport->ReceiveBuffer); - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = nla_read_header(transport->ReceiveBuffer); - } - } - else - { - if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */ - { - /* Ensure the TPKT header is available. */ - if (pos <= 4) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = tpkt_read_header(transport->ReceiveBuffer); - } - else /* Fast Path */ - { - /* Ensure the Fast Path header is available. */ - if (pos <= 2) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - /* Fastpath header can be two or three bytes long. */ - length = fastpath_header_length(transport->ReceiveBuffer); - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; - } - - length = fastpath_read_header(NULL, transport->ReceiveBuffer); - } - } - - if (length == 0) - { - fprintf(stderr, "transport_check_fds: protocol error, not a TPKT or Fast Path header.\n"); - winpr_HexDump(Stream_Buffer(transport->ReceiveBuffer), pos); - return -1; - } - - if (pos < length) - { - Stream_SetPosition(transport->ReceiveBuffer, pos); - return 0; /* Packet is not yet completely received. */ } received = transport->ReceiveBuffer; transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); - - Stream_SetPosition(received, length); - Stream_SealLength(received); - Stream_SetPosition(received, 0); - /** * status: * -1: error * 0: success * 1: redirection */ - recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); - - if (recv_status == 1) - { - return 1; /* session redirection */ - } Stream_Release(received); + /* session redirection or activation */ + if (recv_status == 1 || recv_status == 2) + { + return recv_status; + } + if (recv_status < 0) return -1; } @@ -1222,7 +1059,6 @@ int transport_check_fds(rdpTransport* transport) BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking) { BOOL status; - status = TRUE; transport->blocking = blocking; @@ -1262,25 +1098,19 @@ static void* transport_client_thread(void* arg) freerdp* instance; rdpContext* context; rdpTransport* transport; - transport = (rdpTransport*) arg; assert(NULL != transport); assert(NULL != transport->settings); - instance = (freerdp*) transport->settings->instance; assert(NULL != instance); - context = instance->context; assert(NULL != instance->context); - WLog_Print(transport->log, WLOG_DEBUG, "Starting transport thread"); - nCount = 0; handles[nCount++] = transport->stopEvent; handles[nCount++] = transport->connectedEvent; - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - + if (WaitForSingleObject(transport->stopEvent, 0) == WAIT_OBJECT_0) { WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); @@ -1294,9 +1124,7 @@ static void* transport_client_thread(void* arg) { nCount = 0; handles[nCount++] = transport->stopEvent; - transport_get_read_handles(transport, (HANDLE*) &handles, &nCount); - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (transport->layer == TRANSPORT_LAYER_CLOSED) @@ -1312,13 +1140,11 @@ static void* transport_client_thread(void* arg) if (!freerdp_check_fds(instance)) { - } } } WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); - ExitThread(0); return NULL; } @@ -1326,39 +1152,43 @@ static void* transport_client_thread(void* arg) rdpTransport* transport_new(rdpSettings* settings) { rdpTransport* transport; + transport = (rdpTransport*)calloc(1, sizeof(rdpTransport)); - transport = (rdpTransport *)calloc(1, sizeof(rdpTransport)); if (!transport) return NULL; WLog_Init(); - transport->log = WLog_Get("com.freerdp.core.transport"); + transport->log = WLog_Get(TAG); + if (!transport->log) goto out_free; transport->TcpIn = tcp_new(settings); + if (!transport->TcpIn) goto out_free; transport->settings = settings; - /* a small 0.1ms delay when transport is blocking. */ transport->SleepInterval = 100; - transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); + if (!transport->ReceivePool) goto out_free_tcpin; /* receive buffer for non-blocking read. */ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); + if (!transport->ReceiveBuffer) goto out_free_receivepool; transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!transport->ReceiveEvent || transport->ReceiveEvent == INVALID_HANDLE_VALUE) goto out_free_receivebuffer; transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!transport->connectedEvent || transport->connectedEvent == INVALID_HANDLE_VALUE) goto out_free_receiveEvent; @@ -1368,11 +1198,11 @@ rdpTransport* transport_new(rdpSettings* settings) if (!InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000)) goto out_free_connectedEvent; + if (!InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000)) goto out_free_readlock; return transport; - out_free_readlock: DeleteCriticalSection(&(transport->ReadLock)); out_free_connectedEvent: @@ -1401,7 +1231,6 @@ void transport_free(rdpTransport* transport) Stream_Release(transport->ReceiveBuffer); StreamPool_Free(transport->ReceivePool); - CloseHandle(transport->ReceiveEvent); CloseHandle(transport->connectedEvent); @@ -1422,12 +1251,9 @@ void transport_free(rdpTransport* transport) transport->TcpIn = NULL; transport->TcpOut = NULL; - tsg_free(transport->tsg); transport->tsg = NULL; - DeleteCriticalSection(&(transport->ReadLock)); DeleteCriticalSection(&(transport->WriteLock)); - free(transport); } diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 3a4a41753..142d350f3 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -96,7 +96,7 @@ BOOL transport_accept_rdp(rdpTransport* transport); BOOL transport_accept_tls(rdpTransport* transport); BOOL transport_accept_nla(rdpTransport* transport); void transport_stop(rdpTransport* transport); -int transport_read(rdpTransport* transport, wStream* s); +int transport_read_pdu(rdpTransport* transport, wStream* s); int transport_write(rdpTransport* transport, wStream* s); void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount); int transport_check_fds(rdpTransport* transport); diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 6a243aad0..5039e29b7 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -31,9 +31,12 @@ #include "surface.h" #include "message.h" +#include #include #include +#define TAG FREERDP_TAG("core.update") + const char* const UPDATE_TYPE_STRINGS[] = { "Orders", @@ -164,6 +167,8 @@ BOOL update_read_bitmap_update(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bit Stream_Read_UINT16(s, bitmapUpdate->number); /* numberRectangles (2 bytes) */ + WLog_Print(update->log, WLOG_DEBUG, "BitmapUpdate: %d", bitmapUpdate->number); + if (bitmapUpdate->number > bitmapUpdate->count) { UINT16 count; @@ -230,9 +235,9 @@ BOOL update_read_palette(rdpUpdate* update, wStream* s, PALETTE_UPDATE* palette_ { entry = &palette_update->entries[i]; - Stream_Read_UINT8(s, entry->blue); - Stream_Read_UINT8(s, entry->green); Stream_Read_UINT8(s, entry->red); + Stream_Read_UINT8(s, entry->green); + Stream_Read_UINT8(s, entry->blue); } return TRUE; } @@ -346,9 +351,9 @@ BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color, scanlineSize = ((scanlineSize + 1) / 2) * 2; if (scanlineSize * pointer_color->height != pointer_color->lengthXorMask) { - fprintf(stderr, "%s: invalid lengthXorMask: width=%d height=%d, %d instead of %d\n", __FUNCTION__, - pointer_color->width, pointer_color->height, - pointer_color->lengthXorMask, scanlineSize * pointer_color->height); + WLog_ERR(TAG, "invalid lengthXorMask: width=%d height=%d, %d instead of %d", + pointer_color->width, pointer_color->height, + pointer_color->lengthXorMask, scanlineSize * pointer_color->height); return FALSE; } @@ -377,8 +382,8 @@ BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color, scanlineSize = ((1 + scanlineSize) / 2) * 2; if (scanlineSize * pointer_color->height != pointer_color->lengthAndMask) { - fprintf(stderr, "%s: invalid lengthAndMask: %d instead of %d\n", __FUNCTION__, - pointer_color->lengthAndMask, scanlineSize * pointer_color->height); + WLog_ERR(TAG, "invalid lengthAndMask: %d instead of %d", + pointer_color->lengthAndMask, scanlineSize * pointer_color->height); return FALSE; } @@ -405,7 +410,7 @@ BOOL update_read_pointer_new(wStream* s, POINTER_NEW_UPDATE* pointer_new) Stream_Read_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */ if ((pointer_new->xorBpp < 1) || (pointer_new->xorBpp > 32)) { - fprintf(stderr, "%s: invalid xorBpp %d\n", __FUNCTION__, pointer_new->xorBpp); + WLog_ERR(TAG, "invalid xorBpp %d", pointer_new->xorBpp); return FALSE; } return update_read_pointer_color(s, &pointer_new->colorPtrAttr, pointer_new->xorBpp); /* colorPtrAttr */ @@ -479,8 +484,7 @@ BOOL update_recv(rdpUpdate* update, wStream* s) return FALSE; Stream_Read_UINT16(s, updateType); /* updateType (2 bytes) */ - - //printf("%s Update Data PDU\n", UPDATE_TYPE_STRINGS[updateType]); + //WLog_DBG(TAG, "%s Update Data PDU", UPDATE_TYPE_STRINGS[updateType]); IFCALL(update->BeginPaint, context); @@ -568,6 +572,14 @@ void update_post_connect(rdpUpdate* update) update->initialState = FALSE; } +void update_post_disconnect(rdpUpdate* update) +{ + update->asynchronous = update->context->settings->AsyncUpdate; + + if (update->asynchronous) + update_message_proxy_free(update->proxy); +} + static void update_begin_paint(rdpContext* context) { wStream* s; @@ -604,7 +616,7 @@ static void update_end_paint(rdpContext* context) if (update->numberOrders > 0) { - fprintf(stderr, "%s: sending %d orders\n", __FUNCTION__, update->numberOrders); + WLog_ERR(TAG, "sending %d orders", update->numberOrders); fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s); } @@ -855,7 +867,7 @@ static void update_send_surface_command(rdpContext* context, wStream* s) Stream_Release(update); } -static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) +static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surfaceBitsCommand) { wStream* s; rdpRdp* rdp = context->rdp; @@ -863,9 +875,9 @@ static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* update_force_flush(context); s = fastpath_update_pdu_init(rdp->fastpath); - Stream_EnsureRemainingCapacity(s, SURFCMD_SURFACE_BITS_HEADER_LENGTH + (int) surface_bits_command->bitmapDataLength); - update_write_surfcmd_surface_bits_header(s, surface_bits_command); - Stream_Write(s, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + Stream_EnsureRemainingCapacity(s, SURFCMD_SURFACE_BITS_HEADER_LENGTH + (int) surfaceBitsCommand->bitmapDataLength); + update_write_surfcmd_surface_bits_header(s, surfaceBitsCommand); + Stream_Write(s, surfaceBitsCommand->bitmapData, surfaceBitsCommand->bitmapDataLength); fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); update_force_flush(context); @@ -873,7 +885,7 @@ static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* Stream_Release(s); } -static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) +static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surfaceFrameMarker) { wStream* s; rdpRdp* rdp = context->rdp; @@ -881,7 +893,34 @@ static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_ update_force_flush(context); s = fastpath_update_pdu_init(rdp->fastpath); - update_write_surfcmd_frame_marker(s, surface_frame_marker->frameAction, surface_frame_marker->frameId); + update_write_surfcmd_frame_marker(s, surfaceFrameMarker->frameAction, surfaceFrameMarker->frameId); + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); + + update_force_flush(context); + + Stream_Release(s); +} + +static void update_send_surface_frame_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd, BOOL first, BOOL last, UINT32 frameId) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + + update_force_flush(context); + + s = fastpath_update_pdu_init(rdp->fastpath); + Stream_EnsureRemainingCapacity(s, SURFCMD_SURFACE_BITS_HEADER_LENGTH + (int) cmd->bitmapDataLength + 16); + + if (first) + update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_BEGIN, frameId); + + update_write_surfcmd_surface_bits_header(s, cmd); + Stream_Write(s, cmd->bitmapData, cmd->bitmapDataLength); + + + if (last) + update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_END, frameId); + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); update_force_flush(context); @@ -936,6 +975,20 @@ static void update_send_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap Stream_Release(s); } +static void update_send_play_sound(rdpContext* context, PLAY_SOUND_UPDATE* play_sound) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + + if (!rdp->settings->ReceivedCapabilities[CAPSET_TYPE_SOUND]) { + return; + } + s = rdp_data_pdu_init(rdp); + Stream_Write_UINT32(s, play_sound->duration); + Stream_Write_UINT32(s, play_sound->frequency); + rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_PLAY_SOUND, rdp->mcs->userId); + Stream_Release(s); +} /** * Primary Drawing Orders */ @@ -1448,7 +1501,7 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT updateCode = FASTPATH_UPDATETYPE_PTR_NULL; else updateCode = FASTPATH_UPDATETYPE_PTR_DEFAULT; - + fastpath_send_update_pdu(rdp->fastpath, updateCode, s); Stream_Release(s); } @@ -1467,10 +1520,10 @@ static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer if (pointer_color->lengthXorMask > 0) Stream_Write(s, pointer_color->xorMaskData, pointer_color->lengthXorMask); - + if (pointer_color->lengthAndMask > 0) Stream_Write(s, pointer_color->andMaskData, pointer_color->lengthAndMask); - + Stream_Write_UINT8(s, 0); /* pad (1 byte) */ } @@ -1559,6 +1612,18 @@ BOOL update_read_suppress_output(rdpUpdate* update, wStream* s) return TRUE; } +static void update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + + s = rdp_data_pdu_init(rdp); + Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */ + Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */ + rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId); + Stream_Release(s); +} + void update_register_server_callbacks(rdpUpdate* update) { update->BeginPaint = update_begin_paint; @@ -1570,6 +1635,9 @@ void update_register_server_callbacks(rdpUpdate* update) update->SurfaceBits = update_send_surface_bits; update->SurfaceFrameMarker = update_send_surface_frame_marker; update->SurfaceCommand = update_send_surface_command; + update->SurfaceFrameBits = update_send_surface_frame_bits; + update->PlaySound = update_send_play_sound; + update->SetKeyboardIndicators = update_send_set_keyboard_indicators; update->primary->DstBlt = update_send_dstblt; update->primary->PatBlt = update_send_patblt; update->primary->ScrBlt = update_send_scrblt; @@ -1688,9 +1756,6 @@ void update_free(rdpUpdate* update) free(update->altsec); free(update->window); - if (update->asynchronous) - update_message_proxy_free(update->proxy); - MessageQueue_Free(update->queue); free(update); diff --git a/libfreerdp/core/update.h b/libfreerdp/core/update.h index c67d04fc3..c0b266f64 100644 --- a/libfreerdp/core/update.h +++ b/libfreerdp/core/update.h @@ -44,6 +44,7 @@ void update_free_bitmap(BITMAP_UPDATE* bitmap_update); void update_reset_state(rdpUpdate* update); void update_post_connect(rdpUpdate* update); +void update_post_disconnect(rdpUpdate* update); BOOL update_read_bitmap_update(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmapUpdate); BOOL update_read_palette(rdpUpdate* update, wStream* s, PALETTE_UPDATE* palette_update); diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c index 2eefe2361..c33411c24 100644 --- a/libfreerdp/core/window.c +++ b/libfreerdp/core/window.c @@ -24,22 +24,27 @@ #include +#include #include #include "window.h" +#define TAG FREERDP_TAG("core.window") + BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo) { - BYTE *newBitMask; + BYTE* newBitMask; + if (Stream_GetRemainingLength(s) < 8) return FALSE; Stream_Read_UINT16(s, iconInfo->cacheEntry); /* cacheEntry (2 bytes) */ Stream_Read_UINT8(s, iconInfo->cacheId); /* cacheId (1 byte) */ Stream_Read_UINT8(s, iconInfo->bpp); /* bpp (1 byte) */ + if ((iconInfo->bpp < 1) || (iconInfo->bpp > 32)) { - fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, iconInfo->bpp); + WLog_ERR(TAG, "invalid bpp value %d", iconInfo->bpp); return FALSE; } diff --git a/libfreerdp/core/window.h b/libfreerdp/core/window.h index b32e470ac..44084df9d 100644 --- a/libfreerdp/core/window.h +++ b/libfreerdp/core/window.h @@ -24,13 +24,15 @@ #include "update.h" #include +#include BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s); +#define WND_TAG FREERDP_TAG("core.wnd") #ifdef WITH_DEBUG_WND -#define DEBUG_WND(fmt, ...) DEBUG_CLASS(WND, fmt, ## __VA_ARGS__) +#define DEBUG_WND(fmt, ...) WLog_DBG(WND_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_WND(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_WND(fmt, ...) do { } while (0) #endif #endif /* __WINDOW_H */ diff --git a/libfreerdp/crypto/CMakeLists.txt b/libfreerdp/crypto/CMakeLists.txt index e33200bec..56dd9e99c 100644 --- a/libfreerdp/crypto/CMakeLists.txt +++ b/libfreerdp/crypto/CMakeLists.txt @@ -18,7 +18,7 @@ set(MODULE_NAME "freerdp-crypto") set(MODULE_PREFIX "FREERDP_CRYPTO") -set(${MODULE_PREFIX}_SRCS +freerdp_module_add( er.c der.c ber.c @@ -28,50 +28,17 @@ set(${MODULE_PREFIX}_SRCS crypto.c tls.c) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) +freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR}) +freerdp_include_directory_add(${ZLIB_INCLUDE_DIRS}) -include_directories(${OPENSSL_INCLUDE_DIR}) -include_directories(${ZLIB_INCLUDE_DIRS}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${OPENSSL_LIBRARIES}) - -if(MONOLITHIC_BUILD) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) -else() - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr-sspi winpr-library winpr-path winpr-file) -endif() +freerdp_library_add(${OPENSSL_LIBRARIES}) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) + freerdp_library_add(ws2_32) else() - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ZLIB_LIBRARIES}) + freerdp_library_add(${ZLIB_LIBRARIES}) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-library) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/libfreerdp/crypto/ber.c b/libfreerdp/crypto/ber.c index 74ce23190..9e54232f7 100644 --- a/libfreerdp/crypto/ber.c +++ b/libfreerdp/crypto/ber.c @@ -24,8 +24,11 @@ #include #include +#include #include +#define TAG FREERDP_TAG("crypto") + BOOL ber_read_length(wStream* s, int* length) { BYTE byte; @@ -399,12 +402,12 @@ BOOL ber_read_integer(wStream* s, UINT32* value) } else if (length == 8) { - fprintf(stderr, "%s: should implement reading an 8 bytes integer\n", __FUNCTION__); + WLog_ERR(TAG, "should implement reading an 8 bytes integer"); return FALSE; } else { - fprintf(stderr, "%s: should implement reading an integer with length=%d\n", __FUNCTION__, length); + WLog_ERR(TAG, "should implement reading an integer with length=%d", length); return FALSE; } diff --git a/libfreerdp/crypto/certificate.c b/libfreerdp/crypto/certificate.c index d65796ace..945021d7e 100644 --- a/libfreerdp/crypto/certificate.c +++ b/libfreerdp/crypto/certificate.c @@ -37,9 +37,12 @@ static const char certificate_store_dir[] = "certs"; static const char certificate_server_dir[] = "server"; static const char certificate_known_hosts_file[] = "known_hosts"; +#include #include -void certificate_store_init(rdpCertificateStore* certificate_store) +#define TAG FREERDP_TAG("crypto") + +int certificate_store_init(rdpCertificateStore* certificate_store) { char* server_path; rdpSettings* settings; @@ -49,37 +52,46 @@ void certificate_store_init(rdpCertificateStore* certificate_store) if (!PathFileExistsA(settings->ConfigPath)) { CreateDirectoryA(settings->ConfigPath, 0); - fprintf(stderr, "creating directory %s\n", settings->ConfigPath); + WLog_INFO(TAG, "creating directory %s", settings->ConfigPath); } certificate_store->path = GetCombinedPath(settings->ConfigPath, (char*) certificate_store_dir); + if (!certificate_store->path) + return -1; + if (!PathFileExistsA(certificate_store->path)) { CreateDirectoryA(certificate_store->path, 0); - fprintf(stderr, "creating directory %s\n", certificate_store->path); + WLog_INFO(TAG, "creating directory %s", certificate_store->path); } server_path = GetCombinedPath(settings->ConfigPath, (char*) certificate_server_dir); + if (!server_path) + return -1; + if (!PathFileExistsA(server_path)) { CreateDirectoryA(server_path, 0); - fprintf(stderr, "creating directory %s\n", server_path); + WLog_INFO(TAG, "creating directory %s", server_path); } free(server_path); certificate_store->file = GetCombinedPath(settings->ConfigPath, (char*) certificate_known_hosts_file); + if (!certificate_store->file) + return -1; + if (PathFileExistsA(certificate_store->file) == FALSE) { certificate_store->fp = fopen((char*) certificate_store->file, "w+"); - if (certificate_store->fp == NULL) + if (!certificate_store->fp) { - fprintf(stderr, "certificate_store_open: error opening [%s] for writing\n", certificate_store->file); - return; + WLog_ERR(TAG, "certificate_store_open: error opening [%s] for writing", certificate_store->file); + return -1; } fflush(certificate_store->fp); @@ -88,6 +100,8 @@ void certificate_store_init(rdpCertificateStore* certificate_store) { certificate_store->fp = fopen((char*) certificate_store->file, "r+"); } + + return 1; } int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) @@ -264,14 +278,14 @@ rdpCertificateStore* certificate_store_new(rdpSettings* settings) { rdpCertificateStore* certificate_store; - certificate_store = (rdpCertificateStore *)calloc(1, sizeof(rdpCertificateStore)); + certificate_store = (rdpCertificateStore*) calloc(1, sizeof(rdpCertificateStore)); if (!certificate_store) return NULL; certificate_store->settings = settings; + certificate_store_init(certificate_store); - /* TODO: certificate_store_init should not fail silently */ return certificate_store; } diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index b3d3fbb21..efbdd5aa3 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -23,8 +23,11 @@ #include +#include #include +#define TAG FREERDP_TAG("crypto") + CryptoSha1 crypto_sha1_init(void) { CryptoSha1 sha1 = malloc(sizeof(*sha1)); @@ -202,7 +205,7 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public pkey = X509_get_pubkey(cert->px509); if (!pkey) { - fprintf(stderr, "%s: X509_get_pubkey() failed\n", __FUNCTION__); + WLog_ERR(TAG, "X509_get_pubkey() failed"); status = FALSE; goto exit; } @@ -210,7 +213,7 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public length = i2d_PublicKey(pkey, NULL); if (length < 1) { - fprintf(stderr, "%s: i2d_PublicKey() failed\n", __FUNCTION__); + WLog_ERR(TAG, "i2d_PublicKey() failed"); status = FALSE; goto exit; } @@ -275,7 +278,7 @@ static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, c BN_free(&mod); BN_CTX_free(ctx); -out_free_input_reverse: +out_free_input_reverse: free(input_reverse); return output_length; @@ -569,18 +572,17 @@ void crypto_cert_print_info(X509* xcert) fp = crypto_cert_fingerprint(xcert); if (!fp) { - fprintf(stderr, "%s: error computing fingerprint\n", __FUNCTION__); + WLog_ERR(TAG, "error computing fingerprint"); goto out_free_issuer; } - fprintf(stderr, "Certificate details:\n"); - fprintf(stderr, "\tSubject: %s\n", subject); - fprintf(stderr, "\tIssuer: %s\n", issuer); - fprintf(stderr, "\tThumbprint: %s\n", fp); - fprintf(stderr, "The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); - + WLog_INFO(TAG, "Certificate details:"); + WLog_INFO(TAG, "\tSubject: %s", subject); + WLog_INFO(TAG, "\tIssuer: %s", issuer); + WLog_INFO(TAG, "\tThumbprint: %s", fp); + WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired. " + "Please look at the documentation on how to create local certificate store for a private CA."); free(fp); out_free_issuer: free(issuer); diff --git a/libfreerdp/crypto/test/CMakeLists.txt b/libfreerdp/crypto/test/CMakeLists.txt index 4333b010f..56023e08f 100644 --- a/libfreerdp/crypto/test/CMakeLists.txt +++ b/libfreerdp/crypto/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-crypto) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} freerdp) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index c6e779280..24878d275 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -25,14 +25,22 @@ #include #include +#include #include #include #include +#include #include #include "../core/tcp.h" +#ifdef HAVE_POLL_H +#include +#endif + +#define TAG FREERDP_TAG("crypto") + struct _BIO_RDP_TLS { SSL* ssl; @@ -46,6 +54,7 @@ long bio_rdp_tls_callback(BIO* bio, int mode, const char* argp, int argi, long a static int bio_rdp_tls_write(BIO* bio, const char* buf, int size) { + int error; int status; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; @@ -65,11 +74,11 @@ static int bio_rdp_tls_write(BIO* bio, const char* buf, int size) break; case SSL_ERROR_WANT_WRITE: - BIO_set_flags(bio, BIO_FLAGS_WRITE); + BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_READ: - BIO_set_flags(bio, BIO_FLAGS_READ); + BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_X509_LOOKUP: @@ -83,7 +92,16 @@ static int bio_rdp_tls_write(BIO* bio, const char* buf, int size) break; case SSL_ERROR_SYSCALL: - BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + error = WSAGetLastError(); + if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || + (error == WSAEINPROGRESS) || (error == WSAEALREADY)) + { + BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY)); + } + else + { + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + } break; case SSL_ERROR_SSL: @@ -97,6 +115,7 @@ static int bio_rdp_tls_write(BIO* bio, const char* buf, int size) static int bio_rdp_tls_read(BIO* bio, char* buf, int size) { + int error; int status; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; @@ -116,11 +135,11 @@ static int bio_rdp_tls_read(BIO* bio, char* buf, int size) break; case SSL_ERROR_WANT_READ: - BIO_set_flags(bio, BIO_FLAGS_READ); + BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: - BIO_set_flags(bio, BIO_FLAGS_WRITE); + BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_X509_LOOKUP: @@ -147,7 +166,16 @@ static int bio_rdp_tls_read(BIO* bio, char* buf, int size) break; case SSL_ERROR_SYSCALL: - status = 0; + error = WSAGetLastError(); + if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || + (error == WSAEINPROGRESS) || (error == WSAEALREADY)) + { + BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); + } + else + { + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + } break; } } @@ -484,7 +512,7 @@ static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer) if (!remote_cert) { - fprintf(stderr, "%s: failed to get the server TLS certificate\n", __FUNCTION__); + WLog_ERR(TAG, "failed to get the server TLS certificate"); return NULL; } @@ -557,7 +585,7 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt tls->ctx = SSL_CTX_new(method); if (!tls->ctx) { - fprintf(stderr, "%s: SSL_CTX_new failed\n", __FUNCTION__); + WLog_ERR(TAG, "SSL_CTX_new failed"); return FALSE; } @@ -566,11 +594,18 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt SSL_CTX_set_options(tls->ctx, options); SSL_CTX_set_read_ahead(tls->ctx, 1); + if (tls->settings->PermittedTLSCiphers) { + if(!SSL_CTX_set_cipher_list(tls->ctx, tls->settings->PermittedTLSCiphers)) { + WLog_ERR(TAG, "SSL_CTX_set_cipher_list %s failed", tls->settings->PermittedTLSCiphers); + return FALSE; + } + } + tls->bio = BIO_new_rdp_tls(tls->ctx, clientMode); if (BIO_get_ssl(tls->bio, &tls->ssl) < 0) { - fprintf(stderr, "%s: unable to retrieve the SSL of the connection\n", __FUNCTION__); + WLog_ERR(TAG, "unable to retrieve the SSL of the connection"); return FALSE; } @@ -586,8 +621,12 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) do { +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else struct timeval tv; fd_set rset; +#endif int fd; status = BIO_do_handshake(tls->bio); @@ -600,25 +639,35 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) /* we select() only for read even if we should test both read and write * depending of what have blocked */ - FD_ZERO(&rset); - fd = BIO_get_fd(tls->bio, NULL); if (fd < 0) { - fprintf(stderr, "%s: unable to retrieve BIO fd\n", __FUNCTION__); + WLog_ERR(TAG, "unable to retrieve BIO fd"); return -1; } +#ifdef HAVE_POLL_H + pollfds.fd = fd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, 10 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else + FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec = 0; tv.tv_usec = 10 * 1000; /* 10ms */ - status = select(fd + 1, &rset, NULL, NULL, &tv); - + status = _select(fd + 1, &rset, NULL, NULL, &tv); +#endif if (status < 0) { - fprintf(stderr, "%s: error during select()\n", __FUNCTION__); + WLog_ERR(TAG, "error during select()"); return -1; } } @@ -627,21 +676,21 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) cert = tls_get_certificate(tls, clientMode); if (!cert) { - fprintf(stderr, "%s: tls_get_certificate failed to return the server certificate.\n", __FUNCTION__); + WLog_ERR(TAG, "tls_get_certificate failed to return the server certificate."); return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); if (!tls->Bindings) { - fprintf(stderr, "%s: unable to retrieve bindings\n", __FUNCTION__); + WLog_ERR(TAG, "unable to retrieve bindings"); verify_status = -1; goto out; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { - fprintf(stderr, "%s: crypto_cert_get_public_key failed to return the server public key.\n", __FUNCTION__); + WLog_ERR(TAG, "crypto_cert_get_public_key failed to return the server public key."); verify_status = -1; goto out; } @@ -656,7 +705,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) if (verify_status < 1) { - fprintf(stderr, "%s: certificate not trusted, aborting.\n", __FUNCTION__); + WLog_ERR(TAG, "certificate not trusted, aborting."); tls_disconnect(tls); verify_status = 0; } @@ -755,14 +804,14 @@ BOOL tls_accept(rdpTls* tls, BIO *underlying, const char* cert_file, const char* if (SSL_use_RSAPrivateKey_file(tls->ssl, privatekey_file, SSL_FILETYPE_PEM) <= 0) { - fprintf(stderr, "%s: SSL_CTX_use_RSAPrivateKey_file failed\n", __FUNCTION__); - fprintf(stderr, "PrivateKeyFile: %s\n", privatekey_file); + WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed"); + WLog_ERR(TAG, "PrivateKeyFile: %s", privatekey_file); return FALSE; } if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0) { - fprintf(stderr, "%s: SSL_use_certificate_file failed\n", __FUNCTION__); + WLog_ERR(TAG, "SSL_use_certificate_file failed"); return FALSE; } @@ -830,9 +879,13 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) { int status, nchunks, commitedBytes; rdpTcp *tcp; +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set rset, wset; fd_set *rsetPtr, *wsetPtr; struct timeval tv; +#endif BIO* bio = tls->bio; DataChunk chunks[2]; @@ -840,7 +893,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) if (!bufferedBio) { - fprintf(stderr, "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__); + WLog_ERR(TAG, "error unable to retrieve the bufferedBio in the BIO chain"); return -1; } @@ -855,9 +908,34 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) if (!BIO_should_retry(bio)) return -1; +#ifdef HAVE_POLL_H + pollfds.fd = tcp->sockfd; + pollfds.revents = 0; + pollfds.events = 0; + if (tcp->writeBlocked) + { + pollfds.events |= POLLOUT; + } + else if (tcp->readBlocked) + { + pollfds.events |= POLLIN; + } + else + { + WLog_ERR(TAG, "weird we're blocked but the underlying is not read or write blocked !"); + USleep(10); + continue; + } + + do + { + status = poll(&pollfds, 1, 100); + } + while ((status < 0) && (errno == EINTR)); +#else /* we try to handle SSL want_read and want_write nicely */ - rsetPtr = wsetPtr = 0; + rsetPtr = wsetPtr = NULL; if (tcp->writeBlocked) { @@ -873,7 +951,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) } else { - fprintf(stderr, "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); + WLog_ERR(TAG, "weird we're blocked but the underlying is not read or write blocked !"); USleep(10); continue; } @@ -881,8 +959,8 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) tv.tv_sec = 0; tv.tv_usec = 100 * 1000; - status = select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); - + status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); +#endif if (status < 0) return -1; } @@ -911,13 +989,24 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) if (!BIO_should_retry(tcp->socketBio)) goto out_fail; +#ifdef HAVE_POLL_H + pollfds.fd = tcp->sockfd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, 100); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; - status = select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); - + status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); +#endif if (status < 0) goto out_fail; } @@ -993,7 +1082,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (!bio) { - fprintf(stderr, "%s: BIO_new() failure\n", __FUNCTION__); + WLog_ERR(TAG, "BIO_new() failure"); return -1; } @@ -1001,7 +1090,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - fprintf(stderr, "%s: PEM_write_bio_X509 failure: %d\n", __FUNCTION__, status); + WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status); return -1; } @@ -1013,7 +1102,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - fprintf(stderr, "%s: failed to read certificate\n", __FUNCTION__); + WLog_ERR(TAG, "failed to read certificate"); return -1; } @@ -1034,7 +1123,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - fprintf(stderr, "%s: failed to read certificate\n", __FUNCTION__); + WLog_ERR(TAG, "failed to read certificate"); return -1; } @@ -1048,7 +1137,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por status = instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, tls->isGatewayTransport); } - fprintf(stderr, "%s: (length = %d) status: %d\n%s\n", __FUNCTION__, length, status, pemCert); + WLog_ERR(TAG, "(length = %d) status: %d%s", length, status, pemCert); free(pemCert); BIO_free(bio); @@ -1208,18 +1297,18 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file) { - fprintf(stderr, "The host key for %s has changed\n", hostname); - fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); - fprintf(stderr, "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @\n"); - fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); - fprintf(stderr, "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"); - fprintf(stderr, "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"); - fprintf(stderr, "It is also possible that a host key has just been changed.\n"); - fprintf(stderr, "The fingerprint for the host key sent by the remote host is\n%s\n", fingerprint); - fprintf(stderr, "Please contact your system administrator.\n"); - fprintf(stderr, "Add correct host key in %s to get rid of this message.\n", hosts_file); - fprintf(stderr, "Host key for %s has changed and you have requested strict checking.\n", hostname); - fprintf(stderr, "Host key verification failed.\n"); + WLog_ERR(TAG, "The host key for %s has changed", hostname); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + WLog_ERR(TAG, "Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + WLog_ERR(TAG, "It is also possible that a host key has just been changed."); + WLog_ERR(TAG, "The fingerprint for the host key sent by the remote host is%s", fingerprint); + WLog_ERR(TAG, "Please contact your system administrator."); + WLog_ERR(TAG, "Add correct host key in %s to get rid of this message.", hosts_file); + WLog_ERR(TAG, "Host key for %s has changed and you have requested strict checking.", hostname); + WLog_ERR(TAG, "Host key verification failed."); } void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count) @@ -1227,25 +1316,24 @@ void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name int index; assert(NULL != hostname); - - fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); - fprintf(stderr, "@ WARNING: CERTIFICATE NAME MISMATCH! @\n"); - fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); - fprintf(stderr, "The hostname used for this connection (%s) \n", hostname); - fprintf(stderr, "does not match %s given in the certificate:\n", alt_names_count < 1 ? "the name" : "any of the names"); - fprintf(stderr, "Common Name (CN):\n"); - fprintf(stderr, "\t%s\n", common_name ? common_name : "no CN found in certificate"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "@ WARNING: CERTIFICATE NAME MISMATCH! @"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "The hostname used for this connection (%s) ", hostname); + WLog_ERR(TAG, "does not match %s given in the certificate:", alt_names_count < 1 ? "the name" : "any of the names"); + WLog_ERR(TAG, "Common Name (CN):"); + WLog_ERR(TAG, "\t%s", common_name ? common_name : "no CN found in certificate"); if (alt_names_count > 0) { assert(NULL != alt_names); - fprintf(stderr, "Alternative names:\n"); + WLog_ERR(TAG, "Alternative names:"); for (index = 0; index < alt_names_count; index++) { assert(alt_names[index]); - fprintf(stderr, "\t %s\n", alt_names[index]); + WLog_ERR(TAG, "\t %s", alt_names[index]); } } - fprintf(stderr, "A valid certificate for the wrong name should NOT be trusted!\n"); + WLog_ERR(TAG, "A valid certificate for the wrong name should NOT be trusted!"); } rdpTls* tls_new(rdpSettings* settings) @@ -1257,14 +1345,17 @@ rdpTls* tls_new(rdpSettings* settings) if (!tls) return NULL; - SSL_load_error_strings(); - SSL_library_init(); + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); tls->settings = settings; - tls->certificate_store = certificate_store_new(settings); - if (!tls->certificate_store) - goto out_free; + if (!settings->ServerMode) + { + tls->certificate_store = certificate_store_new(settings); + + if (!tls->certificate_store) + goto out_free; + } tls->alertLevel = TLS_ALERT_LEVEL_WARNING; tls->alertDescription = TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY; @@ -1300,8 +1391,11 @@ void tls_free(rdpTls* tls) tls->Bindings = NULL; } - certificate_store_free(tls->certificate_store); - tls->certificate_store = NULL; + if (tls->certificate_store) + { + certificate_store_free(tls->certificate_store); + tls->certificate_store = NULL; + } free(tls); } diff --git a/libfreerdp/dummy.c b/libfreerdp/dummy.c deleted file mode 100644 index fb941c948..000000000 --- a/libfreerdp/dummy.c +++ /dev/null @@ -1,5 +0,0 @@ - -int freerdp_dummy() -{ - return 0; -} diff --git a/libfreerdp/gdi/16bpp.c b/libfreerdp/gdi/16bpp.c index 3f96425e6..ff90f485f 100644 --- a/libfreerdp/gdi/16bpp.c +++ b/libfreerdp/gdi/16bpp.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -38,12 +39,14 @@ #include +#define TAG FREERDP_TAG("gdi") + UINT16 gdi_get_color_16bpp(HGDI_DC hdc, GDI_COLOR color) { BYTE r, g, b; UINT16 color16; - GetBGR32(r, g, b, color); + GetRGB32(r, g, b, color); if (hdc->rgb555) { @@ -412,7 +415,8 @@ static int BitBlt_DSPDxax_16bpp(HGDI_DC hdcDest, int nXDest, int nYDest, int nWi if (hdcSrc->bytesPerPixel != 1) { - fprintf(stderr, "BitBlt_DSPDxax expects 1 bpp, unimplemented for %d\n", hdcSrc->bytesPerPixel); + WLog_ERR(TAG, "BitBlt_DSPDxax expects 1 bpp, unimplemented for %d", + hdcSrc->bytesPerPixel); return 0; } @@ -893,8 +897,8 @@ int BitBlt_16bpp(HGDI_DC hdcDest, int nXDest, int nYDest, int nWidth, int nHeigh return BitBlt_PATPAINT_16bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; } - - fprintf(stderr, "BitBlt: unknown rop: 0x%08X\n", rop); + + WLog_ERR(TAG, "BitBlt: unknown rop: 0x%08X", rop); return 1; } @@ -939,7 +943,7 @@ int PatBlt_16bpp(HGDI_DC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, i break; } - fprintf(stderr, "PatBlt: unknown rop: 0x%08X\n", rop); + WLog_ERR(TAG, "PatBlt: unknown rop: 0x%08X", rop); return 1; } diff --git a/libfreerdp/gdi/32bpp.c b/libfreerdp/gdi/32bpp.c index 33e1d19d9..5458917ae 100644 --- a/libfreerdp/gdi/32bpp.c +++ b/libfreerdp/gdi/32bpp.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -38,13 +39,15 @@ #include +#define TAG FREERDP_TAG("gdi") + UINT32 gdi_get_color_32bpp(HGDI_DC hdc, GDI_COLOR color) { UINT32 color32; BYTE a, r, g, b; a = 0xFF; - GetBGR32(r, g, b, color); + GetRGB32(r, g, b, color); if (hdc->invert) { @@ -859,7 +862,7 @@ static int BitBlt_PATINVERT_32bpp(HGDI_DC hdcDest, int nXDest, int nYDest, int n } } } - + return 0; } @@ -996,8 +999,8 @@ int BitBlt_32bpp(HGDI_DC hdcDest, int nXDest, int nYDest, int nWidth, int nHeigh return BitBlt_PATPAINT_32bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; } - - fprintf(stderr, "BitBlt: unknown rop: 0x%08X\n", rop); + + WLog_ERR(TAG, "BitBlt: unknown rop: 0x%08X", rop); return 1; } @@ -1041,8 +1044,8 @@ int PatBlt_32bpp(HGDI_DC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, i default: break; } - - fprintf(stderr, "PatBlt: unknown rop: 0x%08X\n", rop); + + WLog_ERR(TAG, "PatBlt: unknown rop: 0x%08X", rop); return 1; } diff --git a/libfreerdp/gdi/8bpp.c b/libfreerdp/gdi/8bpp.c index 0999cedcb..96c1d5883 100644 --- a/libfreerdp/gdi/8bpp.c +++ b/libfreerdp/gdi/8bpp.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,8 @@ #include +#define TAG FREERDP_TAG("gdi") + BYTE gdi_get_color_8bpp(HGDI_DC hdc, GDI_COLOR color) { /* TODO: Implement 8bpp gdi_get_color_8bpp() */ @@ -806,8 +809,8 @@ int BitBlt_8bpp(HGDI_DC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight return BitBlt_PATPAINT_8bpp(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc); break; } - - fprintf(stderr, "BitBlt: unknown rop: 0x%08X\n", rop); + + WLog_ERR(TAG, "BitBlt: unknown rop: 0x%08X", rop); return 1; } @@ -851,8 +854,8 @@ int PatBlt_8bpp(HGDI_DC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, in default: break; } - - fprintf(stderr, "PatBlt: unknown rop: 0x%08X\n", rop); + + WLog_ERR(TAG, "PatBlt: unknown rop: 0x%08X", rop); return 1; } diff --git a/libfreerdp/gdi/CMakeLists.txt b/libfreerdp/gdi/CMakeLists.txt index 6b182fe1e..c64979a2c 100644 --- a/libfreerdp/gdi/CMakeLists.txt +++ b/libfreerdp/gdi/CMakeLists.txt @@ -36,29 +36,11 @@ set(${MODULE_PREFIX}_SRCS shape.c graphics.c graphics.h + gfx.c gdi.c gdi.h) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-core freerdp-cache freerdp-codec) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") +freerdp_module_add(${${MODULE_PREFIX}_SRCS}) if(BUILD_TESTING) add_subdirectory(test) diff --git a/libfreerdp/gdi/bitmap.c b/libfreerdp/gdi/bitmap.c index 10a24fa76..0456a0e04 100644 --- a/libfreerdp/gdi/bitmap.c +++ b/libfreerdp/gdi/bitmap.c @@ -158,12 +158,16 @@ HGDI_BITMAP gdi_CreateBitmap(int nWidth, int nHeight, int cBitsPerPixel, BYTE* d HGDI_BITMAP gdi_CreateCompatibleBitmap(HGDI_DC hdc, int nWidth, int nHeight) { HGDI_BITMAP hBitmap = (HGDI_BITMAP) malloc(sizeof(GDI_BITMAP)); + + if (!hBitmap) + return NULL; + hBitmap->objectType = GDIOBJECT_BITMAP; hBitmap->bytesPerPixel = hdc->bytesPerPixel; hBitmap->bitsPerPixel = hdc->bitsPerPixel; hBitmap->width = nWidth; hBitmap->height = nHeight; - hBitmap->data = malloc(nWidth * nHeight * hBitmap->bytesPerPixel); + hBitmap->data = _aligned_malloc(nWidth * nHeight * hBitmap->bytesPerPixel, 16); hBitmap->scanline = nWidth * hBitmap->bytesPerPixel; return hBitmap; } diff --git a/libfreerdp/gdi/dc.c b/libfreerdp/gdi/dc.c index 892fc1dc1..1f96a1434 100644 --- a/libfreerdp/gdi/dc.c +++ b/libfreerdp/gdi/dc.c @@ -163,15 +163,15 @@ HGDIOBJECT gdi_SelectObject(HGDI_DC hdc, HGDIOBJECT hgdiobject) int gdi_DeleteObject(HGDIOBJECT hgdiobject) { - if (hgdiobject == NULL) + if (!hgdiobject) return 0; if (hgdiobject->objectType == GDIOBJECT_BITMAP) { HGDI_BITMAP hBitmap = (HGDI_BITMAP) hgdiobject; - if (hBitmap->data != NULL) - free(hBitmap->data); + if (hBitmap->data) + _aligned_free(hBitmap->data); free(hBitmap); } diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 2bc0091b4..72720daf1 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -26,11 +26,12 @@ #include #include +#include #include +#include #include #include -#include #include #include #include @@ -51,6 +52,8 @@ #include "gdi.h" +#define TAG FREERDP_TAG("gdi") + /* Ternary Raster Operation Table */ static const UINT32 rop3_code_table[] = { @@ -330,6 +333,36 @@ INLINE UINT32 gdi_rop3_code(BYTE code) return rop3_code_table[code]; } +UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel, BOOL vFlip) +{ + UINT32 format = PIXEL_FORMAT_XRGB32_VF; + + switch (bitsPerPixel) + { + case 32: + format = vFlip ? PIXEL_FORMAT_XRGB32_VF : PIXEL_FORMAT_XRGB32; + break; + + case 24: + format = vFlip ? PIXEL_FORMAT_RGB24_VF : PIXEL_FORMAT_RGB24; + break; + + case 16: + format = vFlip ? PIXEL_FORMAT_RGB16_VF : PIXEL_FORMAT_RGB16; + break; + + case 15: + format = vFlip ? PIXEL_FORMAT_RGB15_VF : PIXEL_FORMAT_RGB15; + break; + + case 8: + format = vFlip ? PIXEL_FORMAT_RGB8_VF : PIXEL_FORMAT_RGB8; + break; + } + + return format; +} + INLINE BYTE* gdi_get_bitmap_pointer(HGDI_DC hdcBmp, int x, int y) { BYTE* p; @@ -342,7 +375,8 @@ INLINE BYTE* gdi_get_bitmap_pointer(HGDI_DC hdcBmp, int x, int y) } else { - fprintf(stderr, "gdi_get_bitmap_pointer: requesting invalid pointer: (%d,%d) in %dx%d\n", x, y, hBmp->width, hBmp->height); + WLog_ERR(TAG, "gdi_get_bitmap_pointer: requesting invalid pointer: (%d,%d) in %dx%d", + x, y, hBmp->width, hBmp->height); return 0; } } @@ -371,61 +405,20 @@ INLINE BYTE* gdi_get_brush_pointer(HGDI_DC hdcBrush, int x, int y) return p; } -INLINE int gdi_is_mono_pixel_set(BYTE* data, int x, int y, int width) -{ - int byte; - int shift; - - width = (width + 7) / 8; - byte = (y * width) + (x / 8); - shift = x % 8; - - return (data[byte] & (0x80 >> shift)) != 0; -} - -gdiBitmap* gdi_glyph_new(rdpGdi* gdi, GLYPH_DATA* glyph) -{ - BYTE* extra; - gdiBitmap* gdi_bmp; - - gdi_bmp = (gdiBitmap*) malloc(sizeof(gdiBitmap)); - - gdi_bmp->hdc = gdi_GetDC(); - gdi_bmp->hdc->bytesPerPixel = 1; - gdi_bmp->hdc->bitsPerPixel = 1; - - extra = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj); - gdi_bmp->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, 1, extra); - gdi_bmp->bitmap->bytesPerPixel = 1; - gdi_bmp->bitmap->bitsPerPixel = 1; - - gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->bitmap); - gdi_bmp->org_bitmap = NULL; - - return gdi_bmp; -} - -void gdi_glyph_free(gdiBitmap *gdi_bmp) -{ - if (gdi_bmp != 0) - { - gdi_SelectObject(gdi_bmp->hdc, (HGDIOBJECT) gdi_bmp->org_bitmap); - gdi_DeleteObject((HGDIOBJECT) gdi_bmp->bitmap); - gdi_DeleteDC(gdi_bmp->hdc); - free(gdi_bmp); - } -} - gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi, int width, int height, int bpp, BYTE* data) { gdiBitmap* bitmap; bitmap = (gdiBitmap*) malloc(sizeof(gdiBitmap)); + + if (!bitmap) + return NULL; + bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc); DEBUG_GDI("gdi_bitmap_new: width:%d height:%d bpp:%d", width, height, bpp); - if (data == NULL) + if (!data) bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, width, height); else bitmap->bitmap = gdi_create_bitmap(gdi, width, height, bpp, data); @@ -447,13 +440,128 @@ void gdi_bitmap_free_ex(gdiBitmap* bitmap) } } -void gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette) +static void gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) { + int status; + int nXDst; + int nYDst; + int nXSrc; + int nYSrc; + int nWidth; + int nHeight; + int nSrcStep; + int nDstStep; + UINT32 index; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + BOOL compressed; + UINT32 SrcFormat; + UINT32 bitsPerPixel; + BITMAP_DATA* bitmap; rdpGdi* gdi = context->gdi; - CopyMemory(gdi->clrconv->palette, palette, sizeof(rdpPalette)); + rdpCodecs* codecs = context->codecs; + + for (index = 0; index < bitmapUpdate->number; index++) + { + bitmap = &(bitmapUpdate->rectangles[index]); + + nXSrc = 0; + nYSrc = 0; + + nXDst = bitmap->destLeft; + nYDst = bitmap->destTop; + + nWidth = bitmap->width; + nHeight = bitmap->height; + + pSrcData = bitmap->bitmapDataStream; + SrcSize = bitmap->bitmapLength; + + compressed = bitmap->compressed; + bitsPerPixel = bitmap->bitsPerPixel; + + if (gdi->bitmap_size < (nWidth * nHeight * 4)) + { + gdi->bitmap_size = nWidth * nHeight * 4; + gdi->bitmap_buffer = (BYTE*) _aligned_realloc(gdi->bitmap_buffer, gdi->bitmap_size, 16); + + if (!gdi->bitmap_buffer) + return; + } + + if (compressed) + { + pDstData = gdi->bitmap_buffer; + + if (bitsPerPixel < 32) + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(codecs->interleaved, pSrcData, SrcSize, bitsPerPixel, + &pDstData, gdi->format, -1, 0, 0, nWidth, nHeight, gdi->palette); + } + else + { + freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(codecs->planar, pSrcData, SrcSize, &pDstData, + gdi->format, -1, 0, 0, nWidth, nHeight, TRUE); + } + + if (status < 0) + { + WLog_ERR(TAG, "bitmap decompression failure"); + return; + } + + pSrcData = gdi->bitmap_buffer; + } + else + { + pDstData = gdi->bitmap_buffer; + SrcFormat = gdi_get_pixel_format(bitsPerPixel, TRUE); + + status = freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, + nWidth, nHeight, pSrcData, SrcFormat, -1, 0, 0, gdi->palette); + + pSrcData = gdi->bitmap_buffer; + } + + nSrcStep = nWidth * 4; + + pDstData = gdi->primary_buffer; + nDstStep = gdi->width * gdi->bytesPerPixel; + + nWidth = bitmap->destRight - bitmap->destLeft + 1; /* clip width */ + nHeight = bitmap->destBottom - bitmap->destTop + 1; /* clip height */ + + status = freerdp_image_copy(pDstData, gdi->format, nDstStep, nXDst, nYDst, + nWidth, nHeight, pSrcData, gdi->format, nSrcStep, nXSrc, nYSrc, gdi->palette); + + gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, nWidth, nHeight); + } } -void gdi_set_bounds(rdpContext* context, rdpBounds* bounds) +static void gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette) +{ + int index; + PALETTE_ENTRY* pe; + UINT32* palette32; + rdpGdi* gdi = context->gdi; + + CopyMemory(gdi->clrconv->palette, palette, sizeof(rdpPalette)); + + palette32 = (UINT32*) gdi->palette; + + for (index = 0; index < palette->number; index++) + { + pe = &(palette->entries[index]); + palette32[index] = RGB32(pe->red, pe->green, pe->blue); + } +} + +static void gdi_set_bounds(rdpContext* context, rdpBounds* bounds) { rdpGdi* gdi = context->gdi; @@ -468,7 +576,7 @@ void gdi_set_bounds(rdpContext* context, rdpBounds* bounds) } } -void gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) +static void gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) { rdpGdi* gdi = context->gdi; @@ -476,7 +584,7 @@ void gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) dstblt->nWidth, dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop)); } -void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) +static void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { BYTE* data; rdpBrush* brush; @@ -488,8 +596,8 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) brush = &patblt->brush; - foreColor = freerdp_color_convert_rgb(patblt->foreColor, gdi->srcBpp, 24, gdi->clrconv); - backColor = freerdp_color_convert_rgb(patblt->backColor, gdi->srcBpp, 24, gdi->clrconv); + foreColor = freerdp_convert_gdi_order_color(patblt->foreColor, gdi->srcBpp, gdi->format, gdi->palette); + backColor = freerdp_convert_gdi_order_color(patblt->backColor, gdi->srcBpp, gdi->format, gdi->palette); originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor); @@ -510,7 +618,7 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) HGDI_BITMAP hBmp; data = freerdp_mono_image_convert(GDI_BS_HATCHED_PATTERNS + 8 * brush->hatch, 8, 8, 1, - gdi->dstBpp, patblt->backColor, patblt->foreColor, gdi->clrconv); + gdi->dstBpp, backColor, foreColor, gdi->clrconv); hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data); @@ -534,7 +642,7 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) else { data = freerdp_mono_image_convert(brush->data, 8, 8, gdi->srcBpp, gdi->dstBpp, - patblt->backColor, patblt->foreColor, gdi->clrconv); + backColor, foreColor, gdi->clrconv); } hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data); @@ -550,13 +658,13 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) } else { - fprintf(stderr, "unimplemented brush style:%d\n", brush->style); + WLog_ERR(TAG, "unimplemented brush style:%d", brush->style); } gdi_SetTextColor(gdi->drawing->hdc, originalColor); } -void gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) +static void gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) { rdpGdi* gdi = context->gdi; @@ -565,7 +673,7 @@ void gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) scrblt->nXSrc, scrblt->nYSrc, gdi_rop3_code(scrblt->bRop)); } -void gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) +static void gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) { GDI_RECT rect; HGDI_BRUSH hBrush; @@ -575,7 +683,7 @@ void gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) gdi_CRgnToRect(opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight, &rect); - brush_color = freerdp_color_convert_var_bgr(opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv); + brush_color = freerdp_convert_gdi_order_color(opaque_rect->color, gdi->srcBpp, gdi->format, gdi->palette); hBrush = gdi_CreateSolidBrush(brush_color); gdi_FillRect(gdi->drawing->hdc, &rect, hBrush); @@ -583,7 +691,7 @@ void gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) gdi_DeleteObject((HGDIOBJECT) hBrush); } -void gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) +static void gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) { int i; GDI_RECT rect; @@ -599,7 +707,7 @@ void gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_o gdi_CRgnToRect(rectangle->left, rectangle->top, rectangle->width, rectangle->height, &rect); - brush_color = freerdp_color_convert_var_bgr(multi_opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv); + brush_color = freerdp_convert_gdi_order_color(multi_opaque_rect->color, gdi->srcBpp, gdi->format, gdi->palette); hBrush = gdi_CreateSolidBrush(brush_color); gdi_FillRect(gdi->drawing->hdc, &rect, hBrush); @@ -608,13 +716,13 @@ void gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_o } } -void gdi_line_to(rdpContext* context, LINE_TO_ORDER* lineTo) +static void gdi_line_to(rdpContext* context, LINE_TO_ORDER* lineTo) { UINT32 color; HGDI_PEN hPen; rdpGdi* gdi = context->gdi; - color = freerdp_color_convert_rgb(lineTo->penColor, gdi->srcBpp, 32, gdi->clrconv); + color = freerdp_convert_gdi_order_color(lineTo->penColor, gdi->srcBpp, gdi->format, gdi->palette); hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, (GDI_COLOR) color); gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen); gdi_SetROP2(gdi->drawing->hdc, lineTo->bRop2); @@ -625,7 +733,7 @@ void gdi_line_to(rdpContext* context, LINE_TO_ORDER* lineTo) gdi_DeleteObject((HGDIOBJECT) hPen); } -void gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) +static void gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) { int i; INT32 x; @@ -635,7 +743,7 @@ void gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) DELTA_POINT* points; rdpGdi* gdi = context->gdi; - color = freerdp_color_convert_rgb(polyline->penColor, gdi->srcBpp, 32, gdi->clrconv); + color = freerdp_convert_gdi_order_color(polyline->penColor, gdi->srcBpp, gdi->format, gdi->palette); hPen = gdi_CreatePen(GDI_PS_SOLID, 1, (GDI_COLOR) color); gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen); gdi_SetROP2(gdi->drawing->hdc, polyline->bRop2); @@ -656,7 +764,7 @@ void gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) gdi_DeleteObject((HGDIOBJECT) hPen); } -void gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) +static void gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { gdiBitmap* bitmap; rdpGdi* gdi = context->gdi; @@ -668,7 +776,7 @@ void gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) memblt->nXSrc, memblt->nYSrc, gdi_rop3_code(memblt->bRop)); } -void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) +static void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) { BYTE* data; rdpBrush* brush; @@ -682,8 +790,8 @@ void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) brush = &mem3blt->brush; bitmap = (gdiBitmap*) mem3blt->bitmap; - foreColor = freerdp_color_convert_rgb(mem3blt->foreColor, gdi->srcBpp, 24, gdi->clrconv); - backColor = freerdp_color_convert_rgb(mem3blt->backColor, gdi->srcBpp, 24, gdi->clrconv); + foreColor = freerdp_convert_gdi_order_color(mem3blt->foreColor, gdi->srcBpp, gdi->format, gdi->palette); + backColor = freerdp_convert_gdi_order_color(mem3blt->backColor, gdi->srcBpp, gdi->format, gdi->palette); originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor); @@ -710,7 +818,7 @@ void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) else { data = freerdp_mono_image_convert(brush->data, 8, 8, gdi->srcBpp, gdi->dstBpp, - mem3blt->backColor, mem3blt->foreColor, gdi->clrconv); + backColor, foreColor, gdi->clrconv); } hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data); @@ -727,166 +835,171 @@ void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) } else { - fprintf(stderr, "Mem3Blt unimplemented brush style:%d\n", brush->style); + WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%d", brush->style); } gdi_SetTextColor(gdi->drawing->hdc, originalColor); } -void gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) +static void gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) { - fprintf(stderr, "PolygonSC\n"); + WLog_VRB(TAG, "not implemented"); } -void gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) +static void gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) { - fprintf(stderr, "PolygonCB\n"); + WLog_VRB(TAG, "not implemented"); } -void gdi_ellipse_sc(rdpContext* context, ELLIPSE_SC_ORDER* ellipse_sc) +static void gdi_ellipse_sc(rdpContext* context, ELLIPSE_SC_ORDER* ellipse_sc) { - fprintf(stderr, "EllipseSC\n"); + WLog_VRB(TAG, "not implemented"); } -void gdi_ellipse_cb(rdpContext* context, ELLIPSE_CB_ORDER* ellipse_cb) +static void gdi_ellipse_cb(rdpContext* context, ELLIPSE_CB_ORDER* ellipse_cb) { - fprintf(stderr, "EllipseCB\n"); + WLog_VRB(TAG, "not implemented"); } -void gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) +static void gdi_frame_marker(rdpContext* context, FRAME_MARKER_ORDER* frameMarker) +{ + + +} + +void gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surfaceFrameMarker) { DEBUG_GDI("frameId %d frameAction %d", - surface_frame_marker->frameId, - surface_frame_marker->frameAction); + surfaceFrameMarker->frameId, + surfaceFrameMarker->frameAction); - /* TODO: Implement frame marker completely */ - - switch (surface_frame_marker->frameAction) + switch (surfaceFrameMarker->frameAction) { case SURFACECMD_FRAMEACTION_BEGIN: break; case SURFACECMD_FRAMEACTION_END: - if (context->instance->settings->FrameAcknowledge > 0) + if (context->settings->FrameAcknowledge > 0) { - IFCALL(context->instance->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId); + IFCALL(context->update->SurfaceFrameAcknowledge, context, surfaceFrameMarker->frameId); } break; } } -int tilenum = 0; - -void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) +static void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd) { int i, j; int tx, ty; - char* tile_bitmap; + BYTE* pSrcData; + BYTE* pDstData; RFX_MESSAGE* message; rdpGdi* gdi = context->gdi; - RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) gdi->rfx_context; - NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) gdi->nsc_context; DEBUG_GDI("destLeft %d destTop %d destRight %d destBottom %d " "bpp %d codecID %d width %d height %d length %d", - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->destRight, surface_bits_command->destBottom, - surface_bits_command->bpp, surface_bits_command->codecID, - surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bitmapDataLength); + cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, + cmd->bpp, cmd->codecID, cmd->width, cmd->height, cmd->bitmapDataLength); - tile_bitmap = (char*) malloc(32); - ZeroMemory(tile_bitmap, 32); - - if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX) + if (cmd->codecID == RDP_CODEC_ID_REMOTEFX) { - message = rfx_process_message(rfx_context, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX); - DEBUG_GDI("num_rects %d num_tiles %d", message->numRects, message->numTiles); + message = rfx_process_message(gdi->codecs->rfx, cmd->bitmapData, cmd->bitmapDataLength); /* blit each tile */ for (i = 0; i < message->numTiles; i++) { - tx = message->tiles[i]->x + surface_bits_command->destLeft; - ty = message->tiles[i]->y + surface_bits_command->destTop; + tx = message->tiles[i]->x + cmd->destLeft; + ty = message->tiles[i]->y + cmd->destTop; - freerdp_image_convert(message->tiles[i]->data, gdi->tile->bitmap->data, 64, 64, 32, 32, gdi->clrconv); - -#ifdef DUMP_REMOTEFX_TILES - sprintf(tile_bitmap, "/tmp/rfx/tile_%d.bmp", tilenum++); - freerdp_bitmap_write(tile_bitmap, gdi->tile->bitmap->data, 64, 64, 32); -#endif + pSrcData = message->tiles[i]->data; + pDstData = gdi->tile->bitmap->data; + if (!gdi->invert && (gdi->dstBpp == 32)) + { + gdi->tile->bitmap->data = pSrcData; + } + else + { + freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, + 64, 64, pSrcData, PIXEL_FORMAT_XRGB32, -1, 0, 0, gdi->palette); + } for (j = 0; j < message->numRects; j++) { gdi_SetClipRgn(gdi->primary->hdc, - surface_bits_command->destLeft + message->rects[j].x, - surface_bits_command->destTop + message->rects[j].y, + cmd->destLeft + message->rects[j].x, + cmd->destTop + message->rects[j].y, message->rects[j].width, message->rects[j].height); gdi_BitBlt(gdi->primary->hdc, tx, ty, 64, 64, gdi->tile->hdc, 0, 0, GDI_SRCCOPY); } + + gdi->tile->bitmap->data = pDstData; } gdi_SetNullClipRgn(gdi->primary->hdc); - rfx_message_free(rfx_context, message); + rfx_message_free(gdi->codecs->rfx, message); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC) + else if (cmd->codecID == RDP_CODEC_ID_NSCODEC) { - nsc_process_message(nsc_context, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); - gdi->image->bitmap->width = surface_bits_command->width; - gdi->image->bitmap->height = surface_bits_command->height; - gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp; - gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8; - gdi->image->bitmap->data = (BYTE*) realloc(gdi->image->bitmap->data, gdi->image->bitmap->width * gdi->image->bitmap->height * 4); - freerdp_image_flip(nsc_context->BitmapData, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); - gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_NSCODEC); + + nsc_process_message(gdi->codecs->nsc, cmd->bpp, cmd->width, cmd->height, cmd->bitmapData, cmd->bitmapDataLength); + + if (gdi->bitmap_size < (cmd->width * cmd->height * 4)) + { + gdi->bitmap_size = cmd->width * cmd->height * 4; + gdi->bitmap_buffer = (BYTE*) _aligned_realloc(gdi->bitmap_buffer, gdi->bitmap_size, 16); + + if (!gdi->bitmap_buffer) + return; + } + + pDstData = gdi->bitmap_buffer; + pSrcData = gdi->codecs->nsc->BitmapData; + + freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, + cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, gdi->palette); + + gdi->image->bitmap->width = cmd->width; + gdi->image->bitmap->height = cmd->height; + gdi->image->bitmap->bitsPerPixel = cmd->bpp; + gdi->image->bitmap->bytesPerPixel = cmd->bpp / 8; + gdi->image->bitmap->data = gdi->bitmap_buffer; + + gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NONE) + else if (cmd->codecID == RDP_CODEC_ID_NONE) { - gdi->image->bitmap->width = surface_bits_command->width; - gdi->image->bitmap->height = surface_bits_command->height; - gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp; - gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8; - - gdi->image->bitmap->data = (BYTE*) realloc(gdi->image->bitmap->data, - gdi->image->bitmap->width * gdi->image->bitmap->height * 4); - - if ((surface_bits_command->bpp != 32) || (gdi->clrconv->alpha == TRUE)) + if (gdi->bitmap_size < (cmd->width * cmd->height * 4)) { - BYTE* temp_image; + gdi->bitmap_size = cmd->width * cmd->height * 4; + gdi->bitmap_buffer = (BYTE*) _aligned_realloc(gdi->bitmap_buffer, gdi->bitmap_size, 16); - freerdp_image_convert(surface_bits_command->bitmapData, gdi->image->bitmap->data, - gdi->image->bitmap->width, gdi->image->bitmap->height, - gdi->image->bitmap->bitsPerPixel, 32, gdi->clrconv); - - surface_bits_command->bpp = 32; - surface_bits_command->bitmapData = gdi->image->bitmap->data; - - temp_image = (BYTE*) malloc(gdi->image->bitmap->width * gdi->image->bitmap->height * 4); - freerdp_image_flip(gdi->image->bitmap->data, temp_image, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); - free(gdi->image->bitmap->data); - gdi->image->bitmap->data = temp_image; - } - else - { - freerdp_image_flip(surface_bits_command->bitmapData, gdi->image->bitmap->data, - gdi->image->bitmap->width, gdi->image->bitmap->height, 32); + if (!gdi->bitmap_buffer) + return; } - gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); + pDstData = gdi->bitmap_buffer; + pSrcData = cmd->bitmapData; + + freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, + cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, gdi->palette); + + gdi->image->bitmap->width = cmd->width; + gdi->image->bitmap->height = cmd->height; + gdi->image->bitmap->bitsPerPixel = cmd->bpp; + gdi->image->bitmap->bytesPerPixel = cmd->bpp / 8; + gdi->image->bitmap->data = gdi->bitmap_buffer; + + gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } else { - fprintf(stderr, "Unsupported codecID %d\n", surface_bits_command->codecID); + WLog_ERR(TAG, "Unsupported codecID %d", cmd->codecID); } - - if (tile_bitmap != NULL) - free(tile_bitmap); } /** @@ -927,11 +1040,17 @@ void gdi_register_update_callbacks(rdpUpdate* update) update->SurfaceBits = gdi_surface_bits; update->SurfaceFrameMarker = gdi_surface_frame_marker; + + update->altsec->FrameMarker = gdi_frame_marker; } void gdi_init_primary(rdpGdi* gdi) { gdi->primary = (gdiBitmap*) malloc(sizeof(gdiBitmap)); + + if (!gdi->primary) + return; + gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc); if (!gdi->primary_buffer) @@ -968,6 +1087,7 @@ void gdi_resize(rdpGdi* gdi, int width, int height) gdi->width = width; gdi->height = height; gdi_bitmap_free_ex(gdi->primary); + gdi->primary_buffer = NULL; gdi_init_primary(gdi); } } @@ -981,15 +1101,20 @@ void gdi_resize(rdpGdi* gdi, int width, int height) int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) { + BOOL rgb555; rdpGdi* gdi; rdpCache* cache; - gdi = (rdpGdi*) malloc(sizeof(rdpGdi)); - ZeroMemory(gdi, sizeof(rdpGdi)); + gdi = (rdpGdi*) calloc(1, sizeof(rdpGdi)); + + if (!gdi) + return -1; instance->context->gdi = gdi; + gdi->context = instance->context; cache = instance->context->cache; + gdi->codecs = instance->context->codecs; gdi->width = instance->settings->DesktopWidth; gdi->height = instance->settings->DesktopHeight; gdi->srcBpp = instance->settings->ColorDepth; @@ -998,6 +1123,12 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) /* default internal buffer format */ gdi->dstBpp = 32; gdi->bytesPerPixel = 4; + gdi->format = PIXEL_FORMAT_XRGB32; + + if (flags & CLRCONV_INVERT) + gdi->invert = TRUE; + + rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE; if (gdi->srcBpp > 16) { @@ -1006,14 +1137,9 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) gdi->dstBpp = 32; gdi->bytesPerPixel = 4; } - else if (flags & CLRBUF_24BPP) - { - gdi->dstBpp = 24; - gdi->bytesPerPixel = 3; - } else if (flags & CLRBUF_16BPP) { - gdi->dstBpp = 16; + gdi->dstBpp = rgb555 ? 15 : 16; gdi->bytesPerPixel = 2; } } @@ -1021,7 +1147,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) { if (flags & CLRBUF_16BPP) { - gdi->dstBpp = 16; + gdi->dstBpp = rgb555 ? 15 : 16; gdi->bytesPerPixel = 2; } else if (flags & CLRBUF_32BPP) @@ -1031,16 +1157,42 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) } } + if (!gdi->invert) + { + if (gdi->bytesPerPixel == 4) + gdi->format = PIXEL_FORMAT_XRGB32; + else if ((gdi->bytesPerPixel == 2) && (gdi->dstBpp == 16)) + gdi->format = PIXEL_FORMAT_RGB565; + else if ((gdi->bytesPerPixel == 2) && (gdi->dstBpp == 15)) + gdi->format = PIXEL_FORMAT_RGB555; + } + else + { + if (gdi->bytesPerPixel == 4) + gdi->format = PIXEL_FORMAT_XBGR32; + else if ((gdi->bytesPerPixel == 2) && (gdi->dstBpp == 16)) + gdi->format = PIXEL_FORMAT_BGR565; + else if ((gdi->bytesPerPixel == 2) && (gdi->dstBpp == 15)) + gdi->format = PIXEL_FORMAT_BGR555; + } + gdi->hdc = gdi_GetDC(); gdi->hdc->bitsPerPixel = gdi->dstBpp; gdi->hdc->bytesPerPixel = gdi->bytesPerPixel; gdi->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV)); - gdi->clrconv->alpha = (flags & CLRCONV_ALPHA) ? 1 : 0; - gdi->clrconv->invert = (flags & CLRCONV_INVERT) ? 1 : 0; - gdi->clrconv->rgb555 = (flags & CLRCONV_RGB555) ? 1 : 0; + + if (!gdi->clrconv) + return -1; + + gdi->clrconv->alpha = (flags & CLRCONV_ALPHA) ? TRUE : FALSE; + gdi->clrconv->invert = (flags & CLRCONV_INVERT) ? TRUE : FALSE; + gdi->clrconv->rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE; gdi->clrconv->palette = (rdpPalette*) malloc(sizeof(rdpPalette)); + if (!gdi->clrconv->palette) + return -1; + gdi->hdc->alpha = gdi->clrconv->alpha; gdi->hdc->invert = gdi->clrconv->invert; gdi->hdc->rgb555 = gdi->clrconv->rgb555; @@ -1066,8 +1218,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) gdi_register_graphics(instance->context->graphics); - gdi->rfx_context = rfx_context_new(FALSE); - gdi->nsc_context = nsc_context_new(); + instance->update->BitmapUpdate = gdi_bitmap_update; return 0; } @@ -1082,8 +1233,7 @@ void gdi_free(freerdp* instance) gdi_bitmap_free_ex(gdi->tile); gdi_bitmap_free_ex(gdi->image); gdi_DeleteDC(gdi->hdc); - rfx_context_free((RFX_CONTEXT*) gdi->rfx_context); - nsc_context_free((NSC_CONTEXT*) gdi->nsc_context); + _aligned_free(gdi->bitmap_buffer); free(gdi->clrconv->palette); free(gdi->clrconv); free(gdi); diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c new file mode 100644 index 000000000..f85a1e50f --- /dev/null +++ b/libfreerdp/gdi/gfx.c @@ -0,0 +1,855 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * GDI Graphics Pipeline + * + * 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 + +#define TAG FREERDP_TAG("gdi") + +int gdi_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) +{ + UINT32 DesktopWidth; + UINT32 DesktopHeight; + rdpGdi* gdi = (rdpGdi*) context->custom; + rdpUpdate* update = gdi->context->update; + rdpSettings* settings = gdi->context->settings; + + DesktopWidth = resetGraphics->width; + DesktopHeight = resetGraphics->height; + + region16_init(&(gdi->invalidRegion)); + + if ((DesktopWidth != settings->DesktopWidth) || + (DesktopHeight != settings->DesktopHeight)) + { + settings->DesktopWidth = DesktopWidth; + settings->DesktopHeight = DesktopHeight; + + if (update) + update->DesktopResize(gdi->context); + } + + gdi->graphicsReset = TRUE; + + return 1; +} + +int gdi_OutputUpdate(rdpGdi* gdi) +{ + int nDstStep; + BYTE* pDstData; + int nXDst, nYDst; + int nXSrc, nYSrc; + int nWidth, nHeight; + gdiGfxSurface* surface; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16* extents; + rdpUpdate* update = gdi->context->update; + + if (!gdi->graphicsReset) + return 1; + + pDstData = gdi->primary_buffer; + nDstStep = gdi->bytesPerPixel * gdi->width; + + surface = (gdiGfxSurface*) gdi->gfx->GetSurfaceData(gdi->gfx, gdi->outputSurfaceId); + + if (!surface) + return -1; + + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = gdi->width; + surfaceRect.bottom = gdi->height; + + region16_intersect_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &surfaceRect); + + if (!region16_is_empty(&(gdi->invalidRegion))) + { + extents = region16_extents(&(gdi->invalidRegion)); + + nXDst = extents->left; + nYDst = extents->top; + + nXSrc = extents->left; + nYSrc = extents->top; + + nWidth = extents->right - extents->left; + nHeight = extents->bottom - extents->top; + + update->BeginPaint(gdi->context); + + freerdp_image_copy(pDstData, gdi->format, nDstStep, nXDst, nYDst, nWidth, nHeight, + surface->data, surface->format, surface->scanline, nXSrc, nYSrc, NULL); + + gdi_InvalidateRegion(gdi->primary->hdc, nXDst, nYDst, nWidth, nHeight); + + update->EndPaint(gdi->context); + } + + region16_clear(&(gdi->invalidRegion)); + + return 1; +} + +int gdi_OutputExpose(rdpGdi* gdi, int x, int y, int width, int height) +{ + RECTANGLE_16 invalidRect; + + invalidRect.left = x; + invalidRect.top = y; + invalidRect.right = x + width; + invalidRect.bottom = y + height; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi->inGfxFrame = TRUE; + + return 1; +} + +int gdi_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi_OutputUpdate(gdi); + + gdi->inGfxFrame = FALSE; + + return 1; +} + +int gdi_SurfaceCommand_Uncompressed(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + freerdp_image_copy(surface->data, surface->format, surface->scanline, cmd->left, cmd->top, + cmd->width, cmd->height, cmd->data, PIXEL_FORMAT_XRGB32, cmd->width * 4, 0, 0, NULL); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_RemoteFX(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int j; + UINT16 i; + RFX_RECT* rect; + RFX_TILE* tile; + int nXDst, nYDst; + int nWidth, nHeight; + int nbUpdateRects; + RFX_MESSAGE* message; + gdiGfxSurface* surface; + REGION16 updateRegion; + RECTANGLE_16 updateRect; + RECTANGLE_16* updateRects; + REGION16 clippingRects; + RECTANGLE_16 clippingRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + message = rfx_process_message(gdi->codecs->rfx, cmd->data, cmd->length); + + if (!message) + return -1; + + region16_init(&clippingRects); + + for (i = 0; i < message->numRects; i++) + { + rect = &(message->rects[i]); + + clippingRect.left = cmd->left + rect->x; + clippingRect.top = cmd->top + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); + } + + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + + updateRect.left = cmd->left + tile->x; + updateRect.top = cmd->top + tile->y; + updateRect.right = updateRect.left + 64; + updateRect.bottom = updateRect.top + 64; + + region16_init(&updateRegion); + region16_intersect_rect(&updateRegion, &clippingRects, &updateRect); + updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects); + + for (j = 0; j < nbUpdateRects; j++) + { + nXDst = updateRects[j].left; + nYDst = updateRects[j].top; + nWidth = updateRects[j].right - updateRects[j].left; + nHeight = updateRects[j].bottom - updateRects[j].top; + + freerdp_image_copy(surface->data, surface->format, surface->scanline, + nXDst, nYDst, nWidth, nHeight, + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0, NULL); + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &updateRects[j]); + } + + region16_uninit(&updateRegion); + } + + rfx_message_free(gdi->codecs->rfx, message); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_ClearCodec(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + BYTE* DstData = NULL; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_CLEARCODEC); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = clear_decompress(gdi->codecs->clear, cmd->data, cmd->length, &DstData, + surface->format, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); + + if (status < 0) + { + WLog_ERR(TAG, "clear_decompress failure: %d", status); + return -1; + } + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + BYTE* DstData = NULL; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PLANAR); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = planar_decompress(gdi->codecs->planar, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, FALSE); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + UINT32 i; + BYTE* DstData = NULL; + H264_CONTEXT* h264; + gdiGfxSurface* surface; + RDPGFX_H264_METABLOCK* meta; + RDPGFX_H264_BITMAP_STREAM* bs; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_H264); + + h264 = gdi->codecs->h264; + + bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; + + if (!bs) + return -1; + + meta = &(bs->meta); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + + status = h264_decompress(gdi->codecs->h264, bs->data, bs->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline , surface->height, meta->regionRects, meta->numRegionRects); + + if (status < 0) + { + WLog_ERR(TAG, "h264_decompress failure: %d",status); + return -1; + } + + for (i = 0; i < meta->numRegionRects; i++) + { + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), (RECTANGLE_16*) &(meta->regionRects[i])); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Alpha(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_ALPHACODEC); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + WLog_DBG(TAG, "gdi_SurfaceCommand_Alpha: status: %d", status); + + /* fill with green for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0x00FF00); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand_Progressive(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int i, j; + int status; + BYTE* DstData; + RFX_RECT* rect; + int nXDst, nYDst; + int nXSrc, nYSrc; + int nWidth, nHeight; + int nbUpdateRects; + gdiGfxSurface* surface; + REGION16 updateRegion; + RECTANGLE_16 updateRect; + RECTANGLE_16* updateRects; + REGION16 clippingRects; + RECTANGLE_16 clippingRect; + RFX_PROGRESSIVE_TILE* tile; + PROGRESSIVE_BLOCK_REGION* region; + + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PROGRESSIVE); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + progressive_create_surface_context(gdi->codecs->progressive, cmd->surfaceId, surface->width, surface->height); + + DstData = surface->data; + + status = progressive_decompress(gdi->codecs->progressive, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, cmd->surfaceId); + + if (status < 0) + { + WLog_ERR(TAG, "progressive_decompress failure: %d", status); + return -1; + } + + region = &(gdi->codecs->progressive->region); + + region16_init(&clippingRects); + + for (i = 0; i < region->numRects; i++) + { + rect = &(region->rects[i]); + + clippingRect.left = cmd->left + rect->x; + clippingRect.top = cmd->top + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); + } + + for (i = 0; i < region->numTiles; i++) + { + tile = region->tiles[i]; + + updateRect.left = cmd->left + tile->x; + updateRect.top = cmd->top + tile->y; + updateRect.right = updateRect.left + 64; + updateRect.bottom = updateRect.top + 64; + + region16_init(&updateRegion); + region16_intersect_rect(&updateRegion, &clippingRects, &updateRect); + updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects); + + for (j = 0; j < nbUpdateRects; j++) + { + nXDst = updateRects[j].left; + nYDst = updateRects[j].top; + nWidth = updateRects[j].right - updateRects[j].left; + nHeight = updateRects[j].bottom - updateRects[j].top; + + nXSrc = nXDst - (cmd->left + tile->x); + nYSrc = nYDst - (cmd->top + tile->y); + + freerdp_image_copy(surface->data, surface->format, + surface->scanline, nXDst, nYDst, nWidth, nHeight, + tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL); + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &updateRects[j]); + } + + region16_uninit(&updateRegion); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 1; + rdpGdi* gdi = (rdpGdi*) context->custom; + + switch (cmd->codecId) + { + case RDPGFX_CODECID_UNCOMPRESSED: + status = gdi_SurfaceCommand_Uncompressed(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAVIDEO: + status = gdi_SurfaceCommand_RemoteFX(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CLEARCODEC: + status = gdi_SurfaceCommand_ClearCodec(gdi, context, cmd); + break; + + case RDPGFX_CODECID_PLANAR: + status = gdi_SurfaceCommand_Planar(gdi, context, cmd); + break; + + case RDPGFX_CODECID_H264: + status = gdi_SurfaceCommand_H264(gdi, context, cmd); + break; + + case RDPGFX_CODECID_ALPHA: + status = gdi_SurfaceCommand_Alpha(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAPROGRESSIVE: + status = gdi_SurfaceCommand_Progressive(gdi, context, cmd); + break; + + case RDPGFX_CODECID_CAPROGRESSIVE_V2: + break; + } + + return 1; +} + +int gdi_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext) +{ + return 1; +} + +int gdi_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface) +{ + gdiGfxSurface* surface; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) calloc(1, sizeof(gdiGfxSurface)); + + if (!surface) + return -1; + + surface->surfaceId = createSurface->surfaceId; + surface->width = (UINT32) createSurface->width; + surface->height = (UINT32) createSurface->height; + surface->alpha = (createSurface->pixelFormat == PIXEL_FORMAT_ARGB_8888) ? TRUE : FALSE; + + surface->format = (!gdi->invert) ? PIXEL_FORMAT_XRGB32 : PIXEL_FORMAT_XBGR32; + + surface->scanline = (surface->width + (surface->width % 4)) * 4; + surface->data = (BYTE*) calloc(1, surface->scanline * surface->height); + + if (!surface->data) + return -1; + + context->SetSurfaceData(context, surface->surfaceId, (void*) surface); + + return 1; +} + +int gdi_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface) +{ + gdiGfxSurface* surface; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId); + + if (surface) + { + free(surface->data); + free(surface); + } + + context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); + + if (gdi->codecs->progressive) + progressive_delete_surface_context(gdi->codecs->progressive, deleteSurface->surfaceId); + + return 1; +} + +int gdi_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) +{ + UINT16 index; + UINT32 color; + BYTE a, r, g, b; + int nWidth, nHeight; + RDPGFX_RECT16* rect; + gdiGfxSurface* surface; + RECTANGLE_16 invalidRect; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, solidFill->surfaceId); + + if (!surface) + return -1; + + b = solidFill->fillPixel.B; + g = solidFill->fillPixel.G; + r = solidFill->fillPixel.R; + a = solidFill->fillPixel.XA; + + if (!gdi->invert) + color = ARGB32(a, r, g, b); + else + color = ABGR32(a, r, g, b); + + for (index = 0; index < solidFill->fillRectCount; index++) + { + rect = &(solidFill->fillRects[index]); + + nWidth = rect->right - rect->left; + nHeight = rect->bottom - rect->top; + + invalidRect.left = rect->left; + invalidRect.top = rect->top; + invalidRect.right = rect->right; + invalidRect.bottom = rect->bottom; + + freerdp_image_fill(surface->data, surface->format, surface->scanline, + rect->left, rect->top, nWidth, nHeight, color); + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface) +{ + UINT16 index; + BOOL sameSurface; + int nWidth, nHeight; + RDPGFX_RECT16* rectSrc; + RDPGFX_POINT16* destPt; + RECTANGLE_16 invalidRect; + gdiGfxSurface* surfaceSrc; + gdiGfxSurface* surfaceDst; + rdpGdi* gdi = (rdpGdi*) context->custom; + + rectSrc = &(surfaceToSurface->rectSrc); + destPt = &surfaceToSurface->destPts[0]; + + surfaceSrc = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc); + + sameSurface = (surfaceToSurface->surfaceIdSrc == surfaceToSurface->surfaceIdDest) ? TRUE : FALSE; + + if (!sameSurface) + surfaceDst = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest); + else + surfaceDst = surfaceSrc; + + if (!surfaceSrc || !surfaceDst) + return -1; + + nWidth = rectSrc->right - rectSrc->left; + nHeight = rectSrc->bottom - rectSrc->top; + + for (index = 0; index < surfaceToSurface->destPtsCount; index++) + { + destPt = &surfaceToSurface->destPts[index]; + + if (sameSurface) + { + freerdp_image_move(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, + destPt->x, destPt->y, nWidth, nHeight, rectSrc->left, rectSrc->top); + } + else + { + freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, + destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, surfaceSrc->format, + surfaceSrc->scanline, rectSrc->left, rectSrc->top, NULL); + } + + invalidRect.left = destPt->x; + invalidRect.top = destPt->y; + invalidRect.right = destPt->x + rectSrc->right; + invalidRect.bottom = destPt->y + rectSrc->bottom; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) +{ + RDPGFX_RECT16* rect; + gdiGfxSurface* surface; + gdiGfxCacheEntry* cacheEntry; + rdpGdi* gdi = (rdpGdi*) context->custom; + + rect = &(surfaceToCache->rectSrc); + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId); + + if (!surface) + return -1; + + cacheEntry = (gdiGfxCacheEntry*) calloc(1, sizeof(gdiGfxCacheEntry)); + + if (!cacheEntry) + return -1; + + cacheEntry->width = (UINT32) (rect->right - rect->left); + cacheEntry->height = (UINT32) (rect->bottom - rect->top); + cacheEntry->alpha = surface->alpha; + + cacheEntry->format = (!gdi->invert) ? PIXEL_FORMAT_XRGB32 : PIXEL_FORMAT_XBGR32; + + cacheEntry->scanline = (cacheEntry->width + (cacheEntry->width % 4)) * 4; + cacheEntry->data = (BYTE*) calloc(1, cacheEntry->scanline * cacheEntry->height); + + if (!cacheEntry->data) + return -1; + + freerdp_image_copy(cacheEntry->data, cacheEntry->format, cacheEntry->scanline, + 0, 0, cacheEntry->width, cacheEntry->height, surface->data, + surface->format, surface->scanline, rect->left, rect->top, NULL); + + context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (void*) cacheEntry); + + return 1; +} + +int gdi_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface) +{ + UINT16 index; + RDPGFX_POINT16* destPt; + gdiGfxSurface* surface; + gdiGfxCacheEntry* cacheEntry; + RECTANGLE_16 invalidRect; + rdpGdi* gdi = (rdpGdi*) context->custom; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId); + cacheEntry = (gdiGfxCacheEntry*) context->GetCacheSlotData(context, cacheToSurface->cacheSlot); + + if (!surface || !cacheEntry) + return -1; + + for (index = 0; index < cacheToSurface->destPtsCount; index++) + { + destPt = &cacheToSurface->destPts[index]; + + freerdp_image_copy(surface->data, surface->format, surface->scanline, + destPt->x, destPt->y, cacheEntry->width, cacheEntry->height, + cacheEntry->data, cacheEntry->format, cacheEntry->scanline, 0, 0, NULL); + + invalidRect.left = destPt->x; + invalidRect.top = destPt->y; + invalidRect.right = destPt->x + cacheEntry->width - 1; + invalidRect.bottom = destPt->y + cacheEntry->height - 1; + + region16_union_rect(&(gdi->invalidRegion), &(gdi->invalidRegion), &invalidRect); + } + + if (!gdi->inGfxFrame) + gdi_OutputUpdate(gdi); + + return 1; +} + +int gdi_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply) +{ + return 1; +} + +int gdi_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry) +{ + gdiGfxCacheEntry* cacheEntry; + + cacheEntry = (gdiGfxCacheEntry*) context->GetCacheSlotData(context, evictCacheEntry->cacheSlot); + + if (cacheEntry) + { + free(cacheEntry->data); + free(cacheEntry); + } + + context->SetCacheSlotData(context, evictCacheEntry->cacheSlot, NULL); + + return 1; +} + +int gdi_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) +{ + rdpGdi* gdi = (rdpGdi*) context->custom; + + gdi->outputSurfaceId = surfaceToOutput->surfaceId; + + return 1; +} + +int gdi_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow) +{ + return 1; +} + +void gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx) +{ + gdi->gfx = gfx; + gfx->custom = (void*) gdi; + + gfx->ResetGraphics = gdi_ResetGraphics; + gfx->StartFrame = gdi_StartFrame; + gfx->EndFrame = gdi_EndFrame; + gfx->SurfaceCommand = gdi_SurfaceCommand; + gfx->DeleteEncodingContext = gdi_DeleteEncodingContext; + gfx->CreateSurface = gdi_CreateSurface; + gfx->DeleteSurface = gdi_DeleteSurface; + gfx->SolidFill = gdi_SolidFill; + gfx->SurfaceToSurface = gdi_SurfaceToSurface; + gfx->SurfaceToCache = gdi_SurfaceToCache; + gfx->CacheToSurface = gdi_CacheToSurface; + gfx->CacheImportReply = gdi_CacheImportReply; + gfx->EvictCacheEntry = gdi_EvictCacheEntry; + gfx->MapSurfaceToOutput = gdi_MapSurfaceToOutput; + gfx->MapSurfaceToWindow = gdi_MapSurfaceToWindow; + + region16_init(&(gdi->invalidRegion)); +} + +void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx) +{ + region16_uninit(&(gdi->invalidRegion)); + + gdi->gfx = NULL; + gfx->custom = NULL; +} + diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c index 084c1b17c..6c7bd881f 100644 --- a/libfreerdp/gdi/graphics.c +++ b/libfreerdp/gdi/graphics.c @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -40,15 +41,66 @@ #include "graphics.h" +#define TAG FREERDP_TAG("gdi") /* Bitmap Class */ -HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, int width, int height, int bpp, BYTE* data) +HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, int nWidth, int nHeight, int bpp, BYTE* data) { - BYTE* bmpData; + int nSrcStep; + int nDstStep; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcFormat; + int bytesPerPixel; HGDI_BITMAP bitmap; - bmpData = freerdp_image_convert(data, NULL, width, height, gdi->srcBpp, bpp, gdi->clrconv); - bitmap = gdi_CreateBitmap(width, height, gdi->dstBpp, bmpData); + nDstStep = nWidth * gdi->bytesPerPixel; + pDstData = _aligned_malloc(nHeight * nDstStep, 16); + + if (!pDstData) + return NULL; + + pSrcData = data; + + switch (bpp) + { + case 32: + bytesPerPixel = 4; + SrcFormat = PIXEL_FORMAT_XRGB32; + break; + + case 24: + bytesPerPixel = 3; + SrcFormat = PIXEL_FORMAT_RGB24; + break; + + case 16: + bytesPerPixel = 2; + SrcFormat = PIXEL_FORMAT_RGB565; + break; + + case 15: + bytesPerPixel = 2; + SrcFormat = PIXEL_FORMAT_RGB555; + break; + + case 8: + bytesPerPixel = 1; + SrcFormat = PIXEL_FORMAT_RGB8; + break; + + default: + SrcFormat = PIXEL_FORMAT_RGB565; + bytesPerPixel = 2; + break; + } + + nSrcStep = nWidth * bytesPerPixel; + + freerdp_image_copy(pDstData, gdi->format, nDstStep, 0, 0, + nWidth, nHeight, pSrcData, SrcFormat, nSrcStep, 0, 0, gdi->palette); + + bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstBpp, pDstData); return bitmap; } @@ -61,10 +113,10 @@ void gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) gdi_bitmap = (gdiBitmap*) bitmap; gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc); - if (bitmap->data == NULL) + if (!bitmap->data) gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, bitmap->width, bitmap->height); else - gdi_bitmap->bitmap = gdi_create_bitmap(gdi, bitmap->width, bitmap->height, gdi->dstBpp, bitmap->data); + gdi_bitmap->bitmap = gdi_create_bitmap(gdi, bitmap->width, bitmap->height, bitmap->bpp, bitmap->data); gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT) gdi_bitmap->bitmap); gdi_bitmap->org_bitmap = NULL; @@ -74,7 +126,7 @@ void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) { gdiBitmap* gdi_bitmap = (gdiBitmap*) bitmap; - if (gdi_bitmap != NULL) + if (gdi_bitmap) { gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT) gdi_bitmap->org_bitmap); gdi_DeleteObject((HGDIOBJECT) gdi_bitmap->bitmap); @@ -98,85 +150,58 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codecId) { - BOOL status; + int status; UINT16 size; - BYTE* src; - BYTE* dst; - int yindex; - int xindex; - rdpGdi* gdi; - RFX_MESSAGE* msg; + BYTE* pSrcData; + BYTE* pDstData; + UINT32 SrcSize; + UINT32 SrcFormat; + UINT32 bytesPerPixel; + rdpGdi* gdi = context->gdi; - size = width * height * ((bpp + 7) / 8); + bytesPerPixel = (bpp + 7) / 8; + size = width * height * 4; - if (!bitmap->data) - bitmap->data = (BYTE*) malloc(size); - else - bitmap->data = (BYTE*) realloc(bitmap->data, size); + bitmap->data = (BYTE*) _aligned_malloc(size, 16); - switch (codecId) + pSrcData = data; + SrcSize = (UINT32) length; + pDstData = bitmap->data; + + if (compressed) { - case RDP_CODEC_ID_NSCODEC: - gdi = context->gdi; - nsc_process_message(gdi->nsc_context, bpp, width, height, data, length); - freerdp_image_flip(((NSC_CONTEXT*) gdi->nsc_context)->BitmapData, bitmap->data, width, height, bpp); - break; + if (bpp < 32) + { + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_INTERLEAVED); - case RDP_CODEC_ID_REMOTEFX: - gdi = context->gdi; - rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(gdi->rfx_context, data, length); - if (!msg) - { - fprintf(stderr, "gdi_Bitmap_Decompress: rfx Decompression Failed\n"); - } - else - { - for (yindex = 0; yindex < height; yindex++) - { - src = msg->tiles[0]->data + yindex * 64 * 4; - dst = bitmap->data + yindex * width * 3; - for (xindex = 0; xindex < width; xindex++) - { - *(dst++) = *(src++); - *(dst++) = *(src++); - *(dst++) = *(src++); - src++; - } - } - rfx_message_free(gdi->rfx_context, msg); - } - break; - case RDP_CODEC_ID_JPEG: -#ifdef WITH_JPEG - if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) - { - fprintf(stderr, "gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); - } -#endif - break; - default: - if (compressed) - { - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + status = interleaved_decompress(gdi->codecs->interleaved, pSrcData, SrcSize, bpp, + &pDstData, gdi->format, -1, 0, 0, width, height, gdi->palette); + } + else + { + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PLANAR); - if (!status) - { - fprintf(stderr, "gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); - } - } - else - { - freerdp_image_flip(data, bitmap->data, width, height, bpp); - } - break; + status = planar_decompress(gdi->codecs->planar, pSrcData, SrcSize, &pDstData, + gdi->format, -1, 0, 0, width, height, TRUE); + } + + if (status < 0) + { + WLog_ERR(TAG, "Bitmap Decompression Failed"); + return; + } + } + else + { + SrcFormat = gdi_get_pixel_format(bpp, TRUE); + + status = freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, + width, height, pSrcData, SrcFormat, -1, 0, 0, gdi->palette); } - bitmap->width = width; - bitmap->height = height; bitmap->compressed = FALSE; bitmap->length = size; - bitmap->bpp = bpp; + bitmap->bpp = gdi->dstBpp; } void gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) @@ -217,7 +242,7 @@ void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph) gdi_glyph = (gdiGlyph*) glyph; - if (gdi_glyph != 0) + if (gdi_glyph) { gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT) gdi_glyph->org_bitmap); gdi_DeleteObject((HGDIOBJECT) gdi_glyph->bitmap); @@ -242,8 +267,8 @@ void gdi_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int heigh HGDI_BRUSH brush; rdpGdi* gdi = context->gdi; - bgcolor = freerdp_color_convert_var_bgr(bgcolor, gdi->srcBpp, 32, gdi->clrconv); - fgcolor = freerdp_color_convert_var_bgr(fgcolor, gdi->srcBpp, 32, gdi->clrconv); + bgcolor = freerdp_convert_gdi_order_color(bgcolor, gdi->srcBpp, gdi->format, gdi->palette); + fgcolor = freerdp_convert_gdi_order_color(fgcolor, gdi->srcBpp, gdi->format, gdi->palette); gdi_CRgnToRect(x, y, width, height, &rect); @@ -258,7 +283,7 @@ void gdi_Glyph_EndDraw(rdpContext* context, int x, int y, int width, int height, { rdpGdi* gdi = context->gdi; - bgcolor = freerdp_color_convert_var_bgr(bgcolor, gdi->srcBpp, 32, gdi->clrconv); + bgcolor = freerdp_convert_gdi_order_color(bgcolor, gdi->srcBpp, gdi->format, gdi->palette); gdi->textColor = gdi_SetTextColor(gdi->drawing->hdc, bgcolor); } diff --git a/libfreerdp/gdi/region.c b/libfreerdp/gdi/region.c index a0869f99e..ec7345cc0 100644 --- a/libfreerdp/gdi/region.c +++ b/libfreerdp/gdi/region.c @@ -371,15 +371,15 @@ INLINE int gdi_InvalidateRegion(HGDI_DC hdc, int x, int y, int w, int h) HGDI_RGN invalid; HGDI_RGN cinvalid; - if (hdc->hwnd == NULL) + if (!hdc->hwnd) return 0; - if (hdc->hwnd->invalid == NULL) + if (!hdc->hwnd->invalid) return 0; cinvalid = hdc->hwnd->cinvalid; - if (hdc->hwnd->ninvalid + 1 > hdc->hwnd->count) + if ((hdc->hwnd->ninvalid + 1) > hdc->hwnd->count) { hdc->hwnd->count *= 2; cinvalid = (HGDI_RGN) realloc(cinvalid, sizeof(GDI_RGN) * (hdc->hwnd->count)); diff --git a/libfreerdp/gdi/test/CMakeLists.txt b/libfreerdp/gdi/test/CMakeLists.txt index 48e5a9125..8f9845bf1 100644 --- a/libfreerdp/gdi/test/CMakeLists.txt +++ b/libfreerdp/gdi/test/CMakeLists.txt @@ -21,19 +21,7 @@ include_directories(..) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-gdi) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/libfreerdp/locale/CMakeLists.txt b/libfreerdp/locale/CMakeLists.txt index a3a844876..f6bdf73f8 100644 --- a/libfreerdp/locale/CMakeLists.txt +++ b/libfreerdp/locale/CMakeLists.txt @@ -44,13 +44,13 @@ if(CMAKE_SYSTEM_NAME MATCHES Solaris) endif() if(WITH_X11) - add_definitions(-DWITH_X11) - include_directories(${X11_INCLUDE_DIRS}) + freerdp_definition_add(-DWITH_X11) + freerdp_include_directory_add(${X11_INCLUDE_DIRS}) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_X11_SRCS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${X11_LIBRARIES}) + freerdp_library_add(${X11_LIBRARIES}) if(WITH_SUN) - add_definitions(-DWITH_SUN) + freerdp_definition_add(-DWITH_SUN) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_SUN_SRCS}) endif() @@ -61,37 +61,13 @@ if(WITH_X11) find_feature(XKBFile ${XKBFILE_FEATURE_TYPE} ${XKBFILE_FEATURE_PURPOSE} ${XKBFILE_FEATURE_DESCRIPTION}) if(WITH_XKBFILE AND (NOT APPLE)) - add_definitions(-DWITH_XKBFILE) - include_directories(${XKBFILE_INCLUDE_DIRS}) + freerdp_definition_add(-DWITH_XKBFILE) + freerdp_include_directory_add(${XKBFILE_INCLUDE_DIRS}) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_XKBFILE_SRCS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XKBFILE_LIBRARIES}) + freerdp_library_add(${XKBFILE_LIBRARIES}) else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_X11_KEYMAP_SRCS}) endif() endif() -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-input winpr-crt) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") +freerdp_module_add(${${MODULE_PREFIX}_SRCS}) diff --git a/libfreerdp/locale/keyboard_layout.c b/libfreerdp/locale/keyboard_layout.c index 3869358cc..df902bef6 100644 --- a/libfreerdp/locale/keyboard_layout.c +++ b/libfreerdp/locale/keyboard_layout.c @@ -120,6 +120,7 @@ static const RDP_KEYBOARD_LAYOUT RDP_KEYBOARD_LAYOUT_TABLE[] = { KBD_CANADIAN_FRENCH_LEGACY, "Canadian French (legacy)" }, { KBD_SERBIAN_CYRILLIC, "Serbian (Cyrillic)" }, { KBD_CANADIAN_FRENCH, "Canadian French" }, + { KBD_CANADIAN_ENGLISH, "Canadian English" }, { KBD_SWISS_FRENCH, "Swiss French" }, { KBD_BOSNIAN, "Bosnian" }, { KBD_IRISH, "Irish" }, diff --git a/libfreerdp/locale/keyboard_xkbfile.c b/libfreerdp/locale/keyboard_xkbfile.c index 8387d2736..a2b4ff210 100644 --- a/libfreerdp/locale/keyboard_xkbfile.c +++ b/libfreerdp/locale/keyboard_xkbfile.c @@ -345,7 +345,7 @@ int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId, DWORD x11_keycode_to_ if (*keyboardLayoutId == 0) { detect_keyboard_layout_from_xkbfile(display, keyboardLayoutId); - DEBUG_KBD("detect_keyboard_layout_from_xkb: %X", (unsigned int) keyboardLayoutId); + DEBUG_KBD("detect_keyboard_layout_from_xkb: %p", keyboardLayoutId); } freerdp_keyboard_load_map_from_xkbfile(display, x11_keycode_to_rdp_scancode); diff --git a/libfreerdp/locale/liblocale.h b/libfreerdp/locale/liblocale.h index 27c0987c9..f88357640 100644 --- a/libfreerdp/locale/liblocale.h +++ b/libfreerdp/locale/liblocale.h @@ -24,18 +24,20 @@ #include "config.h" #endif -#include +#include +#define KBD_TAG FREERDP_TAG("locale") #ifdef WITH_DEBUG_KBD -#define DEBUG_KBD(fmt, ...) DEBUG_CLASS(KBD, fmt, ## __VA_ARGS__) +#define DEBUG_KBD(fmt, ...) WLog_DBG(KBD_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_KBD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_KBD(fmt, ...) do { } while (0) #endif +#define TIMEZONE_TAG FREERDP_TAG("timezone") #ifdef WITH_DEBUG_TIMEZONE -#define DEBUG_TIMEZONE(fmt, ...) DEBUG_CLASS(TIMEZONE, fmt, ## __VA_ARGS__) +#define DEBUG_TIMEZONE(fmt, ...) WLog_DBG(TIMEZONE_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_TIMEZONE(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_TIMEZONE(fmt, ...) do { } while (0) #endif #endif /* __LIBLOCALE_H */ diff --git a/libfreerdp/locale/timezone.c b/libfreerdp/locale/timezone.c index b83471a82..ead84324d 100644 --- a/libfreerdp/locale/timezone.c +++ b/libfreerdp/locale/timezone.c @@ -30,10 +30,12 @@ #include "liblocale.h" +#include #include - #include +#define TAG FREERDP_TAG("locale") + /* Time Zone Redirection table generated with TimeZones.cs script */ @@ -1565,7 +1567,7 @@ char* freerdp_get_unix_timezone_identifier() return tzid; } - fprintf(stderr, "Unable to detect time zone\n"); + WLog_ERR(TAG, "Unable to detect time zone"); return tzid; #else return 0; @@ -1626,7 +1628,7 @@ TIME_ZONE_ENTRY* freerdp_detect_windows_time_zone(UINT32 bias) } } - fprintf(stderr, "Unable to find a match for unix timezone: %s\n", tzid); + WLog_ERR(TAG, "Unable to find a match for unix timezone: %s", tzid); free(tzid); return NULL; } @@ -1642,12 +1644,12 @@ TIME_ZONE_RULE_ENTRY* freerdp_get_current_time_zone_rule(TIME_ZONE_RULE_ENTRY* r { if ((rules[i].TicksStart >= windows_time) && (windows_time >= rules[i].TicksEnd)) { - /*fprintf(stderr, "Got rule %d from table at %p with count %u\n", i, rules, count);*/ + /*WLog_ERR(TAG, "Got rule %d from table at %p with count %u", i, rules, count);*/ return &rules[i]; } } - fprintf(stderr, "Unable to get current timezone rule\n"); + WLog_ERR(TAG, "Unable to get current timezone rule"); return NULL; } diff --git a/libfreerdp/locale/xkb_layout_ids.c b/libfreerdp/locale/xkb_layout_ids.c index 75ae0419b..fc67b2707 100644 --- a/libfreerdp/locale/xkb_layout_ids.c +++ b/libfreerdp/locale/xkb_layout_ids.c @@ -208,15 +208,16 @@ static const XKB_VARIANT ma_variants[] = /* Canada */ static const XKB_VARIANT ca_variants[] = { + { "fr", KBD_CANADIAN_FRENCH }, /* French Dvorak */ { "fr-dvorak", KBD_UNITED_STATES_DVORAK }, /* French Dvorak */ - { "fr-legacy", KBD_CANADIAN_FRENCH }, /* French (legacy) */ + { "fr-legacy", KBD_CANADIAN_FRENCH_LEGACY }, /* French (legacy) */ { "multix", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual */ { "multi", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual, first part */ { "multi-2gr", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Multilingual, second part */ { "ike", KBD_INUKTITUT_LATIN }, /* Inuktitut */ { "shs", 0 }, /* Secwepemctsin */ { "kut", 0 }, /* Ktunaxa */ - { "eng", KBD_US }, /* English */ + { "eng", KBD_CANADIAN_ENGLISH }, /* English */ { "", 0 }, }; diff --git a/libfreerdp/primitives/CMakeLists.txt b/libfreerdp/primitives/CMakeLists.txt deleted file mode 100644 index a35b24d73..000000000 --- a/libfreerdp/primitives/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Client -# libfreerdp-primitives cmake build script -# vi:ts=4 sw=4: -# -# (c) Copyright 2012 Hewlett-Packard Development Company, L.P. -# 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. -# - -set(MODULE_NAME "freerdp-primitives") -set(MODULE_PREFIX "FREERDP_PRIMITIVES") - -set(${MODULE_PREFIX}_SRCS - prim_add.c - prim_andor.c - prim_alphaComp.c - prim_colors.c - prim_copy.c - prim_set.c - prim_shift.c - prim_sign.c - primitives.c - prim_internal.h) - -set(${MODULE_PREFIX}_OPT_SRCS - prim_add_opt.c - prim_andor_opt.c - prim_alphaComp_opt.c - prim_colors_opt.c - prim_set_opt.c - prim_shift_opt.c - prim_sign_opt.c) - -add_definitions(-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) - -### IPP Variable debugging -if(WITH_IPP) - if(CMAKE_COMPILER_IS_GNUCC) - foreach(INCLDIR ${IPP_INCLUDE_DIRS}) - set(OPTIMIZATION "${OPTIMIZATION} -I${INCLDIR}") - endforeach(INCLDIR) - endif() -endif() - -if(WITH_SSE2) - if(CMAKE_COMPILER_IS_GNUCC) - set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -Wdeclaration-after-statement") - endif() - - if(MSVC) - set(OPTIMIZATION "${OPTIMIZATION} /arch:SSE2") - endif() -elseif(WITH_NEON) - if(CMAKE_COMPILER_IS_GNUCC) - set(OPTIMIZATION "${OPTIMIZATION} -mfpu=neon -mfloat-abi=${ARM_FP_ABI}") - endif() - # TODO: Add MSVC equivalent -endif() - -set_property(SOURCE ${${MODULE_PREFIX}_OPT_SRCS} PROPERTY COMPILE_FLAGS ${OPTIMIZATION}) - -set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_OPT_SRCS}) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -if(IPP_FOUND) - include_directories(${IPP_INCLUDE_DIRS}) - foreach(ipp_lib ${IPP_LIBRARIES}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} "${ipp_lib}_imported") - endforeach() -endif() - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sysinfo) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - -if(BUILD_TESTING AND ((NOT WIN32) AND (NOT APPLE))) -# add_subdirectory(test) -endif() - diff --git a/libfreerdp/primitives/prim_16to32bpp.c b/libfreerdp/primitives/prim_16to32bpp.c new file mode 100644 index 000000000..a9110558b --- /dev/null +++ b/libfreerdp/primitives/prim_16to32bpp.c @@ -0,0 +1,137 @@ +/* prim_16to32bpp.c + * 16-bit to 32-bit color conversion (widely used) + * vi:ts=4 sw=4: + * + * The general routine was leveraged from freerdp/codec/color.c. + * + * Copyright 2010 Marc-Andre Moreau + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 "prim_internal.h" +#include "prim_16to32bpp.h" + +/* ------------------------------------------------------------------------- */ +pstatus_t general_RGB565ToARGB_16u32u_C3C4( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert) +{ + const UINT16* src16; + UINT32* dst32; + int x,y; + int srcRowBump, dstRowBump; + BYTE red, green, blue; + + src16 = pSrc; + dst32 = pDst; + srcRowBump = (srcStep - (width * sizeof(UINT16))) / sizeof(UINT16); + dstRowBump = (dstStep - (width * sizeof(UINT32))) / sizeof(UINT32); + + /* Loops are separated so if-decisions are not made in the loop. */ + if (alpha) + { + if (invert) + { + for (y=0; yRGB565ToARGB_16u32u_C3C4 = general_RGB565ToARGB_16u32u_C3C4; + + primitives_init_16to32bpp_opt(prims); +} + +/* ------------------------------------------------------------------------- */ +void primitives_deinit_16to32bpp( + primitives_t *prims) +{ + /* Nothing to do. */ +} diff --git a/libfreerdp/primitives/prim_16to32bpp.h b/libfreerdp/primitives/prim_16to32bpp.h new file mode 100644 index 000000000..80a3cd735 --- /dev/null +++ b/libfreerdp/primitives/prim_16to32bpp.h @@ -0,0 +1,36 @@ +/* FreeRDP: A Remote Desktop Protocol Client + * 16-bit to 32-bit color conversions + * vi:ts=4 sw=4 + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 __GNUC__ +# pragma once +#endif + +#ifndef __PRIM_16TO32BPP_H_INCLUDED__ +#define __PRIM_16TO32BPP_H_INCLUDED__ + +#include + +extern pstatus_t general_RGB565ToARGB_16u32u_C3C4( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert); +extern void primitives_init_16to32bpp_opt(primitives_t* prims); + +#endif /* !__PRIM_16TO32BPP_H_INCLUDED__ */ diff --git a/libfreerdp/primitives/prim_16to32bpp_opt.c b/libfreerdp/primitives/prim_16to32bpp_opt.c new file mode 100644 index 000000000..a37e3e3f8 --- /dev/null +++ b/libfreerdp/primitives/prim_16to32bpp_opt.c @@ -0,0 +1,280 @@ +/* prim_16to32bpp_opt.c + * 16-bit to 32-bit color conversion via SSE/Neon + * vi:ts=4 sw=4: + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#ifdef WITH_SSE2 +#include +#include +/* #elif defined(WITH_NEON) */ +/* #include */ +#endif /* WITH_SSE2 */ + +#include "prim_internal.h" +#include "prim_16to32bpp.h" + +#ifdef WITH_SSE2 +/* ------------------------------------------------------------------------- */ +/* Note: _no_invert and _invert could be coded with variables as shift + * amounts and a single routine, but tests showed that was much slower. + */ +static pstatus_t sse3_RGB565ToARGB_16u32u_C3C4_no_invert( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha) +{ + const BYTE *src = (const BYTE *) pSrc; + BYTE *dst = (BYTE *) pDst; + int h; + int srcRowBump = srcStep - (width * sizeof(UINT16)); + int dstRowBump = dstStep - (width * sizeof(UINT32)); + __m128i R0, R1, R2, R_FC00, R_0300, R_00F8, R_0007, R_alpha; + + R_FC00 = _mm_set1_epi16(0xFC00); + R_0300 = _mm_set1_epi16(0x0300); + R_00F8 = _mm_set1_epi16(0x00F8); + R_0007 = _mm_set1_epi16(0x0007); + if (alpha) R_alpha = _mm_set1_epi32(0xFF00FF00U); + else R_alpha = _mm_set1_epi32(0x00000000U); + + for (h=0; h width) startup = width; + general_RGB565ToARGB_16u32u_C3C4((const UINT16*) src, srcStep, + (UINT32*) dst, dstStep, startup, 1, alpha, FALSE); + src += startup * sizeof(UINT16); + dst += startup * sizeof(UINT32); + w -= startup; + } + + /* The main loop handles eight pixels at a time. */ + while (w >= 8) + { + /* If off-stride, use the slower load. */ + if ((ULONG_PTR) src & 0x0f) + R0 = _mm_lddqu_si128((__m128i *) src); + else + R0 = _mm_load_si128((__m128i *) src); + src += (128/8); + + /* Do the lower two colors, which end up in the lower two bytes. */ + /* G = ((P<<5) & 0xFC00) | ((P>>1) & 0x0300) */ + R2 = _mm_slli_epi16(R0, 5); + R2 = _mm_and_si128(R_FC00, R2); + + R1 = _mm_srli_epi16(R0, 1); + R1 = _mm_and_si128(R_0300, R1); + R2 = _mm_or_si128(R1, R2); + + /* R = ((P<<3) & 0x00F8) | ((P>>2) & 0x0007) */ + R1 = _mm_slli_epi16(R0, 3); + R1 = _mm_and_si128(R_00F8, R1); + R2 = _mm_or_si128(R1, R2); + + R1 = _mm_srli_epi16(R0, 2); + R1 = _mm_and_si128(R_0007, R1); + R2 = _mm_or_si128(R1, R2); /* R2 = lowers */ + + /* Handle the upper color. */ + /* B = ((P<<8) & 0x00F8) | ((P<<13) & 0x0007) */ + R1 = _mm_srli_epi16(R0, 8); + R1 = _mm_and_si128(R_00F8, R1); + + R0 = _mm_srli_epi16(R0, 13); + R0 = _mm_and_si128(R_0007, R0); + R1 = _mm_or_si128(R0, R1); /* R1 = uppers */ + + /* Add alpha (or zero) . */ + R1 = _mm_or_si128(R_alpha, R1); /* + alpha */ + + /* Unpack to intermix the AB and GR pieces. */ + R0 = _mm_unpackhi_epi16(R2, R1); + R2 = _mm_unpacklo_epi16(R2, R1); + + /* Store the results. */ + _mm_store_si128((__m128i *) dst, R2); dst += (128/8); + _mm_store_si128((__m128i *) dst, R0); dst += (128/8); + w -= 8; + } + + /* Handle any remainder. */ + if (w > 0) + { + general_RGB565ToARGB_16u32u_C3C4((const UINT16*) src, srcStep, + (UINT32*) dst, dstStep, w, 1, alpha, FALSE); + src += w * sizeof(UINT16); + dst += w * sizeof(UINT32); + } + + /* Bump to the start of the next row. */ + src += srcRowBump; + dst += dstRowBump; + } + + return PRIMITIVES_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ +static pstatus_t sse3_RGB565ToARGB_16u32u_C3C4_invert( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha) +{ + const BYTE *src = (const BYTE *) pSrc; + BYTE *dst = (BYTE *) pDst; + int h; + int srcRowBump = srcStep - (width * sizeof(UINT16)); + int dstRowBump = dstStep - (width * sizeof(UINT32)); + __m128i R0, R1, R2, R_FC00, R_0300, R_00F8, R_0007, R_alpha; + + R_FC00 = _mm_set1_epi16(0xFC00); + R_0300 = _mm_set1_epi16(0x0300); + R_00F8 = _mm_set1_epi16(0x00F8); + R_0007 = _mm_set1_epi16(0x0007); + if (alpha) R_alpha = _mm_set1_epi32(0xFF00FF00U); + else R_alpha = _mm_set1_epi32(0x00000000U); + + for (h=0; h width) startup = width; + general_RGB565ToARGB_16u32u_C3C4((const UINT16*) src, srcStep, + (UINT32*) dst, dstStep, startup, 1, alpha, TRUE); + src += startup * sizeof(UINT16); + dst += startup * sizeof(UINT32); + w -= startup; + } + + /* The main loop handles eight pixels at a time. */ + while (w >= 8) + { + /* Off-stride, slower load. */ + if ((ULONG_PTR) src & 0x0f) + R0 = _mm_lddqu_si128((__m128i *) src); + else + R0 = _mm_load_si128((__m128i *) src); + src += (128/8); + + /* Do the lower two colors, which end up in the lower two bytes. */ + /* G = ((P<<5) & 0xFC00) | ((P>>1) & 0x0300) */ + R2 = _mm_slli_epi16(R0, 5); + R2 = _mm_and_si128(R_FC00, R2); + + R1 = _mm_srli_epi16(R0, 1); + R1 = _mm_and_si128(R_0300, R1); + R2 = _mm_or_si128(R1, R2); + + /* B = ((P>>8) & 0x00F8) | ((P>>13) & 0x0007) */ + R1 = _mm_srli_epi16(R0, 8); + R1 = _mm_and_si128(R_00F8, R1); + R2 = _mm_or_si128(R1, R2); + + R1 = _mm_srli_epi16(R0, 13); + R1 = _mm_and_si128(R_0007, R1); + R2 = _mm_or_si128(R1, R2); /* R2 = lowers */ + + /* Handle the upper color. */ + /* R = ((P<<3) & 0x00F8) | ((P>>13) & 0x0007) */ + R1 = _mm_slli_epi16(R0, 3); + R1 = _mm_and_si128(R_00F8, R1); + + R0 = _mm_srli_epi16(R0, 2); + R0 = _mm_and_si128(R_0007, R0); + R1 = _mm_or_si128(R0, R1); /* R1 = uppers */ + + /* Add alpha (or zero) . */ + R1 = _mm_or_si128(R_alpha, R1); /* + alpha */ + + /* Unpack to intermix the AR and GB pieces. */ + R0 = _mm_unpackhi_epi16(R2, R1); + R2 = _mm_unpacklo_epi16(R2, R1); + + /* Store the results. */ + _mm_store_si128((__m128i *) dst, R2); dst += (128/8); + _mm_store_si128((__m128i *) dst, R0); dst += (128/8); + w -= 8; + } + + /* Handle any remainder. */ + if (w > 0) + { + general_RGB565ToARGB_16u32u_C3C4((const UINT16*) src, srcStep, + (UINT32*) dst, dstStep, w, 1, alpha, TRUE); + src += w * sizeof(UINT16); + dst += w * sizeof(UINT32); + } + + /* Bump to the start of the next row. */ + src += srcRowBump; + dst += dstRowBump; + } + + return PRIMITIVES_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ +pstatus_t sse3_RGB565ToARGB_16u32u_C3C4( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert) +{ + if (invert) + { + return sse3_RGB565ToARGB_16u32u_C3C4_invert(pSrc, srcStep, + pDst, dstStep, width, height, alpha); + } + else + { + return sse3_RGB565ToARGB_16u32u_C3C4_no_invert(pSrc, srcStep, + pDst, dstStep, width, height, alpha); + } +} +#endif /* WITH_SSE2 */ + +/* ------------------------------------------------------------------------- */ +void primitives_init_16to32bpp_opt( + primitives_t *prims) +{ +#ifdef WITH_SSE2 + if (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) + { + prims->RGB565ToARGB_16u32u_C3C4 = sse3_RGB565ToARGB_16u32u_C3C4; + } +#endif +} diff --git a/libfreerdp/primitives/prim_YCoCg.c b/libfreerdp/primitives/prim_YCoCg.c new file mode 100644 index 000000000..ca6484795 --- /dev/null +++ b/libfreerdp/primitives/prim_YCoCg.c @@ -0,0 +1,131 @@ +/* FreeRDP: A Remote Desktop Protocol Client + * YCoCg<->RGB Color conversion operations. + * vi:ts=4 sw=4: + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 "prim_internal.h" +#include "prim_YCoCg.h" + +#ifndef MINMAX +#define MINMAX(_v_, _l_, _h_) \ + ((_v_) < (_l_) ? (_l_) : ((_v_) > (_h_) ? (_h_) : (_v_))) +#endif /* !MINMAX */ + +/* ------------------------------------------------------------------------- */ +pstatus_t general_YCoCgToRGB_8u_AC4R( + const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, + UINT32 width, UINT32 height, + UINT8 shift, + BOOL withAlpha, + BOOL invert) +{ + BYTE A; + int x, y; + BYTE *dptr = pDst; + const BYTE *sptr = pSrc; + INT16 Cg, Co, Y, T, R, G, B; + int cll = shift - 1; /* -1 builds in the /2's */ + int srcPad = srcStep - (width * 4); + int dstPad = dstStep - (width * 4); + + if (invert) + { + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + /* Note: shifts must be done before sign-conversion. */ + Cg = (INT16) ((INT8) ((*sptr++) << cll)); + Co = (INT16) ((INT8) ((*sptr++) << cll)); + Y = (INT16) (*sptr++); /* UINT8->INT16 */ + + A = *sptr++; + + if (!withAlpha) + A = 0xFFU; + + T = Y - Cg; + R = T + Co; + G = Y + Cg; + B = T - Co; + + *dptr++ = (BYTE) MINMAX(R, 0, 255); + *dptr++ = (BYTE) MINMAX(G, 0, 255); + *dptr++ = (BYTE) MINMAX(B, 0, 255); + *dptr++ = A; + } + + sptr += srcPad; + dptr += dstPad; + } + } + else + { + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + /* Note: shifts must be done before sign-conversion. */ + Cg = (INT16) ((INT8) ((*sptr++) << cll)); + Co = (INT16) ((INT8) ((*sptr++) << cll)); + Y = (INT16) (*sptr++); /* UINT8->INT16 */ + + A = *sptr++; + + if (!withAlpha) + A = 0xFFU; + + T = Y - Cg; + R = T + Co; + G = Y + Cg; + B = T - Co; + + *dptr++ = (BYTE) MINMAX(B, 0, 255); + *dptr++ = (BYTE) MINMAX(G, 0, 255); + *dptr++ = (BYTE) MINMAX(R, 0, 255); + *dptr++ = A; + } + + sptr += srcPad; + dptr += dstPad; + } + } + + return PRIMITIVES_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ +void primitives_init_YCoCg(primitives_t* prims) +{ + prims->YCoCgToRGB_8u_AC4R = general_YCoCgToRGB_8u_AC4R; + + primitives_init_YCoCg_opt(prims); +} + +/* ------------------------------------------------------------------------- */ +void primitives_deinit_YCoCg(primitives_t* prims) +{ + /* Nothing to do. */ +} diff --git a/libfreerdp/primitives/prim_YCoCg.h b/libfreerdp/primitives/prim_YCoCg.h new file mode 100644 index 000000000..c03715bda --- /dev/null +++ b/libfreerdp/primitives/prim_YCoCg.h @@ -0,0 +1,31 @@ +/* FreeRDP: A Remote Desktop Protocol Client + * YCoCg<->RGB color conversion operations. + * vi:ts=4 sw=4 + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 __GNUC__ +# pragma once +#endif + +#ifndef __PRIM_YCOCG_H_INCLUDED__ +#define __PRIM_YCOCG_H_INCLUDED__ + +pstatus_t general_YCoCgToRGB_8u_AC4R(const BYTE *pSrc, INT32 srcStep, BYTE *pDst, INT32 dstStep, UINT32 width, UINT32 height, UINT8 shift, BOOL withAlpha, BOOL invert); + +void primitives_init_YCoCg_opt(primitives_t* prims); + +#endif /* !__PRIM_YCOCG_H_INCLUDED__ */ diff --git a/libfreerdp/primitives/prim_YCoCg_opt.c b/libfreerdp/primitives/prim_YCoCg_opt.c new file mode 100644 index 000000000..e022662b3 --- /dev/null +++ b/libfreerdp/primitives/prim_YCoCg_opt.c @@ -0,0 +1,399 @@ +/* FreeRDP: A Remote Desktop Protocol Client + * Optimized YCoCg<->RGB conversion operations. + * vi:ts=4 sw=4: + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#ifdef WITH_SSE2 +#include +#include +#elif defined(WITH_NEON) +#include +#endif /* WITH_SSE2 else WITH_NEON */ + +#include "prim_internal.h" +#include "prim_templates.h" +#include "prim_YCoCg.h" + +#ifdef WITH_SSE2 + +/* ------------------------------------------------------------------------- */ +static pstatus_t ssse3_YCoCgRToRGB_8u_AC4R_invert( + const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, + UINT32 width, UINT32 height, + UINT8 shift, + BOOL withAlpha) +{ + const BYTE *sptr = pSrc; + BYTE *dptr = (BYTE *) pDst; + int sRowBump = srcStep - width*sizeof(UINT32); + int dRowBump = dstStep - width*sizeof(UINT32); + int h; + /* Shift left by "shift" and divide by two is the same as shift + * left by "shift-1". + */ + int dataShift = shift - 1; + BYTE mask = (BYTE) (0xFFU << dataShift); + + /* Let's say the data is of the form: + * y0y0o0g0 a1y1o1g1 a2y2o2g2... + * Apply: + * |R| | 1 1/2 -1/2 | |y| + * |G| = | 1 0 1/2 | * |o| + * |B| | 1 -1/2 -1/2 | |g| + * where Y is 8-bit unsigned and o & g are 8-bit signed. + */ + + if ((width < 8) || (ULONG_PTR) dptr & 0x03) + { + /* Too small, or we'll never hit a 16-byte boundary. Punt. */ + return general_YCoCgToRGB_8u_AC4R(pSrc, srcStep, + pDst, dstStep, width, height, shift, withAlpha, TRUE); + } + + for (h=0; h width) startup = width; + general_YCoCgToRGB_8u_AC4R(sptr, srcStep, dptr, dstStep, + startup, 1, shift, withAlpha, TRUE); + sptr += startup * sizeof(UINT32); + dptr += startup * sizeof(UINT32); + w -= startup; + } + + /* Each loop handles eight pixels at a time. */ + onStride = (((ULONG_PTR) sptr & 0x0f) == 0) ? TRUE : FALSE; + while (w >= 8) + { + __m128i R0, R1, R2, R3, R4, R5, R6, R7; + if (onStride) + { + /* The faster path, 16-byte aligned load. */ + R0 = _mm_load_si128((__m128i *) sptr); sptr += (128/8); + R1 = _mm_load_si128((__m128i *) sptr); sptr += (128/8); + } + else + { + /* Off-stride, slower LDDQU load. */ + R0 = _mm_lddqu_si128((__m128i *) sptr); sptr += (128/8); + R1 = _mm_lddqu_si128((__m128i *) sptr); sptr += (128/8); + } + /* R0 = a3y3o3g3 a2y2o2g2 a1y1o1g1 a0y0o0g0 */ + /* R1 = a7y7o7g7 a6y6o6g6 a5y5o5g5 a4y4o4g4 */ + + /* Shuffle to pack all the like types together. */ + R2 = _mm_set_epi32(0x0f0b0703, 0x0e0a0602, 0x0d090501, 0x0c080400); + R3 = _mm_shuffle_epi8(R0, R2); + R4 = _mm_shuffle_epi8(R1, R2); + /* R3 = a3a2a1a0 y3y2y1y0 o3o2o1o0 g3g2g1g0 */ + /* R4 = a7a6a5a4 y7y6y5y4 o7o6o5o4 g7g6g5g4 */ + R5 = _mm_unpackhi_epi32(R3, R4); + R6 = _mm_unpacklo_epi32(R3, R4); + /* R5 = a7a6a5a4 a3a2a1a0 y7y6y5y4 y3y2y1y0 */ + /* R6 = o7o6o5o4 o3o2o1o0 g7g6g5g4 g3g2g1g0 */ + /* Save alphas aside */ + if (withAlpha) R7 = _mm_unpackhi_epi64(R5, R5); + else R7 = _mm_set1_epi32(0xFFFFFFFFU); + /* R7 = a7a6a5a4 a3a2a1a0 a7a6a5a4 a3a2a1a0 */ + /* Expand Y's from 8-bit unsigned to 16-bit signed. */ + R1 = _mm_set1_epi32(0); + R0 = _mm_unpacklo_epi8(R5, R1); + /* R0 = 00y700y6 00y500y4 00y300y2 00y100y0 */ + /* Shift Co's and Cg's by (shift-1). -1 covers division by two. + * Note: this must be done before sign-conversion. + * Note also there is no slli_epi8, so we have to use a 16-bit + * version and then mask. + */ + R6 = _mm_slli_epi16(R6, dataShift); + R1 = _mm_set1_epi8(mask); + R6 = _mm_and_si128(R6, R1); + /* R6 = shifted o7o6o5o4 o3o2o1o0 g7g6g5g4 g3g2g1g0 */ + /* Expand Co's from 8-bit signed to 16-bit signed */ + R1 = _mm_unpackhi_epi8(R6, R6); + R1 = _mm_srai_epi16(R1, 8); + /* R1 = xxo7xxo6 xxo5xxo4 xxo3xxo2 xxo1xxo0 */ + /* Expand Cg's form 8-bit signed to 16-bit signed */ + R2 = _mm_unpacklo_epi8(R6, R6); + R2 = _mm_srai_epi16(R2, 8); + /* R2 = xxg7xxg6 xxg5xxg4 xxg3xxg2 xxg1xxg0 */ + /* Get Y - halfCg and save */ + R6 = _mm_subs_epi16(R0, R2); + + /* R = (Y-halfCg) + halfCo */ + R3 = _mm_adds_epi16(R6, R1); + /* R3 = xxR7xxR6 xxR5xxR4 xxR3xxR2 xxR1xxR0 */ + /* G = Y + Cg(/2) */ + R4 = _mm_adds_epi16(R0, R2); + /* R4 = xxG7xxG6 xxG5xxG4 xxG3xxG2 xxG1xxG0 */ + /* B = (Y-halfCg) - Co(/2) */ + R5 = _mm_subs_epi16(R6, R1); + /* R5 = xxB7xxB6 xxB5xxB4 xxB3xxB2 xxB1xxB0 */ + + /* Repack R's & B's. */ + R0 = _mm_packus_epi16(R3, R5); + /* R0 = R7R6R5R4 R3R2R1R0 B7B6B5B4 B3B2B1B0 */ + /* Repack G's. */ + R1 = _mm_packus_epi16(R4, R4); + /* R1 = G7G6G6G4 G3G2G1G0 G7G6G6G4 G3G2G1G0 */ + /* And add the A's. */ + R1 = _mm_unpackhi_epi64(R1, R7); + /* R1 = A7A6A6A4 A3A2A1A0 G7G6G6G4 G3G2G1G0 */ + + /* Now do interleaving again. */ + R2 = _mm_unpacklo_epi8(R0, R1); + /* R2 = G7B7G6B6 G5B5G4B4 G3B3G2B2 G1B1G0B0 */ + R3 = _mm_unpackhi_epi8(R0, R1); + /* R3 = A7R7A6R6 A5R5A4R4 A3R3A2R2 A1R1A0R0 */ + R4 = _mm_unpacklo_epi16(R2, R3); + /* R4 = A3R3G3B3 A2R2G2B2 A1R1G1B1 A0R0G0B0 */ + R5 = _mm_unpackhi_epi16(R2, R3); + /* R5 = A7R7G7B7 A6R6G6B6 A5R6G5B5 A4R4G4B4 */ + + _mm_store_si128((__m128i *) dptr, R4); dptr += (128/8); + _mm_store_si128((__m128i *) dptr, R5); dptr += (128/8); + w -= 8; + } + + /* Handle any remainder pixels. */ + if (w > 0) { + general_YCoCgToRGB_8u_AC4R(sptr, srcStep, dptr, dstStep, + w, 1, shift, withAlpha, TRUE); + sptr += w * sizeof(UINT32); + dptr += w * sizeof(UINT32); + } + + sptr += sRowBump; + dptr += dRowBump; + } + return PRIMITIVES_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ +static pstatus_t ssse3_YCoCgRToRGB_8u_AC4R_no_invert( + const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, + UINT32 width, UINT32 height, + UINT8 shift, + BOOL withAlpha) +{ + const BYTE *sptr = pSrc; + BYTE *dptr = (BYTE *) pDst; + int sRowBump = srcStep - width*sizeof(UINT32); + int dRowBump = dstStep - width*sizeof(UINT32); + int h; + /* Shift left by "shift" and divide by two is the same as shift + * left by "shift-1". + */ + int dataShift = shift - 1; + BYTE mask = (BYTE) (0xFFU << dataShift); + + /* Let's say the data is of the form: + * y0y0o0g0 a1y1o1g1 a2y2o2g2... + * Apply: + * |R| | 1 1/2 -1/2 | |y| + * |G| = | 1 0 1/2 | * |o| + * |B| | 1 -1/2 -1/2 | |g| + * where Y is 8-bit unsigned and o & g are 8-bit signed. + */ + + if ((width < 8) || (ULONG_PTR) dptr & 0x03) + { + /* Too small, or we'll never hit a 16-byte boundary. Punt. */ + return general_YCoCgToRGB_8u_AC4R(pSrc, srcStep, + pDst, dstStep, width, height, shift, withAlpha, FALSE); + } + + for (h=0; h width) startup = width; + general_YCoCgToRGB_8u_AC4R(sptr, srcStep, dptr, dstStep, + startup, 1, shift, withAlpha, FALSE); + sptr += startup * sizeof(UINT32); + dptr += startup * sizeof(UINT32); + w -= startup; + } + + /* Each loop handles eight pixels at a time. */ + onStride = (((ULONG_PTR) sptr & 0x0f) == 0) ? TRUE : FALSE; + while (w >= 8) + { + __m128i R0, R1, R2, R3, R4, R5, R6, R7; + if (onStride) + { + /* The faster path, 16-byte aligned load. */ + R0 = _mm_load_si128((__m128i *) sptr); sptr += (128/8); + R1 = _mm_load_si128((__m128i *) sptr); sptr += (128/8); + } + else + { + /* Off-stride, slower LDDQU load. */ + R0 = _mm_lddqu_si128((__m128i *) sptr); sptr += (128/8); + R1 = _mm_lddqu_si128((__m128i *) sptr); sptr += (128/8); + } + /* R0 = a3y3o3g3 a2y2o2g2 a1y1o1g1 a0y0o0g0 */ + /* R1 = a7y7o7g7 a6y6o6g6 a5y5o5g5 a4y4o4g4 */ + + /* Shuffle to pack all the like types together. */ + R2 = _mm_set_epi32(0x0f0b0703, 0x0e0a0602, 0x0d090501, 0x0c080400); + R3 = _mm_shuffle_epi8(R0, R2); + R4 = _mm_shuffle_epi8(R1, R2); + /* R3 = a3a2a1a0 y3y2y1y0 o3o2o1o0 g3g2g1g0 */ + /* R4 = a7a6a5a4 y7y6y5y4 o7o6o5o4 g7g6g5g4 */ + R5 = _mm_unpackhi_epi32(R3, R4); + R6 = _mm_unpacklo_epi32(R3, R4); + /* R5 = a7a6a5a4 a3a2a1a0 y7y6y5y4 y3y2y1y0 */ + /* R6 = o7o6o5o4 o3o2o1o0 g7g6g5g4 g3g2g1g0 */ + /* Save alphas aside */ + if (withAlpha) R7 = _mm_unpackhi_epi64(R5, R5); + else R7 = _mm_set1_epi32(0xFFFFFFFFU); + /* R7 = a7a6a5a4 a3a2a1a0 a7a6a5a4 a3a2a1a0 */ + /* Expand Y's from 8-bit unsigned to 16-bit signed. */ + R1 = _mm_set1_epi32(0); + R0 = _mm_unpacklo_epi8(R5, R1); + /* R0 = 00y700y6 00y500y4 00y300y2 00y100y0 */ + /* Shift Co's and Cg's by (shift-1). -1 covers division by two. + * Note: this must be done before sign-conversion. + * Note also there is no slli_epi8, so we have to use a 16-bit + * version and then mask. + */ + R6 = _mm_slli_epi16(R6, dataShift); + R1 = _mm_set1_epi8(mask); + R6 = _mm_and_si128(R6, R1); + /* R6 = shifted o7o6o5o4 o3o2o1o0 g7g6g5g4 g3g2g1g0 */ + /* Expand Co's from 8-bit signed to 16-bit signed */ + R1 = _mm_unpackhi_epi8(R6, R6); + R1 = _mm_srai_epi16(R1, 8); + /* R1 = xxo7xxo6 xxo5xxo4 xxo3xxo2 xxo1xxo0 */ + /* Expand Cg's form 8-bit signed to 16-bit signed */ + R2 = _mm_unpacklo_epi8(R6, R6); + R2 = _mm_srai_epi16(R2, 8); + /* R2 = xxg7xxg6 xxg5xxg4 xxg3xxg2 xxg1xxg0 */ + /* Get Y - halfCg and save */ + R6 = _mm_subs_epi16(R0, R2); + + /* R = (Y-halfCg) + halfCo */ + R3 = _mm_adds_epi16(R6, R1); + /* R3 = xxR7xxR6 xxR5xxR4 xxR3xxR2 xxR1xxR0 */ + /* G = Y + Cg(/2) */ + R4 = _mm_adds_epi16(R0, R2); + /* R4 = xxG7xxG6 xxG5xxG4 xxG3xxG2 xxG1xxG0 */ + /* B = (Y-halfCg) - Co(/2) */ + R5 = _mm_subs_epi16(R6, R1); + /* R5 = xxB7xxB6 xxB5xxB4 xxB3xxB2 xxB1xxB0 */ + + /* Repack R's & B's. */ + /* This line is the only diff between inverted and non-inverted. + * Unfortunately, it would be expensive to check "inverted" + * every time through this loop. + */ + R0 = _mm_packus_epi16(R5, R3); + /* R0 = B7B6B5B4 B3B2B1B0 R7R6R5R4 R3R2R1R0 */ + /* Repack G's. */ + R1 = _mm_packus_epi16(R4, R4); + /* R1 = G7G6G6G4 G3G2G1G0 G7G6G6G4 G3G2G1G0 */ + /* And add the A's. */ + R1 = _mm_unpackhi_epi64(R1, R7); + /* R1 = A7A6A6A4 A3A2A1A0 G7G6G6G4 G3G2G1G0 */ + + /* Now do interleaving again. */ + R2 = _mm_unpacklo_epi8(R0, R1); + /* R2 = G7B7G6B6 G5B5G4B4 G3B3G2B2 G1B1G0B0 */ + R3 = _mm_unpackhi_epi8(R0, R1); + /* R3 = A7R7A6R6 A5R5A4R4 A3R3A2R2 A1R1A0R0 */ + R4 = _mm_unpacklo_epi16(R2, R3); + /* R4 = A3R3G3B3 A2R2G2B2 A1R1G1B1 A0R0G0B0 */ + R5 = _mm_unpackhi_epi16(R2, R3); + /* R5 = A7R7G7B7 A6R6G6B6 A5R6G5B5 A4R4G4B4 */ + + _mm_store_si128((__m128i *) dptr, R4); dptr += (128/8); + _mm_store_si128((__m128i *) dptr, R5); dptr += (128/8); + w -= 8; + } + + /* Handle any remainder pixels. */ + if (w > 0) { + general_YCoCgToRGB_8u_AC4R(sptr, srcStep, dptr, dstStep, + w, 1, shift, withAlpha, FALSE); + sptr += w * sizeof(UINT32); + dptr += w * sizeof(UINT32); + } + + sptr += sRowBump; + dptr += dRowBump; + } + return PRIMITIVES_SUCCESS; +} +#endif /* WITH_SSE2 */ + +#ifdef WITH_SSE2 +/* ------------------------------------------------------------------------- */ +pstatus_t ssse3_YCoCgRToRGB_8u_AC4R( + const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, + UINT32 width, UINT32 height, + UINT8 shift, + BOOL withAlpha, + BOOL invert) +{ + if (invert) { + return ssse3_YCoCgRToRGB_8u_AC4R_invert(pSrc, srcStep, pDst, dstStep, + width, height, shift, withAlpha); + } + else { + return ssse3_YCoCgRToRGB_8u_AC4R_no_invert(pSrc, srcStep, pDst, dstStep, + width, height, shift, withAlpha); + } +} +#endif /* WITH_SSE2 */ + +/* ------------------------------------------------------------------------- */ +void primitives_init_YCoCg_opt(primitives_t* prims) +{ +/* While IPP acknowledges the existence of YCoCg-R, it doesn't currently + * include any routines to work with it, especially with variable shift + * width. + */ +#if defined(WITH_SSE2) + if (IsProcessorFeaturePresentEx(PF_EX_SSSE3) + && IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) + { + prims->YCoCgToRGB_8u_AC4R = ssse3_YCoCgRToRGB_8u_AC4R; + } +#endif /* WITH_SSE2 */ +} diff --git a/libfreerdp/primitives/prim_YUV.c b/libfreerdp/primitives/prim_YUV.c new file mode 100644 index 000000000..24ff1a49a --- /dev/null +++ b/libfreerdp/primitives/prim_YUV.c @@ -0,0 +1,278 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "prim_internal.h" +#include "prim_YUV.h" + +/** + * | R | ( | 256 0 403 | | Y | ) + * | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8 + * | B | ( | 256 475 0 | | V - 128 | ) + * + * | Y | ( | 54 183 18 | | R | ) | 0 | + * | U | = ( | -29 -99 128 | | G | ) >> 8 + | 128 | + * | V | ( | 128 -116 -12 | | B | ) | 128 | + */ + +pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], + BYTE* pDst, int dstStep, const prim_size_t* roi) +{ + int x, y; + int dstPad; + int srcPad[3]; + BYTE Y, U, V; + int halfWidth; + int halfHeight; + const BYTE* pY; + const BYTE* pU; + const BYTE* pV; + int R, G, B; + int Yp, Up, Vp; + int Up48, Up475; + int Vp403, Vp120; + BYTE* pRGB = pDst; + int nWidth, nHeight; + int lastRow, lastCol; + + pY = pSrc[0]; + pU = pSrc[1]; + pV = pSrc[2]; + + lastCol = roi->width & 0x01; + lastRow = roi->height & 0x01; + + nWidth = (roi->width + 1) & ~0x0001; + nHeight = (roi->height + 1) & ~0x0001; + + halfWidth = nWidth / 2; + halfHeight = nHeight / 2; + + srcPad[0] = (srcStep[0] - nWidth); + srcPad[1] = (srcStep[1] - halfWidth); + srcPad[2] = (srcStep[2] - halfWidth); + + dstPad = (dstStep - (nWidth * 4)); + + for (y = 0; y < halfHeight; ) + { + if (++y == halfHeight) + lastRow <<= 1; + + for (x = 0; x < halfWidth; ) + { + if (++x == halfWidth) + lastCol <<= 1; + + U = *pU++; + V = *pV++; + + Up = U - 128; + Vp = V - 128; + + Up48 = 48 * Up; + Up475 = 475 * Up; + + Vp403 = Vp * 403; + Vp120 = Vp * 120; + + /* 1st pixel */ + + Y = *pY++; + Yp = Y << 8; + + R = (Yp + Vp403) >> 8; + G = (Yp - Up48 - Vp120) >> 8; + B = (Yp + Up475) >> 8; + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) B; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) R; + *pRGB++ = 0xFF; + + /* 2nd pixel */ + + if (!(lastCol & 0x02)) + { + Y = *pY++; + Yp = Y << 8; + + R = (Yp + Vp403) >> 8; + G = (Yp - Up48 - Vp120) >> 8; + B = (Yp + Up475) >> 8; + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) B; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) R; + *pRGB++ = 0xFF; + } + else + { + pY++; + pRGB += 4; + lastCol >>= 1; + } + } + + pY += srcPad[0]; + pU -= halfWidth; + pV -= halfWidth; + pRGB += dstPad; + + for (x = 0; x < halfWidth; ) + { + if (++x == halfWidth) + lastCol <<= 1; + + U = *pU++; + V = *pV++; + + Up = U - 128; + Vp = V - 128; + + Up48 = 48 * Up; + Up475 = 475 * Up; + + Vp403 = Vp * 403; + Vp120 = Vp * 120; + + /* 3rd pixel */ + + Y = *pY++; + Yp = Y << 8; + + R = (Yp + Vp403) >> 8; + G = (Yp - Up48 - Vp120) >> 8; + B = (Yp + Up475) >> 8; + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) B; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) R; + *pRGB++ = 0xFF; + + /* 4th pixel */ + + if (!(lastCol & 0x02)) + { + Y = *pY++; + Yp = Y << 8; + + R = (Yp + Vp403) >> 8; + G = (Yp - Up48 - Vp120) >> 8; + B = (Yp + Up475) >> 8; + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) B; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) R; + *pRGB++ = 0xFF; + } + else + { + pY++; + pRGB += 4; + lastCol >>= 1; + } + } + + pY += srcPad[0]; + pU += srcPad[1]; + pV += srcPad[2]; + pRGB += dstPad; + } + + return PRIMITIVES_SUCCESS; +} + +void primitives_init_YUV(primitives_t* prims) +{ + prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R; + + primitives_init_YUV_opt(prims); +} + +void primitives_deinit_YUV(primitives_t* prims) +{ + +} diff --git a/libfreerdp/primitives/prim_YUV.h b/libfreerdp/primitives/prim_YUV.h new file mode 100644 index 000000000..99428ada6 --- /dev/null +++ b/libfreerdp/primitives/prim_YUV.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_PRIMITIVES_YUV_H +#define FREERDP_PRIMITIVES_YUV_H + +pstatus_t general_yCbCrToRGB_16s8u_P3AC4R(const INT16* pSrc[3], int srcStep, BYTE* pDst, int dstStep, const prim_size_t* roi); + +void primitives_init_YUV(primitives_t* prims); +void primitives_init_YUV_opt(primitives_t* prims); +void primitives_deinit_YUV(primitives_t* prims); + +#endif /* FREERDP_PRIMITIVES_YUV_H */ diff --git a/libfreerdp/primitives/prim_YUV_opt.c b/libfreerdp/primitives/prim_YUV_opt.c new file mode 100644 index 000000000..7b80a4522 --- /dev/null +++ b/libfreerdp/primitives/prim_YUV_opt.c @@ -0,0 +1,370 @@ +/** function for converting YUV420p data to the RGB format (but without any special upconverting) + * It's completely written in nasm-x86-assembly for intel processors supporting SSSE3 and higher. + * The target dstStep (6th parameter) must be a multiple of 16. + * srcStep[0] must be (target dstStep) / 4 or bigger and srcStep[1] the next multiple of four + * of the half of srcStep[0] or bigger + */ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + + +#ifdef WITH_SSE2 + +#include +#include + +pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, + BYTE *pDst, int dstStep, const prim_size_t *roi) +{ + int lastRow, lastCol; + BYTE *UData,*VData,*YData; + int i,nWidth,nHeight,VaddDst,VaddY,VaddU,VaddV; + __m128i r0,r1,r2,r3,r4,r5,r6,r7; + __m128i *buffer; + + /* last_line: if the last (U,V doubled) line should be skipped, set to 10B + * last_column: if it's the last column in a line, set to 10B (for handling line-endings not multiple by four) */ + + buffer = _aligned_malloc(4 * 16, 16); + + YData = (BYTE*) pSrc[0]; + UData = (BYTE*) pSrc[1]; + VData = (BYTE*) pSrc[2]; + + nWidth = roi->width; + nHeight = roi->height; + + if ((lastCol = (nWidth & 3))) + { + switch (lastCol) + { + case 1: + r7 = _mm_set_epi32(0,0,0,0xFFFFFFFF); + break; + + case 2: + r7 = _mm_set_epi32(0,0,0xFFFFFFFF,0xFFFFFFFF); + break; + + case 3: + r7 = _mm_set_epi32(0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF); + break; + } + + _mm_store_si128(buffer+3,r7); + lastCol = 1; + } + + nWidth += 3; + nWidth = nWidth >> 2; + + lastRow = nHeight & 1; + nHeight++; + nHeight = nHeight >> 1; + + VaddDst = (dstStep << 1) - (nWidth << 4); + VaddY = (srcStep[0] << 1) - (nWidth << 2); + VaddU = srcStep[1] - (((nWidth << 1) + 2) & 0xFFFC); + VaddV = srcStep[2] - (((nWidth << 1) + 2) & 0xFFFC); + + while (nHeight-- > 0) + { + if (nHeight == 0) + lastRow <<= 1; + + i = 0; + + do + { + if (!(i & 0x01)) + { + /* Y-, U- and V-data is stored in different arrays. + * We start with processing U-data. + * + * at first we fetch four U-values from its array and shuffle them like this: + * 0d0d 0c0c 0b0b 0a0a + * we've done two things: converting the values to signed words and duplicating + * each value, because always two pixel "share" the same U- (and V-) data */ + r0 = _mm_cvtsi32_si128(*(UINT32 *)UData); + r5 = _mm_set_epi32(0x80038003,0x80028002,0x80018001,0x80008000); + r0 = _mm_shuffle_epi8(r0,r5); + + UData += 4; + + /* then we subtract 128 from each value, so we get D */ + r3 = _mm_set_epi16(128,128,128,128,128,128,128,128); + r0 = _mm_subs_epi16(r0,r3); + + /* we need to do two things with our D, so let's store it for later use */ + r2 = r0; + + /* now we can multiply our D with 48 and unpack it to xmm4:xmm0 + * this is what we need to get G data later on */ + r4 = r0; + r7 = _mm_set_epi16(48,48,48,48,48,48,48,48); + r0 = _mm_mullo_epi16(r0,r7); + r4 = _mm_mulhi_epi16(r4,r7); + r7 = r0; + r0 = _mm_unpacklo_epi16(r0,r4); + r4 = _mm_unpackhi_epi16(r7,r4); + + /* to get B data, we need to prepare a second value, D*475 */ + r1 = r2; + r7 = _mm_set_epi16(475,475,475,475,475,475,475,475); + r1 = _mm_mullo_epi16(r1,r7); + r2 = _mm_mulhi_epi16(r2,r7); + r7 = r1; + r1 = _mm_unpacklo_epi16(r1,r2); + r7 = _mm_unpackhi_epi16(r7,r2); + + /* so we got something like this: xmm7:xmm1 + * this pair contains values for 16 pixel: + * aabbccdd + * aabbccdd, but we can only work on four pixel at once, so we need to save upper values */ + _mm_store_si128(buffer+1,r7); + + /* Now we've prepared U-data. Preparing V-data is actually the same, just with other coefficients */ + r2 = _mm_cvtsi32_si128(*(UINT32 *)VData); + r2 = _mm_shuffle_epi8(r2,r5); + + VData += 4; + + r2 = _mm_subs_epi16(r2,r3); + + r5 = r2; + + /* this is also known as E*403, we need it to convert R data */ + r3 = r2; + r7 = _mm_set_epi16(403,403,403,403,403,403,403,403); + r2 = _mm_mullo_epi16(r2,r7); + r3 = _mm_mulhi_epi16(r3,r7); + r7 = r2; + r2 = _mm_unpacklo_epi16(r2,r3); + r7 = _mm_unpackhi_epi16(r7,r3); + + /* and preserve upper four values for future ... */ + _mm_store_si128(buffer+2,r7); + + /* doing this step: E*120 */ + r3 = r5; + r7 = _mm_set_epi16(120,120,120,120,120,120,120,120); + r3 = _mm_mullo_epi16(r3,r7); + r5 = _mm_mulhi_epi16(r5,r7); + r7 = r3; + r3 = _mm_unpacklo_epi16(r3,r5); + r7 = _mm_unpackhi_epi16(r7,r5); + + /* now we complete what we've begun above: + * (48*D) + (120*E) = (48*D +120*E) */ + r0 = _mm_add_epi32(r0,r3); + r4 = _mm_add_epi32(r4,r7); + + /* and store to memory ! */ + _mm_store_si128(buffer,r4); + } + else + { + /* maybe you've wondered about the conditional above ? + * Well, we prepared UV data for eight pixel in each line, but can only process four + * per loop. So we need to load the upper four pixel data from memory each secound loop! */ + r1 = _mm_load_si128(buffer+1); + r2 = _mm_load_si128(buffer+2); + r0 = _mm_load_si128(buffer); + } + + if (++i == nWidth) + lastCol <<= 1; + + /* We didn't produce any output yet, so let's do so! + * Ok, fetch four pixel from the Y-data array and shuffle them like this: + * 00d0 00c0 00b0 00a0, to get signed dwords and multiply by 256 */ + r4 = _mm_cvtsi32_si128(*(UINT32 *)YData); + r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080); + r4 = _mm_shuffle_epi8(r4,r7); + + r5 = r4; + r6 = r4; + + /* no we can perform the "real" conversion itself and produce output! */ + r4 = _mm_add_epi32(r4,r2); + r5 = _mm_sub_epi32(r5,r0); + r6 = _mm_add_epi32(r6,r1); + + /* in the end, we only need bytes for RGB values. + * So, what do we do? right! shifting left makes values bigger and thats always good. + * before we had dwords of data, and by shifting left and treating the result + * as packed words, we get not only signed words, but do also divide by 256 + * imagine, data is now ordered this way: ddx0 ccx0 bbx0 aax0, and x is the least + * significant byte, that we don't need anymore, because we've done some rounding */ + r4 = _mm_slli_epi32(r4,8); + r5 = _mm_slli_epi32(r5,8); + r6 = _mm_slli_epi32(r6,8); + + /* one thing we still have to face is the clip() function ... + * we have still signed words, and there are those min/max instructions in SSE2 ... + * the max instruction takes always the bigger of the two operands and stores it in the first one, + * and it operates with signs ! + * if we feed it with our values and zeros, it takes the zeros if our values are smaller than + * zero and otherwise our values */ + r7 = _mm_set_epi32(0,0,0,0); + r4 = _mm_max_epi16(r4,r7); + r5 = _mm_max_epi16(r5,r7); + r6 = _mm_max_epi16(r6,r7); + + /* the same thing just completely different can be used to limit our values to 255, + * but now using the min instruction and 255s */ + r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); + r4 = _mm_min_epi16(r4,r7); + r5 = _mm_min_epi16(r5,r7); + r6 = _mm_min_epi16(r6,r7); + + /* Now we got our bytes. + * the moment has come to assemble the three channels R,G and B to the xrgb dwords + * on Red channel we just have to and each futural dword with 00FF0000H */ + //r7=_mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); + r4 = _mm_and_si128(r4,r7); + + /* on Green channel we have to shuffle somehow, so we get something like this: + * 00d0 00c0 00b0 00a0 */ + r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280); + r5 = _mm_shuffle_epi8(r5,r7); + + /* and on Blue channel that one: + * 000d 000c 000b 000a */ + r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002); + r6 = _mm_shuffle_epi8(r6,r7); + + /* and at last we or it together and get this one: + * xrgb xrgb xrgb xrgb */ + r4 = _mm_or_si128(r4,r5); + r4 = _mm_or_si128(r4,r6); + + /* Only thing to do know is writing data to memory, but this gets a bit more + * complicated if the width is not a multiple of four and it is the last column in line. */ + if (lastCol & 0x02) + { + /* let's say, we need to only convert six pixel in width + * Ok, the first 4 pixel will be converted just like every 4 pixel else, but + * if it's the last loop in line, last_column is shifted left by one (curious? have a look above), + * and we land here. Through initialisation a mask was prepared. In this case it looks like + * 0000FFFFH 0000FFFFH 0000FFFFH 0000FFFFH */ + r6 = _mm_load_si128(buffer+3); + /* we and our output data with this mask to get only the valid pixel */ + r4 = _mm_and_si128(r4,r6); + /* then we fetch memory from the destination array ... */ + r5 = _mm_lddqu_si128((__m128i *)pDst); + /* ... and and it with the inverse mask. We get only those pixel, which should not be updated */ + r6 = _mm_andnot_si128(r6,r5); + /* we only have to or the two values together and write it back to the destination array, + * and only the pixel that should be updated really get changed. */ + r4 = _mm_or_si128(r4,r6); + } + _mm_storeu_si128((__m128i *)pDst,r4); + + if (!(lastRow & 0x02)) + { + /* Because UV data is the same for two lines, we can process the secound line just here, + * in the same loop. Only thing we need to do is to add some offsets to the Y- and destination + * pointer. These offsets are iStride[0] and the target scanline. + * But if we don't need to process the secound line, like if we are in the last line of processing nine lines, + * we just skip all this. */ + r4 = _mm_cvtsi32_si128(*(UINT32 *)(YData+srcStep[0])); + r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080); + r4 = _mm_shuffle_epi8(r4,r7); + + r5 = r4; + r6 = r4; + + r4 = _mm_add_epi32(r4,r2); + r5 = _mm_sub_epi32(r5,r0); + r6 = _mm_add_epi32(r6,r1); + + r4 = _mm_slli_epi32(r4,8); + r5 = _mm_slli_epi32(r5,8); + r6 = _mm_slli_epi32(r6,8); + + r7 = _mm_set_epi32(0,0,0,0); + r4 = _mm_max_epi16(r4,r7); + r5 = _mm_max_epi16(r5,r7); + r6 = _mm_max_epi16(r6,r7); + + r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); + r4 = _mm_min_epi16(r4,r7); + r5 = _mm_min_epi16(r5,r7); + r6 = _mm_min_epi16(r6,r7); + + r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); + r4 = _mm_and_si128(r4,r7); + + r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280); + r5 = _mm_shuffle_epi8(r5,r7); + + r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002); + r6 = _mm_shuffle_epi8(r6,r7); + + r4 = _mm_or_si128(r4,r5); + r4 = _mm_or_si128(r4,r6); + + if (lastCol & 0x02) + { + r6 = _mm_load_si128(buffer+3); + r4 = _mm_and_si128(r4,r6); + r5 = _mm_lddqu_si128((__m128i *)(pDst+dstStep)); + r6 = _mm_andnot_si128(r6,r5); + r4 = _mm_or_si128(r4,r6); + + /* only thing is, we should shift [rbp-42] back here, because we have processed the last column, + * and this "special condition" can be released */ + lastCol >>= 1; + } + _mm_storeu_si128((__m128i *)(pDst+dstStep),r4); + } + + /* after all we have to increase the destination- and Y-data pointer by four pixel */ + pDst += 16; + YData += 4; + } + while (i < nWidth); + + /* after each line we have to add the scanline to the destination pointer, because + * we are processing two lines at once, but only increasing the destination pointer + * in the first line. Well, we only have one pointer, so it's the easiest way to access + * the secound line with the one pointer and an offset (scanline) + * if we're not converting the full width of the scanline, like only 64 pixel, but the + * output buffer was "designed" for 1920p HD, we have to add the remaining length for each line, + * to get into the next line. */ + pDst += VaddDst; + + /* same thing has to be done for Y-data, but with iStride[0] instead of the target scanline */ + YData += VaddY; + + /* and again for UV data, but here it's enough to add the remaining length, because + * UV data is the same for two lines and there exists only one "UV line" on two "real lines" */ + UData += VaddU; + VData += VaddV; + } + + _aligned_free(buffer); + + return PRIMITIVES_SUCCESS; +} +#endif + +void primitives_init_YUV_opt(primitives_t *prims) +{ +#ifdef WITH_SSE2 + if (IsProcessorFeaturePresentEx(PF_EX_SSSE3) && IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) + { + prims->YUV420ToRGB_8u_P3AC4R = ssse3_YUV420ToRGB_8u_P3AC4R; + } +#endif +} diff --git a/libfreerdp/primitives/prim_colors.c b/libfreerdp/primitives/prim_colors.c index a7de64339..46c18642a 100644 --- a/libfreerdp/primitives/prim_colors.c +++ b/libfreerdp/primitives/prim_colors.c @@ -33,6 +33,127 @@ #endif /* !MINMAX */ /* ------------------------------------------------------------------------- */ + +pstatus_t general_yCbCrToRGB_16s8u_P3AC4R(const INT16* pSrc[3], int srcStep, + BYTE* pDst, int dstStep, const prim_size_t* roi) +{ + int x, y; + INT16 R, G, B; + float Y, Cb, Cr; + BYTE* pRGB = pDst; + const INT16* pY = pSrc[0]; + const INT16* pCb = pSrc[1]; + const INT16* pCr = pSrc[2]; + int srcPad = (srcStep - (roi->width * 2)) / 2; + int dstPad = (dstStep - (roi->width * 4)) / 4; + + for (y = 0; y < roi->height; y++) + { + for (x = 0; x < roi->width; x++) + { + Y = (float) (pY[0] + 4096); + Cb = (float) (pCb[0]); + Cr = (float) (pCr[0]); + + R = ((INT16) (((Cr * 1.402525f) + Y + 16.0f)) >> 5); + G = ((INT16) ((Y - (Cb * 0.343730f) - (Cr * 0.714401f) + 16.0f)) >> 5); + B = ((INT16) (((Cb * 1.769905f) + Y + 16.0f)) >> 5); + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) B; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) R; + *pRGB++ = 0xFF; + + pY++; + pCb++; + pCr++; + } + + pY += srcPad; + pCb += srcPad; + pCr += srcPad; + pRGB += dstPad; + } + + return PRIMITIVES_SUCCESS; +} + +pstatus_t general_yCbCrToBGR_16s8u_P3AC4R(const INT16* pSrc[3], int srcStep, + BYTE* pDst, int dstStep, const prim_size_t* roi) +{ + int x, y; + INT16 R, G, B; + float Y, Cb, Cr; + BYTE* pRGB = pDst; + const INT16* pY = pSrc[0]; + const INT16* pCb = pSrc[1]; + const INT16* pCr = pSrc[2]; + int srcPad = (srcStep - (roi->width * 2)) / 2; + int dstPad = (dstStep - (roi->width * 4)) / 4; + + for (y = 0; y < roi->height; y++) + { + for (x = 0; x < roi->width; x++) + { + Y = (float) (pY[0] + 4096); + Cb = (float) (pCb[0]); + Cr = (float) (pCr[0]); + + R = ((INT16) (((Cr * 1.402525f) + Y + 16.0f)) >> 5); + G = ((INT16) ((Y - (Cb * 0.343730f) - (Cr * 0.714401f) + 16.0f)) >> 5); + B = ((INT16) (((Cb * 1.769905f) + Y + 16.0f)) >> 5); + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + *pRGB++ = (BYTE) R; + *pRGB++ = (BYTE) G; + *pRGB++ = (BYTE) B; + *pRGB++ = 0xFF; + + pY++; + pCb++; + pCr++; + } + + pY += srcPad; + pCb += srcPad; + pCr += srcPad; + pRGB += dstPad; + } + + return PRIMITIVES_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ + pstatus_t general_yCbCrToRGB_16s16s_P3P3( const INT16 *pSrc[3], INT32 srcStep, INT16 *pDst[3], INT32 dstStep, @@ -217,9 +338,11 @@ pstatus_t general_RGBToRGB_16s8u_P3AC4R( /* ------------------------------------------------------------------------- */ void primitives_init_colors(primitives_t* prims) { - prims->RGBToRGB_16s8u_P3AC4R = general_RGBToRGB_16s8u_P3AC4R; + prims->yCbCrToRGB_16s8u_P3AC4R = general_yCbCrToRGB_16s8u_P3AC4R; + prims->yCbCrToBGR_16s8u_P3AC4R = general_yCbCrToBGR_16s8u_P3AC4R; prims->yCbCrToRGB_16s16s_P3P3 = general_yCbCrToRGB_16s16s_P3P3; prims->RGBToYCbCr_16s16s_P3P3 = general_RGBToYCbCr_16s16s_P3P3; + prims->RGBToRGB_16s8u_P3AC4R = general_RGBToRGB_16s8u_P3AC4R; primitives_init_colors_opt(prims); } diff --git a/libfreerdp/primitives/prim_colors.h b/libfreerdp/primitives/prim_colors.h index 15b76d997..773bbaeeb 100644 --- a/libfreerdp/primitives/prim_colors.h +++ b/libfreerdp/primitives/prim_colors.h @@ -22,6 +22,7 @@ #ifndef __PRIM_COLORS_H_INCLUDED__ #define __PRIM_COLORS_H_INCLUDED__ +pstatus_t general_yCbCrToRGB_16s8u_P3AC4R(const INT16* pSrc[3], int srcStep, BYTE* pDst, int dstStep, const prim_size_t* roi); pstatus_t general_yCbCrToRGB_16s16s_P3P3(const INT16 *pSrc[3], INT32 srcStep, INT16 *pDst[3], INT32 dstStep, const prim_size_t *roi); pstatus_t general_RGBToYCbCr_16s16s_P3P3(const INT16 *pSrc[3], INT32 srcStep, INT16 *pDst[3], INT32 dstStep, const prim_size_t *roi); pstatus_t general_RGBToRGB_16s8u_P3AC4R(const INT16 *pSrc[3], int srcStep, BYTE *pDst, int dstStep, const prim_size_t *roi); diff --git a/libfreerdp/primitives/prim_internal.h b/libfreerdp/primitives/prim_internal.h index 06418fba2..04c830a1c 100644 --- a/libfreerdp/primitives/prim_internal.h +++ b/libfreerdp/primitives/prim_internal.h @@ -35,44 +35,37 @@ : _mm_load_si128((__m128i *) (_ptr_))) /* Function prototypes for all the init/deinit routines. */ -extern void primitives_init_copy( - primitives_t *prims); -extern void primitives_deinit_copy( - primitives_t *prims); +extern void primitives_init_copy(primitives_t *prims); +extern void primitives_deinit_copy(primitives_t *prims); -extern void primitives_init_set( - primitives_t *prims); -extern void primitives_deinit_set( - primitives_t *prims); +extern void primitives_init_set(primitives_t *prims); +extern void primitives_deinit_set(primitives_t *prims); -extern void primitives_init_add( - primitives_t *prims); -extern void primitives_deinit_add( - primitives_t *prims); +extern void primitives_init_add(primitives_t *prims); +extern void primitives_deinit_add(primitives_t *prims); -extern void primitives_init_andor( - primitives_t *prims); -extern void primitives_deinit_andor( - primitives_t *prims); +extern void primitives_init_andor(primitives_t *prims); +extern void primitives_deinit_andor(primitives_t *prims); -extern void primitives_init_shift( - primitives_t *prims); -extern void primitives_deinit_shift( - primitives_t *prims); +extern void primitives_init_shift(primitives_t *prims); +extern void primitives_deinit_shift(primitives_t *prims); -extern void primitives_init_sign( - primitives_t *prims); -extern void primitives_deinit_sign( - primitives_t *prims); +extern void primitives_init_sign(primitives_t *prims); +extern void primitives_deinit_sign(primitives_t *prims); -extern void primitives_init_alphaComp( - primitives_t *prims); -extern void primitives_deinit_alphaComp( - primitives_t *prims); +extern void primitives_init_alphaComp(primitives_t *prims); +extern void primitives_deinit_alphaComp(primitives_t *prims); -extern void primitives_init_colors( - primitives_t *prims); -extern void primitives_deinit_colors( - primitives_t *prims); +extern void primitives_init_colors(primitives_t *prims); +extern void primitives_deinit_colors(primitives_t *prims); + +extern void primitives_init_YCoCg(primitives_t *prims); +extern void primitives_deinit_YCoCg(primitives_t *prims); + +extern void primitives_init_YUV(primitives_t *prims); +extern void primitives_deinit_YUV(primitives_t *prims); + +extern void primitives_init_16to32bpp(primitives_t *prims); +extern void primitives_deinit_16to32bpp(primitives_t *prims); #endif /* !__PRIM_INTERNAL_H_INCLUDED__ */ diff --git a/libfreerdp/primitives/primitives.c b/libfreerdp/primitives/primitives.c index 33764f1af..dcdd5941a 100644 --- a/libfreerdp/primitives/primitives.c +++ b/libfreerdp/primitives/primitives.c @@ -32,11 +32,11 @@ static primitives_t* pPrimitives = NULL; /* ------------------------------------------------------------------------- */ void primitives_init(void) { - if (pPrimitives == NULL) + if (!pPrimitives) { pPrimitives = calloc(1, sizeof(primitives_t)); - if (pPrimitives == NULL) + if (!pPrimitives) return; } @@ -49,12 +49,15 @@ void primitives_init(void) primitives_init_shift(pPrimitives); primitives_init_sign(pPrimitives); primitives_init_colors(pPrimitives); + primitives_init_YCoCg(pPrimitives); + primitives_init_YUV(pPrimitives); + primitives_init_16to32bpp(pPrimitives); } /* ------------------------------------------------------------------------- */ primitives_t* primitives_get(void) { - if (pPrimitives == NULL) + if (!pPrimitives) primitives_init(); return pPrimitives; @@ -63,7 +66,7 @@ primitives_t* primitives_get(void) /* ------------------------------------------------------------------------- */ void primitives_deinit(void) { - if (pPrimitives == NULL) + if (!pPrimitives) return; /* Call each section's de-initialization routine. */ @@ -75,6 +78,9 @@ void primitives_deinit(void) primitives_deinit_shift(pPrimitives); primitives_deinit_sign(pPrimitives); primitives_deinit_colors(pPrimitives); + primitives_deinit_YCoCg(pPrimitives); + primitives_deinit_YUV(pPrimitives); + primitives_deinit_16to32bpp(pPrimitives); free((void*) pPrimitives); pPrimitives = NULL; diff --git a/libfreerdp/primitives/test/.gitignore b/libfreerdp/primitives/test/.gitignore index 082fee1c1..f25c3eed1 100644 --- a/libfreerdp/primitives/test/.gitignore +++ b/libfreerdp/primitives/test/.gitignore @@ -1,2 +1,3 @@ prim_test +TestPrimitives.c diff --git a/libfreerdp/primitives/test/CMakeLists.txt b/libfreerdp/primitives/test/CMakeLists.txt index 6d6898f17..9a652a36a 100644 --- a/libfreerdp/primitives/test/CMakeLists.txt +++ b/libfreerdp/primitives/test/CMakeLists.txt @@ -1,147 +1,45 @@ -# FreeRDP: A Remote Desktop Protocol Client -# primitives test makefile builder -# vi:ts=4 sw=4: -# -# (c) Copyright 2012 Hewlett-Packard Development Company, L.P. -# 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. -# -# TODO: Integrate this into the testing framework, in some form. -# Right now this produces a standalone test that covers both functionality -# and performance of the primitives library entrypoints. +set(MODULE_NAME "TestPrimitives") +set(MODULE_PREFIX "TEST_FREERDP_PRIMITIVES") -cmake_minimum_required(VERSION 2.8) -set(MODULE_NAME "prim_test") -set(MODULE_PREFIX "PRIMITIVES_LIBRARY_TEST") +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) -set(PRIMITIVE_TEST_CFILES +set(${MODULE_PREFIX}_TESTS + TestPrimitives16to32bpp.c + TestPrimitivesAdd.c + TestPrimitivesAlphaComp.c + TestPrimitivesAndOr.c + TestPrimitivesColors.c + TestPrimitivesCopy.c + TestPrimitivesSet.c + TestPrimitivesShift.c + TestPrimitivesSign.c + TestPrimitivesYCbCr.c + TestPrimitivesYCoCg.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +set(${MODULE_PREFIX}_EXTRA_SRCS prim_test.c - test_add.c - test_alphaComp.c - test_andor.c - test_colors.c - test_copy.c - test_set.c - test_shift.c - test_sign.c - ../prim_add.c - ../prim_andor.c - ../prim_alphaComp.c - ../prim_colors.c - ../prim_copy.c - ../prim_set.c - ../prim_shift.c - ../prim_sign.c - ../prim_add_opt.c - ../prim_alphaComp_opt.c - ../prim_andor_opt.c - ../prim_colors_opt.c - ../prim_set_opt.c - ../prim_shift_opt.c - ../prim_sign_opt.c - ../primitives.c - ) - -set(PRIMITIVE_TEST_HEADERS - measure.h prim_test.h - ../prim_internal.h -) + measure.h) -set(PRIMITIVE_TEST_SRCS - ${PRIMITIVE_TEST_CFILES} - ${PRIMITIVE_TEST_HEADERS} - ) +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_EXTRA_SRCS}) -include_directories(. ../../.. ../../../include ../../../winpr/include) -add_definitions(-DPRIM_STATIC=auto -DALL_PRIMITIVES_VERSIONS -DHAVE_CONFIG_H) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) -# If these haven't been set by the caller, set them now to defaults. -if(NOT DEFINED WITH_IPP) - set(WITH_IPP FALSE) -endif() -if(NOT DEFINED WITH_SSE2) - if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*") - set(WITH_SSE2 FALSE) - else() - set(WITH_SSE2 TRUE) - endif() -endif() -if(NOT DEFINED WITH_NEON) - if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*") - set(WITH_NEON TRUE) - else() - set(WITH_NEON FALSE) - endif() -endif() +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -if(WITH_SSE2) - if(CMAKE_COMPILER_IS_GNUCC) - set(OPTFLAGS "${OPTFLAGS} -msse2 -mssse3 -O2 -Wdeclaration-after-statement") - endif() +add_definitions(-DPRIM_STATIC=auto -DALL_PRIMITIVES_VERSIONS) - if(MSVC) - set(OPTFLAGS "${OPTFLAGS} /arch:SSE2") - endif() -elseif(WITH_NEON) - if(CMAKE_COMPILER_IS_GNUCC) - set(OPTFLAGS "${OPTFLAGS} -mfpu=neon -mfloat-abi=${ARM_FP_ABI} -O2") - endif() - # TODO: Add MSVC equivalent -endif() +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") -add_executable(prim_test ${PRIMITIVE_TEST_SRCS}) - -if(WITH_IPP) - if(NOT DEFINED IPP_FOUND) - include(../../../cmake/FindIPP.cmake) - endif() - - # IPP PATH debugging messages - message(IPP_FOUND=${IPP_FOUND}) - message(IPP_VERSION_STR=${IPP_VERSION_STR}) - message(IPP_VERSION_MAJOR=${IPP_VERSION_MAJOR}) - message(IPP_VERSION_MINOR=${IPP_VERSION_MINOR}) - message(IPP_VERSION_BUILD=${IPP_VERSION_BUILD}) - message(IPP_ROOT_DIR=${IPP_ROOT_DIR}) - message(IPP_INCLUDE_DIRS=${IPP_INCLUDE_DIRS}) - message(IPP_LIBRARY_DIRS=${IPP_LIBRARY_DIRS}) - message(IPP_LIBRARIES=${IPP_LIBRARIES}) - message(IPP_COMPILER_LIBRARY_DIRS=${IPP_COMPILER_LIBRARY_DIRS}) - message(IPP_COMPILER_LIBRARIES=${IPP_COMPILER_LIBRARIES}) - message(IPP_LIBRARY_LIST=${IPP_LIBRARY_LIST}) - message(IPP_LIB_PREFIX=${IPP_LIB_PREFIX}) - message(IPP_LIB_SUFFIX=${IPP_LIB_SUFFIX}) - message(IPP_PREFIX=${IPP_PREFIX}) - message(IPP_SUFFIX=${IPP_SUFFIX}) - message(IPPCORE=${IPPCORE}) - message(IPPS=${IPPS}) - message(IPPI=${IPPI}) - message(IPPCC=${IPPCC}) - message(IPPCV=${IPPCV}) - message(IPPVM=${IPPVM}) - - if(CMAKE_COMPILER_IS_GNUCC) - foreach(INCLDIR ${IPP_INCLUDE_DIRS}) - set(OPTFLAGS "${OPTFLAGS} -I${INCLDIR}") - endforeach(INCLDIR) - endif() - target_link_libraries(prim_test ${IPP_LIBRARY_LIST}) -endif() - -set_property(SOURCE ${PRIMITIVE_TEST_CFILES} PROPERTY COMPILE_FLAGS ${OPTFLAGS}) - -target_link_libraries(prim_test rt winpr-sysinfo) -if(NOT TESTING_OUTPUT_DIRECTORY) - set(TESTING_OUTPUT_DIRECTORY .) -endif() -add_test(prim_test ${TESTING_OUTPUT_DIRECTORY}/prim_test functionality) +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 "FreeRDP/Test") + diff --git a/libfreerdp/primitives/test/TestPrimitives16to32bpp.c b/libfreerdp/primitives/test/TestPrimitives16to32bpp.c new file mode 100644 index 000000000..03a070e40 --- /dev/null +++ b/libfreerdp/primitives/test/TestPrimitives16to32bpp.c @@ -0,0 +1,209 @@ +/* test_colors.c + * vi:ts=4 sw=4 + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "prim_test.h" + +static const int RGB_TRIAL_ITERATIONS = 1000; +static const float TEST_TIME = 4.0; + +extern BOOL g_TestPrimitivesPerformance; + +extern pstatus_t general_RGB565ToARGB_16u32u_C3C4( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert); +extern pstatus_t sse3_RGB565ToARGB_16u32u_C3C4( + const UINT16* pSrc, INT32 srcStep, + UINT32* pDst, INT32 dstStep, + UINT32 width, UINT32 height, + BOOL alpha, BOOL invert); + +/* ------------------------------------------------------------------------- */ +static BOOL try_16To32( + const UINT16 *data16, + int sOffset, + int dOffset, + int width, int height) +{ + BOOL success; + const char *sAligned = "sAlign"; + const char *sUnaligned = "s!Align"; + const char *dAligned = "dAlign"; + const char *dUnaligned = "d!Align"; + const char *sAlignStr, *dAlignStr; + const UINT16 *src; + UINT32 ALIGN(outNN1[4096+3]), ALIGN(outAN1[4096+3]), + ALIGN(outNI1[4096+3]), ALIGN(outAI1[4096+3]); + UINT32 ALIGN(outNN2[4096+3]), ALIGN(outAN2[4096+3]), + ALIGN(outNI2[4096+3]), ALIGN(outAI2[4096+3]); + + assert(sOffset < 4); + assert(dOffset < 4); + assert(width*height <= 4096); + + success = TRUE; + src = data16 + sOffset; + sAlignStr = (sOffset == 0) ? sAligned : sUnaligned; + dAlignStr = (dOffset == 0) ? dAligned : dUnaligned; + + general_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outNN1+dOffset, width*sizeof(UINT32), width, height, FALSE, FALSE); + general_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outAN1+dOffset, width*sizeof(UINT32), width, height, TRUE, FALSE); + general_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outNI1+dOffset, width*sizeof(UINT32), width, height, FALSE, TRUE); + general_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outAI1+dOffset, width*sizeof(UINT32), width, height, TRUE, TRUE); + +#ifdef WITH_SSE2 + printf(" Testing 16-to-32bpp SSE3 version (%s, %s, %dx%d)\n", + sAlignStr, dAlignStr, width, height); + if (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) + { + int i; + + sse3_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outNN2+dOffset, width*sizeof(UINT32), width, height, FALSE, FALSE); + sse3_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outAN2+dOffset, width*sizeof(UINT32), width, height, TRUE, FALSE); + sse3_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outNI2+dOffset, width*sizeof(UINT32), width, height, FALSE, TRUE); + sse3_RGB565ToARGB_16u32u_C3C4(src, width*sizeof(UINT16), + outAI2+dOffset, width*sizeof(UINT32), width, height, TRUE, TRUE); + for (i=0; i 0x%08x rather than 0x%08x\n", + sAlignStr, dAlignStr, data16[s], outNN2[d], outNN1[d]); + success = FALSE; + } + if (outAN1[d] != outAN2[d]) + { + printf("16To32bpp-SSE FAIL (%s, %s, alpha, !invert)" + " 0x%04x -> 0x%08x rather than 0x%08x\n", + sAlignStr, dAlignStr, data16[s], outAN2[d], outAN1[d]); + success = FALSE; + } + if (outNI1[d] != outNI2[d]) + { + printf("16To32bpp-SSE FAIL (%s, %s, !alpha, invert)" + " 0x%04x -> 0x%08x rather than 0x%08x\n", + sAlignStr, dAlignStr, data16[s], outNI2[d], outNI1[d]); + success = FALSE; + } + if (outAI1[d] != outAI2[d]) + { + printf("16To32bpp-SSE FAIL (%s, %s, alpha, invert)" + " 0x%04x -> 0x%08x rather than 0x%08x\n", + sAlignStr, dAlignStr, data16[s], outAI2[d], outNI1[d]); + success = FALSE; + } + } + } +#endif /* WITH_SSE2 */ + + return success; +} + + +/* ------------------------------------------------------------------------- */ +int test_RGB565ToARGB_16u32u_C3C4_func(void) +{ + UINT16 ALIGN(data16[4096+3]); + BOOL success; + + success = TRUE; + get_random_data(data16, sizeof(data16)); + + /* Source aligned, dest aligned, 64x64 */ + success &= try_16To32(data16, 0, 0, 64, 64); + /* Source !aligned, dest aligned, 64x64 */ + success &= try_16To32(data16, 1, 0, 64, 64); + /* Source aligned, dest !aligned, 64x64 */ + success &= try_16To32(data16, 0, 1, 64, 64); + /* Source !aligned, dest !aligned, 64x64 */ + success &= try_16To32(data16, 1, 1, 64, 64); + /* Odd size */ + success &= try_16To32(data16, 0, 0, 17, 53); + + if (success) printf("All RGB565ToARGB_16u32u_C3C4 tests passed.\n"); + return success ? SUCCESS : FAILURE; +} + +/* ------------------------------------------------------------------------- */ +STD_SPEED_TEST( + test16to32_speed, UINT16, UINT32, PRIM_NOP, + TRUE, general_RGB565ToARGB_16u32u_C3C4( + (const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4, + 64,64, TRUE, TRUE), +#ifdef WITH_SSE2 + TRUE, sse3_RGB565ToARGB_16u32u_C3C4( + (const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4, + 64,64, TRUE, TRUE), + PF_SSE3_INSTRUCTIONS_AVAILABLE, FALSE, +#else + FALSE, PRIM_NOP, 0, FALSE, +#endif + FALSE, PRIM_NOP); + +/* ------------------------------------------------------------------------- */ +int test_RGB565ToARGB_16u32u_C3C4_speed(void) +{ + UINT16 ALIGN(src[4096]); + UINT32 ALIGN(dst[4096]); + int size_array[] = { 64 }; + + get_random_data(src, sizeof(src)); + + test16to32_speed("16-to-32bpp", "aligned", + (const UINT16 *) src, 0, 0, (UINT32 *) dst, + size_array, 1, RGB_TRIAL_ITERATIONS, TEST_TIME); + return SUCCESS; +} + +int TestPrimitives16to32bpp(int argc, char* argv[]) +{ + int status; + + status = test_RGB565ToARGB_16u32u_C3C4_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_RGB565ToARGB_16u32u_C3C4_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_add.c b/libfreerdp/primitives/test/TestPrimitivesAdd.c similarity index 92% rename from libfreerdp/primitives/test/test_add.c rename to libfreerdp/primitives/test/TestPrimitivesAdd.c index 453e2a7de..08ab41ff4 100644 --- a/libfreerdp/primitives/test/test_add.c +++ b/libfreerdp/primitives/test/TestPrimitivesAdd.c @@ -23,6 +23,8 @@ static const int ADD16S_PRETEST_ITERATIONS = 300000*64; static const int TEST_TIME = 2.0; // seconds +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_add_16s( const INT16 *pSrc1, const INT16 *pSrc2, INT16 *pDst, int len); extern pstatus_t sse3_add_16s( @@ -112,3 +114,23 @@ int test_add16s_speed(void) test_sizes, NUM_TEST_SIZES, ADD16S_PRETEST_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesAdd(int argc, char* argv[]) +{ + int status; + + status = test_add16s_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_add16s_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_alphaComp.c b/libfreerdp/primitives/test/TestPrimitivesAlphaComp.c similarity index 95% rename from libfreerdp/primitives/test/test_alphaComp.c rename to libfreerdp/primitives/test/TestPrimitivesAlphaComp.c index c3b5e9ca1..18332dcb5 100644 --- a/libfreerdp/primitives/test/test_alphaComp.c +++ b/libfreerdp/primitives/test/TestPrimitivesAlphaComp.c @@ -22,6 +22,8 @@ static const int ALPHA_PRETEST_ITERATIONS = 5000000; static const float TEST_TIME = 5.0; +extern BOOL g_TestPrimitivesPerformance; + static const int block_size[] = { 4, 64, 256 }; #define NUM_BLOCK_SIZES (sizeof(block_size)/sizeof(int)) #define MAX_BLOCK_SIZE 256 @@ -233,3 +235,23 @@ int test_alphaComp_speed(void) return SUCCESS; } + +int TestPrimitivesAlphaComp(int argc, char* argv[]) +{ + int status; + + status = test_alphaComp_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_alphaComp_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_andor.c b/libfreerdp/primitives/test/TestPrimitivesAndOr.c similarity index 92% rename from libfreerdp/primitives/test/test_andor.c rename to libfreerdp/primitives/test/TestPrimitivesAndOr.c index d82991408..24d73d43a 100644 --- a/libfreerdp/primitives/test/test_andor.c +++ b/libfreerdp/primitives/test/TestPrimitivesAndOr.c @@ -23,6 +23,8 @@ static const int ANDOR_PRETEST_ITERATIONS = 100000; static const int TEST_TIME = 2.0; // seconds +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_andC_32u(const UINT32 *pSrc, UINT32 val, UINT32 *pDst, int len); extern pstatus_t sse3_andC_32u(const UINT32 *pSrc, UINT32 val, @@ -185,3 +187,36 @@ int test_or_32u_speed(void) test_sizes, NUM_TEST_SIZES, ANDOR_PRETEST_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesAndOr(int argc, char* argv[]) +{ + int status; + + status = test_and_32u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_and_32u_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_or_32u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_or_32u_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_colors.c b/libfreerdp/primitives/test/TestPrimitivesColors.c similarity index 92% rename from libfreerdp/primitives/test/test_colors.c rename to libfreerdp/primitives/test/TestPrimitivesColors.c index 628cb5d5e..717328246 100644 --- a/libfreerdp/primitives/test/test_colors.c +++ b/libfreerdp/primitives/test/TestPrimitivesColors.c @@ -23,6 +23,8 @@ static const int RGB_TRIAL_ITERATIONS = 1000; static const int YCBCR_TRIAL_ITERATIONS = 1000; static const float TEST_TIME = 4.0; +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_RGBToRGB_16s8u_P3AC4R(const INT16 *pSrc[3], int srcStep, BYTE *pDst, int dstStep, const prim_size_t *roi); extern pstatus_t sse2_RGBToRGB_16s8u_P3AC4R(const INT16 *pSrc[3], @@ -241,3 +243,36 @@ int test_yCbCrToRGB_16s16s_P3P3_speed(void) size_array, 1, YCBCR_TRIAL_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesColors(int argc, char* argv[]) +{ + int status; + + status = test_RGBToRGB_16s8u_P3AC4R_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_RGBToRGB_16s8u_P3AC4R_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_yCbCrToRGB_16s16s_P3P3_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_yCbCrToRGB_16s16s_P3P3_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_copy.c b/libfreerdp/primitives/test/TestPrimitivesCopy.c similarity index 89% rename from libfreerdp/primitives/test/test_copy.c rename to libfreerdp/primitives/test/TestPrimitivesCopy.c index 13b4f57f2..189969d7c 100644 --- a/libfreerdp/primitives/test/test_copy.c +++ b/libfreerdp/primitives/test/TestPrimitivesCopy.c @@ -26,6 +26,8 @@ static const int TEST_TIME = 1.0; // seconds extern pstatus_t sse3_copy_8u(const BYTE *pSrc, BYTE *pDst, int len); #endif +extern BOOL g_TestPrimitivesPerformance; + /* ------------------------------------------------------------------------- */ int test_copy8u_func(void) { @@ -84,3 +86,23 @@ int test_copy8u_speed(void) test_sizes, NUM_TEST_SIZES, MEMCPY_PRETEST_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesCopy(int argc, char* argv[]) +{ + int status; + + status = test_copy8u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_copy8u_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_set.c b/libfreerdp/primitives/test/TestPrimitivesSet.c similarity index 91% rename from libfreerdp/primitives/test/test_set.c rename to libfreerdp/primitives/test/TestPrimitivesSet.c index 32d22c71d..2111d65c3 100644 --- a/libfreerdp/primitives/test/test_set.c +++ b/libfreerdp/primitives/test/TestPrimitivesSet.c @@ -23,6 +23,8 @@ static const int MEMSET8_PRETEST_ITERATIONS = 100000000; static const int MEMSET32_PRETEST_ITERATIONS = 40000000; static const float TEST_TIME = 1.0; +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_set_8u(BYTE val, BYTE *pDst, int len); extern pstatus_t sse2_set_8u(BYTE val, BYTE *pDst, int len); extern pstatus_t general_set_32s(INT32 val, INT32 *pDst, int len); @@ -241,7 +243,7 @@ int test_set32u_func(void) } /* ------------------------------------------------------------------------- */ -static inline void memset32u_naive( +static INLINE void memset32u_naive( UINT32 val, UINT32 *dst, size_t count) @@ -273,7 +275,7 @@ int test_set32u_speed(void) } /* ------------------------------------------------------------------------- */ -static inline void memset32s_naive( +static INLINE void memset32s_naive( INT32 val, INT32 *dst, size_t count) @@ -303,3 +305,49 @@ int test_set32s_speed(void) #endif return SUCCESS; } + +int TestPrimitivesSet(int argc, char* argv[]) +{ + int status; + + status = test_set8u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_set8u_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_set32s_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_set32s_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_set32u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_set32u_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_shift.c b/libfreerdp/primitives/test/TestPrimitivesShift.c similarity index 88% rename from libfreerdp/primitives/test/test_shift.c rename to libfreerdp/primitives/test/TestPrimitivesShift.c index 588187a4b..693c12b34 100644 --- a/libfreerdp/primitives/test/test_shift.c +++ b/libfreerdp/primitives/test/TestPrimitivesShift.c @@ -23,6 +23,8 @@ static const int SHIFT_PRETEST_ITERATIONS = 50000; static const float TEST_TIME = 1.0; +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_lShiftC_16s( const INT16 *pSrc, int val, INT16 *pDst, int len); extern pstatus_t general_rShiftC_16s( @@ -187,3 +189,62 @@ int test_rShift_16u_speed(void) test_sizes, NUM_TEST_SIZES, SHIFT_PRETEST_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesShift(int argc, char* argv[]) +{ + int status; + + status = test_lShift_16s_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_lShift_16s_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_lShift_16u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_lShift_16u_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_rShift_16s_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_rShift_16s_speed(); + + if (status != SUCCESS) + return 1; + } + + status = test_rShift_16u_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_rShift_16u_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/test_sign.c b/libfreerdp/primitives/test/TestPrimitivesSign.c similarity index 90% rename from libfreerdp/primitives/test/test_sign.c rename to libfreerdp/primitives/test/TestPrimitivesSign.c index beb22ee1d..0d06d64bc 100644 --- a/libfreerdp/primitives/test/test_sign.c +++ b/libfreerdp/primitives/test/TestPrimitivesSign.c @@ -22,6 +22,8 @@ static const int SIGN_PRETEST_ITERATIONS = 100000; static const float TEST_TIME = 1.0; +extern BOOL g_TestPrimitivesPerformance; + extern pstatus_t general_sign_16s(const INT16 *pSrc, INT16 *pDst, int len); #ifdef WITH_SSE2 extern pstatus_t ssse3_sign_16s(const INT16 *pSrc, INT16 *pDst, int len); @@ -101,3 +103,23 @@ int test_sign16s_speed(void) test_sizes, NUM_TEST_SIZES, SIGN_PRETEST_ITERATIONS, TEST_TIME); return SUCCESS; } + +int TestPrimitivesSign(int argc, char* argv[]) +{ + int status; + + status = test_sign16s_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_sign16s_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/TestPrimitivesYCbCr.c b/libfreerdp/primitives/test/TestPrimitivesYCbCr.c new file mode 100644 index 000000000..c9f24b9a2 --- /dev/null +++ b/libfreerdp/primitives/test/TestPrimitivesYCbCr.c @@ -0,0 +1,2392 @@ + +#include "prim_test.h" + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define TAG __FILE__ + +static INT16 TEST_Y_COMPONENT[4096] = +{ + -32, +16, +64, +272, -32, -16, +0, -16, + -32, -24, -16, -8, +0, -24, -48, -72, + -96, -90, -84, -78, -72, -98, -124, -150, + -176, -192, -208, -224, -240, -256, -272, -288, + -304, -304, -304, -304, -304, -336, -368, -400, + -432, -450, -468, -486, -504, -522, -540, -558, + -576, -598, -620, -642, -664, -686, -708, -730, + -752, -768, -784, -800, -816, -816, -816, -816, + +68, +120, +172, +240, +53, +55, +57, +43, + +30, +32, +34, +36, +38, +20, +2, -16, + -34, -36, -38, -40, -42, -68, -94, -120, + -146, -148, -151, -186, -220, -227, -233, -240, + -247, -254, -261, -268, -275, -302, -329, -356, + -384, -403, -423, -443, -463, -484, -506, -528, + -550, -572, -594, -616, -639, -673, -707, -709, + -712, -733, -754, -775, -796, -796, -796, -796, + +168, +224, +281, +209, +138, +126, +115, +103, + +92, +88, +84, +80, +76, +64, +52, +40, + +28, +18, +8, -2, -12, -38, -64, -90, + -116, -105, -95, -148, -201, -198, -195, -192, + -190, -204, -218, -232, -247, -269, -291, -313, + -336, -357, -379, -400, -422, -447, -473, -498, + -524, -546, -569, -591, -614, -660, -707, -689, + -672, -698, -724, -750, -776, -776, -776, -776, + +268, +312, +357, +273, +191, +181, +172, +162, + +154, +144, +134, +124, +114, +108, +102, +80, + +58, +56, +54, +52, +50, +24, -2, -44, + -86, -61, -38, -93, -149, -137, -124, -144, + -165, -170, -175, -196, -218, -235, -252, -269, + -288, -310, -334, -357, -381, -409, -439, -468, + -498, -520, -543, -565, -589, -647, -706, -668, + -632, -663, -694, -725, -756, -756, -756, -756, + +368, +401, +434, +339, +244, +237, +230, +223, + +216, +200, +184, +168, +152, +152, +152, +120, + +88, +94, +100, +106, +112, +86, +60, +2, + -56, -18, +19, -39, -98, -76, -55, -97, + -140, -136, -133, -161, -190, -202, -215, -227, + -240, -265, -290, -315, -340, -373, -406, -439, + -472, -495, -518, -541, -564, -635, -706, -649, + -592, -628, -664, -700, -736, -736, -736, -736, + +404, +556, +454, +383, +313, +531, +239, +282, + +326, +304, +282, +260, +238, +246, +254, +118, + +238, +196, +154, +32, -90, -88, -86, +76, + +238, +243, +247, +29, -191, -232, -272, -121, + +29, -62, -153, -149, -145, -162, -180, -197, + -216, -240, -265, -289, -315, -345, -376, -406, + -438, -446, -456, -497, -539, -595, -653, -502, + -608, -625, -642, -675, -708, -708, -708, -708, + +440, +713, +475, +428, +382, +827, +249, +342, + +436, +408, +380, +352, +324, +340, +356, -140, + -124, +42, +208, +214, +220, +250, +280, +406, + +532, +504, +476, +352, +229, +125, +22, -146, + -314, -244, -175, -138, -101, -123, -146, -169, + -192, -216, -241, -265, -290, -318, -347, -375, + -404, -399, -395, -454, -514, -557, -601, -356, + -624, -622, -620, -650, -680, -680, -680, -680, + +604, +677, +495, +457, +419, +770, +354, +386, + +418, +416, +414, +380, +346, +258, -342, -302, + -6, +288, +582, +604, +626, +588, +550, +688, + +826, +829, +833, +724, +616, +481, +348, +181, + +15, -139, -292, -175, -56, -83, -112, -139, + -168, -192, -216, -240, -265, -291, -317, -343, + -370, -351, -333, -411, -489, -486, -484, -402, + -576, -587, -598, -625, -652, -652, -652, -652, + +1280, +1154, +1028, +998, +968, +970, +460, +430, + +400, +424, +448, +408, +368, +432, -528, -208, + +112, +534, +956, +994, +1032, +926, +820, +970, + +1120, +1155, +1190, +1097, +1004, +839, +674, +509, + +344, +223, +102, +45, -12, -45, -78, -111, + -144, -168, -192, -216, -240, -264, -288, -312, + -336, -304, -272, -368, -464, -416, -368, -448, + -528, -552, -576, -600, -624, -624, -624, -624, + +770, +671, +573, +554, +536, +629, +467, +464, + +462, +492, +523, +490, +457, +281, -405, -101, + +204, +599, +995, +1310, +1370, +1297, +1225, +1296, + +1368, +1432, +1498, +1402, +1308, +1184, +1062, +874, + +688, +586, +485, +303, +123, -82, -32, -76, + -122, -174, -226, -199, -171, -193, -216, -238, + -261, -314, -368, -325, -283, -360, -438, -451, + -465, -515, -565, -583, -601, -617, -633, -633, + +772, +701, +630, +623, +616, +545, +474, +499, + +524, +561, +599, +572, +546, +131, -283, +6, + +296, +665, +1034, +1627, +1708, +1669, +1630, +1623, + +1616, +1711, +1806, +1709, +1612, +1531, +1450, +1241, + +1032, +950, +869, +563, +258, -120, +15, -42, + -100, -180, -261, -182, -103, -123, -144, -165, + -186, -325, -464, -283, -102, -305, -508, -455, + -402, -478, -554, -566, -578, -610, -642, -642, + +774, +730, +687, +675, +664, +620, +577, +581, + +586, +597, +610, +590, +571, -147, -96, +209, + +516, +794, +1073, +1575, +1822, +1976, +1875, +1869, + +1864, +1988, +2114, +2014, +1916, +1876, +1838, +1606, + +1376, +1266, +1156, +902, +137, -61, -3, -120, + -238, -122, -7, -69, -130, -164, -200, -219, + -239, -271, -304, -128, -209, -297, -386, -426, + -467, -937, -895, -549, -459, -667, -619, -619, + +776, +760, +744, +728, +712, +696, +680, +664, + +648, +635, +622, +609, +596, -425, +90, +413, + +736, +924, +1112, +1524, +1936, +2284, +2120, +2116, + +2112, +2267, +2422, +2321, +2220, +2223, +2226, +1973, + +1720, +1582, +1444, +1242, +16, -2, -20, +58, + +136, -65, -267, -212, -158, -207, -257, -274, + -292, -218, -144, +26, -316, -290, -264, -142, + -20, +2956, +2860, -788, -852, -980, -596, -596, + +826, +807, +789, +770, +752, +749, +747, +744, + +742, +677, +613, +516, +421, -285, +288, +573, + +860, +1081, +1303, +1668, +2034, +2313, +2337, +2344, + +2352, +2452, +2554, +2574, +2596, +2506, +2418, +2248, + +2080, +1961, +1843, +925, +7, +40, +74, +748, + +654, +453, +251, +48, -154, -107, -61, -111, + -161, -28, +104, +45, -271, -274, -278, -842, + +1411, +3007, +3323, +327, -1389, -1197, -493, -493, + +876, +855, +834, +813, +792, +803, +814, +825, + +836, +720, +605, +681, +758, +110, +487, +735, + +984, +1239, +1494, +1813, +2132, +2343, +2554, +2573, + +2592, +2639, +2686, +2829, +2972, +2791, +2610, +2525, + +2440, +2341, +2243, +608, -2, +83, +169, +1438, + +1172, +970, +768, +565, +363, +249, +135, +52, + -30, -95, -160, -193, -226, -259, -292, +763, + -742, +2290, +1738, -1118, -902, -902, -390, -390, + +926, +902, +879, +855, +832, +824, +817, +809, + +802, +763, +724, +397, +2375, +970, +589, +848, + +1108, +1396, +1685, +1941, +2198, +2468, +2739, +2785, + +2832, +2888, +2946, +3178, +2900, +3058, +2962, +2848, + +2736, +2896, +2546, -364, +309, +205, +871, +1760, + +1626, +1471, +1317, +1145, +975, +844, +714, +599, + +485, +351, +216, +146, +75, -355, +750, +2687, + +529, -1067, -615, -835, -799, -847, -383, -383, + +976, +950, +924, +898, +872, +846, +820, +794, + +768, +806, +844, +882, +1432, +2598, +692, +962, + +1232, +1554, +1876, +2070, +2264, +2594, +2924, +2998, + +3072, +3139, +3206, +3273, +2316, +3071, +3314, +3173, + +3032, +2941, +1826, -57, +108, +73, +1574, +2083, + +2080, +1973, +1866, +1727, +1588, +1441, +1294, +1147, + +1000, +796, +592, +484, +376, +828, +256, +772, + -248, -72, -408, +984, -184, -536, -376, -376, + +1026, +997, +969, +941, +913, +888, +864, +840, + +816, +762, +709, +768, +1339, +2269, +2176, +1411, + +1414, +1677, +1941, +2188, +2436, +2730, +3023, +3157, + +3291, +3349, +3409, +3420, +2152, +3000, +3594, +3403, + +3213, +3233, +951, +12, +97, -303, +2883, +2755, + +2373, +2312, +2252, +2143, +2036, +1861, +1687, +1544, + +1403, +1254, +1106, +974, +842, +1229, +1105, +21, + +217, +46, -381, +1912, +3181, +2765, +301, -723, + +1076, +1045, +1015, +984, +954, +931, +909, +886, + +864, +719, +575, +654, +1246, +1685, +3149, +1604, + +1596, +1801, +2006, +2307, +2609, +2866, +3123, +3316, + +3510, +3561, +3613, +3568, +1988, +2931, +3875, +3634, + +3394, +3527, +76, +81, +86, +859, +3168, +2917, + +2666, +2652, +2639, +2561, +2484, +2282, +2081, +1943, + +1806, +1713, +1621, +1464, +1308, +1119, +931, +550, + +170, -92, -354, +1560, +3986, +1970, -558, -558, + +1126, +1092, +1060, +1027, +995, +973, +953, +932, + +912, +899, +888, -340, +1249, +1756, +2521, +2421, + +1810, +2036, +2263, +2521, +2781, +3066, +3350, +3443, + +3537, +3612, +3688, +3476, +2496, +3021, +3803, +3833, + +3863, +2843, +33, +133, -21, +2099, +3197, +3061, + +2927, +2944, +2961, +2882, +2804, +2607, +2410, +2309, + +2209, +2139, +2071, +1842, +1614, +1328, +1044, +663, + +283, +10, -263, -488, -201, -201, -457, -457, + +1176, +1141, +1106, +1071, +1036, +1017, +998, +979, + +960, +825, +690, +203, +740, +1573, +1894, +3239, + +2024, +2272, +2521, +2737, +2954, +3010, +3067, +3315, + +3564, +3664, +3764, +3384, +3004, +3112, +3732, +3776, + +3820, +1905, -10, +187, -128, +3341, +3226, +3207, + +3188, +3236, +3284, +3204, +3124, +2932, +2740, +2676, + +2612, +2567, +2522, +2221, +1920, +1539, +1158, +777, + +396, +112, -172, -488, -292, -324, -356, -356, + +1194, +1162, +1131, +1099, +1069, +1047, +1026, +972, + +920, +969, +507, +380, +767, +1428, +1834, +2799, + +2486, +2347, +2721, +2919, +3118, +3290, +3462, +3266, + +3071, +3157, +3243, +3521, +3800, +3674, +3548, +3710, + +3873, +874, +179, +91, +517, +3439, +3291, +3333, + +3377, +3403, +3430, +3361, +3292, +3174, +3057, +3004, + +2951, +2761, +2572, +2222, +1874, +1554, +1235, +883, + +533, +220, -93, -470, -335, -319, -303, -303, + +1212, +1184, +1157, +1129, +1102, +1078, +1055, +967, + +880, +1114, +325, +559, +794, +1284, +1775, +2361, + +2948, +2423, +2923, +3103, +3283, +3314, +3346, +3474, + +3602, +3674, +3747, +3659, +3572, +3980, +3877, +3901, + +3926, -157, +368, +253, +1674, +3795, +3356, +3461, + +3566, +3571, +3577, +3518, +3460, +3417, +3375, +3332, + +3290, +2956, +2623, +2225, +1828, +1570, +1313, +991, + +670, +328, -14, -452, -378, -314, -250, -250, + +1230, +1206, +1182, +1158, +1135, +1109, +1083, +1025, + +968, +779, +78, +481, +885, +1284, +1939, +2466, + +3250, +2626, +2772, +3157, +3543, +3514, +3486, +3729, + +3717, +3775, +3834, +3780, +3728, +3934, +3885, +3915, + +2667, +92, +333, +173, +2831, +3701, +3549, +3587, + +3627, +3642, +3659, +3643, +3628, +3675, +3724, +3436, + +3149, +2847, +2545, +2275, +2006, +1730, +1454, +1114, + +775, +388, +1, -402, -293, -309, -325, -325, + +1248, +1228, +1208, +1188, +1168, +1140, +1112, +1084, + +1056, +700, +344, +660, +976, +1284, +2104, +2316, + +3040, +2319, +2110, +2189, +2268, +2691, +3114, +3729, + +3832, +3877, +3922, +3903, +3884, +3889, +3894, +3931, + +1408, +341, +298, +95, +3988, +3609, +3742, +3715, + +3688, +3715, +3742, +3769, +3796, +3679, +3562, +3285, + +3008, +2738, +2468, +2326, +2184, +1890, +1596, +1238, + +880, +448, +16, -352, -208, -304, -400, -400, + +1296, +1284, +1272, +1260, +1249, +1165, +1081, +1093, + +1106, +232, +382, +677, +971, +973, +1232, +834, + +693, +537, +639, +564, +490, +563, +637, -106, + +944, +2358, +3773, +3795, +4074, +3964, +3855, +4337, + +212, +204, +197, +1341, +4023, +3813, +3860, +3810, + +3762, +3766, +3771, +3776, +3781, +3603, +3427, +3201, + +2977, +2838, +2699, +2400, +2101, +1982, +1607, +1280, + +954, +545, -120, -321, -266, -314, -362, -362, + +1344, +1340, +1337, +1333, +1330, +1190, +1051, +1103, + +1156, +20, +933, +950, +967, +919, +872, +889, + +906, +805, +705, +733, +761, +740, +720, +668, + +616, +328, +40, +1640, +3752, +3784, +3816, +3208, + +40, +581, +97, +2589, +4058, +4018, +3979, +3907, + +3836, +3818, +3801, +3784, +3767, +3529, +3292, +3375, + +3458, +3706, +3954, +3754, +3555, +2843, +1619, +1067, + +516, +386, -256, -290, -324, -324, -324, -324, + +1392, +1364, +1337, +1309, +1283, +1247, +1212, +968, + +982, +1424, +1099, +1079, +1058, +1072, +1088, +815, + +799, +1056, +802, +772, +743, +645, +547, +769, + +736, +649, +563, +332, +102, +1939, +4033, +1982, + +444, +332, -36, +4076, +4093, +4047, +4001, +3955, + +3910, +3870, +3830, +3791, +3752, +3806, +3861, +3835, + +3811, +3678, +3545, +3380, +3216, +3639, +3806, +2341, + +1134, +1091, +24, -387, -286, -286, -286, -286, + +1440, +1389, +1338, +1287, +1236, +1305, +1374, +1091, + +1320, +1037, +1267, +1208, +1150, +715, +281, +486, + +1204, +1564, +901, +1325, +1750, +1830, +1911, +1383, + +344, +459, +574, +817, +548, +351, +666, +757, + +336, +340, +856, +4028, +4128, +4076, +4024, +4004, + +3984, +3922, +3861, +3799, +3738, +3828, +3919, +3785, + +3652, +3394, +3137, +3007, +2878, +2900, +2923, +3105, + +3800, +1284, +1328, +28, -248, -248, -248, -248, + +1456, +1406, +1358, +1309, +1261, +1209, +1159, +1444, + +1218, +1265, +33, -654, -1342, -977, -356, +394, + +1401, +1753, +1338, +1738, +2140, +2575, +3009, +3524, + +3784, +2536, +1033, +265, +522, +440, +615, +629, + +388, +403, +2211, +4051, +4099, +4078, +4058, +3990, + +3922, +3910, +3898, +3886, +3875, +3805, +3735, +3553, + +3373, +3126, +2879, +2585, +2291, +2026, +1762, +2649, + +3026, +2303, +2092, +665, -250, -250, -250, -250, + +1472, +1425, +1379, +1332, +1286, +1371, +1457, +1030, + -932, -1834, -1712, -1237, -763, -621, +33, +815, + +1598, +1943, +1776, +2153, +2531, +2808, +3085, +3362, + +3640, +4102, +4052, +3042, +496, +530, +564, +502, + +440, +211, +3055, +3818, +4070, +4081, +4093, +3976, + +3860, +3898, +3936, +3974, +4013, +3783, +3553, +3323, + +3094, +2858, +2623, +2420, +2217, +1921, +1626, +915, + +2764, +250, +296, +22, -252, -252, -252, -252, + +1488, +1443, +1399, +1371, +1343, +1308, +1530, -408, + -1834, -1589, -1089, -811, -535, -281, +485, +1171, + +1859, +2132, +2150, +2503, +2857, +3105, +3352, +3536, + +3720, +3875, +3775, +4298, +4054, +2123, +449, +502, + +556, +546, +26, +2113, +3945, +4115, +4031, +3946, + +3862, +3838, +3814, +3982, +3894, +3488, +3338, +3140, + +2943, +2622, +2302, +2030, +1758, +1495, +1234, +1259, + +774, -347, -188, -189, -190, -222, -254, -254, + +1504, +1462, +1420, +1410, +1400, +1246, +1604, -1334, + -1712, -1089, -978, -643, -308, +59, +938, +1529, + +2120, +2322, +2524, +2854, +3184, +3402, +3620, +3710, + +3800, +3905, +4010, +4019, +4028, +3973, +334, +503, + +672, +627, +582, +409, +236, +2359, +3970, +3917, + +3864, +3778, +3692, +3990, +3776, +3194, +3124, +2958, + +2792, +2387, +1982, +1641, +1300, +1071, +842, +69, + -192, -176, -160, -144, -128, -192, -256, -256, + +1546, +1496, +1447, +1430, +1413, +1627, +1330, -2102, + -1184, -819, -712, -395, -80, +405, +1148, +1713, + +2280, +2486, +2692, +2995, +3297, +3467, +3638, +3712, + +3787, +3915, +4045, +3917, +4047, +3097, +357, +655, + +699, +198, +466, +381, +297, +376, +200, +1815, + +3431, +3568, +3961, +4114, +3755, +3310, +3121, +2804, + +2487, +2208, +1931, +1189, +447, +37, -116, -254, + -136, -111, -86, -109, -132, -196, -260, -260, + +1588, +1531, +1475, +1450, +1426, +1497, +33, -1591, + -1168, -807, -446, -149, +148, +753, +1358, +1899, + +2440, +2650, +2861, +3136, +3411, +3533, +3656, +3715, + +3774, +3927, +4080, +3817, +4066, +2223, +380, +553, + +214, +3610, +350, +354, +358, +442, +526, +226, + -74, +286, +1158, +1678, +1686, +1634, +1582, +1114, + +646, +239, -168, -31, +107, -228, -51, -65, + -80, -46, -12, -74, -136, -200, -264, -264, + +1630, +1565, +1502, +1470, +1439, +1590, -817, -1399, + -960, -633, -308, -14, +280, +875, +1472, +1971, + +2472, +2718, +2965, +3229, +3492, +3582, +3674, +3701, + +3729, +3793, +3859, +4147, +4181, +707, +563, +417, + +1297, +3917, +4234, +2198, +163, +267, +372, +348, + +325, +108, +147, +186, -31, +38, +107, +96, + +85, +61, +38, -162, -106, -126, +111, +876, + -152, -93, -34, -87, -140, -204, -268, -268, + +1672, +1601, +1530, +1491, +1452, +1685, -1666, -1209, + -752, -461, -170, +121, +412, +999, +1586, +2045, + +2504, +2787, +3071, +3322, +3574, +3633, +3693, +3688, + +3684, +3661, +3638, +3711, +2760, +473, +746, +283, + +2380, +4225, +4022, +4043, +4064, +2141, +218, +215, + +212, +186, +160, +230, +300, +234, +168, +102, + +36, -117, -269, +218, +1218, +2025, +2833, +1048, + -224, -140, -56, -100, -144, -208, -272, -272, + +1626, +1607, +1589, +1458, +1585, +692, -1479, -1107, + -736, -451, -168, +115, +400, +805, +1468, +1937, + +2408, +2703, +2999, +3327, +3655, +3568, +3482, +3620, + +3759, +3439, +3121, +1601, +851, +819, +533, +437, + +3415, +4252, +4066, +4055, +4045, +4084, +4124, +2995, + +1867, +1068, +269, +62, -145, -38, +69, +704, + +1339, +2183, +3028, +2816, +2861, +2953, +2790, -349, + +96, -19, -134, -137, -140, -204, -268, -268, + +1580, +1614, +1649, +1427, +1718, -300, -1293, -1006, + -720, -443, -166, +111, +388, +613, +1350, +1831, + +2312, +2620, +2928, +3076, +3225, +3249, +3273, +3297, + +3322, +3475, +3628, +3333, +1502, +655, +832, +593, + +3938, +4024, +4110, +4068, +4026, +3980, +3934, +3984, + +4034, +3998, +3962, +3990, +4018, +3786, +3554, +3610, + +3666, +3459, +3253, +3111, +2969, +2858, +2236, -210, + -96, -154, -212, -174, -136, -200, -264, -264, + +1662, +1653, +1644, +1619, +1851, -988, -1266, -985, + -704, -401, -100, +9, +120, +403, +944, +1579, + +2216, +2504, +2793, +2873, +2954, +2976, +2999, +3085, + +3173, +3237, +3303, +3575, +521, +553, +587, +1771, + +3981, +4019, +4058, +4032, +4007, +3971, +3936, +3948, + +3961, +3920, +3879, +3806, +3989, +3866, +3743, +3636, + +3529, +3375, +3222, +3069, +2916, +2907, +1362, -119, + -64, -113, -162, -147, -132, -196, -260, -260, + +1744, +1692, +1640, +1556, +1472, -1932, -1240, -964, + -688, -361, -34, +165, +364, +707, +1050, +1585, + +2120, +2389, +2658, +2671, +2684, +2705, +2726, +2875, + +3024, +3001, +2978, +2283, +564, +965, +342, +2951, + +4024, +4015, +4006, +3997, +3988, +3963, +3938, +3913, + +3888, +3842, +3796, +3622, +3960, +3946, +3932, +3662, + +3392, +3292, +3192, +3028, +2864, +2956, +488, -28, + -32, -72, -112, -120, -128, -192, -256, -256, + +1834, +1635, +1692, +1718, +208, -1663, -1229, -924, + -619, -283, +50, +256, +719, +705, +948, +1126, + +1562, +1845, +2129, +2236, +2344, +2447, +2551, +2654, + +2759, +2738, +2719, +1562, +663, +623, +327, +4207, + +3992, +4012, +4034, +3990, +3948, +3922, +3898, +3872, + +3848, +3774, +3701, +3484, +3523, +3726, +3929, +3812, + +3695, +3604, +3513, +3407, +3300, +3350, -440, -231, + -22, -48, -74, -100, -126, -174, -222, -222, + +1924, +1578, +1745, +1880, -1057, -1394, -1219, -884, + -550, -207, +135, +93, +563, +449, +847, +669, + +1004, +1302, +1600, +1802, +2005, +2191, +2377, +2435, + +2494, +2477, +2460, +843, +763, +794, +1337, +3928, + +3960, +4011, +4062, +3985, +3908, +3883, +3858, +3833, + +3808, +3707, +3607, +3603, +3599, +3506, +3414, +3706, + +3998, +3916, +3835, +3786, +3737, +2208, -345, +78, + -12, -24, -36, -80, -124, -156, -188, -188, + +1598, +1585, +1829, +2154, -1873, -1413, -1208, -556, + -417, -514, -102, +440, +214, +191, +681, +435, + +702, +870, +1039, +1224, +1409, +1709, +2010, +2039, + +2069, +2086, +1849, +795, +766, +596, +2474, +3953, + +3896, +3928, +3962, +3914, +3868, +3842, +3818, +3792, + +3768, +3687, +3608, +3577, +3546, +3462, +3379, +3312, + +3245, +3364, +3484, +3189, +2893, +858, -154, +35, + -34, -48, -62, -108, -154, -154, -154, -154, + +1784, +1849, +1915, +892, -1666, -1176, -1711, -741, + -796, -822, +175, -748, +378, +191, +517, +202, + +400, +439, +479, +646, +814, +1229, +1645, +1644, + +1644, +1697, +1239, +748, +770, +399, +3613, +3978, + +3832, +3847, +3862, +3845, +3828, +3803, +3778, +3753, + +3728, +3669, +3611, +3552, +3494, +3419, +3345, +3174, + +3004, +2813, +2623, +2592, +2562, -237, +37, -9, + -56, -72, -88, -136, -184, -152, -120, -120, + +1802, +1900, +2255, -286, -1290, -1129, -712, -391, + -327, -385, -445, +201, -178, +436, +27, -45, + -118, +204, +270, +384, +498, +685, +874, +998, + +1123, +1252, +1127, +794, +717, +1161, +3654, +3843, + +3776, +3788, +3802, +3782, +3764, +3616, +3726, +3690, + +3656, +3595, +3536, +3476, +3417, +3341, +3265, +3078, + +2891, +2687, +2484, +2617, +1982, -28, +8, +14, + +18, -18, -54, +6, +66, -30, -126, -126, + +1820, +1696, +2084, -2232, -1939, -570, -1762, -1834, + -1394, -461, -552, -387, -223, -1110, -462, -37, + -124, -31, -451, -134, +183, +143, +104, +353, + +602, +809, +1017, +841, +665, +1924, +3696, +3708, + +3720, +3731, +3742, +3721, +3700, +3431, +3674, +3629, + +3584, +3523, +3462, +3401, +3341, +3264, +3187, +2982, + +2778, +2562, +2346, +2386, +891, -77, -20, +36, + +92, +36, -20, -108, -196, -164, -132, -132, + +1710, +1955, +1177, -2833, -955, -2075, -2172, -364, + -1885, -1352, -820, -1599, -843, -1249, -887, -652, + -674, -554, -435, -636, -325, -304, -282, -101, + -175, +493, +906, +871, +580, +2767, +3674, +3653, + +3632, +3656, +3682, +3626, +3572, +3436, +3558, +3534, + +3512, +3449, +3388, +3325, +3264, +3186, +3108, +2902, + +2697, +2500, +2304, +2219, +343, +179, +271, +154, + +38, -6, -50, -110, -170, -154, -138, -138, + +1600, +1959, -242, -2667, -2020, -2557, -2582, -1455, + +696, +316, +960, +2052, +2120, +1940, +1760, +1292, + +824, -310, -932, -1394, -832, -750, -668, -298, + -440, +434, +796, +902, +496, +3610, +3652, +3598, + +3544, +3583, +3622, +3533, +3444, +3443, +3442, +3441, + +3440, +3377, +3314, +3251, +3188, +3109, +3030, +2823, + +2616, +2439, +2262, +2053, -204, +179, +50, +17, + -16, -48, -80, -112, -144, -144, -144, -144, + +1956, +1852, -2091, -3025, -1145, +322, +2045, +1672, + +1555, +1328, +1614, +1916, +1706, +1622, +1282, +1502, + +1466, +1301, +1393, +940, -792, -1548, -768, -820, + -617, +926, +934, +909, +1397, +3323, +3456, +3446, + +3436, +3393, +3351, +3388, +3426, +3373, +3321, +3444, + +3313, +3264, +3217, +3153, +3090, +2997, +2906, +2686, + +2467, +2290, +2115, +1282, -61, +136, +79, +36, + -5, -37, -69, -101, -133, -133, -133, -133, + +1800, +1746, +669, +1992, +1779, +1665, +1552, +1727, + +1390, +1317, +1245, +1269, +1293, +1560, +1316, +1456, + +1084, +1121, +1158, +971, +1297, +726, -869, -1343, + -794, +1419, +1072, +917, +2299, +3036, +3261, +3294, + +3328, +3204, +3080, +3244, +3409, +3305, +3201, +3449, + +3186, +3153, +3121, +3056, +2992, +2887, +2783, +2550, + +2318, +2143, +1968, +513, +82, +95, +108, +57, + +6, -26, -58, -90, -122, -122, -122, -122, + +1516, +1832, +1636, +1905, +1406, +1344, +1283, +1589, + +1641, +1465, +1291, +1277, +1263, +1386, +1254, +1314, + +1118, +1116, +1115, +905, +953, +1160, +1111, +118, + -363, +807, +698, +700, +2240, +3325, +2361, +2934, + +3252, +2998, +2745, +2924, +3103, +3155, +2952, +3277, + +3091, +3057, +3024, +2959, +2894, +2776, +2659, +2414, + +2169, +2074, +1981, +255, +65, +68, +73, +44, + +17, -15, -47, -79, -111, -111, -111, -111, + +1744, +1662, +1581, +1563, +1546, +1536, +1527, +1453, + +1380, +1359, +1339, +1286, +1234, +1213, +1193, +1172, + +1152, +1112, +1073, +1097, +1122, +826, +1043, +1067, + +1092, +964, +837, +741, +2182, +2078, +2487, +2831, + +2664, +2793, +2923, +2860, +2798, +3007, +2705, +3106, + +2996, +2962, +2928, +2862, +2796, +2666, +2536, +2278, + +2020, +1751, +1482, -259, +48, +43, +38, +33, + +28, -4, -36, -68, -100, -100, -100, -100, + +1684, +1640, +1596, +1584, +1573, +1543, +1513, +1451, + +1391, +1359, +1329, +1282, +1236, +1213, +1190, +1168, + +1146, +1107, +1069, +1063, +1058, +920, +1038, +996, + +955, +924, +894, +880, +1635, +1679, +2235, +2439, + +2132, +2451, +2771, +2580, +2644, +2713, +2528, +2742, + +2701, +2828, +2699, +2570, +2442, +2383, +2324, +2105, + +1887, +1732, +811, -79, +55, +62, +71, +46, + +23, -7, -37, -67, -97, -113, -129, -129, + +1624, +1618, +1612, +1606, +1601, +1551, +1501, +1451, + +1402, +1361, +1320, +1279, +1239, +1214, +1189, +1164, + +1140, +1103, +1067, +1031, +995, +1014, +1034, +926, + +818, +885, +953, +1021, +1089, +1024, +1472, +2048, + +2112, +2110, +2109, +2044, +2491, +2421, +2352, +2379, + +2406, +2694, +2471, +2279, +2088, +2100, +2113, +1933, + +1754, +1715, +140, +101, +62, +83, +104, +61, + +18, -10, -38, -66, -94, -126, -158, -158, + +1724, +1788, +1852, +1692, +1532, +1494, +1456, +1418, + +1381, +1345, +1311, +1275, +1241, +1214, +1187, +1160, + +1134, +1098, +1064, +1029, +995, +996, +998, +935, + +873, +877, +883, +792, +702, +657, +1125, +1832, + +2284, +1193, +1638, +1796, +2209, +2320, +2176, +2239, + +2047, +2560, +2562, +1891, +1734, +1673, +1613, +1744, + +1621, +1152, -83, -8, +69, +70, +73, +42, + +13, -13, -39, -65, -91, -139, -187, -187, + +1824, +1702, +1580, +1522, +1464, +1438, +1412, +1386, + +1360, +1331, +1302, +1273, +1244, +1215, +1186, +1157, + +1128, +1095, +1062, +1029, +996, +979, +962, +945, + +928, +871, +814, +821, +828, +803, +1290, +1617, + +1944, +2068, +1168, +1292, +1416, +1708, +1488, +1844, + +1688, +2171, +2142, +1249, +1380, +1503, +1626, +1045, + -48, +79, +206, +141, +76, +59, +42, +25, + +8, -16, -40, -64, -88, -152, -216, -216, + +1688, +1615, +1542, +1501, +1460, +1429, +1398, +1367, + +1336, +1309, +1284, +1257, +1232, +1205, +1180, +1153, + +1128, +1092, +1058, +1022, +988, +968, +950, +930, + +912, +861, +812, +793, +776, +595, +672, +971, + +1272, +330, +924, +1038, +1152, +1298, +1444, +1910, + +1608, +1531, +1200, +515, +344, +259, +176, +251, + +72, +122, +174, +128, +84, +64, +46, +26, + +8, -18, -44, -70, -96, -144, -192, -192, + +1552, +1528, +1504, +1480, +1456, +1420, +1384, +1348, + +1312, +1289, +1266, +1243, +1220, +1197, +1174, +1151, + +1128, +1091, +1054, +1017, +980, +959, +938, +917, + +896, +853, +810, +767, +724, +645, +566, +583, + +600, +640, +680, +528, +376, +376, +888, +1464, + +1016, +637, +258, +295, +332, +297, +262, +227, + +192, +167, +142, +117, +92, +71, +50, +29, + +8, -20, -48, -76, -104, -136, -168, -168, + +1544, +1521, +1498, +1475, +1452, +1411, +1370, +1329, + +1288, +1267, +1248, +1227, +1208, +1187, +1168, +1147, + +1128, +1088, +1050, +1010, +972, +948, +926, +902, + +880, +843, +808, +771, +736, +677, +620, +609, + +600, +614, +628, +546, +464, +238, +2060, +1690, + +1576, +1709, +308, +313, +320, +285, +252, +217, + +184, +162, +142, +120, +100, +76, +54, +30, + +8, -22, -52, -82, -112, -128, -144, -144, + +1536, +1514, +1492, +1470, +1448, +1402, +1356, +1310, + +1264, +1247, +1230, +1213, +1196, +1179, +1162, +1145, + +1128, +1087, +1046, +1005, +964, +939, +914, +889, + +864, +835, +806, +777, +748, +711, +674, +637, + +600, +588, +576, +564, +552, +612, +160, +1916, + +1112, +223, +358, +333, +308, +275, +242, +209, + +176, +159, +142, +125, +108, +83, +58, +33, + +8, -24, -56, -88, -120, -120, -120, -120, + +1536, +1514, +1492, +1470, +1448, +1402, +1356, +1310, + +1264, +1246, +1230, +1212, +1196, +1178, +1162, +1144, + +1128, +1086, +1046, +1004, +964, +938, +914, +888, + +864, +834, +806, +776, +748, +710, +674, +636, + +600, +588, +576, +564, +552, +644, +480, +108, + +504, +158, +326, +316, +308, +274, +242, +208, + +176, +158, +142, +124, +108, +82, +58, +32, + +8, -24, -56, -88, -120, -120, -120, -120, + +1536, +1514, +1492, +1470, +1448, +1402, +1356, +1310, + +1264, +1247, +1230, +1213, +1196, +1179, +1162, +1145, + +1128, +1087, +1046, +1005, +964, +939, +914, +889, + +864, +835, +806, +777, +748, +711, +674, +637, + +600, +588, +576, +564, +552, +420, +288, +348, + +408, +351, +294, +301, +308, +275, +242, +209, + +176, +159, +142, +125, +108, +83, +58, +33, + +8, -24, -56, -88, -120, -120, -120, -120, + +1536, +1514, +1492, +1470, +1448, +1402, +1356, +1310, + +1264, +1246, +1230, +1212, +1196, +1178, +1162, +1144, + +1128, +1086, +1046, +1004, +964, +938, +914, +888, + +864, +834, +806, +776, +748, +710, +674, +636, + +600, +588, +576, +564, +552, +420, +288, +348, + +408, +350, +294, +300, +308, +274, +242, +208, + +176, +158, +142, +124, +108, +82, +58, +32, + +8, -24, -56, -88, -120, -120, -120, -120 +}; + +static INT16 TEST_CB_COMPONENT[4096] = +{ + +1728, +1730, +1732, +1734, +1736, +1738, +1740, +1742, + +1744, +1740, +1736, +1732, +1728, +1796, +1864, +1804, + +1744, +1754, +1764, +1774, +1784, +1794, +1804, +1814, + +1824, +1774, +1724, +1802, +1880, +1814, +1748, +1810, + +1872, +1878, +1884, +1890, +1896, +1910, +1924, +1938, + +1952, +1938, +1924, +1910, +1896, +1914, +1932, +1950, + +1968, +1974, +1980, +1986, +1992, +1998, +2004, +2010, + +2016, +2016, +2016, +2016, +2016, +2016, +2016, +2016, + +1710, +1697, +1684, +1704, +1723, +1726, +1730, +1733, + +1737, +1738, +1740, +1741, +1743, +1758, +1774, +1757, + +1741, +1762, +1783, +1788, +1793, +1774, +1755, +1784, + +1813, +1817, +1821, +1825, +1829, +1857, +1885, +1881, + +1877, +1849, +1821, +1857, +1894, +1904, +1914, +1924, + +1935, +1928, +1922, +1915, +1909, +1922, +1936, +1949, + +1963, +1974, +1985, +1997, +2008, +2009, +2011, +2012, + +2014, +2017, +2020, +2023, +2026, +2026, +2026, +2026, + +1692, +1664, +1637, +1674, +1711, +1715, +1720, +1725, + +1730, +1737, +1744, +1751, +1758, +1721, +1684, +1711, + +1738, +1770, +1802, +1802, +1802, +1754, +1706, +1754, + +1802, +1860, +1918, +1848, +1778, +1900, +2022, +1952, + +1882, +1820, +1759, +1825, +1892, +1898, +1905, +1911, + +1918, +1919, +1920, +1921, +1922, +1931, +1940, +1949, + +1958, +1974, +1991, +2008, +2025, +2021, +2018, +2015, + +2012, +2018, +2024, +2030, +2036, +2036, +2036, +2036, + +1674, +1631, +1589, +1644, +1698, +1703, +1710, +1716, + +1723, +1735, +1748, +1760, +1773, +1763, +1754, +1760, + +1767, +1794, +1821, +1800, +1779, +1830, +1881, +1900, + +1919, +2047, +2175, +2015, +1855, +1879, +1903, +1927, + +1951, +1759, +1824, +1856, +1890, +1892, +1895, +1897, + +1901, +1909, +1918, +1926, +1935, +1939, +1944, +1948, + +1953, +1974, +1996, +2019, +2041, +2032, +2025, +2017, + +2010, +2019, +2028, +2037, +2046, +2046, +2046, +2046, + +1656, +1599, +1543, +1614, +1686, +1693, +1701, +1708, + +1716, +1734, +1752, +1770, +1788, +1806, +1824, +1810, + +1796, +1818, +1840, +2054, +2268, +1650, +1032, +510, + -12, -70, -128, +390, +908, +1602, +2296, +2158, + +2020, +1699, +1890, +1889, +1888, +1887, +1886, +1885, + +1884, +1900, +1916, +1932, +1948, +1948, +1948, +1948, + +1948, +1975, +2003, +2030, +2058, +2045, +2033, +2020, + +2008, +2020, +2032, +2044, +2056, +2056, +2056, +2056, + +1590, +1570, +1551, +1612, +1673, +1579, +1742, +1713, + +1685, +1672, +1660, +1711, +1763, +1694, +1626, +1941, + +2001, +2060, +583, -654, -1891, -2046, -2201, -2084, + -1967, -2049, -2131, -2053, -1975, -1751, -1527, +41, + +1609, +2374, +1859, +2000, +1886, +1898, +1912, +1909, + +1907, +1900, +1894, +1919, +1945, +1944, +1944, +1943, + +1943, +1967, +1992, +2017, +2042, +2032, +2023, +2014, + +2006, +2017, +2028, +2039, +2050, +2050, +2050, +2050, + +1524, +1542, +1560, +1610, +1661, +1467, +1785, +1719, + +1654, +1611, +1568, +1653, +1738, +1839, +1940, +793, + -866, -2050, -2210, -2082, -1954, -1902, -1850, -1862, + -1874, -1980, -2086, -1936, -1786, -1776, -1766, -1820, + -1874, -534, +1829, +2112, +1884, +1911, +1939, +1934, + +1930, +1901, +1872, +1907, +1942, +1941, +1940, +1939, + +1938, +1960, +1982, +2004, +2027, +2021, +2015, +2009, + +2004, +2014, +2024, +2034, +2044, +2044, +2044, +2044, + +1586, +1641, +1697, +1704, +1712, +1577, +1699, +1660, + +1623, +1613, +1604, +1642, +1681, +1791, -402, -2036, + -1877, -2144, -1899, -1942, -1985, -1918, -1851, -1880, + -1909, -1959, -2009, -1931, -1853, -1801, -1749, -1617, + -1485, -1939, -1882, +96, +2074, +1971, +1869, +1895, + +1921, +1885, +1850, +1894, +1939, +1937, +1936, +1934, + +1933, +1952, +1972, +1991, +2011, +2008, +2006, +2003, + +2002, +2011, +2020, +2029, +2038, +2038, +2038, +2038, + +1136, +1229, +1322, +1287, +1252, +1433, +1614, +1603, + +1592, +1616, +1640, +1632, +1624, +2256, -1720, -1792, + -1864, -1982, -2100, -2058, -2016, -1934, -1852, -1898, + -1944, -1938, -1932, -1926, -1920, -1826, -1732, -1670, + -1608, -1552, -1496, -1664, -1320, +2288, +1800, +1856, + +1912, +1870, +1828, +1882, +1936, +1934, +1932, +1930, + +1928, +1945, +1962, +1979, +1996, +1997, +1998, +1999, + +2000, +2008, +2016, +2024, +2032, +2032, +2032, +2032, + +1552, +1624, +1698, +1674, +1652, +1644, +1638, +1614, + +1592, +1611, +1630, +1681, +1733, +1146, -2000, -1787, + -1830, -1924, -2019, -2049, -2080, -1986, -1893, -1895, + -1898, -1896, -1894, -1860, -1827, -1779, -1731, -1667, + -1604, -1615, -1626, -1878, -594, +2063, +1903, +2016, + +1873, +2132, +1880, +1884, +1888, +1921, +1955, +1941, + +1927, +1925, +1925, +1955, +1987, +2005, +2025, +2043, + +2063, +1995, +1927, +2099, +2015, +2095, +2175, +2175, + +1456, +1509, +1562, +1551, +1540, +1601, +1662, +1627, + +1592, +1606, +1621, +1731, +1842, +37, -2281, -1782, + -1796, -1867, -1938, -2041, -2144, -2039, -1934, -1893, + -1852, -1854, -1857, -1795, -1734, -1732, -1731, -1665, + -1600, -1678, -1757, -1836, +645, +2094, +2007, +1920, + +1322, +2139, +1933, +1886, +1840, +1909, +1979, +1952, + +1926, +1907, +1888, +1933, +1978, +2015, +2052, +2089, + +2126, +1982, +1838, +2174, +1998, +2158, +2318, +2318, + +1488, +1520, +1554, +1554, +1556, +1588, +1622, +1606, + +1592, +1569, +1547, +1700, +1855, -993, -2049, -1825, + -1858, -1905, -1953, -2016, -2080, -1995, -1911, -1858, + -1806, -1812, -1819, -1729, -1641, -1685, -1730, -1678, + -1628, -1677, -1727, -2194, +1947, +2125, +2046, +945, + -2205, +114, +2177, +2144, +1856, +1912, +1970, +1963, + +1957, +1935, +1915, +1925, +1937, +1991, +2047, +2181, + +2061, +2337, +2613, +1817, +2301, +2157, +2269, +2397, + +1520, +1533, +1546, +1559, +1572, +1577, +1582, +1587, + +1592, +1533, +1474, +1671, +1868, -2023, -1818, -1869, + -1920, -1944, -1968, -1992, -2016, -1952, -1888, -1824, + -1760, -1771, -1782, -1665, -1548, -1639, -1730, -1693, + -1656, -1677, -1699, -1017, +2226, +1644, +2087, -286, + -2148, -2167, -1674, +611, +2384, +2173, +1962, +1975, + +1988, +1965, +1942, +1919, +1896, +1969, +2042, +2019, + +1484, -1916, -1220, +2484, +1068, -916, +1708, +1964, + +1504, +1514, +1526, +1536, +1548, +1550, +1554, +1556, + +1560, +1581, +1604, +1786, +689, -2138, -1894, -1905, + -1918, -1926, -1935, -1943, -1952, -1878, -1805, -1731, + -1658, -1626, -1596, -1549, -1503, -1507, -1513, -1518, + -1524, -1526, -1785, +148, +2080, +1995, +2422, -2094, + -2003, -2033, -1809, -1665, -1776, -189, +1398, +2536, + +2139, +2122, +2105, +2327, +2295, +2204, +2113, +2870, + -213, -1669, -1077, -1237, -1653, -1589, +2059, +1931, + +1488, +1497, +1506, +1515, +1524, +1525, +1526, +1527, + +1528, +1631, +1735, +1902, -490, -2254, -1971, -1943, + -1916, -1909, -1902, -1895, -1888, -1805, -1722, -1639, + -1556, -1483, -1411, -1434, -1458, -1377, -1297, -1344, + -1392, -1376, -1872, +1312, +1935, +1834, +1734, -2622, + -2370, -2157, -1945, -1892, -1840, -2039, -2239, -2022, + -782, -281, +220, +433, +134, -377, -888, -1655, + -1398, -1166, -934, -1374, -1302, -726, +2410, +1898, + +1472, +1478, +1486, +1492, +1500, +1498, +1498, +1496, + +1496, +1600, +1705, +1666, -933, -1474, -2015, -1964, + -1914, -1891, -1869, -1846, -1824, -1731, -1639, -1546, + -1454, -1387, -1321, -1191, -1317, -1150, -1240, -1250, + -1260, -1545, -1575, +2459, +1885, +2057, +182, -2429, + -2225, -2088, -1952, -1928, -1904, -1905, -1907, -2149, + -1879, -1835, -1793, -1670, -1803, -1645, -1489, -1491, + -1239, -1335, -1431, -1335, -1495, +681, +2345, +2089, + +1456, +1461, +1466, +1471, +1476, +1473, +1470, +1467, + +1464, +1570, +1676, +1174, -1888, -950, -2060, -1986, + -1912, -1874, -1836, -1798, -1760, -1658, -1556, -1454, + -1352, -1292, -1232, -1204, -1688, -1180, -1184, -1156, + -1128, -1203, -254, +2071, +1836, +2281, -1370, -2237, + -2080, -2020, -1960, -1964, -1968, -2028, -2088, -2020, + -1952, -1855, -1758, -1725, -1692, -1635, -1578, -1329, + -1592, -1504, -1416, -1040, -1688, +2088, +2280, +2280, + +1428, +1438, +1450, +1460, +1472, +1463, +1454, +1493, + +1533, +1512, +1748, -160, -2068, -1346, -1137, -1775, + -1902, -1848, -1794, -1708, -1622, -1544, -1466, -1356, + -1247, -1198, -1149, -1196, -1755, -1246, -993, -1012, + -1032, -1202, +930, +2023, +1837, +2238, -2480, -2286, + -1838, -1799, -1761, -1835, -1909, -1954, -2000, -1982, + -1964, -1908, -1853, -1829, -1807, -1749, -1692, -1538, + -1642, -1526, -1410, -638, -122, +774, +1926, +1926, + +1400, +1417, +1434, +1451, +1469, +1454, +1439, +1520, + +1602, +1455, +1820, -1239, -1737, -1743, -726, -1821, + -1892, -1822, -1752, -1618, -1485, -1431, -1377, -1259, + -1142, -1104, -1066, -1188, -1823, -1313, -803, -869, + -936, -1203, +2115, +1976, +1838, +916, -2055, -1569, + -1596, -1579, -1563, -1706, -1850, -1881, -1913, -1944, + -1976, -1962, -1949, -1935, -1922, -1864, -1807, -1749, + -1692, -1548, -1404, -1004, -92, +996, +2084, +2084, + +1372, +1394, +1418, +1441, +1465, +1444, +1423, +1483, + +1543, +1765, +1732, -2204, -1533, -1611, -1179, -1274, + -1882, -1764, -1646, -1560, -1475, -1301, -1127, -1113, + -1101, -994, -887, -1052, -1730, -1395, -804, -709, + -872, -306, +2051, +1929, +2063, -151, -1597, -1347, + -1354, -1326, -1300, -1417, -1535, -1599, -1665, -1730, + -1796, -1824, -1852, -1880, -1909, -1883, -1857, -1767, + -1678, -1570, -1462, -1434, +1154, +2402, +1858, +1858, + +1344, +1373, +1403, +1432, +1462, +1435, +1409, +1446, + +1484, +1564, +621, -1890, -1842, -1737, -1633, -728, + -1872, -1706, -1541, -1503, -1466, -1428, -1391, -1225, + -1060, -884, -709, -917, -1638, -1478, -807, -551, + -808, +590, +1988, +1882, +2288, -1218, -1140, -1126, + -1112, -1075, -1038, -1129, -1220, -1319, -1418, -1517, + -1616, -1686, -1756, -1826, -1896, -1902, -1908, -1786, + -1664, -1592, -1520, -1864, +2400, +2016, +2144, +2144, + +1348, +1372, +1398, +1424, +1450, +1463, +1477, +1491, + +1505, +1729, -607, -1838, -1790, -1735, -1681, -1003, + -1350, -1710, -1558, -1519, -1480, -1382, -1285, -1379, + -1475, -1208, -941, -611, -793, -796, -800, -611, + -680, +1364, +1872, +1932, +1481, -1150, -966, -926, + -886, -868, -851, -929, -1009, -1061, -1114, -1230, + -1348, -1521, -1695, -1805, -1915, -1900, -1886, -1792, + -1698, -1604, -1766, -744, +2326, +2134, +2198, +2198, + +1352, +1373, +1395, +1417, +1439, +1492, +1546, +1536, + +1526, +1894, -1835, -1787, -1739, -1735, -1731, -1279, + -828, -1714, -1577, -1536, -1495, -1337, -1180, -1023, + -866, -764, -663, -562, -973, -371, -282, -417, + -552, +2138, +1757, +1983, +674, -1083, -793, -726, + -660, -662, -665, -731, -798, -804, -811, -945, + -1080, -1357, -1635, -1784, -1934, -1899, -1865, -1798, + -1732, -1616, -2012, +376, +2252, +2252, +2252, +2252, + +1356, +1373, +1391, +1409, +1427, +1425, +1423, +1501, + +1579, +907, -1814, -1702, -1847, -1909, -1716, -1634, + -786, -1686, -1819, -1712, -1605, -1371, -1139, -921, + -705, -656, -608, -384, -416, -233, -308, -477, + +376, +1968, +1769, +2033, -5, -839, -651, -606, + -562, -584, -606, -660, -715, -739, -763, -963, + -1164, -1432, -1702, -1843, -1985, -1977, -1971, -1884, + -1798, -2012, -2226, +2152, +2178, +2194, +2210, +2210, + +1360, +1374, +1388, +1402, +1416, +1358, +1300, +1466, + +1632, -81, -1794, -1619, -1956, -2085, -1702, -1991, + -744, -891, -526, -353, -180, -383, -586, -821, + -1056, -805, -554, -463, -372, -353, -334, -539, + +1304, +1799, +1782, +2085, -684, -597, -510, -487, + -464, -506, -548, -590, -632, -674, -716, -982, + -1248, -1509, -1770, -1903, -2036, -2057, -2078, -1971, + -1864, -1896, -1416, +2392, +2104, +2136, +2168, +2168, + +1346, +1358, +1371, +1383, +1396, +1395, +1393, +1552, + +1711, -1177, -1762, -2203, -1364, -465, +690, +1942, + +1913, +1747, +1837, +1816, +1794, +1889, +1983, +1774, + +1564, +548, -468, -299, -386, -391, -398, -147, + +1895, +1920, +1946, +1284, -401, -397, -393, -421, + -450, -478, -507, -568, -629, -722, -815, -1068, + -1321, -1697, -2074, -2082, -2091, -2129, -2168, -2030, + -1894, -2028, +142, +2280, +2114, +2082, +2050, +2050, + +1332, +1343, +1354, +1365, +1377, +1432, +1487, +1382, + +1278, -1763, -195, +1308, +1788, +1667, +1547, +1522, + +1498, +1569, +1641, +1681, +1721, +1600, +1480, +1552, + +1624, +1901, +2179, +1145, -401, -431, -462, -12, + +1974, +1786, +2111, +484, -119, -198, -277, -356, + -436, -451, -467, -547, -627, -770, -914, -898, + -882, -606, -330, -470, -611, -1435, -2259, -2091, + -1924, -2160, +1700, +2168, +2124, +2028, +1932, +1932, + +1318, +1327, +1337, +1346, +1357, +1405, +1452, +1420, + +1389, +1381, +1629, +1748, +1356, +1495, +1635, +1631, + +1627, +1551, +1732, +1689, +1647, +1728, +1809, +1730, + +1652, +1686, +1721, +1948, +1921, +874, -430, +363, + +1925, +1764, +1859, +148, -28, -95, -160, -291, + -422, -423, -426, -557, -688, -370, -309, -280, + -251, -570, -890, -858, -826, -563, -301, -1079, + -1858, -1636, +2170, +2296, +2166, +2118, +2070, +2070, + +1304, +1312, +1321, +1329, +1338, +1378, +1419, +1459, + +1500, +1452, +1404, +1420, +1436, +1580, +1724, +1484, + +1244, +1022, +1313, +1187, +1062, +1088, +1115, +1397, + +1680, +1728, +1777, +1729, +1682, +1922, +1651, +1763, + +1876, +1742, +1609, -189, +62, +8, -45, -226, + -408, -397, -387, -568, -750, -227, -217, -430, + -644, -1047, -1451, -1502, -1554, -1229, -905, -580, + -256, -856, +1616, +1912, +2208, +2208, +2208, +2208, + +1290, +1304, +1319, +1334, +1350, +1377, +1404, +1271, + +1395, +1525, +1655, +1769, +1884, +1802, +1720, +1430, + +1141, +1026, +1168, +1037, +908, +700, +491, +331, + +172, +873, +1575, +1524, +1731, +1991, +1738, +1774, + +1811, +1914, +993, -119, +48, -74, -196, -271, + -346, -407, -470, -324, -179, -213, -503, -810, + -1117, -1273, -1430, -1636, -1841, -1823, -1551, -1246, + -686, +1194, +1026, +1610, +2194, +2194, +2194, +2194, + +1276, +1297, +1319, +1341, +1363, +1376, +1390, +1340, + +1802, +1854, +1907, +1863, +1820, +1768, +1717, +1377, + +1038, +1031, +1024, +889, +755, +568, +381, +290, + +200, +19, -162, +553, +1781, +2060, +1827, +1786, + +1746, +2086, +378, -50, +35, -156, -348, -316, + -284, -419, -554, -337, -121, -456, -791, -934, + -1078, -1244, -1411, -1514, -1617, -1907, -1686, -1657, + -1116, +1964, +1972, +2076, +2180, +2180, +2180, +2180, + +1262, +1289, +1318, +1346, +1375, +1359, +1344, +1632, + +1921, +1927, +1934, +1876, +1820, +1702, +1585, +1259, + +935, +907, +880, +724, +569, +436, +302, +217, + +132, +44, -43, -99, +102, +801, +2011, +1878, + +1745, +1426, +2131, +916, -43, -191, -340, -393, + -446, -461, -478, -237, -254, -522, -790, -962, + -1135, -1519, -1647, -1760, -1872, -1446, -2045, -1827, + -1354, +2254, +2278, +2222, +2166, +2166, +2166, +2166, + +1248, +1283, +1318, +1353, +1388, +1343, +1298, +1925, + +2040, +2001, +1962, +1891, +1820, +1637, +1454, +1143, + +832, +784, +736, +560, +384, +304, +224, +144, + +64, +70, +76, +18, -40, +54, +1684, +1714, + +1744, +1790, +1836, +1882, +1928, +798, -332, -470, + -608, -505, -402, -139, -388, -589, -790, -991, + -1192, -1794, -1884, -2006, -2128, -2266, -868, +818, + +2504, +2288, +2072, +2112, +2152, +2152, +2152, +2152, + +1238, +1263, +1290, +1332, +1375, +1301, +1484, +2002, + +2009, +1973, +1939, +1871, +1805, +1608, +1411, +1118, + +826, +751, +676, +505, +334, +273, +212, +151, + +91, +69, +48, +11, -26, +482, +1758, +1771, + +1784, +2033, +1771, +1860, +1950, +1989, +2029, +884, + -260, -1156, -261, -309, -614, -922, -975, -1411, + -1848, -2062, -2019, -697, +626, +2060, +2471, +2273, + +2076, +2051, +2026, +2081, +2136, +2136, +2136, +2136, + +1228, +1245, +1263, +1313, +1363, +1260, +1670, +2080, + +1978, +1947, +1916, +1853, +1791, +1580, +1369, +1094, + +820, +718, +616, +450, +285, +243, +201, +159, + +118, +69, +20, +4, -13, +910, +1833, +1828, + +1824, +229, +1706, +1839, +1972, +1901, +1830, +1983, + +2136, +2032, +1416, +1056, +696, +280, +376, +728, + +1080, +1767, +2454, +2405, +2356, +2035, +2226, +2193, + +2160, +2070, +1980, +2050, +2120, +2120, +2120, +2120, + +1218, +1226, +1235, +1292, +1350, +1235, +1888, +2061, + +1979, +1935, +1893, +1834, +1776, +1551, +1326, +1070, + +814, +685, +556, +395, +235, +212, +189, +166, + +145, +116, +88, -68, +33, +1306, +1811, +1949, + +1576, -200, -183, +905, +1994, +1956, +1919, +1881, + +1844, +2004, +1909, +2005, +2102, +2042, +2239, +2195, + +2152, +2043, +1935, +2370, +2038, +2697, +1821, +368, + +2244, +2121, +1998, +2051, +2104, +2104, +2104, +2104, + +1208, +1208, +1209, +1273, +1338, +1210, +2107, +2043, + +1980, +1925, +1871, +1816, +1762, +1523, +1285, +1046, + +808, +652, +497, +341, +186, +182, +179, +175, + +172, +164, +157, +117, +590, +1958, +1791, +1815, + +816, +140, -24, -28, -32, +988, +2008, +2036, + +2064, +1977, +1890, +1931, +1972, +2013, +2054, +2127, + +2200, +2320, +2440, +2080, +184, -1760, -3192, +336, + +2328, +2172, +2016, +2052, +2088, +2088, +2088, +2088, + +1222, +1215, +1209, +1266, +1325, +1459, +2104, +2046, + +1989, +1945, +1903, +1861, +1819, +1612, +1406, +1136, + +866, +715, +564, +446, +328, +295, +263, +230, + +199, +481, +764, +711, +1427, +2086, +1721, +1692, + +128, -37, +55, -14, -82, -108, -135, +335, + +804, +1293, +1783, +2272, +2250, +2197, +1889, +1356, + +568, -763, -2095, -3010, -2646, -2931, -2705, +2305, + +2196, +2159, +2122, +2117, +2112, +2112, +2112, +2112, + +1236, +1223, +1210, +1261, +1313, +1708, +2103, +2050, + +1998, +1967, +1937, +1907, +1877, +1702, +1528, +1226, + +924, +778, +633, +552, +471, +409, +348, +287, + +226, +287, +349, +283, +1241, +1702, +1652, +1826, + -48, +43, +134, +1, -132, -181, -230, -343, + -456, -670, -884, -202, -544, -946, -1860, -1718, + -2088, -2311, -2534, -2469, -2404, -2311, -1706, +2483, + +2064, +2146, +2228, +2182, +2136, +2136, +2136, +2136, + +1250, +1230, +1211, +1255, +1300, +1957, +2101, +2054, + +2007, +1956, +1906, +1856, +1806, +1696, +1586, +1284, + +982, +841, +701, +657, +613, +554, +497, +438, + +381, +412, +445, +717, +1758, +1782, +1807, +1095, + -128, -70, -11, -97, -182, -253, -325, -428, + -532, -761, -991, -580, -170, -1033, -873, -1976, + -1800, -2018, -2237, -2343, -2450, -2650, -35, +2308, + +2092, +2117, +2142, +2151, +2160, +2160, +2160, +2160, + +1264, +1238, +1212, +1250, +1288, +2206, +2100, +2058, + +2016, +1946, +1876, +1806, +1736, +1690, +1644, +1342, + +1040, +905, +770, +763, +756, +701, +646, +591, + +536, +539, +542, +897, +1764, +1607, +1962, +365, + -208, -182, -156, -194, -232, -326, -420, -514, + -608, -853, -1098, -1471, -820, -97, -910, -955, + -2024, -2238, -2452, -2474, -2496, -2990, +1636, +2134, + +2120, +2088, +2056, +2120, +2184, +2184, +2184, +2184, + +1198, +1191, +1185, +1227, +1525, +2065, +2093, +2009, + +1925, +1887, +1850, +1781, +1712, +1682, +1653, +1464, + +1275, +1130, +986, +937, +889, +840, +792, +743, + +696, +684, +674, +1335, +1741, +1839, +1939, +54, + -294, -295, -297, -298, -300, -414, -527, -641, + -755, -947, -1140, -1732, -1813, -733, -166, -1038, + -887, -1234, -1581, -1609, -1636, -1158, +2392, +2279, + +2166, +2119, +2072, +2121, +2170, +2170, +2170, +2170, + +1132, +1145, +1159, +1205, +1763, +1924, +2086, +1960, + +1834, +1829, +1825, +1756, +1688, +1675, +1663, +1586, + +1510, +1356, +1202, +1112, +1023, +981, +939, +897, + +856, +831, +807, +1774, +1718, +1817, +1405, -512, + -380, -409, -438, -403, -369, -502, -635, -768, + -902, -1042, -1182, -1482, -1782, -2138, -1982, -610, + -262, -486, -711, -744, -777, +162, +2125, +1912, + +2212, +2150, +2088, +2122, +2156, +2156, +2156, +2156, + +1194, +1146, +1100, +1182, +1776, +1927, +2079, +1863, + +1903, +1978, +1799, +1843, +1632, +1619, +1608, +1612, + +1617, +1517, +1418, +1351, +1284, +1216, +1149, +1098, + +1048, +945, +1099, +1781, +1695, +1954, +422, -566, + -530, -554, -579, -571, -565, -686, -806, -927, + -1049, -1232, -1416, -1679, -1943, -2342, -2486, -2501, + -2773, -2074, -1376, -1671, -2221, +458, +2369, +2137, + +2162, +2133, +2104, +2123, +2142, +2142, +2142, +2142, + +1256, +1149, +1043, +1160, +1790, +1931, +2073, +1766, + +1972, +2129, +1774, +1931, +1576, +1565, +1554, +1639, + +1724, +1679, +1635, +1590, +1546, +1453, +1361, +1300, + +1240, +1060, +1392, +1788, +1672, +2092, -560, -620, + -680, -700, -721, -741, -762, -870, -979, -1087, + -1196, -1423, -1650, -1877, -2104, -2291, -2478, -2857, + -2724, -2895, -3067, -3110, -3666, +2547, +2103, +2107, + +2112, +2116, +2120, +2124, +2128, +2128, +2128, +2128, + +1214, +1170, +1128, +1453, +1779, +1692, +1861, +1807, + +1753, +1732, +1712, +1803, +1640, +1759, +1623, +1710, + +1799, +1666, +1790, +1755, +1719, +1628, +1539, +1497, + +1456, +1352, +1504, +1752, +1745, +1445, -902, -898, + -894, -907, -921, -935, -950, -1070, -1190, -1310, + -1431, -1641, -1852, -2062, -2273, -2431, -2590, -2812, + -2779, -2929, -3080, -3279, -2198, +2298, +2187, +2124, + +2062, +2081, +2100, +2119, +2138, +2138, +2138, +2138, + +1172, +1193, +1214, +1747, +1769, +1710, +2163, +2360, + +2046, +1592, +1651, +1677, +1704, +1954, +1693, +1783, + +1874, +1654, +1947, +1920, +1893, +1805, +1718, +1695, + +1672, +1644, +1617, +1717, +1818, +798, -1245, -1176, + -1108, -1115, -1123, -1131, -1139, -1270, -1402, -1534, + -1666, -1860, -2054, -2248, -2442, -2572, -2702, -2768, + -2834, -2964, -3094, -3192, -219, +2306, +2272, +2142, + +2012, +2046, +2080, +2114, +2148, +2148, +2148, +2148, + +1194, +1150, +1364, +1784, +1694, +1983, +2272, +1441, + +2147, +1980, +1813, +1838, +1864, +1909, +1698, +1823, + +1949, +1818, +1943, +1989, +2034, +1933, +1833, +1812, + +1792, +1712, +1633, +1649, +1923, -536, -1459, -1390, + -1322, -1354, -1388, -1421, -1455, -1566, -1678, -1789, + -1901, -2078, -2256, -2433, -2611, -2744, -2878, -2915, + -2953, -2998, -3044, -3777, +1633, +2298, +1941, +2015, + +2090, +2107, +2124, +2141, +2158, +2158, +2158, +2158, + +1216, +1109, +1514, +1823, +1620, +2001, +1870, +1803, + +1224, +1600, +1464, +1232, +1000, +1096, +1192, +1352, + +1512, +1726, +1940, +2058, +2176, +2062, +1948, +1930, + +1912, +1781, +1650, +1583, +2028, -1871, -1674, -1605, + -1536, -1595, -1654, -1713, -1772, -1863, -1954, -2045, + -2136, -2297, -2458, -2619, -2780, -2917, -3054, -3063, + -3072, -3033, -2994, -2827, +2460, +2035, +2122, +2145, + +2168, +2168, +2168, +2168, +2168, +2168, +2168, +2168, + +1190, +1271, +1610, +1756, +1647, +1523, +1144, +1324, + +1249, +1364, +1224, +1211, +1199, +1255, +1566, +1430, + +1294, +1404, +1514, +1800, +2087, +2075, +2063, +2003, + +1944, +1654, +1621, +1811, +979, -1997, -1903, -1888, + -1874, -1927, -1982, -2036, -2091, -2163, -2236, -2308, + -2381, -2513, -2646, -2778, -2911, -3005, -3100, -3114, + -3129, -3039, -3206, -1084, +2317, +2104, +2148, +2159, + +2171, +2175, +2179, +2183, +2187, +2187, +2187, +2187, + +1164, +1179, +1195, +1179, +1163, +1302, +1442, +1358, + +1274, +1385, +1496, +1447, +1399, +1158, +1429, +1508, + +1588, +1594, +1601, +1543, +1486, +1832, +2179, +2077, + +1976, +1528, +1593, +1785, -582, -2381, -2133, -2172, + -2212, -2261, -2311, -2361, -2411, -2464, -2518, -2572, + -2626, -2730, -2834, -2938, -3042, -3094, -3146, -3166, + -3186, -3046, -3418, +658, +2174, +2174, +2174, +2174, + +2174, +2182, +2190, +2198, +2206, +2206, +2206, +2206, + +1202, +1230, +1259, +1272, +1286, +1321, +1356, +1343, + +1331, +1405, +1480, +1474, +1470, +1349, +1483, +1522, + +1562, +1576, +1591, +1573, +1557, +1589, +1622, +1718, + +1816, +1690, +1820, +1694, -2015, -2556, -2330, -2376, + -2422, -2610, -2799, -2700, -2602, -2669, -2736, -2803, + -2871, -2946, -3022, -3097, -3173, -3182, -3192, -3153, + -3115, -3324, -3278, +2256, +2159, +2147, +2136, +2156, + +2177, +2189, +2201, +2213, +2225, +2225, +2225, +2225, + +1240, +1282, +1325, +1367, +1410, +1340, +1271, +1329, + +1388, +1426, +1465, +1503, +1542, +1540, +1539, +1537, + +1536, +1559, +1582, +1605, +1628, +1603, +1578, +1617, + +1656, +1596, +1536, +1604, -2936, -2476, -2528, -2580, + -2632, -2704, -2777, -2785, -2794, -2874, -2955, -3035, + -3116, -3163, -3210, -3257, -3304, -3271, -3238, -3141, + -3044, -3091, -2114, +2319, +2144, +2121, +2098, +2139, + +2180, +2196, +2212, +2228, +2244, +2244, +2244, +2244, + +1230, +1255, +1281, +1306, +1333, +1303, +1272, +1338, + +1405, +1436, +1468, +1500, +1533, +1535, +1537, +1539, + +1542, +1562, +1584, +1605, +1627, +1601, +1577, +1616, + +1656, +1807, +1959, -417, -2793, -2797, -2545, -2581, + -2618, -2687, -2757, -2794, -2833, -2901, -2968, -3036, + -3105, -3145, -3186, -3178, -3171, -3149, -3128, -3058, + -2989, -3221, -126, +2281, +2129, +2084, +2040, +2107, + +2175, +2189, +2203, +2217, +2231, +2231, +2231, +2231, + +1220, +1229, +1238, +1247, +1257, +1266, +1275, +1348, + +1422, +1447, +1473, +1499, +1525, +1530, +1536, +1542, + +1548, +1567, +1587, +1606, +1626, +1601, +1577, +1616, + +1656, +1763, +1871, +1658, -2138, -2862, -2563, -2583, + -2604, -2671, -2738, -2805, -2873, -2928, -2983, -3038, + -3094, -3128, -3162, -3100, -3038, -3028, -3018, -2976, + -2934, -3352, +1862, +2244, +2114, +2048, +1982, +2076, + +2170, +2182, +2194, +2206, +2218, +2218, +2218, +2218, + +1210, +1234, +1259, +1283, +1308, +1325, +1341, +1390, + +1439, +1457, +1477, +1496, +1516, +1525, +1535, +1544, + +1554, +1571, +1589, +1607, +1625, +1616, +1608, +1632, + +1656, +1718, +1782, +1685, +1845, +528, -2836, -2728, + -2622, -2654, -2687, -2719, -2752, -2763, -2773, -2992, + -2955, -3030, -3106, -2813, -2777, -3226, -2908, -3134, + -3359, -971, +2186, +2270, +2099, +2075, +2052, +2108, + +2165, +2175, +2185, +2195, +2205, +2205, +2205, +2205, + +1200, +1240, +1280, +1320, +1360, +1384, +1408, +1432, + +1456, +1469, +1482, +1495, +1508, +1521, +1534, +1547, + +1560, +1576, +1592, +1608, +1624, +1632, +1640, +1648, + +1656, +1675, +1694, +1713, +1732, +1871, +986, -827, + -2640, -2638, -2636, -2634, -2632, -2598, -2564, -2946, + -2816, -2933, -3050, -2783, -3028, -3169, -1774, +293, + +2360, +2179, +1998, +2041, +2084, +2103, +2122, +2141, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1232, +1266, +1300, +1334, +1368, +1390, +1412, +1434, + +1456, +1468, +1482, +1494, +1508, +1520, +1534, +1546, + +1560, +1578, +1596, +1614, +1632, +1640, +1648, +1656, + +1664, +1645, +1628, +1705, +1784, +2101, +1908, +1298, + +688, +1071, -594, -1587, -2580, -2891, -3202, -2281, + -2640, -2058, -1476, -94, +1032, +2278, +2244, +2209, + +2176, +2131, +2088, +2091, +2096, +2111, +2128, +2143, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1264, +1292, +1320, +1348, +1376, +1396, +1416, +1436, + +1456, +1469, +1482, +1495, +1508, +1521, +1534, +1547, + +1560, +1580, +1600, +1620, +1640, +1648, +1656, +1664, + +1672, +1617, +1562, +1699, +1836, +1821, +1806, +1887, + +1968, +1964, +1960, +2020, +2080, +1936, +1792, +1200, + +1632, +1889, +2146, +2083, +2020, +2093, +2166, +2079, + +1992, +2085, +2178, +2143, +2108, +2121, +2134, +2147, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1296, +1318, +1340, +1362, +1384, +1402, +1420, +1438, + +1456, +1468, +1482, +1494, +1508, +1520, +1534, +1546, + +1560, +1582, +1604, +1626, +1648, +1656, +1664, +1672, + +1680, +1667, +1656, +1739, +1824, +1811, +1800, +1835, + +1872, +1881, +1890, +1819, +1748, +1995, +450, +937, + +912, +715, +2056, +2019, +1984, +2035, +2088, +2059, + +2032, +2085, +2140, +2129, +2120, +2129, +2140, +2149, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1328, +1344, +1360, +1376, +1392, +1408, +1424, +1440, + +1456, +1469, +1482, +1495, +1508, +1521, +1534, +1547, + +1560, +1584, +1608, +1632, +1656, +1664, +1672, +1680, + +1688, +1719, +1750, +1781, +1812, +1803, +1794, +1785, + +1776, +1798, +1820, +1874, +1928, +1798, +2180, +674, + +1216, +2103, +1966, +1957, +1948, +1979, +2010, +2041, + +2072, +2087, +2102, +2117, +2132, +2139, +2146, +2153, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1328, +1344, +1360, +1376, +1392, +1408, +1424, +1440, + +1456, +1468, +1482, +1494, +1508, +1520, +1534, +1546, + +1560, +1584, +1608, +1632, +1656, +1664, +1672, +1680, + +1688, +1718, +1750, +1780, +1812, +1802, +1794, +1784, + +1776, +1798, +1820, +1858, +1896, +1750, +1860, +2338, + +1792, +2134, +1966, +1956, +1948, +1978, +2010, +2040, + +2072, +2086, +2102, +2116, +2132, +2138, +2146, +2152, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1328, +1344, +1360, +1376, +1392, +1408, +1424, +1440, + +1456, +1469, +1482, +1495, +1508, +1521, +1534, +1547, + +1560, +1584, +1608, +1632, +1656, +1664, +1672, +1680, + +1688, +1719, +1750, +1781, +1812, +1803, +1794, +1785, + +1776, +1798, +1820, +1842, +1864, +1958, +2052, +1954, + +1856, +1911, +1966, +1957, +1948, +1979, +2010, +2041, + +2072, +2087, +2102, +2117, +2132, +2139, +2146, +2153, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192, + +1328, +1344, +1360, +1376, +1392, +1408, +1424, +1440, + +1456, +1468, +1482, +1494, +1508, +1520, +1534, +1546, + +1560, +1584, +1608, +1632, +1656, +1664, +1672, +1680, + +1688, +1718, +1750, +1780, +1812, +1802, +1794, +1784, + +1776, +1798, +1820, +1842, +1864, +1958, +2052, +1954, + +1856, +1910, +1966, +1956, +1948, +1978, +2010, +2040, + +2072, +2086, +2102, +2116, +2132, +2138, +2146, +2152, + +2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192 +}; + +static INT16 TEST_CR_COMPONENT[4096] = +{ + -2112, -2114, -2116, -2118, -2120, -2122, -2124, -2126, + -2128, -2118, -2108, -2098, -2088, -2150, -2212, -2146, + -2080, -2100, -2120, -2140, -2160, -2164, -2168, -2172, + -2176, -2092, -2008, -2052, -2096, -2132, -2168, -2076, + -1984, -2088, -2192, -2168, -2144, -2136, -2128, -2120, + -2112, -2126, -2140, -2154, -2168, -2150, -2132, -2114, + -2096, -2096, -2096, -2096, -2096, -2096, -2096, -2096, + -2096, -2080, -2064, -2048, -2032, -2032, -2032, -2032, + -2128, -2113, -2098, -2115, -2132, -2133, -2134, -2135, + -2137, -2127, -2117, -2107, -2097, -2117, -2137, -2125, + -2114, -2134, -2154, -2159, -2163, -2135, -2108, -2128, + -2149, -2132, -2116, -2116, -2115, -2115, -2114, -2098, + -2082, -2112, -2142, -2141, -2139, -2133, -2128, -2122, + -2117, -2127, -2137, -2147, -2158, -2146, -2134, -2122, + -2111, -2108, -2106, -2104, -2102, -2101, -2101, -2101, + -2101, -2087, -2073, -2059, -2045, -2045, -2045, -2045, + -2144, -2112, -2080, -2112, -2145, -2145, -2145, -2145, + -2146, -2136, -2126, -2116, -2107, -2085, -2063, -2105, + -2148, -2168, -2189, -2178, -2167, -2107, -2048, -2085, + -2122, -2173, -2225, -2180, -2135, -2098, -2061, -2120, + -2180, -2136, -2093, -2114, -2135, -2131, -2128, -2125, + -2122, -2128, -2135, -2141, -2148, -2142, -2137, -2131, + -2126, -2121, -2117, -2112, -2108, -2107, -2107, -2106, + -2106, -2094, -2082, -2070, -2058, -2058, -2058, -2058, + -2160, -2111, -2062, -2109, -2157, -2156, -2155, -2154, + -2155, -2145, -2135, -2125, -2116, -2132, -2148, -2132, + -2118, -2154, -2191, -2181, -2170, -2494, -2308, -2393, + -2479, -2470, -2461, -2243, -2282, -2353, -2167, -2174, + -2182, -2160, -2139, -2135, -2130, -2128, -2128, -2127, + -2127, -2129, -2132, -2134, -2138, -2138, -2139, -2139, + -2141, -2133, -2127, -2120, -2114, -2112, -2112, -2111, + -2111, -2101, -2091, -2081, -2071, -2071, -2071, -2071, + -2176, -2110, -2045, -2107, -2170, -2168, -2167, -2165, + -2164, -2154, -2145, -2135, -2126, -2180, -2235, -2161, + -2088, -2141, -2195, -2440, -2686, -2371, -1033, -398, + +236, +305, +375, -3, -894, -2096, -2787, -2485, + -2184, -2185, -2187, -2156, -2126, -2127, -2129, -2130, + -2132, -2131, -2130, -2129, -2128, -2135, -2142, -2149, + -2156, -2147, -2138, -2129, -2120, -2119, -2118, -2117, + -2116, -2108, -2100, -2092, -2084, -2084, -2084, -2084, + -2112, -2085, -2058, -2112, -2166, -2067, -2225, -2190, + -2157, -2107, -2057, -2104, -2151, -2119, -2088, -2632, + -2666, -2263, -837, +844, +2526, +3327, +2847, +2847, + +2847, +2726, +2606, +2967, +3070, +2968, +2867, +397, + -2074, -2745, -2137, -2281, -2169, -2202, -2236, -2190, + -2145, -2145, -2147, -2148, -2150, -2152, -2156, -2159, + -2163, -2159, -2156, -2152, -2150, -2130, -2111, -2123, + -2137, -2127, -2117, -2107, -2097, -2097, -2097, -2097, + -2048, -2060, -2073, -2118, -2163, -1967, -2284, -2217, + -2150, -2060, -1971, -2074, -2177, -2315, -2454, -1057, + +1364, +2990, +2568, +2593, +2619, +2369, +2631, +2508, + +2386, +2332, +2278, +2352, +2427, +2913, +2888, +3022, + +3156, +1302, -2088, -2406, -2213, -2279, -2345, -2251, + -2158, -2161, -2165, -2168, -2172, -2171, -2171, -2170, + -2170, -2172, -2175, -2177, -2180, -2142, -2105, -2131, + -2158, -2146, -2134, -2122, -2110, -2110, -2110, -2110, + -2112, -2163, -2215, -2235, -2255, -1994, -2247, -2194, + -2143, -2109, -2076, -2123, -2170, -2270, +700, +3527, + +2770, +2035, +2325, +2293, +2263, +2178, +2350, +2265, + +2181, +2129, +2078, +2154, +2231, +2521, +2557, +2559, + +2562, +3221, +3113, +140, -2832, -2034, -2261, -2199, + -2139, -2160, -2182, -2188, -2194, -2189, -2185, -2181, + -2177, -2185, -2193, -2201, -2210, -2154, -2098, -2138, + -2179, -2165, -2151, -2137, -2123, -2123, -2123, -2123, + -1664, -1755, -1846, -1841, -1836, -1767, -2210, -2173, + -2136, -2159, -2182, -2173, -2164, -2739, +2830, +2735, + +2640, +2361, +2082, +1995, +1908, +1989, +2070, +2023, + +1976, +1927, +1878, +1957, +2036, +2131, +2226, +2353, + +2480, +2581, +2682, +2943, +2692, -2815, -2178, -2149, + -2120, -2160, -2200, -2208, -2216, -2208, -2200, -2192, + -2184, -2198, -2212, -2226, -2240, -2166, -2092, -2146, + -2200, -2184, -2168, -2152, -2136, -2136, -2136, -2136, + -2096, -2166, -2238, -2228, -2220, -2087, -2210, -2173, + -2137, -2189, -2243, -2152, -2318, -2031, +3375, +2861, + +2605, +2305, +2007, +1851, +1697, +1756, +1815, +1810, + +1806, +1756, +1707, +1754, +1801, +1911, +2023, +2149, + +2277, +2299, +2323, +2729, +1345, -2439, -2129, -2217, + -2307, -2349, -2136, -2179, -2222, -2223, -2224, -2193, + -2162, -2171, -2180, -2190, -2199, -2198, -2198, -2213, + -2229, -2172, -2115, -2170, -2225, -2113, -2257, -2257, + -2016, -2067, -2118, -2105, -2093, -2152, -2211, -2174, + -2138, -2221, -2305, -2132, -2472, +212, +2897, +2477, + +2570, +2251, +1932, +1709, +1487, +1524, +1561, +1598, + +1636, +1586, +1537, +1552, +1567, +1693, +1820, +1947, + +2074, +2019, +1964, +2261, -514, -2321, -2080, -2031, + -1982, -2283, -2073, -2151, -2229, -2238, -2248, -2194, + -2140, -2144, -2149, -2154, -2159, -2231, -2304, -2281, + -2258, -2160, -2062, -2188, -2314, -2090, -2378, -2378, + -2064, -2094, -2126, -2125, -2125, -2152, -2179, -2159, + -2139, -2204, -2270, -2144, -2530, +1688, +2834, +2460, + +2343, +2147, +1953, +1678, +1404, +1387, +1370, +1418, + +1466, +1416, +1366, +1349, +1332, +1442, +1553, +1663, + +1775, +1817, +1861, +2415, -2405, -2457, -1999, -2035, + -281, -1464, -2393, -2378, -2363, -2301, -2240, -2195, + -2150, -2165, -2181, -2182, -2182, -2199, -2218, -2188, + -2159, -2756, -2329, -1934, -2307, -2627, -2179, -2307, + -2112, -2123, -2135, -2146, -2158, -2153, -2149, -2144, + -2140, -2188, -2236, -2156, -2588, +3164, +2772, +2444, + +2116, +2045, +1975, +1648, +1322, +1251, +1181, +1238, + +1296, +1246, +1197, +1147, +1098, +1192, +1287, +1381, + +1476, +1617, +1758, +1291, -2760, -2083, -2430, -1273, + -628, -647, -667, -1582, -2498, -2365, -2233, -2196, + -2160, -2187, -2215, -2210, -2206, -2169, -2133, -2096, + -2060, -280, -548, -2448, -1788, -860, -1980, -2236, + -2112, -2120, -2130, -2140, -2150, -2145, -2141, -2137, + -2133, -2147, -2161, -2079, -718, +3207, +2525, +2291, + +2057, +1941, +1827, +1553, +1279, +1174, +1070, +1094, + +1118, +1044, +970, +976, +983, +1001, +1019, +1165, + +1313, +1305, +1555, -212, -2491, -2189, -2401, -867, + -615, -642, -671, -603, -536, -1354, -2172, -2271, + -2370, -2340, -2311, -2330, -2349, -2315, -2282, -2697, + -1321, -420, -543, -394, -757, -741, -2261, -2261, + -2112, -2119, -2127, -2135, -2143, -2138, -2134, -2130, + -2126, -2106, -2087, -2259, +640, +2995, +2279, +2138, + +1998, +1839, +1681, +1459, +1237, +1098, +960, +950, + +940, +842, +744, +806, +869, +811, +753, +951, + +1150, +995, +1352, -1715, -2222, -2297, -2372, -463, + -602, -639, -676, -649, -623, -600, -577, -810, + -1044, -1214, -1384, -1426, -1469, -1183, -897, -483, + -582, -560, -538, -900, -750, -1134, -2542, -2286, + -2112, -2117, -2123, -2129, -2135, -2131, -2127, -2123, + -2119, -2017, -1916, -2886, +1262, +2014, +2256, +2097, + +1939, +1736, +1534, +1364, +1194, +1022, +850, +806, + +762, +736, +710, +508, +818, +604, +646, +752, + +859, +1131, +1149, -2865, -2273, -2339, -1639, -425, + -493, -522, -553, -566, -581, -677, -773, -661, + -550, -567, -585, -586, -588, -657, -727, -572, + -675, -668, -661, -798, -679, -1799, -2407, -2151, + -2112, -2116, -2120, -2124, -2128, -2124, -2120, -2116, + -2112, -2185, -2258, -1723, +1884, +1035, +2234, +2057, + +1880, +1634, +1388, +1270, +1152, +946, +740, +662, + +584, +630, +676, +466, +1280, +654, +540, +554, + +568, +757, -78, -2481, -2324, -2383, -906, -389, + -384, -407, -430, -485, -540, -499, -458, -513, + -568, -689, -810, -771, -732, -645, -558, -663, + -768, -776, -784, -696, -608, -2464, -2272, -2016, + -2104, -2110, -2116, -2122, -2129, -2105, -2081, -2105, + -2130, -2204, -2536, -84, +1856, +1148, +1209, +1701, + +1683, +1507, +1332, +1188, +1045, +837, +630, +518, + +407, +489, +572, +398, +1249, +662, +330, +383, + +436, +589, -1304, -2350, -2117, -2615, +213, -12, + -239, -265, -293, -320, -348, -377, -407, -484, + -562, -626, -691, -675, -661, -625, -590, -682, + -776, -804, -832, -540, -248, -664, -1848, -2616, + -2096, -2104, -2113, -2121, -2130, -2086, -2043, -2095, + -2148, -2225, -2815, +1555, +1829, +1519, +697, +1603, + +1486, +1381, +1276, +1107, +938, +729, +520, +375, + +230, +349, +468, +331, +1219, +670, +121, +212, + +304, +423, -2531, -2477, -2423, -1569, +309, -149, + -94, -125, -157, -157, -157, -256, -356, -456, + -556, -564, -573, -581, -590, -606, -623, -703, + -784, -832, -880, -384, +112, -1424, -2448, -2192, + -2088, -2098, -2109, -2119, -2131, -2099, -2068, -2100, + -2134, -2485, -2325, +2921, +2025, +1536, +1048, +1088, + +1385, +1270, +1156, +993, +831, +700, +570, +407, + +245, +256, +268, +343, +932, +662, +135, +185, + +236, -337, -2445, -2346, -2504, -793, +149, -75, + -45, -64, -84, -88, -93, -183, -273, -363, + -454, -454, -454, -518, -583, -619, -655, -723, + -792, -796, -800, -868, -1960, -2296, -2376, -2248, + -2080, -2093, -2106, -2119, -2132, -2113, -2094, -2107, + -2120, -2234, -813, +2752, +2222, +1555, +1401, +574, + +1284, +1160, +1036, +880, +724, +672, +620, +440, + +260, +164, +69, +357, +646, +654, +151, +159, + +168, -1096, -2361, -2217, -2586, -18, -11, -3, + +4, -4, -13, -21, -30, -110, -191, -271, + -352, -344, -336, -456, -576, -632, -688, -744, + -800, -760, -720, -584, -2496, -2400, -2304, -2304, + -2072, -2086, -2102, -2117, -2133, -2171, -2211, -2170, + -2130, -2462, +1045, +2615, +2138, +1656, +1432, +807, + +951, +1193, +924, +734, +545, +397, +250, +486, + +723, +569, +416, +311, +207, +384, +305, +242, + +180, -1825, -2295, -2348, -1891, +69, -19, -10, + -3, -7, -12, -16, -22, -65, -107, -182, + -258, -309, -361, -477, -593, -640, -688, -736, + -784, -752, -720, -1200, -2448, -2384, -2320, -2320, + -2064, -2081, -2099, -2116, -2134, -2231, -2329, -2234, + -2140, -2691, +2902, +2478, +2055, +1759, +1464, +1041, + +618, +1227, +812, +589, +366, +379, +392, +277, + +162, +207, +253, +267, +281, +114, -52, +70, + +192, -2555, -2230, -2481, -1197, +156, -28, -19, + -10, -11, -12, -13, -15, -20, -25, -94, + -164, -275, -387, -498, -610, -649, -689, -728, + -768, -744, -720, -1816, -2400, -2368, -2336, -2336, + -2056, -2075, -2095, -2115, -2135, -2178, -2222, -2138, + -2310, -1319, +2743, +2293, +2099, +1893, +1432, +1242, + +541, +1036, +1020, +699, +379, +376, +374, +275, + +177, +196, +217, +189, +162, +100, +39, +153, + -756, -2420, -2293, -2549, -502, +131, -4, -10, + -17, -14, -12, -9, -7, -7, -6, -102, + -198, -320, -444, -519, -595, -641, -689, -720, + -752, -768, -784, -2192, -2320, -2336, -2352, -2352, + -2048, -2070, -2092, -2114, -2136, -2126, -2116, -2042, + -2480, +52, +2584, +2108, +2144, +2028, +1400, +1444, + +464, +78, -308, -470, -632, -394, -156, +18, + +192, +187, +182, +113, +44, +87, +130, +237, + -1704, -2286, -2356, -2618, +192, +106, +20, -2, + -24, -18, -12, -6, +0, +6, +12, -110, + -232, -367, -502, -541, -580, -635, -690, -713, + -736, -792, -848, -2568, -2240, -2304, -2368, -2368, + -2046, -2068, -2091, -2113, -2136, -2121, -2105, -2186, + -2523, +1999, +2681, +2740, +1518, +117, -1541, -2639, + -2457, -2465, -2474, -2466, -2459, -2498, -2536, -2303, + -2070, -995, +81, -76, +24, +35, +47, -150, + -2394, -2422, -2450, -1806, +117, +85, +53, +21, + -11, -11, -11, -11, -11, -11, -11, -107, + -203, -404, -606, -615, -625, -610, -596, -693, + -791, -757, -1491, -2401, -2287, -2303, -2319, -2319, + -2044, -2067, -2090, -2113, -2137, -2116, -2095, -2074, + -2054, +2923, +219, -1748, -2692, -2563, -2435, -2114, + -2306, -2193, -2080, -2159, -2239, -2298, -2357, -2320, + -2284, -2432, -2580, -1544, +4, -16, -36, -280, + -2572, -2302, -2544, -994, +43, +64, +86, +44, + +2, -4, -10, -16, -22, -28, -34, -104, + -174, -186, -198, -178, -158, -330, -502, -674, + -846, -722, -2134, -2234, -2334, -2302, -2270, -2270, + -2042, -2065, -2089, -2112, -2137, -2159, -2180, -2154, + -2129, -2458, -2532, -2604, -2166, -2218, -2272, -2293, + -2315, -2000, -2198, -2219, -2242, -2322, -2401, -2385, + -2370, -2285, -2201, -2452, -2704, -1411, +137, -1402, + -2174, -2502, -2830, +250, +0, +28, +55, +35, + +15, +3, -9, -21, -33, -45, -57, -101, + -145, -175, -206, -220, -235, -177, -120, -414, + -709, -191, -2489, -2547, -2349, -2349, -2349, -2349, + -2040, -2064, -2089, -2113, -2138, -2202, -2267, -2235, + -2204, -2207, -2210, -2181, -2152, -2131, -2110, -2217, + -1812, -1552, -2317, -2025, -1734, -1578, -1423, -1939, + -2456, -2395, -2334, -2081, -2340, -2551, -2250, -2013, + -2288, -2446, -2093, -43, -42, -8, +25, +26, + +28, +10, -8, -26, -44, -62, -80, -98, + -116, -165, -214, -263, -312, -281, -250, -155, + -60, -940, -1820, -2348, -2364, -2396, -2428, -2428, + -2038, -2058, -2079, -2100, -2122, -2123, -2124, -2285, + -2191, -2065, -1940, -1910, -1882, -2232, -2327, -2149, + -1717, -1485, -2022, -1759, -1497, -1242, -987, -716, + -446, -1226, -2007, -2723, -2160, -2330, -2245, -2175, + -2362, -2338, -1034, +109, -28, -19, -10, +15, + +41, +19, -3, -25, -47, -89, -131, -141, + -151, -208, -266, -355, -445, -458, -472, -405, + -83, -1135, -1163, -1895, -2371, -2387, -2403, -2403, + -2036, -2053, -2071, -2089, -2107, -2044, -1982, -2080, + -1666, -1668, -1671, -1897, -2124, -2590, -2545, -2083, + -1622, -1419, -1729, -1495, -1261, -1162, -1064, -774, + -484, -314, -144, -806, -2492, -2366, -2240, -2338, + -2436, -2486, -489, +4, -15, -30, -45, +4, + +54, +28, +2, -24, -50, -116, -182, -184, + -186, -252, -318, -448, -578, -636, -694, -656, + -106, -2098, -2042, -2210, -2378, -2378, -2378, -2378, + -2034, -2047, -2062, -2076, -2091, -2093, -2096, -1650, + -1461, -1687, -1913, -2155, -2398, -2676, -2442, -2016, + -1591, -1448, -1563, -1341, -1120, -986, -853, -623, + -394, -265, -137, +200, +24, -1554, -2363, -2324, + -2286, -2122, -2727, -1220, +31, +136, -15, +25, + +67, +37, +7, -7, -21, -111, -201, -211, + -221, -295, -370, -460, -551, -509, -468, -634, + -545, -2805, -2249, -2301, -2353, -2353, -2353, -2353, + -2032, -2043, -2054, -2065, -2076, -2143, -2210, -1477, + -1768, -1962, -2156, -2414, -2672, -2762, -2340, -1950, + -1560, -1479, -1398, -1189, -980, -811, -642, -473, + -304, -217, -130, -75, -20, +27, -2486, -2311, + -2136, -2527, -2406, -2445, -2484, -979, +14, +47, + +80, +46, +12, +10, +8, -106, -220, -238, + -256, -339, -422, -473, -524, -639, -754, -1637, + -2520, -2232, -2456, -2392, -2328, -2328, -2328, -2328, + -2012, -2030, -2049, -2052, -2055, -2191, -2073, -1585, + -1867, -2081, -2296, -2526, -2757, -2653, -2294, -1886, + -1479, -1380, -1282, -1087, -893, -748, -604, -491, + -379, -243, -109, -181, +1, -606, -2493, -2283, + -2331, -2481, -2376, -2413, -2452, -2308, -2421, -1350, + -278, -124, +30, +88, +145, +127, +109, +27, + -56, -278, -501, -1107, -1714, -2162, -2612, -2532, + -2453, -2297, -2397, -2369, -2341, -2341, -2341, -2341, + -1992, -2018, -2045, -2040, -2035, -2241, -1936, -1695, + -1966, -2201, -2436, -2639, -2842, -2545, -2248, -1823, + -1398, -1282, -1166, -986, -806, -686, -566, -510, + -454, -271, -88, -289, +22, -1239, -2500, -2257, + -2526, -388, -2346, -2383, -2421, -2358, -2296, -2490, + -2684, -2342, -2001, -1627, -1254, -1176, -1099, -1501, + -1904, -2266, -2628, -2510, -2393, -2407, -2422, -2404, + -2386, -2362, -2338, -2346, -2354, -2354, -2354, -2354, + -1972, -2006, -2040, -2043, -2046, -2194, -1831, -1835, + -2097, -2336, -2576, -2735, -2895, -2564, -2234, -1839, + -1445, -1279, -1114, -916, -719, -623, -528, -528, + -529, -425, -323, -59, -53, -2527, -2443, -2517, + -2081, +170, -140, -1312, -2485, -2440, -2395, -2382, + -2370, -2400, -2431, -2509, -2589, -2559, -2530, -2500, + -2472, -2429, -2387, -2489, -2335, -2939, -2008, -1331, + -2447, -2395, -2343, -2355, -2367, -2367, -2367, -2367, + -1952, -1994, -2037, -2047, -2058, -2148, -1727, -1977, + -2228, -2472, -2716, -2832, -2948, -2584, -2220, -1856, + -1492, -1277, -1062, -847, -632, -561, -490, -547, + -604, -581, -558, -343, -1152, -2281, -2386, -2523, + -1124, -40, +19, +15, +10, -1242, -2495, -2531, + -2568, -2459, -2350, -2369, -2388, -2407, -2426, -2477, + -2528, -2593, -2659, -2212, -1254, +369, +967, -1026, + -2508, -2428, -2348, -2364, -2380, -2380, -2380, -2380, + -1948, -1996, -2044, -2060, -2077, -1957, -1837, -2069, + -2303, -2545, -2788, -2918, -3049, -2873, -2442, -2026, + -1611, -1374, -1138, -965, -793, -732, -672, -707, + -743, -847, -953, -2017, -2059, -2441, -2313, -2327, + -295, +99, -19, +23, +65, +26, -13, -629, + -1246, -1795, -2345, -2509, -2675, -2540, -2406, -1887, + -1368, -467, +434, +439, +699, +1162, +856, -2695, + -2409, -2413, -2417, -2389, -2361, -2361, -2361, -2361, + -1944, -1998, -2052, -2074, -2097, -1767, -1949, -2163, + -2378, -2619, -2860, -3005, -3150, -3163, -2664, -2197, + -1730, -1472, -1214, -1084, -954, -904, -854, -868, + -882, -859, -836, -877, -1942, -2091, -2240, -2389, + +22, -18, -57, +32, +121, +14, -93, -9, + +76, +149, +221, +166, +110, +143, +175, +239, + +304, +379, +455, +530, +605, +676, +235, -2573, + -2310, -2398, -2486, -2414, -2342, -2342, -2342, -2342, + -1940, -2000, -2060, -2072, -2084, -1640, -1964, -2144, + -2325, -2532, -2740, -2899, -3059, -3052, -2790, -2319, + -1849, -1569, -1290, -1202, -1115, -1075, -1036, -1028, + -1021, -1077, -1135, -503, -2689, -2395, -2359, -1553, + +19, -6, -30, +25, +80, +34, -12, +37, + +86, +124, +162, +137, +111, +137, +163, +237, + +312, +393, +475, +525, +574, +654, -803, -2466, + -2339, -2383, -2427, -2375, -2323, -2323, -2323, -2323, + -1936, -2002, -2068, -2070, -2072, -1514, -1980, -2126, + -2272, -2446, -2620, -2794, -2968, -2942, -2916, -2442, + -1968, -1667, -1366, -1321, -1276, -1247, -1218, -1189, + -1160, -1041, -922, -1411, -2412, -2189, -2478, -719, + +16, +6, -4, +18, +40, +54, +68, +82, + +96, +100, +104, +108, +112, +132, +152, +236, + +320, +408, +496, +520, +544, +632, -1840, -2360, + -2368, -2368, -2368, -2336, -2304, -2304, -2304, -2304, + -1898, -1921, -1944, -2111, -1766, -1551, -1848, -1985, + -2122, -2318, -2515, -2664, -2813, -3074, -3079, -2828, + -2321, -2024, -1729, -1608, -1489, -1457, -1425, -1393, + -1362, -1246, -1131, -1879, -2372, -2532, -2693, +331, + +25, +40, +55, +54, +54, +71, +88, +105, + +123, +151, +180, +208, +237, +83, -70, +48, + +167, +248, +329, +346, +363, +733, -2738, -2577, + -2416, -2395, -2374, -2353, -2332, -2332, -2332, -2332, + -1860, -1840, -1820, -2152, -1460, -1588, -1716, -1844, + -1972, -2191, -2411, -2535, -2659, -2950, -2730, -2958, + -2674, -2383, -2092, -1897, -1703, -1668, -1633, -1598, + -1564, -1452, -1340, -2348, -2333, -2365, -1885, -157, + +34, +74, +115, +91, +68, +88, +109, +129, + +150, +203, +256, +309, +362, +291, +220, +117, + +14, +88, +162, +172, +183, -702, -2612, -2282, + -2464, -2422, -2380, -2370, -2360, -2360, -2360, -2360, + -2110, -1967, -1824, -1953, -1314, -1513, -1712, -1815, + -1918, -2207, -2242, -2453, -2408, -2602, -2541, -2752, + -2707, -2692, -2679, -2409, -2140, -2054, -1968, -1867, + -1766, -1721, -1677, -2369, -2293, -2516, -948, -53, + +75, +92, +110, +95, +82, +105, +129, +152, + +177, +222, +268, +313, +359, +354, +350, +441, + +533, +472, +411, +414, +674, -1689, -2518, -2339, + -2416, -2401, -2386, -2387, -2388, -2388, -2388, -2388, + -1848, -1838, -1828, -1754, -1168, -1438, -1708, -1786, + -1864, -2225, -2075, -2372, -2158, -2255, -2353, -2546, + -2740, -2747, -2755, -2666, -2578, -2441, -2305, -2136, + -1968, -1991, -2015, -2390, -2254, -2669, -13, +51, + +116, +111, +106, +101, +96, +123, +150, +177, + +204, +242, +280, +318, +356, +418, +480, +510, + +540, +600, +661, +657, +1166, -2677, -2425, -2396, + -2368, -2380, -2392, -2404, -2416, -2416, -2416, -2416, + -1882, -1711, -1796, -1369, -1198, -1419, -1640, -1749, + -1858, -1977, -1842, -2058, -2019, -2113, -2207, -2366, + -2525, -2478, -2689, -2836, -2983, -2759, -2536, -2393, + -2250, -2194, -2139, -2357, -2318, -2018, +72, +113, + +157, +150, +145, +139, +134, +159, +186, +212, + +239, +273, +308, +342, +377, +439, +502, +548, + +595, +632, +669, +931, +170, -2666, -2430, -2403, + -2376, -2385, -2394, -2403, -2412, -2412, -2412, -2412, + -1916, -1840, -2276, -1240, -1228, -1400, -1572, -1712, + -1852, -1731, -1610, -1745, -1881, -1972, -2063, -2186, + -2310, -2211, -2625, -2751, -2877, -2822, -2768, -2650, + -2532, -2398, -2265, -2324, -2383, -1369, +156, +177, + +198, +191, +185, +178, +172, +197, +223, +248, + +274, +305, +336, +367, +398, +461, +524, +587, + +650, +664, +679, +1206, -827, -2656, -2437, -2410, + -2384, -2390, -2396, -2402, -2408, -2408, -2408, -2408, + -1950, -1953, -1956, -1063, -1194, -1317, -1440, -1435, + -1430, -1499, -1314, -1431, -1550, -1638, -1726, -1798, + -1871, -1927, -2240, -2409, -2578, -2597, -2616, -2731, + -2846, -2554, -2262, -2259, -2511, -527, +176, +207, + +239, +231, +224, +217, +210, +234, +259, +284, + +309, +336, +364, +391, +419, +482, +546, +609, + +673, +744, +816, +936, -2015, -2485, -2187, -2289, + -2392, -2395, -2398, -2401, -2404, -2404, -2404, -2404, + -1984, -2066, -1636, -886, -1160, -1234, -1308, -1414, + -1520, -2037, -2042, -1887, -1732, -1817, -1902, -1923, + -1944, -1900, -1856, -2068, -2280, -2372, -2464, -2556, + -2648, -2454, -2260, -2194, -2640, +314, +196, +238, + +280, +272, +264, +256, +248, +272, +296, +320, + +344, +368, +392, +416, +440, +504, +568, +632, + +696, +825, +954, +923, -2692, -2315, -2450, -2425, + -2400, -2400, -2400, -2400, -2400, -2400, -2400, -2400, + -2252, -1953, -1142, -1035, -1441, -1826, -2211, -2244, + -2278, -2220, -1908, -1914, -1922, -2001, -2336, -2095, + -2111, -2171, -2231, -2131, -2031, -2143, -2255, -2303, + -2352, -2306, -2260, -2359, -1689, +442, +269, +305, + +341, +333, +325, +317, +309, +329, +349, +369, + +389, +415, +441, +468, +494, +536, +579, +669, + +760, +797, +1091, -248, -2610, -2406, -2459, -2431, + -2404, -2400, -2396, -2392, -2388, -2388, -2388, -2388, + -2008, -2096, -1673, -1953, -2234, -2162, -2091, -2051, + -2012, -2149, -2286, -2199, -2113, -1930, -2259, -2012, + -2278, -2186, -2094, -2194, -2295, -2171, -2047, -2051, + -2056, -2158, -2261, -2524, -739, +570, +343, +372, + +402, +394, +386, +378, +370, +386, +402, +418, + +434, +462, +491, +520, +549, +569, +590, +707, + +824, +770, +1228, -1418, -2528, -2498, -2468, -2438, + -2408, -2400, -2392, -2384, -2376, -2376, -2376, -2376, + -1988, -2191, -2139, -2150, -2163, -2130, -2098, -2081, + -2066, -2140, -2216, -2179, -2143, -2066, -2245, -2137, + -2285, -2233, -2181, -2225, -2270, -2326, -2382, -2166, + -1952, -2250, -2549, -2465, +180, +394, +352, +407, + +463, +455, +447, +423, +399, +523, +391, +547, + +447, +493, +540, +572, +603, +633, +665, +792, + +920, +1094, +1269, -2764, -2446, -2429, -2413, -2412, + -2412, -2400, -2388, -2376, -2364, -2364, -2364, -2364, + -1968, -2031, -2094, -2093, -2092, -2099, -2106, -2113, + -2120, -2133, -2147, -2160, -2174, -2203, -2233, -2262, + -2292, -2280, -2269, -2257, -2246, -2226, -2207, -2283, + -2360, -2343, -2327, -2406, +586, -38, +363, +443, + +524, +516, +508, +468, +428, +660, +380, +676, + +460, +525, +591, +624, +658, +699, +741, +878, + +1016, +907, +286, -2575, -2364, -2361, -2358, -2387, + -2416, -2400, -2384, -2368, -2352, -2352, -2352, -2352, + -2020, -2071, -2124, -2080, -2037, -2062, -2089, -2115, + -2142, -2152, -2164, -2176, -2188, -2211, -2235, -2259, + -2283, -2275, -2267, -2260, -2253, -2249, -2246, -2290, + -2336, -2337, -2339, -1205, -71, -16, +296, +496, + +441, +469, +497, +381, +521, +635, +493, +735, + +465, +544, +624, +640, +656, +747, +839, +899, + +960, +1115, -1033, -2493, -2418, -2378, -2339, -2379, + -2420, -2408, -2396, -2384, -2372, -2372, -2372, -2372, + -2072, -2113, -2155, -2068, -1982, -2027, -2073, -2118, + -2164, -2173, -2183, -2193, -2203, -2220, -2238, -2256, + -2274, -2270, -2267, -2264, -2261, -2273, -2286, -2299, + -2312, -2332, -2352, -2052, -729, +7, +230, +550, + +358, +422, +486, +294, +614, +610, +606, +794, + +470, +564, +658, +656, +655, +797, +939, +921, + +904, +1324, -2352, -2412, -2472, -2396, -2320, -2372, + -2424, -2416, -2408, -2400, -2392, -2392, -2392, -2392, + -1996, -1930, -1865, -1960, -2055, -2087, -2120, -2153, + -2186, -2193, -2201, -2209, -2217, -2229, -2241, -2253, + -2265, -2265, -2266, -2267, -2268, -2280, -2294, -2306, + -2320, -2342, -2365, -2707, -2538, -1491, -188, +172, + +275, +327, +379, +287, +451, +505, +559, +773, + +475, +551, +628, +512, +653, +909, +654, +1007, + +1104, -739, -2583, -2506, -2430, -2397, -2365, -2396, + -2428, -2424, -2420, -2416, -2412, -2412, -2412, -2412, + -1920, -2004, -2088, -2108, -2128, -2148, -2168, -2188, + -2208, -2214, -2220, -2226, -2232, -2238, -2244, -2250, + -2256, -2261, -2266, -2271, -2276, -2289, -2302, -2315, + -2328, -2353, -2378, -2339, -2300, -2477, -1630, -719, + +192, +232, +272, +280, +288, +400, +512, +752, + +480, +539, +598, +369, +652, +767, -142, -1211, + -2792, -2547, -2302, -2345, -2388, -2399, -2410, -2421, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2024, -2070, -2116, -2130, -2144, -2164, -2184, -2204, + -2224, -2228, -2232, -2236, -2240, -2244, -2248, -2252, + -2256, -2262, -2270, -2276, -2284, -2296, -2310, -2322, + -2336, -2319, -2304, -2287, -2272, -2559, -2336, -1855, + -1376, -2264, -1104, -520, +64, +384, +704, +704, + +192, -44, -280, -1236, -1936, -3018, -2564, -2349, + -2392, -2390, -2390, -2388, -2388, -2398, -2410, -2420, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2128, -2136, -2144, -2152, -2160, -2180, -2200, -2220, + -2240, -2242, -2244, -2246, -2248, -2250, -2252, -2254, + -2256, -2265, -2274, -2283, -2292, -2305, -2318, -2331, + -2344, -2287, -2230, -2237, -2244, -2387, -2530, -2481, + -2432, -2456, -2480, -2600, -2720, -2448, -2176, -1904, + -2144, -2419, -2694, -2585, -2476, -2451, -2426, -2465, + -2504, -2491, -2478, -2433, -2388, -2399, -2410, -2421, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2104, -2122, -2140, -2158, -2176, -2196, -2216, -2236, + -2256, -2256, -2256, -2256, -2256, -2256, -2256, -2256, + -2256, -2266, -2278, -2288, -2300, -2312, -2326, -2338, + -2352, -2317, -2284, -2281, -2280, -2357, -2436, -2417, + -2400, -2408, -2416, -2360, -2304, -2480, -864, -1648, + -1408, -1225, -2580, -2509, -2440, -2427, -2416, -2435, + -2456, -2446, -2438, -2412, -2388, -2398, -2410, -2420, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2080, -2108, -2136, -2164, -2192, -2212, -2232, -2252, + -2272, -2270, -2268, -2266, -2264, -2262, -2260, -2258, + -2256, -2269, -2282, -2295, -2308, -2321, -2334, -2347, + -2360, -2349, -2338, -2327, -2316, -2329, -2342, -2355, + -2368, -2360, -2352, -2376, -2400, -2256, -2624, -1392, + -1696, -2593, -2466, -2435, -2404, -2405, -2406, -2407, + -2408, -2403, -2398, -2393, -2388, -2399, -2410, -2421, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2080, -2108, -2136, -2164, -2192, -2212, -2232, -2252, + -2272, -2270, -2268, -2266, -2264, -2262, -2260, -2258, + -2256, -2268, -2282, -2294, -2308, -2320, -2334, -2346, + -2360, -2348, -2338, -2326, -2316, -2328, -2342, -2354, + -2368, -2360, -2352, -2360, -2368, -2352, -2592, -2192, + -2560, -2768, -2466, -2434, -2404, -2404, -2406, -2406, + -2408, -2402, -2398, -2392, -2388, -2398, -2410, -2420, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2080, -2108, -2136, -2164, -2192, -2212, -2232, -2252, + -2272, -2270, -2268, -2266, -2264, -2262, -2260, -2258, + -2256, -2269, -2282, -2295, -2308, -2321, -2334, -2347, + -2360, -2349, -2338, -2327, -2316, -2329, -2342, -2355, + -2368, -2360, -2352, -2344, -2336, -2448, -2560, -2480, + -2400, -2433, -2466, -2435, -2404, -2405, -2406, -2407, + -2408, -2403, -2398, -2393, -2388, -2399, -2410, -2421, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432, + -2080, -2108, -2136, -2164, -2192, -2212, -2232, -2252, + -2272, -2270, -2268, -2266, -2264, -2262, -2260, -2258, + -2256, -2268, -2282, -2294, -2308, -2320, -2334, -2346, + -2360, -2348, -2338, -2326, -2316, -2328, -2342, -2354, + -2368, -2360, -2352, -2344, -2336, -2448, -2560, -2480, + -2400, -2432, -2466, -2434, -2404, -2404, -2406, -2406, + -2408, -2402, -2398, -2392, -2388, -2398, -2410, -2420, + -2432, -2432, -2432, -2432, -2432, -2432, -2432, -2432 +}; + +/** + * 64x64 XRGB Image + */ + +static UINT32 TEST_XRGB_IMAGE[4096] = +{ + 0xFF229cdf, 0xFF249de0, 0xFF259fe2, 0xFF2ca5e8, 0xFF229cdf, 0xFF229ce0, 0xFF239de0, 0xFF229ce0, + 0xFF229cdf, 0xFF229cdf, 0xFF239ce0, 0xFF249ce0, 0xFF249ce0, 0xFF219ce3, 0xFF1e9ce6, 0xFF209ae2, + 0xFF2299dd, 0xFF2199de, 0xFF209adf, 0xFF209ae0, 0xFF1f9be0, 0xFF1e9ae0, 0xFF1d99e0, 0xFF1c98e0, + 0xFF1b97df, 0xFF1e96dc, 0xFF2194d9, 0xFF1f93dd, 0xFF1d93e0, 0xFF1b94dc, 0xFF1895d8, 0xFF1c92db, + 0xFF208fde, 0xFF1b91de, 0xFF1693df, 0xFF1793df, 0xFF1992df, 0xFF1891df, 0xFF178fdf, 0xFF178edf, + 0xFF168dde, 0xFF158cdd, 0xFF148cdc, 0xFF128cda, 0xFF118cd9, 0xFF118bd9, 0xFF128ada, 0xFF1289da, + 0xFF1288db, 0xFF1187da, 0xFF1186da, 0xFF1085da, 0xFF0f85d9, 0xFF0f84d9, 0xFF0e83d9, 0xFF0d82d8, + 0xFF0d82d8, 0xFF0d81d8, 0xFF0d80d7, 0xFF0d7fd7, 0xFF0d7ed6, 0xFF0d7ed6, 0xFF0d7ed6, 0xFF0d7ed6, + 0xFF259fe1, 0xFF27a1e2, 0xFF29a2e3, 0xFF2ba4e6, 0xFF249fe1, 0xFF249fe1, 0xFF249fe1, 0xFF249ee1, + 0xFF239ee1, 0xFF249ee1, 0xFF249ee1, 0xFF259de1, 0xFF259de2, 0xFF249de2, 0xFF229de2, 0xFF229ce1, + 0xFF229bdf, 0xFF219ce0, 0xFF209ce1, 0xFF209ce2, 0xFF209ce2, 0xFF209ae0, 0xFF2199de, 0xFF1f99df, + 0xFF1d98e0, 0xFF1e97e0, 0xFF1f97e0, 0xFF1d96df, 0xFF1c95de, 0xFF1c94e0, 0xFF1c94e1, 0xFF1d93e1, + 0xFF1d92e0, 0xFF1b93de, 0xFF1a94dc, 0xFF1a93de, 0xFF1a93e0, 0xFF1992e0, 0xFF1891df, 0xFF188fdf, + 0xFF178edf, 0xFF168ede, 0xFF158edd, 0xFF148ddc, 0xFF138ddb, 0xFF138cdb, 0xFF138bdb, 0xFF128adb, + 0xFF1289db, 0xFF1288db, 0xFF1187db, 0xFF1186db, 0xFF1085db, 0xFF0f84da, 0xFF0e83d9, 0xFF0e83d9, + 0xFF0e83d9, 0xFF0e82d9, 0xFF0e81d8, 0xFF0e80d8, 0xFF0d7fd7, 0xFF0d7fd7, 0xFF0d7fd7, 0xFF0d7fd7, + 0xFF27a3e3, 0xFF2aa4e3, 0xFF2ea6e3, 0xFF2aa4e3, 0xFF26a2e3, 0xFF26a1e3, 0xFF25a1e3, 0xFF25a0e3, + 0xFF25a0e3, 0xFF25a0e3, 0xFF259fe3, 0xFF269fe3, 0xFF269ee4, 0xFF279ee1, 0xFF279edf, 0xFF259ee0, + 0xFF239ee1, 0xFF219ee2, 0xFF209ee4, 0xFF209de4, 0xFF219de3, 0xFF229be0, 0xFF2499dc, 0xFF2299de, + 0xFF1f98e0, 0xFF1d99e4, 0xFF1b9ae7, 0xFF1c98e2, 0xFF1c96dc, 0xFF1e94e3, 0xFF2092ea, 0xFF1d94e6, + 0xFF1a96e2, 0xFF1c96de, 0xFF1d95da, 0xFF1c94de, 0xFF1b94e1, 0xFF1a93e0, 0xFF1a92e0, 0xFF1991e0, + 0xFF1890e0, 0xFF1790df, 0xFF178fde, 0xFF168fde, 0xFF158edd, 0xFF148ddd, 0xFF138cdc, 0xFF138bdc, + 0xFF128adc, 0xFF1289dc, 0xFF1188dc, 0xFF1187dd, 0xFF1086dd, 0xFF0f85db, 0xFF0e83d9, 0xFF0e84da, + 0xFF0f84da, 0xFF0e83da, 0xFF0e82d9, 0xFF0e81d9, 0xFF0e80d8, 0xFF0e80d8, 0xFF0e80d8, 0xFF0e80d8, + 0xFF2aa7e5, 0xFF2da7e4, 0xFF31a8e3, 0xFF2ca6e3, 0xFF27a4e4, 0xFF27a3e4, 0xFF27a3e4, 0xFF27a3e4, + 0xFF26a2e4, 0xFF26a2e4, 0xFF27a1e5, 0xFF27a0e5, 0xFF27a0e6, 0xFF26a0e5, 0xFF25a0e4, 0xFF259fe4, + 0xFF259ee3, 0xFF239ee5, 0xFF229fe6, 0xFF229fe5, 0xFF229fe4, 0xFF13a5e6, 0xFF1b9fe8, 0xFF16a0e8, + 0xFF11a0e7, 0xFF129fef, 0xFF139ef7, 0xFF1b99ec, 0xFF179ae2, 0xFF149ce4, 0xFF1d98e5, 0xFF1c97e6, + 0xFF1b96e7, 0xFF1c98dc, 0xFF1d97df, 0xFF1c96e1, 0xFF1c94e2, 0xFF1b94e1, 0xFF1b93e1, 0xFF1a93e0, + 0xFF1a92e0, 0xFF1991e0, 0xFF1890e0, 0xFF1790df, 0xFF168fdf, 0xFF158ede, 0xFF158dde, 0xFF148cdd, + 0xFF138bdc, 0xFF128add, 0xFF1289dd, 0xFF1188de, 0xFF1187de, 0xFF0f85dc, 0xFF0d83da, 0xFF0f85db, + 0xFF1086db, 0xFF0f84db, 0xFF0f83da, 0xFF0e82da, 0xFF0e81da, 0xFF0e81da, 0xFF0e81da, 0xFF0e81da, + 0xFF2caae7, 0xFF30aae5, 0xFF34abe3, 0xFF2ea8e4, 0xFF29a6e5, 0xFF28a6e5, 0xFF28a5e5, 0xFF28a5e5, + 0xFF28a5e6, 0xFF28a4e6, 0xFF28a3e7, 0xFF28a2e7, 0xFF28a1e8, 0xFF25a2e9, 0xFF23a3ea, 0xFF25a0e8, + 0xFF279ee6, 0xFF259fe7, 0xFF23a0e9, 0xFF18a4f5, 0xFF0ea7ff, 0xFF1ba6de, 0xFF558ebb, 0xFF6f839c, + 0xFF89797e, 0xFF8d797c, 0xFF917979, 0xFF7f7b94, 0xFF5687af, 0xFF229bd6, 0xFF04a4fd, 0xFF109df4, + 0xFF1c97eb, 0xFF1c9ada, 0xFF1c98e4, 0xFF1c97e3, 0xFF1d95e2, 0xFF1c95e2, 0xFF1c94e2, 0xFF1c94e1, + 0xFF1b94e1, 0xFF1a93e1, 0xFF1a92e1, 0xFF1991e1, 0xFF1890e1, 0xFF178fe0, 0xFF158edf, 0xFF148dde, + 0xFF138cdd, 0xFF128bde, 0xFF128adf, 0xFF1289df, 0xFF1188e0, 0xFF0f85dd, 0xFF0d83da, 0xFF0f85db, + 0xFF1187dd, 0xFF1086dc, 0xFF0f84dc, 0xFF0e83db, 0xFF0e81db, 0xFF0e81db, 0xFF0e81db, 0xFF0e81db, + 0xFF30abe5, 0xFF36afe8, 0xFF34abe4, 0xFF2faae5, 0xFF2ba8e6, 0xFF36aee8, 0xFF26a6e8, 0xFF29a7e7, + 0xFF2ca8e7, 0xFF2da7e6, 0xFF2fa5e5, 0xFF2ca5e7, 0xFF29a4e9, 0xFF2ba5e5, 0xFF2ca5e2, 0xFF10aaef, + 0xFF13adf6, 0xFF23a3f8, 0xFF6091a5, 0xFFa6755d, 0xFFec5915, 0xFFff490c, 0xFFfa5504, 0xFFff590f, + 0xFFff5d1b, 0xFFff6116, 0xFFfa6412, 0xFFff550f, 0xFFff4b0d, 0xFFfb4918, 0xFFf54823, 0xFF8e737e, + 0xFF269eda, 0xFF06a2ff, 0xFF1d97e2, 0xFF1799ea, 0xFF1c97e4, 0xFF1a98e4, 0xFF1898e4, 0xFF1a96e3, + 0xFF1b95e3, 0xFF1a94e2, 0xFF1a93e0, 0xFF1992e1, 0xFF1891e2, 0xFF1790e1, 0xFF168fe0, 0xFF158fdf, + 0xFF138ede, 0xFF138ddf, 0xFF138ce0, 0xFF128be0, 0xFF1189e0, 0xFF1087de, 0xFF0f85db, 0xFF138ae0, + 0xFF0f87dc, 0xFF0f86dc, 0xFF0f85dc, 0xFF0f84dc, 0xFF0e83db, 0xFF0e83db, 0xFF0e83db, 0xFF0e83db, + 0xFF34abe2, 0xFF3cb4ec, 0xFF34ace5, 0xFF31abe6, 0xFF2daae8, 0xFF44b6eb, 0xFF24a7ea, 0xFF29aaea, + 0xFF2face9, 0xFF32a9e6, 0xFF35a7e3, 0xFF30a7e6, 0xFF2ba8ea, 0xFF25aaf0, 0xFF20adf6, 0xFF4d8ba7, + 0xFFb8674c, 0xFFff5510, 0xFFf7650c, 0xFFf86313, 0xFFfa611b, 0xFFf0671f, 0xFFfc6222, 0xFFfb6926, + 0xFFf96f29, 0xFFf67122, 0xFFf3721b, 0xFFf26b20, 0xFFf16424, 0xFFff5622, 0xFFff531f, 0xFFff4b17, + 0xFFff440e, 0xFFb1615b, 0xFF1f95e0, 0xFF129bf0, 0xFF1c9ae5, 0xFF189ae6, 0xFF159be7, 0xFF1898e6, + 0xFF1b95e5, 0xFF1b95e2, 0xFF1995e0, 0xFF1994e1, 0xFF1892e2, 0xFF1792e1, 0xFF1691e0, 0xFF1590df, + 0xFF148fdf, 0xFF148fe0, 0xFF148fe1, 0xFF128de1, 0xFF108be0, 0xFF1189de, 0xFF1186dd, 0xFF178fe4, + 0xFF0e87db, 0xFF0e87dc, 0xFF0f87dd, 0xFF0f85dc, 0xFF0e84dc, 0xFF0e84dc, 0xFF0e84dc, 0xFF0e84dc, + 0xFF36b1eb, 0xFF36b4f0, 0xFF2eafed, 0xFF2caeec, 0xFF2aadec, 0xFF41b4ef, 0xFF29abe9, 0xFF2cabe8, + 0xFF2fabe7, 0xFF31abe6, 0xFF32aae6, 0xFF2faae7, 0xFF2ca9e8, 0xFF25a7eb, 0xFF946a5f, 0xFFff3e06, + 0xFFf95618, 0xFFe27312, 0xFFf87329, 0xFFf77427, 0xFFf77626, 0xFFf27628, 0xFFf8712b, 0xFFf9772e, + 0xFFf97e30, 0xFFf77f2e, 0xFFf5812b, 0xFFf57b2c, 0xFFf5752d, 0xFFfd6a2b, 0xFFfb652a, 0xFFf65e2c, + 0xFFf1572e, 0xFFff4810, 0xFFff460f, 0xFF817680, 0xFF02a7f1, 0xFF2496ea, 0xFF199be4, 0xFF1b98e4, + 0xFF1d96e5, 0xFF1b96e2, 0xFF1a96e0, 0xFF1995e1, 0xFF1794e3, 0xFF1793e2, 0xFF1692e1, 0xFF1691e0, + 0xFF1590df, 0xFF1591e1, 0xFF1591e3, 0xFF138fe1, 0xFF108ce0, 0xFF128be0, 0xFF158ae0, 0xFF168de2, + 0xFF0f89dd, 0xFF0f88dd, 0xFF0f88dd, 0xFF0f86dd, 0xFF0f85dc, 0xFF0f85dc, 0xFF0f85dc, 0xFF0f85dc, + 0xFF5fc1e7, 0xFF57bee8, 0xFF4fbbe9, 0xFF4ebae6, 0xFF4ebae3, 0xFF51b6ee, 0xFF2eaee8, 0xFF2eade6, + 0xFF2fabe5, 0xFF2face7, 0xFF2eade9, 0xFF2eace7, 0xFF2daae5, 0xFF15b2ff, 0xFFec4310, 0xFFf15016, + 0xFFf75d1c, 0xFFf87123, 0xFFf9862a, 0xFFf6882d, 0xFFf48b31, 0xFFf48532, 0xFFf47f33, 0xFFf78535, + 0xFFfa8c37, 0xFFf88e39, 0xFFf7903a, 0xFFf88b38, 0xFFf98635, 0xFFf87e35, 0xFFf77635, 0xFFf76d34, + 0xFFf76532, 0xFFf85e31, 0xFFf95730, 0xFFff5125, 0xFFf65237, 0xFF03a5fd, 0xFF1e9be1, 0xFF1e98e3, + 0xFF1f96e5, 0xFF1c97e2, 0xFF1a97df, 0xFF1896e1, 0xFF1795e4, 0xFF1794e3, 0xFF1793e2, 0xFF1692e1, + 0xFF1692e0, 0xFF1693e2, 0xFF1794e4, 0xFF1391e2, 0xFF0f8ee0, 0xFF148ee1, 0xFF198ee3, 0xFF148ce1, + 0xFF0f8bde, 0xFF0f8ade, 0xFF0f89de, 0xFF0f88dd, 0xFF0f86dd, 0xFF0f86dd, 0xFF0f86dd, 0xFF0f86dd, + 0xFF3cb6ee, 0xFF36b4ef, 0xFF30b2f0, 0xFF30b1ee, 0xFF2fb1ec, 0xFF38b0ef, 0xFF2eaee9, 0xFF2faee8, + 0xFF31ade6, 0xFF2fafe8, 0xFF2eb1ea, 0xFF31adec, 0xFF29afee, 0xFF30aac8, 0xFFff3d05, 0xFFfa501a, + 0xFFf96021, 0xFFf87428, 0xFFf7882f, 0xFFfa9638, 0xFFf59b38, 0xFFf5973b, 0xFFf6923e, 0xFFf89440, + 0xFFfa9742, 0xFFfa9a44, 0xFFfa9d46, 0xFFf99845, 0xFFf89444, 0xFFf98d43, 0xFFfa8641, 0xFFf97d3f, + 0xFFf9743d, 0xFFf77039, 0xFFf56d35, 0xFFff6122, 0xFFbf6c63, 0xFF129eef, 0xFF229ae8, 0xFF1c99ed, + 0xFF179ce4, 0xFF1498f0, 0xFF1b94e1, 0xFF1a96e2, 0xFF1998e3, 0xFF1897e4, 0xFF1896e5, 0xFF1895e4, + 0xFF1993e2, 0xFF1792e1, 0xFF1590df, 0xFF1692e2, 0xFF1793e5, 0xFF1490e4, 0xFF128ee2, 0xFF118de3, + 0xFF108de3, 0xFF118bde, 0xFF1289d9, 0xFF0f88e2, 0xFF0c89dd, 0xFF1085e0, 0xFF0987e4, 0xFF0987e4, + 0xFF40b5e9, 0xFF3bb4e9, 0xFF37b2ea, 0xFF37b2e9, 0xFF38b1e8, 0xFF33b0ea, 0xFF2eaeeb, 0xFF30afe9, + 0xFF33afe8, 0xFF30b2ea, 0xFF2eb5ec, 0xFF34aff2, 0xFF25b4f7, 0xFF8d7f86, 0xFFf64f00, 0xFFed5c1e, + 0xFFfa6326, 0xFFf7762d, 0xFFf58a35, 0xFFfea242, 0xFFf7ab3f, 0xFFf7a843, 0xFFf7a548, 0xFFf9a34a, + 0xFFfaa24c, 0xFFfba64f, 0xFFfcaa52, 0xFFf9a652, 0xFFf7a252, 0xFFfa9c50, 0xFFfd974e, 0xFFfc8d4b, + 0xFFfb8348, 0xFFf68341, 0xFFf1823a, 0xFFf5732c, 0xFF718cac, 0xFF179af0, 0xFF2599ef, 0xFF2697e9, + 0xFF269bc6, 0xFF1696f1, 0xFF1d91e3, 0xFF1c96e3, 0xFF1b9be3, 0xFF1a99e6, 0xFF1998e9, 0xFF1b97e7, + 0xFF1c95e5, 0xFF1891df, 0xFF138dda, 0xFF1992e2, 0xFF1e98ea, 0xFF1592e6, 0xFF0b8de2, 0xFF0e8ee5, + 0xFF108fe9, 0xFF128cdf, 0xFF1489d4, 0xFF0e88e6, 0xFF088cdc, 0xFF1184e4, 0xFF0488ec, 0xFF0488ec, + 0xFF3eb6ea, 0xFF3bb5eb, 0xFF38b4eb, 0xFF38b4eb, 0xFF38b3eb, 0xFF35b2eb, 0xFF33b1ec, 0xFF34b1eb, + 0xFF35b1ea, 0xFF32b3e9, 0xFF30b5e9, 0xFF34b0f0, 0xFF23b6f8, 0xFFc56044, 0xFFf9540c, 0xFFf26322, + 0xFFf77029, 0xFFf77d2f, 0xFFf78b35, 0xFFfba142, 0xFFf6b046, 0xFFfbb44f, 0xFFf7b051, 0xFFf9af54, + 0xFFfbad56, 0xFFfcb25a, 0xFFfeb75d, 0xFFfab35f, 0xFFf6b061, 0xFFfaac5d, 0xFFfda95a, 0xFFfb9f55, + 0xFFf99551, 0xFFf7914b, 0xFFf68d45, 0xFFff7e23, 0xFF1ba5f0, 0xFF129ef4, 0xFF2896f1, 0xFF239fb1, + 0xFF6c9600, 0xFF3c9c82, 0xFF179ef8, 0xFF169cf4, 0xFF149de3, 0xFF169ae5, 0xFF1897e7, 0xFF1995e6, + 0xFF1a93e5, 0xFF1993e3, 0xFF1793e0, 0xFF1c98e6, 0xFF1a95e5, 0xFF1692e5, 0xFF138fe5, 0xFF138ceb, + 0xFF138be3, 0xFF0087e4, 0xFF007cf5, 0xFF1a86d3, 0xFF0d8cf1, 0xFF008fe2, 0xFF0d85ea, 0xFF0886f1, + 0xFF3cb7ec, 0xFF3bb7ed, 0xFF3ab6ed, 0xFF39b6ed, 0xFF38b5ed, 0xFF37b5ed, 0xFF37b4ed, 0xFF37b3ed, + 0xFF36b3ec, 0xFF34b4e9, 0xFF31b5e5, 0xFF35b1ef, 0xFF21b8fa, 0xFFfd4203, 0xFFfc581e, 0xFFf86a26, + 0xFFf47c2d, 0xFFf78431, 0xFFf98c36, 0xFFf8a041, 0xFFf6b54d, 0xFFfec05b, 0xFFf6bc5a, 0xFFf8ba5d, + 0xFFfbb861, 0xFFfdbe65, 0xFFffc469, 0xFFfbc16c, 0xFFf5bd70, 0xFFfabc6b, 0xFFfebb66, 0xFFfab160, + 0xFFf6a75a, 0xFFf89f55, 0xFFfa984f, 0xFFdf956f, 0xFF08a6fc, 0xFF259ddb, 0xFF159ff3, 0xFF4aa172, + 0xFF69a90d, 0xFF62a406, 0xFF5a981b, 0xFF34969b, 0xFF0e99ff, 0xFF1297f2, 0xFF1695e4, 0xFF1793e5, + 0xFF1892e5, 0xFF1995e6, 0xFF1a98e7, 0xFF209deb, 0xFF1593df, 0xFF1892e4, 0xFF1a91e9, 0xFF2095eb, + 0xFF259dd1, 0xFFd0f772, 0xFFc1f396, 0xFF0083f1, 0xFF1782a0, 0xFF3c7e2f, 0xFF1787cc, 0xFF0b8ada, + 0xFF3db9ed, 0xFF3cb8ed, 0xFF3bb8ed, 0xFF3ab7ed, 0xFF39b7ed, 0xFF39b7ed, 0xFF39b6ed, 0xFF3ab6ed, + 0xFF3ab6ed, 0xFF37b4ed, 0xFF34b2ec, 0xFF35abf3, 0xFF6e96b3, 0xFFff4601, 0xFFf86520, 0xFFf67329, + 0xFFf58131, 0xFFf78b37, 0xFFf9953e, 0xFFf8a649, 0xFFf8b854, 0xFFfcc260, 0xFFf8c465, 0xFFf9c36a, + 0xFFfac26e, 0xFFfac773, 0xFFfacb77, 0xFFfbcb7b, 0xFFfccb7e, 0xFFfac87b, 0xFFf8c578, 0xFFf9bc72, + 0xFFfbb46d, 0xFFf6b069, 0xFFfeaa57, 0xFF94a0a5, 0xFF13a1f3, 0xFF219df0, 0xFF199eff, 0xFF71c124, + 0xFF79b826, 0xFF72b21e, 0xFF6aaa24, 0xFF67a125, 0xFF649a19, 0xFF419d72, 0xFF1f9fcb, 0xFF1994ff, + 0xFF1399f1, 0xFF199cf4, 0xFF1ea0f8, 0xFF1b9cff, 0xFF1193f6, 0xFF1293f1, 0xFF1393ec, 0xFF0083ff, + 0xFF72cca0, 0xFFcbf982, 0xFFd0ffac, 0xFF79a046, 0xFF337700, 0xFF3a7c03, 0xFF0d8de2, 0xFF0d8edb, + 0xFF3fbbee, 0xFF3ebaed, 0xFF3db9ed, 0xFF3cb9ed, 0xFF3bb8ed, 0xFF3bb8ed, 0xFF3cb9ee, 0xFF3cb9ee, + 0xFF3db9ef, 0xFF3ab4f1, 0xFF37aff3, 0xFF32b3fe, 0xFFb48f7d, 0xFFff5907, 0xFFf37122, 0xFFf57c2b, + 0xFFf68735, 0xFFf7923d, 0xFFf89d45, 0xFFf9ac50, 0xFFf9bb5a, 0xFFf9c465, 0xFFfacd71, 0xFFfacd76, + 0xFFfacd7b, 0xFFf7cf80, 0xFFf4d286, 0xFFfcd689, 0xFFffd98c, 0xFFfbd48b, 0xFFf3cf8a, 0xFFf9c885, + 0xFFffc17f, 0xFFf5c27d, 0xFFffbc5e, 0xFF48abdc, 0xFF1e9deb, 0xFF1ea2e8, 0xFF1da8e5, 0xFF99d31c, + 0xFF8acb22, 0xFF82c427, 0xFF7abc2c, 0xFF75b429, 0xFF70ad25, 0xFF6dab17, 0xFF6ba908, 0xFF5ea912, + 0xFF519f54, 0xFF489b6d, 0xFF3e9887, 0xFF3b9592, 0xFF389880, 0xFF449663, 0xFF509446, 0xFF83b43c, + 0xFF4f851b, 0xFFafe187, 0xFF9fcc83, 0xFF368011, 0xFF43821c, 0xFF32853c, 0xFF0492f9, 0xFF1092dd, + 0xFF40bcee, 0xFF3fbcee, 0xFF3ebbee, 0xFF3dbaed, 0xFF3cbaed, 0xFF3cb9ed, 0xFF3cb9ec, 0xFF3cb9ec, + 0xFF3cb8ec, 0xFF3fb4f0, 0xFF43aff5, 0xFF0ebbe9, 0xFFffb897, 0xFFf7814d, 0xFFf57623, 0xFFf6812e, + 0xFFf88c39, 0xFFf89943, 0xFFf8a64d, 0xFFf8b257, 0xFFf9bd60, 0xFFfac96d, 0xFFfbd47b, 0xFFfad681, + 0xFFfad788, 0xFFfbd98e, 0xFFfbda93, 0xFFfae5a1, 0xFFfed692, 0xFFfadea0, 0xFFf9db98, 0xFFfad694, + 0xFFfbd090, 0xFFffd285, 0xFFffc778, 0xFF009afd, 0xFF26a8f2, 0xFF20a4f8, 0xFF53bea5, 0xFFa4da31, + 0xFF9dd638, 0xFF97d03a, 0xFF91ca3d, 0xFF8bc539, 0xFF85c035, 0xFF7dbe31, 0xFF74bc2d, 0xFF76b81c, + 0xFF77b027, 0xFF72ab25, 0xFF6da724, 0xFF6ba328, 0xFF68a31f, 0xFF58951a, 0xFF78b745, 0xFFbbf181, + 0xFF73ad4c, 0xFF417c15, 0xFF508b1e, 0xFF43861c, 0xFF498614, 0xFF17868b, 0xFF0b90f6, 0xFF168ee8, + 0xFF42beef, 0xFF41bdee, 0xFF40bcee, 0xFF3fbced, 0xFF3ebbed, 0xFF3dbaec, 0xFF3db9eb, 0xFF3cb8ea, + 0xFF3bb7e9, 0xFF39b9f0, 0xFF37bbf7, 0xFF50b5dc, 0xFFff9744, 0xFFfec49d, 0xFFf87a24, 0xFFf88530, + 0xFFf9913d, 0xFFf8a049, 0xFFf7af55, 0xFFf8b85d, 0xFFf9c065, 0xFFface75, 0xFFfcdb85, 0xFFfbde8d, + 0xFFfae195, 0xFFfee29b, 0xFFffe2a0, 0xFFfbe9a4, 0xFFffbe6b, 0xFFfdde9f, 0xFFffe8a6, 0xFFfbe3a3, + 0xFFf8dea0, 0xFFfdd899, 0xFFb6bdab, 0xFF119ff1, 0xFF1ea4e9, 0xFF1a9fff, 0xFF89d465, 0xFFb0e245, + 0xFFb0e04e, 0xFFacdc4e, 0xFFa7d94e, 0xFFa1d649, 0xFF9ad345, 0xFF97ce3d, 0xFF94c935, 0xFF8dc534, + 0xFF86c133, 0xFF7bbc32, 0xFF6fb731, 0xFF6db330, 0xFF6cae2e, 0xFF7eba3f, 0xFF70a531, 0xFF7bb54f, + 0xFF579a20, 0xFF5c9f2b, 0xFF519425, 0xFF80b965, 0xFF609a1d, 0xFF0390e3, 0xFF118ef2, 0xFF1c89f2, + 0xFF44c0ef, 0xFF43bfef, 0xFF42beee, 0xFF40bdee, 0xFF3fbcee, 0xFF3fbbed, 0xFF40baeb, 0xFF3eb9ed, + 0xFF3cb9ee, 0xFF37b9eb, 0xFF27bcf7, 0xFF949c8f, 0xFFfb9637, 0xFFf9bc7c, 0xFFf9b585, 0xFFf7994a, + 0xFFf69b43, 0xFFf6a64e, 0xFFf7b259, 0xFFf8bc66, 0xFFfac672, 0xFFfad380, 0xFFfae08d, 0xFFf9e698, + 0xFFf9eba2, 0xFFfeeaa6, 0xFFffeaab, 0xFFfcefa9, 0xFFfaba62, 0xFFfbdc99, 0xFFfff4b9, 0xFFfbecb2, + 0xFFf7e6ab, 0xFFffe5a3, 0xFF64b1d1, 0xFF199ff0, 0xFF269fe9, 0xFF0499f2, 0xFFe3f051, 0xFFd5ef58, + 0xFFc0e364, 0xFFbde165, 0xFFbae065, 0xFFb5de5d, 0xFFb0dc56, 0xFFaad74e, 0xFFa3d346, 0xFF9bd043, + 0xFF93cd3f, 0xFF8cc93e, 0xFF84c63c, 0xFF81c139, 0xFF7dbc36, 0xFF8bc746, 0xFF89c245, 0xFF63a02c, + 0xFF65aa2c, 0xFF5ea42d, 0xFF509626, 0xFFa4cf98, 0xFFd9eadd, 0xFFb9ddff, 0xFF389ef4, 0xFF008fd4, + 0xFF46c1ef, 0xFF44c0ef, 0xFF43bfef, 0xFF42beef, 0xFF40bdef, 0xFF42bced, 0xFF43baec, 0xFF40baf0, + 0xFF3dbaf4, 0xFF35b8e7, 0xFF17bdf7, 0xFFd97f50, 0xFFf79147, 0xFFf7a554, 0xFFffdbba, 0xFFf8a24d, + 0xFFf3a549, 0xFFf5ad53, 0xFFf7b55e, 0xFFf9c16f, 0xFFfbcc7f, 0xFFf9d88a, 0xFFf8e595, 0xFFf8eda2, + 0xFFf8f5ae, 0xFFfff3b2, 0xFFfff2b6, 0xFFfef5ae, 0xFFf4b659, 0xFFf9db93, 0xFFfeffcd, 0xFFfbf6c1, + 0xFFf7edb6, 0xFFfff2ac, 0xFF13a4f7, 0xFF16a5f0, 0xFF18a5e8, 0xFF56b4cd, 0xFFf1f271, 0xFFd5ef84, + 0xFFcfe67b, 0xFFcde77c, 0xFFcbe77c, 0xFFc9e672, 0xFFc7e567, 0xFFbce15f, 0xFFb1dd57, 0xFFa9dc51, + 0xFFa0da4b, 0xFF9dd749, 0xFF9ad447, 0xFF94cf43, 0xFF8fcb3f, 0xFF88c43c, 0xFF82be39, 0xFF72b430, + 0xFF63a928, 0xFF59a028, 0xFF4e9827, 0xFFa0c479, 0xFFfffbf7, 0xFF7fd3f5, 0xFF038fe2, 0xFF0e89e2, + 0xFF48c3ef, 0xFF46c2ef, 0xFF45c1f0, 0xFF43c0f0, 0xFF42bff0, 0xFF42beee, 0xFF43bdec, 0xFF41bcef, + 0xFF3fbcf2, 0xFF2fc0fe, 0xFF36bdfc, 0xFFf54c00, 0xFFff8a52, 0xFFfaa65e, 0xFFfdc48e, 0xFFfbc185, + 0xFFf5ae50, 0xFFf7b65e, 0xFFf9be6c, 0xFFfac978, 0xFFfbd485, 0xFFfede98, 0xFFffe8aa, 0xFFfdeeae, + 0xFFf9f5b2, 0xFFfcf6ba, 0xFFfff7c2, 0xFFfcf0b2, 0xFFf7cc6e, 0xFFfbde91, 0xFFfdfcca, 0xFFfffbd1, + 0xFFfffdc8, 0xFFcae4c8, 0xFF16a1f2, 0xFF1da4ef, 0xFF12a1f1, 0xFF9fd5b9, 0xFFeaf28c, 0xFFdcf095, + 0xFFd9eb90, 0xFFd9ec93, 0xFFd9ec95, 0xFFd6eb8c, 0xFFd4ea83, 0xFFc9e779, 0xFFbfe36f, 0xFFb8e368, + 0xFFb1e262, 0xFFafe05e, 0xFFaddf5a, 0xFFa3d952, 0xFF99d449, 0xFF8ecb41, 0xFF84c33a, 0xFF75b833, + 0xFF66ac2c, 0xFF5da329, 0xFF559927, 0xFF4b9421, 0xFF2499b9, 0xFF1593fe, 0xFF0993d8, 0xFF0f90d8, + 0xFF4ac5ef, 0xFF48c4f0, 0xFF46c2f0, 0xFF45c1f1, 0xFF43c0f1, 0xFF43bfef, 0xFF43bfed, 0xFF42beee, + 0xFF41bdf0, 0xFF38bbf0, 0xFF72a1b8, 0xFFff5d1e, 0xFFf97931, 0xFFf5a151, 0xFFf9ad61, 0xFFfee0bd, + 0xFFf8b758, 0xFFfabf69, 0xFFfcc87a, 0xFFfcd282, 0xFFfcdc8b, 0xFFfbde8f, 0xFFfbe193, 0xFFfbeba4, + 0xFFfbf5b5, 0xFFfaf8c2, 0xFFf9fcce, 0xFFf9ecb7, 0xFFfae183, 0xFFfee290, 0xFFfbfac8, 0xFFfdf8d8, + 0xFFfffccb, 0xFF8bcedc, 0xFF189fee, 0xFF25a3ee, 0xFF0b9dfb, 0xFFe8f6a5, 0xFFe4f1a6, 0xFFe4f0a6, + 0xFFe4efa6, 0xFFe5f1aa, 0xFFe6f2ad, 0xFFe3f1a6, 0xFFe0ef9e, 0xFFd7ec93, 0xFFcde987, 0xFFc8ea80, + 0xFFc2eb78, 0xFFc1ea73, 0xFFc0e96e, 0xFFb1e360, 0xFFa3dd53, 0xFF94d247, 0xFF86c83b, 0xFF78bc35, + 0xFF69b030, 0xFF62a52b, 0xFF5b9b27, 0xFF57920a, 0xFF0995fc, 0xFF0d96e5, 0xFF1091eb, 0xFF1091eb, + 0xFF4ac5f0, 0xFF49c4f0, 0xFF47c3f1, 0xFF45c2f1, 0xFF44c1f2, 0xFF41c1f2, 0xFF3fc1f2, 0xFF3fbff1, + 0xFF3fbcf0, 0xFF32c3fe, 0xFFbe7f6e, 0xFFfe6526, 0xFFf67b35, 0xFFf59a4d, 0xFFf8ab5c, 0xFFfbd0a0, + 0xFFf7c783, 0xFFfec16b, 0xFFfdd17f, 0xFFfbdb87, 0xFFf9e590, 0xFFf8ed9a, 0xFFf7f4a5, 0xFFfbea9a, + 0xFFffdf8e, 0xFFfce3a0, 0xFFf7e6b1, 0xFFfceecc, 0xFFfffbcb, 0xFFfff3c7, 0xFFfcf1c3, 0xFFfef5d2, + 0xFFfffcd3, 0xFF4bb5e7, 0xFF21a5ed, 0xFF1ca2ee, 0xFF3daae2, 0xFFeef6ac, 0xFFe6f2b1, 0xFFe8f2b5, + 0xFFe9f3b8, 0xFFeaf4ba, 0xFFebf5bc, 0xFFe8f3b6, 0xFFe6f2af, 0xFFe0f0a8, 0xFFdbeea2, 0xFFd6ef9a, + 0xFFd1f092, 0xFFc9ed82, 0xFFc1eb73, 0xFFb0e362, 0xFFa1dc51, 0xFF94d347, 0xFF88ca3e, 0xFF7bbf38, + 0xFF6eb433, 0xFF66a92e, 0xFF5da01b, 0xFF3d9448, 0xFF0a93f6, 0xFF0e94ec, 0xFF1193f0, 0xFF1193f0, + 0xFF4bc5f1, 0xFF4ac5f1, 0xFF48c4f1, 0xFF47c3f2, 0xFF45c3f2, 0xFF40c3f4, 0xFF3bc4f6, 0xFF3cbff3, + 0xFF3ebbf0, 0xFF2dcaff, 0xFFff5d25, 0xFFfe6d2f, 0xFFf37d39, 0xFFf59348, 0xFFf8a958, 0xFFf7c083, + 0xFFf7d7ae, 0xFFffc36d, 0xFFffda84, 0xFFfbe48c, 0xFFf7ee94, 0xFFf8ed9e, 0xFFfaeca7, 0xFFf9f1b4, + 0xFFf8f6c1, 0xFFfcf6c8, 0xFFfff6d0, 0xFFfef2d3, 0xFFfcf4ba, 0xFFfffee8, 0xFFf7fdea, 0xFFfdfde3, + 0xFFfffcdc, 0xFF0b9df1, 0xFF2aaaed, 0xFF1baaf6, 0xFF80c8da, 0xFFfdffbb, 0xFFe8f2bd, 0xFFebf4c4, + 0xFFeff7cb, 0xFFeff7cb, 0xFFeff7cb, 0xFFedf6c5, 0xFFebf5c0, 0xFFeaf4be, 0xFFe8f3bd, 0xFFe4f4b4, + 0xFFe0f6ab, 0xFFd0f191, 0xFFc1ec77, 0xFFb0e463, 0xFF9edb4e, 0xFF95d448, 0xFF8bcc42, 0xFF7fc23b, + 0xFF73b935, 0xFF6aac31, 0xFF60a510, 0xFF229687, 0xFF0b91f1, 0xFF0e93f3, 0xFF1294f5, 0xFF1294f5, + 0xFF4cc6f1, 0xFF4bc5f2, 0xFF49c5f2, 0xFF47c4f2, 0xFF46c4f2, 0xFF43c4f1, 0xFF40c4f0, 0xFF42c0f3, + 0xFF39c1f6, 0xFF5eacca, 0xFFfb591e, 0xFFf36e31, 0xFFf88135, 0xFFfb923f, 0xFFfbaf5e, 0xFFffc373, + 0xFFfde2ba, 0xFFffcd75, 0xFFffd372, 0xFFffe584, 0xFFfff796, 0xFFfef4a2, 0xFFfdf1ae, 0xFFfff8c2, + 0xFFfcf8cd, 0xFFfef8d2, 0xFFfff9d6, 0xFFfef6e1, 0xFFfcf5dd, 0xFFfffbee, 0xFFfbfce8, 0xFFfffce0, + 0xFFb2e0e8, 0xFF19a4f0, 0xFF26abec, 0xFF16a8f6, 0xFFc2e4d8, 0xFFf9fac5, 0xFFeff6cb, 0xFFf0f7ce, + 0xFFf1f8d2, 0xFFf1f8d1, 0xFFf2f9d1, 0xFFf1f9cd, 0xFFf1f9ca, 0xFFf2fbca, 0xFFf4fdca, 0xFFe7f8b6, + 0xFFdaf3a2, 0xFFcbef8a, 0xFFbcec71, 0xFFb0e661, 0xFFa5e151, 0xFF9ad949, 0xFF8fd240, 0xFF83c73b, + 0xFF77bc35, 0xFF6ab31d, 0xFF5ea905, 0xFF138dea, 0xFF1193ef, 0xFF1093f0, 0xFF0f93f0, 0xFF0f93f0, + 0xFF4dc6f2, 0xFF4cc6f2, 0xFF4ac5f3, 0xFF48c5f3, 0xFF47c5f3, 0xFF46c4ef, 0xFF46c4eb, 0xFF48c0f3, + 0xFF34c7fb, 0xFF989591, 0xFFfc6428, 0xFFf1773b, 0xFFfc8432, 0xFFff9135, 0xFFffb564, 0xFFffbe5a, + 0xFFf3ddb6, 0xFFccd097, 0xFFb4cea5, 0xFFb0d3b1, 0xFFabd7bd, 0xFFc3e1bf, 0xFFdaebc1, 0xFFf5fdc7, + 0xFFffffbd, 0xFFfffecd, 0xFFfffcdc, 0xFFfffce0, 0xFFfbfce5, 0xFFfdfbe6, 0xFFfffae7, 0xFFfffbdd, + 0xFF61c4f4, 0xFF26aaee, 0xFF22abec, 0xFF10a7f6, 0xFFffffd7, 0xFFf5f5d0, 0xFFf6fad9, 0xFFf4f9d9, + 0xFFf2f9da, 0xFFf3fad8, 0xFFf4fbd7, 0xFFf5fcd5, 0xFFf7fdd4, 0xFFf3face, 0xFFf0f7c8, 0xFFe2f4b0, + 0xFFd4f199, 0xFFc5ee82, 0xFFb7eb6b, 0xFFb1e95f, 0xFFabe754, 0xFF9fdf49, 0xFF94d83f, 0xFF87cc3a, + 0xFF7bc034, 0xFF6bb425, 0xFF5ba332, 0xFF0495f9, 0xFF1795ee, 0xFF1293ed, 0xFF0c91eb, 0xFF0c91eb, + 0xFF4fc8f3, 0xFF4dc8f3, 0xFF4cc8f4, 0xFF4bc8f4, 0xFF49c8f4, 0xFF47c5f2, 0xFF45c2ef, 0xFF42c2f8, + 0xFF34c8ff, 0xFFdf6746, 0xFFff632a, 0xFFff701b, 0xFFe18b53, 0xFFa4a185, 0xFF63c1cd, 0xFF26c0ff, + 0xFF2ab8ff, 0xFF25b5f1, 0xFF27b7f9, 0xFF26b5f6, 0xFF23b3f2, 0xFF24b5fa, 0xFF25b7ff, 0xFF189ddf, + 0xFF43bbf4, 0xFF9edae8, 0xFFf9f9dc, 0xFFf3fbe6, 0xFFffffea, 0xFFfdffe6, 0xFFfafce2, 0xFFffffff, + 0xFF1ea8ef, 0xFF1ca8f1, 0xFF1ba8f2, 0xFF5bc4f1, 0xFFffffe7, 0xFFfbf9e1, 0xFFfbfce3, 0xFFf8fbe0, + 0xFFf5fadd, 0xFFf5fbdb, 0xFFf5fbda, 0xFFf6fcd7, 0xFFf6fdd3, 0xFFf0f8c9, 0xFFebf4be, 0xFFdff2a9, + 0xFFd4f094, 0xFFc7f47b, 0xFFbaf862, 0xFFb0ef58, 0xFFa6e64e, 0xFFa3e248, 0xFF98d73a, 0xFF8acd38, + 0xFF7bc435, 0xFF70b821, 0xFF3b9c84, 0xFF0d93f4, 0xFF1394ed, 0xFF1193e9, 0xFF0f92e6, 0xFF0f92e6, + 0xFF50c9f4, 0xFF4fcaf4, 0xFF4ecaf5, 0xFF4dcaf5, 0xFF4ccaf6, 0xFF48c5f4, 0xFF45c0f3, 0xFF47c2ef, + 0xFF4ac4eb, 0xFFff521f, 0xFFa79a92, 0xFF51b7e6, 0xFF28c7ff, 0xFF2cc4f9, 0xFF31c1f1, 0xFF3fbbf0, + 0xFF37c0ef, 0xFF39b9f0, 0xFF3bb3f1, 0xFF38b5f4, 0xFF36b7f7, 0xFF32b9f0, 0xFF2fbbe8, 0xFF2fb8eb, + 0xFF2fb5ed, 0xFF20acf3, 0xFF10a3fa, 0xFF70c9f3, 0xFFf5f9df, 0xFFf6fbde, 0xFFf6fdde, 0xFFd8ebe4, + 0xFF11a5ee, 0xFF2db2f5, 0xFF14a5f8, 0xFFa5e2ec, 0xFFfffff8, 0xFFfffef3, 0xFFfffded, 0xFFfcfde6, + 0xFFf8fce0, 0xFFf7fcde, 0xFFf6fcdd, 0xFFf6fcd8, 0xFFf5fdd3, 0xFFedf7c4, 0xFFe5f1b4, 0xFFe5f5b8, + 0xFFe4f9bb, 0xFFecfed2, 0xFFf3ffe9, 0xFFedfedb, 0xFFe8f9cd, 0xFFcaef89, 0xFF9cd636, 0xFF84c72e, + 0xFF6bb826, 0xFF6cb315, 0xFF1a95d6, 0xFF1591ef, 0xFF1093eb, 0xFF1193e6, 0xFF1294e1, 0xFF1294e1, + 0xFF52cbf4, 0xFF50caf4, 0xFF4ecaf4, 0xFF4ccaf3, 0xFF4ac9f3, 0xFF48c8f5, 0xFF46c7f6, 0xFF40bfed, + 0xFF41bfeb, 0xFF41d4f9, 0xFF33c9fc, 0xFF2fc9ff, 0xFF42c3ec, 0xFF40c3f4, 0xFF3ec3fc, 0xFF35bbf4, + 0xFF33bbf3, 0xFF49bdf7, 0xFF39b7f9, 0xFF37b7f6, 0xFF35b7f2, 0xFF2eb5f4, 0xFF28b3f5, 0xFF2fbbf8, + 0xFF2fbaf2, 0xFF30b5f2, 0xFF31b0f1, 0xFF1facf6, 0xFF0dabed, 0xFF7fd2ed, 0xFFffffe6, 0xFF80d9d2, + 0xFF2faaf8, 0xFF1dafec, 0xFF03aae6, 0xFFfff8ff, 0xFFfffffe, 0xFFfffff9, 0xFFfffdf4, 0xFFfdfeeb, + 0xFFfbfee3, 0xFFf9fde1, 0xFFf7fce0, 0xFFf5fdd8, 0xFFf4fdcf, 0xFFf5fce2, 0xFFf6fde8, 0xFFf3fde8, + 0xFFf1fde9, 0xFFebfdd3, 0xFFe6fdbe, 0xFFe0f8ba, 0xFFdaf2b7, 0xFFeafcd2, 0xFFf2fde6, 0xFFb7de8d, + 0xFF84c73d, 0xFF9ab848, 0xFF14a1f9, 0xFF0494f3, 0xFF1094ef, 0xFF1095ec, 0xFF1095e9, 0xFF1095e9, + 0xFF54ccf5, 0xFF51cbf4, 0xFF4ecaf3, 0xFF4cc9f2, 0xFF49c8f1, 0xFF48cbf5, 0xFF48cef9, 0xFF40c4f3, + 0xFF49cafc, 0xFF40c2f1, 0xFF47caf5, 0xFF46c7f4, 0xFF46c4f3, 0xFF39b5ee, 0xFF2ca5e8, 0xFF2eb1e1, + 0xFF56c1ea, 0xFF6dc9e9, 0xFF37c2e5, 0xFF51caeb, 0xFF6bd2f1, 0xFF74d1f5, 0xFF7dcff9, 0xFF56c7f8, + 0xFF1fafe8, 0xFF25b1ee, 0xFF2cb3f4, 0xFF3eb5f9, 0xFF2bb3ee, 0xFF1baff5, 0xFF32b5f0, 0xFF3fb2f9, + 0xFF26a9f2, 0xFF1faeeb, 0xFF3fb8f4, 0xFFfcfff3, 0xFFffffff, 0xFFffffff, 0xFFfffefb, 0xFFfefff1, + 0xFFfeffe6, 0xFFfbffe5, 0xFFf8fde3, 0xFFf5fdd7, 0xFFf3fecb, 0xFFf5fbeb, 0xFFf7feee, 0xFFf2fdde, + 0xFFedfccf, 0xFFe3f9b0, 0xFFd9f692, 0xFFd2f48b, 0xFFccf184, 0xFFceee97, 0xFFd0eaa9, 0xFFdaebc1, + 0xFFf4fbe9, 0xFF7fc679, 0xFF5ac1ff, 0xFF1aa1eb, 0xFF1195f2, 0xFF0f96f2, 0xFF0e97f2, 0xFF0e97f2, + 0xFF54cdf5, 0xFF52ccf4, 0xFF4fcbf3, 0xFF4dc9f3, 0xFF4ac8f2, 0xFF49c6f2, 0xFF47c4f2, 0xFF49d2f3, + 0xFF46c8f3, 0xFF4dc5fc, 0xFF2c9add, 0xFF1883cd, 0xFF046cbe, 0xFF0080c5, 0xFF0f96d4, 0xFF2eaddb, + 0xFF60c6eb, 0xFF76cdef, 0xFF51caea, 0xFF69d2f0, 0xFF81daf5, 0xFF9ae4f7, 0xFFb3eff9, 0xFFcffaff, + 0xFFe3feff, 0xFF9ae1ff, 0xFF48bcf7, 0xFF11b5dd, 0xFF32aef0, 0xFF28acfc, 0xFF31b2f3, 0xFF34b1f6, + 0xFF25adf0, 0xFF26acf6, 0xFF98d1fc, 0xFFfffdf8, 0xFFffffff, 0xFFfffffb, 0xFFfefff4, 0xFFfdffee, + 0xFFfcfde7, 0xFFfbfee4, 0xFFfaffe0, 0xFFf8fde7, 0xFFf7fcef, 0xFFf3fbeb, 0xFFeffdd9, 0xFFe9fbc2, + 0xFFe3f9ac, 0xFFd9f49b, 0xFFceef8b, 0xFFc1ea76, 0xFFb4e562, 0xFFabdd5a, 0xFFa2d261, 0xFFc1e98e, + 0xFFdbe8b9, 0xFF96d4ff, 0xFF8ed0fa, 0xFF42aeee, 0xFF1095f1, 0xFF1096f1, 0xFF0f96f1, 0xFF0f96f1, + 0xFF55cef5, 0xFF53ccf4, 0xFF50cbf4, 0xFF4ecaf4, 0xFF4cc8f4, 0xFF51caf7, 0xFF57cbfa, 0xFF45c0ea, + 0xFF1a75c7, 0xFF0058ad, 0xFF015bb4, 0xFF066fc0, 0xFF0b84cd, 0xFF0093ce, 0xFF11a7e0, 0xFF3eb9e6, + 0xFF6bcbeb, 0xFF7ed1f6, 0xFF6cd3f0, 0xFF82dbf4, 0xFF98e3f9, 0xFFa5ecf7, 0xFFb2f4f5, 0xFFc7f7f9, + 0xFFddfafd, 0xFFf2ffff, 0xFFf8fff6, 0xFFbcebfe, 0xFF22b4f2, 0xFF29afff, 0xFF2fb0f7, 0xFF29b1f2, + 0xFF23b1ee, 0xFF1aa7fa, 0xFFcae6f4, 0xFFf7f8f4, 0xFFfeffff, 0xFFfefff7, 0xFFfeffed, 0xFFfcffeb, + 0xFFfbfae9, 0xFFfbfee3, 0xFFfbffdc, 0xFFfbffe9, 0xFFfbfff7, 0xFFf1fedd, 0xFFe7fbc3, 0xFFe0f6b4, + 0xFFd8f0a5, 0xFFceec94, 0xFFc4e884, 0xFFb8e678, 0xFFace36c, 0xFFa0df53, 0xFF94d455, 0xFF80bd41, + 0xFFd2e599, 0xFF2ca1f4, 0xFF30a2f6, 0xFF209cf3, 0xFF1096f1, 0xFF1096f1, 0xFF1096f1, 0xFF1096f1, + 0xFF55cef4, 0xFF53cdf4, 0xFF51cbf5, 0xFF50cbf5, 0xFF4ecaf6, 0xFF4dc9f4, 0xFF54d0fa, 0xFF2b86ce, + 0xFF0752b1, 0xFF045fb9, 0xFF0a74c9, 0xFF0882ce, 0xFF0691d4, 0xFF02a0d5, 0xFF24b5e7, 0xFF4cc4ea, + 0xFF74d3ee, 0xFF83d9f5, 0xFF7fddf4, 0xFF93e4f6, 0xFFa8ecf9, 0xFFb6f2f9, 0xFFc3f9f9, 0xFFd3fafb, + 0xFFe3fcfc, 0xFFedfefb, 0xFFf0f9f3, 0xFFffffff, 0xFFfffdff, 0xFF7edcef, 0xFF26adfd, 0xFF2aaff7, + 0xFF2db2f2, 0xFF34b1e0, 0xFF09a7f7, 0xFF8dd3f5, 0xFFfdfbf9, 0xFFfffff6, 0xFFfdffeb, 0xFFfcffe6, + 0xFFfcfce0, 0xFFf9fcde, 0xFFf7fcdd, 0xFFfcffef, 0xFFf9fdec, 0xFFe8f5d0, 0xFFdff5bd, 0xFFd9f1ad, + 0xFFd2ed9d, 0xFFc5e97e, 0xFFb8e26d, 0xFFabdd5e, 0xFF9fd74f, 0xFF98c95f, 0xFF92c735, 0xFF8bc942, + 0xFF80b34d, 0xFF009bf2, 0xFF1894f8, 0xFF1595f5, 0xFF1397f2, 0xFF1296f1, 0xFF1195f0, 0xFF1195f0, + 0xFF56cff4, 0xFF54cdf5, 0xFF52ccf5, 0xFF51cbf7, 0xFF51cbf9, 0xFF49c8f1, 0xFF51d5fa, 0xFF1662c1, + 0xFF005cbb, 0xFF0874cd, 0xFF037cce, 0xFF028dd4, 0xFF019edb, 0xFF09aedc, 0xFF37c2ee, 0xFF5acfef, + 0xFF7edcf0, 0xFF88e1f4, 0xFF92e6f8, 0xFFa5eef8, 0xFFb9f5f9, 0xFFc7f9fb, 0xFFd5fdfe, 0xFFdffdfc, + 0xFFe9fdfa, 0xFFf0fefe, 0xFFf8ffff, 0xFFfafffe, 0xFFfdfffc, 0xFFfdfbff, 0xFF1db0e8, 0xFF2ab1ee, + 0xFF37b2f5, 0xFF25b9f7, 0xFF29b4f8, 0xFF22aff5, 0xFF1baaf2, 0xFF9fd7f6, 0xFFfdffea, 0xFFfcfee0, + 0xFFfcfdd7, 0xFFf8fada, 0xFFf4f7dd, 0xFFfdfef5, 0xFFf6fae1, 0xFFdfecc3, 0xFFd8efb6, 0xFFd2eca6, + 0xFFccea95, 0xFFbce567, 0xFFabdb56, 0xFF9fd344, 0xFF92cb33, 0xFF85c824, 0xFF79b46a, 0xFF3a9eaf, + 0xFF0c97ff, 0xFF1994f9, 0xFF0f9bee, 0xFF139af0, 0xFF1699f3, 0xFF1497f1, 0xFF1295ef, 0xFF1295ef, + 0xFF58d0f5, 0xFF56cef5, 0xFF53cdf4, 0xFF53ccf6, 0xFF52cbf8, 0xFF53d6fb, 0xFF4fc8fc, 0xFF004cad, + 0xFF096fca, 0xFF0b80d4, 0xFF0588d5, 0xFF0598db, 0xFF05a8e1, 0xFF18b6e6, 0xFF3fc8f2, 0xFF63d3f3, + 0xFF86dff5, 0xFF91e4f7, 0xFF9ce9fa, 0xFFaef0f9, 0xFFc0f7f9, 0xFFcbfafb, 0xFFd7fdfd, 0xFFdefdfc, + 0xFFe6fefb, 0xFFf0fffe, 0xFFfaffff, 0xFFf2fefb, 0xFFfefffd, 0xFFc6e9fb, 0xFF1eb0ec, 0xFF30b4f6, + 0xFF30b7f8, 0xFF19a8f7, 0xFF26b0f0, 0xFF22aef3, 0xFF1eabf5, 0xFF27aafa, 0xFF1ca6f6, 0xFF7dcdea, + 0xFFdff4dd, 0xFFeaffb0, 0xFFfdfeed, 0xFFffffef, 0xFFfcf9d3, 0xFFedeeb4, 0xFFe6e9ac, 0xFFd9e68a, + 0xFFcbe367, 0xFFb9e153, 0xFFa6dd4d, 0xFF75c57f, 0xFF43adb0, 0xFF229bf3, 0xFF0a9cff, 0xFF0998f6, + 0xFF109cef, 0xFF189aee, 0xFF149ded, 0xFF159bf0, 0xFF1599f2, 0xFF1397f0, 0xFF1195ee, 0xFF1195ee, + 0xFF5ad1f6, 0xFF57cff5, 0xFF54cef4, 0xFF54cdf6, 0xFF53cbf8, 0xFF4dd3f4, 0xFF2c9add, 0xFF045ec1, + 0xFF0572c9, 0xFF0683d2, 0xFF0794dc, 0xFF08a2e2, 0xFF08b1e8, 0xFF28bfef, 0xFF48cef6, 0xFF6bd8f8, + 0xFF8fe3fa, 0xFF9be8fa, 0xFFa6edfb, 0xFFb7f3fb, 0xFFc7f9fa, 0xFFd0fbfc, 0xFFd9fdfd, 0xFFdefefd, + 0xFFe2fffc, 0xFFeffffe, 0xFFfcffff, 0xFFebfef7, 0xFFfffffe, 0xFF8fd7f8, 0xFF1eb0f1, 0xFF2eb0f6, + 0xFF18abec, 0xFFe0f7fd, 0xFF24ade9, 0xFF23acf1, 0xFF21acf8, 0xFF26aef7, 0xFF2cb0f6, 0xFF1aa9f5, + 0xFF08a3f4, 0xFF22a7f9, 0xFF4cc2f2, 0xFF6dcdef, 0xFF7ec9db, 0xFF7fcac2, 0xFF81c6c6, 0xFF61bccb, + 0xFF41b3d0, 0xFF24a7e9, 0xFF089bff, 0xFF119dff, 0xFF1a9fff, 0xFF0f99e9, 0xFF149cf9, 0xFF159cf7, + 0xFF159cf5, 0xFF179df1, 0xFF199eed, 0xFF179cef, 0xFF1599f1, 0xFF1397ef, 0xFF1195ed, 0xFF1195ed, + 0xFF5cd2f6, 0xFF59d0f5, 0xFF55cff3, 0xFF54cdf5, 0xFF53ccf8, 0xFF51d5f6, 0xFF167bcf, 0xFF0467c6, + 0xFF067bcf, 0xFF068bd7, 0xFF059cdf, 0xFF08a9e5, 0xFF0ab6eb, 0xFF2bc4f1, 0xFF4cd2f7, 0xFF6ddbf9, + 0xFF8ee5fa, 0xFF9deafb, 0xFFaceffb, 0xFFbdf5fb, 0xFFcefbfa, 0xFFd5fbfc, 0xFFdcfcfd, 0xFFdcfefd, + 0xFFddfffd, 0xFFe4fffd, 0xFFeafffd, 0xFFfffffe, 0xFFffffff, 0xFF27c0de, 0xFF26b5f6, 0xFF1fb0f9, + 0xFF4dc6ff, 0xFFfff9ef, 0xFFfefffa, 0xFF8bd8f7, 0xFF18a7f3, 0xFF1daaf4, 0xFF23acf6, 0xFF22acf3, + 0xFF22abf0, 0xFF1aa3f2, 0xFF1aa6ee, 0xFF18a8f5, 0xFF0ea2f3, 0xFF11a4f2, 0xFF14a4ff, 0xFF15a3fc, + 0xFF16a3fa, 0xFF17a2f3, 0xFF19a2ec, 0xFF0e99fe, 0xFF169bed, 0xFF00a1ff, 0xFF2b9de8, 0xFF61b5b0, + 0xFF109af7, 0xFF149cf2, 0xFF189eed, 0xFF169cef, 0xFF149af0, 0xFF1298ee, 0xFF1096ec, 0xFF1096ec, + 0xFF5fd3f7, 0xFF5bd2f5, 0xFF56d0f3, 0xFF55cef5, 0xFF53cdf7, 0xFF56d8f8, 0xFF005cc0, 0xFF0370cb, + 0xFF0785d6, 0xFF0594dc, 0xFF04a3e2, 0xFF08afe8, 0xFF0cbcee, 0xFF2ec8f3, 0xFF50d5f9, 0xFF6fdefa, + 0xFF8de7fb, 0xFF9fecfb, 0xFFb1f2fb, 0xFFc3f7fb, 0xFFd4fcfa, 0xFFd9fcfc, 0xFFdefcfd, 0xFFdbfdfd, + 0xFFd9fffd, 0xFFd9fdfb, 0xFFd9fcfa, 0xFFe5fafa, 0xFFa4eaf7, 0xFF2badfb, 0xFF2fb9fa, 0xFF1aaeed, + 0xFF99dbf8, 0xFFffffff, 0xFFfefdfc, 0xFFfffefd, 0xFFfffffd, 0xFF8cd4fa, 0xFF19a9f6, 0xFF18a9f7, + 0xFF16aaf9, 0xFF1aa7f3, 0xFF1ea5ee, 0xFF1fa7f2, 0xFF21a9f6, 0xFF1ea7f7, 0xFF1ba5f7, 0xFF17a4f9, + 0xFF12a2fb, 0xFF0b9dfd, 0xFF0399fe, 0xFF26a2fa, 0xFF6fc0b0, 0xFFcfca5e, 0xFFffe528, 0xFF74b4b3, + 0xFF0b98fa, 0xFF119af4, 0xFF179dee, 0xFF159cee, 0xFF139aef, 0xFF1198ed, 0xFF0f96eb, 0xFF0f96eb, + 0xFF5dd1f6, 0xFF5bd2f5, 0xFF58d2f4, 0xFF53cef4, 0xFF56d2fb, 0xFF40b2e6, 0xFF0164c6, 0xFF0376cf, + 0xFF0487d7, 0xFF0296dd, 0xFF01a4e4, 0xFF04b1ea, 0xFF07bdf1, 0xFF1bc8f2, 0xFF43d5fc, 0xFF64ddfb, + 0xFF85e6fb, 0xFF98ebfc, 0xFFacf1fd, 0xFFbef9ff, 0xFFcfffff, 0xFFcffdff, 0xFFcff9fb, 0xFFd2fefe, + 0xFFd5ffff, 0xFFc6f9ff, 0xFFb8efff, 0xFF5ad7d9, 0xFF40b9e9, 0xFF2fb9ff, 0xFF2bb2f0, 0xFF28afeb, + 0xFFdef0f2, 0xFFffffff, 0xFFfeffff, 0xFFfffefe, 0xFFfffefa, 0xFFfffffa, 0xFFfffff9, 0xFFc2e8f0, + 0xFF84cde7, 0xFF53bbe9, 0xFF22a9eb, 0xFF14a1ff, 0xFF069ff8, 0xFF0fa0f8, 0xFF19a3eb, 0xFF43b1e1, + 0xFF6ec2c9, 0xFFb0d79a, 0xFFf2eb6b, 0xFFebee32, 0xFFf8e647, 0xFFffe23a, 0xFFfde142, 0xFF0098f4, + 0xFF19a1fc, 0xFF169ef7, 0xFF129bf1, 0xFF139af1, 0xFF149af0, 0xFF1298ee, 0xFF1096ec, 0xFF1096ec, + 0xFF5ccff6, 0xFF5bd2f6, 0xFF5ad4f6, 0xFF52cdf2, 0xFF5ad6fe, 0xFF298cd5, 0xFF026ccc, 0xFF027bd2, + 0xFF0189d8, 0xFF0097df, 0xFF00a6e6, 0xFF00b2ed, 0xFF02bef4, 0xFF09c7f1, 0xFF35d5ff, 0xFF59ddfd, + 0xFF7ce5fb, 0xFF91eafd, 0xFFa6f0ff, 0xFFb1f2ff, 0xFFbbf5ff, 0xFFbef5fc, 0xFFc1f6f9, 0xFFc1f7f7, + 0xFFc1f9f4, 0xFFc7fdfc, 0xFFcdffff, 0xFFc2f9f8, 0xFF5acdf4, 0xFF39b1f3, 0xFF38baf5, 0xFF2ab4f7, + 0xFFfcfbf8, 0xFFfdfeff, 0xFFfeffff, 0xFFfffeff, 0xFFfffcf6, 0xFFfdfef2, 0xFFf7ffee, 0xFFfcffea, + 0xFFffffe5, 0xFFffffd8, 0xFFffffcb, 0xFFfffbf1, 0xFFffffdf, 0xFFfdfdc2, 0xFFf7ff88, 0xFFfbfe92, + 0xFFffff7f, 0xFFfdfc6c, 0xFFfaf759, 0xFFf8f059, 0xFFf7e958, 0xFFf7e359, 0xFFd0d368, 0xFF0998ff, + 0xFF189aef, 0xFF129af2, 0xFF0c99f5, 0xFF1199f3, 0xFF1599f2, 0xFF1397f0, 0xFF1195ee, 0xFF1195ee, + 0xFF5fd2f9, 0xFF5cd3f8, 0xFF59d4f6, 0xFF58d3f8, 0xFF5edaff, 0xFF1971cd, 0xFF026ecd, 0xFF037bd3, + 0xFF0488d9, 0xFF0497e0, 0xFF05a6e6, 0xFF01ade7, 0xFF00b5e8, 0xFF07beea, 0xFF23cbf5, 0xFF4cd7f8, + 0xFF74e4fc, 0xFF89e8fd, 0xFF9fecfe, 0xFFa5edfe, 0xFFabeffe, 0xFFaeeffc, 0xFFb0eff9, 0xFFb3f3f9, + 0xFFb6f6f8, 0xFFb6f9fc, 0xFFb5fcff, 0xFFdaf3ff, 0xFF1ab9f1, 0xFF28b3f4, 0xFF2bb3f6, 0xFF73cef4, + 0xFFfdfdf5, 0xFFfdfefa, 0xFFfdfffe, 0xFFfffef9, 0xFFfffdf3, 0xFFfdfeee, 0xFFfaffe9, 0xFFfdffe4, + 0xFFffffde, 0xFFffffd0, 0xFFffffc2, 0xFFfdfad7, 0xFFfffcf3, 0xFFffffc0, 0xFFfcfbc5, 0xFFfcff84, + 0xFFfcfb8b, 0xFFfbf67a, 0xFFf9f269, 0xFFf7ed5e, 0xFFf4e954, 0xFFf7e948, 0xFF87bda9, 0xFF109afc, + 0xFF179cf2, 0xFF149bf1, 0xFF119af1, 0xFF1399f2, 0xFF1698f3, 0xFF1496f1, 0xFF1294ef, 0xFF1294ef, + 0xFF62d4fc, 0xFF5dd4f9, 0xFF59d4f6, 0xFF56d1f6, 0xFF53cef5, 0xFF014ebe, 0xFF026fcd, 0xFF057bd4, + 0xFF0787da, 0xFF0996e0, 0xFF0ca5e7, 0xFF0bb0e9, 0xFF09bbeb, 0xFF15c5f3, 0xFF21d0fc, 0xFF46dafc, + 0xFF6ce3fc, 0xFF82e6fd, 0xFF97e9fe, 0xFF99e9fe, 0xFF9ce8fe, 0xFF9ee9fb, 0xFFa0e9f9, 0xFFa6eefa, + 0xFFacf3fc, 0xFFb0effc, 0xFFb5ecfb, 0xFF89ddf9, 0xFF28b4f3, 0xFF3ebef7, 0xFF1eadf7, 0xFFbde8f0, + 0xFFfefff2, 0xFFfefff3, 0xFFfdfff4, 0xFFfefef2, 0xFFfefef0, 0xFFfefeea, 0xFFfefee4, 0xFFfefede, + 0xFFfefed8, 0xFFfcffc9, 0xFFfbffba, 0xFFf6fea0, 0xFFffffce, 0xFFfff9f6, 0xFFffffc9, 0xFFfdf7be, + 0xFFf8f87a, 0xFFf9f66b, 0xFFf9f35c, 0xFFf5ee56, 0xFFf1e84f, 0xFFf8ee37, 0xFF3fa7ea, 0xFF189df5, + 0xFF179df4, 0xFF169cf1, 0xFF159bee, 0xFF169af2, 0xFF1798f5, 0xFF1596f3, 0xFF1394f1, 0xFF1394f1, + 0xFF66d7fc, 0xFF5fd1f5, 0xFF60d4f6, 0xFF59d8f9, 0xFF399ddb, 0xFF0858be, 0xFF096ccd, 0xFF0c7ad2, + 0xFF1087d7, 0xFF1296df, 0xFF13a6e8, 0xFF13b0eb, 0xFF1bc3f5, 0xFF0fc8f3, 0xFF17d0f9, 0xFF27d3f4, + 0xFF4bd7f7, 0xFF61dbf8, 0xFF77def9, 0xFF7fe0fa, 0xFF88e1fa, 0xFF8de4fb, 0xFF91e7fb, 0xFF96eafc, + 0xFF9aedfd, 0xFF9feafb, 0xFFa3e7fa, 0xFF5eccfb, 0xFF2db7f5, 0xFF24b8f9, 0xFF14b1f5, 0xFFfffbff, + 0xFFfeffec, 0xFFffffed, 0xFFffffee, 0xFFffffec, 0xFFfefdeb, 0xFFfefde4, 0xFFfefddd, 0xFFfefed6, + 0xFFfefece, 0xFFfcfdc1, 0xFFfcfcb5, 0xFFf6fb8d, 0xFFf8fc8a, 0xFFf8facc, 0xFFf8fef2, 0xFFf9ffbe, + 0xFFfbf9c2, 0xFFfbf8ac, 0xFFfcf796, 0xFFfaf491, 0xFFf7f18d, 0xFFffe5a9, 0xFF0096f7, 0xFF089af7, + 0xFF159ef7, 0xFF169df4, 0xFF169cf0, 0xFF169bf2, 0xFF1699f4, 0xFF1497f3, 0xFF1396f1, 0xFF1396f1, + 0xFF6bd9fb, 0xFF61cef1, 0xFF67d3f7, 0xFF5cdefd, 0xFF1f6cc0, 0xFF0f63bf, 0xFF0f6acd, 0xFF1478d1, + 0xFF1887d4, 0xFF1997df, 0xFF1aa6e9, 0xFF14a9e4, 0xFF1dbbef, 0xFF0dbeeb, 0xFF23c5f6, 0xFF13c6ed, + 0xFF2acbf3, 0xFF40cff4, 0xFF56d4f4, 0xFF65d7f6, 0xFF74daf7, 0xFF7bdffb, 0xFF83e5fe, 0xFF86e6fe, + 0xFF89e8fd, 0xFF8ee5fb, 0xFF92e2fa, 0xFF33bcfc, 0xFF32b9f7, 0xFF31bafd, 0xFF57c5f7, 0xFFf4ffde, + 0xFFfdffe7, 0xFFffffe7, 0xFFffffe7, 0xFFffffe6, 0xFFfdfce6, 0xFFfdfddd, 0xFFfdfdd5, 0xFFfdfdcd, + 0xFFfefdc5, 0xFFfdfaba, 0xFFfcf8af, 0xFFfef99f, 0xFFfffb8e, 0xFFfafe77, 0xFFf4fb7d, 0xFFf9f8d2, + 0xFFfdffee, 0xFFfefedf, 0xFFfffcd0, 0xFFfefacd, 0xFFfdf9ca, 0xFFa6d3ce, 0xFF0399eb, 0xFF1ea1ec, + 0xFF149ffa, 0xFF159ef6, 0xFF179ef2, 0xFF169cf3, 0xFF159af3, 0xFF1499f2, 0xFF1398f1, 0xFF1398f1, + 0xFF55d4f4, 0xFF5bd1f1, 0xFF69d6f6, 0xFF6ee2ff, 0xFF0c50a8, 0xFF1161be, 0xFF0f6acd, 0xFF1f83d6, + 0xFF1f89dc, 0xFF0f8cdd, 0xFF1a9be0, 0xFF22b1f4, 0xFF1dabe1, 0xFF14aedf, 0xFF26bdee, 0xFF15bae7, + 0xFF1fc1ef, 0xFF25c7ef, 0xFF2bcdef, 0xFF3dcdf1, 0xFF4ecef3, 0xFF5bd6f9, 0xFF68defe, 0xFF6eddfc, + 0xFF73ddfb, 0xFF76ddf5, 0xFF70d3f7, 0xFF31bafb, 0xFF33b9f6, 0xFF24b6ff, 0xFFa4dee5, 0xFFf9ffdc, + 0xFFfdfedc, 0xFFffffdc, 0xFFffffdc, 0xFFfefedb, 0xFFfcfdda, 0xFFfdfdd2, 0xFFfdfdcb, 0xFFfdfdc3, + 0xFFfefdbc, 0xFFfdfbaf, 0xFFfcfaa2, 0xFFfdfb93, 0xFFfefb83, 0xFFfcfd6b, 0xFFf9fc60, 0xFFfbf85d, + 0xFFfdf74c, 0xFFfef576, 0xFFfff2a1, 0xFFf6ec87, 0xFFf8e360, 0xFF51bbb4, 0xFF0d9afe, 0xFF1a9ef7, + 0xFF159ef6, 0xFF159df4, 0xFF159df2, 0xFF149bf2, 0xFF1299f2, 0xFF1299f2, 0xFF1299f2, 0xFF1299f2, + 0xFF67d4fd, 0xFF69d6f9, 0xFF6cd9f5, 0xFF4fb7dc, 0xFF1953af, 0xFF1c67c6, 0xFF005abd, 0xFF1a7eca, + 0xFF157bd4, 0xFF0581dc, 0xFF2aa1e7, 0xFF0189d3, 0xFF2dabe3, 0xFF23a7dc, 0xFF29b4e6, 0xFF17ade1, + 0xFF14b7ec, 0xFF15b9ea, 0xFF16bbe9, 0xFF1fbfec, 0xFF28c2ef, 0xFF3bcdf7, 0xFF4ed8ff, 0xFF56d5fb, + 0xFF5dd2f8, 0xFF5ed6f0, 0xFF4ec5f4, 0xFF2fb9fa, 0xFF35b8f4, 0xFF17b1ff, 0xFFf0f7d2, 0xFFfeffda, + 0xFFfdfcd2, 0xFFfdfdd1, 0xFFfdfed1, 0xFFfdfecf, 0xFFfcfecd, 0xFFfcfdc7, 0xFFfdfdc0, 0xFFfdfdb9, + 0xFFfdfdb2, 0xFFfdfca4, 0xFFfdfc95, 0xFFfdfc87, 0xFFfdfc79, 0xFFfdfa6c, 0xFFfef85f, 0xFFf9f645, + 0xFFf6ef47, 0xFFf2e938, 0xFFefe428, 0xFFeee425, 0xFFffdd05, 0xFF0399ff, 0xFF17a1f5, 0xFF179ef4, + 0xFF169cf3, 0xFF159cf3, 0xFF149cf3, 0xFF129bf1, 0xFF1099f0, 0xFF119af1, 0xFF129bf2, 0xFF129bf2, + 0xFF66d5fb, 0xFF70d5fc, 0xFF78e2ff, 0xFF3b86c7, 0xFF235fba, 0xFF1e6aba, 0xFF227ad1, 0xFF2787d8, + 0xFF248cd7, 0xFF1d8dd4, 0xFF2189d1, 0xFF2ca1ea, 0xFF2296d5, 0xFF31aaef, 0xFF20a1db, 0xFF17a1dd, + 0xFF0ea1e0, 0xFF1aace3, 0xFF13b1eb, 0xFF10b8ed, 0xFF0dc0ef, 0xFF1cc1ef, 0xFF2cc3f0, 0xFF36c4f2, + 0xFF40c5f4, 0xFF47c9f2, 0xFF45c3f6, 0xFF31bafa, 0xFF31b7f7, 0xFF4cc2f4, 0xFFf5fac0, 0xFFfdffc6, + 0xFFfdfcc5, 0xFFfdfdc4, 0xFFfdfdc4, 0xFFfcfdc2, 0xFFfbfdc1, 0xFFf8f9b6, 0xFFfdfdb3, 0xFFfdfdab, + 0xFFfdfca3, 0xFFfcfc95, 0xFFfcfb88, 0xFFfcfb7b, 0xFFfbfb6d, 0xFFfcf962, 0xFFfcf757, 0xFFf8f245, + 0xFFf4eb41, 0xFFf0e532, 0xFFebe023, 0xFFfbe01c, 0xFFc5d244, 0xFF0aa2fe, 0xFF169ff9, 0xFF179ff6, + 0xFF189ff3, 0xFF179ef2, 0xFF159df2, 0xFF179ff5, 0xFF18a1f8, 0xFF159ef5, 0xFF129bf2, 0xFF129bf2, + 0xFF65d7fa, 0xFF64d1f7, 0xFF5de7ff, 0xFF04439b, 0xFF0e4ca5, 0xFF317bcd, 0xFF0455c1, 0xFF0053c9, + 0xFF0368c6, 0xFF2687ca, 0xFF2881ca, 0xFF2789d1, 0xFF2791d7, 0xFF0774c9, 0xFF178dcf, 0xFF1f9ce1, + 0xFF179be4, 0xFF1e9eda, 0xFF0097de, 0xFF03a5e6, 0xFF08b1ee, 0xFF09b0e8, 0xFF0aafe2, 0xFF17b4e9, + 0xFF24b9ef, 0xFF30bdf4, 0xFF3cc1f9, 0xFF34bcf9, 0xFF2cb6f9, 0xFF80d2e8, 0xFFfafdaf, 0xFFfcfdb3, + 0xFFfdfcb7, 0xFFfdfcb7, 0xFFfdfdb7, 0xFFfcfcb6, 0xFFfbfcb5, 0xFFf4f4a5, 0xFFfdfda5, 0xFFfcfc9d, + 0xFFfcfc94, 0xFFfbfb87, 0xFFfbfb7b, 0xFFfafa6e, 0xFFfafa61, 0xFFfaf758, 0xFFfaf54e, 0xFFf7ee44, + 0xFFf3e73a, 0xFFede12c, 0xFFe7db1e, 0xFFffd21a, 0xFF78b090, 0xFF09a0fd, 0xFF159dfd, 0xFF18a0f8, + 0xFF1aa2f2, 0xFF18a0f2, 0xFF169ef2, 0xFF139bf2, 0xFF1099f1, 0xFF119af2, 0xFF129bf3, 0xFF129bf3, + 0xFF60d4f7, 0xFF67dcfd, 0xFF4fc2f0, 0xFF002c8a, 0xFF2e6bc0, 0xFF0547ad, 0xFF0044ba, 0xFF3685c4, + 0xFF064ebc, 0xFF1462c3, 0xFF2d70cb, 0xFF0f5ab4, 0xFF2274cd, 0xFF1169c2, 0xFF1979c2, 0xFF1d80d0, + 0xFF1980d7, 0xFF1a86d3, 0xFF1090de, 0xFF038dda, 0xFF0599e6, 0xFF059ce1, 0xFF049edd, 0xFF05a6e1, + 0xFF00a7de, 0xFF1fb6ee, 0xFF39bdf7, 0xFF38bcf6, 0xFF24b5fc, 0xFFbfe8b9, 0xFFfafea2, 0xFFfbfca5, + 0xFFfcfaa8, 0xFFfcfca7, 0xFFfdfda6, 0xFFfbfca3, 0xFFf9fb9f, 0xFFf6f795, 0xFFfafb92, 0xFFfbfb8b, + 0xFFfbfb85, 0xFFfafa79, 0xFFfafa6d, 0xFFf9f961, 0xFFf8f956, 0xFFf9f64c, 0xFFf9f442, 0xFFf5ec39, + 0xFFf2e531, 0xFFefde28, 0xFFecd620, 0xFFeed900, 0xFF32a6e5, 0xFF19a4ff, 0xFF29a4f4, 0xFF20a2f4, + 0xFF18a0f5, 0xFF179ef4, 0xFF159df4, 0xFF139bf3, 0xFF1199f2, 0xFF129af2, 0xFF129af3, 0xFF129af3, + 0xFF5bd1f5, 0xFF63dffa, 0xFF318dcc, 0xFF062d91, 0xFF0e499a, 0xFF00369f, 0xFF003897, 0xFF155fb6, + 0xFF53aad9, 0xFF31a6e2, 0xFF45bcef, 0xFF6dddff, 0xFF76defa, 0xFF6dd9f9, 0xFF64d5f9, 0xFF54c5f3, + 0xFF45b5ed, 0xFF238ed6, 0xFF1277ce, 0xFF006cc6, 0xFF0282de, 0xFF0187db, 0xFF008dd7, 0xFF079be1, + 0xFF0099dc, 0xFF22b1f0, 0xFF36baf4, 0xFF3cbcf4, 0xFF1cb5ff, 0xFFfffe89, 0xFFfbff96, 0xFFfbfc98, + 0xFFfbf99a, 0xFFfcfb98, 0xFFfdfd96, 0xFFfafb90, 0xFFf6f98a, 0xFFf7f984, 0xFFf8fa7f, 0xFFfafa7a, + 0xFFfbfb75, 0xFFfafa6a, 0xFFf9f960, 0xFFf8f855, 0xFFf7f84a, 0xFFf7f540, 0xFFf8f336, 0xFFf4eb2f, + 0xFFf0e328, 0xFFf0da24, 0xFFf0d121, 0xFFe9ca24, 0xFF049bff, 0xFF20a3f6, 0xFF16a1f7, 0xFF16a0f7, + 0xFF169ef7, 0xFF159df6, 0xFF149cf5, 0xFF139bf4, 0xFF129af3, 0xFF129af3, 0xFF129af3, 0xFF129af3, + 0xFF5ae3ff, 0xFF64d8ff, 0xFF0d4798, 0xFF002682, 0xFF1d6bb7, 0xFF3aa2de, 0xFF5fe5ff, 0xFF52d8fd, + 0xFF4dd6f6, 0xFF48ccf5, 0xFF5fd0f6, 0xFF68d9ff, 0xFF61d3f8, 0xFF5bd2f8, 0xFF42cbff, 0xFF53cefe, + 0xFF51cff5, 0xFF49caf6, 0xFF4acdff, 0xFF40baff, 0xFF0e7edb, 0xFF0069c2, 0xFF0584da, 0xFF0184d5, + 0xFF068cd8, 0xFF38bef8, 0xFF3abef7, 0xFF35beff, 0xFF62c7e2, 0xFFfbf379, 0xFFf8fa83, 0xFFf9f983, + 0xFFfaf884, 0xFFf9f77f, 0xFFf7f77b, 0xFFf8f979, 0xFFf9fa77, 0xFFf8f972, 0xFFf7f86c, 0xFFfcfc6c, + 0xFFf9f864, 0xFFf8f85b, 0xFFf8f752, 0xFFf7f649, 0xFFf6f53f, 0xFFf5f237, 0xFFf4ef2f, 0xFFf1e628, + 0xFFeede20, 0xFFead61f, 0xFFf2cc11, 0xFF9db96c, 0xFF0c9ffe, 0xFF1ba3f9, 0xFF17a2f9, 0xFF17a0f9, + 0xFF169ef8, 0xFF169df7, 0xFF159cf6, 0xFF149bf5, 0xFF139af5, 0xFF139af5, 0xFF139af5, 0xFF139af5, + 0xFF60d8f9, 0xFF5bd9f8, 0xFF4cadd7, 0xFF69ddff, 0xFF56ddf8, 0xFF55d6fc, 0xFF55d0ff, 0xFF5cd5ff, + 0xFF53cbf2, 0xFF4bcaf6, 0xFF43cafa, 0xFF47c9f8, 0xFF4cc8f6, 0xFF5ccff1, 0xFF46ccf8, 0xFF55caff, + 0xFF3ec4fa, 0xFF43c3fb, 0xFF48c2fd, 0xFF3ebff4, 0xFF44ccfb, 0xFF37b3fc, 0xFF0b7bdd, 0xFF006dc9, + 0xFF0d80d4, 0xFF4eccff, 0xFF3ec3fa, 0xFF2ec2ff, 0xFFa7dea8, 0xFFf8ec5b, 0xFFf5f570, 0xFFf7f66f, + 0xFFfaf76e, 0xFFf5f467, 0xFFf1f060, 0xFFf6f663, 0xFFfbfc65, 0xFFf8f95f, 0xFFf6f659, 0xFFfefe5d, + 0xFFf7f652, 0xFFf7f54c, 0xFFf7f545, 0xFFf6f33d, 0xFFf6f235, 0xFFf3ef2f, 0xFFf1eb29, 0xFFefe221, + 0xFFecd818, 0xFFe5d21a, 0xFFf3c700, 0xFF52a9b4, 0xFF14a4fb, 0xFF15a3fb, 0xFF17a3fc, 0xFF17a1fa, + 0xFF179ff8, 0xFF169df8, 0xFF159cf7, 0xFF159bf7, 0xFF1499f6, 0xFF1499f6, 0xFF1499f6, 0xFF1499f6, + 0xFF58cff2, 0xFF59ddfd, 0xFF55d5f9, 0xFF5ddeff, 0xFF4dcef3, 0xFF4dcbf3, 0xFF4cc8f3, 0xFF56d2fc, + 0xFF59d3fd, 0xFF50cefb, 0xFF47cafa, 0xFF48c9f9, 0xFF49c7f9, 0xFF51cbf6, 0xFF45c9f9, 0xFF4bc8fd, + 0xFF3fc5f9, 0xFF41c4fa, 0xFF43c2fb, 0xFF3bbdf3, 0xFF3ac0f4, 0xFF3ec7fc, 0xFF3ac6fc, 0xFF25a1e3, + 0xFF1f8dd9, 0xFF37b9f7, 0xFF26bbfa, 0xFF2abbf4, 0xFFced857, 0xFFf9fa5b, 0xFFd9db49, 0xFFedec58, + 0xFFfaf560, 0xFFf2ef4d, 0xFFe9ea3b, 0xFFeeef46, 0xFFf2f451, 0xFFf9f34f, 0xFFedf145, 0xFFfef84b, + 0xFFf4f542, 0xFFf5f43d, 0xFFf6f337, 0xFFf5f131, 0xFFf5ef2b, 0xFFf2eb27, 0xFFf0e622, 0xFFeedb1d, + 0xFFecd117, 0xFFf1cc09, 0xFFf5c509, 0xFF0fadff, 0xFF17a1f9, 0xFF18a1f9, 0xFF18a1f8, 0xFF18a0f9, + 0xFF179ff9, 0xFF169df9, 0xFF169cf8, 0xFF159bf8, 0xFF1599f8, 0xFF1599f8, 0xFF1599f8, 0xFF1599f8, + 0xFF60d5fb, 0xFF5bd3fb, 0xFF56d2fb, 0xFF55d1fc, 0xFF55d0fe, 0xFF54d0fa, 0xFF53d1f6, 0xFF51cef7, + 0xFF4ecbf8, 0xFF4dcbf9, 0xFF4ccafb, 0xFF49c8fb, 0xFF47c6fc, 0xFF45c6fb, 0xFF43c6fa, 0xFF41c6fa, + 0xFF40c7f9, 0xFF3fc5f9, 0xFF3ec3f9, 0xFF3fc3fb, 0xFF41c4fd, 0xFF38baf2, 0xFF40c1f8, 0xFF3dc3fb, + 0xFF3bc5fe, 0xFF37c1f6, 0xFF34beef, 0xFF2ebcf0, 0xFFded722, 0xFFbfdc38, 0xFFdee142, 0xFFecea4a, + 0xFFeae442, 0xFFeee942, 0xFFf2ee42, 0xFFeeed3f, 0xFFeaec3d, 0xFFfbee3f, 0xFFe5ec31, 0xFFfff239, + 0xFFf2f531, 0xFFf4f32e, 0xFFf5f12a, 0xFFf5ee25, 0xFFf4ec21, 0xFFf2e71e, 0xFFf0e11c, 0xFFeed519, + 0xFFecc917, 0xFFdec40c, 0xFFbbbe39, 0xFF0798f8, 0xFF1a9ff8, 0xFF1a9ff7, 0xFF1a9ff5, 0xFF189ff7, + 0xFF179ff9, 0xFF179ef9, 0xFF169cf9, 0xFF169bf9, 0xFF1699f9, 0xFF1699f9, 0xFF1699f9, 0xFF1699f9, + 0xFF5cd4f9, 0xFF58d4f9, 0xFF55d3f9, 0xFF56d2fa, 0xFF58d0fb, 0xFF56d0f8, 0xFF54d0f6, 0xFF51cef7, + 0xFF4dccf9, 0xFF4ccbfa, 0xFF4bcafb, 0xFF49c8fb, 0xFF47c7fb, 0xFF45c7fb, 0xFF43c6fa, 0xFF41c6fa, + 0xFF40c6f9, 0xFF3fc4f9, 0xFF3ec3f9, 0xFF3ec2fa, 0xFF3ec2fb, 0xFF3abef5, 0xFF3ec2f8, 0xFF3bc1f9, + 0xFF37c0f9, 0xFF36beff, 0xFF35bbff, 0xFF67bb84, 0xFFb0d219, 0xFFb4d31a, 0xFFd3da39, 0xFFe2dd3d, + 0xFFd6d532, 0xFFe1df38, 0xFFece93e, 0xFFe1e636, 0xFFe9e536, 0xFFf1e634, 0xFFe5e42b, 0xFFf6e62e, + 0xFFe9eb29, 0xFFf0ee2a, 0xFFf0e824, 0xFFece420, 0xFFe9e01d, 0xFFebdb1c, 0xFFedd71c, 0xFFe9ce19, + 0xFFe5c516, 0xFFe7c004, 0xFF6cb292, 0xFF109dfc, 0xFF18a1f7, 0xFF1aa0f5, 0xFF1ca0f3, 0xFF19a0f6, + 0xFF179ff9, 0xFF169ef9, 0xFF169cf9, 0xFF159bf8, 0xFF159af8, 0xFF1499f8, 0xFF1499f7, 0xFF1499f7, + 0xFF58d4f6, 0xFF56d4f6, 0xFF54d5f7, 0xFF57d3f7, 0xFF5bd1f8, 0xFF58d0f6, 0xFF54cff5, 0xFF50cef8, + 0xFF4dcdfa, 0xFF4bcbfb, 0xFF4acafb, 0xFF48c9fb, 0xFF46c7fb, 0xFF45c7fa, 0xFF43c7fa, 0xFF42c6fa, + 0xFF40c6f9, 0xFF3fc4f9, 0xFF3ec3f9, 0xFF3dc1f9, 0xFF3cc0f9, 0xFF3cc1f8, 0xFF3cc2f7, 0xFF38bff6, + 0xFF34bbf5, 0xFF35bdfd, 0xFF37beff, 0xFF46bcfc, 0xFF82c92c, 0xFFa0be02, 0xFFb8c420, 0xFFd8cf31, + 0xFFd2d632, 0xFFd4d52e, 0xFFd7d42a, 0xFFcdd725, 0xFFe9df2f, 0xFFe6dd2a, 0xFFe4dc25, 0xFFedd922, + 0xFFe0e220, 0xFFede927, 0xFFeae01e, 0xFFe4da1c, 0xFFded319, 0xFFe5d01a, 0xFFebcd1b, 0xFFe5c818, + 0xFFdec214, 0xFFf0bc00, 0xFF1da5eb, 0xFF19a1ff, 0xFF16a2f7, 0xFF19a2f4, 0xFF1ea2f1, 0xFF1aa0f5, + 0xFF169ff9, 0xFF169ef8, 0xFF159df8, 0xFF159cf8, 0xFF149bf8, 0xFF139af7, 0xFF1299f6, 0xFF1299f6, + 0xFF5ed5f9, 0xFF63d6fc, 0xFF68d6ff, 0xFF5fd3fc, 0xFF56d0f8, 0xFF53cff8, 0xFF51cef8, 0xFF4ecdf9, + 0xFF4bccfb, 0xFF4acbfb, 0xFF48cafb, 0xFF47c9fa, 0xFF46c8fb, 0xFF44c7fa, 0xFF43c7fa, 0xFF42c6fa, + 0xFF40c5f9, 0xFF3fc4f9, 0xFF3ec3f9, 0xFF3dc1f9, 0xFF3cc0f9, 0xFF3bc1f9, 0xFF3bc1f8, 0xFF38bff7, + 0xFF36bdf7, 0xFF35bdfa, 0xFF34bdfe, 0xFF22c3f6, 0xFF27bbfc, 0xFF53b0b2, 0xFF9bc606, 0xFFc1d322, + 0xFFd3dd36, 0xFFb4ba12, 0xFFc4c71f, 0xFFc5cf22, 0xFFd9d82d, 0xFFdfdb30, 0xFFdcd52b, 0xFFe8d520, + 0xFFd5d51c, 0xFFe8e428, 0xFFece324, 0xFFd1ce1f, 0xFFd3c51d, 0xFFdcc302, 0xFFcfc312, 0xFFe3c209, + 0xFFe3be00, 0xFF84bf6e, 0xFF0ca0f6, 0xFF129ffd, 0xFF18a2f6, 0xFF19a1f5, 0xFF1ba1f4, 0xFF18a0f6, + 0xFF169ff8, 0xFF159ef8, 0xFF159df8, 0xFF149cf7, 0xFF139bf7, 0xFF129af6, 0xFF1098f4, 0xFF1098f4, + 0xFF65d7fb, 0xFF5dd4fa, 0xFF56d2f8, 0xFF53d0f9, 0xFF50cff9, 0xFF4fcef9, 0xFF4dcdfa, 0xFF4bcdfa, + 0xFF4accfb, 0xFF48cbfb, 0xFF47cafb, 0xFF46c9fa, 0xFF45c8fa, 0xFF44c7fa, 0xFF43c7fa, 0xFF42c6fa, + 0xFF40c5fa, 0xFF3fc4f9, 0xFF3ec3f9, 0xFF3dc1f9, 0xFF3bc0f9, 0xFF3ac0f9, 0xFF39c0f9, 0xFF38bff9, + 0xFF37bff9, 0xFF34bef8, 0xFF31bcf7, 0xFF33bbf8, 0xFF35bbfa, 0xFF2cbcff, 0xFF61c2df, 0xFF93cb85, + 0xFFc5d52b, 0xFFcbd82f, 0xFFb0bb13, 0xFFb5be17, 0xFFb9c21b, 0xFFc7c826, 0xFFc5bf21, 0xFFdbc817, + 0xFFcac819, 0xFFdbd722, 0xFFddd61a, 0xFFb7bd0d, 0xFFc8bd04, 0xFFd0c000, 0xFFadc951, 0xFF6cb8b1, + 0xFF04a3ff, 0xFF13a4fb, 0xFF21a4f5, 0xFF1ea3f5, 0xFF1aa1f6, 0xFF19a1f6, 0xFF18a0f7, 0xFF17a0f7, + 0xFF169ff8, 0xFF159ef7, 0xFF149ef7, 0xFF139df7, 0xFF139cf6, 0xFF119af4, 0xFF0f98f2, 0xFF0f98f2, + 0xFF5cd5f9, 0xFF58d3f8, 0xFF53d1f8, 0xFF52d0f9, 0xFF50cff9, 0xFF4ecefa, 0xFF4ccdfa, 0xFF4accfa, + 0xFF48ccfa, 0xFF47cbfa, 0xFF46cafa, 0xFF45c9fa, 0xFF44c8fa, 0xFF43c7fa, 0xFF42c7fa, 0xFF41c6fa, + 0xFF40c5fa, 0xFF3fc4f9, 0xFF3ec2f9, 0xFF3cc1f9, 0xFF3bc0f9, 0xFF3ac0f9, 0xFF38bff9, 0xFF37bff9, + 0xFF36bff9, 0xFF35bdf6, 0xFF34bbf3, 0xFF35b9f7, 0xFF35b8fb, 0xFF22b5ff, 0xFF2fb5ff, 0xFF4dbae6, + 0xFF6bbfce, 0xFF27b1c5, 0xFF6cbc7c, 0xFF8abd49, 0xFFa7be15, 0xFFb9bf09, 0xFFccc000, 0xFFdac43d, + 0xFFbbca20, 0xFFaec73e, 0xFF99bc54, 0xFF5aad8b, 0xFF36abc4, 0xFF04b3ff, 0xFF15a7ff, 0xFF21a4ff, + 0xFF19a0fb, 0xFF1ba2fa, 0xFF1da4f9, 0xFF1ba3f8, 0xFF1aa1f7, 0xFF19a1f7, 0xFF18a0f7, 0xFF17a0f7, + 0xFF169ff8, 0xFF159ef7, 0xFF149ef7, 0xFF139df7, 0xFF129cf6, 0xFF119af5, 0xFF0f99f3, 0xFF0f99f3, + 0xFF53d2f6, 0xFF52d1f7, 0xFF51d1f8, 0xFF50d0f9, 0xFF4fcffa, 0xFF4dcefa, 0xFF4bcdfa, 0xFF49ccfa, + 0xFF47cbfa, 0xFF46caf9, 0xFF45caf9, 0xFF44c9f9, 0xFF44c8fa, 0xFF43c7fa, 0xFF42c6f9, 0xFF41c6f9, + 0xFF40c5fa, 0xFF3fc4f9, 0xFF3dc2f9, 0xFF3cc1f9, 0xFF3ac0f9, 0xFF39c0f9, 0xFF38bff9, 0xFF36bff9, + 0xFF35bef8, 0xFF36bcf4, 0xFF38baf0, 0xFF36b8f6, 0xFF34b5fc, 0xFF2cb6f9, 0xFF23b7f6, 0xFF25b5fa, + 0xFF28b4ff, 0xFF28b6ff, 0xFF29b7ff, 0xFF1fb5ff, 0xFF15b2ff, 0xFF20aef7, 0xFF3cb9ff, 0xFF5acbf0, + 0xFF42befa, 0xFF2ab6fc, 0xFF12adff, 0xFF18acfc, 0xFF1eacfa, 0xFF1ea9fd, 0xFF1ea7ff, 0xFF1ba8fa, + 0xFF18a8f4, 0xFF18a6f8, 0xFF18a4fd, 0xFF19a3fa, 0xFF1aa1f7, 0xFF19a1f7, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf6, 0xFF119af5, 0xFF1099f4, 0xFF1099f4, + 0xFF54d1f8, 0xFF52d1f8, 0xFF51d0f9, 0xFF4fcff9, 0xFF4ecffa, 0xFF4ccefa, 0xFF4acdf9, 0xFF48ccf9, + 0xFF45cbf9, 0xFF45caf9, 0xFF44c9f9, 0xFF43c8f9, 0xFF43c8f9, 0xFF42c7f9, 0xFF42c6f9, 0xFF41c5f9, + 0xFF40c5fa, 0xFF3fc4f9, 0xFF3dc2f9, 0xFF3bc1f9, 0xFF3ac0fa, 0xFF38bff9, 0xFF37bff9, 0xFF36bef9, + 0xFF34bef8, 0xFF35bcf6, 0xFF35baf5, 0xFF34b8f8, 0xFF33b6fc, 0xFF2eb6f9, 0xFF29b6f7, 0xFF29b5f8, + 0xFF2ab4fa, 0xFF2ab5fb, 0xFF2ab5fc, 0xFF2ab2f6, 0xFF2aafef, 0xFF1ba9f6, 0xFF9bcfd9, 0xFF6dcfe9, + 0xFF74c7e4, 0xFF80c9dd, 0xFF19adfb, 0xFF1cacf9, 0xFF1fabf8, 0xFF1fa9f9, 0xFF1ea7fb, 0xFF1ca7f9, + 0xFF1aa7f6, 0xFF1aa5f8, 0xFF1aa4fb, 0xFF1aa3fa, 0xFF1aa2f8, 0xFF19a1f8, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf6, 0xFF119bf5, 0xFF119af5, 0xFF119af5, + 0xFF55d0f9, 0xFF53d0fa, 0xFF51d0fa, 0xFF4fcffa, 0xFF4dcffa, 0xFF4bcefa, 0xFF49cdf9, 0xFF46ccf9, + 0xFF44caf8, 0xFF43caf8, 0xFF43c9f8, 0xFF43c8f9, 0xFF42c8f9, 0xFF42c7f9, 0xFF41c6f9, 0xFF41c6f9, + 0xFF40c5fa, 0xFF3ec3f9, 0xFF3dc2fa, 0xFF3bc1fa, 0xFF39c0fa, 0xFF38bff9, 0xFF36bff9, 0xFF35bef9, + 0xFF34bdf8, 0xFF33bcf9, 0xFF33bafa, 0xFF32b9fb, 0xFF32b8fc, 0xFF30b7fa, 0xFF2eb6f8, 0xFF2db5f7, + 0xFF2bb4f5, 0xFF2bb4f6, 0xFF2bb3f7, 0xFF29b2f9, 0xFF28b2fc, 0xFF30b2f7, 0xFF12a8fe, 0xFF7fd4e1, + 0xFF58bbe6, 0xFF15aafb, 0xFF1fadf8, 0xFF20acf7, 0xFF20aaf5, 0xFF1fa9f6, 0xFF1ea8f7, 0xFF1da6f7, + 0xFF1ca5f8, 0xFF1ca4f8, 0xFF1ba3f9, 0xFF1ba3f9, 0xFF1ba2f9, 0xFF19a1f9, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, + 0xFF55d0f9, 0xFF53d0fa, 0xFF51d0fa, 0xFF4fcffa, 0xFF4dcffa, 0xFF4bcefa, 0xFF49cdf9, 0xFF46ccf9, + 0xFF44caf8, 0xFF43caf8, 0xFF43c9f8, 0xFF43c8f9, 0xFF42c8f9, 0xFF42c7f9, 0xFF41c6f9, 0xFF41c6f9, + 0xFF40c5fa, 0xFF3ec3f9, 0xFF3dc2fa, 0xFF3bc1fa, 0xFF39c0fa, 0xFF38bff9, 0xFF36bff9, 0xFF35bef9, + 0xFF34bdf8, 0xFF33bcf9, 0xFF33bafa, 0xFF32b9fb, 0xFF32b8fc, 0xFF30b7fa, 0xFF2eb6f8, 0xFF2db5f7, + 0xFF2bb4f5, 0xFF2bb4f6, 0xFF2bb3f7, 0xFF2ab2f8, 0xFF29b2fa, 0xFF2db6f5, 0xFF1db5f6, 0xFF239bff, + 0xFF20b6f3, 0xFF0cacfb, 0xFF1eacf7, 0xFF1fabf6, 0xFF20aaf5, 0xFF1fa9f6, 0xFF1ea8f7, 0xFF1da6f7, + 0xFF1ca5f8, 0xFF1ca4f8, 0xFF1ba3f9, 0xFF1ba3f9, 0xFF1ba2f9, 0xFF19a1f9, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, + 0xFF55d0f9, 0xFF53d0fa, 0xFF51d0fa, 0xFF4fcffa, 0xFF4dcffa, 0xFF4bcefa, 0xFF49cdf9, 0xFF46ccf9, + 0xFF44caf8, 0xFF43caf8, 0xFF43c9f8, 0xFF43c8f9, 0xFF42c8f9, 0xFF42c7f9, 0xFF41c6f9, 0xFF41c6f9, + 0xFF40c5fa, 0xFF3ec3f9, 0xFF3dc2fa, 0xFF3bc1fa, 0xFF39c0fa, 0xFF38bff9, 0xFF36bff9, 0xFF35bef9, + 0xFF34bdf8, 0xFF33bcf9, 0xFF33bafa, 0xFF32b9fb, 0xFF32b8fc, 0xFF30b7fa, 0xFF2eb6f8, 0xFF2db5f7, + 0xFF2bb4f5, 0xFF2bb4f6, 0xFF2bb3f7, 0xFF2bb2f8, 0xFF2bb1f8, 0xFF22aff9, 0xFF19acfa, 0xFF1eadf7, + 0xFF24aef3, 0xFF20adf5, 0xFF1dabf6, 0xFF1fabf6, 0xFF20aaf5, 0xFF1fa9f6, 0xFF1ea8f7, 0xFF1da6f7, + 0xFF1ca5f8, 0xFF1ca4f8, 0xFF1ba3f9, 0xFF1ba3f9, 0xFF1ba2f9, 0xFF19a1f9, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, + 0xFF55d0f9, 0xFF53d0fa, 0xFF51d0fa, 0xFF4fcffa, 0xFF4dcffa, 0xFF4bcefa, 0xFF49cdf9, 0xFF46ccf9, + 0xFF44caf8, 0xFF43caf8, 0xFF43c9f8, 0xFF43c8f9, 0xFF42c8f9, 0xFF42c7f9, 0xFF41c6f9, 0xFF41c6f9, + 0xFF40c5fa, 0xFF3ec3f9, 0xFF3dc2fa, 0xFF3bc1fa, 0xFF39c0fa, 0xFF38bff9, 0xFF36bff9, 0xFF35bef9, + 0xFF34bdf8, 0xFF33bcf9, 0xFF33bafa, 0xFF32b9fb, 0xFF32b8fc, 0xFF30b7fa, 0xFF2eb6f8, 0xFF2db5f7, + 0xFF2bb4f5, 0xFF2bb4f6, 0xFF2bb3f7, 0xFF2bb2f8, 0xFF2bb1f8, 0xFF22aff9, 0xFF19acfa, 0xFF1eadf7, + 0xFF24aef3, 0xFF20adf5, 0xFF1dabf6, 0xFF1fabf6, 0xFF20aaf5, 0xFF1fa9f6, 0xFF1ea8f7, 0xFF1da6f7, + 0xFF1ca5f8, 0xFF1ca4f8, 0xFF1ba3f9, 0xFF1ba3f9, 0xFF1ba2f9, 0xFF19a1f9, 0xFF18a0f8, 0xFF17a0f8, + 0xFF169ff8, 0xFF159ef7, 0xFF149df7, 0xFF139cf6, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5, 0xFF129bf5 +}; + +static int test_bmp_cmp_count(const BYTE* mem1, const BYTE* mem2, int size, int channel, int margin) +{ + int error; + int count = 0; + int index = 0; + + size /= 4; + mem1 += channel; + mem2 += channel; + + for (index = 0; index < size; index++) + { + if (*mem1 != *mem2) + { + error = (*mem1 > *mem2) ? *mem1 - *mem2 : *mem2 - *mem1; + + if (error > margin) + count++; + } + + mem1 += 4; + mem2 += 4; + } + + return count; +} + +static int test_bmp_cmp_dump(const BYTE* actual, const BYTE* expected, int size, int channel, int margin) +{ + int x, y; + int error[3]; + UINT32 pixel; + int count = 0; + int index = 0; + BYTE R, G, B; + BYTE eR, eG, eB; + INT16 Y, Cb, Cr; + + size /= 4; + actual += channel; + expected += channel; + + for (index = 0; index < size; index++) + { + if (*actual != *expected) + { + pixel = *((UINT32*) &actual[-channel]); + GetRGB32(R, G, B, pixel); + + pixel = *((UINT32*) &expected[-channel]); + GetRGB32(eR, eG, eB, pixel); + + Y = TEST_Y_COMPONENT[index]; + Cb = TEST_CB_COMPONENT[index]; + Cr = TEST_CR_COMPONENT[index]; + + x = index % 64; + y = (index - x) / 64; + + error[0] = (R > eR) ? R - eR : eR - R; + error[1] = (G > eG) ? G - eG : eG - G; + error[2] = (B > eB) ? B - eB : eB - B; + + if ((error[0] > margin) || (error[1] > margin) || (error[2] > margin)) + { + printf("(%2d,%2d) Y: %+5d Cb: %+5d Cr: %+5d R: %03d/%03d G: %03d/%03d B: %03d/%03d %d %d %d\n", + x, y, Y, Cb, Cr, R, eR, G, eG, B, eB, R - eR, G - eG, B - eB); + count++; + } + } + + actual += 4; + expected += 4; + } + + return count; +} + +static void test_fill_bitmap_channel(BYTE* data, int width, int height, BYTE value, int nChannel) +{ + int x, y; + BYTE* pChannel; + + pChannel = data + nChannel; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + *pChannel = value; + pChannel += 4; + } + } +} + +#define TEST_FP_TYPE float + +static TEST_FP_TYPE TEST_YCbCrToRGB_01[4] = { 1.403f, 0.344f, 0.714f, 1.770f }; +static TEST_FP_TYPE TEST_YCbCrToRGB_02[4] = { 1.402525f, 0.343730f, 0.714401f, 1.769905f }; +static TEST_FP_TYPE TEST_YCbCrToRGB_03[4] = { 1.402524948120117L, 0.3437300026416779L, 0.7144010066986084L, 1.769904971122742L }; + +static INT16 TEST_YCbCr_01[3] = { +3443, -1863, +272 }; +static BYTE TEST_RGB_01[3] = { 247, 249, 132 }; + +static INT16 TEST_YCbCr_02[3] = { +1086, +1584, -2268 }; +static BYTE TEST_RGB_02[3] = { 62, 195, 249 }; + +static INT16 TEST_YCbCr_03[3] = { -576, +2002, -2179 }; +static BYTE TEST_RGB_03[3] = { 15, 137, 221 }; + +int test_YCbCr_fp(TEST_FP_TYPE coeffs[4], INT16 YCbCr[3], BYTE RGB[3]) +{ + INT16 R, G, B; + TEST_FP_TYPE Y, Cb, Cr; + TEST_FP_TYPE fR, fG, fB; + TEST_FP_TYPE fR1, fR2; + + Y = (TEST_FP_TYPE) (YCbCr[0] + 4096); + Cb = (TEST_FP_TYPE) (YCbCr[1]); + Cr = (TEST_FP_TYPE) (YCbCr[2]); + +#if 1 + fR1 = Cr * coeffs[0]; + fR2 = fR1 + Y + 16.0f; + + fR = ((Cr * coeffs[0]) + Y + 16.0f); + fG = (Y - (Cb * coeffs[1]) - (Cr * coeffs[2]) + 16.0f); + fB = ((Cb * coeffs[3]) + Y + 16.0f); + + printf("fR: %f fG: %f fB: %f fY: %f\n", fR, fG, fB, Y); + + R = (INT16) fR; + G = (INT16) fG; + B = (INT16) fB; + + printf("mR: %d mG: %d mB: %d\n", + (R - 16) % 32, (G - 16) % 32, (B - 16) % 32); + + printf("iR: %d iG: %d iB: %d\n", R, G, B); + + R >>= 5; + G >>= 5; + B >>= 5; + + printf("R5: %d G5: %d B5: %d\n", R, G, B); + +#else + R = ((INT16) (((Cr * coeffs[0]) + Y + 16.0f)) >> 5); + G = ((INT16) ((Y - (Cb * coeffs[1]) - (Cr * coeffs[2]) + 16.0f)) >> 5); + B = ((INT16) (((Cb * coeffs[3]) + Y + 16.0f)) >> 5); +#endif + + if (R < 0) + R = 0; + else if (R > 255) + R = 255; + + if (G < 0) + G = 0; + else if (G > 255) + G = 255; + + if (B < 0) + B = 0; + else if (B > 255) + B = 255; + + printf("--------------------------------\n"); + printf("R: A: %3d E: %3d %s\n", R, RGB[0], (R == RGB[0]) ? "" : "***"); + printf("G: A: %3d E: %3d %s\n", G, RGB[1], (G == RGB[1]) ? "" : "***"); + printf("B: A: %3d E: %3d %s\n", B, RGB[2], (B == RGB[2]) ? "" : "***"); + printf("Y: %+5d Cb: %+5d Cr: %+5d\n", YCbCr[0], YCbCr[1], YCbCr[2]); + //printf("[0]: %20.20lf\n", coeffs[0]); + //printf("[1]: %20.20lf\n", coeffs[1]); + //printf("[2]: %20.20lf\n", coeffs[2]); + //printf("[3]: %20.20lf\n", coeffs[3]); + printf("--------------------------------\n\n"); + + return 0; +} + +int test_YCbCr_pixels() +{ + if (0) + { + test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_01, TEST_RGB_01); + test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_02, TEST_RGB_02); + test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_03, TEST_RGB_03); + } + + if (1) + { + test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_01, TEST_RGB_01); + test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_02, TEST_RGB_02); + test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_03, TEST_RGB_03); + } + + if (0) + { + test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_01, TEST_RGB_01); + test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_02, TEST_RGB_02); + test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_03, TEST_RGB_03); + } + + return 0; +} + +int TestPrimitivesYCbCr(int argc, char* argv[]) +{ + int size; + int cnt[3]; + float err[3]; + BYTE* actual; + BYTE* expected; + int margin = 1; + INT16* pYCbCr[3]; + const primitives_t* prims = primitives_get(); + static const prim_size_t roi_64x64 = { 64, 64 }; + + //return test_YCbCr_pixels(); + + expected = (BYTE*) TEST_XRGB_IMAGE; + + size = 64 * 64 * 4; + actual = _aligned_malloc(size, 16); + + if (!actual) + return 1; + + ZeroMemory(actual, size); + + pYCbCr[0] = TEST_Y_COMPONENT; + pYCbCr[1] = TEST_CB_COMPONENT; + pYCbCr[2] = TEST_CR_COMPONENT; + + if (1) + { + prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**) pYCbCr, 64 * 2, + actual, 64 * 4, &roi_64x64); + } + else + { + INT16* pSrcDst[3]; + + pSrcDst[0] = _aligned_malloc(4096 * 2, 16); + pSrcDst[1] = _aligned_malloc(4096 * 2, 16); + pSrcDst[2] = _aligned_malloc(4096 * 2, 16); + + CopyMemory(pSrcDst[0], pYCbCr[0], 4096 * 2); + CopyMemory(pSrcDst[1], pYCbCr[1], 4096 * 2); + CopyMemory(pSrcDst[2], pYCbCr[2], 4096 * 2); + + prims->yCbCrToRGB_16s16s_P3P3((const INT16**) pSrcDst, 64 * 2, + pSrcDst, 64 * 2, &roi_64x64); + + prims->RGBToRGB_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2, + actual, 64 * 4, &roi_64x64); + + _aligned_free(pSrcDst[0]); + _aligned_free(pSrcDst[1]); + _aligned_free(pSrcDst[2]); + } + + if (0) + { + test_fill_bitmap_channel(actual, 64, 64, 0, 2); /* red */ + test_fill_bitmap_channel(expected, 64, 64, 0, 2); /* red */ + } + + if (0) + { + test_fill_bitmap_channel(actual, 64, 64, 0, 1); /* green */ + test_fill_bitmap_channel(expected, 64, 64, 0, 1); /* green */ + } + + if (0) + { + test_fill_bitmap_channel(actual, 64, 64, 0, 0); /* blue */ + test_fill_bitmap_channel(expected, 64, 64, 0, 0); /* blue */ + } + + cnt[2] = test_bmp_cmp_count(actual, expected, size, 2, margin); /* red */ + err[2] = ((float) cnt[2]) / ((float) size / 4) * 100.0f; + + cnt[1] = test_bmp_cmp_count(actual, expected, size, 1, margin); /* green */ + err[1] = ((float) cnt[1]) / ((float) size / 4) * 100.0f; + + cnt[0] = test_bmp_cmp_count(actual, expected, size, 0, margin); /* blue */ + err[0] = ((float) cnt[0]) / ((float) size / 4) * 100.0f; + + if (cnt[0] || cnt[1] || cnt[2]) + { + printf("Red Error Dump:\n"); + test_bmp_cmp_dump(actual, expected, size, 2, margin); /* red */ + + printf("Green Error Dump:\n"); + test_bmp_cmp_dump(actual, expected, size, 1, margin); /* green */ + + printf("Blue Error Dump:\n"); + test_bmp_cmp_dump(actual, expected, size, 0, margin); /* blue */ + + printf("R: diff: %d (%f%%)\n", cnt[2], err[2]); + printf("G: diff: %d (%f%%)\n", cnt[1], err[1]); + printf("B: diff: %d (%f%%)\n", cnt[0], err[0]); + } + + _aligned_free(actual); + + return 0; +} + diff --git a/libfreerdp/primitives/test/TestPrimitivesYCoCg.c b/libfreerdp/primitives/test/TestPrimitivesYCoCg.c new file mode 100644 index 000000000..4c6a4b8e4 --- /dev/null +++ b/libfreerdp/primitives/test/TestPrimitivesYCoCg.c @@ -0,0 +1,130 @@ +/* test_YCoCg.c + * vi:ts=4 sw=4 + * + * (c) Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 "prim_test.h" + +static const int YCOCG_TRIAL_ITERATIONS = 20000; +static const float TEST_TIME = 4.0; + +extern BOOL g_TestPrimitivesPerformance; + +extern pstatus_t general_YCoCgToRGB_8u_AC4R(const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, UINT32 width, UINT32 height, + UINT8 shift, BOOL withAlpha, BOOL invert); +extern pstatus_t ssse3_YCoCgRToRGB_8u_AC4R(const BYTE *pSrc, INT32 srcStep, + BYTE *pDst, INT32 dstStep, UINT32 width, UINT32 height, + UINT8 shift, BOOL withAlpha, BOOL invert); + +/* ------------------------------------------------------------------------- */ +int test_YCoCgRToRGB_8u_AC4R_func(void) +{ + INT32 ALIGN(in[4098]); + INT32 ALIGN(out_c[4098]), ALIGN(out_c_inv[4098]); + INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]); + char testStr[256]; + BOOL failed = FALSE; + int i; + + testStr[0] = '\0'; + get_random_data(in, sizeof(in)); + + general_YCoCgToRGB_8u_AC4R((const BYTE *) (in+1), 63*4, + (BYTE *) out_c, 63*4, 63, 61, 2, TRUE, FALSE); + general_YCoCgToRGB_8u_AC4R((const BYTE *) (in+1), 63*4, + (BYTE *) out_c_inv, 63*4, 63, 61, 2, TRUE, TRUE); +#ifdef WITH_SSE2 + if (IsProcessorFeaturePresentEx(PF_EX_SSSE3)) + { + strcat(testStr, " SSSE3"); + ssse3_YCoCgRToRGB_8u_AC4R((const BYTE *) (in+1), 63*4, + (BYTE *) out_sse, 63*4, 63, 61, 2, TRUE, FALSE); + + for (i=0; i<63*61; ++i) + { + if (out_c[i] != out_sse[i]) { + printf("YCoCgRToRGB-SSE FAIL[%d]: 0x%08x -> C 0x%08x vs SSE 0x%08x\n", i, + in[i+1], out_c[i], out_sse[i]); + failed = TRUE; + } + } + ssse3_YCoCgRToRGB_8u_AC4R((const BYTE *) (in+1), 63*4, + (BYTE *) out_sse_inv, 63*4, 63, 61, 2, TRUE, TRUE); + for (i=0; i<63*61; ++i) + { + if (out_c_inv[i] != out_sse_inv[i]) { + printf("YCoCgRToRGB-SSE inverted FAIL[%d]: 0x%08x -> C 0x%08x vs SSE 0x%08x\n", i, + in[i+1], out_c_inv[i], out_sse_inv[i]); + failed = TRUE; + } + } + } +#endif /* i386 */ + if (!failed) printf("All YCoCgRToRGB_8u_AC4R tests passed (%s).\n", testStr); + return (failed > 0) ? FAILURE : SUCCESS; +} + +/* ------------------------------------------------------------------------- */ +STD_SPEED_TEST( + ycocg_to_rgb_speed, BYTE, BYTE, PRIM_NOP, + TRUE, general_YCoCgToRGB_8u_AC4R(src1, 64*4, dst, 64*4, 64, 64, 2, FALSE, FALSE), +#ifdef WITH_SSE2 + TRUE, ssse3_YCoCgRToRGB_8u_AC4R(src1, 64*4, dst, 64*4, 64, 64, 2, FALSE, FALSE), + PF_EX_SSSE3, TRUE, +#else + FALSE, PRIM_NOP, 0, FALSE, +#endif + FALSE, PRIM_NOP); + +int test_YCoCgRToRGB_8u_AC4R_speed(void) +{ + INT32 ALIGN(in[4096]); + INT32 ALIGN(out[4096]); + int size_array[] = { 64 }; + + get_random_data(in, sizeof(in)); + + ycocg_to_rgb_speed("YCoCgToRGB", "aligned", (const BYTE *) in, + 0, 0, (BYTE *) out, + size_array, 1, YCOCG_TRIAL_ITERATIONS, TEST_TIME); + return SUCCESS; +} + +int TestPrimitivesYCoCg(int argc, char* argv[]) +{ + int status; + + status = test_YCoCgRToRGB_8u_AC4R_func(); + + if (status != SUCCESS) + return 1; + + if (g_TestPrimitivesPerformance) + { + status = test_YCoCgRToRGB_8u_AC4R_speed(); + + if (status != SUCCESS) + return 1; + } + + return 0; +} diff --git a/libfreerdp/primitives/test/measure.h b/libfreerdp/primitives/test/measure.h index ba2909c00..2eb8ae80e 100644 --- a/libfreerdp/primitives/test/measure.h +++ b/libfreerdp/primitives/test/measure.h @@ -22,10 +22,6 @@ * Define GOOGLE_PROFILER if you want gperftools included. */ -#ifdef _GNUC_ -# pragma once -#endif - #ifndef __MEASURE_H_INCLUDED__ #define __MEASURE_H_INCLUDED__ @@ -35,9 +31,21 @@ #include #endif -#include -#include -#include +#include + +#ifdef _WIN32 + +#define PROFILER_START(_prefix_) +#define PROFILER_STOP + +#define MEASURE_LOOP_START(_prefix_, _count_) +#define MEASURE_LOOP_STOP +#define MEASURE_GET_RESULTS(_result_) +#define MEASURE_SHOW_RESULTS(_result_) +#define MEASURE_SHOW_RESULTS_SCALED(_scale_, _label_) +#define MEASURE_TIMED(_label_, _init_iter_, _test_time_, _result_, _call_) + +#else #ifdef GOOGLE_PROFILER #include @@ -122,4 +130,6 @@ extern void _floatprint(float t, char *output); MEASURE_SHOW_RESULTS(_result_); \ } +#endif + #endif // __MEASURE_H_INCLUDED__ diff --git a/libfreerdp/primitives/test/prim_test.c b/libfreerdp/primitives/test/prim_test.c index 52d520970..b9757ac05 100644 --- a/libfreerdp/primitives/test/prim_test.c +++ b/libfreerdp/primitives/test/prim_test.c @@ -18,108 +18,24 @@ #include "prim_test.h" +#ifndef _WIN32 +#include #include #include -#include -#include +#endif + #include +#include #ifdef HAVE_UNISTD_H #include #endif -#include -#include - +BOOL g_TestPrimitivesPerformance = FALSE; int test_sizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 }; -int Quiet = 0; - - /* ------------------------------------------------------------------------- */ -typedef struct -{ - UINT32 flag; - const char *str; -} flagpair_t; - -static const flagpair_t flags[] = -{ -#ifdef _M_IX86_AMD64 - { PF_MMX_INSTRUCTIONS_AVAILABLE, "MMX" }, - { PF_3DNOW_INSTRUCTIONS_AVAILABLE, "3DNow" }, - { PF_SSE_INSTRUCTIONS_AVAILABLE, "SSE" }, - { PF_SSE2_INSTRUCTIONS_AVAILABLE, "SSE2" }, - { PF_SSE3_INSTRUCTIONS_AVAILABLE, "SSE3" }, -#elif defined(_M_ARM) - { PF_ARM_VFP3, "VFP3" }, - { PF_ARM_INTEL_WMMX, "IWMMXT" }, - { PF_ARM_NEON_INSTRUCTIONS_AVAILABLE, "NEON" }, -#endif -}; - -static const flagpair_t flags_extended[] = -{ -#ifdef _M_IX86_AMD64 - { PF_EX_3DNOW_PREFETCH, "3DNow-PF" }, - { PF_EX_SSSE3, "SSSE3" }, - { PF_EX_SSE41, "SSE4.1" }, - { PF_EX_SSE42, "SSE4.2" }, - { PF_EX_AVX, "AVX" }, - { PF_EX_FMA, "FMA" }, - { PF_EX_AVX_AES, "AVX-AES" }, - { PF_EX_AVX2, "AVX2" }, -#elif defined(_M_ARM) - { PF_EX_ARM_VFP1, "VFP1"}, - { PF_EX_ARM_VFP4, "VFP4" }, -#endif -}; - -void primitives_flags_str(char* str, size_t len) -{ - int i; - - *str = '\0'; - --len; /* for the '/0' */ - - for (i = 0; i < sizeof(flags) / sizeof(flagpair_t); ++i) - { - if (IsProcessorFeaturePresent(flags[i].flag)) - { - int slen = strlen(flags[i].str) + 1; - - if (len < slen) - break; - - if (*str != '\0') - strcat(str, " "); - - strcat(str, flags[i].str); - len -= slen; - } - } - for (i = 0; i < sizeof(flags_extended) / sizeof(flagpair_t); ++i) - { - if (IsProcessorFeaturePresentEx(flags_extended[i].flag)) - { - int slen = strlen(flags_extended[i].str) + 1; - - if (len < slen) - break; - - if (*str != '\0') - strcat(str, " "); - - strcat(str, flags_extended[i].str); - len -= slen; - } - } -} - -/* ------------------------------------------------------------------------- */ -static void get_random_data_lrand( - void *buffer, - size_t size) +static void get_random_data_lrand(void *buffer, size_t size) { static int seeded = 0; long int *ptr = (long int *) buffer; @@ -145,11 +61,9 @@ static void get_random_data_lrand( } /* ------------------------------------------------------------------------- */ -void get_random_data( - void *buffer, - size_t size) +void get_random_data(void *buffer, size_t size) { -#ifdef linux +#ifdef __linux__ size_t offset = 0; int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) @@ -171,346 +85,44 @@ void get_random_data( } /* ------------------------------------------------------------------------- */ -float _delta_time( - const struct timespec *t0, - const struct timespec *t1) + +#ifdef _WIN32 +float _delta_time(const struct timespec *t0, const struct timespec *t1) { return 0.0f; } +#else +float _delta_time(const struct timespec *t0, const struct timespec *t1) { - INT64 secs = (INT64) (t1->tv_sec) - (INT64) (t0->tv_sec); - long nsecs = t1->tv_nsec - t0->tv_nsec; + INT64 secs = (INT64) (t1->tv_sec) - (INT64) (t0->tv_sec); + long nsecs = t1->tv_nsec - t0->tv_nsec; double retval; - if (nsecs < 0) + if (nsecs < 0) { - --secs; - nsecs += 1000000000; - } - retval = (double) secs + (double) nsecs / (double) 1000000000.0; - return (retval < 0.0) ? 0.0 : (float) retval; + --secs; + nsecs += 1000000000; + } + + retval = (double) secs + (double) nsecs / (double) 1000000000.0; + return (retval < 0.0) ? 0.0 : (float) retval; } +#endif /* ------------------------------------------------------------------------- */ -void _floatprint( - float t, - char *output) +void _floatprint(float t, char *output) { - /* I don't want to link against -lm, so avoid log,exp,... */ - float f = 10.0; + /* I don't want to link against -lm, so avoid log,exp,... */ + float f = 10.0; int i; - while (t > f) f *= 10.0; - f /= 1000.0; - i = ((int) (t/f+0.5)) * (int) f; - if (t < 0.0) sprintf(output, "%f", t); - else if (i == 0) sprintf(output, "%d", (int) (t+0.5)); - else if (t < 1e+3) sprintf(output, "%3d", i); - else if (t < 1e+6) sprintf(output, "%3d,%03d", - i/1000, i % 1000); - else if (t < 1e+9) sprintf(output, "%3d,%03d,000", - i/1000000, (i % 1000000) / 1000); - else if (t < 1e+12) sprintf(output, "%3d,%03d,000,000", - i/1000000000, (i % 1000000000) / 1000000); - else sprintf(output, "%f", t); -} - -/* ------------------------------------------------------------------------- */ -/* Specific areas to test: */ -#define TEST_COPY8 (1<<0) -#define TEST_SET8 (1<<1) -#define TEST_SET32S (1<<2) -#define TEST_SET32U (1<<3) -#define TEST_SIGN16S (1<<4) -#define TEST_ADD16S (1<<5) -#define TEST_LSHIFT16S (1<<6) -#define TEST_LSHIFT16U (1<<7) -#define TEST_RSHIFT16S (1<<8) -#define TEST_RSHIFT16U (1<<9) -#define TEST_RGB (1<<10) -#define TEST_ALPHA (1<<11) -#define TEST_AND (1<<12) -#define TEST_OR (1<<13) - -/* Specific types of testing: */ -#define TEST_FUNCTIONALITY (1<<0) -#define TEST_PERFORMANCE (1<<1) - -/* ------------------------------------------------------------------------- */ - -typedef struct -{ - const char *testStr; - UINT32 bits; -} test_t; - -static const test_t testList[] = -{ - { "all", 0xFFFFFFFFU }, - { "copy", TEST_COPY8 }, - { "copy8", TEST_COPY8 }, - { "set", TEST_SET8|TEST_SET32S|TEST_SET32U }, - { "set8", TEST_SET8 }, - { "set32", TEST_SET32S|TEST_SET32U }, - { "set32s", TEST_SET32S }, - { "set32u", TEST_SET32U }, - { "sign", TEST_SIGN16S }, - { "sign16s", TEST_SIGN16S }, - { "add", TEST_ADD16S }, - { "add16s", TEST_ADD16S }, - { "lshift", TEST_LSHIFT16S|TEST_LSHIFT16U }, - { "rshift", TEST_RSHIFT16S|TEST_RSHIFT16U }, - { "shift", TEST_LSHIFT16S|TEST_LSHIFT16U|TEST_RSHIFT16S|TEST_RSHIFT16U }, - { "lshift16s", TEST_LSHIFT16S }, - { "lshift16u", TEST_LSHIFT16U }, - { "rshift16s", TEST_RSHIFT16S }, - { "rshift16u", TEST_RSHIFT16U }, - { "rgb", TEST_RGB }, - { "color", TEST_RGB }, - { "colors", TEST_RGB }, - { "alpha", TEST_ALPHA }, - { "and", TEST_AND }, - { "or", TEST_OR } -}; - -#define NUMTESTS (sizeof(testList)/sizeof(test_t)) - -static const test_t testTypeList[] = -{ - { "functionality", TEST_FUNCTIONALITY }, - { "performance", TEST_PERFORMANCE }, -}; - -#define NUMTESTTYPES (sizeof(testTypeList)/sizeof(test_t)) - -int main(int argc, char** argv) -{ - int i; - char hints[1024]; - UINT32 testSet = 0; - UINT32 testTypes = 0; - int results = SUCCESS; - - /* Parse command line for the test set. */ - - for (i = 1; i < argc; ++i) - { - int j; - BOOL found = 0; - - for (j=0; j f) f *= 10.0; + f /= 1000.0; + i = ((int) (t/f+0.5)) * (int) f; + if (t < 0.0) sprintf(output, "%f", t); + else if (i == 0) sprintf(output, "%d", (int) (t+0.5)); + else if (t < 1e+3) sprintf(output, "%3d", i); + else if (t < 1e+6) sprintf(output, "%3d,%03d", + i/1000, i % 1000); + else if (t < 1e+9) sprintf(output, "%3d,%03d,000", + i/1000000, (i % 1000000) / 1000); + else if (t < 1e+12) sprintf(output, "%3d,%03d,000,000", + i/1000000000, (i % 1000000000) / 1000000); + else sprintf(output, "%f", t); } diff --git a/libfreerdp/primitives/test/prim_test.h b/libfreerdp/primitives/test/prim_test.h index f32f46889..e535b4710 100644 --- a/libfreerdp/primitives/test/prim_test.h +++ b/libfreerdp/primitives/test/prim_test.h @@ -13,38 +13,29 @@ * this code may be covered by patents by HP, Microsoft, or other parties. */ -#ifdef __GNUC__ -# pragma once -#endif - #ifndef __PRIMTEST_H_INCLUDED__ #define __PRIMTEST_H_INCLUDED__ -#include -#include +#include +#include #include - -#include -#include -#include +#include #include -#include + +#include "measure.h" #ifdef WITH_IPP #include #include #endif -#define BLOCK_ALIGNMENT 16 -#ifdef __GNUC__ -#define ALIGN(x) x __attribute((aligned(BLOCK_ALIGNMENT))) -#define POSSIBLY_UNUSED(x) x __attribute((unused)) -#else -/* TODO: Someone needs to finish this for non-GNU C */ +#ifdef _WIN32 #define ALIGN(x) x -#define POSSIBLY_UNUSED(x) x +#else +#define ALIGN(x) x DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) #endif + #define ABS(_x_) ((_x_) < 0 ? (-(_x_)) : (_x_)) #define MAX_TEST_SIZE 4096 @@ -89,6 +80,11 @@ extern int test_RGBToRGB_16s8u_P3AC4R_func(void); extern int test_RGBToRGB_16s8u_P3AC4R_speed(void); extern int test_yCbCrToRGB_16s16s_P3P3_func(void); extern int test_yCbCrToRGB_16s16s_P3P3_speed(void); +extern int test_YCoCgRToRGB_8u_AC4R_func(void); +extern int test_YCoCgRToRGB_8u_AC4R_speed(void); + +extern int test_RGB565ToARGB_16u32u_C3C4_func(void); +extern int test_RGB565ToARGB_16u32u_C3C4_speed(void); extern int test_alphaComp_func(void); extern int test_alphaComp_speed(void); @@ -162,6 +158,14 @@ extern int test_or_32u_speed(void); #define PRIM_NOP do {} while (0) /* ------------------------------------------------------------------------- */ + +#ifdef _WIN32 +#define STD_SPEED_TEST( \ + _name_, _srctype_, _dsttype_, _prework_, \ + _doNormal_, _funcNormal_, \ + _doOpt_, _funcOpt_, _flagOpt_, _flagExt_, \ + _doIPP_, _funcIPP_) +#else #define STD_SPEED_TEST( \ _name_, _srctype_, _dsttype_, _prework_, \ _doNormal_, _funcNormal_, \ @@ -232,5 +236,6 @@ static void _name_( \ } \ free(resultNormal); free(resultOpt); free(resultIPP); \ } +#endif #endif // !__PRIMTEST_H_INCLUDED__ diff --git a/libfreerdp/rail/CMakeLists.txt b/libfreerdp/rail/CMakeLists.txt index fe0f5741d..c84d74ba9 100644 --- a/libfreerdp/rail/CMakeLists.txt +++ b/libfreerdp/rail/CMakeLists.txt @@ -18,30 +18,9 @@ set(MODULE_NAME "freerdp-rail") set(MODULE_PREFIX "FREERDP_RAIL") -set(${MODULE_PREFIX}_SRCS +freerdp_module_add( window_list.c window.c icon.c rail.c librail.h) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-utils) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") diff --git a/libfreerdp/rail/icon.c b/libfreerdp/rail/icon.c index 4f7365413..73d09a3ba 100644 --- a/libfreerdp/rail/icon.c +++ b/libfreerdp/rail/icon.c @@ -26,21 +26,24 @@ #include +#include #include +#define TAG FREERDP_TAG("rail") + ICON_INFO* icon_cache_get(rdpIconCache* cache, BYTE id, UINT16 index, void** extra) { ICON_INFO* entry; if (id >= cache->numCaches) { - fprintf(stderr, "invalid window icon cache id:%d\n", id); + WLog_ERR(TAG, "invalid window icon cache id:%d", id); return (ICON_INFO*) NULL; } if (index >= cache->numCacheEntries) { - fprintf(stderr, "invalid window icon cache index:%d in cache id:%d\n", index, id); + WLog_ERR(TAG, "invalid window icon cache index:%d in cache id:%d", index, id); return (ICON_INFO*) NULL; } @@ -56,13 +59,13 @@ void icon_cache_put(rdpIconCache* cache, BYTE id, UINT16 index, ICON_INFO* entry { if (id >= cache->numCaches) { - fprintf(stderr, "invalid window icon cache id:%d\n", id); + WLog_ERR(TAG, "invalid window icon cache id:%d", id); return; } if (index >= cache->numCacheEntries) { - fprintf(stderr, "invalid window icon cache index:%d in cache id:%d\n", index, id); + WLog_ERR(TAG, "invalid window icon cache index:%d in cache id:%d", index, id); return; } diff --git a/libfreerdp/rail/librail.h b/libfreerdp/rail/librail.h index f4795caa0..b762e4816 100644 --- a/libfreerdp/rail/librail.h +++ b/libfreerdp/rail/librail.h @@ -24,12 +24,13 @@ #include "config.h" #endif -#include +#include +#define RAIL_TAG FREERDP_TAG("rail") #ifdef WITH_DEBUG_RAIL -#define DEBUG_RAIL(fmt, ...) DEBUG_CLASS(RAIL, fmt, ## __VA_ARGS__) +#define DEBUG_RAIL(fmt, ...) WLog_DBG(RAIL_TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_RAIL(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_RAIL(fmt, ...) do { } while (0) #endif #endif /* __LIBRAIL_H */ diff --git a/libfreerdp/rail/window.c b/libfreerdp/rail/window.c index 9dd3d3c72..b020c3c94 100644 --- a/libfreerdp/rail/window.c +++ b/libfreerdp/rail/window.c @@ -30,6 +30,9 @@ #include "librail.h" #include +#include + +#define TAG FREERDP_TAG("rail") struct _WINDOW_STYLE { @@ -99,8 +102,8 @@ static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = void print_window_styles(UINT32 style) { int i; + WLog_INFO(TAG, "Window Styles:{"); - fprintf(stderr, "Window Styles:\n{\n"); for (i = 0; i < ARRAYSIZE(WINDOW_STYLES); i++) { if (style & WINDOW_STYLES[i].style) @@ -108,20 +111,21 @@ void print_window_styles(UINT32 style) if (WINDOW_STYLES[i].multi) { if ((style & WINDOW_STYLES[i].style) != WINDOW_STYLES[i].style) - continue; + continue; } - fprintf(stderr, "\t%s\n", WINDOW_STYLES[i].name); + WLog_INFO(TAG, "\t%s", WINDOW_STYLES[i].name); } } - fprintf(stderr, "}\n"); + + WLog_INFO(TAG, "}"); } void print_extended_window_styles(UINT32 style) { int i; + WLog_INFO(TAG, "Extended Window Styles:{"); - fprintf(stderr, "Extended Window Styles:\n{\n"); for (i = 0; i < ARRAYSIZE(EXTENDED_WINDOW_STYLES); i++) { if (style & EXTENDED_WINDOW_STYLES[i].style) @@ -129,13 +133,14 @@ void print_extended_window_styles(UINT32 style) if (EXTENDED_WINDOW_STYLES[i].multi) { if ((style & EXTENDED_WINDOW_STYLES[i].style) != EXTENDED_WINDOW_STYLES[i].style) - continue; + continue; } - fprintf(stderr, "\t%s\n", EXTENDED_WINDOW_STYLES[i].name); + WLog_INFO(TAG, "\t%s", EXTENDED_WINDOW_STYLES[i].name); } } - fprintf(stderr, "}\n"); + + WLog_INFO(TAG, "}"); } void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* window_state) @@ -149,13 +154,12 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW } DEBUG_RAIL("windowId=0x%X ownerWindowId=0x%X", - window->windowId, window->ownerWindowId); + window->windowId, window->ownerWindowId); if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE) { window->style = window_state->style; window->extendedStyle = window_state->extendedStyle; - #ifdef WITH_DEBUG_RAIL print_window_styles(window->style); print_extended_window_styles(window->extendedStyle); @@ -173,9 +177,8 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW window->titleInfo.length = window_state->titleInfo.length; window->titleInfo.string = malloc(window_state->titleInfo.length); memcpy(window->titleInfo.string, window_state->titleInfo.string, window->titleInfo.length); - #ifdef WITH_DEBUG_RAIL - winpr_HexDump(window->titleInfo.string, window->titleInfo.length); + winpr_HexDump(TAG, WLOG_DEBUG, window->titleInfo.string, window->titleInfo.length); #endif } @@ -183,18 +186,16 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW { window->clientOffsetX = window_state->clientOffsetX; window->clientOffsetY = window_state->clientOffsetY; - DEBUG_RAIL("Client Area Offset: (%d, %d)", - window->clientOffsetX, window->clientOffsetY); + window->clientOffsetX, window->clientOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) { window->clientAreaWidth = window_state->clientAreaWidth; window->clientAreaHeight = window_state->clientAreaHeight; - DEBUG_RAIL("Client Area Size: (%d, %d)", - window->clientAreaWidth, window->clientAreaHeight); + window->clientAreaWidth, window->clientAreaHeight); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) @@ -211,27 +212,24 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW { window->windowOffsetX = window_state->windowOffsetX; window->windowOffsetY = window_state->windowOffsetY; - DEBUG_RAIL("Window Offset: (%d, %d)", - window->windowOffsetX, window->windowOffsetY); + window->windowOffsetX, window->windowOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) { window->windowClientDeltaX = window_state->windowClientDeltaX; window->windowClientDeltaY = window_state->windowClientDeltaY; - DEBUG_RAIL("Window Client Delta: (%d, %d)", - window->windowClientDeltaX, window->windowClientDeltaY); + window->windowClientDeltaX, window->windowClientDeltaY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) { window->windowWidth = window_state->windowWidth; window->windowHeight = window_state->windowHeight; - DEBUG_RAIL("Window Size: (%d, %d)", - window->windowWidth, window->windowHeight); + window->windowWidth, window->windowHeight); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) @@ -247,8 +245,8 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW for (i = 0; i < (int) window_state->numWindowRects; i++) { DEBUG_RAIL("Window Rect #%d: left:%d top:%d right:%d bottom:%d", i, - window_state->windowRects[i].left, window_state->windowRects[i].top, - window_state->windowRects[i].right, window_state->windowRects[i].bottom); + window_state->windowRects[i].left, window_state->windowRects[i].top, + window_state->windowRects[i].right, window_state->windowRects[i].bottom); } } @@ -256,9 +254,8 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW { window->visibleOffsetX = window_state->visibleOffsetX; window->visibleOffsetY = window_state->visibleOffsetY; - DEBUG_RAIL("Window Visible Offset: (%d, %d)", - window->visibleOffsetX, window->visibleOffsetY); + window->visibleOffsetX, window->visibleOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) @@ -274,8 +271,8 @@ void window_state_update(rdpWindow* window, WINDOW_ORDER_INFO* orderInfo, WINDOW for (i = 0; i < (int) window_state->numVisibilityRects; i++) { DEBUG_RAIL("Visibility Rect #%d: left:%d top:%d right:%d bottom:%d", i, - window_state->visibilityRects[i].left, window_state->visibilityRects[i].top, - window_state->visibilityRects[i].right, window_state->visibilityRects[i].bottom); + window_state->visibilityRects[i].left, window_state->visibilityRects[i].top, + window_state->visibilityRects[i].right, window_state->visibilityRects[i].bottom); } } } @@ -285,7 +282,7 @@ void rail_CreateWindow(rdpRail* rail, rdpWindow* window) if (window->titleInfo.length > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) window->titleInfo.string, window->titleInfo.length / 2, - &window->title, 0, NULL, NULL); + &window->title, 0, NULL, NULL); } else { @@ -299,6 +296,7 @@ void rail_CreateWindow(rdpRail* rail, rdpWindow* window) { IFCALL(rail->rail_SetWindowRects, rail, window); } + if (window->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) { IFCALL(rail->rail_SetWindowVisibilityRects, rail, window); @@ -309,12 +307,10 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) { if (window->fieldFlags & WINDOW_ORDER_FIELD_OWNER) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_STYLE) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_SHOW) @@ -331,29 +327,24 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) } ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) window->titleInfo.string, window->titleInfo.length / 2, - &window->title, 0, NULL, NULL); - + &window->title, 0, NULL, NULL); IFCALL(rail->rail_SetWindowText, rail, window); } if (window->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) { - } if ((window->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || @@ -364,7 +355,6 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) if (window->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) @@ -374,7 +364,6 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) if (window->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) { - } if (window->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt index 6e5858672..6c0ac2c62 100644 --- a/libfreerdp/utils/CMakeLists.txt +++ b/libfreerdp/utils/CMakeLists.txt @@ -20,7 +20,6 @@ set(MODULE_PREFIX "FREERDP_UTILS") set(${MODULE_PREFIX}_SRCS event.c - bitmap.c passphrase.c pcap.c profiler.c @@ -37,41 +36,18 @@ if(NOT WIN32) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} msusb.c) endif() -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) +freerdp_module_add(${${MODULE_PREFIX}_SRCS}) -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS}) +freerdp_library_add(${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) + freerdp_library_add(ws2_32) endif() if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + freerdp_library_add(rt) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-thread winpr-utils winpr-path) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDPTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") - - if(BUILD_TESTING) add_subdirectory(test) endif() - diff --git a/libfreerdp/utils/bitmap.c b/libfreerdp/utils/bitmap.c deleted file mode 100644 index bc49d6d00..000000000 --- a/libfreerdp/utils/bitmap.c +++ /dev/null @@ -1,109 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Bitmap File Format Utils - * - * Copyright 2011 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 - -typedef struct -{ - BYTE magic[2]; -} BITMAP_MAGIC; - -typedef struct -{ - UINT32 filesz; - UINT16 creator1; - UINT16 creator2; - UINT32 bmp_offset; -} BITMAP_CORE_HEADER; - -typedef struct -{ - UINT32 header_sz; - INT32 width; - INT32 height; - UINT16 nplanes; - UINT16 bitspp; - UINT32 compress_type; - UINT32 bmp_bytesz; - INT32 hres; - INT32 vres; - UINT32 ncolors; - UINT32 nimpcolors; -} BITMAP_INFO_HEADER; - -void freerdp_bitmap_write(char* filename, void* data, int width, int height, int bpp) -{ - FILE* fp; - BITMAP_MAGIC magic; - BITMAP_CORE_HEADER header; - BITMAP_INFO_HEADER info_header; - - fp = fopen(filename, "w+b"); - - if (fp == NULL) - { - fprintf(stderr, "failed to open file %s\n", filename); - return; - } - - magic.magic[0] = 'B'; - magic.magic[1] = 'M'; - - header.creator1 = 0; - header.creator2 = 0; - - header.bmp_offset = - sizeof(BITMAP_MAGIC) + - sizeof(BITMAP_CORE_HEADER) + - sizeof(BITMAP_INFO_HEADER); - - info_header.bmp_bytesz = width * height * (bpp / 8); - - header.filesz = - header.bmp_offset + - info_header.bmp_bytesz; - - info_header.width = width; - info_header.height = (-1) * height; - info_header.nplanes = 1; - info_header.bitspp = bpp; - info_header.compress_type = 0; - info_header.hres = width; - info_header.vres = height; - info_header.ncolors = 0; - info_header.nimpcolors = 0; - info_header.header_sz = sizeof(BITMAP_INFO_HEADER); - - fwrite((void*) &magic, sizeof(BITMAP_MAGIC), 1, fp); - fwrite((void*) &header, sizeof(BITMAP_CORE_HEADER), 1, fp); - fwrite((void*) &info_header, sizeof(BITMAP_INFO_HEADER), 1, fp); - fwrite((void*) data, info_header.bmp_bytesz, 1, fp); - - fclose(fp); -} - diff --git a/libfreerdp/utils/msusb.c b/libfreerdp/utils/msusb.c index 3bf5957ba..4d75d74c4 100644 --- a/libfreerdp/utils/msusb.c +++ b/libfreerdp/utils/msusb.c @@ -22,13 +22,15 @@ #include #include -#include +#include #include +#define TAG FREERDP_TAG("utils") + #ifdef WITH_DEBUG_MSUSB -#define DEBUG_MSUSB(fmt, ...) DEBUG_CLASS(MSUSB, fmt, ## __VA_ARGS__) +#define DEBUG_MSUSB(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) #else -#define DEBUG_MSUSB(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#define DEBUG_MSUSB(fmt, ...) do { } while (0) #endif @@ -321,42 +323,41 @@ void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfig) MSUSB_PIPE_DESCRIPTOR ** MsPipes; MSUSB_PIPE_DESCRIPTOR * MsPipe; int inum = 0, pnum = 0; - - fprintf(stderr, "=================MsConfig:========================\n"); - fprintf(stderr, "wTotalLength:%d\n", MsConfig->wTotalLength); - fprintf(stderr, "bConfigurationValue:%d\n", MsConfig->bConfigurationValue); - fprintf(stderr, "ConfigurationHandle:0x%x\n", MsConfig->ConfigurationHandle); - fprintf(stderr, "InitCompleted:%d\n", MsConfig->InitCompleted); - fprintf(stderr, "MsOutSize:%d\n", MsConfig->MsOutSize); - fprintf(stderr, "NumInterfaces:%d\n\n", MsConfig->NumInterfaces); + WLog_INFO(TAG, "=================MsConfig:========================"); + WLog_INFO(TAG, "wTotalLength:%d", MsConfig->wTotalLength); + WLog_INFO(TAG, "bConfigurationValue:%d", MsConfig->bConfigurationValue); + WLog_INFO(TAG, "ConfigurationHandle:0x%x", MsConfig->ConfigurationHandle); + WLog_INFO(TAG, "InitCompleted:%d", MsConfig->InitCompleted); + WLog_INFO(TAG, "MsOutSize:%d", MsConfig->MsOutSize); + WLog_INFO(TAG, "NumInterfaces:%d", MsConfig->NumInterfaces); MsInterfaces = MsConfig->MsInterfaces; for(inum = 0; inum < MsConfig->NumInterfaces; inum++) { MsInterface = MsInterfaces[inum]; - fprintf(stderr, " Interfase: %d\n", MsInterface->InterfaceNumber); - fprintf(stderr, " Length: %d\n", MsInterface->Length); - fprintf(stderr, " NumberOfPipesExpected: %d\n", MsInterface->NumberOfPipesExpected); - fprintf(stderr, " AlternateSetting: %d\n", MsInterface->AlternateSetting); - fprintf(stderr, " NumberOfPipes: %d\n", MsInterface->NumberOfPipes); - fprintf(stderr, " InterfaceHandle: 0x%x\n", MsInterface->InterfaceHandle); - fprintf(stderr, " bInterfaceClass: 0x%x\n", MsInterface->bInterfaceClass); - fprintf(stderr, " bInterfaceSubClass: 0x%x\n", MsInterface->bInterfaceSubClass); - fprintf(stderr, " bInterfaceProtocol: 0x%x\n", MsInterface->bInterfaceProtocol); - fprintf(stderr, " InitCompleted: %d\n\n", MsInterface->InitCompleted); + WLog_INFO(TAG, " Interfase: %d", MsInterface->InterfaceNumber); + WLog_INFO(TAG, " Length: %d", MsInterface->Length); + WLog_INFO(TAG, " NumberOfPipesExpected: %d", MsInterface->NumberOfPipesExpected); + WLog_INFO(TAG, " AlternateSetting: %d", MsInterface->AlternateSetting); + WLog_INFO(TAG, " NumberOfPipes: %d", MsInterface->NumberOfPipes); + WLog_INFO(TAG, " InterfaceHandle: 0x%x", MsInterface->InterfaceHandle); + WLog_INFO(TAG, " bInterfaceClass: 0x%x", MsInterface->bInterfaceClass); + WLog_INFO(TAG, " bInterfaceSubClass: 0x%x", MsInterface->bInterfaceSubClass); + WLog_INFO(TAG, " bInterfaceProtocol: 0x%x", MsInterface->bInterfaceProtocol); + WLog_INFO(TAG, " InitCompleted: %d", MsInterface->InitCompleted); MsPipes = MsInterface->MsPipes; for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) { MsPipe = MsPipes[pnum]; - fprintf(stderr, " Pipe: %d\n", pnum); - fprintf(stderr, " MaximumPacketSize: 0x%x\n", MsPipe->MaximumPacketSize); - fprintf(stderr, " MaximumTransferSize: 0x%x\n", MsPipe->MaximumTransferSize); - fprintf(stderr, " PipeFlags: 0x%x\n", MsPipe->PipeFlags); - fprintf(stderr, " PipeHandle: 0x%x\n", MsPipe->PipeHandle); - fprintf(stderr, " bEndpointAddress: 0x%x\n", MsPipe->bEndpointAddress); - fprintf(stderr, " bInterval: %d\n", MsPipe->bInterval); - fprintf(stderr, " PipeType: 0x%x\n", MsPipe->PipeType); - fprintf(stderr, " InitCompleted: %d\n\n", MsPipe->InitCompleted); + WLog_INFO(TAG, " Pipe: %d", pnum); + WLog_INFO(TAG, " MaximumPacketSize: 0x%x", MsPipe->MaximumPacketSize); + WLog_INFO(TAG, " MaximumTransferSize: 0x%x", MsPipe->MaximumTransferSize); + WLog_INFO(TAG, " PipeFlags: 0x%x", MsPipe->PipeFlags); + WLog_INFO(TAG, " PipeHandle: 0x%x", MsPipe->PipeHandle); + WLog_INFO(TAG, " bEndpointAddress: 0x%x", MsPipe->bEndpointAddress); + WLog_INFO(TAG, " bInterval: %d", MsPipe->bInterval); + WLog_INFO(TAG, " PipeType: 0x%x", MsPipe->PipeType); + WLog_INFO(TAG, " InitCompleted: %d", MsPipe->InitCompleted); } } - fprintf(stderr, "==================================================\n"); + WLog_INFO(TAG, "=================================================="); } diff --git a/libfreerdp/utils/pcap.c b/libfreerdp/utils/pcap.c index 5e174a847..21e906e6c 100644 --- a/libfreerdp/utils/pcap.c +++ b/libfreerdp/utils/pcap.c @@ -26,6 +26,9 @@ #include #include +#include + +#define TAG FREERDP_TAG("utils") #ifndef _WIN32 #include @@ -162,7 +165,7 @@ rdpPcap* pcap_open(char* name, BOOL write) if (pcap_fp == NULL) { - perror("opening pcap dump"); + WLog_ERR(TAG, "opening pcap dump"); return NULL; } diff --git a/libfreerdp/utils/profiler.c b/libfreerdp/utils/profiler.c index d735dba77..11737a210 100644 --- a/libfreerdp/utils/profiler.c +++ b/libfreerdp/utils/profiler.c @@ -25,6 +25,9 @@ #include #include +#include + +#define TAG FREERDP_TAG("utils") PROFILER* profiler_create(char* name) { @@ -57,24 +60,22 @@ void profiler_exit(PROFILER* profiler) void profiler_print_header() { - fprintf(stderr, "\n"); - fprintf(stderr, " |-----------------------|\n" ); - fprintf(stderr, " PROFILER | elapsed seconds |\n" ); - fprintf(stderr, "|--------------------------------------------|-----------------------|\n" ); - fprintf(stderr, "| code section | iterations | total | avg. |\n" ); - fprintf(stderr, "|-------------------------------|------------|-----------|-----------|\n" ); + WLog_INFO(TAG, " |-----------------------|"); + WLog_INFO(TAG, " PROFILER | elapsed seconds |"); + WLog_INFO(TAG, "|--------------------------------------------|-----------------------|"); + WLog_INFO(TAG, "| code section | iterations | total | avg. |"); + WLog_INFO(TAG, "|-------------------------------|------------|-----------|-----------|"); } void profiler_print(PROFILER* profiler) { double elapsed_sec = stopwatch_get_elapsed_time_in_seconds(profiler->stopwatch); double avg_sec = elapsed_sec / (double) profiler->stopwatch->count; - - fprintf(stderr, "| %-30.30s| %10du | %9f | %9f |\n", - profiler->name, profiler->stopwatch->count, elapsed_sec, avg_sec); + WLog_INFO(TAG, "| %-30.30s| %10du | %9f | %9f |", + profiler->name, profiler->stopwatch->count, elapsed_sec, avg_sec); } void profiler_print_footer() { - fprintf(stderr, "|--------------------------------------------------------------------|\n" ); + WLog_INFO(TAG, "|--------------------------------------------------------------------|"); } diff --git a/libfreerdp/utils/rail.c b/libfreerdp/utils/rail.c index ebfb8e7a1..19029f43b 100644 --- a/libfreerdp/utils/rail.c +++ b/libfreerdp/utils/rail.c @@ -143,7 +143,7 @@ void* rail_clone_order(UINT32 event_type, void* order) new_order = malloc(order_size); CopyMemory(new_order, order, order_size); - //fprintf(stderr, "rail_clone_order: type=%d order=%p\n", event_type, new_order); + //WLog_ERR(TAG, "rail_clone_order: type=%d order=%p\n", event_type, new_order); // Create copy of variable data for some orders if ((event_type == RailChannel_GetSystemParam) || @@ -183,7 +183,7 @@ void* rail_clone_order(UINT32 event_type, void* order) void rail_free_cloned_order(UINT32 event_type, void* order) { - //fprintf(stderr, "rail_free_cloned_order: type=%d order=%p\n", event_type, order); + //WLog_ERR(TAG, "rail_free_cloned_order: type=%d order=%p\n", event_type, order); if ((event_type == RailChannel_GetSystemParam) || (event_type == RailChannel_ClientSystemParam)) { diff --git a/libfreerdp/utils/signal.c b/libfreerdp/utils/signal.c index 1fd62a28e..978aac6dd 100644 --- a/libfreerdp/utils/signal.c +++ b/libfreerdp/utils/signal.c @@ -26,6 +26,9 @@ #include #include +#include + +#define TAG FREERDP_TAG("utils") #ifdef _WIN32 @@ -48,8 +51,7 @@ static void fatal_handler(int signum) { struct sigaction default_sigaction; sigset_t this_mask; - - printf("fatal_handler: signum=%d\n", signum); + WLog_DBG(TAG, "fatal_handler: signum=%d", signum); if (terminal_needs_reset) tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags); diff --git a/libfreerdp/utils/svc_plugin.c b/libfreerdp/utils/svc_plugin.c index 7a529d256..50e418529 100644 --- a/libfreerdp/utils/svc_plugin.c +++ b/libfreerdp/utils/svc_plugin.c @@ -33,10 +33,12 @@ #include #include -#include +#include #include #include +#define TAG FREERDP_TAG("utils") + static wListDictionary* g_InitHandles; static wListDictionary* g_OpenHandles; @@ -106,7 +108,6 @@ static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, UINT3 Stream_Release(plugin->data_in); plugin->data_in = StreamPool_Take(plugin->pool, totalLength); - Stream_AddRef(plugin->data_in); } s = plugin->data_in; @@ -115,11 +116,6 @@ static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, UINT3 if (dataFlags & CHANNEL_FLAG_LAST) { - if (Stream_Capacity(s) != Stream_GetPosition(s)) - { - fprintf(stderr, "svc_plugin_process_received: read error\n"); - } - plugin->data_in = NULL; Stream_SealLength(s); Stream_SetPosition(s, 0); @@ -145,7 +141,7 @@ static VOID VCAPITYPE svc_plugin_open_event(DWORD openHandle, UINT event, LPVOID if (!plugin) { - fprintf(stderr, "svc_plugin_open_event: error no match\n"); + WLog_ERR(TAG, "svc_plugin_open_event: error no match"); return; } @@ -220,7 +216,7 @@ static void svc_plugin_process_connected(rdpSvcPlugin* plugin, LPVOID pData, UIN if (status != CHANNEL_RC_OK) { - fprintf(stderr, "svc_plugin_process_connected: open failed: status: %d\n", status); + WLog_ERR(TAG, "svc_plugin_process_connected: open failed: status: %d", status); return; } @@ -250,7 +246,7 @@ static void svc_plugin_process_terminated(rdpSvcPlugin* plugin) if (plugin->data_in) { - Stream_Free(plugin->data_in, TRUE); + Stream_Release(plugin->data_in); plugin->data_in = NULL; } @@ -270,7 +266,7 @@ static VOID VCAPITYPE svc_plugin_init_event(LPVOID pInitHandle, UINT event, LPVO if (!plugin) { - fprintf(stderr, "svc_plugin_init_event: error no match\n"); + WLog_ERR(TAG, "svc_plugin_init_event: error no match"); return; } @@ -339,7 +335,7 @@ int svc_plugin_send(rdpSvcPlugin* plugin, wStream* data_out) if (status != CHANNEL_RC_OK) { Stream_Free(data_out, TRUE); - fprintf(stderr, "svc_plugin_send: VirtualChannelWrite failed %d\n", status); + WLog_ERR(TAG, "svc_plugin_send: VirtualChannelWrite failed %d", status); } return status; @@ -355,7 +351,7 @@ int svc_plugin_send_event(rdpSvcPlugin* plugin, wMessage* event) status = plugin->channel_entry_points.pVirtualChannelEventPush(plugin->OpenHandle, event); if (status != CHANNEL_RC_OK) - fprintf(stderr, "svc_plugin_send_event: VirtualChannelEventPush failed %d\n", status); + WLog_ERR(TAG, "svc_plugin_send_event: VirtualChannelEventPush failed %d", status); return status; } diff --git a/libfreerdp/utils/tcp.c b/libfreerdp/utils/tcp.c index 45293dbf3..a64c49cd6 100644 --- a/libfreerdp/utils/tcp.c +++ b/libfreerdp/utils/tcp.c @@ -24,7 +24,9 @@ #include #include +#include +#include #include #include @@ -41,11 +43,16 @@ #include #include #include -#include #include #include #include +#ifdef HAVE_POLL_H +#include +#else +#include +#endif + #ifdef __APPLE__ #ifndef TCP_KEEPIDLE #define TCP_KEEPIDLE TCP_KEEPALIVE @@ -67,6 +74,8 @@ #endif +#define TAG FREERDP_TAG("utils") + int freerdp_tcp_connect(const char* hostname, int port) { int status; @@ -90,7 +99,7 @@ int freerdp_tcp_connect(const char* hostname, int port) if (status != 0) { - //fprintf(stderr, "tcp_connect: getaddrinfo (%s)\n", gai_strerror(status)); + //WLog_ERR(TAG, "tcp_connect: getaddrinfo (%s)", gai_strerror(status)); return -1; } @@ -105,7 +114,7 @@ int freerdp_tcp_connect(const char* hostname, int port) if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 0) { - fprintf(stderr, "connected to %s:%s\n", hostname, servname); + WLog_ERR(TAG, "connected to %s:%s", hostname, servname); break; } @@ -117,7 +126,7 @@ int freerdp_tcp_connect(const char* hostname, int port) if (sockfd == -1) { - fprintf(stderr, "unable to connect to %s:%s\n", hostname, servname); + WLog_ERR(TAG, "unable to connect to %s:%s", hostname, servname); return -1; } @@ -143,13 +152,13 @@ int freerdp_tcp_read(int sockfd, BYTE* data, int length) if (wsa_error == WSAEWOULDBLOCK) return 0; - fprintf(stderr, "recv() error: %d\n", wsa_error); + WLog_ERR(TAG, "recv() error: %d", wsa_error); #else /* No data available */ if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; - perror("recv"); + WLog_ERR(TAG, "recv"); #endif return -1; } @@ -172,12 +181,14 @@ int freerdp_tcp_write(int sockfd, BYTE* data, int length) if (wsa_error == WSAEWOULDBLOCK) status = 0; else - perror("send"); + WLog_ERR(TAG, "send"); + #else if (errno == EAGAIN || errno == EWOULDBLOCK) status = 0; else - perror("send"); + WLog_ERR(TAG, "send"); + #endif } @@ -186,46 +197,76 @@ int freerdp_tcp_write(int sockfd, BYTE* data, int length) int freerdp_tcp_wait_read(int sockfd) { + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set fds; struct timeval timeout; +#endif if (sockfd < 1) { - fprintf(stderr, "Invalid socket to watch: %d\n", sockfd); + WLog_ERR(TAG, "Invalid socket to watch: %d", sockfd); return 0 ; } +#ifdef HAVE_POLL_H + pollfds.fd = sockfd; + pollfds.events = POLLIN; + pollfds.revents = 0; + do + { + status = poll(&pollfds, 1, 5 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&fds); FD_SET(sockfd, &fds); timeout.tv_sec = 5; timeout.tv_usec = 0; - select(sockfd+1, &fds, NULL, NULL, &timeout); - if (!FD_ISSET(sockfd, &fds)) - return -1; + status = _select(sockfd+1, &fds, NULL, NULL, &timeout); +#endif - return 0; + return status > 0 ? 1 : 0; } int freerdp_tcp_wait_write(int sockfd) { + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set fds; struct timeval timeout; +#endif if (sockfd < 1) { - fprintf(stderr, "Invalid socket to watch: %d\n", sockfd); - return 0; + WLog_ERR(TAG, "Invalid socket to watch: %d", sockfd); + return 0 ; } +#ifdef HAVE_POLL_H + pollfds.fd = sockfd; + pollfds.events = POLLOUT; + pollfds.revents = 0; + do + { + status = poll(&pollfds, 1, 5 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&fds); FD_SET(sockfd, &fds); timeout.tv_sec = 5; timeout.tv_usec = 0; - select(sockfd+1, NULL, &fds, NULL, &timeout); - if (!FD_ISSET(sockfd, &fds)) - return -1; + status = _select(sockfd+1, NULL, &fds, NULL, &timeout); +#endif - return 0; + return status > 0 ? 1 : 0; } int freerdp_tcp_disconnect(int sockfd) diff --git a/libfreerdp/utils/test/CMakeLists.txt b/libfreerdp/utils/test/CMakeLists.txt index e6ab6134c..a08ee112d 100644 --- a/libfreerdp/utils/test/CMakeLists.txt +++ b/libfreerdp/utils/test/CMakeLists.txt @@ -13,17 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-thread winpr-synch winpr-file winpr-utils winpr-crt) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr freerdp) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/libfreerdp/utils/test/TestRingBuffer.c b/libfreerdp/utils/test/TestRingBuffer.c index 1f4e3f504..dd128f44e 100644 --- a/libfreerdp/utils/test/TestRingBuffer.c +++ b/libfreerdp/utils/test/TestRingBuffer.c @@ -111,7 +111,7 @@ int TestRingBuffer(int argc, char* argv[]) if (ringbuffer_used(&ringBuffer) != 15) { - fprintf(stderr, "invalid used size got %d when i would expect 15\n", ringbuffer_used(&ringBuffer)); + fprintf(stderr, "invalid used size got %ld when i would expect 15\n", ringbuffer_used(&ringBuffer)); return -1; } @@ -134,7 +134,7 @@ int TestRingBuffer(int argc, char* argv[]) if (ringbuffer_used(&ringBuffer) != 5) { - fprintf(stderr, "invalid used size after read got %d when i would expect 5\n", ringbuffer_used(&ringBuffer)); + fprintf(stderr, "invalid used size after read got %ld when i would expect 5\n", ringbuffer_used(&ringBuffer)); return -1; } @@ -189,7 +189,7 @@ int TestRingBuffer(int argc, char* argv[]) if (ringbuffer_capacity(&ringBuffer) != 10) { - fprintf(stderr, "not the expected capacity, have %d and expects 10\n", ringbuffer_capacity(&ringBuffer)); + fprintf(stderr, "not the expected capacity, have %ld and expects 10\n", ringbuffer_capacity(&ringBuffer)); return -1; } fprintf(stderr, "ok\n"); @@ -213,7 +213,7 @@ int TestRingBuffer(int argc, char* argv[]) fprintf(stderr, "%d: specific overlaps test...", ++testNo); if (!test_overlaps()) { - fprintf(stderr, "ko\n", i); + fprintf(stderr, "ko\n"); return -1; } fprintf(stderr, "ok\n"); diff --git a/libfreerdp/utils/uds.c b/libfreerdp/utils/uds.c index d05f6ff32..9aa62588b 100644 --- a/libfreerdp/utils/uds.c +++ b/libfreerdp/utils/uds.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -43,6 +44,8 @@ #endif +#define TAG FREERDP_TAG("utils") + int freerdp_uds_connect(const char* path) { #ifndef _WIN32 @@ -54,7 +57,7 @@ int freerdp_uds_connect(const char* path) sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd == -1) { - perror("socket"); + WLog_ERR(TAG, "socket"); return -1; } @@ -63,7 +66,7 @@ int freerdp_uds_connect(const char* path) status = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)); if (status < 0) { - perror("connect"); + WLog_ERR(TAG, "connect"); close(sockfd); return -1; } diff --git a/rdtk/CMakeLists.txt b/rdtk/CMakeLists.txt new file mode 100644 index 000000000..41f1ebf9a --- /dev/null +++ b/rdtk/CMakeLists.txt @@ -0,0 +1,90 @@ +# RdTk: Remote Desktop Toolkit +# rdtk 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. + +cmake_minimum_required(VERSION 2.8) + +project(RdTk C) + +set(CMAKE_COLOR_MAKEFILE ON) + +# Include cmake modules +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckStructHasMember) +include(FindPkgConfig) +include(TestBigEndian) + +# Include our extra modules +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/) + +# Check for cmake compatibility (enable/disable features) +include(CheckCmakeCompat) +include(FindFeature) +include(AutoVersioning) +include(ConfigOptions) +include(CheckCCompilerFlag) +include(GNUInstallDirsWrapper) +include(CMakePackageConfigHelpers) + +# Soname versioning +set(RDTK_VERSION_MAJOR "1") +set(RDTK_VERSION_MINOR "1") +set(RDTK_VERSION_REVISION "0") +set(RDTK_VERSION "${RDTK_VERSION_MAJOR}.${RDTK_VERSION_MINOR}") +set(RDTK_VERSION_FULL "${RDTK_VERSION}.${RDTK_VERSION_REVISION}") +set(RDTK_VERSION_FULL ${RDTK_VERSION_FULL} PARENT_SCOPE) + +# Default to release build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +# Default to build shared libs +if(NOT DEFINED BUILD_SHARED_LIBS) + set(BUILD_SHARED_LIBS ON) +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DRDTK_EXPORTS") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) + +add_subdirectory(include) +add_subdirectory(librdtk) + +# Exporting + +if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") + + export(PACKAGE rdtk) + + set(RDTK_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/RdTk") + + set(RDTK_INCLUDE_DIR "include") + + configure_package_config_file(RdTkConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/RdTkConfig.cmake + INSTALL_DESTINATION ${RDTK_CMAKE_INSTALL_DIR} PATH_VARS RDTK_INCLUDE_DIR) + + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/RdTkConfigVersion.cmake + VERSION ${RDTK_VERSION} COMPATIBILITY SameMajorVersion) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RdTkConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/RdTkConfigVersion.cmake + DESTINATION ${RDTK_CMAKE_INSTALL_DIR}) + + install(EXPORT RdTkTargets DESTINATION ${RDTK_CMAKE_INSTALL_DIR}) +endif() + diff --git a/rdtk/RdTkConfig.cmake.in b/rdtk/RdTkConfig.cmake.in new file mode 100644 index 000000000..d3e9653d8 --- /dev/null +++ b/rdtk/RdTkConfig.cmake.in @@ -0,0 +1,11 @@ + +@PACKAGE_INIT@ + +set(RdTk_VERSION_MAJOR "@RDTK_VERSION_MAJOR@") +set(RdTk_VERSION_MINOR "@RDTK_VERSION_MINOR@") +set(RdTk_VERSION_REVISION "@RDTK_VERSION_REVISION@") + +set_and_check(RdTk_INCLUDE_DIR "@PACKAGE_RDTK_INCLUDE_DIR@") + +include("${CMAKE_CURRENT_LIST_DIR}/RdTkTargets.cmake") + diff --git a/rdtk/include/CMakeLists.txt b/rdtk/include/CMakeLists.txt new file mode 100644 index 000000000..d35c350de --- /dev/null +++ b/rdtk/include/CMakeLists.txt @@ -0,0 +1,20 @@ +# RdTk: Remote Desktop Toolkit +# rdtk 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. + +file(GLOB RDTK_HEADERS "rdtk/*.h") +install(FILES ${RDTK_HEADERS} DESTINATION include/rdtk COMPONENT headers) + diff --git a/rdtk/include/rdtk/api.h b/rdtk/include/rdtk/api.h new file mode 100644 index 000000000..89b26ed13 --- /dev/null +++ b/rdtk/include/rdtk/api.h @@ -0,0 +1,46 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_API_H +#define RDTK_API_H + +#include + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RDTK_EXPORTS + #ifdef __GNUC__ + #define RDTK_EXPORT __attribute__((dllexport)) + #else + #define RDTK_EXPORT __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define RDTK_EXPORT __attribute__((dllimport)) + #else + #define RDTK_EXPORT __declspec(dllimport) + #endif + #endif +#else + #if __GNUC__ >= 4 + #define RDTK_EXPORT __attribute__ ((visibility("default"))) + #else + #define RDTK_EXPORT + #endif +#endif + +#endif /* RDTK_API_H */ diff --git a/rdtk/include/rdtk/rdtk.h b/rdtk/include/rdtk/rdtk.h new file mode 100644 index 000000000..dff5139f8 --- /dev/null +++ b/rdtk/include/rdtk/rdtk.h @@ -0,0 +1,79 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_H +#define RDTK_H + +#include + +#include +#include + +#include +#include + +typedef struct rdtk_engine rdtkEngine; +typedef struct rdtk_font rdtkFont; +typedef struct rdtk_glyph rdtkGlyph; +typedef struct rdtk_surface rdtkSurface; +typedef struct rdtk_button rdtkButton; +typedef struct rdtk_label rdtkLabel; +typedef struct rdtk_text_field rdtkTextField; +typedef struct rdtk_nine_patch rdtkNinePatch; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Engine */ + +RDTK_EXPORT rdtkEngine* rdtk_engine_new(); +RDTK_EXPORT void rdtk_engine_free(rdtkEngine* engine); + +/* Surface */ + +RDTK_EXPORT int rdtk_surface_fill(rdtkSurface* surface, int x, int y, int width, int height, UINT32 color); + +RDTK_EXPORT rdtkSurface* rdtk_surface_new(rdtkEngine* engine, BYTE* data, int width, int height, int scanline); +RDTK_EXPORT void rdtk_surface_free(rdtkSurface* surface); + +/* Font */ + +RDTK_EXPORT int rdtk_font_draw_text(rdtkSurface* surface, int nXDst, int nYDst, rdtkFont* font, const char* text); + +/* Button */ + +RDTK_EXPORT int rdtk_button_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkButton* button, const char* text); + +/* Label */ + +RDTK_EXPORT int rdtk_label_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkLabel* label, const char* text, int hAlign, int vAlign); + +/* TextField */ + +RDTK_EXPORT int rdtk_text_field_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkTextField* textField, const char* text); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_H */ + diff --git a/rdtk/librdtk/CMakeLists.txt b/rdtk/librdtk/CMakeLists.txt new file mode 100644 index 000000000..21c6ba92a --- /dev/null +++ b/rdtk/librdtk/CMakeLists.txt @@ -0,0 +1,53 @@ +# RdTk: Remote Desktop Toolkit +# +# 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. + +set(MODULE_NAME "rdtk") +set(MODULE_PREFIX "RDTK") + +include_directories(${OPENSSL_INCLUDE_DIR}) + +set(${MODULE_PREFIX}_SRCS + rdtk_resources.c + rdtk_resources.h + rdtk_surface.c + rdtk_surface.h + rdtk_font.c + rdtk_font.h + rdtk_button.c + rdtk_button.h + rdtk_label.c + rdtk_label.h + rdtk_nine_patch.c + rdtk_nine_patch.h + rdtk_text_field.c + rdtk_text_field.h + rdtk_engine.c + rdtk_engine.h) + +add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +list(APPEND ${MODULE_PREFIX}_LIBS winpr) +list(APPEND ${MODULE_PREFIX}_LIBS freerdp) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT RdTkTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "RdTk") + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/rdtk/librdtk/rdtk_button.c b/rdtk/librdtk/rdtk_button.c new file mode 100644 index 000000000..ead14985d --- /dev/null +++ b/rdtk/librdtk/rdtk_button.c @@ -0,0 +1,116 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_font.h" + +#include "rdtk_button.h" + +int rdtk_button_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkButton* button, const char* text) +{ + int offsetX; + int offsetY; + int textWidth; + int textHeight; + int fillWidth; + int fillHeight; + rdtkFont* font; + rdtkEngine* engine; + rdtkNinePatch* ninePatch; + + engine = surface->engine; + font = engine->font; + button = engine->button; + ninePatch = button->ninePatch; + + rdtk_font_text_draw_size(font, &textWidth, &textHeight, text); + + rdtk_nine_patch_draw(surface, nXDst, nYDst, nWidth, nHeight, ninePatch); + + if ((textWidth > 0) && (textHeight > 0)) + { + fillWidth = nWidth - (ninePatch->width - ninePatch->fillWidth); + fillHeight = nHeight - (ninePatch->height - ninePatch->fillHeight); + + offsetX = ninePatch->fillLeft; + offsetY = ninePatch->fillTop; + + if (textWidth < fillWidth) + offsetX = ((fillWidth - textWidth) / 2) + ninePatch->fillLeft; + else if (textWidth < ninePatch->width) + offsetX = ((ninePatch->width - textWidth) / 2); + + if (textHeight < fillHeight) + offsetY = ((fillHeight - textHeight) / 2) + ninePatch->fillTop; + else if (textHeight < ninePatch->height) + offsetY = ((ninePatch->height - textHeight) / 2); + + rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text); + } + + return 1; +} + +rdtkButton* rdtk_button_new(rdtkEngine* engine, rdtkNinePatch* ninePatch) +{ + rdtkButton* button; + + button = (rdtkButton*) calloc(1, sizeof(rdtkButton)); + + if (!button) + return NULL; + + button->engine = engine; + button->ninePatch = ninePatch; + + return button; +} + +void rdtk_button_free(rdtkButton* button) +{ + if (!button) + return; + + free(button); +} + +int rdtk_button_engine_init(rdtkEngine* engine) +{ + if (!engine->button) + { + engine->button = rdtk_button_new(engine, engine->button9patch); + } + + return 1; +} + +int rdtk_button_engine_uninit(rdtkEngine* engine) +{ + if (engine->button) + { + rdtk_button_free(engine->button); + engine->button = NULL; + } + + return 1; +} + diff --git a/rdtk/librdtk/rdtk_button.h b/rdtk/librdtk/rdtk_button.h new file mode 100644 index 000000000..7d79ac707 --- /dev/null +++ b/rdtk/librdtk/rdtk_button.h @@ -0,0 +1,50 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_BUTTON_PRIVATE_H +#define RDTK_BUTTON_PRIVATE_H + +#include + +#include "rdtk_surface.h" +#include "rdtk_nine_patch.h" + +#include "rdtk_engine.h" + +struct rdtk_button +{ + rdtkEngine* engine; + rdtkNinePatch* ninePatch; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_button_engine_init(rdtkEngine* engine); +int rdtk_button_engine_uninit(rdtkEngine* engine); + +rdtkButton* rdtk_button_new(rdtkEngine* engine, rdtkNinePatch* ninePatch); +void rdtk_button_free(rdtkButton* button); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_BUTTON_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_engine.c b/rdtk/librdtk/rdtk_engine.c new file mode 100644 index 000000000..5bbfdd8a0 --- /dev/null +++ b/rdtk/librdtk/rdtk_engine.c @@ -0,0 +1,58 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_font.h" +#include "rdtk_nine_patch.h" +#include "rdtk_button.h" +#include "rdtk_text_field.h" + +#include "rdtk_engine.h" + +rdtkEngine* rdtk_engine_new() +{ + rdtkEngine* engine; + + engine = (rdtkEngine*) calloc(1, sizeof(rdtkEngine)); + + if (!engine) + return NULL; + + rdtk_font_engine_init(engine); + rdtk_nine_patch_engine_init(engine); + rdtk_button_engine_init(engine); + rdtk_text_field_engine_init(engine); + + return engine; +} + +void rdtk_engine_free(rdtkEngine* engine) +{ + if (!engine) + return; + + rdtk_font_engine_uninit(engine); + rdtk_nine_patch_engine_uninit(engine); + rdtk_button_engine_uninit(engine); + rdtk_text_field_engine_uninit(engine); + + free(engine); +} diff --git a/rdtk/librdtk/rdtk_engine.h b/rdtk/librdtk/rdtk_engine.h new file mode 100644 index 000000000..c81587282 --- /dev/null +++ b/rdtk/librdtk/rdtk_engine.h @@ -0,0 +1,48 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_ENGINE_PRIVATE_H +#define RDTK_ENGINE_PRIVATE_H + +#include + +struct rdtk_engine +{ + rdtkFont* font; + + rdtkLabel* label; + + rdtkButton* button; + rdtkNinePatch* button9patch; + + rdtkTextField* textField; + rdtkNinePatch* textField9patch; +}; + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_ENGINE_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_font.c b/rdtk/librdtk/rdtk_font.c new file mode 100644 index 000000000..90837b801 --- /dev/null +++ b/rdtk/librdtk/rdtk_font.c @@ -0,0 +1,724 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_engine.h" +#include "rdtk_resources.h" +#include "rdtk_surface.h" + +#include "rdtk_font.h" + +int rdtk_font_draw_glyph(rdtkSurface* surface, int nXDst, int nYDst, rdtkFont* font, rdtkGlyph* glyph) +{ + int x, y; + int nXSrc; + int nYSrc; + int nWidth; + int nHeight; + int nSrcStep; + int nDstStep; + int nSrcPad; + int nDstPad; + BYTE* pSrcData; + BYTE* pSrcPixel; + BYTE* pDstData; + BYTE* pDstPixel; + BYTE A, R, G, B; + + nXDst += glyph->offsetX; + nYDst += glyph->offsetY; + + nXSrc = glyph->rectX; + nYSrc = glyph->rectY; + + nWidth = glyph->rectWidth; + nHeight = glyph->rectHeight; + + nSrcStep = font->image->scanline; + pSrcData = font->image->data; + + pDstData = surface->data; + nDstStep = surface->scanline; + + nSrcPad = (nSrcStep - (nWidth * 4)); + nDstPad = (nDstStep - (nWidth * 4)); + + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + + for (x = 0; x < nWidth; x++) + { + B = pSrcPixel[0]; + G = pSrcPixel[1]; + R = pSrcPixel[2]; + A = pSrcPixel[3]; + pSrcPixel += 4; + + if (1) + { + /* tint black */ + R = 255 - R; + G = 255 - G; + B = 255 - B; + } + + if (A == 255) + { + pDstPixel[0] = B; + pDstPixel[1] = G; + pDstPixel[2] = R; + } + else + { + R = (R * A) / 255; + G = (G * A) / 255; + B = (B * A) / 255; + + pDstPixel[0] = B + (pDstPixel[0] * (255 - A) + (255 / 2)) / 255; + pDstPixel[1] = G + (pDstPixel[1] * (255 - A) + (255 / 2)) / 255; + pDstPixel[2] = R + (pDstPixel[2] * (255 - A) + (255 / 2)) / 255; + } + + pDstPixel[3] = 0xFF; + pDstPixel += 4; + } + + pSrcPixel += nSrcPad; + pDstPixel += nDstPad; + } + + return 1; +} + +int rdtk_font_draw_text(rdtkSurface* surface, int nXDst, int nYDst, rdtkFont* font, const char* text) +{ + int index; + int length; + rdtkGlyph* glyph; + + font = surface->engine->font; + + length = strlen(text); + + for (index = 0; index < length; index++) + { + glyph = &font->glyphs[text[index] - 32]; + rdtk_font_draw_glyph(surface, nXDst, nYDst, font, glyph); + nXDst += (glyph->width + 1); + } + + return 1; +} + +int rdtk_font_text_draw_size(rdtkFont* font, int* width, int* height, const char* text) +{ + int index; + int length; + int glyphIndex; + rdtkGlyph* glyph; + + *width = 0; + *height = 0; + + length = strlen(text); + + for (index = 0; index < length; index++) + { + glyphIndex = text[index] - 32; + + if (glyphIndex < font->glyphCount) + { + glyph = &font->glyphs[glyphIndex]; + *width += (glyph->width + 1); + } + } + + *height = font->height + 2; + + return 1; +} + +char* rdtk_font_load_descriptor_file(const char* filename, int* pSize) +{ + BYTE* buffer; + FILE* fp = NULL; + size_t readSize; + size_t fileSize; + + fp = fopen(filename, "r"); + + if (!fp) + return NULL; + + fseek(fp, 0, SEEK_END); + fileSize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (fileSize < 1) + { + fclose(fp); + return NULL; + } + + buffer = (BYTE*) malloc(fileSize + 2); + + if (!buffer) + { + fclose(fp); + return NULL; + } + + readSize = fread(buffer, fileSize, 1, fp); + + if (!readSize) + { + if (!ferror(fp)) + readSize = fileSize; + } + + fclose(fp); + + if (readSize < 1) + { + free(buffer); + return NULL; + } + + buffer[fileSize] = '\0'; + buffer[fileSize + 1] = '\0'; + + *pSize = (int) fileSize; + return (char*) buffer; +} + +int rdtk_font_convert_descriptor_code_to_utf8(const char* str, BYTE* utf8) +{ + int len = strlen(str); + + *((UINT32*) utf8) = 0; + + if (len < 1) + return 1; + + if (len == 1) + { + if ((str[0] > 31) && (str[0] < 127)) + { + utf8[0] = str[0]; + } + } + else + { + if (str[0] == '&') + { + const char* acc = &str[1]; + + if (strcmp(acc, "quot;") == 0) + utf8[0] = '"'; + else if (strcmp(acc, "amp;") == 0) + utf8[0] = '&'; + else if (strcmp(acc, "lt;") == 0) + utf8[0] = '<'; + else if (strcmp(acc, "gt;") == 0) + utf8[0] = '>'; + } + } + + return 1; +} + +int rdtk_font_parse_descriptor_buffer(rdtkFont* font, BYTE* buffer, int size) +{ + char* p; + char* q; + char* r; + char* beg; + char* end; + char* tok[4]; + int index; + int count; + rdtkGlyph* glyph; + + p = strstr((char*) buffer, ""); + + if (!p) + return -1; + + p += sizeof("") - 1; + + p = strstr(p, ""); + + if (!end) + return -1; + + /* parse font size */ + + p = strstr(p, "size=\""); + + if (!p) + return -1; + + p += sizeof("size=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + font->size = atoi(p); + *q = '"'; + + if (font->size <= 0) + return -1; + + p = q + 1; + + /* parse font family */ + + p = strstr(p, "family=\""); + + if (!p) + return -1; + + p += sizeof("family=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + font->family = _strdup(p); + *q = '"'; + + if (!font->family) + return -1; + + p = q + 1; + + /* parse font height */ + + p = strstr(p, "height=\""); + + if (!p) + return -1; + + p += sizeof("height=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + font->height = atoi(p); + *q = '"'; + + if (font->height <= 0) + return -1; + + p = q + 1; + + /* parse font style */ + + p = strstr(p, "style=\""); + + if (!p) + return -1; + + p += sizeof("style=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + font->style = _strdup(p); + *q = '"'; + + if (!font->style) + return -1; + + p = q + 1; + + //printf("size: %d family: %s height: %d style: %s\n", + // font->size, font->family, font->height, font->style); + + beg = p; + count = 0; + + while (p < end) + { + p = strstr(p, ""); + + if (!r) + return -1; + + *r = '\0'; + + p = r + sizeof("/>"); + *r = '/'; + + count++; + } + + font->glyphCount = count; + font->glyphs = (rdtkGlyph*) calloc(font->glyphCount, sizeof(rdtkGlyph)); + + if (!font->glyphs) + return -1; + + p = beg; + index = 0; + + while (p < end) + { + p = strstr(p, ""); + + if (!r) + return -1; + + *r = '\0'; + + /* start parsing glyph */ + + glyph = &font->glyphs[index]; + + /* parse glyph width */ + + p = strstr(p, "width=\""); + + if (!p) + return -1; + + p += sizeof("width=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + glyph->width = atoi(p); + *q = '"'; + + if (glyph->width < 0) + return -1; + + p = q + 1; + + /* parse glyph offset x,y */ + + p = strstr(p, "offset=\""); + + if (!p) + return -1; + + p += sizeof("offset=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + + tok[0] = p; + + p = strchr(tok[0] + 1, ' '); + + if (!p) + return -1; + + *p = 0; + tok[1] = p + 1; + + glyph->offsetX = atoi(tok[0]); + glyph->offsetY = atoi(tok[1]); + + *q = '"'; + + p = q + 1; + + /* parse glyph rect x,y,w,h */ + + p = strstr(p, "rect=\""); + + if (!p) + return -1; + + p += sizeof("rect=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + + tok[0] = p; + + p = strchr(tok[0] + 1, ' '); + + if (!p) + return -1; + + *p = 0; + tok[1] = p + 1; + + p = strchr(tok[1] + 1, ' '); + + if (!p) + return -1; + + *p = 0; + tok[2] = p + 1; + + p = strchr(tok[2] + 1, ' '); + + if (!p) + return -1; + + *p = 0; + tok[3] = p + 1; + + glyph->rectX = atoi(tok[0]); + glyph->rectY = atoi(tok[1]); + glyph->rectWidth = atoi(tok[2]); + glyph->rectHeight = atoi(tok[3]); + + *q = '"'; + + p = q + 1; + + /* parse code */ + + p = strstr(p, "code=\""); + + if (!p) + return -1; + + p += sizeof("code=\"") - 1; + q = strchr(p, '"'); + + if (!q) + return -1; + + *q = '\0'; + rdtk_font_convert_descriptor_code_to_utf8(p, glyph->code); + *q = '"'; + + p = q + 1; + + /* finish parsing glyph */ + + p = r + sizeof("/>"); + *r = '/'; + + index++; + } + + return 1; +} + +int rdtk_font_load_descriptor(rdtkFont* font, const char* filename) +{ + int size; + char* buffer; + + buffer = rdtk_font_load_descriptor_file(filename, &size); + + if (!buffer) + return -1; + + return rdtk_font_parse_descriptor_buffer(font, (BYTE*) buffer, size); +} + +rdtkFont* rdtk_font_new(rdtkEngine* engine, const char* path, const char* file) +{ + int status; + int length; + rdtkFont* font; + char* fontBaseFile; + char* fontImageFile; + char* fontDescriptorFile; + + fontBaseFile = GetCombinedPath(path, file); + + if (!fontBaseFile) + return NULL; + + length = strlen(fontBaseFile); + + fontImageFile = (char*) malloc(length + 8); + + if (!fontImageFile) + return NULL; + + strcpy(fontImageFile, fontBaseFile); + strcpy(&fontImageFile[length], ".png"); + + fontDescriptorFile = (char*) malloc(length + 8); + + if (!fontImageFile) + return NULL; + + strcpy(fontDescriptorFile, fontBaseFile); + strcpy(&fontDescriptorFile[length], ".xml"); + + free(fontBaseFile); + + if (!PathFileExistsA(fontImageFile)) + return NULL; + + if (!PathFileExistsA(fontDescriptorFile)) + return NULL; + + font = (rdtkFont*) calloc(1, sizeof(rdtkFont)); + + if (!font) + return NULL; + + font->engine = engine; + + font->image = winpr_image_new(); + + if (!font->image) + return NULL; + + status = winpr_image_read(font->image, fontImageFile); + + if (status < 0) + return NULL; + + status = rdtk_font_load_descriptor(font, fontDescriptorFile); + + free(fontImageFile); + free(fontDescriptorFile); + + return font; +} + +rdtkFont* rdtk_embedded_font_new(rdtkEngine* engine, BYTE* imageData, int imageSize, BYTE* descriptorData, int descriptorSize) +{ + int size; + int status; + BYTE* buffer; + rdtkFont* font; + + font = (rdtkFont*) calloc(1, sizeof(rdtkFont)); + + if (!font) + return NULL; + + font->engine = engine; + + font->image = winpr_image_new(); + + if (!font->image) + return NULL; + + status = winpr_image_read_buffer(font->image, imageData, imageSize); + + if (status < 0) + return NULL; + + size = descriptorSize; + buffer = (BYTE*) malloc(size); + + if (!buffer) + return NULL; + + CopyMemory(buffer, descriptorData, size); + + status = rdtk_font_parse_descriptor_buffer(font, buffer, size); + + free(buffer); + + return font; +} + +void rdtk_font_free(rdtkFont* font) +{ + if (!font) + return; + + free(font); +} + +int rdtk_font_engine_init(rdtkEngine* engine) +{ + if (!engine->font) + { + int imageSize; + int descriptorSize; + BYTE* imageData = NULL; + BYTE* descriptorData = NULL; + + imageSize = rdtk_get_embedded_resource_file("source_serif_pro_regular_12.png", &imageData); + descriptorSize = rdtk_get_embedded_resource_file("source_serif_pro_regular_12.xml", &descriptorData); + + if ((imageSize < 0) || (descriptorSize < 0)) + return -1; + + engine->font = rdtk_embedded_font_new(engine, imageData, imageSize, descriptorData, descriptorSize); + } + + return 1; +} + +int rdtk_font_engine_uninit(rdtkEngine* engine) +{ + if (engine->font) + { + rdtk_font_free(engine->font); + engine->font = NULL; + } + + return 1; +} diff --git a/rdtk/librdtk/rdtk_font.h b/rdtk/librdtk/rdtk_font.h new file mode 100644 index 000000000..8f3b984d0 --- /dev/null +++ b/rdtk/librdtk/rdtk_font.h @@ -0,0 +1,72 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_FONT_PRIVATE_H +#define RDTK_FONT_PRIVATE_H + +#include + +#include +#include +#include + +#include "rdtk_engine.h" + +struct rdtk_glyph +{ + int width; + int offsetX; + int offsetY; + int rectX; + int rectY; + int rectWidth; + int rectHeight; + BYTE code[4]; +}; + +struct rdtk_font +{ + rdtkEngine* engine; + + int size; + int height; + char* family; + char* style; + wImage* image; + int glyphCount; + rdtkGlyph* glyphs; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_font_text_draw_size(rdtkFont* font, int* width, int* height, const char* text); + +int rdtk_font_engine_init(rdtkEngine* engine); +int rdtk_font_engine_uninit(rdtkEngine* engine); + +rdtkFont* rdtk_font_new(rdtkEngine* engine, const char* path, const char* file); +void rdtk_font_free(rdtkFont* font); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_FONT_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_label.c b/rdtk/librdtk/rdtk_label.c new file mode 100644 index 000000000..a05cdcbf7 --- /dev/null +++ b/rdtk/librdtk/rdtk_label.c @@ -0,0 +1,100 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_font.h" + +#include "rdtk_label.h" + +int rdtk_label_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkLabel* label, const char* text, int hAlign, int vAlign) +{ + int offsetX; + int offsetY; + int textWidth; + int textHeight; + rdtkFont* font; + rdtkEngine* engine; + + engine = surface->engine; + font = engine->font; + + rdtk_font_text_draw_size(font, &textWidth, &textHeight, text); + + if ((textWidth > 0) && (textHeight > 0)) + { + offsetX = 0; + offsetY = 0; + + if (textWidth < nWidth) + offsetX = ((nWidth - textWidth) / 2); + + if (textHeight < nHeight) + offsetY = ((nHeight - textHeight) / 2); + + rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text); + } + + return 1; +} + +rdtkLabel* rdtk_label_new(rdtkEngine* engine) +{ + rdtkLabel* label; + + label = (rdtkLabel*) calloc(1, sizeof(rdtkLabel)); + + if (!label) + return NULL; + + label->engine = engine; + + return label; +} + +void rdtk_label_free(rdtkLabel* label) +{ + if (!label) + return; + + free(label); +} + +int rdtk_label_engine_init(rdtkEngine* engine) +{ + if (!engine->label) + { + engine->label = rdtk_label_new(engine); + } + + return 1; +} + +int rdtk_label_engine_uninit(rdtkEngine* engine) +{ + if (engine->label) + { + rdtk_label_free(engine->label); + engine->label = NULL; + } + + return 1; +} diff --git a/rdtk/librdtk/rdtk_label.h b/rdtk/librdtk/rdtk_label.h new file mode 100644 index 000000000..a0f2a603a --- /dev/null +++ b/rdtk/librdtk/rdtk_label.h @@ -0,0 +1,48 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_LABEL_PRIVATE_H +#define RDTK_LABEL_PRIVATE_H + +#include + +#include "rdtk_surface.h" + +#include "rdtk_engine.h" + +struct rdtk_label +{ + rdtkEngine* engine; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_label_engine_init(rdtkEngine* engine); +int rdtk_label_engine_uninit(rdtkEngine* engine); + +rdtkLabel* rdtk_label_new(rdtkEngine* engine); +void rdtk_label_free(rdtkLabel* label); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_LABEL_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_nine_patch.c b/rdtk/librdtk/rdtk_nine_patch.c new file mode 100644 index 000000000..226372e28 --- /dev/null +++ b/rdtk/librdtk/rdtk_nine_patch.c @@ -0,0 +1,513 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_resources.h" + +#include "rdtk_nine_patch.h" + +int rdtk_image_copy_alpha_blend(BYTE* pDstData, int nDstStep, int nXDst, int nYDst, + int nWidth, int nHeight, BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc) +{ + int x, y; + int nSrcPad; + int nDstPad; + BYTE* pSrcPixel; + BYTE* pDstPixel; + BYTE A, R, G, B; + + nSrcPad = (nSrcStep - (nWidth * 4)); + nDstPad = (nDstStep - (nWidth * 4)); + + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + + for (x = 0; x < nWidth; x++) + { + B = pSrcPixel[0]; + G = pSrcPixel[1]; + R = pSrcPixel[2]; + A = pSrcPixel[3]; + pSrcPixel += 4; + + if (A == 255) + { + pDstPixel[0] = B; + pDstPixel[1] = G; + pDstPixel[2] = R; + } + else + { + R = (R * A) / 255; + G = (G * A) / 255; + B = (B * A) / 255; + + pDstPixel[0] = B + (pDstPixel[0] * (255 - A) + (255 / 2)) / 255; + pDstPixel[1] = G + (pDstPixel[1] * (255 - A) + (255 / 2)) / 255; + pDstPixel[2] = R + (pDstPixel[2] * (255 - A) + (255 / 2)) / 255; + } + + pDstPixel[3] = 0xFF; + pDstPixel += 4; + } + + pSrcPixel += nSrcPad; + pDstPixel += nDstPad; + } + + return 1; +} + +int rdtk_nine_patch_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, rdtkNinePatch* ninePatch) +{ + int x, y; + int width; + int height; + int nXSrc; + int nYSrc; + int nSrcStep; + int nDstStep; + BYTE* pSrcData; + BYTE* pDstData; + int scaleWidth; + int scaleHeight; + + if (nWidth < ninePatch->width) + nWidth = ninePatch->width; + + if (nHeight < ninePatch->height) + nHeight = ninePatch->height; + + scaleWidth = nWidth - (ninePatch->width - ninePatch->scaleWidth); + scaleHeight = nHeight - (ninePatch->height - ninePatch->scaleHeight); + + nSrcStep = ninePatch->scanline; + pSrcData = ninePatch->data; + + pDstData = surface->data; + nDstStep = surface->scanline; + + /* top */ + + x = 0; + y = 0; + + /* top left */ + + nXSrc = 0; + nYSrc = 0; + width = ninePatch->scaleLeft; + height = ninePatch->scaleTop; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + + /* top middle (scalable) */ + + nXSrc = ninePatch->scaleLeft; + nYSrc = 0; + width = ninePatch->scaleWidth; + height = ninePatch->scaleTop; + + while (x < (nXSrc + scaleWidth)) + { + width = (nXSrc + scaleWidth) - x; + + if (width > ninePatch->scaleWidth) + width = ninePatch->scaleWidth; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + } + + /* top right */ + + nXSrc = ninePatch->scaleRight; + nYSrc = 0; + width = ninePatch->width - ninePatch->scaleRight; + height = ninePatch->scaleTop; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + /* middle */ + + x = 0; + y = ninePatch->scaleTop; + + /* middle left */ + + nXSrc = 0; + nYSrc = ninePatch->scaleTop; + width = ninePatch->scaleLeft; + height = ninePatch->scaleHeight; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + + /* middle (scalable) */ + + nXSrc = ninePatch->scaleLeft; + nYSrc = ninePatch->scaleTop; + width = ninePatch->scaleWidth; + height = ninePatch->scaleHeight; + + while (x < (nXSrc + scaleWidth)) + { + width = (nXSrc + scaleWidth) - x; + + if (width > ninePatch->scaleWidth) + width = ninePatch->scaleWidth; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + } + + /* middle right */ + + nXSrc = ninePatch->scaleRight; + nYSrc = ninePatch->scaleTop; + width = ninePatch->width - ninePatch->scaleRight; + height = ninePatch->scaleHeight; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + /* bottom */ + + x = 0; + y = ninePatch->scaleBottom; + + /* bottom left */ + + nXSrc = 0; + nYSrc = ninePatch->scaleBottom; + width = ninePatch->scaleLeft; + height = ninePatch->height - ninePatch->scaleBottom; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + + /* bottom middle (scalable) */ + + nXSrc = ninePatch->scaleLeft; + nYSrc = ninePatch->scaleBottom; + width = ninePatch->scaleWidth; + height = ninePatch->height - ninePatch->scaleBottom; + + while (x < (nXSrc + scaleWidth)) + { + width = (nXSrc + scaleWidth) - x; + + if (width > ninePatch->scaleWidth) + width = ninePatch->scaleWidth; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + x += width; + } + + /* bottom right */ + + nXSrc = ninePatch->scaleRight; + nYSrc = ninePatch->scaleBottom; + width = ninePatch->width - ninePatch->scaleRight; + height = ninePatch->height - ninePatch->scaleBottom; + + rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, + width, height, pSrcData, nSrcStep, nXSrc, nYSrc); + + return 1; +} + +int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image) +{ + int x, y; + BYTE* data; + int beg, end; + int scanline; + UINT32* pixel; + int width, height; + + ninePatch->image = image; + + width = image->width; + height = image->height; + scanline = image->scanline; + data = image->data; + + /* parse scalable area */ + + beg = end = -1; + pixel = (UINT32*) &data[4]; /* (1, 0) */ + + for (x = 1; x < width - 1; x++) + { + if (beg < 0) + { + if (*pixel) + { + beg = x; + } + } + else if (end < 0) + { + if (!(*pixel)) + { + end = x; + break; + } + } + + pixel++; + } + + ninePatch->scaleLeft = beg - 1; + ninePatch->scaleRight = end - 1; + ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft; + + beg = end = -1; + pixel = (UINT32*) &data[scanline]; /* (0, 1) */ + + for (y = 1; y < height - 1; y++) + { + if (beg < 0) + { + if (*pixel) + { + beg = y; + } + } + else if (end < 0) + { + if (!(*pixel)) + { + end = y; + break; + } + } + + pixel = (UINT32*) &((BYTE*) pixel)[scanline]; + } + + ninePatch->scaleTop = beg - 1; + ninePatch->scaleBottom = end - 1; + ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop; + + /* parse fillable area */ + + beg = end = -1; + pixel = (UINT32*) &data[((height - 1) * scanline) + 4]; /* (1, height - 1) */ + + for (x = 1; x < width - 1; x++) + { + if (beg < 0) + { + if (*pixel) + { + beg = x; + } + } + else if (end < 0) + { + if (!(*pixel)) + { + end = x; + break; + } + } + + pixel++; + } + + ninePatch->fillLeft = beg - 1; + ninePatch->fillRight = end - 1; + ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft; + + beg = end = -1; + pixel = (UINT32*) &data[((width - 1) * 4) + scanline]; /* (width - 1, 1) */ + + for (y = 1; y < height - 1; y++) + { + if (beg < 0) + { + if (*pixel) + { + beg = y; + } + } + else if (end < 0) + { + if (!(*pixel)) + { + end = y; + break; + } + } + + pixel = (UINT32*) &((BYTE*) pixel)[scanline]; + } + + ninePatch->fillTop = beg - 1; + ninePatch->fillBottom = end - 1; + ninePatch->fillHeight = ninePatch->fillBottom - ninePatch->fillTop; + + /* cut out borders from image */ + + ninePatch->width = width - 2; + ninePatch->height = height - 2; + ninePatch->data = &data[scanline + 4]; /* (1, 1) */ + ninePatch->scanline = scanline; + +#if 0 + printf("width: %d height: %d\n", ninePatch->width, ninePatch->height); + + printf("scale: left: %d right: %d top: %d bottom: %d\n", + ninePatch->scaleLeft, ninePatch->scaleRight, + ninePatch->scaleTop, ninePatch->scaleBottom); + + printf("fill: left: %d right: %d top: %d bottom: %d\n", + ninePatch->fillLeft, ninePatch->fillRight, + ninePatch->fillTop, ninePatch->fillBottom); +#endif + + return 1; +} + +rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine) +{ + rdtkNinePatch* ninePatch; + + ninePatch = (rdtkNinePatch*) calloc(1, sizeof(rdtkNinePatch)); + + if (!ninePatch) + return NULL; + + ninePatch->engine = engine; + + return ninePatch; +} + +void rdtk_nine_patch_free(rdtkNinePatch* ninePatch) +{ + if (!ninePatch) + return; + + winpr_image_free(ninePatch->image, TRUE); + + free(ninePatch); +} + +int rdtk_nine_patch_engine_init(rdtkEngine* engine) +{ + int status; + wImage* image; + rdtkNinePatch* ninePatch; + + if (!engine->button9patch) + { + int size; + BYTE* data; + + status = -1; + + size = rdtk_get_embedded_resource_file("btn_default_normal.9.png", &data); + + if (size > 0) + { + image = winpr_image_new(); + + if (image) + status = winpr_image_read_buffer(image, data, size); + } + + if (status > 0) + { + ninePatch = engine->button9patch = rdtk_nine_patch_new(engine); + + if (ninePatch) + rdtk_nine_patch_set_image(ninePatch, image); + } + } + + if (!engine->textField9patch) + { + int size; + BYTE* data; + + status = -1; + + size = rdtk_get_embedded_resource_file("textfield_default.9.png", &data); + + if (size > 0) + { + image = winpr_image_new(); + + if (image) + status = winpr_image_read_buffer(image, data, size); + } + + if (status > 0) + { + ninePatch = engine->textField9patch = rdtk_nine_patch_new(engine); + + if (ninePatch) + rdtk_nine_patch_set_image(ninePatch, image); + } + } + + return 1; +} + +int rdtk_nine_patch_engine_uninit(rdtkEngine* engine) +{ + if (engine->button9patch) + { + rdtk_nine_patch_free(engine->button9patch); + engine->button9patch = NULL; + } + + if (engine->textField9patch) + { + rdtk_nine_patch_free(engine->textField9patch); + engine->textField9patch = NULL; + } + + return 1; +} diff --git a/rdtk/librdtk/rdtk_nine_patch.h b/rdtk/librdtk/rdtk_nine_patch.h new file mode 100644 index 000000000..157a68758 --- /dev/null +++ b/rdtk/librdtk/rdtk_nine_patch.h @@ -0,0 +1,74 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_NINE_PATCH_PRIVATE_H +#define RDTK_NINE_PATCH_PRIVATE_H + +#include + +#include + +#include "rdtk_surface.h" + +#include "rdtk_engine.h" + +struct rdtk_nine_patch +{ + rdtkEngine* engine; + + wImage* image; + + int width; + int height; + int scanline; + BYTE* data; + + int scaleLeft; + int scaleRight; + int scaleWidth; + int scaleTop; + int scaleBottom; + int scaleHeight; + + int fillLeft; + int fillRight; + int fillWidth; + int fillTop; + int fillBottom; + int fillHeight; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image); +int rdtk_nine_patch_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, rdtkNinePatch* ninePatch); + +int rdtk_nine_patch_engine_init(rdtkEngine* engine); +int rdtk_nine_patch_engine_uninit(rdtkEngine* engine); + +rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine); +void rdtk_nine_patch_free(rdtkNinePatch* ninePatch); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_NINE_PATCH_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_resources.c b/rdtk/librdtk/rdtk_resources.c new file mode 100644 index 000000000..7bcc352e7 --- /dev/null +++ b/rdtk/librdtk/rdtk_resources.c @@ -0,0 +1,1349 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_resources.h" + +/* Nine Patches */ + +static BYTE btn_default_normal_9_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x32, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x42, 0xb5, 0xcb, 0x95, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x89, 0x00, 0x00, 0x0b, + 0x89, 0x01, 0x37, 0xc9, 0xcb, 0xad, 0x00, 0x00, 0x02, 0x5d, 0x49, 0x44, + 0x41, 0x54, 0x58, 0x85, 0xed, 0x58, 0x41, 0xae, 0xd3, 0x40, 0x0c, 0x7d, + 0x9e, 0x52, 0x84, 0x10, 0x69, 0xd5, 0x05, 0x57, 0xe8, 0x8e, 0x4d, 0x51, + 0x57, 0xdc, 0x80, 0x43, 0xf4, 0x08, 0x1c, 0xaa, 0x87, 0xe0, 0x02, 0x88, + 0x13, 0xb0, 0xeb, 0x0d, 0x10, 0x8b, 0x4a, 0x5f, 0x15, 0x42, 0xe4, 0x63, + 0xb3, 0xa0, 0x53, 0x39, 0x8e, 0x3d, 0x33, 0x49, 0xbf, 0xf4, 0x37, 0x58, + 0x8a, 0x32, 0x3f, 0x99, 0xf1, 0xf3, 0x1b, 0x3f, 0x7b, 0xd2, 0x4f, 0x22, + 0x02, 0x22, 0x82, 0x63, 0xe2, 0x3d, 0x6c, 0xb0, 0x91, 0x33, 0x91, 0xb9, + 0xae, 0x9e, 0x02, 0x1d, 0xc0, 0xeb, 0xe3, 0xf1, 0xf8, 0x71, 0xbb, 0xdd, + 0x7e, 0x00, 0x40, 0x44, 0x74, 0x63, 0x6c, 0x99, 0xe7, 0x48, 0x45, 0x24, + 0x8f, 0xe5, 0x74, 0x3a, 0x7d, 0x3d, 0x1c, 0x0e, 0x9f, 0x01, 0xfc, 0xd4, + 0x73, 0x5f, 0x38, 0x40, 0xdd, 0x7e, 0xbf, 0xff, 0xb4, 0xd9, 0x6c, 0x76, + 0x44, 0x84, 0x94, 0x52, 0x13, 0x10, 0x33, 0x43, 0x44, 0xb0, 0x5e, 0xaf, + 0xdf, 0x03, 0xf8, 0xd2, 0x02, 0xb4, 0xea, 0xba, 0x6e, 0xd7, 0xf7, 0xbd, + 0xa4, 0x94, 0x6e, 0x40, 0x16, 0xcc, 0xb2, 0x61, 0x66, 0x30, 0x33, 0xba, + 0xae, 0xdb, 0x01, 0x58, 0x01, 0xf8, 0xae, 0x9d, 0x26, 0x8c, 0x93, 0xbe, + 0x64, 0xe6, 0x41, 0xd4, 0x3a, 0x99, 0xb5, 0xbf, 0xaf, 0x6b, 0x97, 0x36, + 0x7a, 0x8f, 0xd1, 0x20, 0xda, 0xcc, 0x42, 0x8f, 0xf5, 0x3b, 0x0d, 0x66, + 0x41, 0x2d, 0x23, 0x6b, 0xe4, 0x2d, 0x72, 0x12, 0x1f, 0x82, 0xc1, 0x11, + 0x99, 0x07, 0x14, 0x32, 0x9c, 0xfa, 0x4e, 0x4f, 0xf3, 0xb6, 0x6e, 0x10, + 0x4d, 0x0d, 0x24, 0xd8, 0xae, 0x36, 0x46, 0x59, 0xaa, 0xf9, 0x1e, 0x6d, + 0x65, 0x74, 0x79, 0xe6, 0x32, 0xca, 0x0b, 0xb4, 0x08, 0x22, 0x86, 0x01, + 0xd0, 0x88, 0x91, 0xab, 0x3a, 0xed, 0x00, 0x88, 0x55, 0x67, 0x05, 0x32, + 0x8b, 0x91, 0x8e, 0x9e, 0x99, 0x5d, 0x59, 0xe7, 0x77, 0x16, 0xcc, 0x63, + 0x54, 0x55, 0x5d, 0x8b, 0xe2, 0x5a, 0x94, 0x57, 0xcc, 0x11, 0x00, 0xa4, + 0x94, 0x06, 0x0e, 0x4b, 0x2d, 0x68, 0x32, 0xa3, 0x28, 0xe1, 0x76, 0x6c, + 0xe7, 0x96, 0x98, 0x85, 0x75, 0xa4, 0x23, 0xd5, 0x2c, 0x22, 0x46, 0x26, + 0x80, 0x76, 0xd5, 0x45, 0x36, 0xf7, 0xb4, 0x2c, 0x32, 0xca, 0x6c, 0xf4, + 0x65, 0x41, 0xed, 0x75, 0x9d, 0xd3, 0x94, 0x23, 0x8a, 0xa2, 0x8e, 0x1a, + 0x6a, 0x14, 0x6c, 0x8d, 0xd1, 0x28, 0xc1, 0x59, 0x79, 0x5e, 0x7e, 0x74, + 0x00, 0x93, 0x0b, 0x36, 0x2f, 0xce, 0x8e, 0xb5, 0x20, 0xac, 0xd9, 0x43, + 0x32, 0xda, 0xba, 0x62, 0x1d, 0x79, 0x2c, 0x22, 0x33, 0x2c, 0xa7, 0xd5, + 0x51, 0xa9, 0xa1, 0x96, 0xba, 0xb9, 0x67, 0xc5, 0x5e, 0x07, 0x60, 0xa0, + 0xbc, 0x08, 0xbc, 0xa5, 0x8e, 0x5c, 0xd5, 0xd5, 0xa2, 0xaf, 0x3d, 0xf7, + 0x80, 0x8a, 0x05, 0x5b, 0xcb, 0x91, 0xc7, 0x2e, 0x12, 0x8d, 0xbb, 0x75, + 0x5a, 0x49, 0x79, 0xec, 0x39, 0x28, 0xc8, 0xfb, 0xbe, 0x16, 0xd4, 0xc2, + 0x2a, 0xb2, 0xb0, 0x8e, 0x98, 0x19, 0x29, 0xfd, 0x4b, 0xa1, 0x77, 0xa4, + 0x5b, 0xb0, 0x5a, 0x0b, 0x6a, 0xfa, 0x80, 0xb4, 0x7b, 0xaf, 0x81, 0xa3, + 0xe3, 0xc3, 0x5a, 0x73, 0xaf, 0x6b, 0x3d, 0x77, 0x9e, 0xe4, 0x28, 0x8f, + 0x24, 0x7f, 0xf7, 0x51, 0x9e, 0x73, 0x64, 0xc7, 0x36, 0x10, 0xe7, 0x23, + 0x66, 0x7e, 0x1d, 0x79, 0x8d, 0xb5, 0x75, 0x3b, 0x43, 0x46, 0x76, 0x71, + 0xad, 0xb1, 0x3a, 0x42, 0x78, 0xb6, 0x8f, 0xfc, 0xb8, 0xd7, 0x59, 0x47, + 0x25, 0x25, 0x3a, 0xef, 0x2c, 0x23, 0xba, 0xbb, 0x33, 0xb4, 0x5a, 0x53, + 0x1d, 0xcd, 0xd8, 0x3a, 0x57, 0x75, 0xa3, 0x87, 0xcc, 0x8c, 0xbe, 0xef, + 0x5d, 0x27, 0x25, 0x61, 0x10, 0x11, 0x96, 0xcb, 0xd1, 0xcf, 0xd7, 0x1b, + 0x90, 0xb5, 0xc7, 0xf3, 0xf9, 0xfc, 0xb0, 0x58, 0x2c, 0x56, 0x53, 0xb7, + 0x8a, 0x88, 0x70, 0xb9, 0x5c, 0x1e, 0x00, 0x3c, 0x8e, 0xde, 0x39, 0xf3, + 0xdf, 0x02, 0x78, 0x77, 0xbd, 0x2f, 0x26, 0x21, 0x01, 0x7f, 0x00, 0xfc, + 0x00, 0xf0, 0xed, 0x7a, 0x2f, 0x02, 0xbd, 0x04, 0xf0, 0x06, 0xc0, 0x2b, + 0x34, 0xca, 0x5f, 0x19, 0x03, 0xf8, 0x05, 0xe0, 0x02, 0xe0, 0xf7, 0xc4, + 0xb5, 0xff, 0xed, 0xb9, 0x6d, 0x46, 0xb5, 0x0b, 0x26, 0xfe, 0xd3, 0x50, + 0x44, 0xf0, 0x17, 0xa0, 0xb1, 0xe0, 0x73, 0xc3, 0xe6, 0x24, 0xdb, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +static int btn_default_normal_9_png_len = 683; + +static BYTE textfield_default_9_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x32, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x46, 0x40, 0x1b, 0xa8, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x89, 0x00, 0x00, 0x0b, + 0x89, 0x01, 0x37, 0xc9, 0xcb, 0xad, 0x00, 0x00, 0x01, 0x53, 0x49, 0x44, + 0x41, 0x54, 0x58, 0x85, 0xed, 0x98, 0x4b, 0x6e, 0x83, 0x30, 0x10, 0x86, + 0x67, 0xc6, 0xa8, 0x8a, 0x58, 0xb1, 0x45, 0xa2, 0x9b, 0x8a, 0x83, 0xf4, + 0x28, 0xbd, 0x03, 0xea, 0x71, 0xb8, 0x0b, 0xf7, 0x60, 0x55, 0xa9, 0x97, + 0x60, 0x51, 0x4f, 0x17, 0xcd, 0x44, 0x7e, 0x76, 0x30, 0x09, 0x52, 0xa9, + 0xf8, 0x25, 0x0b, 0x3f, 0x26, 0xf3, 0xf9, 0xb7, 0xad, 0x10, 0x07, 0x98, + 0x19, 0x0a, 0x54, 0x16, 0xcc, 0x0c, 0x18, 0xf4, 0x3d, 0x03, 0x44, 0x7d, + 0xa5, 0xb2, 0x00, 0xf0, 0x29, 0x8d, 0xca, 0x1d, 0x99, 0xa6, 0xe9, 0xbd, + 0xef, 0xfb, 0x37, 0x71, 0x85, 0xa8, 0xb3, 0xdc, 0x15, 0xa8, 0xaa, 0x0a, + 0xda, 0xb6, 0x7d, 0xcd, 0x02, 0x2e, 0x97, 0x0b, 0xd7, 0x75, 0xfd, 0x63, + 0xcd, 0x49, 0x9e, 0x02, 0xb9, 0x89, 0x83, 0x09, 0x7d, 0xb9, 0x71, 0x1e, + 0xc0, 0x18, 0xc3, 0xc6, 0x18, 0x40, 0xc4, 0x5b, 0x59, 0xeb, 0x80, 0x99, + 0xa5, 0x6e, 0xb3, 0x00, 0x22, 0x62, 0x22, 0x8a, 0x00, 0x39, 0x50, 0x98, + 0xfc, 0xda, 0xf6, 0x0e, 0x82, 0x07, 0x90, 0xa4, 0x2e, 0x24, 0x07, 0x90, + 0x65, 0x94, 0xa7, 0xb5, 0x16, 0x52, 0x27, 0x32, 0x02, 0x48, 0x72, 0x79, + 0x6a, 0x0e, 0xa4, 0x10, 0x51, 0x32, 0x46, 0x75, 0xb0, 0x66, 0x1f, 0xc4, + 0x41, 0x22, 0x96, 0x93, 0x00, 0xb7, 0x9e, 0x83, 0xb8, 0x27, 0x47, 0x92, + 0xa7, 0xe2, 0x92, 0xbe, 0xb4, 0xe4, 0xa9, 0xc9, 0xe4, 0x54, 0x85, 0x1d, + 0xa9, 0xe4, 0xbf, 0x6d, 0x72, 0x0a, 0xa8, 0x3a, 0x08, 0x81, 0x25, 0xfd, + 0xc5, 0x80, 0x7b, 0x75, 0x38, 0x40, 0xb4, 0x6e, 0x87, 0x73, 0xa0, 0x02, + 0xee, 0x7d, 0xd9, 0xa8, 0x80, 0x87, 0xeb, 0x7f, 0x00, 0x8a, 0x7e, 0x29, + 0x6c, 0x01, 0x3c, 0x7c, 0x63, 0x43, 0xc0, 0xae, 0xf2, 0x00, 0x6b, 0xbf, + 0xc0, 0x36, 0x03, 0xf6, 0xd0, 0x09, 0x38, 0x01, 0x27, 0xe0, 0x04, 0xfc, + 0x01, 0x00, 0xaa, 0x80, 0xc2, 0x6b, 0x6e, 0xa4, 0xcd, 0x0e, 0xd6, 0x82, + 0xa3, 0xfb, 0x41, 0x70, 0xdf, 0x52, 0x21, 0x5a, 0xac, 0xe7, 0x80, 0x88, + 0x10, 0x11, 0x09, 0x11, 0xe9, 0x3a, 0xe6, 0xd5, 0x53, 0x45, 0xc6, 0xe5, + 0x73, 0x4d, 0xd3, 0x78, 0x6f, 0x2d, 0xaf, 0x31, 0x0c, 0xc3, 0x4b, 0xd7, + 0x75, 0x4f, 0xea, 0xd4, 0x33, 0x5a, 0x96, 0xc5, 0xce, 0xf3, 0xbc, 0x8c, + 0xe3, 0xf8, 0xb1, 0x35, 0xc7, 0xa9, 0x23, 0x6a, 0xef, 0x3f, 0xa4, 0xbe, + 0x01, 0x9f, 0x91, 0x87, 0x71, 0x3a, 0x69, 0xd1, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +static int textfield_default_9_png_len = 417; + +/* Fonts */ + +static BYTE source_serif_pro_regular_12_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x02, 0xe7, 0x00, 0x00, 0x00, 0x11, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x7e, 0x53, 0x02, 0xe5, 0x00, 0x00, 0x00, + 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64, + 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0e, + 0xc4, 0x00, 0x00, 0x0e, 0xc4, 0x01, 0x95, 0x2b, 0x0e, 0x1b, 0x00, 0x00, + 0x20, 0x00, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x9d, 0x77, 0xd8, + 0x55, 0xc5, 0xb5, 0xc6, 0x7f, 0x14, 0x15, 0xb1, 0xa2, 0x62, 0x12, 0x8d, + 0x0d, 0x1b, 0x26, 0xf6, 0x86, 0x1a, 0x13, 0x10, 0x7b, 0xb0, 0xc4, 0x28, + 0x18, 0x4b, 0x14, 0x31, 0x17, 0x15, 0x8d, 0xc6, 0x42, 0xbc, 0x26, 0x16, + 0xbc, 0x46, 0x63, 0xbc, 0x26, 0xd8, 0x35, 0x09, 0x0a, 0x51, 0xb1, 0x44, + 0x63, 0x8f, 0x1d, 0xf9, 0x00, 0x1b, 0x62, 0x45, 0xc4, 0xd8, 0x51, 0x11, + 0x8d, 0x8a, 0x60, 0x45, 0x41, 0x7c, 0xef, 0x1f, 0xef, 0xcc, 0xdd, 0x73, + 0xf6, 0xd9, 0xfb, 0x9c, 0xf3, 0x7d, 0x7c, 0x60, 0xd4, 0xef, 0x7d, 0x9e, + 0x79, 0xce, 0xd9, 0xb3, 0x67, 0x66, 0xcf, 0x9e, 0xb2, 0x66, 0xcd, 0x5a, + 0x6b, 0xd6, 0x6e, 0x27, 0x89, 0xaf, 0x19, 0x3a, 0x01, 0x5f, 0x00, 0x9f, + 0x87, 0xdf, 0x36, 0xb4, 0xa1, 0x0d, 0x6d, 0x68, 0x43, 0x1b, 0xda, 0xd0, + 0x86, 0x79, 0x45, 0x07, 0x60, 0x71, 0xe0, 0xfd, 0x2f, 0xbb, 0x22, 0x6d, + 0xf8, 0x7a, 0xa3, 0x7d, 0xf2, 0xff, 0x5f, 0xc0, 0x7e, 0x05, 0xff, 0x9b, + 0x83, 0x29, 0xf3, 0x5a, 0xa1, 0x66, 0x22, 0x5f, 0xcf, 0x8d, 0x80, 0xbf, + 0x01, 0x9b, 0x00, 0x7f, 0xa9, 0x91, 0x6f, 0x10, 0xf0, 0xe6, 0x7c, 0xac, + 0x57, 0x11, 0x9e, 0x03, 0x56, 0x58, 0xc0, 0xcf, 0x9c, 0x1f, 0xe8, 0x04, + 0x74, 0xfe, 0xb2, 0x2b, 0x31, 0x1f, 0xd0, 0x11, 0xf8, 0x01, 0xb0, 0xd4, + 0x97, 0x5d, 0x91, 0x36, 0xb4, 0xa1, 0x0d, 0x5f, 0x6b, 0x08, 0x78, 0x1b, + 0x18, 0x8d, 0xd7, 0xaa, 0x27, 0x81, 0x55, 0x0a, 0xd2, 0x9d, 0x0d, 0x3c, + 0x16, 0xd2, 0x0f, 0x99, 0x87, 0xe7, 0xfd, 0x1e, 0xb8, 0xb9, 0x99, 0x79, + 0x96, 0x00, 0x0e, 0x00, 0xae, 0x06, 0x0e, 0x9b, 0x87, 0x67, 0x47, 0x6c, + 0x0a, 0xfc, 0x0f, 0xf0, 0x40, 0x0b, 0xf2, 0xfe, 0x04, 0x78, 0x0a, 0x98, + 0x0d, 0x34, 0x01, 0x0b, 0x35, 0x90, 0x27, 0xd6, 0xff, 0x1a, 0xea, 0xd7, + 0x7f, 0x0c, 0x5e, 0x9f, 0x17, 0xad, 0x11, 0xbf, 0x06, 0x70, 0x2d, 0xf0, + 0x0e, 0x70, 0x74, 0x9d, 0xe7, 0xfe, 0x1c, 0xb8, 0xaa, 0x81, 0xe7, 0xb6, + 0xe1, 0xeb, 0x8b, 0x01, 0x78, 0x5e, 0x5f, 0x40, 0x36, 0x7f, 0xcf, 0x05, + 0x5e, 0x00, 0xfe, 0x8e, 0x37, 0x78, 0x35, 0xd1, 0x1e, 0x78, 0x06, 0xd8, + 0x07, 0x58, 0x0d, 0xf8, 0x6e, 0x88, 0x4f, 0xff, 0x03, 0xac, 0x09, 0x9c, + 0x11, 0xfe, 0x6f, 0x06, 0xfc, 0x36, 0x57, 0xce, 0x2a, 0xc0, 0xaf, 0x81, + 0x2e, 0x98, 0xf1, 0xed, 0x14, 0xe2, 0x57, 0x06, 0xc6, 0x03, 0x93, 0x0a, + 0xf2, 0xc4, 0xe7, 0x9f, 0x96, 0x8b, 0x5b, 0x1f, 0xb8, 0x2f, 0xe4, 0x9b, + 0x02, 0x5c, 0x49, 0xf5, 0xa4, 0x89, 0x48, 0xeb, 0xb9, 0x3c, 0x70, 0x13, + 0x6e, 0x84, 0x87, 0x42, 0x1d, 0x7e, 0x93, 0x4b, 0xbf, 0x74, 0xf8, 0x9d, + 0x01, 0xbc, 0x1b, 0xfe, 0x77, 0x02, 0x16, 0x29, 0x29, 0xbf, 0xb5, 0xb0, + 0x0e, 0xde, 0x69, 0x4f, 0x0b, 0xd7, 0xbb, 0x00, 0x13, 0xf0, 0x3b, 0x5e, + 0x01, 0x2c, 0x96, 0xa4, 0x6d, 0x0f, 0x6c, 0x0c, 0x1c, 0x1b, 0xd2, 0xa5, + 0x58, 0x16, 0xf8, 0x2b, 0x70, 0x1b, 0xf0, 0x3a, 0x70, 0x07, 0xd9, 0xfb, + 0xb7, 0xc3, 0x6d, 0x7c, 0x0f, 0xf0, 0x08, 0x30, 0x11, 0xd8, 0xab, 0xa4, + 0x3e, 0x07, 0xe3, 0x01, 0x13, 0xf1, 0x12, 0x26, 0x7a, 0x69, 0x48, 0xd1, + 0x01, 0xf8, 0x45, 0x78, 0xde, 0x9f, 0xa8, 0x1c, 0x1b, 0x65, 0xe8, 0x1f, + 0xea, 0xf0, 0x28, 0x26, 0x72, 0xab, 0x27, 0xf7, 0x06, 0xe1, 0x81, 0x3b, + 0x36, 0xa4, 0xe9, 0xd7, 0x40, 0x79, 0xf3, 0x1b, 0x83, 0x80, 0xfb, 0x81, + 0xb7, 0x80, 0xa1, 0x64, 0x63, 0x38, 0xc5, 0x32, 0xc0, 0xa9, 0xb8, 0xde, + 0xf7, 0xe1, 0x85, 0xe6, 0x69, 0xe0, 0x2c, 0x3c, 0xfe, 0xca, 0xb0, 0x3b, + 0xf0, 0x11, 0xc5, 0xe3, 0xb8, 0x2f, 0xf0, 0x30, 0xee, 0x8f, 0x29, 0xb8, + 0xad, 0x26, 0x85, 0xb8, 0x1d, 0x73, 0x69, 0x37, 0xc6, 0x8b, 0xcd, 0xf8, + 0x24, 0xdd, 0x4d, 0x78, 0x81, 0xef, 0x1b, 0xea, 0x13, 0xcb, 0x69, 0x02, + 0x1e, 0xc4, 0xf3, 0x7b, 0x28, 0xf0, 0xad, 0xa4, 0x9c, 0xdd, 0x70, 0x5f, + 0xa6, 0x69, 0x63, 0x78, 0x1d, 0xcf, 0xa1, 0x5a, 0x69, 0xde, 0xa2, 0x92, + 0x59, 0x58, 0x07, 0xb8, 0x34, 0xd4, 0x6b, 0x34, 0xf0, 0x04, 0x66, 0x2a, + 0x62, 0x9a, 0x7d, 0x70, 0x7f, 0x0b, 0xcf, 0xbb, 0x3b, 0x92, 0xbc, 0xb7, + 0x85, 0x38, 0x85, 0x34, 0xfb, 0x00, 0x7b, 0xe3, 0x71, 0x13, 0x99, 0x98, + 0x7b, 0x93, 0xf4, 0xa7, 0xe0, 0xb9, 0xa3, 0x50, 0x8f, 0x7b, 0xf0, 0x9c, + 0xc9, 0xe7, 0x19, 0x85, 0x17, 0xf1, 0x83, 0x80, 0xd7, 0xf0, 0x9c, 0xbf, + 0x1f, 0x58, 0xb1, 0x20, 0xed, 0x5d, 0x54, 0xa3, 0x77, 0x78, 0x9f, 0xb9, + 0xc0, 0xad, 0x05, 0xf7, 0x23, 0x8e, 0x0c, 0xe5, 0x3c, 0x0a, 0xec, 0x1b, + 0xda, 0xe2, 0xa1, 0x10, 0x77, 0x55, 0x2e, 0xed, 0x51, 0x98, 0xc9, 0xf8, + 0x3c, 0xb4, 0xcf, 0xa6, 0xc9, 0xbd, 0x7e, 0xb8, 0x6d, 0xc7, 0x84, 0xe7, + 0x0e, 0x03, 0x56, 0x4a, 0xee, 0x17, 0x8d, 0x93, 0xc7, 0xc3, 0xb3, 0xf6, + 0xcf, 0x3d, 0x67, 0xe7, 0xf0, 0xfe, 0xb1, 0xac, 0x0b, 0x80, 0xae, 0xb9, + 0xb2, 0xf2, 0x63, 0xe5, 0x7e, 0xdc, 0x6f, 0x43, 0x80, 0x85, 0x93, 0xb4, + 0xed, 0x31, 0x6d, 0x7f, 0x3c, 0xa4, 0x79, 0x0a, 0x33, 0x29, 0xdd, 0x42, + 0xda, 0xb7, 0xc8, 0xc6, 0x45, 0x5a, 0x5e, 0xac, 0xeb, 0x0f, 0x42, 0x3d, + 0x62, 0x7f, 0xdd, 0x15, 0xca, 0x6c, 0x1f, 0xea, 0x38, 0x3d, 0xdc, 0x7b, + 0x08, 0xd8, 0x0e, 0x38, 0x27, 0xa4, 0x13, 0x66, 0x8c, 0x8e, 0x09, 0xf5, + 0x58, 0x2a, 0xd4, 0xe1, 0x23, 0xe0, 0x45, 0xe0, 0x57, 0x21, 0xed, 0xd4, + 0x90, 0xf6, 0x29, 0xe0, 0x50, 0x2c, 0x38, 0x18, 0x85, 0xfb, 0xf5, 0x43, + 0x60, 0x1c, 0x5e, 0x53, 0xb6, 0xc7, 0xe3, 0xe6, 0xb3, 0xd0, 0x26, 0xeb, + 0x02, 0x27, 0x01, 0xcf, 0x86, 0xfc, 0x53, 0x81, 0x8b, 0xc2, 0xb3, 0x2e, + 0xc2, 0x4c, 0xd8, 0x9b, 0x98, 0x39, 0x05, 0x33, 0x5d, 0xa3, 0x81, 0x8f, + 0xb1, 0x46, 0xf6, 0x11, 0xa0, 0x4f, 0x78, 0xde, 0x18, 0x4c, 0xdf, 0x5f, + 0x04, 0x7e, 0x99, 0x94, 0xd7, 0x94, 0x0b, 0x9f, 0x85, 0xf7, 0x8d, 0xcf, + 0xd8, 0x06, 0x8f, 0x83, 0x5b, 0xf1, 0x7c, 0xcb, 0xe3, 0x38, 0x3c, 0xb7, + 0xe7, 0x15, 0x57, 0x02, 0x3d, 0x30, 0xb3, 0xda, 0x28, 0xba, 0x02, 0xdf, + 0x07, 0x7e, 0x46, 0x25, 0xed, 0x68, 0x29, 0x36, 0x02, 0x76, 0x00, 0xb6, + 0x6a, 0x66, 0xbe, 0x6d, 0x80, 0x11, 0x78, 0x2d, 0x1b, 0x09, 0x7c, 0x8a, + 0xd7, 0xba, 0x7a, 0x88, 0xf5, 0xdf, 0x9b, 0xfa, 0xf5, 0xef, 0x8a, 0x69, + 0x7b, 0xc7, 0x1a, 0xf1, 0x6f, 0xe1, 0x79, 0xd4, 0xa5, 0x81, 0xb2, 0xd6, + 0xc5, 0x74, 0xac, 0x35, 0xda, 0xad, 0x0d, 0x5f, 0x4d, 0xfc, 0x09, 0xd3, + 0x9c, 0x23, 0x92, 0xb8, 0xa3, 0xf0, 0xf8, 0xef, 0x8b, 0xd7, 0xa5, 0xda, + 0x90, 0xf4, 0xb9, 0xa4, 0xdf, 0x4a, 0x7a, 0x49, 0xd2, 0x7e, 0x92, 0x08, + 0xff, 0xf7, 0x0d, 0xff, 0x91, 0xb4, 0x93, 0xa4, 0x83, 0xc3, 0xff, 0x7e, + 0x92, 0xf6, 0x49, 0xee, 0xfd, 0x58, 0xd2, 0x74, 0x49, 0x47, 0x48, 0x9a, + 0x26, 0xe9, 0x77, 0x92, 0xee, 0x0e, 0xf7, 0xae, 0x95, 0x74, 0xa3, 0xa4, + 0xf5, 0x65, 0x7c, 0x3f, 0xc9, 0x87, 0xa4, 0xe3, 0x25, 0xed, 0x92, 0x8b, + 0x7b, 0x41, 0xd2, 0x15, 0xe1, 0xff, 0xda, 0x21, 0xdf, 0xe1, 0xb9, 0x34, + 0x31, 0xa4, 0x75, 0xbe, 0x46, 0xd2, 0xb0, 0xe4, 0xde, 0x6a, 0x92, 0x66, + 0x49, 0x5a, 0x37, 0x5c, 0x2f, 0x2a, 0xe9, 0x7d, 0x49, 0xf7, 0x84, 0xf2, + 0x6e, 0x0b, 0x75, 0x9d, 0x21, 0xe9, 0xc8, 0x92, 0xf2, 0x5b, 0x2b, 0x1c, + 0x2f, 0xe9, 0xc4, 0xf0, 0xbf, 0x7b, 0xa8, 0x57, 0x6c, 0x8b, 0x1b, 0x24, + 0x0d, 0x0f, 0xff, 0x3b, 0x4b, 0xba, 0x2f, 0xd4, 0x51, 0x92, 0x86, 0xe4, + 0xca, 0xb9, 0x5b, 0xd2, 0xed, 0xe1, 0x7f, 0x17, 0x49, 0x53, 0x92, 0xeb, + 0x5f, 0x84, 0x3c, 0x6b, 0x86, 0xeb, 0xff, 0x92, 0x34, 0x57, 0xd2, 0x86, + 0xb9, 0x32, 0x56, 0x95, 0x34, 0x33, 0xa4, 0x8d, 0x71, 0xd3, 0x6a, 0xd4, + 0x7d, 0x39, 0x49, 0xe3, 0x24, 0x9d, 0x2c, 0xa9, 0x53, 0x12, 0xdf, 0x54, + 0x10, 0x1e, 0x94, 0x34, 0x59, 0xd2, 0x16, 0xa1, 0xfc, 0x1f, 0x86, 0xb4, + 0xa3, 0x24, 0x3d, 0x14, 0xfe, 0x1f, 0x1e, 0xfa, 0x61, 0xf5, 0x70, 0xbd, + 0xbd, 0xa4, 0x2f, 0xc2, 0x6f, 0x4b, 0xda, 0x76, 0x39, 0x49, 0x2b, 0x34, + 0x98, 0x76, 0x05, 0x49, 0x5d, 0x4b, 0xee, 0x75, 0x91, 0x74, 0x8c, 0xa4, + 0x2b, 0x25, 0xbd, 0x28, 0xe9, 0x2e, 0x49, 0xed, 0x93, 0xfb, 0x7b, 0x84, + 0x76, 0x3a, 0x3a, 0xd7, 0x0e, 0xcb, 0x4a, 0xba, 0x3c, 0xdc, 0x5b, 0xbb, + 0xa4, 0xec, 0x91, 0xa1, 0x3d, 0xf6, 0xaa, 0x51, 0x37, 0xa9, 0xb2, 0xbf, + 0x7f, 0x29, 0x69, 0x8e, 0xa4, 0xf5, 0xc2, 0xf5, 0x00, 0x49, 0xff, 0x96, + 0xe7, 0x5b, 0x4c, 0xd3, 0x41, 0xd2, 0x1b, 0xb9, 0x7c, 0xf9, 0x72, 0x96, + 0x96, 0xc7, 0xd7, 0x9b, 0x92, 0xd6, 0xaa, 0xf3, 0x4c, 0x42, 0x1b, 0xd4, + 0x2a, 0x0f, 0x79, 0xde, 0xc4, 0xb8, 0xfd, 0x24, 0xbd, 0x2d, 0xa9, 0xaf, + 0xa4, 0x76, 0x49, 0x9a, 0xe3, 0x43, 0xde, 0x7a, 0xcf, 0x23, 0xc4, 0xe5, + 0xd3, 0xd6, 0x4a, 0x5f, 0xeb, 0x5e, 0x3e, 0xbe, 0xb3, 0xa4, 0xb1, 0x05, + 0xef, 0x5e, 0xaf, 0xfc, 0x18, 0x66, 0xca, 0x34, 0x72, 0xa5, 0x82, 0x7b, + 0xed, 0x24, 0xfd, 0xab, 0xa4, 0xee, 0x71, 0x8e, 0xed, 0x5b, 0x70, 0x6f, + 0x4a, 0xee, 0xfa, 0x34, 0x49, 0x8f, 0x4b, 0xfa, 0x4e, 0x12, 0x77, 0x98, + 0xdc, 0xdf, 0xf9, 0x31, 0x95, 0xaf, 0x73, 0x2f, 0x99, 0x9e, 0x44, 0x1a, + 0x79, 0xb8, 0xa4, 0x67, 0x24, 0xad, 0x9c, 0xd4, 0xf1, 0x38, 0x49, 0x2f, + 0xe7, 0xca, 0x2f, 0x2a, 0xeb, 0x5b, 0x32, 0x4d, 0x1d, 0x91, 0xc4, 0xfd, + 0x41, 0xd2, 0xd3, 0xf2, 0x38, 0x47, 0x52, 0x47, 0x49, 0x9f, 0x48, 0x3a, + 0x34, 0xe4, 0x3d, 0xab, 0xa4, 0xbc, 0xce, 0xf2, 0xbc, 0x6e, 0x49, 0xdf, + 0xef, 0x11, 0xe2, 0x76, 0x2c, 0x48, 0xff, 0xa4, 0xa4, 0x25, 0x92, 0xeb, + 0xed, 0x42, 0xda, 0x9d, 0x72, 0xe9, 0x6e, 0x91, 0xf4, 0x4a, 0x2e, 0x6e, + 0x19, 0x99, 0x16, 0xa5, 0x71, 0x0b, 0xc9, 0x7d, 0xf8, 0x90, 0xb2, 0xf1, + 0xdb, 0x41, 0x1e, 0x33, 0xdf, 0x2d, 0x78, 0xfe, 0xc9, 0xe1, 0x79, 0x9b, + 0x24, 0x71, 0x1d, 0x25, 0x3d, 0x20, 0x69, 0xe1, 0xe4, 0x5d, 0x7f, 0x95, + 0xcb, 0xd7, 0x27, 0xc4, 0x1f, 0x54, 0xd0, 0x16, 0x9b, 0xc9, 0x34, 0xbf, + 0x6c, 0x0c, 0x96, 0xb5, 0x5d, 0x73, 0x42, 0xb7, 0x50, 0xc7, 0x2e, 0xcd, + 0xcc, 0xd7, 0x1a, 0xcf, 0xae, 0xd5, 0xd7, 0xf5, 0xc2, 0xf5, 0x92, 0xae, + 0x9e, 0x87, 0x67, 0x36, 0x52, 0xff, 0x85, 0x65, 0xfe, 0xa0, 0x91, 0xf8, + 0x46, 0xdb, 0xa3, 0x35, 0xdb, 0xed, 0xeb, 0x10, 0xce, 0xfb, 0x86, 0xb5, + 0x87, 0x72, 0xff, 0x87, 0xd4, 0xb8, 0x2e, 0x0c, 0xed, 0x81, 0x99, 0x78, + 0xd7, 0xff, 0x0a, 0x96, 0xa0, 0x12, 0x7e, 0x5f, 0x4a, 0x78, 0xf8, 0xd5, + 0x81, 0x97, 0xc3, 0xff, 0xd5, 0x42, 0xda, 0x88, 0x73, 0xb1, 0x24, 0xe5, + 0x02, 0xac, 0x76, 0x1a, 0x89, 0x25, 0x20, 0x2b, 0x02, 0xdb, 0x62, 0xe9, + 0xc7, 0xf3, 0x21, 0x6d, 0xaf, 0x24, 0xdf, 0x7a, 0x58, 0xb2, 0x7e, 0x5b, + 0x6e, 0xbf, 0xb0, 0x34, 0x99, 0xda, 0x6a, 0x66, 0xf8, 0xfd, 0xa4, 0x64, + 0x6f, 0x11, 0xeb, 0xbc, 0x1e, 0x96, 0x3c, 0x9d, 0x93, 0xbb, 0x77, 0x27, + 0x96, 0xb4, 0x01, 0xcc, 0x02, 0x96, 0xc3, 0xbb, 0x97, 0x6d, 0x80, 0xef, + 0x61, 0x89, 0xdc, 0x3a, 0xc0, 0x79, 0x05, 0x65, 0xcf, 0xab, 0x2a, 0x31, + 0xc5, 0x6e, 0x64, 0x6a, 0xc5, 0xc3, 0xb1, 0x94, 0xe7, 0x99, 0x70, 0x7d, + 0x19, 0x56, 0x83, 0x2d, 0x8f, 0xdf, 0xb3, 0x37, 0xde, 0x71, 0xe5, 0xb1, + 0x10, 0x6e, 0xbf, 0x7f, 0x86, 0xeb, 0x19, 0xc0, 0x0d, 0x64, 0x6d, 0xba, + 0x08, 0x96, 0xa2, 0xbe, 0x10, 0xae, 0xaf, 0xc0, 0xd2, 0xa9, 0x54, 0xfa, + 0xda, 0x0e, 0xbf, 0xeb, 0x8d, 0xb9, 0xb2, 0x67, 0x52, 0x8c, 0x8e, 0xa1, + 0xde, 0x97, 0x62, 0x95, 0xe4, 0xa7, 0xc9, 0xbd, 0x5e, 0x05, 0xe1, 0x66, + 0x2c, 0x5d, 0x8b, 0x75, 0x7a, 0x38, 0xfc, 0x8e, 0xc7, 0x52, 0x5f, 0x70, + 0xfb, 0xdf, 0x40, 0x36, 0xbe, 0xee, 0xc1, 0x12, 0xad, 0xe3, 0x4a, 0xea, + 0x50, 0x86, 0x0e, 0x58, 0xda, 0x3d, 0x09, 0xf7, 0x67, 0x23, 0xd8, 0x06, + 0x4b, 0xba, 0x8f, 0x08, 0xf9, 0x53, 0xcc, 0xc0, 0xbb, 0xdd, 0xfd, 0x71, + 0xfd, 0x77, 0xc0, 0x12, 0x6f, 0x80, 0x3d, 0xb0, 0xf4, 0xa9, 0x2f, 0x96, + 0x42, 0xa7, 0xed, 0x30, 0x1d, 0x38, 0x10, 0x98, 0x8c, 0xa5, 0x6c, 0x79, + 0xa9, 0x4e, 0x27, 0x2c, 0x01, 0x7d, 0x93, 0xe6, 0x69, 0x08, 0x86, 0xe1, + 0xf6, 0xdf, 0x19, 0xd8, 0x00, 0xf8, 0x33, 0x96, 0x7c, 0xdd, 0x9e, 0xa4, + 0x99, 0x4b, 0x36, 0x8e, 0xca, 0x30, 0x13, 0xab, 0xd8, 0x9e, 0x0b, 0xef, + 0x50, 0x0f, 0x77, 0x63, 0xa9, 0x60, 0x2d, 0xdc, 0x12, 0xd2, 0xac, 0x07, + 0x0c, 0xc7, 0x52, 0x80, 0xeb, 0xa8, 0xd4, 0xc6, 0x3c, 0x1c, 0xea, 0xf7, + 0x65, 0xe3, 0xaf, 0xc0, 0x99, 0x64, 0x34, 0xa8, 0xb9, 0xf8, 0x04, 0x4b, + 0x6b, 0x07, 0x16, 0xdc, 0xdb, 0x8e, 0x72, 0x8d, 0xc9, 0x87, 0x58, 0x9a, + 0x7e, 0x11, 0xa6, 0x73, 0x65, 0xf8, 0x11, 0x70, 0x02, 0x96, 0xb4, 0xa5, + 0xa6, 0x76, 0x17, 0x63, 0xfa, 0x34, 0xbc, 0x4e, 0xfd, 0x9a, 0xb0, 0x9a, + 0xf4, 0x38, 0x4c, 0xd3, 0x86, 0xe2, 0xf1, 0xf8, 0x5a, 0xb8, 0x2f, 0x6c, + 0x1e, 0x31, 0x19, 0xb8, 0xb0, 0x4e, 0x59, 0xff, 0x06, 0xae, 0xc7, 0xe3, + 0x3c, 0x62, 0x20, 0xa6, 0x39, 0x51, 0xe2, 0xfb, 0x39, 0x1e, 0x23, 0xef, + 0x03, 0xef, 0xe1, 0x77, 0x2c, 0xc2, 0x27, 0x98, 0x16, 0xb4, 0x04, 0xf1, + 0x79, 0x3f, 0xcb, 0xc5, 0xaf, 0x87, 0x25, 0xf3, 0x1f, 0x26, 0x71, 0xe3, + 0xb0, 0x34, 0x7b, 0xbb, 0x24, 0x6e, 0x09, 0xac, 0x95, 0x58, 0x15, 0x4b, + 0x6c, 0x23, 0xb6, 0xc3, 0x1a, 0xaf, 0x14, 0x73, 0xb0, 0x74, 0x7e, 0x0b, + 0x32, 0x13, 0xc9, 0x23, 0x70, 0x3b, 0x4c, 0x2d, 0xa8, 0xdb, 0xf9, 0xe1, + 0xf9, 0xa9, 0x69, 0xc3, 0xcf, 0x80, 0x7f, 0xe0, 0xf5, 0x0f, 0xe0, 0x55, + 0xac, 0x09, 0x88, 0x58, 0x1c, 0x8f, 0x83, 0x51, 0x14, 0xf7, 0xe7, 0xa3, + 0x58, 0x3b, 0x3d, 0x3f, 0x4d, 0xea, 0x5e, 0xc6, 0x9a, 0xd8, 0x0f, 0xeb, + 0x25, 0xfc, 0x0f, 0xc3, 0xa6, 0x64, 0xbc, 0xc7, 0xfc, 0xc2, 0x6c, 0x8a, + 0xcf, 0xa7, 0xcd, 0xa6, 0x31, 0x13, 0x9a, 0x36, 0xd4, 0xc7, 0xe6, 0x5f, + 0x76, 0x05, 0xbe, 0x6a, 0x68, 0x8f, 0xd5, 0x7f, 0xef, 0x60, 0xa6, 0x2e, + 0x32, 0x4c, 0x2f, 0x90, 0x4d, 0x88, 0x26, 0xcc, 0xe0, 0x9e, 0x12, 0xfe, + 0x0f, 0xc6, 0x8b, 0x5d, 0x53, 0xb8, 0xbf, 0x12, 0x95, 0xea, 0xfa, 0x67, + 0x31, 0x03, 0xff, 0x06, 0x66, 0xb4, 0x3f, 0x0b, 0x01, 0x32, 0x95, 0xd0, + 0xc2, 0xd8, 0x9c, 0xe5, 0xbf, 0x0b, 0xea, 0x34, 0x18, 0x2f, 0x0e, 0xfd, + 0x31, 0x23, 0x79, 0x35, 0x66, 0x34, 0x7b, 0x61, 0x46, 0x64, 0x36, 0x56, + 0x6f, 0x76, 0x49, 0xea, 0xdc, 0x3f, 0xfc, 0x9f, 0x94, 0x2b, 0xeb, 0x06, + 0x6c, 0xaf, 0x16, 0xcd, 0x59, 0xe6, 0x60, 0x62, 0xdd, 0x15, 0xdb, 0xe1, + 0xf5, 0xc6, 0xea, 0xaa, 0xf9, 0x89, 0xae, 0x58, 0xbd, 0xf5, 0x74, 0xb8, + 0xee, 0x85, 0x99, 0xf3, 0x88, 0xa7, 0x30, 0xa3, 0xb8, 0x75, 0x9d, 0x72, + 0xe6, 0x60, 0x55, 0xf2, 0xc5, 0x49, 0xdc, 0xdc, 0x10, 0x0f, 0x5e, 0x78, + 0xf7, 0x48, 0xee, 0xc5, 0x77, 0x7e, 0x23, 0x89, 0x3b, 0x0a, 0x9b, 0x14, + 0xbc, 0x9a, 0x2b, 0xbb, 0xec, 0x70, 0xcb, 0x01, 0x98, 0xe9, 0x1f, 0x51, + 0xa7, 0x6e, 0x60, 0xd3, 0x9c, 0x63, 0x71, 0x9f, 0x45, 0xc6, 0xa0, 0x77, + 0xf8, 0x5d, 0x15, 0x2f, 0xa2, 0xf1, 0x7f, 0x7e, 0xd1, 0x7b, 0x0c, 0x9b, + 0x4b, 0xdd, 0x8d, 0xc7, 0x4f, 0x6a, 0xd3, 0x5e, 0x14, 0xb7, 0x35, 0x5e, + 0xd0, 0x76, 0x0c, 0xff, 0x47, 0x62, 0x26, 0xa2, 0xa9, 0x46, 0xe8, 0x10, + 0xd2, 0x6d, 0x8d, 0x37, 0x3f, 0x8f, 0x51, 0xde, 0xe6, 0x91, 0x71, 0x5f, + 0x03, 0x6f, 0xe8, 0x46, 0xe0, 0x8d, 0xda, 0x03, 0xa1, 0x1e, 0x97, 0x60, + 0xe6, 0xb3, 0x09, 0xab, 0xa4, 0x85, 0x4d, 0x5b, 0x36, 0xc2, 0x8b, 0x7c, + 0x8a, 0x9d, 0x31, 0x93, 0x75, 0x0b, 0x99, 0x1a, 0xbc, 0x11, 0xc4, 0x74, + 0xef, 0xe2, 0x39, 0xf1, 0x34, 0xc5, 0xe6, 0x17, 0x3b, 0xe1, 0x8d, 0x53, + 0x2d, 0x08, 0x6f, 0x3c, 0x36, 0xa3, 0xd2, 0x94, 0x22, 0x8f, 0x89, 0x78, + 0x0e, 0xdd, 0x5e, 0x23, 0xcd, 0xe3, 0x98, 0x31, 0xbf, 0x1d, 0x9b, 0x3b, + 0x4c, 0x22, 0xdb, 0x30, 0xa6, 0x18, 0x43, 0xb5, 0x9a, 0x78, 0x41, 0xe3, + 0x58, 0xea, 0xbf, 0x4f, 0x3d, 0xcc, 0x06, 0x2e, 0xc7, 0xa6, 0x60, 0xf9, + 0xf7, 0xf9, 0x05, 0x99, 0xd9, 0x43, 0x1e, 0x73, 0x31, 0xc3, 0xdd, 0x9e, + 0x6c, 0xa3, 0x5c, 0x84, 0xa3, 0x30, 0x23, 0xf7, 0x5c, 0xc1, 0xbd, 0xe1, + 0xc0, 0x96, 0xc0, 0x86, 0x75, 0xea, 0x38, 0x15, 0x9f, 0x67, 0x39, 0x12, + 0xcf, 0x95, 0x22, 0x86, 0xf9, 0x52, 0x4c, 0x0b, 0x8b, 0x6c, 0x9b, 0x53, + 0x74, 0xa5, 0x9a, 0x1e, 0x6c, 0x43, 0xa5, 0xa9, 0xcb, 0x4f, 0xf0, 0x7b, + 0x9f, 0x87, 0x37, 0x06, 0x65, 0xf8, 0x51, 0x9d, 0x67, 0x95, 0x61, 0x36, + 0x36, 0xdf, 0xda, 0x83, 0x4a, 0x93, 0xc3, 0x7e, 0x05, 0xcf, 0xfb, 0x0c, + 0x33, 0xdc, 0xa9, 0x40, 0x63, 0x17, 0xbc, 0x21, 0x79, 0x0f, 0xf8, 0x69, + 0x12, 0xbf, 0x03, 0x95, 0x26, 0x52, 0x11, 0xb7, 0x87, 0x70, 0x26, 0x9e, + 0xf3, 0xbb, 0x62, 0x61, 0x53, 0x11, 0x66, 0xe0, 0xf9, 0xdf, 0x8f, 0xec, + 0x0c, 0xd1, 0x00, 0x2a, 0xcf, 0x38, 0xad, 0x8a, 0x05, 0x12, 0x11, 0x67, + 0x60, 0x3a, 0x52, 0xb4, 0xc1, 0x03, 0xcf, 0xcf, 0xbb, 0x30, 0xad, 0x68, + 0x04, 0x7f, 0xc4, 0x1b, 0x92, 0x7a, 0x7d, 0x99, 0xc7, 0x0c, 0xbc, 0xb9, + 0x02, 0x0b, 0x4b, 0x6e, 0xc4, 0xc2, 0x91, 0x29, 0xa1, 0xcc, 0x32, 0x73, + 0x91, 0x65, 0xf0, 0xe6, 0xe2, 0x6e, 0x4c, 0xdb, 0x8f, 0x4f, 0xee, 0x6d, + 0x8e, 0x37, 0x1d, 0x0f, 0xe1, 0x7e, 0xf8, 0x75, 0x72, 0x6f, 0x0f, 0x4c, + 0xb7, 0xee, 0xc7, 0x82, 0xa3, 0xef, 0x15, 0x94, 0xbd, 0x1e, 0x16, 0xea, + 0x8c, 0xc6, 0x63, 0xf7, 0x22, 0x4c, 0xfb, 0x36, 0xc4, 0x7d, 0xb2, 0x0a, + 0xde, 0x34, 0x35, 0xe1, 0x35, 0x3b, 0xc5, 0x31, 0x78, 0xdd, 0x7f, 0x28, + 0xe4, 0x3f, 0x10, 0xcf, 0xd5, 0x23, 0x73, 0xe9, 0x3a, 0x63, 0x13, 0xa6, + 0x6b, 0x30, 0xbf, 0x73, 0x13, 0x19, 0xd3, 0xdd, 0x13, 0xcf, 0xcf, 0xf7, + 0x72, 0x79, 0x76, 0x0f, 0xf5, 0x7a, 0x97, 0x72, 0x5c, 0x8b, 0x37, 0xa1, + 0xaf, 0x51, 0x3e, 0x5e, 0xc0, 0x66, 0xa0, 0xe7, 0x63, 0x01, 0xc1, 0x40, + 0xbc, 0x81, 0xbe, 0x0f, 0x0b, 0x4e, 0x06, 0x62, 0x81, 0xd0, 0xd5, 0xd8, + 0xec, 0xf5, 0x4e, 0xb2, 0x31, 0x9f, 0xe6, 0x1b, 0x00, 0xfc, 0x01, 0x6f, + 0x1a, 0xdf, 0xc6, 0x9b, 0xc1, 0x74, 0xe3, 0xb0, 0x15, 0x1e, 0xdb, 0x63, + 0x31, 0x7d, 0x3e, 0x33, 0x29, 0xa7, 0x1b, 0x5e, 0x23, 0x26, 0x61, 0x7a, + 0x33, 0x02, 0xf7, 0xd9, 0x2b, 0xd8, 0x3c, 0x2c, 0xa2, 0x2f, 0xde, 0xc4, + 0x8f, 0x0b, 0xcf, 0xd9, 0x9d, 0x4a, 0x41, 0x4d, 0x47, 0x3c, 0xee, 0x1f, + 0xc4, 0x63, 0xf5, 0xa0, 0xf0, 0x0e, 0x23, 0xb0, 0x00, 0xf7, 0x5e, 0xdc, + 0x17, 0x13, 0xc9, 0x04, 0xa5, 0x9b, 0xe0, 0xf5, 0xa1, 0x07, 0xe6, 0xd3, + 0x9a, 0x30, 0xdf, 0xd7, 0x19, 0x9b, 0x88, 0x5e, 0x4c, 0xc6, 0xb7, 0x2c, + 0x1e, 0xe2, 0x2e, 0x49, 0xe2, 0xc6, 0xe2, 0xf9, 0xf1, 0x6f, 0xdc, 0x4f, + 0x4b, 0xe3, 0xf1, 0xf4, 0x19, 0x9e, 0x33, 0xf1, 0xfe, 0x54, 0x3c, 0xf6, + 0xb6, 0xc2, 0x63, 0x2e, 0x9a, 0x1a, 0xae, 0x1e, 0xea, 0xf7, 0x41, 0xa8, + 0xd7, 0xd2, 0x58, 0xa0, 0xfc, 0x01, 0x16, 0xb2, 0x9d, 0x84, 0x85, 0x27, + 0x93, 0xf0, 0xc6, 0xf5, 0xa4, 0xd0, 0xae, 0x0f, 0x27, 0xcf, 0x1d, 0x81, + 0x85, 0xcd, 0xe3, 0xc3, 0x73, 0xa3, 0x49, 0xe0, 0x13, 0x64, 0xfc, 0xc5, + 0x4c, 0x2c, 0xc4, 0x69, 0x3d, 0x48, 0x1a, 0x2d, 0x69, 0x9b, 0x3a, 0x22, + 0xf6, 0x7f, 0x24, 0xff, 0x6f, 0xcc, 0xdd, 0xbb, 0x55, 0x56, 0xfb, 0x0e, + 0x91, 0xf4, 0x7a, 0xee, 0xde, 0x9b, 0xb2, 0xda, 0xb3, 0x73, 0x10, 0xe5, + 0x1f, 0x12, 0xe2, 0x4f, 0x93, 0x55, 0x97, 0xd7, 0xc9, 0xea, 0xc4, 0x9f, + 0xe7, 0xf2, 0x9d, 0x13, 0xd2, 0xff, 0x2e, 0x17, 0xbf, 0xa8, 0x6c, 0x8e, + 0x92, 0xaf, 0xdf, 0x63, 0xca, 0x4c, 0x61, 0xd2, 0x10, 0xcd, 0x62, 0x52, + 0xd3, 0x99, 0x97, 0x64, 0x95, 0x64, 0x67, 0x49, 0x4f, 0xd4, 0x51, 0x4b, + 0xb4, 0x86, 0x1a, 0xe6, 0x20, 0x49, 0xe7, 0x26, 0xd7, 0x1f, 0x4a, 0x3a, + 0x3d, 0xb9, 0x5e, 0x24, 0x3c, 0xeb, 0x98, 0x16, 0x3c, 0xff, 0x61, 0xd9, + 0x74, 0x28, 0x1f, 0xdf, 0x49, 0x56, 0x4d, 0x8f, 0x56, 0xa6, 0x6a, 0xed, + 0x2e, 0xe9, 0x9f, 0xb2, 0xea, 0x76, 0x48, 0x28, 0x3f, 0xa6, 0x7f, 0x47, + 0x36, 0xe3, 0x78, 0x54, 0xd2, 0x9d, 0x92, 0x7e, 0x12, 0xe2, 0x9b, 0x24, + 0x5d, 0x26, 0xe9, 0x8f, 0xb2, 0x49, 0xcd, 0x04, 0x49, 0x83, 0x55, 0x69, + 0xee, 0x11, 0xc3, 0x60, 0xd9, 0x24, 0x27, 0xbe, 0xd3, 0xe3, 0xb2, 0x5a, + 0x7e, 0x50, 0xa8, 0x67, 0x34, 0x3d, 0xc9, 0xab, 0xcd, 0x91, 0xfb, 0x79, + 0x8e, 0xa4, 0xe7, 0x64, 0x73, 0x80, 0xa5, 0x93, 0x7b, 0x69, 0xdc, 0x77, + 0xe4, 0x7e, 0x7e, 0x4a, 0xd2, 0xb6, 0xf3, 0xd8, 0x2f, 0xdb, 0x86, 0x72, + 0xae, 0x50, 0xa6, 0xee, 0xef, 0x2a, 0x8f, 0xcd, 0xb7, 0x42, 0x3f, 0x7d, + 0x2f, 0xf4, 0xd5, 0x0c, 0x79, 0xbc, 0xb4, 0x97, 0xcd, 0x88, 0xa2, 0x2a, + 0x7f, 0x7f, 0x59, 0xed, 0x8a, 0xa4, 0xa5, 0x42, 0x9b, 0xe6, 0x4d, 0xa4, + 0xae, 0x96, 0xcd, 0xba, 0x76, 0x0a, 0xf7, 0xfb, 0x96, 0xd4, 0x47, 0xaa, + 0x34, 0x09, 0xb8, 0x28, 0xb4, 0x61, 0x67, 0xd9, 0x64, 0xe6, 0x82, 0x06, + 0xdf, 0x2b, 0x2d, 0x27, 0x0d, 0x5d, 0xc3, 0xbd, 0x41, 0x35, 0xd2, 0xce, + 0x68, 0xa0, 0xbc, 0x77, 0x92, 0xff, 0x6f, 0x34, 0xa3, 0x5e, 0xb5, 0xea, + 0x96, 0x1f, 0x8f, 0x8d, 0xcc, 0x81, 0xb2, 0x7b, 0x31, 0x7e, 0x1b, 0x49, + 0x1f, 0xa9, 0xb6, 0x1a, 0xbf, 0x56, 0xf9, 0x31, 0x4c, 0x91, 0xc7, 0x81, + 0x24, 0xfd, 0x34, 0x89, 0x5f, 0x59, 0xd2, 0xdf, 0x6a, 0xd4, 0x7d, 0x4a, + 0xf8, 0xfd, 0x79, 0xb8, 0x7f, 0x42, 0xc1, 0x3d, 0xe4, 0x39, 0x72, 0x5e, + 0xc9, 0xb3, 0x97, 0x0d, 0x79, 0x0f, 0xab, 0x53, 0xe7, 0x5b, 0x65, 0x3a, + 0xfa, 0xa2, 0xa4, 0xbf, 0x96, 0x94, 0xb5, 0x62, 0xc8, 0x7b, 0x40, 0x8d, + 0xb2, 0x76, 0x93, 0xf4, 0xa9, 0x2a, 0xc7, 0xf0, 0x69, 0x21, 0xdd, 0x64, + 0xd9, 0x74, 0x6e, 0x89, 0x82, 0xb2, 0xe7, 0xa5, 0xbf, 0xca, 0xda, 0x6f, + 0xf3, 0x10, 0xbf, 0x47, 0x12, 0x97, 0x37, 0x69, 0x89, 0xe1, 0x50, 0xd9, + 0x84, 0x66, 0xf9, 0x70, 0x7d, 0x9d, 0xdc, 0x3f, 0x97, 0x4a, 0x9a, 0x94, + 0xa4, 0x7b, 0x4a, 0x36, 0x59, 0x29, 0xaa, 0xdf, 0x5a, 0x92, 0x66, 0xcb, + 0x73, 0x3f, 0x6f, 0x0a, 0x98, 0x0f, 0xdf, 0x96, 0x4d, 0x89, 0x4e, 0x97, + 0xe7, 0xf5, 0xa9, 0x35, 0xd2, 0xf6, 0x90, 0xcd, 0x0b, 0x8f, 0xab, 0xd3, + 0x16, 0x7d, 0x24, 0x5d, 0xd5, 0x40, 0xdb, 0xad, 0x2b, 0xd3, 0xd0, 0xa3, + 0x55, 0xbd, 0x16, 0x37, 0x1a, 0xba, 0x48, 0x7a, 0x2f, 0xa9, 0x77, 0x8f, + 0xf0, 0x8c, 0x3e, 0x25, 0xcf, 0x1e, 0xab, 0xcc, 0x1c, 0x70, 0x53, 0x99, + 0x56, 0xf7, 0x97, 0xd7, 0xd1, 0x4f, 0x94, 0xad, 0xaf, 0x2b, 0x84, 0xf4, + 0x07, 0xc9, 0xe6, 0x46, 0x73, 0x24, 0xf5, 0x0e, 0xf7, 0x3a, 0xcb, 0x6b, + 0xb7, 0x92, 0xb2, 0xd7, 0x95, 0x4d, 0x62, 0xb7, 0x08, 0xd7, 0x8b, 0xc9, + 0x34, 0x2f, 0x1d, 0xc3, 0x45, 0x6d, 0x15, 0xdb, 0x4b, 0x92, 0x76, 0x0e, + 0xd7, 0xdb, 0xc8, 0xfd, 0xb7, 0xaf, 0x2a, 0xcd, 0x91, 0x24, 0x8f, 0x81, + 0x68, 0x1e, 0xb6, 0x59, 0x88, 0x8b, 0xe3, 0x6a, 0xb0, 0xbc, 0xae, 0xa5, + 0xf5, 0x42, 0x36, 0xe3, 0x1d, 0x53, 0x10, 0x9f, 0xd6, 0x67, 0x67, 0xd9, + 0x9c, 0xb6, 0x68, 0x3d, 0x4c, 0xd3, 0x2d, 0xa9, 0x8c, 0xfe, 0x3f, 0x2a, + 0x9b, 0x8f, 0x21, 0x9b, 0x5e, 0xcd, 0x91, 0x4d, 0x16, 0x51, 0x66, 0xfe, + 0xbb, 0x77, 0x41, 0xbe, 0x27, 0x64, 0x53, 0x5d, 0x94, 0x99, 0x8d, 0xc6, + 0x77, 0xe8, 0x21, 0xd3, 0xba, 0x2d, 0xc3, 0xf5, 0x42, 0xa1, 0xec, 0x1b, + 0x92, 0x77, 0x3e, 0x25, 0xe4, 0xb9, 0x47, 0xd9, 0xfa, 0xda, 0x43, 0xe6, + 0xdd, 0xf6, 0x93, 0xcd, 0x4a, 0xe7, 0x28, 0xe3, 0x05, 0x17, 0x97, 0xd7, + 0xfc, 0xf4, 0xfd, 0xf7, 0x97, 0x4d, 0xdc, 0x24, 0xd3, 0xfd, 0xe1, 0x72, + 0x9f, 0x9e, 0x1e, 0xde, 0x2b, 0x9a, 0x15, 0xaf, 0x2f, 0xd3, 0x91, 0x5a, + 0xf3, 0xbf, 0x43, 0x78, 0x56, 0x1a, 0x5f, 0x14, 0x87, 0xa4, 0x67, 0x55, + 0xc9, 0xf7, 0x2d, 0x16, 0x9e, 0x17, 0xaf, 0xff, 0xa5, 0x4a, 0x93, 0xe6, + 0x03, 0x42, 0x19, 0x3f, 0x4c, 0xe2, 0x26, 0x84, 0x7c, 0xf1, 0x7a, 0xaf, + 0xf0, 0xee, 0x9b, 0x86, 0xeb, 0xf3, 0x25, 0xed, 0x9a, 0xab, 0xf3, 0x73, + 0x72, 0xff, 0xc6, 0xeb, 0xc8, 0xd7, 0xc4, 0xf7, 0x89, 0xfd, 0xb8, 0xbe, + 0x3c, 0xf6, 0xe2, 0xda, 0xba, 0x84, 0xcc, 0x3f, 0x94, 0xbd, 0xfb, 0x7b, + 0x32, 0x4f, 0x85, 0x6c, 0xba, 0xf7, 0xa0, 0x3c, 0x97, 0x57, 0x49, 0xd2, + 0x5c, 0xda, 0x3e, 0xec, 0x0c, 0xde, 0xae, 0xc3, 0xc3, 0xa7, 0x3b, 0xea, + 0xbc, 0xfa, 0xa7, 0x3f, 0x96, 0x0a, 0x9e, 0x82, 0x77, 0x7a, 0xa3, 0xf1, + 0x6e, 0x18, 0xbc, 0x63, 0xda, 0x00, 0x1f, 0xc8, 0x99, 0x8b, 0x77, 0xe9, + 0x3d, 0xb0, 0xa4, 0x7d, 0x27, 0xac, 0x7e, 0x3c, 0x12, 0x9b, 0x76, 0xac, + 0x8a, 0xa5, 0x33, 0x23, 0xf0, 0xee, 0xfe, 0x58, 0xac, 0x3a, 0xec, 0x99, + 0x3c, 0xab, 0x2f, 0xde, 0xd1, 0xe5, 0xb1, 0x06, 0xd9, 0x61, 0xcb, 0x14, + 0x53, 0x93, 0xfb, 0x11, 0xab, 0x63, 0xa9, 0xe9, 0x27, 0x54, 0xaa, 0x3c, + 0x37, 0xa7, 0xfa, 0x40, 0x64, 0xff, 0xe4, 0xfa, 0x22, 0x5a, 0x86, 0xdd, + 0x70, 0xfb, 0x44, 0x74, 0x26, 0x93, 0x76, 0x43, 0xa6, 0x0a, 0x6d, 0xae, + 0x07, 0x94, 0x1f, 0xe1, 0x76, 0x3e, 0x31, 0x17, 0x7f, 0x33, 0x96, 0x26, + 0x6c, 0x82, 0x0f, 0x27, 0xcd, 0xc6, 0x3b, 0xde, 0x8b, 0xc8, 0x0e, 0x2b, + 0xe5, 0xf1, 0x6d, 0x2c, 0x85, 0xde, 0x0c, 0x4b, 0x97, 0xaf, 0xc7, 0x3b, + 0xf5, 0x0d, 0x80, 0xb5, 0xf1, 0x4e, 0x73, 0x07, 0x6c, 0x7e, 0x73, 0x42, + 0x08, 0x29, 0x3a, 0x63, 0xb5, 0x7a, 0x34, 0x0f, 0xfa, 0x0c, 0x4b, 0x89, + 0x3f, 0xc2, 0x3b, 0xff, 0xe7, 0xb0, 0x59, 0x11, 0x58, 0x82, 0xdb, 0x17, + 0x4b, 0x04, 0xc1, 0x63, 0x60, 0x03, 0xac, 0xbd, 0xd9, 0x08, 0x8f, 0x83, + 0xd4, 0xcc, 0x26, 0x8d, 0x7b, 0x2e, 0xfc, 0x6e, 0x8c, 0x77, 0xfe, 0xf3, + 0x82, 0x51, 0xa1, 0x9c, 0xe9, 0x64, 0x52, 0xcb, 0xe1, 0x58, 0xda, 0x39, + 0x1c, 0x8f, 0xd9, 0xc9, 0x58, 0x8a, 0x76, 0x1f, 0x1e, 0x2f, 0x03, 0x43, + 0x5d, 0x63, 0x9b, 0xaf, 0x81, 0xc7, 0x12, 0x58, 0x92, 0x05, 0x95, 0x87, + 0x7b, 0x17, 0xc5, 0xd2, 0xa2, 0x89, 0xa1, 0x8c, 0x0f, 0xa9, 0x6d, 0xda, + 0xd2, 0x1f, 0xef, 0xca, 0xa7, 0x61, 0xc9, 0x51, 0xdf, 0xf0, 0xdc, 0xe5, + 0x28, 0x37, 0x3d, 0x6a, 0x14, 0x33, 0xc2, 0xef, 0xd2, 0xb9, 0xf8, 0xfe, + 0x64, 0x63, 0xbc, 0x4c, 0xad, 0x9e, 0xa6, 0x59, 0x36, 0x89, 0xef, 0x5a, + 0x50, 0xaf, 0x65, 0xb0, 0xf9, 0x40, 0x1a, 0xca, 0xca, 0x8a, 0xa1, 0x7f, + 0xad, 0x8a, 0xb7, 0x00, 0x2b, 0xe1, 0xc3, 0xe0, 0xef, 0x53, 0x7d, 0x28, + 0xbc, 0x25, 0x98, 0x8c, 0x35, 0x01, 0x87, 0x26, 0x71, 0x87, 0x51, 0xdb, + 0x23, 0x54, 0xc4, 0x15, 0xd8, 0x9c, 0xe8, 0x54, 0x8a, 0x0f, 0xf7, 0x2d, + 0x43, 0xb9, 0xe6, 0x2a, 0xb6, 0x6d, 0xd9, 0x21, 0xb4, 0x4e, 0x58, 0xab, + 0xf2, 0x43, 0x2c, 0x11, 0xfb, 0x2e, 0xa6, 0xe7, 0x45, 0x88, 0xf1, 0xdf, + 0xc9, 0xc5, 0xf7, 0xc7, 0x92, 0xa8, 0xe9, 0x78, 0x9e, 0xef, 0x4e, 0xa5, + 0x99, 0xdf, 0xc9, 0xb8, 0x0d, 0x57, 0xc2, 0x26, 0x42, 0x53, 0xf1, 0xf8, + 0xcf, 0x9b, 0x85, 0xb5, 0x36, 0x1e, 0xc1, 0xde, 0xb8, 0xf6, 0x09, 0xd7, + 0xeb, 0x61, 0x49, 0x5f, 0x91, 0x59, 0xc6, 0x1d, 0x78, 0x8d, 0xda, 0x16, + 0xd3, 0xa2, 0xef, 0x60, 0x69, 0xe6, 0x75, 0xf8, 0x50, 0xe0, 0x9a, 0x40, + 0x77, 0x7c, 0x60, 0xb3, 0xcc, 0xd4, 0xea, 0x79, 0xdc, 0x57, 0x5d, 0x4a, + 0x9e, 0x91, 0xe2, 0x2d, 0xbc, 0x66, 0x1d, 0x82, 0xd7, 0xa8, 0x22, 0xb3, + 0x48, 0xb0, 0x04, 0x6e, 0x18, 0x96, 0xb0, 0x0d, 0xad, 0x53, 0xe6, 0x28, + 0x4c, 0xd3, 0xeb, 0x69, 0x9b, 0x2e, 0xc4, 0x6b, 0xe3, 0x39, 0x98, 0x6e, + 0xef, 0x54, 0x27, 0x7d, 0x11, 0x16, 0xc5, 0xa6, 0x84, 0x97, 0x87, 0xeb, + 0xa8, 0x69, 0xd9, 0xa0, 0x24, 0xfd, 0x7d, 0x98, 0x3e, 0xc7, 0xb4, 0x77, + 0x60, 0x93, 0xc2, 0xdf, 0x61, 0xc9, 0x65, 0x34, 0x4d, 0x9d, 0x86, 0xc7, + 0xd0, 0x6c, 0x3c, 0x66, 0xee, 0x25, 0x33, 0x23, 0xfa, 0x84, 0x6a, 0x8d, + 0xce, 0x19, 0x58, 0xfa, 0x19, 0xcd, 0x1f, 0x3f, 0xc6, 0x63, 0xb1, 0x2f, + 0xf5, 0xb1, 0x6e, 0xf8, 0x6d, 0x0a, 0xbf, 0x0f, 0xe3, 0xf6, 0x5e, 0x89, + 0x6a, 0xcd, 0xec, 0xf5, 0x64, 0x34, 0xfe, 0x89, 0xf0, 0xdb, 0x3d, 0xfc, + 0xfe, 0x2f, 0xc5, 0x9a, 0xbf, 0x4b, 0x31, 0x2f, 0x53, 0x86, 0x1e, 0x58, + 0x72, 0x7f, 0x20, 0xf5, 0x5d, 0x36, 0x7f, 0x80, 0x25, 0xe2, 0xe0, 0xb6, + 0x8a, 0x73, 0x71, 0x22, 0xee, 0xef, 0xcb, 0xc2, 0x75, 0x34, 0x51, 0x5c, + 0xa3, 0x20, 0xdf, 0xcd, 0x64, 0xe6, 0xc4, 0xb1, 0x1d, 0xe3, 0x3b, 0x9c, + 0x4e, 0xa6, 0xbd, 0x00, 0xf3, 0x17, 0xa7, 0x62, 0xe9, 0xf3, 0x16, 0xb8, + 0xaf, 0x4f, 0x0d, 0xf7, 0x1e, 0x20, 0xa3, 0x2b, 0xe3, 0x43, 0xf9, 0x47, + 0x91, 0xf5, 0x57, 0x7c, 0xe7, 0x8f, 0xb0, 0x84, 0x3c, 0xc5, 0x95, 0x64, + 0xbc, 0xdd, 0x76, 0x78, 0x3d, 0xdc, 0x05, 0x3b, 0xa2, 0x58, 0x07, 0x5b, + 0x4c, 0x74, 0xc6, 0xf4, 0xb2, 0x9e, 0x16, 0x68, 0x2e, 0xd5, 0xed, 0x5b, + 0x14, 0x07, 0x36, 0xe9, 0xdc, 0x91, 0xcc, 0x84, 0x70, 0x57, 0x2a, 0xf9, + 0xc0, 0x91, 0x98, 0x6e, 0xc5, 0xb9, 0xb3, 0x27, 0x6e, 0xdb, 0x78, 0x50, + 0xbe, 0x1b, 0xb6, 0x16, 0xf8, 0x38, 0xc9, 0x73, 0x3d, 0xd6, 0xa0, 0xfc, + 0x25, 0xbc, 0x43, 0xd1, 0xc1, 0xff, 0xe1, 0x98, 0x7f, 0x5b, 0x22, 0x5c, + 0xef, 0x40, 0x36, 0x56, 0xce, 0xc2, 0xfd, 0xd8, 0x01, 0x8f, 0x95, 0xfb, + 0xb1, 0x16, 0xa0, 0x2b, 0xa6, 0x23, 0x23, 0x0a, 0xde, 0x23, 0xe2, 0x44, + 0xcc, 0x07, 0xf4, 0xc3, 0x1a, 0xab, 0x7d, 0xf1, 0x9c, 0x1e, 0x81, 0xfb, + 0x7e, 0x65, 0x60, 0xb3, 0xf6, 0x58, 0x6d, 0xf3, 0x4e, 0x71, 0x19, 0xff, + 0x8f, 0x94, 0x39, 0xcf, 0x33, 0x77, 0xd3, 0xb1, 0xea, 0x70, 0x6d, 0xdc, + 0xe9, 0xdd, 0xf1, 0x84, 0x5d, 0x11, 0xab, 0xbf, 0x3e, 0xc6, 0x13, 0xf6, + 0xbf, 0xb0, 0x4d, 0xe5, 0x6f, 0xb0, 0xea, 0x60, 0x37, 0xdc, 0x80, 0xcf, + 0xe0, 0x46, 0xdd, 0x11, 0x13, 0x9c, 0x6e, 0x98, 0xd1, 0xfb, 0x53, 0x78, + 0xd9, 0xdb, 0x30, 0xd3, 0x48, 0x78, 0x99, 0x6b, 0x0a, 0xea, 0xb7, 0x38, + 0x95, 0x76, 0xc0, 0x11, 0xb3, 0x92, 0xfb, 0xf5, 0xf0, 0x08, 0x95, 0xf6, + 0xd3, 0xe0, 0xc6, 0x8a, 0xd7, 0x83, 0x0a, 0xf2, 0x34, 0x51, 0xcd, 0xd0, + 0xa7, 0xe8, 0x84, 0xeb, 0x3e, 0x26, 0x89, 0xfb, 0x84, 0x4a, 0x75, 0xd4, + 0xc2, 0x49, 0x7c, 0xa3, 0x58, 0x1c, 0x0f, 0xd8, 0x83, 0xc9, 0x6c, 0xcc, + 0x23, 0x76, 0xc7, 0x04, 0xea, 0x70, 0xdc, 0x0f, 0x07, 0x63, 0x66, 0xfa, + 0x46, 0xca, 0x6d, 0xf7, 0xe2, 0x82, 0x25, 0x3c, 0xb0, 0x6e, 0x08, 0x79, + 0x16, 0x0f, 0x75, 0x8f, 0x66, 0x2a, 0xff, 0xc2, 0xea, 0xb4, 0x43, 0x72, + 0xf9, 0x0f, 0x0d, 0xf5, 0x8f, 0x9b, 0x90, 0xe8, 0x71, 0x67, 0x5f, 0x6c, + 0x3a, 0xd2, 0x0b, 0x13, 0x85, 0x25, 0xf0, 0xe2, 0x72, 0x24, 0xee, 0xdf, + 0x31, 0x78, 0xc1, 0x5f, 0x11, 0xb7, 0xff, 0x27, 0x54, 0x33, 0x7b, 0x69, + 0xdc, 0x01, 0x78, 0x31, 0x3a, 0x97, 0x4a, 0x26, 0x11, 0x1a, 0x33, 0x6b, + 0x49, 0xb1, 0x0c, 0x1e, 0x6f, 0x7d, 0xc8, 0xbc, 0x18, 0xcc, 0xc4, 0x6a, + 0xb1, 0x13, 0xc8, 0x08, 0xe1, 0x9a, 0x64, 0xe6, 0x5e, 0x87, 0x62, 0x55, + 0x6b, 0xdc, 0x50, 0xad, 0x47, 0xc6, 0x9c, 0x7f, 0x3b, 0xfc, 0xbe, 0x9e, + 0x3c, 0x23, 0x7a, 0xcd, 0x20, 0xe4, 0xb9, 0x13, 0xf8, 0x31, 0x95, 0x0c, + 0x7c, 0x8a, 0x11, 0xd8, 0xbb, 0xc5, 0x32, 0x78, 0xd1, 0x98, 0x80, 0x99, + 0x93, 0x19, 0xcc, 0xbb, 0x3d, 0x6a, 0x64, 0xca, 0xa7, 0xe7, 0xe2, 0x47, + 0x90, 0x8d, 0xf1, 0x57, 0x28, 0x46, 0x9a, 0x26, 0x3d, 0x8b, 0x32, 0x9d, + 0x6a, 0x66, 0x7f, 0x11, 0x4c, 0x03, 0x4e, 0xc0, 0x9b, 0xf1, 0x35, 0x72, + 0xf7, 0xd3, 0xb2, 0x62, 0x18, 0x51, 0xab, 0xe2, 0x2d, 0xc0, 0x6e, 0x98, + 0xde, 0x0c, 0xc1, 0x1b, 0xd2, 0xd5, 0x5a, 0xa1, 0xcc, 0x4b, 0xf0, 0x82, + 0xb4, 0x3a, 0x7e, 0xc7, 0xcd, 0x68, 0xdc, 0x2d, 0xdc, 0x20, 0xbc, 0x38, + 0x8c, 0xa4, 0x7a, 0x13, 0x3e, 0x93, 0xf2, 0xbe, 0x8d, 0x6d, 0x9b, 0x57, + 0xb9, 0xf7, 0xc7, 0x0b, 0xe9, 0xad, 0xc0, 0x92, 0x98, 0x01, 0x7d, 0x04, + 0x33, 0x09, 0x65, 0x36, 0xb2, 0x31, 0x3e, 0xcf, 0x48, 0x8c, 0xc0, 0x73, + 0x74, 0xc3, 0x50, 0xb7, 0xbc, 0x6d, 0xa8, 0xb0, 0x39, 0xc1, 0x0a, 0xb8, + 0x4d, 0x5f, 0xc7, 0x26, 0x89, 0x7f, 0x2c, 0x79, 0x4e, 0x2d, 0x14, 0x31, + 0xf4, 0x0b, 0x51, 0xce, 0x30, 0x5f, 0x8e, 0x17, 0xce, 0xc5, 0x29, 0x36, + 0x69, 0x89, 0x78, 0x15, 0x9b, 0x44, 0x6c, 0x8f, 0xe7, 0xdc, 0x3d, 0x21, + 0x7e, 0x14, 0x9e, 0x3b, 0x7b, 0xe2, 0x85, 0xf5, 0x9e, 0xc2, 0xdc, 0xc6, + 0xb2, 0x98, 0x6e, 0xbe, 0x8f, 0x69, 0x53, 0x3d, 0x9c, 0x15, 0xf2, 0xbc, + 0x42, 0xf5, 0x9c, 0x8a, 0x38, 0x1e, 0xcf, 0x85, 0x5f, 0x50, 0xff, 0xfc, + 0xc5, 0xa7, 0x78, 0xbe, 0xf7, 0xac, 0x91, 0x66, 0x1f, 0xcc, 0xb0, 0xdd, + 0x84, 0xfb, 0xe5, 0x30, 0xcc, 0xf4, 0x37, 0xd7, 0x7c, 0x6c, 0x1a, 0x5e, + 0x6f, 0xdf, 0xc3, 0xeb, 0xc3, 0x9f, 0x43, 0xfc, 0xc2, 0xa5, 0x39, 0x2a, + 0x31, 0x19, 0xd3, 0xbe, 0xad, 0xb1, 0x87, 0xa5, 0x14, 0xbf, 0xc2, 0xe3, + 0x7c, 0x73, 0x2a, 0xcd, 0x37, 0x8b, 0xd0, 0x0b, 0xd3, 0xdb, 0xa6, 0x10, + 0xc6, 0xe1, 0xfe, 0x7e, 0xa3, 0x34, 0x47, 0x86, 0x3b, 0xb0, 0x10, 0x28, + 0x7a, 0x34, 0xeb, 0x87, 0xdb, 0xa4, 0xde, 0x39, 0x87, 0x68, 0xd6, 0x33, + 0x2f, 0x1e, 0xda, 0xd6, 0xc6, 0x6b, 0xe4, 0x5a, 0xcc, 0xdb, 0x26, 0xf5, + 0xf3, 0xdc, 0x75, 0x1c, 0x23, 0xf5, 0xec, 0xdc, 0xf3, 0xef, 0xb0, 0x05, + 0xee, 0x93, 0x14, 0x91, 0xd1, 0xff, 0x41, 0x9d, 0xb2, 0x26, 0xe1, 0xbe, + 0xdc, 0x8c, 0xfa, 0xfd, 0x95, 0xe2, 0x26, 0x2a, 0x85, 0x8c, 0x67, 0x60, + 0x33, 0xd6, 0x57, 0xf1, 0xdc, 0x28, 0x32, 0xd3, 0x6b, 0x29, 0x2e, 0xc7, + 0xef, 0x1c, 0x37, 0xea, 0x7b, 0x52, 0x79, 0x7e, 0x6a, 0x24, 0x16, 0x60, + 0xf5, 0xc4, 0x0c, 0xfc, 0x2c, 0xcc, 0x3b, 0xf6, 0xc5, 0x63, 0x7a, 0x77, + 0x8a, 0x85, 0xba, 0x87, 0x63, 0xb3, 0xa9, 0xdf, 0x53, 0x69, 0x8e, 0x15, + 0xf1, 0xb7, 0x90, 0x3f, 0x9a, 0xc6, 0xed, 0x49, 0x66, 0xc6, 0x18, 0x4d, + 0xbb, 0x8e, 0xc1, 0x1b, 0x93, 0xe8, 0x01, 0xaf, 0x5d, 0x08, 0xb5, 0x36, + 0x6c, 0xb1, 0x9f, 0xdb, 0xe1, 0x8d, 0xd6, 0x14, 0xcc, 0x9b, 0xed, 0x87, + 0xcd, 0x91, 0xae, 0x01, 0x7e, 0xdd, 0x1e, 0x33, 0xe6, 0x65, 0xc4, 0xa5, + 0x09, 0x0f, 0xf6, 0x2d, 0xc2, 0xff, 0x07, 0xb0, 0xc4, 0xb3, 0xa9, 0x20, + 0xed, 0xf3, 0x98, 0xb0, 0xed, 0x8a, 0x17, 0x95, 0x3d, 0xc9, 0x18, 0xf7, + 0x1e, 0x78, 0x17, 0x72, 0x7a, 0x08, 0xb3, 0xf0, 0x0e, 0x63, 0x16, 0x19, + 0x03, 0xbd, 0x1c, 0x96, 0xcc, 0x8e, 0x4d, 0xca, 0x1c, 0x4c, 0x66, 0x0f, + 0x78, 0x7c, 0xf8, 0x2d, 0x62, 0xc2, 0x3f, 0xa4, 0xd8, 0xf5, 0x5d, 0xe7, + 0xe4, 0xfe, 0xfc, 0x40, 0x2f, 0xaa, 0x19, 0xfa, 0x14, 0xdb, 0xe2, 0xf7, + 0x49, 0x27, 0xe1, 0x14, 0xfc, 0xae, 0x11, 0xcb, 0x27, 0xf1, 0x8d, 0xa0, + 0x3d, 0x1e, 0x98, 0xc3, 0x28, 0xde, 0xa8, 0x44, 0x8c, 0xc5, 0x83, 0xf6, + 0x4c, 0xdc, 0xae, 0x7b, 0x51, 0x2d, 0xa9, 0x6c, 0x2a, 0xc9, 0xfb, 0x02, + 0xde, 0xbd, 0xbd, 0x4b, 0xf5, 0x81, 0xb7, 0xb7, 0xc8, 0x18, 0x51, 0xb0, + 0x14, 0x66, 0x30, 0x66, 0xba, 0xe3, 0x80, 0x1c, 0x89, 0x77, 0xdd, 0xe3, + 0xf1, 0x6e, 0xfe, 0xa7, 0x78, 0x00, 0xc7, 0x03, 0x5e, 0x97, 0xe2, 0x71, + 0xd4, 0x13, 0x33, 0xc6, 0x2b, 0xe2, 0x89, 0x50, 0x0f, 0x37, 0x61, 0xc6, + 0x7f, 0x3a, 0xb6, 0x2b, 0x3b, 0x92, 0x6c, 0x61, 0xfa, 0x0b, 0xc5, 0x87, + 0x54, 0x63, 0x88, 0x13, 0xa2, 0x63, 0xc8, 0xf7, 0x34, 0x5e, 0xb8, 0xd7, + 0x0f, 0xe5, 0x82, 0x17, 0xa9, 0x0f, 0x6a, 0x3c, 0x7f, 0x1d, 0x2a, 0x25, + 0x93, 0x29, 0x73, 0xde, 0x1b, 0x8f, 0xe5, 0xd4, 0x2e, 0xbc, 0x5f, 0x78, + 0x76, 0x53, 0x08, 0xdf, 0xc7, 0x63, 0xb2, 0x4f, 0xad, 0x97, 0xc4, 0xed, + 0x78, 0x23, 0xb6, 0x69, 0x3c, 0x1b, 0xcf, 0xc1, 0x1e, 0x25, 0x69, 0x3b, + 0xd0, 0xd8, 0xe2, 0x1c, 0x5d, 0x98, 0x8d, 0xab, 0x91, 0x26, 0xba, 0xbb, + 0xfc, 0x7e, 0x8d, 0x34, 0x6b, 0x26, 0xff, 0x47, 0x53, 0x6d, 0xb7, 0xff, + 0x26, 0xb6, 0xbf, 0x8c, 0xcf, 0xb9, 0xa4, 0x81, 0xba, 0xb5, 0x36, 0x2e, + 0xc1, 0xf3, 0xe9, 0x32, 0xcc, 0x3c, 0x9d, 0xd9, 0x8c, 0xbc, 0x8b, 0x52, + 0xbc, 0x99, 0xbf, 0x01, 0xd3, 0xca, 0x43, 0xb0, 0x7b, 0xb6, 0x22, 0x62, + 0x5f, 0x86, 0x0f, 0xf1, 0xc2, 0xd2, 0x8d, 0x6a, 0xc6, 0xef, 0x11, 0xb2, + 0xc3, 0xd2, 0x79, 0x44, 0xcd, 0x5e, 0x5e, 0x82, 0x35, 0x02, 0x6f, 0x14, + 0xb6, 0xc7, 0x82, 0x8e, 0xc8, 0xcc, 0xbc, 0x84, 0xb5, 0x4c, 0x45, 0x88, + 0xf1, 0x65, 0x1b, 0xf4, 0xd7, 0xf1, 0x78, 0x1b, 0x4c, 0x25, 0x2d, 0x8d, + 0xff, 0x3f, 0xc4, 0x34, 0x67, 0x43, 0xbc, 0xa9, 0x3e, 0xb8, 0xa4, 0x9c, + 0x32, 0xbc, 0x4f, 0xf1, 0xe1, 0xd9, 0x15, 0x28, 0xb7, 0xeb, 0xbd, 0x12, + 0x33, 0x20, 0xbb, 0x63, 0x26, 0xac, 0x96, 0x4b, 0xcb, 0x3b, 0x30, 0xbd, + 0xdd, 0x8b, 0x6c, 0x3e, 0xcf, 0x09, 0xff, 0xf7, 0xa0, 0xdc, 0xde, 0x3c, + 0xe2, 0x2c, 0x2c, 0x01, 0xfc, 0x2d, 0xde, 0xdc, 0xed, 0x50, 0x23, 0x2d, + 0x64, 0xe7, 0x76, 0xca, 0xce, 0x2c, 0xad, 0x8d, 0x25, 0x64, 0x7f, 0xa4, + 0x9a, 0x81, 0x2d, 0xc3, 0x2d, 0x14, 0xbb, 0x54, 0x8c, 0xb8, 0x9b, 0x4a, + 0xed, 0xcd, 0x93, 0x98, 0xa6, 0xe6, 0x99, 0xbc, 0x7a, 0x88, 0x2e, 0x8c, + 0x47, 0x63, 0x06, 0xbd, 0x48, 0xf0, 0x54, 0x0b, 0xc2, 0xf4, 0xb4, 0x03, + 0xc5, 0x9a, 0x58, 0x30, 0x4d, 0xaa, 0xf7, 0x85, 0xc3, 0x85, 0xb0, 0x76, + 0xa3, 0x57, 0x08, 0x3f, 0xc4, 0x73, 0xa4, 0x16, 0xfd, 0x89, 0x98, 0x88, + 0x05, 0x7d, 0xa7, 0xe0, 0x35, 0x66, 0x00, 0x99, 0x8b, 0xd0, 0xf9, 0x8d, + 0x0d, 0xb1, 0x90, 0xa8, 0x0b, 0xc5, 0x2e, 0xa2, 0x17, 0x34, 0xda, 0x51, + 0xdd, 0xd6, 0xf1, 0xba, 0xec, 0xac, 0x4b, 0x9a, 0x6e, 0x2e, 0x8d, 0xf5, + 0x57, 0x8a, 0x3c, 0x1f, 0x76, 0x3a, 0xde, 0x90, 0xdd, 0x85, 0x0f, 0x54, + 0x3f, 0x45, 0xa5, 0x2b, 0xd8, 0x79, 0xc1, 0x7b, 0x78, 0x9c, 0x1c, 0x80, + 0x69, 0x73, 0x27, 0x2a, 0xb5, 0x23, 0x2f, 0xe3, 0x31, 0xb0, 0x27, 0xa6, + 0xcd, 0xd7, 0x86, 0xd0, 0x19, 0xd3, 0x8d, 0xed, 0xa9, 0x76, 0x3c, 0x02, + 0xa6, 0x69, 0x53, 0xb0, 0x00, 0x69, 0xd5, 0x82, 0xfb, 0x6f, 0x62, 0xba, + 0xb2, 0x1f, 0x1e, 0xab, 0xab, 0x50, 0xb9, 0x09, 0x5a, 0x03, 0x6b, 0x24, + 0x8e, 0x27, 0x13, 0x6c, 0xbd, 0x8d, 0xf9, 0xad, 0x01, 0x35, 0xde, 0xe7, + 0xf7, 0xe1, 0x7d, 0xae, 0xa5, 0x52, 0x6b, 0x3c, 0x0d, 0xd3, 0xaf, 0xad, + 0x80, 0x3b, 0xdb, 0x63, 0xe2, 0x51, 0xb6, 0xab, 0xef, 0x85, 0x89, 0xf5, + 0xd0, 0xf0, 0xff, 0x24, 0xdc, 0x09, 0xbd, 0xc2, 0xfd, 0x4e, 0xa1, 0xf2, + 0x3f, 0x4e, 0xf2, 0x4c, 0x0c, 0xbf, 0xf9, 0x5d, 0x78, 0x6f, 0xac, 0x2a, + 0x89, 0x07, 0x0c, 0x66, 0x62, 0xc2, 0x1b, 0x77, 0x7f, 0xef, 0x63, 0xe6, + 0xa6, 0x5b, 0x92, 0x47, 0xa1, 0xf2, 0x53, 0x70, 0x23, 0x8c, 0x2c, 0xa9, + 0xe7, 0xf3, 0x14, 0x0f, 0x84, 0x95, 0x92, 0xfb, 0x0b, 0x02, 0x9d, 0xa9, + 0x94, 0x24, 0xe6, 0x4d, 0x5a, 0xc0, 0x4c, 0x5a, 0x7a, 0xc0, 0x6b, 0x03, + 0xdc, 0xfe, 0x8d, 0x7a, 0x36, 0xb8, 0x00, 0xab, 0xe6, 0xf2, 0x92, 0xab, + 0xf3, 0xa8, 0x3e, 0x70, 0xf4, 0x39, 0x9e, 0x9c, 0x6b, 0x61, 0x46, 0xb8, + 0x17, 0x95, 0x92, 0xca, 0x5e, 0x98, 0xc0, 0x0f, 0xc9, 0xe5, 0x5b, 0x0d, + 0xab, 0x80, 0x1f, 0xa0, 0x9a, 0x29, 0xfc, 0x36, 0x95, 0x1b, 0x89, 0x81, + 0x58, 0x7a, 0x37, 0x2c, 0x89, 0x5b, 0x8b, 0xca, 0x05, 0xf7, 0xd9, 0xf0, + 0x9b, 0x97, 0xb2, 0x82, 0x17, 0xb0, 0x27, 0x30, 0x33, 0x9a, 0x6f, 0x3f, + 0x70, 0xfb, 0xa4, 0xea, 0xd6, 0x59, 0x98, 0x20, 0x6f, 0x8d, 0x19, 0x94, + 0x89, 0xd4, 0x3f, 0x4c, 0x1b, 0xb1, 0x75, 0x48, 0xbf, 0x3d, 0x5e, 0x08, + 0x4e, 0x26, 0xdb, 0x1c, 0x82, 0x0f, 0x3b, 0xce, 0xce, 0xe5, 0x99, 0x4a, + 0x26, 0xfd, 0x7d, 0x3b, 0xa9, 0x4b, 0x1f, 0xbc, 0x81, 0x99, 0x8b, 0xd5, + 0xe8, 0x27, 0xe1, 0x83, 0x2e, 0x51, 0x0b, 0xb5, 0x28, 0x96, 0x9a, 0x6d, + 0x42, 0xd6, 0xee, 0x9b, 0x62, 0xe6, 0xbf, 0x51, 0xaf, 0x2d, 0x9f, 0x62, + 0x29, 0xfb, 0xd0, 0x90, 0xb7, 0xc8, 0x47, 0xf0, 0xb9, 0x54, 0x9b, 0x36, + 0xe5, 0xd1, 0x0e, 0xab, 0xdf, 0x6f, 0xa7, 0x5a, 0xc2, 0x92, 0xc7, 0x52, + 0x54, 0x1f, 0xac, 0x2e, 0xc3, 0x59, 0x78, 0x21, 0xdd, 0xb5, 0xc1, 0xf4, + 0x0b, 0x0a, 0x73, 0x93, 0xdf, 0xdf, 0xe0, 0xf6, 0xde, 0xb2, 0x3c, 0x79, + 0x05, 0x4e, 0xa2, 0xd8, 0x73, 0xd0, 0x6c, 0xbc, 0xa9, 0xec, 0x8f, 0x0f, + 0x42, 0x35, 0xe2, 0xf9, 0x26, 0xc5, 0xa3, 0x78, 0x21, 0x3f, 0x04, 0xcf, + 0x97, 0x88, 0x8b, 0x43, 0xdd, 0xd6, 0x29, 0xc8, 0x73, 0x30, 0xd9, 0xb7, + 0x00, 0x1a, 0xc1, 0x1d, 0x78, 0x9e, 0x17, 0x49, 0xf3, 0xb6, 0xc5, 0xe3, + 0x29, 0xef, 0xad, 0x24, 0xc5, 0x68, 0xac, 0xdd, 0xea, 0x95, 0xc4, 0xcd, + 0xa2, 0xd2, 0xdb, 0xcc, 0xe7, 0x64, 0x07, 0xa3, 0x9a, 0x83, 0x47, 0xf1, + 0x7c, 0x4d, 0xeb, 0xb6, 0x50, 0x88, 0x2b, 0xa3, 0x7d, 0xaf, 0x87, 0x3a, + 0x9d, 0x84, 0x17, 0xbf, 0x5a, 0x07, 0xae, 0x6e, 0x0f, 0xf5, 0xdc, 0x88, + 0x4a, 0x09, 0xe0, 0x75, 0x58, 0x2a, 0xd8, 0x0d, 0xd3, 0xb4, 0x22, 0xc4, + 0x8d, 0xf5, 0x04, 0xdc, 0xc7, 0x8f, 0x61, 0xad, 0x5a, 0x4b, 0x0f, 0x34, + 0xb7, 0xc3, 0xc2, 0x82, 0xf8, 0xcd, 0x80, 0x14, 0x77, 0x54, 0xa5, 0xce, + 0x70, 0x1b, 0xb5, 0x37, 0xee, 0xd3, 0xa9, 0x96, 0x2a, 0x37, 0x47, 0xda, + 0x19, 0x71, 0x00, 0x1e, 0x8b, 0x3b, 0x61, 0xba, 0x9b, 0xa7, 0x79, 0xf5, + 0x10, 0x85, 0x12, 0x4f, 0x52, 0xee, 0x87, 0x7d, 0x22, 0x99, 0xe9, 0x49, + 0x19, 0x9e, 0xa4, 0xf1, 0x79, 0x99, 0x47, 0x0f, 0xbc, 0xe9, 0xee, 0x49, + 0x26, 0xe8, 0xf9, 0x47, 0x0b, 0xcb, 0x6a, 0x2e, 0xae, 0xc5, 0xc2, 0x9d, + 0xd3, 0x30, 0xad, 0x58, 0xb3, 0x76, 0xf2, 0xf9, 0x8e, 0x47, 0xa9, 0xa6, + 0x1f, 0xf1, 0xf0, 0xed, 0x78, 0x6a, 0x23, 0xf6, 0x65, 0x23, 0xfd, 0x55, + 0x0b, 0xfb, 0xe0, 0xf9, 0xb3, 0x3f, 0x3e, 0x40, 0xbe, 0x1c, 0x8d, 0xad, + 0x73, 0x73, 0xa9, 0xbf, 0x81, 0x00, 0x0b, 0x5c, 0x36, 0xc6, 0x6b, 0xec, + 0x75, 0x05, 0xf7, 0xaf, 0xc4, 0x9b, 0xf0, 0x3e, 0x98, 0x16, 0xcc, 0xc0, + 0xbc, 0xd7, 0x11, 0x98, 0x6e, 0x14, 0xd1, 0x8e, 0xb3, 0x71, 0xff, 0x3d, + 0x84, 0xf9, 0x97, 0xa2, 0x03, 0xd1, 0x97, 0x62, 0xfa, 0xb0, 0x2f, 0x95, + 0x82, 0xb7, 0x76, 0x58, 0xeb, 0x3f, 0x9e, 0xcc, 0xe4, 0xf9, 0xfc, 0xf0, + 0xfb, 0x01, 0xb5, 0xad, 0x35, 0xba, 0x50, 0x5b, 0x08, 0x08, 0xb8, 0x51, + 0x26, 0x51, 0xdb, 0xe6, 0x33, 0x75, 0x9d, 0xd8, 0x8d, 0x4a, 0xd5, 0xf7, + 0x6c, 0xcc, 0x88, 0xa5, 0x8b, 0xd9, 0xd6, 0x98, 0x80, 0xa7, 0x44, 0x68, + 0x49, 0x2c, 0xad, 0x4c, 0x3f, 0x38, 0x74, 0x2f, 0x1e, 0xd4, 0xab, 0x63, + 0x26, 0x7c, 0x34, 0x66, 0x34, 0xfa, 0x52, 0x79, 0xf2, 0x7e, 0xad, 0xf0, + 0x9c, 0xe9, 0xb8, 0x31, 0x8a, 0x70, 0x1f, 0xc5, 0x92, 0xc5, 0x1e, 0x21, + 0x6f, 0x6b, 0xef, 0xa6, 0x9f, 0x20, 0xb3, 0x05, 0xcb, 0xc7, 0x4f, 0xc1, + 0x0c, 0x66, 0x3b, 0x2c, 0x7d, 0xc9, 0x13, 0xe3, 0x0b, 0xb1, 0xb4, 0x36, + 0x4a, 0x07, 0x0e, 0xc2, 0xa6, 0x24, 0xf5, 0xec, 0xfe, 0xc1, 0x4c, 0xd8, + 0xb2, 0x98, 0x38, 0x74, 0xcf, 0x85, 0x15, 0x70, 0xfb, 0xc6, 0x81, 0xde, + 0x0d, 0x0f, 0xa8, 0x7a, 0xb6, 0xf2, 0x2f, 0x50, 0x29, 0x05, 0xdb, 0x0a, + 0x4b, 0xba, 0x7f, 0x87, 0x4d, 0x2b, 0xba, 0x93, 0x9d, 0x9c, 0x5e, 0x01, + 0x7b, 0x6a, 0x88, 0x65, 0x76, 0xc2, 0xbb, 0xc6, 0x2b, 0xa8, 0x34, 0x47, + 0x19, 0x15, 0xd2, 0x45, 0x26, 0xa4, 0x1f, 0x5e, 0xcc, 0x6f, 0x4a, 0xd2, + 0x2c, 0x8c, 0x37, 0x7a, 0x5b, 0x92, 0xd9, 0x18, 0xa6, 0xed, 0x17, 0x31, + 0x16, 0x13, 0x8f, 0x3c, 0xd3, 0xfe, 0x32, 0xde, 0xfc, 0x1c, 0x4b, 0xe3, + 0x3b, 0xfe, 0x2f, 0xb0, 0xfa, 0x6a, 0x57, 0x8a, 0x25, 0x88, 0x4f, 0x93, + 0x7d, 0x6c, 0x2b, 0xe2, 0x2e, 0x3c, 0x1e, 0x97, 0xc1, 0x12, 0xa6, 0x55, + 0xf1, 0x22, 0x30, 0x0b, 0xb7, 0xf7, 0xdd, 0x58, 0x2b, 0x74, 0x3c, 0x95, + 0xb6, 0xa7, 0x7d, 0xb0, 0x1a, 0x3e, 0xad, 0xdb, 0x2c, 0xac, 0xed, 0xa8, + 0x65, 0xda, 0x12, 0xb1, 0x2e, 0xde, 0xb1, 0xff, 0x19, 0x33, 0x2f, 0x27, + 0xe0, 0x7e, 0x4f, 0x17, 0xb3, 0x8e, 0xd4, 0xf6, 0xbe, 0x02, 0x66, 0xb6, + 0x87, 0x61, 0x4d, 0x55, 0xfd, 0x0f, 0x1f, 0x54, 0x6e, 0x8e, 0xeb, 0xe1, + 0x49, 0xcc, 0x6c, 0x5e, 0x81, 0xc7, 0x50, 0x2a, 0x71, 0xad, 0xf7, 0x7e, + 0xad, 0x81, 0x46, 0xfa, 0xfd, 0x46, 0x4c, 0x7c, 0x1b, 0x35, 0xc3, 0xa8, + 0xf5, 0xd1, 0x97, 0xbf, 0xe0, 0xf9, 0x37, 0x99, 0x96, 0x9d, 0xcc, 0x3f, + 0x1b, 0x8f, 0x97, 0x74, 0x31, 0xba, 0x0d, 0x2f, 0x3c, 0xd7, 0x60, 0x0d, + 0x12, 0x98, 0x76, 0x1c, 0x89, 0x19, 0x8e, 0x5a, 0x12, 0x98, 0x3c, 0xce, + 0xc5, 0x1b, 0xdc, 0x7c, 0x9e, 0xce, 0xd8, 0xdc, 0xe0, 0x42, 0xb2, 0xb3, + 0x07, 0x45, 0x18, 0x83, 0xe7, 0x48, 0xde, 0x8e, 0x39, 0x1d, 0x63, 0x2b, + 0xe1, 0xf9, 0xdc, 0x5c, 0x8d, 0xc8, 0xe9, 0x78, 0xee, 0x8c, 0xc0, 0xcc, + 0xf2, 0x96, 0xf8, 0x9d, 0x97, 0xa7, 0xda, 0x0b, 0x47, 0x8a, 0xcb, 0xb1, + 0x14, 0xba, 0x96, 0x57, 0x18, 0xb0, 0xa6, 0xe6, 0x23, 0xaa, 0xe9, 0xed, + 0xbd, 0x98, 0x36, 0x95, 0x6d, 0x00, 0x3a, 0x61, 0xc1, 0x4f, 0xdc, 0xe0, + 0x7e, 0x81, 0xdb, 0xbe, 0x3b, 0x56, 0x7b, 0xb7, 0x04, 0x03, 0xb1, 0xfd, + 0xf8, 0x40, 0x2a, 0x25, 0x8c, 0xed, 0xa9, 0x6d, 0x66, 0xf0, 0x0e, 0xd6, + 0xcc, 0xad, 0x57, 0x23, 0x4d, 0x6b, 0x20, 0xda, 0xd0, 0xc6, 0xcd, 0x47, + 0xb4, 0x0f, 0x2e, 0x33, 0xf5, 0xd8, 0x8a, 0x8c, 0xd9, 0xd8, 0x0a, 0x9b, + 0xc4, 0x9c, 0x15, 0xc2, 0x76, 0x54, 0x32, 0x61, 0x3f, 0xc2, 0xed, 0x36, + 0x14, 0x8f, 0xa3, 0x48, 0xaf, 0x16, 0xa5, 0xda, 0x93, 0xd5, 0x69, 0xa1, + 0xbc, 0x54, 0x1b, 0xb0, 0x3a, 0xf5, 0x5d, 0x7e, 0x82, 0xdb, 0x71, 0x21, + 0xca, 0x3f, 0x50, 0xb8, 0x20, 0x70, 0x0e, 0xe6, 0x87, 0xca, 0xce, 0x1c, + 0x2c, 0x28, 0x9c, 0x82, 0xfb, 0x24, 0xf2, 0x40, 0x1d, 0xb1, 0xe0, 0xe9, + 0x6e, 0x2a, 0x2d, 0x11, 0xc0, 0x9b, 0xd7, 0xd8, 0xcf, 0x3d, 0xc9, 0xfa, + 0xf2, 0x3c, 0xdc, 0x5f, 0xd1, 0xac, 0x6d, 0x09, 0x1a, 0x77, 0x51, 0x0c, + 0xfe, 0xe0, 0x5a, 0x14, 0x86, 0x46, 0x33, 0xbc, 0x74, 0x33, 0xfc, 0x31, + 0x99, 0xc5, 0x40, 0xba, 0x96, 0xbf, 0x48, 0x26, 0xac, 0x6c, 0x87, 0x4d, + 0xb5, 0x8a, 0xe8, 0xfa, 0x83, 0x98, 0x57, 0xfd, 0x25, 0xc5, 0x9b, 0xb0, + 0x6b, 0x31, 0x6d, 0x7e, 0x9d, 0x4c, 0x70, 0xf0, 0x37, 0xfc, 0x0e, 0x37, + 0x15, 0xa4, 0xdf, 0x1d, 0xcf, 0xcd, 0xd1, 0x78, 0xfc, 0x6d, 0x4e, 0xf1, + 0x17, 0x5d, 0x6f, 0xc3, 0xbc, 0xe7, 0x50, 0x2a, 0x2d, 0x15, 0x06, 0x62, + 0x3a, 0x36, 0x20, 0xd4, 0xb7, 0x23, 0xcd, 0xa3, 0xd5, 0xf5, 0x11, 0x4e, + 0x9f, 0xa6, 0x5e, 0x08, 0xf2, 0xe1, 0xb7, 0xc9, 0x89, 0xd6, 0xdf, 0xcb, + 0x5e, 0x3f, 0xd2, 0xfb, 0x6b, 0xc8, 0xa7, 0x82, 0x47, 0x85, 0x13, 0xba, + 0x13, 0x94, 0x79, 0xfb, 0x88, 0xe1, 0x12, 0x65, 0x1f, 0x03, 0x8a, 0x61, + 0x65, 0x49, 0x8f, 0xc8, 0x1f, 0xcc, 0x38, 0x31, 0x89, 0x3f, 0x4c, 0xf6, + 0x0c, 0x30, 0x41, 0xf6, 0xfe, 0x71, 0xb9, 0x7c, 0x4a, 0x79, 0x4d, 0x65, + 0x1f, 0xb9, 0x39, 0x23, 0x57, 0x56, 0x77, 0xf9, 0xb4, 0xfe, 0x46, 0xb9, + 0xf8, 0x5b, 0xe5, 0x0f, 0xc0, 0xb4, 0xe4, 0x44, 0x7b, 0xad, 0xf0, 0x5a, + 0x38, 0x9d, 0x9b, 0x8f, 0xbf, 0x37, 0x9c, 0xf0, 0xed, 0xac, 0xda, 0x1f, + 0x96, 0xd8, 0x25, 0xbc, 0xdf, 0x78, 0xd9, 0x5b, 0x48, 0x3c, 0x45, 0xbc, + 0xb6, 0xec, 0x35, 0xe5, 0x8d, 0x70, 0xc2, 0xf7, 0x53, 0xf9, 0x94, 0x76, + 0x3c, 0x55, 0x5f, 0x0b, 0xf1, 0x63, 0x38, 0xa3, 0xe4, 0x8f, 0x4d, 0x3c, + 0x2e, 0x7f, 0xc8, 0x26, 0xfd, 0x30, 0x4c, 0x0c, 0x43, 0x42, 0x1e, 0xe4, + 0x0f, 0x73, 0x5c, 0x15, 0xda, 0xfa, 0xc1, 0x90, 0x37, 0xed, 0xbf, 0x3e, + 0xa1, 0x0e, 0xf7, 0xcb, 0xde, 0x12, 0x8e, 0x4b, 0xca, 0x3c, 0x34, 0x94, + 0x93, 0xff, 0xb8, 0x54, 0xd7, 0xd0, 0xee, 0xcf, 0xcb, 0x27, 0xfd, 0xc7, + 0xc9, 0x1f, 0x4b, 0x21, 0xb4, 0xcd, 0x89, 0xf2, 0x49, 0xf8, 0x43, 0x55, + 0x79, 0xd2, 0x3d, 0x6d, 0xbf, 0x18, 0x17, 0x4f, 0xf8, 0xaf, 0xa6, 0xe2, + 0xb6, 0x6c, 0xcd, 0x30, 0x41, 0xfe, 0x78, 0x4e, 0x1a, 0xb7, 0xaa, 0x7c, + 0xf2, 0x7a, 0x64, 0x49, 0x5b, 0x16, 0x85, 0x61, 0xb2, 0xe7, 0xa2, 0x09, + 0x92, 0x4e, 0x4a, 0xe2, 0xcf, 0x93, 0x34, 0x31, 0xbc, 0xcf, 0x58, 0xf9, + 0x83, 0x42, 0x7b, 0x85, 0x36, 0x97, 0xec, 0xc5, 0x63, 0x8c, 0xb2, 0xb1, + 0x31, 0x28, 0xd7, 0x3e, 0xbd, 0xe4, 0x53, 0xf8, 0x0f, 0x86, 0x74, 0x93, + 0xe5, 0xb9, 0xb7, 0x71, 0x41, 0x39, 0x4d, 0x21, 0xdc, 0x2f, 0x7b, 0x24, + 0x48, 0x3f, 0xa6, 0xd1, 0x2f, 0x94, 0x2f, 0xd9, 0x3b, 0xc5, 0x93, 0x49, + 0x78, 0x31, 0xc4, 0x0f, 0x90, 0xbd, 0xc4, 0x48, 0xf6, 0x4c, 0x31, 0x59, + 0x99, 0xe7, 0x9f, 0x7c, 0xd8, 0x58, 0x3e, 0xd5, 0xfe, 0x8a, 0xdc, 0x7f, + 0x4f, 0x87, 0xeb, 0xe8, 0x51, 0x27, 0xad, 0xdb, 0x34, 0x55, 0x7a, 0x7f, + 0xfa, 0x7b, 0xf2, 0x9c, 0x07, 0x42, 0xda, 0x7e, 0xca, 0x3c, 0x28, 0xbc, + 0x2d, 0x8f, 0x8b, 0xfc, 0x33, 0x25, 0xe9, 0xd8, 0xdc, 0x3b, 0xe5, 0xf3, + 0x2c, 0x24, 0x7b, 0x02, 0x9a, 0x1a, 0xe2, 0x1f, 0x93, 0xbd, 0x1f, 0xd4, + 0x7a, 0xff, 0x4f, 0xe5, 0xf9, 0xb1, 0x83, 0x3c, 0x87, 0x3e, 0x0f, 0xe5, + 0xc6, 0x8f, 0x18, 0xdd, 0xa6, 0x8c, 0x96, 0x5d, 0x24, 0x7b, 0xa4, 0x92, + 0xec, 0x3d, 0x60, 0x5f, 0xd9, 0x03, 0xc2, 0x23, 0x21, 0xdf, 0xd3, 0x92, + 0x8e, 0xca, 0xd5, 0xfb, 0x5b, 0xa1, 0x8d, 0xf2, 0xef, 0x73, 0x50, 0x78, + 0xff, 0xb1, 0x21, 0xff, 0x30, 0x55, 0x7e, 0x5c, 0xeb, 0xa7, 0xca, 0xbc, + 0x47, 0x4c, 0x0d, 0xf5, 0x58, 0xaa, 0xa0, 0x9c, 0x9d, 0x24, 0xbd, 0x2b, + 0x7f, 0x8c, 0x68, 0xe5, 0x50, 0x9f, 0x26, 0x99, 0x16, 0x2d, 0x12, 0xd2, + 0xfc, 0x2c, 0xb4, 0x45, 0x6c, 0xab, 0x26, 0x65, 0x1e, 0x1c, 0xce, 0x95, + 0x3d, 0xf2, 0x8c, 0x91, 0x69, 0xca, 0x51, 0xf2, 0xfc, 0x1d, 0x23, 0x8f, + 0xa5, 0x09, 0xf2, 0x07, 0xe7, 0xd2, 0xb9, 0x70, 0x48, 0xae, 0xbc, 0xd1, + 0xaa, 0xf4, 0x8c, 0x10, 0xc3, 0x76, 0xe1, 0xfd, 0x3e, 0x96, 0xbd, 0x7c, + 0x8c, 0x55, 0xa5, 0x47, 0x85, 0xa2, 0xb0, 0x58, 0x28, 0xb3, 0xa8, 0xbc, + 0x7c, 0xb8, 0x59, 0x52, 0xcf, 0x82, 0xf8, 0xe1, 0x72, 0x9f, 0xe7, 0xe3, + 0x2f, 0x91, 0x3d, 0x9f, 0xbc, 0xa7, 0xcc, 0x43, 0xc8, 0xa6, 0xa1, 0x1f, + 0xe6, 0x84, 0x7a, 0x8e, 0x96, 0x69, 0x40, 0x9a, 0xef, 0xd8, 0xdc, 0xfb, + 0xde, 0x27, 0x7b, 0x70, 0x89, 0xf7, 0x67, 0x4a, 0xfa, 0x4c, 0x95, 0xe3, + 0xea, 0x49, 0x65, 0x9e, 0x2e, 0xa4, 0x72, 0xaf, 0x36, 0xe9, 0x07, 0xeb, + 0xd2, 0xb1, 0x5e, 0x96, 0xbe, 0x25, 0x61, 0x49, 0xd9, 0x73, 0xd7, 0x9b, + 0xb2, 0x67, 0x9b, 0x01, 0xe1, 0xfd, 0xff, 0xad, 0xcc, 0xb3, 0xd8, 0x9a, + 0xca, 0xe6, 0xc8, 0xd9, 0xb2, 0x37, 0x89, 0xb1, 0xb2, 0xe7, 0x8c, 0xfd, + 0x92, 0xb2, 0xf6, 0x96, 0x69, 0xda, 0xe3, 0xb2, 0x27, 0xab, 0x33, 0xe5, + 0x8f, 0x32, 0x21, 0xd3, 0xaf, 0x97, 0xe4, 0xf1, 0xf3, 0xf7, 0x70, 0x4f, + 0xb2, 0x67, 0xa1, 0xf8, 0x71, 0xb5, 0x9f, 0xc8, 0xeb, 0xcb, 0x24, 0x79, + 0x4c, 0x5f, 0x22, 0x8f, 0xbb, 0xf5, 0xe5, 0xf1, 0x16, 0xdb, 0xf8, 0x9f, + 0xb9, 0x77, 0x58, 0x2e, 0x94, 0xf3, 0x86, 0x3c, 0x7e, 0x47, 0x87, 0xfc, + 0xc7, 0xca, 0x34, 0x73, 0x8d, 0xf0, 0x5c, 0x85, 0xf7, 0x8c, 0xf3, 0x61, + 0x6c, 0x12, 0x77, 0xb4, 0xec, 0x79, 0x2b, 0xd2, 0x87, 0xcb, 0x73, 0xcf, + 0x18, 0x12, 0xe2, 0x09, 0xf5, 0x6d, 0x0a, 0xd7, 0xd3, 0x64, 0x5e, 0x08, + 0xd9, 0xdb, 0x86, 0xe4, 0x31, 0xb0, 0xb2, 0x4c, 0x1b, 0xa2, 0x97, 0x93, + 0xd7, 0xe4, 0xb5, 0x3b, 0x7d, 0xee, 0xb4, 0xd0, 0x66, 0x07, 0x2a, 0xa3, + 0x7b, 0xf7, 0xc9, 0x73, 0x73, 0x74, 0xae, 0x6e, 0x45, 0xf5, 0x5d, 0x2d, + 0xf7, 0x5e, 0x47, 0x87, 0x7a, 0xf4, 0x96, 0xe7, 0xe8, 0x58, 0x79, 0x8e, + 0xfe, 0x49, 0x95, 0xeb, 0x68, 0x1c, 0x47, 0xd7, 0xca, 0xf4, 0x77, 0x9c, + 0xdc, 0x97, 0xe9, 0x47, 0xd2, 0x8e, 0x92, 0x69, 0x78, 0x93, 0x3c, 0x1e, + 0x2e, 0x4c, 0xde, 0x1f, 0x99, 0xa7, 0x89, 0xeb, 0xf1, 0x6b, 0xf2, 0x07, + 0xca, 0xe2, 0xbd, 0xe8, 0x5d, 0x6c, 0x9c, 0xec, 0x15, 0x29, 0xff, 0x11, + 0xae, 0xe3, 0x64, 0xba, 0x74, 0x8f, 0xa4, 0x81, 0x49, 0xfc, 0xae, 0x32, + 0x0d, 0x1e, 0x2f, 0xb7, 0x7f, 0x6f, 0x79, 0x6e, 0xdd, 0xa5, 0x8c, 0x67, + 0x88, 0xe1, 0x08, 0x55, 0xf7, 0x51, 0x1a, 0x6e, 0x51, 0xa5, 0xe7, 0xc1, + 0x8e, 0xf2, 0x5a, 0x98, 0xf7, 0xf0, 0x74, 0x81, 0xfc, 0x21, 0xc4, 0x07, + 0x65, 0xde, 0x71, 0xa8, 0xbc, 0xc6, 0x7f, 0xac, 0x4a, 0xef, 0x2c, 0x31, + 0xfc, 0xaf, 0xb2, 0x8f, 0x28, 0xc6, 0xf0, 0xbe, 0x3c, 0x6e, 0x6e, 0x0a, + 0xe1, 0xae, 0x5c, 0x5b, 0xe5, 0xff, 0x0f, 0xa9, 0x71, 0x5d, 0x18, 0xda, + 0x49, 0xcd, 0x31, 0x33, 0xaa, 0x8b, 0x29, 0x14, 0xdb, 0xee, 0xac, 0xc5, + 0xfc, 0x37, 0x2d, 0x89, 0x36, 0xcb, 0x07, 0x86, 0xdf, 0x35, 0xb1, 0xca, + 0x6f, 0x23, 0x5a, 0xf7, 0x70, 0x02, 0xa1, 0xcc, 0xeb, 0xa8, 0x3e, 0xec, + 0x96, 0xe2, 0x34, 0x2c, 0x0d, 0x3f, 0xbf, 0x46, 0x9a, 0x6f, 0x22, 0x3a, + 0xe2, 0xf6, 0x8b, 0x9f, 0x4f, 0xaf, 0x87, 0xa5, 0xf1, 0x8e, 0x79, 0x15, + 0xbe, 0xbc, 0x8f, 0xda, 0x6c, 0x87, 0x25, 0x77, 0xe3, 0xb1, 0x84, 0x2d, + 0xda, 0x99, 0x2f, 0x82, 0xa5, 0x05, 0x65, 0xea, 0xf2, 0x36, 0xcc, 0x1f, + 0x2c, 0x89, 0xcd, 0xe0, 0x7a, 0x52, 0x2d, 0x19, 0x6a, 0x83, 0xb5, 0x9d, + 0x83, 0xb0, 0x46, 0xf3, 0x19, 0x2c, 0xe1, 0x1b, 0xce, 0x7f, 0xc6, 0x47, + 0xa1, 0xda, 0x60, 0xba, 0x77, 0x2a, 0xc5, 0x1f, 0xb9, 0x5b, 0x07, 0xaf, + 0x65, 0x9b, 0x37, 0x98, 0x3e, 0xa2, 0xa9, 0xc6, 0xbd, 0x5e, 0xcd, 0xa9, + 0xdc, 0x57, 0x04, 0xbb, 0xe2, 0xc3, 0x78, 0xdb, 0x63, 0x4d, 0x7d, 0x3b, + 0x2c, 0x0d, 0xbd, 0x11, 0x4b, 0x30, 0xeb, 0x7d, 0xbc, 0xab, 0x11, 0x9c, + 0x8a, 0xcd, 0xe2, 0xbe, 0x2e, 0x1f, 0x22, 0x6a, 0x64, 0x1c, 0xa5, 0x18, + 0x82, 0xa5, 0xf2, 0x65, 0xfe, 0xef, 0xbf, 0x29, 0xe8, 0x8b, 0xa5, 0xfe, + 0x17, 0xd7, 0x4b, 0x98, 0x60, 0x26, 0xd6, 0x02, 0x4d, 0xa7, 0xb2, 0xdd, + 0x97, 0xc3, 0x1a, 0xb2, 0x23, 0xa9, 0xc3, 0x1b, 0x2e, 0xa8, 0x8f, 0x84, + 0x2c, 0x08, 0x9b, 0xef, 0xa3, 0xb1, 0xcd, 0xd3, 0xfa, 0xd8, 0x7e, 0xea, + 0x0c, 0x3c, 0xb1, 0x5a, 0x9b, 0x31, 0x07, 0xdb, 0x5d, 0x5f, 0x55, 0x27, + 0xcd, 0xae, 0x64, 0x5f, 0x98, 0x6c, 0x43, 0x86, 0xcf, 0x71, 0x3f, 0x35, + 0x8a, 0xa3, 0xb1, 0x6d, 0xe1, 0x97, 0xc9, 0x58, 0xdc, 0x8b, 0xd5, 0xdc, + 0x87, 0xe1, 0x03, 0x7d, 0x8b, 0xe1, 0x83, 0x60, 0xaf, 0x52, 0x69, 0x6b, + 0xdf, 0x86, 0xf9, 0x87, 0x45, 0x31, 0x1d, 0x99, 0x81, 0xdd, 0x8a, 0xdd, + 0x4c, 0x1b, 0x63, 0x5e, 0x86, 0x57, 0xf0, 0x59, 0xa1, 0xfd, 0x70, 0x1b, + 0xb5, 0x8d, 0xd1, 0xff, 0x3c, 0x0c, 0xc2, 0x26, 0x20, 0x83, 0xc9, 0x36, + 0xfb, 0xe0, 0xf3, 0x39, 0x4b, 0xe1, 0x73, 0x2c, 0xc7, 0x90, 0x7d, 0xc8, + 0xad, 0x1e, 0x7a, 0xb5, 0x66, 0xe5, 0xbe, 0x02, 0xb8, 0x0c, 0x9b, 0xb9, + 0xc6, 0xc3, 0xb0, 0x22, 0xf3, 0x8c, 0xd5, 0x5a, 0x26, 0x75, 0xdf, 0xa2, + 0xdc, 0x83, 0x55, 0x1b, 0xbe, 0x39, 0xd8, 0x87, 0x4c, 0xe8, 0xdb, 0x28, + 0x8e, 0xc1, 0xde, 0xa1, 0x52, 0x07, 0x0c, 0x43, 0xb1, 0x49, 0xeb, 0x75, + 0x34, 0xb0, 0x79, 0x6c, 0x6d, 0xc9, 0xf9, 0x97, 0x8d, 0x75, 0xf0, 0xe1, + 0xa1, 0x8b, 0xf0, 0xa9, 0xd7, 0x5f, 0xd5, 0x4e, 0xde, 0x22, 0xfc, 0x00, + 0xdb, 0x17, 0xef, 0x4d, 0xe5, 0x61, 0xc2, 0x36, 0xb4, 0x2e, 0x16, 0xc1, + 0x5f, 0x44, 0x9b, 0x45, 0xb5, 0x5f, 0xf5, 0x36, 0x7c, 0x33, 0x31, 0x08, + 0x6f, 0x92, 0x1e, 0xc1, 0x2e, 0xad, 0xda, 0x24, 0xc1, 0xb5, 0x71, 0x3a, + 0x76, 0x7f, 0xb8, 0x09, 0x95, 0x2e, 0x3e, 0xdb, 0xd0, 0x86, 0xaf, 0x3a, + 0x9e, 0xc4, 0x0c, 0xf9, 0x8e, 0x58, 0x43, 0xbd, 0x18, 0xb6, 0x9b, 0xee, + 0x8d, 0xc7, 0x7b, 0xde, 0xfd, 0x68, 0xa3, 0x38, 0x04, 0x1f, 0x98, 0x3d, + 0x19, 0x9f, 0xa5, 0xb9, 0x98, 0xca, 0xb3, 0x72, 0x5f, 0x65, 0xb4, 0x49, + 0xce, 0x1b, 0x43, 0x7b, 0x7c, 0x10, 0xf4, 0x0b, 0x3c, 0xce, 0x16, 0xa3, + 0x79, 0x1e, 0xbf, 0xf2, 0x68, 0x6e, 0xbb, 0x03, 0x5f, 0xfe, 0xe7, 0xb5, + 0x5b, 0x1b, 0xcf, 0x62, 0x37, 0x36, 0x8d, 0xf8, 0x3b, 0x6d, 0x09, 0xe2, + 0xc7, 0x93, 0xda, 0x18, 0xf3, 0xf9, 0x8f, 0xb9, 0x58, 0xbd, 0xfb, 0x44, + 0xbd, 0x84, 0x6d, 0xf8, 0xc6, 0xa0, 0xa5, 0x1f, 0x02, 0xfb, 0xa6, 0xe2, + 0x14, 0x4c, 0xb3, 0x1e, 0xc4, 0x5a, 0x87, 0x67, 0xa8, 0xfe, 0xb4, 0x79, + 0x1b, 0xda, 0xf0, 0x55, 0xc4, 0x8f, 0xb1, 0x66, 0xfc, 0x9f, 0xf8, 0x5b, + 0x18, 0x71, 0xcd, 0xdf, 0x94, 0x96, 0x33, 0xe6, 0x60, 0x49, 0xfc, 0xba, + 0xd8, 0x75, 0x7e, 0x25, 0xe2, 0x26, 0x00, 0x00, 0x00, 0x32, 0x49, 0x44, + 0x41, 0x54, 0xea, 0x65, 0x54, 0x3b, 0x08, 0xf8, 0x2a, 0x62, 0x6f, 0xec, + 0x38, 0x01, 0xec, 0xbd, 0x64, 0x43, 0xec, 0xb0, 0xa1, 0x16, 0xae, 0x26, + 0x73, 0xcc, 0xf1, 0x10, 0x16, 0x8c, 0x7c, 0x53, 0xd6, 0x62, 0x61, 0xcd, + 0x55, 0x4f, 0xcc, 0xa0, 0x1f, 0x5a, 0x3b, 0xf9, 0xfc, 0xc1, 0xff, 0x01, + 0xf4, 0x4f, 0x9a, 0x26, 0x12, 0xca, 0xbf, 0xd8, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +static int source_serif_pro_regular_12_png_len = 8348; + +static BYTE source_serif_pro_regular_12_xml[] = { + 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, + 0x3f, 0x3e, 0x0a, 0x3c, 0x46, 0x6f, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, + 0x65, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, + 0x79, 0x3d, 0x22, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x53, 0x65, + 0x72, 0x69, 0x66, 0x20, 0x50, 0x72, 0x6f, 0x22, 0x20, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x30, 0x22, 0x20, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x3d, 0x22, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x22, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x30, 0x20, 0x31, 0x35, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x30, 0x20, 0x31, 0x33, 0x20, 0x30, 0x20, 0x30, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x20, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x30, 0x20, 0x32, 0x20, 0x32, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x21, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, + 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x32, 0x20, 0x31, + 0x20, 0x35, 0x20, 0x35, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x26, 0x71, 0x75, 0x6f, 0x74, 0x3b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, + 0x20, 0x32, 0x20, 0x38, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x23, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, + 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x33, + 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x35, 0x20, 0x31, + 0x20, 0x38, 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x24, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x34, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x32, 0x33, 0x20, 0x32, 0x20, + 0x31, 0x32, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x25, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x35, 0x20, 0x32, 0x20, + 0x31, 0x32, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x26, 0x61, 0x6d, 0x70, 0x3b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x33, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, + 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x37, + 0x20, 0x31, 0x20, 0x32, 0x20, 0x35, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x27, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x32, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x39, 0x20, 0x30, 0x20, + 0x34, 0x20, 0x31, 0x37, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x28, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x32, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x33, 0x20, 0x30, 0x20, 0x35, 0x20, + 0x31, 0x37, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x29, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x2d, 0x31, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x35, 0x38, 0x20, 0x31, 0x20, 0x38, 0x20, 0x36, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x2a, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x30, 0x20, 0x36, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x36, 0x36, 0x20, 0x34, 0x20, 0x39, 0x20, 0x38, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x2b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x2d, + 0x31, 0x20, 0x31, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x37, 0x35, 0x20, 0x31, 0x31, 0x20, 0x34, 0x20, 0x36, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x2c, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, + 0x20, 0x31, 0x30, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, + 0x39, 0x20, 0x38, 0x20, 0x34, 0x20, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x2d, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x34, 0x22, + 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x31, + 0x32, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x38, 0x33, 0x20, + 0x31, 0x30, 0x20, 0x33, 0x20, 0x33, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x2e, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x33, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x38, 0x36, 0x20, 0x31, 0x20, + 0x36, 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x2f, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x39, 0x32, 0x20, 0x32, 0x20, 0x37, 0x20, + 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x30, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x39, 0x39, 0x20, 0x32, 0x20, 0x37, 0x20, 0x31, 0x31, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x31, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x31, 0x30, 0x36, 0x20, 0x32, 0x20, 0x38, 0x20, 0x31, 0x31, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x32, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x31, 0x31, 0x34, 0x20, 0x32, 0x20, 0x37, 0x20, 0x31, 0x31, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x33, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, + 0x32, 0x31, 0x20, 0x32, 0x20, 0x37, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x34, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, + 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x32, + 0x38, 0x20, 0x32, 0x20, 0x37, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x35, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, + 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x33, 0x35, + 0x20, 0x31, 0x20, 0x37, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x36, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, + 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x35, + 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x34, 0x32, 0x20, + 0x33, 0x20, 0x37, 0x20, 0x31, 0x30, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x37, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x34, 0x39, 0x20, 0x32, + 0x20, 0x37, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x38, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, + 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x35, 0x36, 0x20, 0x32, 0x20, + 0x37, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x39, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x34, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x31, 0x36, 0x33, 0x20, 0x35, 0x20, 0x33, + 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x3a, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x2d, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x31, 0x36, 0x36, 0x20, 0x35, 0x20, 0x35, 0x20, + 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x3b, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x35, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x31, 0x37, 0x31, 0x20, 0x33, 0x20, 0x37, 0x20, 0x39, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x26, 0x6c, 0x74, 0x3b, + 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x31, 0x37, 0x38, 0x20, 0x35, 0x20, 0x39, 0x20, + 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x3d, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x31, 0x20, 0x35, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x31, 0x38, 0x37, 0x20, 0x33, 0x20, 0x37, 0x20, 0x39, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x3e, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x31, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x31, 0x39, 0x34, 0x20, 0x31, 0x20, 0x36, 0x20, 0x31, 0x32, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x3f, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x31, 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x32, 0x30, 0x30, 0x20, 0x32, 0x20, 0x31, 0x33, 0x20, 0x31, 0x33, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x40, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x31, 0x31, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x32, 0x31, 0x33, 0x20, 0x32, 0x20, 0x31, 0x31, 0x20, 0x31, 0x31, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x41, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x32, 0x32, 0x34, 0x20, 0x32, 0x20, 0x39, 0x20, 0x31, 0x31, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x42, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x32, 0x33, 0x33, 0x20, 0x32, 0x20, 0x39, 0x20, 0x31, 0x31, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x43, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x31, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x32, 0x34, 0x32, 0x20, 0x32, 0x20, 0x31, 0x31, 0x20, 0x31, + 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x44, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x32, 0x35, 0x33, 0x20, 0x32, 0x20, 0x39, 0x20, 0x31, + 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x45, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x32, 0x36, 0x32, 0x20, 0x32, 0x20, 0x39, 0x20, 0x31, 0x31, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x46, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x31, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x32, 0x37, 0x31, 0x20, 0x32, 0x20, 0x31, 0x30, 0x20, 0x31, + 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x47, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x32, 0x38, 0x31, 0x20, 0x32, 0x20, 0x31, 0x32, 0x20, + 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x48, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x32, 0x39, 0x33, 0x20, 0x32, 0x20, 0x35, 0x20, 0x31, + 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x49, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x2d, 0x32, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x32, 0x39, 0x38, 0x20, 0x32, 0x20, 0x38, 0x20, 0x31, + 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x4a, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x33, 0x30, 0x36, 0x20, 0x32, 0x20, 0x31, 0x31, 0x20, + 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x4b, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x33, 0x31, 0x37, 0x20, 0x32, 0x20, 0x39, 0x20, 0x31, + 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x4c, 0x22, 0x2f, + 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x22, 0x31, 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x33, 0x32, 0x36, 0x20, 0x32, 0x20, 0x31, 0x34, 0x20, + 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x4d, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x20, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x33, 0x34, 0x30, 0x20, 0x32, 0x20, 0x31, 0x32, + 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x4e, + 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x31, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x35, 0x32, 0x20, 0x32, 0x20, 0x31, + 0x30, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x4f, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, 0x20, + 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x36, 0x32, 0x20, 0x32, 0x20, + 0x39, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x50, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x31, 0x22, 0x20, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, + 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x37, 0x31, 0x20, 0x32, 0x20, + 0x31, 0x30, 0x20, 0x31, 0x35, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x51, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x38, 0x31, 0x20, 0x32, + 0x20, 0x31, 0x31, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x52, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x39, 0x32, 0x20, 0x32, + 0x20, 0x37, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x53, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x33, 0x39, 0x39, 0x20, 0x32, + 0x20, 0x39, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x54, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x30, 0x38, 0x20, 0x32, + 0x20, 0x31, 0x32, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x55, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x31, 0x22, + 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x34, + 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x32, 0x30, 0x20, + 0x32, 0x20, 0x31, 0x31, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x56, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x35, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, + 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x33, 0x31, + 0x20, 0x32, 0x20, 0x31, 0x36, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x57, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, + 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, + 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x34, + 0x37, 0x20, 0x32, 0x20, 0x31, 0x31, 0x20, 0x31, 0x31, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x58, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x2d, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x34, 0x35, 0x38, 0x20, 0x32, 0x20, 0x31, 0x31, 0x20, 0x31, 0x31, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x59, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x31, 0x20, 0x34, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x34, 0x36, 0x39, 0x20, 0x32, 0x20, 0x38, 0x20, 0x31, 0x31, 0x22, + 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x5a, 0x22, 0x2f, 0x3e, 0x0a, + 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x32, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x34, 0x37, 0x37, 0x20, 0x31, 0x20, 0x34, 0x20, 0x31, 0x34, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x5b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x35, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x30, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, + 0x38, 0x31, 0x20, 0x31, 0x20, 0x36, 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x5c, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x35, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, + 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x38, + 0x37, 0x20, 0x31, 0x20, 0x34, 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x5d, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, + 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x39, 0x31, + 0x20, 0x35, 0x20, 0x37, 0x20, 0x35, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x5e, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x31, 0x35, + 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x34, 0x39, 0x38, 0x20, + 0x31, 0x33, 0x20, 0x37, 0x20, 0x31, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x5f, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x36, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x33, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x30, 0x35, 0x20, 0x31, + 0x20, 0x34, 0x20, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x60, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x30, 0x39, 0x20, 0x35, 0x20, 0x39, + 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x61, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x35, 0x31, 0x38, 0x20, 0x31, 0x20, 0x39, 0x20, + 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x62, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x35, 0x32, 0x37, 0x20, 0x35, 0x20, 0x37, 0x20, 0x38, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x63, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x31, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x35, 0x33, 0x34, 0x20, 0x31, 0x20, 0x39, 0x20, 0x31, 0x32, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x64, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x35, 0x34, 0x33, 0x20, 0x35, 0x20, 0x37, 0x20, 0x38, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x65, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x36, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x30, 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, + 0x35, 0x30, 0x20, 0x31, 0x20, 0x38, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x66, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, + 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x35, + 0x38, 0x20, 0x35, 0x20, 0x38, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x67, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, + 0x30, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, + 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x36, + 0x36, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, + 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x68, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, + 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x34, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, + 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x37, + 0x36, 0x20, 0x31, 0x20, 0x34, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x69, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x34, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x2d, 0x32, + 0x20, 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x38, + 0x30, 0x20, 0x31, 0x20, 0x36, 0x20, 0x31, 0x36, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x6a, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, + 0x32, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x38, 0x36, + 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x31, 0x33, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x6b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, + 0x33, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x35, 0x39, 0x36, + 0x20, 0x31, 0x20, 0x35, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x6c, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x34, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, + 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x30, 0x31, + 0x20, 0x35, 0x20, 0x31, 0x34, 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x6d, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, + 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x31, 0x35, + 0x20, 0x35, 0x20, 0x31, 0x30, 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x3d, 0x22, 0x6e, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, + 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, + 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x37, + 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x32, 0x35, 0x20, + 0x35, 0x20, 0x38, 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x6f, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x37, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x33, 0x33, 0x20, 0x35, + 0x20, 0x39, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x70, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x37, 0x22, 0x20, + 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x34, 0x32, 0x20, 0x35, 0x20, + 0x39, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x71, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x37, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x36, 0x35, 0x31, 0x20, 0x35, 0x20, 0x37, + 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x72, 0x22, + 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x37, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, + 0x74, 0x3d, 0x22, 0x36, 0x35, 0x38, 0x20, 0x35, 0x20, 0x36, 0x20, 0x38, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x73, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x2d, 0x31, 0x20, 0x35, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x36, 0x36, 0x34, 0x20, 0x33, 0x20, 0x36, 0x20, 0x31, 0x30, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x74, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x2d, 0x31, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, + 0x3d, 0x22, 0x36, 0x37, 0x30, 0x20, 0x35, 0x20, 0x31, 0x30, 0x20, 0x38, + 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x75, 0x22, 0x2f, 0x3e, + 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x3d, 0x22, 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, + 0x22, 0x36, 0x38, 0x30, 0x20, 0x35, 0x20, 0x38, 0x20, 0x38, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x76, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x31, 0x32, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, + 0x22, 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, + 0x36, 0x38, 0x38, 0x20, 0x35, 0x20, 0x31, 0x33, 0x20, 0x38, 0x22, 0x20, + 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x77, 0x22, 0x2f, 0x3e, 0x0a, 0x20, + 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x22, 0x38, 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x30, 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, + 0x30, 0x31, 0x20, 0x35, 0x20, 0x38, 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x78, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x2d, 0x31, + 0x20, 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, 0x30, + 0x39, 0x20, 0x35, 0x20, 0x39, 0x20, 0x31, 0x32, 0x22, 0x20, 0x63, 0x6f, + 0x64, 0x65, 0x3d, 0x22, 0x79, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, + 0x68, 0x61, 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x38, + 0x22, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, + 0x37, 0x22, 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, 0x31, 0x38, + 0x20, 0x35, 0x20, 0x36, 0x20, 0x38, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, + 0x3d, 0x22, 0x7a, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, + 0x72, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x33, 0x22, + 0x20, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, 0x32, 0x34, 0x20, 0x31, + 0x20, 0x35, 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, + 0x22, 0x7b, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x32, 0x20, 0x33, 0x22, 0x20, + 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, 0x32, 0x39, 0x20, 0x31, 0x20, + 0x32, 0x20, 0x31, 0x36, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, + 0x7c, 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x35, 0x22, 0x20, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x30, 0x20, 0x33, 0x22, 0x20, 0x72, + 0x65, 0x63, 0x74, 0x3d, 0x22, 0x37, 0x33, 0x31, 0x20, 0x31, 0x20, 0x35, + 0x20, 0x31, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x7d, + 0x22, 0x2f, 0x3e, 0x0a, 0x20, 0x3c, 0x43, 0x68, 0x61, 0x72, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x39, 0x22, 0x20, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x3d, 0x22, 0x31, 0x20, 0x38, 0x22, 0x20, 0x72, 0x65, + 0x63, 0x74, 0x3d, 0x22, 0x37, 0x33, 0x36, 0x20, 0x36, 0x20, 0x37, 0x20, + 0x33, 0x22, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x7e, 0x22, 0x2f, + 0x3e, 0x0a, 0x3c, 0x2f, 0x46, 0x6f, 0x6e, 0x74, 0x3e, 0x0a +}; +static int source_serif_pro_regular_12_xml_len = 5758; + +/** + * Bitmap fonts were generated using FontBuilder on Windows with the following settings: + * + * Line layout, no pixel separator, no "power of two image". + * The image is a png with alpha transparency. + * The .xml descriptor file is in the "Divo compatible" format. + */ + +/** + * These embedded resources were converted from binaries files to C arrays using "xxd -i" + */ + +int rdtk_get_embedded_resource_file(const char* filename, BYTE** pData) +{ + if (strcmp(filename, "source_serif_pro_regular_12.png") == 0) + { + *pData = (BYTE*) source_serif_pro_regular_12_png; + return source_serif_pro_regular_12_png_len; + } + else if (strcmp(filename, "source_serif_pro_regular_12.xml") == 0) + { + *pData = (BYTE*) source_serif_pro_regular_12_xml; + return source_serif_pro_regular_12_xml_len; + } + else if (strcmp(filename, "btn_default_normal.9.png") == 0) + { + *pData = (BYTE*) btn_default_normal_9_png; + return btn_default_normal_9_png_len; + } + else if (strcmp(filename, "textfield_default.9.png") == 0) + { + *pData = (BYTE*) textfield_default_9_png; + return textfield_default_9_png_len; + } + + return -1; +} diff --git a/rdtk/librdtk/rdtk_resources.h b/rdtk/librdtk/rdtk_resources.h new file mode 100644 index 000000000..4bf1c3b70 --- /dev/null +++ b/rdtk/librdtk/rdtk_resources.h @@ -0,0 +1,37 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_RESOURCES_PRIVATE_H +#define RDTK_RESOURCES_PRIVATE_H + +#include + +#include "rdtk_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_get_embedded_resource_file(const char* filename, BYTE** pData); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_RESOURCES_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_surface.c b/rdtk/librdtk/rdtk_surface.c new file mode 100644 index 000000000..2c02f8ea1 --- /dev/null +++ b/rdtk/librdtk/rdtk_surface.c @@ -0,0 +1,82 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_surface.h" + +int rdtk_surface_fill(rdtkSurface* surface, int x, int y, int width, int height, UINT32 color) +{ + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x, y, width, height, color); + + return 1; +} + +rdtkSurface* rdtk_surface_new(rdtkEngine* engine, BYTE* data, int width, int height, int scanline) +{ + rdtkSurface* surface; + + surface = (rdtkSurface*) calloc(1, sizeof(rdtkSurface)); + + if (!surface) + return NULL; + + surface->engine = engine; + + surface->width = width; + surface->height = height; + + if (scanline < 0) + scanline = width * 4; + + surface->scanline = scanline; + + surface->data = data; + surface->owner = FALSE; + + if (!data) + { + surface->scanline = (surface->width + (surface->width % 4)) * 4; + + surface->data = (BYTE*) malloc(surface->scanline * surface->height); + + if (!surface->data) + return NULL; + + ZeroMemory(surface->data, surface->scanline * surface->height); + + surface->owner = TRUE; + } + + return surface; +} + +void rdtk_surface_free(rdtkSurface* surface) +{ + if (!surface) + return; + + if (surface->owner) + free(surface->data); + + free(surface); +} + diff --git a/rdtk/librdtk/rdtk_surface.h b/rdtk/librdtk/rdtk_surface.h new file mode 100644 index 000000000..efe7a879b --- /dev/null +++ b/rdtk/librdtk/rdtk_surface.h @@ -0,0 +1,49 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_SURFACE_PRIVATE_H +#define RDTK_SURFACE_PRIVATE_H + +#include + +#include "rdtk_engine.h" + +struct rdtk_surface +{ + rdtkEngine* engine; + + int width; + int height; + int scanline; + BYTE* data; + BOOL owner; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +rdtkSurface* rdtk_surface_new(rdtkEngine* engine, BYTE* data, int width, int height, int scanline); +void rdtk_surface_free(rdtkSurface* surface); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_SURFACE_PRIVATE_H */ + diff --git a/rdtk/librdtk/rdtk_text_field.c b/rdtk/librdtk/rdtk_text_field.c new file mode 100644 index 000000000..e5865ec52 --- /dev/null +++ b/rdtk/librdtk/rdtk_text_field.c @@ -0,0 +1,115 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 "rdtk_font.h" + +#include "rdtk_text_field.h" + +int rdtk_text_field_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight, + rdtkTextField* textField, const char* text) +{ + int offsetX; + int offsetY; + int textWidth; + int textHeight; + int fillWidth; + int fillHeight; + rdtkFont* font; + rdtkEngine* engine; + rdtkNinePatch* ninePatch; + + engine = surface->engine; + font = engine->font; + textField = surface->engine->textField; + ninePatch = textField->ninePatch; + + rdtk_font_text_draw_size(font, &textWidth, &textHeight, text); + + rdtk_nine_patch_draw(surface, nXDst, nYDst, nWidth, nHeight, ninePatch); + + if ((textWidth > 0) && (textHeight > 0)) + { + fillWidth = nWidth - (ninePatch->width - ninePatch->fillWidth); + fillHeight = nHeight - (ninePatch->height - ninePatch->fillHeight); + + offsetX = ninePatch->fillLeft; + offsetY = ninePatch->fillTop; + + if (textWidth < fillWidth) + offsetX = ((fillWidth - textWidth) / 2) + ninePatch->fillLeft; + else if (textWidth < ninePatch->width) + offsetX = ((ninePatch->width - textWidth) / 2); + + if (textHeight < fillHeight) + offsetY = ((fillHeight - textHeight) / 2) + ninePatch->fillTop; + else if (textHeight < ninePatch->height) + offsetY = ((ninePatch->height - textHeight) / 2); + + rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text); + } + + return 1; +} + +rdtkTextField* rdtk_text_field_new(rdtkEngine* engine, rdtkNinePatch* ninePatch) +{ + rdtkTextField* textField; + + textField = (rdtkTextField*) calloc(1, sizeof(rdtkTextField)); + + if (!textField) + return NULL; + + textField->engine = engine; + textField->ninePatch = ninePatch; + + return textField; +} + +void rdtk_text_field_free(rdtkTextField* textField) +{ + if (!textField) + return; + + free(textField); +} + +int rdtk_text_field_engine_init(rdtkEngine* engine) +{ + if (!engine->textField) + { + engine->textField = rdtk_text_field_new(engine, engine->textField9patch); + } + + return 1; +} + +int rdtk_text_field_engine_uninit(rdtkEngine* engine) +{ + if (engine->textField) + { + rdtk_text_field_free(engine->textField); + engine->textField = NULL; + } + + return 1; +} diff --git a/rdtk/librdtk/rdtk_text_field.h b/rdtk/librdtk/rdtk_text_field.h new file mode 100644 index 000000000..ba03afa30 --- /dev/null +++ b/rdtk/librdtk/rdtk_text_field.h @@ -0,0 +1,50 @@ +/** + * RdTk: Remote Desktop Toolkit + * + * 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 RDTK_TEXT_FIELD_PRIVATE_H +#define RDTK_TEXT_FIELD_PRIVATE_H + +#include + +#include "rdtk_surface.h" +#include "rdtk_nine_patch.h" + +#include "rdtk_engine.h" + +struct rdtk_text_field +{ + rdtkEngine* engine; + rdtkNinePatch* ninePatch; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int rdtk_text_field_engine_init(rdtkEngine* engine); +int rdtk_text_field_engine_uninit(rdtkEngine* engine); + +rdtkTextField* rdtk_text_field_new(rdtkEngine* engine, rdtkNinePatch* ninePatch); +void rdtk_text_field_free(rdtkTextField* textField); + +#ifdef __cplusplus +} +#endif + +#endif /* RDTK_TEXT_FIELD_PRIVATE_H */ + diff --git a/rdtk/librdtk/test/.gitignore b/rdtk/librdtk/test/.gitignore new file mode 100644 index 000000000..409b2b6bc --- /dev/null +++ b/rdtk/librdtk/test/.gitignore @@ -0,0 +1,4 @@ +TestRdTk +TestRdTk.c + + diff --git a/rdtk/librdtk/test/CMakeLists.txt b/rdtk/librdtk/test/CMakeLists.txt new file mode 100644 index 000000000..c570541ed --- /dev/null +++ b/rdtk/librdtk/test/CMakeLists.txt @@ -0,0 +1,25 @@ + +set(MODULE_NAME "TestRdTk") +set(MODULE_PREFIX "TEST_RDTK") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestRdTkNinePatch.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} rdtk) + +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 "RdTk/Test") diff --git a/rdtk/librdtk/test/TestRdTkNinePatch.c b/rdtk/librdtk/test/TestRdTkNinePatch.c new file mode 100644 index 000000000..fb50dee8c --- /dev/null +++ b/rdtk/librdtk/test/TestRdTkNinePatch.c @@ -0,0 +1,13 @@ + +#include + +int TestRdTkNinePatch(int argc, char* argv[]) +{ + rdtkEngine* engine; + + engine = rdtk_engine_new(); + + rdtk_engine_free(engine); + + return 0; +} diff --git a/resources/FreeRDP_Icon.png b/resources/FreeRDP_Icon.png index 40792cc1a..397e62d8f 100644 Binary files a/resources/FreeRDP_Icon.png and b/resources/FreeRDP_Icon.png differ diff --git a/resources/FreeRDP_Icon_256px.png b/resources/FreeRDP_Icon_256px.png index b43d8c5cd..66489e1a1 100644 Binary files a/resources/FreeRDP_Icon_256px.png and b/resources/FreeRDP_Icon_256px.png differ diff --git a/resources/FreeRDP_Logo.png b/resources/FreeRDP_Logo.png index 3b2d02f1d..1e272627b 100644 Binary files a/resources/FreeRDP_Logo.png and b/resources/FreeRDP_Logo.png differ diff --git a/scripts/android_setup_build_env.sh b/scripts/android_setup_build_env.sh index f60fca422..9d0fd2749 100755 --- a/scripts/android_setup_build_env.sh +++ b/scripts/android_setup_build_env.sh @@ -12,10 +12,19 @@ # android_setup_build_env.sh OPENSSL_SCM=https://github.com/akallabeth/openssl-android.git +OPENSSL_TAG=1.0.1h-fips-2.0.7 NDK_PROFILER_SCM=https://github.com/richq/android-ndk-profiler.git JPEG_LIBRARY_SCM=https://github.com/akallabeth/jpeg8d.git -SCRIPT_NAME=`basename $0` +SCRIPT_NAME=$(basename $0) + +if [ -x $ANDROID_NDK/ndk-build ]; then + NDK_BUILD=$ANDROID_NDK/ndk-build +else + echo "ndk-build not found in NDK directory $ANDROID_NDK" + echo "assuming ndk-build is in path..." + NDK_BUILD=ndk-build +fi if [ $# -ne 1 ]; then @@ -36,7 +45,7 @@ echo "Preparing OpenSSL..." OPENSSL_SRC=$ROOT/openssl-build if [ -d $OPENSSL_SRC ]; then cd $OPENSSL_SRC - git pull + git fetch RETVAL=$? else git clone $OPENSSL_SCM $OPENSSL_SRC @@ -47,13 +56,15 @@ if [ $RETVAL -ne 0 ]; then exit -3 fi cd $OPENSSL_SRC + +# We want to build a specific TAG +git checkout $OPENSSL_TAG + make clean # The makefile has a bug, which aborts during # first compilation. Rerun make to build the whole lib. make -make -make -RETVAL=0 # TODO: Check, why 2 is returned. +RETVAL=$? if [ $RETVAL -ne 0 ]; then echo "Failed to execute make command [$RETVAL]" exit -4 @@ -86,11 +97,11 @@ if [ $RETVAL -ne 0 ]; then exit -5 fi cd $NDK_PROFILER_SRC -ndk-build V=1 APP_ABI=armeabi-v7a clean -ndk-build V=1 APP_ABI=armeabi-v7a +$NDK_BUILD V=1 APP_ABI=armeabi-v7a clean +$NDK_BUILD V=1 APP_ABI=armeabi-v7a RETVAL=$? if [ $RETVAL -ne 0 ]; then - echo "Failed to execute ndk-build command [$RETVAL]" + echo "Failed to execute $NDK_BUILD command [$RETVAL]" exit -6 fi @@ -109,11 +120,11 @@ if [ $RETVAL -ne 0 ]; then exit -6 fi cd $JPEG_LIBRARY_SRC -ndk-build V=1 APP_ABI=armeabi-v7a clean -ndk-build V=1 APP_ABI=armeabi-v7a +$NDK_BUILD V=1 APP_ABI=armeabi-v7a clean +$NDK_BUILD V=1 APP_ABI=armeabi-v7a RETVAL=$? if [ $RETVAL -ne 0 ]; then - echo "Failed to execute ndk-build command [$RETVAL]" + echo "Failed to execute $NDK_BUILD command [$RETVAL]" exit -7 fi mkdir -p $JPEG_LIBRARY_SRC/lib diff --git a/scripts/autoformat.sh b/scripts/autoformat.sh new file mode 100755 index 000000000..4598975ca --- /dev/null +++ b/scripts/autoformat.sh @@ -0,0 +1,10 @@ +#!/bin/sh +MY_PATH="`dirname \"$0\"`" # relative +MY_PATH="`( cd \"$MY_PATH\" && pwd )`" # absolutized and normalized +CHANGESET=`git status | cut -d ':' -f 2 | grep -vE "#|no" | grep -E "*\.h|*\.c"` # get filenames from git status + +for f in $CHANGESET; do + if [ -e $f ]; then + sh $MY_PATH/format_code.sh $f + fi +done diff --git a/scripts/format_code.sh b/scripts/format_code.sh index d4c30e020..9ea3fbf95 100755 --- a/scripts/format_code.sh +++ b/scripts/format_code.sh @@ -1,23 +1,38 @@ -#!/bin/sh +#!/bin/bash -ASTYLE=`which astyle` +ASTYLE=$(which astyle) -if [ ! -x $ASTYLE ]; -then +if [ ! -x $ASTYLE ]; then echo "No astyle found in path, please install." exit 1 fi +# Need at least astyle 2.03 due to bugs in older versions +# indenting headers with extern "C" +STR_VERSION=$(($ASTYLE --version) 2>&1) +VERSION=$(echo $STR_VERSION | cut -d ' ' -f4) +MAJOR_VERSION=$(echo $VERSION | cut -d'.' -f1) +MINOR_VERSION=$(echo $VERSION | cut -d'.' -f2) + +if [ "$MAJOR_VERSION" -lt "2" ]; then + echo "Your version of astyle($VERSION) is too old, need at least 2.03" + exit 1 +fi + +if [ "$MINOR_VERSION" -lt "3" ]; then + echo "Your version of astyle($VERSION) is too old, need at least 2.03" + exit 1 +fi + if [ $# -le 0 ]; then echo "Usage:" - echo "\t$0 [ ...]" -# echo "\t$0 -r " + echo -e "\t$0 [ ...]" exit 2 fi $ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux --pad-header \ - --indent-switches --indent-cases --indent-preprocessor \ - --indent-col1-comments --delete-empty-lines --break-closing-brackets \ - --align-pointer=name --indent-labels --brackets=break \ - --unpad-paren --break-blocks $@ -exit $? + --indent-switches --indent-cases --indent-preprocessor \ + --indent-col1-comments --delete-empty-lines --break-closing-brackets \ + --align-pointer=type --indent-labels --brackets=break \ + --unpad-paren --break-blocks $@ + exit $? diff --git a/server/.gitignore b/server/.gitignore index b5581fbbc..ef902f781 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -4,4 +4,5 @@ !/Sample !/Windows !/X11 +!/shadow !/CmakeLists.txt diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index a361a8b63..75acf2563 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -18,6 +18,7 @@ # Servers add_subdirectory(common) +add_subdirectory(shadow) if(FREERDP_VENDOR) if(WITH_SAMPLE) @@ -25,15 +26,11 @@ if(FREERDP_VENDOR) endif() if(NOT WIN32) - if(WITH_X11) - add_subdirectory(X11) - endif() - if(APPLE AND (NOT IOS)) - add_subdirectory(Mac) + #add_subdirectory(Mac) endif() else() - add_subdirectory(Windows) + #add_subdirectory(Windows) endif() if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/FreeRDS") @@ -62,3 +59,4 @@ endforeach() foreach(FREERDP_SERVER ${FREERDP_EXTRA_SERVERS}) add_subdirectory(${FREERDP_SERVER}) endforeach() + diff --git a/server/Mac/CMakeLists.txt b/server/Mac/CMakeLists.txt index 50cfc1fc1..4217d5477 100644 --- a/server/Mac/CMakeLists.txt +++ b/server/Mac/CMakeLists.txt @@ -67,15 +67,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${IOSURFACE} ${CARBON}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-utils freerdp-codec freerdp-primitives) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/server/Mac/mf_audin.c b/server/Mac/mf_audin.c index 94de80984..dd32ca7bf 100644 --- a/server/Mac/mf_audin.c +++ b/server/Mac/mf_audin.c @@ -25,28 +25,28 @@ #include "mf_audin.h" +#include +#define TAG SERVER_TAG("mac") + static const AUDIO_FORMAT supported_audio_formats[] = { - { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, NULL }, { WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, NULL } }; static void mf_peer_audin_opening(audin_server_context* context) { - fprintf(stderr, "AUDIN opening.\n"); - /* Simply choose the first format supported by the client. */ context->SelectFormat(context, 0); } static void mf_peer_audin_open_result(audin_server_context* context, UINT32 result) { - fprintf(stderr, "AUDIN open result %d.\n", result); + } static void mf_peer_audin_receive_samples(audin_server_context* context, const void* buf, int nframes) { - fprintf(stderr, "AUDIN receive %d frames.\n", nframes); + } void mf_peer_audin_init(mfPeerContext* context) diff --git a/server/Mac/mf_audin.h b/server/Mac/mf_audin.h index 188cdaefa..d3e172b97 100644 --- a/server/Mac/mf_audin.h +++ b/server/Mac/mf_audin.h @@ -1,34 +1,34 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Mac OS X Server (Audio Input) - * - * Copyright 2012 Marc-Andre Moreau - * Copyright 2013 Corey Clayton - * - * 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 MF_AUDIN_H -#define MF_AUDIN_H - -#include -#include - -#include "mf_interface.h" -#include "mfreerdp.h" - - -void mf_peer_audin_init(mfPeerContext* context); - -#endif /* MF_AUDIN_H */ - +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server (Audio Input) + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2013 Corey Clayton + * + * 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 MF_AUDIN_H +#define MF_AUDIN_H + +#include +#include + +#include "mf_interface.h" +#include "mfreerdp.h" + + +void mf_peer_audin_init(mfPeerContext* context); + +#endif /* MF_AUDIN_H */ + diff --git a/server/Mac/mf_event.c b/server/Mac/mf_event.c index 6e68e6b85..70971e1ab 100644 --- a/server/Mac/mf_event.c +++ b/server/Mac/mf_event.c @@ -26,10 +26,12 @@ #include #include #include -//#include #include "mf_event.h" +#include +#define TAG SERVER_TAG("mac") + int mf_is_event_set(mfEventQueue* event_queue) { fd_set rfds; @@ -51,7 +53,7 @@ void mf_signal_event(mfEventQueue* event_queue) length = write(event_queue->pipe_fd[1], "sig", 4); if (length != 4) - fprintf(stderr, "mf_signal_event: error\n"); + WLog_ERR(TAG, "mf_signal_event: error"); } void mf_set_event(mfEventQueue* event_queue) @@ -61,7 +63,7 @@ void mf_set_event(mfEventQueue* event_queue) length = write(event_queue->pipe_fd[1], "sig", 4); if (length != 4) - fprintf(stderr, "mf_set_event: error\n"); + WLog_ERR(TAG, "mf_set_event: error"); } void mf_clear_events(mfEventQueue* event_queue) @@ -73,7 +75,7 @@ void mf_clear_events(mfEventQueue* event_queue) length = read(event_queue->pipe_fd[0], &length, 4); if (length != 4) - fprintf(stderr, "mf_clear_event: error\n"); + WLog_ERR(TAG, "mf_clear_event: error"); } } @@ -84,7 +86,7 @@ void mf_clear_event(mfEventQueue* event_queue) length = read(event_queue->pipe_fd[0], &length, 4); if (length != 4) - fprintf(stderr, "mf_clear_event: error\n"); + WLog_ERR(TAG, "mf_clear_event: error"); } void mf_event_push(mfEventQueue* event_queue, mfEvent* event) @@ -188,7 +190,7 @@ mfEventQueue* mf_event_queue_new() event_queue->events = (mfEvent**) malloc(sizeof(mfEvent*) * event_queue->size); if (pipe(event_queue->pipe_fd) < 0) - fprintf(stderr, "mf_event_queue_new: pipe failed\n"); + return NULL; pthread_mutex_init(&(event_queue->mutex), NULL); } diff --git a/server/Mac/mf_event.h b/server/Mac/mf_event.h index edf648332..a9111a67f 100644 --- a/server/Mac/mf_event.h +++ b/server/Mac/mf_event.h @@ -18,7 +18,7 @@ */ #ifndef __MF_EVENT_H -#define __XMF_EVENT_H +#define __MF_EVENT_H typedef struct mf_event mfEvent; typedef struct mf_event_queue mfEventQueue; diff --git a/server/Mac/mf_info.c b/server/Mac/mf_info.c index 7c79eb335..c65fbe7d0 100644 --- a/server/Mac/mf_info.c +++ b/server/Mac/mf_info.c @@ -1,309 +1,231 @@ -/** - * FreeRDP: A Remote Desktop Protocol Client - * FreeRDP Mac OS X Server - * - * Copyright 2012 Corey Clayton - * - * 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 "mf_info.h" -#include "mf_mountain_lion.h" -//#include "mf_update.h" - -static mfInfo* mfInfoInstance = NULL; -//static int _IDcount = 0; - -int mf_info_lock(mfInfo* mfi) -{ - - int status = pthread_mutex_lock(&mfi->mutex); - - switch (status) { - case 0: - return TRUE; - break; - - default: - printf("mf_info_lock failed with %#X\n", status); - return -1; - break; - } - -} - -int mf_info_try_lock(mfInfo* mfi, UINT32 ms) -{ - - int status = pthread_mutex_trylock(&mfi->mutex); - - switch (status) { - case 0: - return TRUE; - break; - - case EBUSY: - return FALSE; - break; - - default: - printf("mf_info_try_lock failed with %#X\n", status); - return -1; - break; - } - -} - -int mf_info_unlock(mfInfo* mfi) -{ - int status = pthread_mutex_unlock(&mfi->mutex); - - switch (status) { - case 0: - return TRUE; - break; - - default: - printf("mf_info_unlock failed with %#X\n", status); - return -1; - break; - } - -} - -mfInfo* mf_info_init() -{ - mfInfo* mfi; - - mfi = (mfInfo*) malloc(sizeof(mfInfo)); - memset(mfi, 0, sizeof(mfInfo)); - - - if (mfi != NULL) - { - /* HKEY hKey; - LONG status; - DWORD dwType; - DWORD dwSize; - DWORD dwValue; - */ - - int mutexInitStatus = pthread_mutex_init(&mfi->mutex, NULL); - - if (mutexInitStatus != 0) - { - printf(_T("CreateMutex error: %#X\n"), mutexInitStatus); - } - - mfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); - memset(mfi->peers, 0, sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); - - //Set FPS - mfi->framesPerSecond = MF_INFO_DEFAULT_FPS; - - /*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - if (status == ERROR_SUCCESS) - { - if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) - mfi->framesPerSecond = dwValue; - } - RegCloseKey(hKey);*/ - - //Set input toggle - mfi->input_disabled = FALSE; - - /*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - if (status == ERROR_SUCCESS) - { - if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) - { - if (dwValue != 0) - mfi->input_disabled = TRUE; - } - } - RegCloseKey(hKey);*/ - - - } - - return mfi; -} - -mfInfo* mf_info_get_instance() -{ - if (mfInfoInstance == NULL) - mfInfoInstance = mf_info_init(); - - return mfInfoInstance; -} - -void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context) -{ - if (mf_info_lock(mfi) > 0) - { - int i; - int peerId; - if (mfi->peerCount == MF_INFO_MAXPEERS) - { - printf("TODO: socketClose on OS X\n"); - //context->socketClose = TRUE; - mf_info_unlock(mfi); - return; - } - - context->info = mfi; - - //get the offset of the top left corner of selected screen - //EnumDisplayMonitors(NULL, NULL, mf_info_monEnumCB, 0); - //_IDcount = 0; - - //initialize screen capture - if (mfi->peerCount == 0) - { - mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale); - mf_mlion_screen_updates_init(); - mf_mlion_start_getting_screen_updates(); - } - - //look trhough the array of peers until an empty slot - peerId = NULL; - for(i=0; ipeers[i] == NULL) - { - peerId = i; - break; - } - } - - mfi->peers[peerId] = ((rdpContext*) context)->peer; - mfi->peers[peerId]->pId = peerId; - mfi->peerCount++; - //printf("Registering Peer: id=%d #=%d\n", peerId, mfi->peerCount); - - mf_info_unlock(mfi); - - //mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_CONNECT); - } -} - -void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context) -{ - if (mf_info_lock(mfi) > 0) - { - int peerId; - - peerId = ((rdpContext*) context)->peer->pId; - mfi->peers[peerId] = NULL; - mfi->peerCount--; - - //printf("Unregistering Peer: id=%d, #=%d\n", peerId, mfi->peerCount); - - //screen capture cleanup - if (mfi->peerCount == 0) - { - mf_mlion_stop_getting_screen_updates(); - } - mf_info_unlock(mfi); - - //mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_DISCONNECT); - } -} - -BOOL mf_info_have_updates(mfInfo* mfi) -{ - if(mfi->framesWaiting == 0) - return FALSE; - - return TRUE; -} - -void mf_info_update_changes(mfInfo* mfi) -{ - /*#ifdef WITH_WIN8 - mf_dxgi_nextFrame(mfi, mfi->framesPerSecond * 1000); - #else - GETCHANGESBUF* buf; - - buf = (GETCHANGESBUF*) mfi->changeBuffer; - mfi->nextUpdate = buf->buffer->counter; - #endif*/ -} - -void mf_info_find_invalid_region(mfInfo* mfi) -{ - mf_mlion_get_dirty_region(&mfi->invalid); -} - -void mf_info_clear_invalid_region(mfInfo* mfi) -{ - mf_mlion_clear_dirty_region(); - mfi->invalid.height = 0; - mfi->invalid.width = 0; -} - -void mf_info_invalidate_full_screen(mfInfo* mfi) -{ - mfi->invalid.x = 0; - mfi->invalid.y = 0; - mfi->invalid.height = mfi->servscreen_height; - mfi->invalid.height = mfi->servscreen_width; -} - -BOOL mf_info_have_invalid_region(mfInfo* mfi) -{ - if (mfi->invalid.width * mfi->invalid.height == 0) { - return FALSE; - } - return TRUE; -} - -void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch) -{ - *width = mfi->invalid.width / mfi->scale; - *height = mfi->invalid.height / mfi->scale; - *pitch = mfi->servscreen_width * mfi->scale * 4; - - mf_mlion_get_pixelData(mfi->invalid.x / mfi->scale, mfi->invalid.y / mfi->scale, *width, *height, pBits); - - *pBits = *pBits + (mfi->invalid.x * 4) + (*pitch * mfi->invalid.y); - -} - -/* - BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) - { - mfInfo * mfi; - - mfi = mf_info_get_instance(); - - if(_IDcount == mfi->screenID) - { - mfi->servscreen_xoffset = lprcMonitor->left; - mfi->servscreen_yoffset = lprcMonitor->top; - } - - _IDcount++; - - return TRUE; - } - */ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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 "mf_info.h" +#include "mf_mountain_lion.h" + +static mfInfo* mfInfoInstance = NULL; + +int mf_info_lock(mfInfo* mfi) +{ + int status = pthread_mutex_lock(&mfi->mutex); + + switch (status) + { + case 0: + return TRUE; + break; + + default: + return -1; + break; + } + + return 1; +} + +int mf_info_try_lock(mfInfo* mfi, UINT32 ms) +{ + int status = pthread_mutex_trylock(&mfi->mutex); + + switch (status) + { + case 0: + return TRUE; + break; + + case EBUSY: + return FALSE; + break; + + default: + return -1; + break; + } + + return 1; +} + +int mf_info_unlock(mfInfo* mfi) +{ + int status = pthread_mutex_unlock(&mfi->mutex); + + switch (status) + { + case 0: + return TRUE; + break; + + default: + return -1; + break; + } + + return 1; +} + +mfInfo* mf_info_init() +{ + mfInfo* mfi; + + mfi = (mfInfo*) malloc(sizeof(mfInfo)); + memset(mfi, 0, sizeof(mfInfo)); + + if (mfi != NULL) + { + pthread_mutex_init(&mfi->mutex, NULL); + + mfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); + memset(mfi->peers, 0, sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); + + mfi->framesPerSecond = MF_INFO_DEFAULT_FPS; + + mfi->input_disabled = FALSE; + } + + return mfi; +} + +mfInfo* mf_info_get_instance() +{ + if (mfInfoInstance == NULL) + mfInfoInstance = mf_info_init(); + + return mfInfoInstance; +} + +void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context) +{ + if (mf_info_lock(mfi) > 0) + { + int i; + int peerId; + + if (mfi->peerCount == MF_INFO_MAXPEERS) + { + mf_info_unlock(mfi); + return; + } + + context->info = mfi; + + if (mfi->peerCount == 0) + { + mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale); + mf_mlion_screen_updates_init(); + mf_mlion_start_getting_screen_updates(); + } + + peerId = NULL; + + for(i=0; ipeers[i] == NULL) + { + peerId = i; + break; + } + } + + mfi->peers[peerId] = ((rdpContext*) context)->peer; + mfi->peers[peerId]->pId = peerId; + mfi->peerCount++; + + mf_info_unlock(mfi); + } +} + +void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context) +{ + if (mf_info_lock(mfi) > 0) + { + int peerId; + + peerId = ((rdpContext*) context)->peer->pId; + mfi->peers[peerId] = NULL; + mfi->peerCount--; + + if (mfi->peerCount == 0) + mf_mlion_stop_getting_screen_updates(); + + mf_info_unlock(mfi); + } +} + +BOOL mf_info_have_updates(mfInfo* mfi) +{ + if(mfi->framesWaiting == 0) + return FALSE; + + return TRUE; +} + +void mf_info_update_changes(mfInfo* mfi) +{ + +} + +void mf_info_find_invalid_region(mfInfo* mfi) +{ + mf_mlion_get_dirty_region(&mfi->invalid); +} + +void mf_info_clear_invalid_region(mfInfo* mfi) +{ + mf_mlion_clear_dirty_region(); + mfi->invalid.height = 0; + mfi->invalid.width = 0; +} + +void mf_info_invalidate_full_screen(mfInfo* mfi) +{ + mfi->invalid.x = 0; + mfi->invalid.y = 0; + mfi->invalid.height = mfi->servscreen_height; + mfi->invalid.height = mfi->servscreen_width; +} + +BOOL mf_info_have_invalid_region(mfInfo* mfi) +{ + if (mfi->invalid.width * mfi->invalid.height == 0) + return FALSE; + + return TRUE; +} + +void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch) +{ + *width = mfi->invalid.width / mfi->scale; + *height = mfi->invalid.height / mfi->scale; + *pitch = mfi->servscreen_width * mfi->scale * 4; + + mf_mlion_get_pixelData(mfi->invalid.x / mfi->scale, mfi->invalid.y / mfi->scale, *width, *height, pBits); + + *pBits = *pBits + (mfi->invalid.x * 4) + (*pitch * mfi->invalid.y); + +} diff --git a/server/Mac/mf_info.h b/server/Mac/mf_info.h index ba2a58ed3..da420c3f5 100644 --- a/server/Mac/mf_info.h +++ b/server/Mac/mf_info.h @@ -1,50 +1,50 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Mac OS X Server - * - * Copyright 2012 Corey Clayton - * - * 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 MF_INFO_H -#define MF_INFO_H - -#define MF_INFO_DEFAULT_FPS 1 -#define MF_INFO_MAXPEERS 1 - - - -#include -#include - -#include "mf_interface.h" - -int mf_info_lock(mfInfo* mfi); -int mf_info_try_lock(mfInfo* mfi, UINT32 ms); -int mf_info_unlock(mfInfo* mfi); - -mfInfo* mf_info_get_instance(void); -void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context); -void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context); - -BOOL mf_info_have_updates(mfInfo* mfi); -void mf_info_update_changes(mfInfo* mfi); -void mf_info_find_invalid_region(mfInfo* mfi); -void mf_info_clear_invalid_region(mfInfo* mfi); -void mf_info_invalidate_full_screen(mfInfo* mfi); -BOOL mf_info_have_invalid_region(mfInfo* mfi); -void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch); -//BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); - -#endif /* mf_info_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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 MF_INFO_H +#define MF_INFO_H + +#define MF_INFO_DEFAULT_FPS 1 +#define MF_INFO_MAXPEERS 1 + + + +#include +#include + +#include "mf_interface.h" + +int mf_info_lock(mfInfo* mfi); +int mf_info_try_lock(mfInfo* mfi, UINT32 ms); +int mf_info_unlock(mfInfo* mfi); + +mfInfo* mf_info_get_instance(void); +void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context); +void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context); + +BOOL mf_info_have_updates(mfInfo* mfi); +void mf_info_update_changes(mfInfo* mfi); +void mf_info_find_invalid_region(mfInfo* mfi); +void mf_info_clear_invalid_region(mfInfo* mfi); +void mf_info_invalidate_full_screen(mfInfo* mfi); +BOOL mf_info_have_invalid_region(mfInfo* mfi); +void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch); +//BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); + +#endif /* mf_info_H */ diff --git a/server/Mac/mf_input.c b/server/Mac/mf_input.c index ce58f5476..dbfb617d7 100644 --- a/server/Mac/mf_input.c +++ b/server/Mac/mf_input.c @@ -29,7 +29,11 @@ #include "mf_input.h" #include "mf_info.h" -static const CGKeyCode keymap[256] = { +#include +#define TAG SERVER_TAG("mac") + +static const CGKeyCode keymap[256] = +{ 0xFF, //0x0 kVK_Escape, //0x1 kVK_ANSI_1, //0x2 @@ -353,31 +357,11 @@ void mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) CGEventPost(kCGHIDEventTap, kbEvent); CFRelease(kbEvent); CFRelease(source); - - /* - if (flags & KBD_FLAGS_EXTENDED) - fprintf(stderr, "extended "); - fprintf(stderr, "keypress: down = %d, SCAN=%#0X, VK=%#0X\n", keyDown, code, keymap[code]); - */ } void mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { - /* - INPUT keyboard_event; - - keyboard_event.type = INPUT_KEYBOARD; - keyboard_event.ki.wVk = 0; - keyboard_event.ki.wScan = code; - keyboard_event.ki.dwFlags = KEYEVENTF_UNICODE; - keyboard_event.ki.dwExtraInfo = 0; - keyboard_event.ki.time = 0; - - if (flags & KBD_FLAGS_RELEASE) - keyboard_event.ki.dwFlags |= KEYEVENTF_KEYUP; - - SendInput(1, &keyboard_event, sizeof(INPUT)); - */ + } void mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) @@ -412,34 +396,6 @@ void mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) CFRelease(scroll); CFRelease(source); } - /* - /////////////////////////////////////////////// - // We dont support horizontal scrolling yet... - /////////////////////////////////////////////// - else if (flags & PTR_FLAGS_) - { - scroll_y = flags & WheelRotationMask; - - if (flags & PTR_FLAGS_WHEEL_NEGATIVE) - { - scroll_y = -(flags & WheelRotationMask) / 392; - } - else - { - scroll_y = (flags & WheelRotationMask) / 120; - } - - CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState); - CGEventRef scroll = CGEventCreateScrollWheelEvent(source, - kCGScrollEventUnitLine, - wheelCount, - scroll_y, - scroll_x); - CGEventPost(kCGHIDEventTap, scroll); - - CFRelease(scroll); - CFRelease(source); - } */ else { @@ -548,56 +504,7 @@ void mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) void mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { - fprintf(stderr, "Unhandled mouse event!!!\n"); - /* - if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2)) - { - INPUT mouse_event; - ZeroMemory(&mouse_event, sizeof(INPUT)); - - mouse_event.type = INPUT_MOUSE; - - if (flags & PTR_FLAGS_MOVE) - { - float width, height; - wfInfo * wfi; - - wfi = wf_info_get_instance(); - //width and height of primary screen (even in multimon setups - width = (float) GetSystemMetrics(SM_CXSCREEN); - height = (float) GetSystemMetrics(SM_CYSCREEN); - - x += wfi->servscreen_xoffset; - y += wfi->servscreen_yoffset; - - //mouse_event.mi.dx = x * (0xFFFF / width); - //mouse_event.mi.dy = y * (0xFFFF / height); - mouse_event.mi.dx = (LONG) ((float) x * (65535.0f / width)); - mouse_event.mi.dy = (LONG) ((float) y * (65535.0f / height)); - mouse_event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - - SendInput(1, &mouse_event, sizeof(INPUT)); - } - - mouse_event.mi.dx = mouse_event.mi.dy = mouse_event.mi.dwFlags = 0; - - if (flags & PTR_XFLAGS_DOWN) - mouse_event.mi.dwFlags |= MOUSEEVENTF_XDOWN; - else - mouse_event.mi.dwFlags |= MOUSEEVENTF_XUP; - - if (flags & PTR_XFLAGS_BUTTON1) - mouse_event.mi.mouseData = XBUTTON1; - else if (flags & PTR_XFLAGS_BUTTON2) - mouse_event.mi.mouseData = XBUTTON2; - - SendInput(1, &mouse_event, sizeof(INPUT)); - } - else - { - mf_input_mouse_event(input, flags, x, y); - } - */ + } diff --git a/server/Mac/mf_mountain_lion.c b/server/Mac/mf_mountain_lion.c index 88d59033a..0b8c9125c 100644 --- a/server/Mac/mf_mountain_lion.c +++ b/server/Mac/mf_mountain_lion.c @@ -82,24 +82,19 @@ void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisp if (status != kCGDisplayStreamFrameStatusFrameComplete) { - //unhandled switch(status) { case kCGDisplayStreamFrameStatusFrameIdle: - printf("kCGDisplayStreamFrameStatusFrameIdle\n"); break; case kCGDisplayStreamFrameStatusStopped: - //we dont need to clean up - //printf("kCGDisplayStreamFrameStatusStopped\n"); break; case kCGDisplayStreamFrameStatusFrameBlank: - printf("kCGDisplayStreamFrameStatusFrameBlank\n"); break; default: - printf("Unhandled Frame Status!!!\n"); + break; } } @@ -191,9 +186,9 @@ int mf_mlion_start_getting_screen_updates() CGError err; err = CGDisplayStreamStart(stream); - if(err != kCGErrorSuccess) + + if (err != kCGErrorSuccess) { - printf("Failed to start displaystream!! err = %d\n", err); return 1; } @@ -205,14 +200,14 @@ int mf_mlion_stop_getting_screen_updates() CGError err; err = CGDisplayStreamStop(stream); - if(err != kCGErrorSuccess) + + if (err != kCGErrorSuccess) { - printf("Failed to stop displaystream!! err = %d\n", err); return 1; } return 0; - + return 0; } @@ -225,7 +220,6 @@ int mf_mlion_get_dirty_region(RFX_RECT* invalid) mf_mlion_peek_dirty_region(invalid); } - dispatch_semaphore_signal(region_sem); return 0; @@ -283,4 +277,3 @@ int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxDat return 0; } - diff --git a/server/Mac/mf_peer.c b/server/Mac/mf_peer.c index 93ab74e6e..239aafd6d 100644 --- a/server/Mac/mf_peer.c +++ b/server/Mac/mf_peer.c @@ -1,501 +1,443 @@ -/** - * FreeRDP: A Remote Desktop Protocol Client - * FreeRDP Mac OS X Server - * - * Copyright 2012 Corey Clayton - * - * 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 - -#include "mf_peer.h" -#include "mf_info.h" -#include "mf_input.h" -#include "mf_event.h" -#include "mf_rdpsnd.h" - -#include -#include -#include - -#include "OpenGL/OpenGL.h" -#include "OpenGL/gl.h" - -#include "CoreVideo/CoreVideo.h" - -//refactor these -int info_last_sec = 0; -int info_last_nsec = 0; - -dispatch_source_t info_timer; -dispatch_queue_t info_queue; - -mfEventQueue* info_event_queue; - - -CGLContextObj glContext; -CGContextRef bmp; -CGImageRef img; - - - -BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) -{ - if (info_event_queue->pipe_fd[0] == -1) - return TRUE; - - rfds[*rcount] = (void *)(long) info_event_queue->pipe_fd[0]; - (*rcount)++; - - return TRUE; -} - -BOOL mf_peer_check_fds(freerdp_peer* client) -{ - mfPeerContext* context = (mfPeerContext*) client->context; - mfEvent* event; - - if (context->activated == FALSE) - return TRUE; - - event = mf_event_peek(info_event_queue); - - if (event != NULL) - { - if (event->type == MF_EVENT_TYPE_REGION) - { - fprintf(stderr, "unhandled event\n"); - } - else if (event->type == MF_EVENT_TYPE_FRAME_TICK) - { - event = mf_event_pop(info_event_queue); - - mf_peer_rfx_update(client); - - mf_event_free(event); - } - } - - return TRUE; -} - -void mf_peer_rfx_update(freerdp_peer* client) -{ - //check - mfInfo* mfi = mf_info_get_instance(); - - mf_info_find_invalid_region(mfi); - - if (mf_info_have_invalid_region(mfi) == false) { - return; - } - - - long width; - long height; - int pitch; - BYTE* dataBits = NULL; - - mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch); - - mf_info_clear_invalid_region(mfi); - - //encode - - wStream* s; - RFX_RECT rect; - rdpUpdate* update; - mfPeerContext* mfp; - SURFACE_BITS_COMMAND* cmd; - - update = client->update; - mfp = (mfPeerContext*) client->context; - cmd = &update->surface_bits_command; - - - s = mfp->s; - Stream_Clear(s); - Stream_SetPosition(s, 0); - - UINT32 x = mfi->invalid.x / mfi->scale; - UINT32 y = mfi->invalid.y / mfi->scale; - - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - - mfp->rfx_context->width = mfi->servscreen_width; - mfp->rfx_context->height = mfi->servscreen_height; - - rfx_compose_message(mfp->rfx_context, s, &rect, 1, - (BYTE*) dataBits, rect.width, rect.height, pitch); - - cmd->destLeft = x; - cmd->destTop = y; - cmd->destRight = x + rect.width; - cmd->destBottom = y + rect.height; - - - cmd->bpp = 32; - cmd->codecID = 3; - cmd->width = rect.width; - cmd->height = rect.height; - cmd->bitmapDataLength = Stream_GetPosition(s); - cmd->bitmapData = Stream_Buffer(s); - - //send - - update->SurfaceBits(update->context, cmd); - - //clean up... maybe? - -} - -/* Called when we have a new peer connecting */ -int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context) -{ - context->info = mf_info_get_instance(); - context->rfx_context = rfx_context_new(TRUE); - context->rfx_context->mode = RLGR3; - context->rfx_context->width = client->settings->DesktopWidth; - context->rfx_context->height = client->settings->DesktopHeight; - rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - - //context->nsc_context = nsc_context_new(); - //nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8); - - context->s = Stream_New(NULL, 0xFFFF); - - context->vcm = WTSOpenServerA((LPSTR) client->context); - - mf_info_peer_register(context->info, context); - - return 0; -} - -/* Called after a peer disconnects */ -void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context) -{ - if (context) - { - mf_info_peer_unregister(context->info, context); - - dispatch_suspend(info_timer); - - Stream_Free(context->s, TRUE); - - rfx_context_free(context->rfx_context); - //nsc_context_free(context->nsc_context); - -#ifdef CHANNEL_AUDIN_SERVER - if (context->audin) - audin_server_context_free(context->audin); -#endif - - //#ifdef CHANNEL_RDPSND_SERVER - mf_peer_rdpsnd_stop(); - if (context->rdpsnd) - rdpsnd_server_context_free(context->rdpsnd); - //#endif - - WTSCloseServer(context->vcm); - } -} - -/* Called when a new client connects */ -void mf_peer_init(freerdp_peer* client) -{ - client->ContextSize = sizeof(mfPeerContext); - client->ContextNew = (psPeerContextNew) mf_peer_context_new; - client->ContextFree = (psPeerContextFree) mf_peer_context_free; - freerdp_peer_context_new(client); - - info_event_queue = mf_event_queue_new(); - - info_queue = dispatch_queue_create("FreeRDP.update.timer", DISPATCH_QUEUE_SERIAL); - info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue); - - if(info_timer) - { - //fprintf(stderr, "created timer\n"); - dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 42ull * NSEC_PER_MSEC, 100ull * NSEC_PER_MSEC); - dispatch_source_set_event_handler(info_timer, ^{ - //fprintf(stderr, "dispatch\n"); - mfEvent* event = mf_event_new(MF_EVENT_TYPE_FRAME_TICK); - mf_event_push(info_event_queue, (mfEvent*) event);} - ); - dispatch_resume(info_timer); - } -} - -BOOL mf_peer_post_connect(freerdp_peer* client) -{ - mfPeerContext* context = (mfPeerContext*) client->context; - rdpSettings* settings = client->settings; - - fprintf(stderr, "Client %s post connect\n", client->hostname); - - if (client->settings->AutoLogonEnabled) - { - fprintf(stderr, " and wants to login automatically as %s\\%s", - client->settings->Domain ? client->settings->Domain : "", - client->settings->Username); - - /* A real server may perform OS login here if NLA is not executed previously. */ - } - fprintf(stderr, "\n"); - - mfInfo* mfi = mf_info_get_instance(); - mfi->scale = 1; - - //mfi->servscreen_width = 2880 / mfi->scale; - //mfi->servscreen_height = 1800 / mfi->scale; - UINT32 bitsPerPixel = 32; - - if ((settings->DesktopWidth != mfi->servscreen_width) || (settings->DesktopHeight != mfi->servscreen_height)) - { - fprintf(stderr, "Client requested resolution %dx%d, but will resize to %dx%d\n", - settings->DesktopWidth, settings->DesktopHeight, mfi->servscreen_width, mfi->servscreen_height); - } - - settings->DesktopWidth = mfi->servscreen_width; - settings->DesktopHeight = mfi->servscreen_height; - settings->ColorDepth = bitsPerPixel; - - client->update->DesktopResize(client->update->context); - - mfi->mouse_down_left = FALSE; - mfi->mouse_down_right = FALSE; - mfi->mouse_down_other = FALSE; - - if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) - { - mf_peer_rdpsnd_init(context); /* Audio Output */ - } - - /* Dynamic Virtual Channels */ - -#ifdef CHANNEL_AUDIN_SERVER - mf_peer_audin_init(context); /* Audio Input */ -#endif - - return TRUE; -} - -BOOL mf_peer_activate(freerdp_peer* client) -{ - mfPeerContext* context = (mfPeerContext*) client->context; - - rfx_context_reset(context->rfx_context); - context->activated = TRUE; - - return TRUE; -} - -void mf_peer_synchronize_event(rdpInput* input, UINT32 flags) -{ - fprintf(stderr, "Client sent a synchronize event (flags:0x%08X)\n", flags); -} - -void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ - fprintf(stderr, "Client sent a keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); - - UINT16 down = 0x4000; - //UINT16 up = 0x8000; - - bool state_down = FALSE; - - if (flags == down) - { - state_down = TRUE; - } - - /* - CGEventRef event; - event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, state_down); - CGEventPost(kCGHIDEventTap, event); - CFRelease(event); - */ -} - -void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ - fprintf(stderr, "Client sent a unicode keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); -} - -/*void mf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ - //fprintf(stderr, "Client sent a mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); -} - -void mf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ - //fprintf(stderr, "Client sent an extended mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); -} -*/ -/*static void mf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas) - { - BYTE i; - - fprintf(stderr, "Client requested to refresh:\n"); - - for (i = 0; i < count; i++) - { - fprintf(stderr, " (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom); - } - }*/ - -static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area) -{ - if (allow > 0) - { - fprintf(stderr, "Client restore output (%d, %d) (%d, %d).\n", area->left, area->top, area->right, area->bottom); - } - else - { - fprintf(stderr, "Client minimized and suppress output.\n"); - } -} - -void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) -{ - pthread_t th; - - pthread_create(&th, 0, mf_peer_main_loop, client); - pthread_detach(th); -} - -void* mf_peer_main_loop(void* arg) -{ - int i; - int fds; - int max_fds; - int rcount; - void* rfds[32]; - fd_set rfds_set; - mfPeerContext* context; - freerdp_peer* client = (freerdp_peer*) arg; - - memset(rfds, 0, sizeof(rfds)); - - mf_peer_init(client); - - /* Initialize the real server settings here */ - client->settings->CertificateFile = _strdup("server.crt"); - client->settings->PrivateKeyFile = _strdup("server.key"); - client->settings->NlaSecurity = FALSE; - client->settings->RemoteFxCodec = TRUE; - client->settings->ColorDepth = 32; - client->settings->SuppressOutput = TRUE; - client->settings->RefreshRect = FALSE; - - client->PostConnect = mf_peer_post_connect; - client->Activate = mf_peer_activate; - - client->input->SynchronizeEvent = mf_peer_synchronize_event; - client->input->KeyboardEvent = mf_input_keyboard_event;//mf_peer_keyboard_event; - client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event; - client->input->MouseEvent = mf_input_mouse_event; - client->input->ExtendedMouseEvent = mf_input_extended_mouse_event; - - //client->update->RefreshRect = mf_peer_refresh_rect; - client->update->SuppressOutput = mf_peer_suppress_output; - - client->Initialize(client); - context = (mfPeerContext*) client->context; - - fprintf(stderr, "We've got a client %s\n", client->local ? "(local)" : client->hostname); - - while (1) - { - rcount = 0; - - if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) - { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); - break; - } - if (mf_peer_get_fds(client, rfds, &rcount) != TRUE) - { - fprintf(stderr, "Failed to get mfreerdp file descriptor\n"); - break; - } - - WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); - - max_fds = 0; - FD_ZERO(&rfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - fprintf(stderr, "select failed\n"); - break; - } - } - - if (client->CheckFileDescriptor(client) != TRUE) - { - fprintf(stderr, "Failed to check freerdp file descriptor\n"); - break; - } - - if ((mf_peer_check_fds(client)) != TRUE) - { - fprintf(stderr, "Failed to check mfreerdp file descriptor\n"); - break; - } - - if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) - { - break; - } - } - - fprintf(stderr, "Client %s disconnected.\n", client->local ? "(local)" : client->hostname); - - client->Disconnect(client); - freerdp_peer_context_free(client); - freerdp_peer_free(client); - - return NULL; -} +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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 + +#include "mf_peer.h" +#include "mf_info.h" +#include "mf_input.h" +#include "mf_event.h" +#include "mf_rdpsnd.h" + +#include +#include +#include + +#include "OpenGL/OpenGL.h" +#include "OpenGL/gl.h" + +#include "CoreVideo/CoreVideo.h" + +//refactor these +int info_last_sec = 0; +int info_last_nsec = 0; + +dispatch_source_t info_timer; +dispatch_queue_t info_queue; + +mfEventQueue* info_event_queue; + + +CGLContextObj glContext; +CGContextRef bmp; +CGImageRef img; + + + +BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) +{ + if (info_event_queue->pipe_fd[0] == -1) + return TRUE; + + rfds[*rcount] = (void *)(long) info_event_queue->pipe_fd[0]; + (*rcount)++; + + return TRUE; +} + +BOOL mf_peer_check_fds(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*) client->context; + mfEvent* event; + + if (context->activated == FALSE) + return TRUE; + + event = mf_event_peek(info_event_queue); + + if (event != NULL) + { + if (event->type == MF_EVENT_TYPE_REGION) + { + + } + else if (event->type == MF_EVENT_TYPE_FRAME_TICK) + { + event = mf_event_pop(info_event_queue); + + mf_peer_rfx_update(client); + + mf_event_free(event); + } + } + + return TRUE; +} + +void mf_peer_rfx_update(freerdp_peer* client) +{ + //check + mfInfo* mfi = mf_info_get_instance(); + + mf_info_find_invalid_region(mfi); + + if (mf_info_have_invalid_region(mfi) == false) { + return; + } + + + long width; + long height; + int pitch; + BYTE* dataBits = NULL; + + mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch); + + mf_info_clear_invalid_region(mfi); + + //encode + + wStream* s; + RFX_RECT rect; + rdpUpdate* update; + mfPeerContext* mfp; + SURFACE_BITS_COMMAND* cmd; + + update = client->update; + mfp = (mfPeerContext*) client->context; + cmd = &update->surface_bits_command; + + + s = mfp->s; + Stream_Clear(s); + Stream_SetPosition(s, 0); + + UINT32 x = mfi->invalid.x / mfi->scale; + UINT32 y = mfi->invalid.y / mfi->scale; + + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + + mfp->rfx_context->width = mfi->servscreen_width; + mfp->rfx_context->height = mfi->servscreen_height; + + rfx_compose_message(mfp->rfx_context, s, &rect, 1, + (BYTE*) dataBits, rect.width, rect.height, pitch); + + cmd->destLeft = x; + cmd->destTop = y; + cmd->destRight = x + rect.width; + cmd->destBottom = y + rect.height; + + + cmd->bpp = 32; + cmd->codecID = 3; + cmd->width = rect.width; + cmd->height = rect.height; + cmd->bitmapDataLength = Stream_GetPosition(s); + cmd->bitmapData = Stream_Buffer(s); + + //send + + update->SurfaceBits(update->context, cmd); + + //clean up... maybe? + +} + +/* Called when we have a new peer connecting */ +int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context) +{ + context->info = mf_info_get_instance(); + context->rfx_context = rfx_context_new(TRUE); + context->rfx_context->mode = RLGR3; + context->rfx_context->width = client->settings->DesktopWidth; + context->rfx_context->height = client->settings->DesktopHeight; + rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + + //context->nsc_context = nsc_context_new(); + //nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8); + + context->s = Stream_New(NULL, 0xFFFF); + + context->vcm = WTSOpenServerA((LPSTR) client->context); + + mf_info_peer_register(context->info, context); + + return 0; +} + +/* Called after a peer disconnects */ +void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context) +{ + if (context) + { + mf_info_peer_unregister(context->info, context); + + dispatch_suspend(info_timer); + + Stream_Free(context->s, TRUE); + + rfx_context_free(context->rfx_context); + //nsc_context_free(context->nsc_context); + +#ifdef CHANNEL_AUDIN_SERVER + if (context->audin) + audin_server_context_free(context->audin); +#endif + + //#ifdef CHANNEL_RDPSND_SERVER + mf_peer_rdpsnd_stop(); + if (context->rdpsnd) + rdpsnd_server_context_free(context->rdpsnd); + //#endif + + WTSCloseServer(context->vcm); + } +} + +/* Called when a new client connects */ +void mf_peer_init(freerdp_peer* client) +{ + client->ContextSize = sizeof(mfPeerContext); + client->ContextNew = (psPeerContextNew) mf_peer_context_new; + client->ContextFree = (psPeerContextFree) mf_peer_context_free; + freerdp_peer_context_new(client); + + info_event_queue = mf_event_queue_new(); + + info_queue = dispatch_queue_create("FreeRDP.update.timer", DISPATCH_QUEUE_SERIAL); + info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue); + + if(info_timer) + { + //DEBUG_WARN( "created timer\n"); + dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 42ull * NSEC_PER_MSEC, 100ull * NSEC_PER_MSEC); + dispatch_source_set_event_handler(info_timer, ^{ + //DEBUG_WARN( "dispatch\n"); + mfEvent* event = mf_event_new(MF_EVENT_TYPE_FRAME_TICK); + mf_event_push(info_event_queue, (mfEvent*) event);} + ); + dispatch_resume(info_timer); + } +} + +BOOL mf_peer_post_connect(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*) client->context; + rdpSettings* settings = client->settings; + + mfInfo* mfi = mf_info_get_instance(); + mfi->scale = 1; + + //mfi->servscreen_width = 2880 / mfi->scale; + //mfi->servscreen_height = 1800 / mfi->scale; + UINT32 bitsPerPixel = 32; + + if ((settings->DesktopWidth != mfi->servscreen_width) || (settings->DesktopHeight != mfi->servscreen_height)) + { + + } + + settings->DesktopWidth = mfi->servscreen_width; + settings->DesktopHeight = mfi->servscreen_height; + settings->ColorDepth = bitsPerPixel; + + client->update->DesktopResize(client->update->context); + + mfi->mouse_down_left = FALSE; + mfi->mouse_down_right = FALSE; + mfi->mouse_down_other = FALSE; + + if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) + { + mf_peer_rdpsnd_init(context); /* Audio Output */ + } + + /* Dynamic Virtual Channels */ + +#ifdef CHANNEL_AUDIN_SERVER + mf_peer_audin_init(context); /* Audio Input */ +#endif + + return TRUE; +} + +BOOL mf_peer_activate(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*) client->context; + + rfx_context_reset(context->rfx_context); + context->activated = TRUE; + + return TRUE; +} + +void mf_peer_synchronize_event(rdpInput* input, UINT32 flags) +{ + +} + +void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + UINT16 down = 0x4000; + //UINT16 up = 0x8000; + + bool state_down = FALSE; + + if (flags == down) + { + state_down = TRUE; + } +} + +void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + +} + +static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area) +{ + +} + +void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + pthread_t th; + + pthread_create(&th, 0, mf_peer_main_loop, client); + pthread_detach(th); +} + +void* mf_peer_main_loop(void* arg) +{ + int i; + int fds; + int max_fds; + int rcount; + void* rfds[32]; + fd_set rfds_set; + mfPeerContext* context; + freerdp_peer* client = (freerdp_peer*) arg; + + memset(rfds, 0, sizeof(rfds)); + + mf_peer_init(client); + + /* Initialize the real server settings here */ + client->settings->CertificateFile = _strdup("server.crt"); + client->settings->PrivateKeyFile = _strdup("server.key"); + client->settings->NlaSecurity = FALSE; + client->settings->RemoteFxCodec = TRUE; + client->settings->ColorDepth = 32; + client->settings->SuppressOutput = TRUE; + client->settings->RefreshRect = FALSE; + + client->PostConnect = mf_peer_post_connect; + client->Activate = mf_peer_activate; + + client->input->SynchronizeEvent = mf_peer_synchronize_event; + client->input->KeyboardEvent = mf_input_keyboard_event;//mf_peer_keyboard_event; + client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event; + client->input->MouseEvent = mf_input_mouse_event; + client->input->ExtendedMouseEvent = mf_input_extended_mouse_event; + + //client->update->RefreshRect = mf_peer_refresh_rect; + client->update->SuppressOutput = mf_peer_suppress_output; + + client->Initialize(client); + context = (mfPeerContext*) client->context; + + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) + { + break; + } + + if (mf_peer_get_fds(client, rfds, &rcount) != TRUE) + { + break; + } + + WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) + { + /* these are not really errors */ + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) /* signal occurred */ + { + break; + } + } + + if (client->CheckFileDescriptor(client) != TRUE) + { + break; + } + + if ((mf_peer_check_fds(client)) != TRUE) + { + break; + } + + if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) + { + break; + } + } + + client->Disconnect(client); + freerdp_peer_context_free(client); + freerdp_peer_free(client); + + return NULL; +} diff --git a/server/Mac/mf_peer.h b/server/Mac/mf_peer.h index 5c3f71572..f5249affe 100644 --- a/server/Mac/mf_peer.h +++ b/server/Mac/mf_peer.h @@ -1,44 +1,44 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Mac OS X Server - * - * Copyright 2012 Corey Clayton - * - * 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 WF_PEER_H -#define WF_PEER_H - -#include "mf_interface.h" - -BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount); -BOOL mf_peer_check_fds(freerdp_peer* client); - -void mf_peer_rfx_update(freerdp_peer* client); - -int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context); -void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context); - -void mf_peer_init(freerdp_peer* client); - -BOOL mf_peer_post_connect(freerdp_peer* client); -BOOL mf_peer_activate(freerdp_peer* client); - -void mf_peer_synchronize_event(rdpInput* input, UINT32 flags); - -void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); - -void* mf_peer_main_loop(void* arg); - -#endif /* MF_PEER_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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 WF_PEER_H +#define WF_PEER_H + +#include "mf_interface.h" + +BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount); +BOOL mf_peer_check_fds(freerdp_peer* client); + +void mf_peer_rfx_update(freerdp_peer* client); + +int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context); +void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context); + +void mf_peer_init(freerdp_peer* client); + +BOOL mf_peer_post_connect(freerdp_peer* client); +BOOL mf_peer_activate(freerdp_peer* client); + +void mf_peer_synchronize_event(rdpInput* input, UINT32 flags); + +void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); + +void* mf_peer_main_loop(void* arg); + +#endif /* MF_PEER_H */ diff --git a/server/Mac/mf_rdpsnd.c b/server/Mac/mf_rdpsnd.c index 3333795af..1580a437d 100644 --- a/server/Mac/mf_rdpsnd.c +++ b/server/Mac/mf_rdpsnd.c @@ -26,12 +26,15 @@ #include "mf_info.h" #include "mf_rdpsnd.h" +#include +#define TAG SERVER_TAG("mac") + AQRecorderState recorderState; static const AUDIO_FORMAT supported_audio_formats[] = { - { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, NULL }, - { WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, NULL } + { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL }, + { WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL } }; static void mf_peer_rdpsnd_activated(RdpsndServerContext* context) @@ -43,9 +46,12 @@ static void mf_peer_rdpsnd_activated(RdpsndServerContext* context) //we should actually loop through the list of client formats here //and see if we can send the client something that it supports... +<<<<<<< HEAD - printf("Client supports the following %d formats: \n", context->num_client_formats); - +======= + WLog_DBG(TAG, "Client supports the following %d formats: ", context->num_client_formats); + +>>>>>>> f7d21655fa2552c8813be9d2d5bac4bbaa5abf6a for (i = 0; i < context->num_client_formats; i++) { /* TODO: improve the way we agree on a format */ @@ -55,7 +61,10 @@ static void mf_peer_rdpsnd_activated(RdpsndServerContext* context) (context->client_formats[i].nChannels == context->server_formats[j].nChannels) && (context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec)) { - printf("agreed on format!\n"); +<<<<<<< HEAD +======= + WLog_DBG(TAG, "agreed on format!"); +>>>>>>> f7d21655fa2552c8813be9d2d5bac4bbaa5abf6a formatAgreed = TRUE; agreedFormat = (AUDIO_FORMAT*)&context->server_formats[j]; break; @@ -68,10 +77,13 @@ static void mf_peer_rdpsnd_activated(RdpsndServerContext* context) if (formatAgreed == FALSE) { - printf("Could not agree on a audio format with the server\n"); +<<<<<<< HEAD +======= + WLog_DBG(TAG, "Could not agree on a audio format with the server"); +>>>>>>> f7d21655fa2552c8813be9d2d5bac4bbaa5abf6a return; } - + context->SelectFormat(context, i); context->SetVolume(context, 0x7FFF, 0x7FFF); @@ -111,10 +123,13 @@ static void mf_peer_rdpsnd_activated(RdpsndServerContext* context) if (status != noErr) { - printf("Failed to create a new Audio Queue. Status code: %d\n", status); +<<<<<<< HEAD + +======= + WLog_DBG(TAG, "Failed to create a new Audio Queue. Status code: %d", status); +>>>>>>> f7d21655fa2552c8813be9d2d5bac4bbaa5abf6a } - UInt32 dataFormatSize = sizeof (recorderState.dataFormat); AudioQueueGetProperty(recorderState.queue, @@ -161,7 +176,7 @@ BOOL mf_peer_rdpsnd_init(mfPeerContext* context) context->rdpsnd->Activated = mf_peer_rdpsnd_activated; - context->rdpsnd->Initialize(context->rdpsnd); + context->rdpsnd->Initialize(context->rdpsnd, TRUE); return TRUE; } @@ -208,7 +223,11 @@ void mf_peer_rdpsnd_input_callback (void *inUserD if (status != noErr) { - printf("AudioQueueEnqueueBuffer() returned status = %d\n", status); +<<<<<<< HEAD + +======= + WLog_DBG(TAG, "AudioQueueEnqueueBuffer() returned status = %d", status); +>>>>>>> f7d21655fa2552c8813be9d2d5bac4bbaa5abf6a } } diff --git a/server/Mac/mf_rdpsnd.h b/server/Mac/mf_rdpsnd.h index 2c3c6de2d..dedc09d24 100644 --- a/server/Mac/mf_rdpsnd.h +++ b/server/Mac/mf_rdpsnd.h @@ -1,66 +1,66 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Mac OS X Server (Audio Output) - * - * Copyright 2012 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 MF_RDPSND_H -#define MF_RDPSND_H - -#include -#include - -#include -#include -#include - -#include "mf_interface.h" -#include "mfreerdp.h" - -void mf_rdpsnd_derive_buffer_size (AudioQueueRef audioQueue, - AudioStreamBasicDescription *ASBDescription, - Float64 seconds, - UInt32 *outBufferSize); - -void mf_peer_rdpsnd_input_callback (void *inUserData, - AudioQueueRef inAQ, - AudioQueueBufferRef inBuffer, - const AudioTimeStamp *inStartTime, - UInt32 inNumberPacketDescriptions, - const AudioStreamPacketDescription *inPacketDescs); - - -#define SND_NUMBUFFERS 3 -struct _AQRecorderState -{ - AudioStreamBasicDescription dataFormat; - AudioQueueRef queue; - AudioQueueBufferRef buffers[SND_NUMBUFFERS]; - AudioFileID audioFile; - UInt32 bufferByteSize; - SInt64 currentPacket; - bool isRunning; - RdpsndServerContext* snd_context; - -}; - -typedef struct _AQRecorderState AQRecorderState; - -BOOL mf_peer_rdpsnd_init(mfPeerContext* context); -BOOL mf_peer_rdpsnd_stop(void); - -#endif /* MF_RDPSND_H */ - +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server (Audio Output) + * + * Copyright 2012 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 MF_RDPSND_H +#define MF_RDPSND_H + +#include +#include + +#include +#include +#include + +#include "mf_interface.h" +#include "mfreerdp.h" + +void mf_rdpsnd_derive_buffer_size (AudioQueueRef audioQueue, + AudioStreamBasicDescription *ASBDescription, + Float64 seconds, + UInt32 *outBufferSize); + +void mf_peer_rdpsnd_input_callback (void *inUserData, + AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer, + const AudioTimeStamp *inStartTime, + UInt32 inNumberPacketDescriptions, + const AudioStreamPacketDescription *inPacketDescs); + + +#define SND_NUMBUFFERS 3 +struct _AQRecorderState +{ + AudioStreamBasicDescription dataFormat; + AudioQueueRef queue; + AudioQueueBufferRef buffers[SND_NUMBUFFERS]; + AudioFileID audioFile; + UInt32 bufferByteSize; + SInt64 currentPacket; + bool isRunning; + RdpsndServerContext* snd_context; + +}; + +typedef struct _AQRecorderState AQRecorderState; + +BOOL mf_peer_rdpsnd_init(mfPeerContext* context); +BOOL mf_peer_rdpsnd_stop(void); + +#endif /* MF_RDPSND_H */ + diff --git a/server/Mac/mfreerdp.c b/server/Mac/mfreerdp.c index 2ac3122a2..ad6233c5c 100644 --- a/server/Mac/mfreerdp.c +++ b/server/Mac/mfreerdp.c @@ -60,7 +60,6 @@ static void mf_server_main_loop(freerdp_listener* instance) if (instance->GetFileDescriptor(instance, rfds, &rcount) != TRUE) { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); break; } @@ -88,14 +87,12 @@ static void mf_server_main_loop(freerdp_listener* instance) (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - fprintf(stderr, "select failed\n"); break; } } if (instance->CheckFileDescriptor(instance) != TRUE) { - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); break; } } @@ -124,4 +121,3 @@ int main(int argc, char* argv[]) return 0; } - diff --git a/server/Mac/mfreerdp.h b/server/Mac/mfreerdp.h index 153485cb2..2008b2581 100644 --- a/server/Mac/mfreerdp.h +++ b/server/Mac/mfreerdp.h @@ -1,28 +1,28 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Mac OS X Server - * - * Copyright 2012 Marc-Andre Moreau - * Copyright 2012 Corey Clayton - * - * 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 MFREERDP_SERVER_H -#define MFREERDP_SERVER_H - -#include -#include -#include - -#endif /* MFREERDP_SERVER_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2012 Corey Clayton + * + * 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 MFREERDP_SERVER_H +#define MFREERDP_SERVER_H + +#include +#include +#include + +#endif /* MFREERDP_SERVER_H */ diff --git a/server/Sample/CMakeLists.txt b/server/Sample/CMakeLists.txt index 972cc29f6..6e3b16077 100644 --- a/server/Sample/CMakeLists.txt +++ b/server/Sample/CMakeLists.txt @@ -24,21 +24,14 @@ set(${MODULE_PREFIX}_SRCS sf_audin.c sf_audin.h sf_rdpsnd.c - sf_rdpsnd.h) + sf_rdpsnd.h + sf_encomsp.c + sf_encomsp.h) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-utils freerdp-codec freerdp-primitives) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/server/Sample/sf_audin.c b/server/Sample/sf_audin.c index 3d2a5538d..1fdf0f1fe 100644 --- a/server/Sample/sf_audin.c +++ b/server/Sample/sf_audin.c @@ -21,10 +21,15 @@ #include "config.h" #endif + + #include "sfreerdp.h" #include "sf_audin.h" +#include +#define TAG SERVER_TAG("sample") + static const AUDIO_FORMAT test_audio_formats[] = { { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL }, @@ -33,19 +38,19 @@ static const AUDIO_FORMAT test_audio_formats[] = static void sf_peer_audin_opening(audin_server_context* context) { - printf("AUDIN opening.\n"); + WLog_DBG(TAG, "AUDIN opening."); /* Simply choose the first format supported by the client. */ context->SelectFormat(context, 0); } static void sf_peer_audin_open_result(audin_server_context* context, UINT32 result) { - printf("AUDIN open result %d.\n", result); + WLog_DBG(TAG, "AUDIN open result %d.", result); } static void sf_peer_audin_receive_samples(audin_server_context* context, const void* buf, int nframes) { - printf("AUDIN receive %d frames.\n", nframes); + WLog_DBG(TAG, "AUDIN receive %d frames.", nframes); } void sf_peer_audin_init(testPeerContext* context) diff --git a/server/Sample/sf_audin.h b/server/Sample/sf_audin.h index 51ec4b31a..db762fc55 100644 --- a/server/Sample/sf_audin.h +++ b/server/Sample/sf_audin.h @@ -1,32 +1,32 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Sample Server (Audio Input) - * - * Copyright 2012 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 SF_AUDIN_H -#define SF_AUDIN_H - -#include -#include -#include - -#include "sfreerdp.h" - -void sf_peer_audin_init(testPeerContext* context); - -#endif /* WF_AUDIN_H */ - +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Sample Server (Audio Input) + * + * Copyright 2012 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 SF_AUDIN_H +#define SF_AUDIN_H + +#include +#include +#include + +#include "sfreerdp.h" + +void sf_peer_audin_init(testPeerContext* context); + +#endif /* WF_AUDIN_H */ + diff --git a/client/Windows/wf_window.c b/server/Sample/sf_encomsp.c similarity index 64% rename from client/Windows/wf_window.c rename to server/Sample/sf_encomsp.c index d15472ea4..a152182aa 100644 --- a/client/Windows/wf_window.c +++ b/server/Sample/sf_encomsp.c @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Windows RAIL + * FreeRDP Sample Server (Lync Multiparty) * - * Copyright 2012 Jason Champion + * 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. @@ -21,4 +21,17 @@ #include "config.h" #endif -#include "wf_window.h" +#include "sf_encomsp.h" + +BOOL sf_peer_encomsp_init(testPeerContext* context) +{ + context->encomsp = encomsp_server_context_new(context->vcm); + + if (!context->encomsp) + return FALSE; + + if (context->encomsp->Start(context->encomsp) < 0) + return FALSE; + + return TRUE; +} diff --git a/server/X11/xf_cursor.h b/server/Sample/sf_encomsp.h similarity index 64% rename from server/X11/xf_cursor.h rename to server/Sample/sf_encomsp.h index 64c95c312..27703145d 100644 --- a/server/X11/xf_cursor.h +++ b/server/Sample/sf_encomsp.h @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Cursor + * FreeRDP Sample Server (Lync Multiparty) * - * Copyright 2013 Marc-Andre Moreau + * 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. @@ -17,11 +17,15 @@ * limitations under the License. */ -#ifndef XFREERDP_SERVER_CURSOR_H -#define XFREERDP_SERVER_CURSOR_H +#ifndef SF_ENCOMSP_H +#define SF_ENCOMSP_H -#include "xfreerdp.h" +#include +#include +#include -int xf_cursor_init(xfInfo* xfi); +#include "sfreerdp.h" -#endif /* XFREERDP_SERVER_CURSOR_H */ +BOOL sf_peer_encomsp_init(testPeerContext* context); + +#endif /* SF_ENCOMSP_H */ diff --git a/server/Sample/sf_rdpsnd.c b/server/Sample/sf_rdpsnd.c index 9a1b70bcb..0475b9f9a 100644 --- a/server/Sample/sf_rdpsnd.c +++ b/server/Sample/sf_rdpsnd.c @@ -23,8 +23,12 @@ #include + #include "sf_rdpsnd.h" +#include +#define TAG SERVER_TAG("sample") + static const AUDIO_FORMAT test_audio_formats[] = { { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL }, @@ -33,7 +37,7 @@ static const AUDIO_FORMAT test_audio_formats[] = static void sf_peer_rdpsnd_activated(RdpsndServerContext* context) { - printf("RDPSND Activated\n"); + WLog_DBG(TAG, "RDPSND Activated"); } BOOL sf_peer_rdpsnd_init(testPeerContext* context) @@ -52,7 +56,7 @@ BOOL sf_peer_rdpsnd_init(testPeerContext* context) context->rdpsnd->Activated = sf_peer_rdpsnd_activated; - context->rdpsnd->Initialize(context->rdpsnd); + context->rdpsnd->Initialize(context->rdpsnd, TRUE); return TRUE; } diff --git a/server/Sample/sf_rdpsnd.h b/server/Sample/sf_rdpsnd.h index ce2875f17..78e7c9bbd 100644 --- a/server/Sample/sf_rdpsnd.h +++ b/server/Sample/sf_rdpsnd.h @@ -1,32 +1,32 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Sample Server (Audio Output) - * - * Copyright 2012 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 SF_RDPSND_H -#define SF_RDPSND_H - -#include -#include -#include - -#include "sfreerdp.h" - -BOOL sf_peer_rdpsnd_init(testPeerContext* context); - -#endif /* SF_RDPSND_H */ - +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Sample Server (Audio Output) + * + * Copyright 2012 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 SF_RDPSND_H +#define SF_RDPSND_H + +#include +#include +#include + +#include "sfreerdp.h" + +BOOL sf_peer_rdpsnd_init(testPeerContext* context); + +#endif /* SF_RDPSND_H */ + diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index 3a2d36d06..c39b9566c 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -30,6 +30,7 @@ #include #include + #include #include @@ -40,9 +41,13 @@ #include "sf_audin.h" #include "sf_rdpsnd.h" +#include "sf_encomsp.h" #include "sfreerdp.h" +#include +#define TAG SERVER_TAG("sample") + #define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1 #define SAMPLE_SERVER_DEFAULT_WIDTH 1024 #define SAMPLE_SERVER_DEFAULT_HEIGHT 768 @@ -96,6 +101,9 @@ void test_peer_context_free(freerdp_peer* client, testPeerContext* context) if (context->rdpsnd) rdpsnd_server_context_free(context->rdpsnd); + if (context->encomsp) + encomsp_server_context_free(context->encomsp); + WTSCloseServer((HANDLE) context->vcm); } } @@ -337,7 +345,7 @@ static BOOL test_sleep_tsdiff(UINT32 *old_sec, UINT32 *old_usec, UINT32 new_sec, if ((sec < 0) || ((sec == 0) && (usec < 0))) { - printf("Invalid time stamp detected.\n"); + WLog_ERR(TAG, "Invalid time stamp detected."); return FALSE; } @@ -446,8 +454,7 @@ static void* tf_debug_channel_thread_func(void* arg) } Stream_SetPosition(s, BytesReturned); - - printf("got %lu bytes\n", BytesReturned); + WLog_DBG(TAG, "got %lu bytes", BytesReturned); } Stream_Free(s, TRUE); @@ -465,31 +472,28 @@ BOOL tf_peer_post_connect(freerdp_peer* client) * The server may start sending graphics output and receiving keyboard/mouse input after this * callback returns. */ - - printf("Client %s is activated (osMajorType %d osMinorType %d)", client->local ? "(local)" : client->hostname, - client->settings->OsMajorType, client->settings->OsMinorType); + WLog_DBG(TAG, "Client %s is activated (osMajorType %d osMinorType %d)", client->local ? "(local)" : client->hostname, + client->settings->OsMajorType, client->settings->OsMinorType); if (client->settings->AutoLogonEnabled) { - printf(" and wants to login automatically as %s\\%s", - client->settings->Domain ? client->settings->Domain : "", - client->settings->Username); - + WLog_DBG(TAG, " and wants to login automatically as %s\\%s", + client->settings->Domain ? client->settings->Domain : "", + client->settings->Username); /* A real server may perform OS login here if NLA is not executed previously. */ } - printf("\n"); - - printf("Client requested desktop: %dx%dx%d\n", - client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); + WLog_DBG(TAG, ""); + WLog_DBG(TAG, "Client requested desktop: %dx%dx%d", + client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); #if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1) context->rfx_context->width = client->settings->DesktopWidth; context->rfx_context->height = client->settings->DesktopHeight; - printf("Using resolution requested by client.\n"); + WLog_DBG(TAG, "Using resolution requested by client."); #else client->settings->DesktopWidth = context->rfx_context->width; client->settings->DesktopHeight = context->rfx_context->height; - printf("Resizing client to %dx%d\n", client->settings->DesktopWidth, client->settings->DesktopHeight); + WLog_DBG(TAG, "Resizing client to %dx%d", client->settings->DesktopWidth, client->settings->DesktopHeight); client->update->DesktopResize(client->update->context); #endif @@ -502,8 +506,7 @@ BOOL tf_peer_post_connect(freerdp_peer* client) if (context->debug_channel != NULL) { - printf("Open channel rdpdbg.\n"); - + WLog_DBG(TAG, "Open channel rdpdbg."); context->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); context->debug_channel_thread = CreateThread(NULL, 0, @@ -516,6 +519,11 @@ BOOL tf_peer_post_connect(freerdp_peer* client) sf_peer_rdpsnd_init(context); /* Audio Output */ } + if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "encomsp")) + { + sf_peer_encomsp_init(context); /* Lync Multiparty */ + } + /* Dynamic Virtual Channels */ sf_peer_audin_init(context); /* Audio Input */ @@ -552,7 +560,7 @@ BOOL tf_peer_activate(freerdp_peer* client) void tf_peer_synchronize_event(rdpInput* input, UINT32 flags) { - printf("Client sent a synchronize event (flags:0x%X)\n", flags); + WLog_DBG(TAG, "Client sent a synchronize event (flags:0x%X)", flags); } void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) @@ -560,8 +568,7 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) freerdp_peer* client = input->context->peer; rdpUpdate* update = client->update; testPeerContext* context = (testPeerContext*) input->context; - - printf("Client sent a keyboard event (flags:0x%X code:0x%X)\n", flags, code); + WLog_DBG(TAG, "Client sent a keyboard event (flags:0x%X code:0x%X)", flags, code); if ((flags & 0x4000) && code == 0x22) /* 'g' key */ { @@ -613,30 +620,28 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) void tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { - printf("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code); + WLog_DBG(TAG, "Client sent a unicode keyboard event (flags:0x%X code:0x%X)", flags, code); } void tf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { - //printf("Client sent a mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); - + //WLog_DBG(TAG, "Client sent a mouse event (flags:0x%X pos:%d,%d)", flags, x, y); test_peer_draw_icon(input->context->peer, x + 10, y); } void tf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { - //printf("Client sent an extended mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); + //WLog_DBG(TAG, "Client sent an extended mouse event (flags:0x%X pos:%d,%d)", flags, x, y); } static void tf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas) { BYTE i; - - printf("Client requested to refresh:\n"); + WLog_DBG(TAG, "Client requested to refresh:"); for (i = 0; i < count; i++) { - printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom); + WLog_DBG(TAG, " (%d, %d) (%d, %d)", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom); } } @@ -644,11 +649,11 @@ static void tf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_1 { if (allow > 0) { - printf("Client restore output (%d, %d) (%d, %d).\n", area->left, area->top, area->right, area->bottom); + WLog_DBG(TAG, "Client restore output (%d, %d) (%d, %d).", area->left, area->top, area->right, area->bottom); } else { - printf("Client minimized and suppress output.\n"); + WLog_DBG(TAG, "Client minimized and suppress output."); } } @@ -690,8 +695,7 @@ static void* test_peer_mainloop(void* arg) client->Initialize(client); context = (testPeerContext*) client->context; - - printf("We've got a client %s\n", client->local ? "(local)" : client->hostname); + WLog_INFO(TAG, "We've got a client %s", client->local ? "(local)" : client->hostname); while (1) { @@ -700,7 +704,7 @@ static void* test_peer_mainloop(void* arg) memset(rfds, 0, sizeof(rfds)); if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) { - printf("Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } @@ -734,7 +738,7 @@ static void* test_peer_mainloop(void* arg) (wsa_error == WSAEINPROGRESS) || (wsa_error == WSAEINTR))) { - printf("select failed (WSAGetLastError: %d)\n", wsa_error); + WLog_ERR(TAG, "select failed (WSAGetLastError: %d)", wsa_error); break; } #else @@ -744,7 +748,7 @@ static void* test_peer_mainloop(void* arg) (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - printf("select failed (errno: %d)\n", errno); + WLog_ERR(TAG, "select failed (errno: %d)", errno); break; } #endif @@ -757,8 +761,7 @@ static void* test_peer_mainloop(void* arg) break; } - printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname); - + WLog_INFO(TAG, "Client %s disconnected.", client->local ? "(local)" : client->hostname); client->Disconnect(client); freerdp_peer_context_free(client); freerdp_peer_free(client); @@ -790,7 +793,7 @@ static void test_server_mainloop(freerdp_listener* instance) memset(rfds, 0, sizeof(rfds)); if (instance->GetFileDescriptor(instance, rfds, &rcount) != TRUE) { - printf("Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } @@ -818,14 +821,14 @@ static void test_server_mainloop(freerdp_listener* instance) (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - printf("select failed\n"); + WLog_ERR(TAG, "select failed"); break; } } if (instance->CheckFileDescriptor(instance) != TRUE) { - printf("Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } } diff --git a/server/Sample/sfreerdp.h b/server/Sample/sfreerdp.h index a052da93d..1b81d82a4 100644 --- a/server/Sample/sfreerdp.h +++ b/server/Sample/sfreerdp.h @@ -1,62 +1,64 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Sample Server - * - * Copyright 2012 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 SFREERDP_SERVER_H -#define SFREERDP_SERVER_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct test_peer_context -{ - rdpContext _p; - - RFX_CONTEXT* rfx_context; - NSC_CONTEXT* nsc_context; - wStream* s; - BYTE* icon_data; - BYTE* bg_data; - int icon_width; - int icon_height; - int icon_x; - int icon_y; - BOOL activated; - HANDLE event; - HANDLE stopEvent; - HANDLE vcm; - void* debug_channel; - HANDLE debug_channel_thread; - audin_server_context* audin; - BOOL audin_open; - UINT32 frame_id; - RdpsndServerContext* rdpsnd; -}; -typedef struct test_peer_context testPeerContext; - -#endif /* SFREERDP_SERVER_H */ - +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Sample Server + * + * Copyright 2012 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 SFREERDP_SERVER_H +#define SFREERDP_SERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct test_peer_context +{ + rdpContext _p; + + RFX_CONTEXT* rfx_context; + NSC_CONTEXT* nsc_context; + wStream* s; + BYTE* icon_data; + BYTE* bg_data; + int icon_width; + int icon_height; + int icon_x; + int icon_y; + BOOL activated; + HANDLE event; + HANDLE stopEvent; + HANDLE vcm; + void* debug_channel; + HANDLE debug_channel_thread; + audin_server_context* audin; + BOOL audin_open; + UINT32 frame_id; + RdpsndServerContext* rdpsnd; + EncomspServerContext* encomsp; +}; +typedef struct test_peer_context testPeerContext; + +#endif /* SFREERDP_SERVER_H */ + diff --git a/server/Windows/CMakeLists.txt b/server/Windows/CMakeLists.txt index b817e8121..93336a5b6 100644 --- a/server/Windows/CMakeLists.txt +++ b/server/Windows/CMakeLists.txt @@ -60,24 +60,22 @@ endif() if(WITH_SERVER_INTERFACE) add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") + if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) + endif() + set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/wfreerdp.c cli/wfreerdp.h) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) endif() - -if(WITH_WIN8) + +if(CMAKE_WINDOWS_VERSION STREQUAL "WIN8") set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} d3d11 dxgi dxguid) endif() set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dsound) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-utils freerdp-codec freerdp-primitives) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/server/Windows/cli/wfreerdp.c b/server/Windows/cli/wfreerdp.c index 0e28c4398..5599d13b1 100644 --- a/server/Windows/cli/wfreerdp.c +++ b/server/Windows/cli/wfreerdp.c @@ -32,14 +32,16 @@ #include "wfreerdp.h" +#include +#define TAG SERVER_TAG("windows") + int IDcount = 0; BOOL CALLBACK moncb(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { - printf("%d\t(%d, %d), (%d, %d)\n", - IDcount, lprcMonitor->left, lprcMonitor->top, - lprcMonitor->right, lprcMonitor->bottom); - + WLog_DBG(TAG, "%d\t(%d, %d), (%d, %d)", + IDcount, lprcMonitor->left, lprcMonitor->top, + lprcMonitor->right, lprcMonitor->bottom); IDcount++; return TRUE; @@ -67,10 +69,9 @@ int main(int argc, char* argv[]) int height; int bpp; int i; + WLog_INFO(TAG, "Detecting screens..."); + WLog_INFO(TAG, "ID\tResolution\t\tName (Interface)"); - _tprintf(_T("Detecting screens...\n")); - _tprintf(_T("\nID\tResolution\t\tName (Interface)\n\n")); - for (i=0; ; i++) { if (get_screen_info(i, name, &width, &height, &bpp) != 0) @@ -78,8 +79,8 @@ int main(int argc, char* argv[]) if ( (width * height * bpp) == 0 ) continue; - _tprintf(_T("%d\t%dx%dx%d\t"), i, width, height, bpp); - _tprintf(_T("%s\n"), name); + WLog_INFO(TAG, "%d\t%dx%dx%d\t", i, width, height, bpp); + WLog_INFO(TAG, "%s", name); } else { @@ -92,11 +93,10 @@ int main(int argc, char* argv[]) int vscreen_h; vscreen_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); vscreen_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - printf("\n"); + WLog_INFO(TAG, ""); EnumDisplayMonitors(NULL, NULL, moncb, 0); IDcount = 0; - printf("\nVirtual Screen = %dx%d\n", vscreen_w, vscreen_h); + WLog_INFO(TAG, "Virtual Screen = %dx%d", vscreen_w, vscreen_h); } return 0; @@ -108,7 +108,7 @@ int main(int argc, char* argv[]) index++; if (index == argc) { - printf("missing screen id parameter\n"); + WLog_INFO(TAG, "missing screen id parameter"); return 0; } @@ -130,10 +130,9 @@ int main(int argc, char* argv[]) int height; int bpp; int i; - - _tprintf(_T("screen id not provided. attempting to detect...\n")); - _tprintf(_T("Detecting screens...\n")); - _tprintf(_T("\nID\tResolution\t\tName (Interface)\n\n")); + WLog_INFO(TAG, "screen id not provided. attempting to detect..."); + WLog_INFO(TAG, "Detecting screens..."); + WLog_INFO(TAG, "ID\tResolution\t\tName (Interface)"); for (i=0; ; i++) { @@ -142,8 +141,8 @@ int main(int argc, char* argv[]) if ( (width * height * bpp) == 0 ) continue; - _tprintf(_T("%d\t%dx%dx%d\t"), i, width, height, bpp); - _tprintf(_T("%s\n"), name); + WLog_INFO(TAG, "%d\t%dx%dx%d\t", i, width, height, bpp); + WLog_INFO(TAG, "%s", name); set_screen_id(i); break; } @@ -154,14 +153,11 @@ int main(int argc, char* argv[]) } } - printf("Starting server\n"); - + WLog_INFO(TAG, "Starting server"); wfreerdp_server_start(server); WaitForSingleObject(server->thread, INFINITE); - - printf("Stopping server\n"); - + WLog_INFO(TAG, "Stopping server"); wfreerdp_server_stop(server); wfreerdp_server_free(server); diff --git a/server/Windows/wf_directsound.c b/server/Windows/wf_directsound.c index 22190c96f..37c31205d 100644 --- a/server/Windows/wf_directsound.c +++ b/server/Windows/wf_directsound.c @@ -14,6 +14,9 @@ #include #include +#include +#define TAG SERVER_TAG("windows") + IDirectSoundCapture8* cap; IDirectSoundCaptureBuffer8* capBuf; DSCBUFFERDESC dscbd; @@ -34,18 +37,16 @@ int wf_directsound_activate(RdpsndServerContext* context) LPDIRECTSOUNDCAPTUREBUFFER pDSCB; wfi = wf_info_get_instance(); - - printf("RDPSND (direct sound) Activated\n"); - + WLog_DBG(TAG, "RDPSND (direct sound) Activated"); hr = DirectSoundCaptureCreate8(NULL, &cap, NULL); if (FAILED(hr)) { - _tprintf(_T("Failed to create sound capture device\n")); + WLog_ERR(TAG, "Failed to create sound capture device"); return 1; } - _tprintf(_T("Created sound capture device\n")); + WLog_INFO(TAG, "Created sound capture device"); dscbd.dwSize = sizeof(DSCBUFFERDESC); dscbd.dwFlags = 0; dscbd.dwBufferBytes = wfi->agreed_format->nAvgBytesPerSec; @@ -58,18 +59,17 @@ int wf_directsound_activate(RdpsndServerContext* context) if (FAILED(hr)) { - _tprintf(_T("Failed to create capture buffer\n")); + WLog_ERR(TAG, "Failed to create capture buffer"); } - _tprintf(_T("Created capture buffer")); + WLog_INFO(TAG, "Created capture buffer"); hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf); if (FAILED(hr)) { - _tprintf(_T("Failed to QI capture buffer\n")); + WLog_ERR(TAG, "Failed to QI capture buffer"); } - _tprintf(_T("Created IDirectSoundCaptureBuffer8\n")); - pDSCB->lpVtbl->Release(pDSCB); - + WLog_INFO(TAG, "Created IDirectSoundCaptureBuffer8"); + pDSCB->lpVtbl->Release(pDSCB); lastPos = 0; CreateThread(NULL, 0, wf_rdpsnd_directsound_thread, latestPeer, 0, NULL); @@ -98,14 +98,13 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) context = (wfPeerContext*)lpParam; rate = 1000 / 24; - - _tprintf(_T("Trying to start capture\n")); + WLog_INFO(TAG, "Trying to start capture"); hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING); if (FAILED(hr)) { - _tprintf(_T("Failed to start capture\n")); + WLog_ERR(TAG, "Failed to start capture"); } - _tprintf(_T("Capture started\n")); + WLog_INFO(TAG, "Capture started"); while (1) { @@ -132,7 +131,7 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, NULL, &dwReadPos); if (FAILED(hr)) { - _tprintf(_T("Failed to get read pos\n")); + WLog_ERR(TAG, "Failed to get read pos"); wf_rdpsnd_unlock(); break; } @@ -140,9 +139,9 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) lLockSize = dwReadPos - lastPos;//dscbd.dwBufferBytes; if (lLockSize < 0) lLockSize += dscbd.dwBufferBytes; - //printf("Last, read, lock = [%d, %d, %d]\n", lastPos, dwReadPos, lLockSize); + //WLog_DBG(TAG, "Last, read, lock = [%d, %d, %d]\n", lastPos, dwReadPos, lLockSize); - if (lLockSize == 0) + if (lLockSize == 0) { wf_rdpsnd_unlock(); continue; @@ -152,7 +151,7 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength, &pbCaptureData2, &dwCaptureLength2, 0L); if (FAILED(hr)) { - _tprintf(_T("Failed to lock sound capture buffer\n")); + WLog_ERR(TAG, "Failed to lock sound capture buffer"); wf_rdpsnd_unlock(); break; } @@ -169,7 +168,7 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2, dwCaptureLength2); if (FAILED(hr)) { - _tprintf(_T("Failed to unlock sound capture buffer\n")); + WLog_ERR(TAG, "Failed to unlock sound capture buffer"); wf_rdpsnd_unlock(); return 0; } @@ -186,13 +185,14 @@ DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam) } - _tprintf(_T("Trying to stop sound capture\n")); + WLog_INFO(TAG, "Trying to stop sound capture"); hr = capBuf->lpVtbl->Stop(capBuf); if (FAILED(hr)) { - _tprintf(_T("Failed to stop capture\n")); + WLog_ERR(TAG, "Failed to stop capture"); } - _tprintf(_T("Capture stopped\n")); + + WLog_INFO(TAG, "Capture stopped"); capBuf->lpVtbl->Release(capBuf); cap->lpVtbl->Release(cap); diff --git a/server/Windows/wf_dxgi.c b/server/Windows/wf_dxgi.c index dd5ac3421..a2801f665 100644 --- a/server/Windows/wf_dxgi.c +++ b/server/Windows/wf_dxgi.c @@ -23,7 +23,7 @@ #include "wf_interface.h" -#ifdef WITH_WIN8 +#ifdef WITH_DXGI_1_2 #define CINTERFACE @@ -33,6 +33,9 @@ #include #include "wf_dxgi.h" +#include +#define TAG SERVER_TAG("windows") + /* Driver types supported */ D3D_DRIVER_TYPE DriverTypes[] = { @@ -67,7 +70,6 @@ DXGI_OUTDUPL_FRAME_INFO FrameInfo; int wf_dxgi_init(wfInfo* wfi) { - //not sure if needed gAcquiredDesktopImage = NULL; if (wf_dxgi_createDevice(wfi) != 0) @@ -81,7 +83,6 @@ int wf_dxgi_init(wfInfo* wfi) } return 0; - } int wf_dxgi_createDevice(wfInfo* wfi) @@ -96,12 +97,12 @@ int wf_dxgi_createDevice(wfInfo* wfi) if (SUCCEEDED(status)) break; - _tprintf(_T("D3D11CreateDevice returned [%d] for Driver Type %d\n"), status, DriverTypes[DriverTypeIndex]); + WLog_INFO(TAG, "D3D11CreateDevice returned [%d] for Driver Type %d", status, DriverTypes[DriverTypeIndex]); } if (FAILED(status)) { - _tprintf(_T("Failed to create device in InitializeDx\n")); + WLog_ERR(TAG, "Failed to create device in InitializeDx"); return 1; } @@ -123,7 +124,7 @@ int wf_dxgi_getDuplication(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to get QI for DXGI Device\n")); + WLog_ERR(TAG, "Failed to get QI for DXGI Device"); return 1; } @@ -133,7 +134,7 @@ int wf_dxgi_getDuplication(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to get parent DXGI Adapter\n")); + WLog_ERR(TAG, "Failed to get parent DXGI Adapter"); return 1; } @@ -148,11 +149,11 @@ int wf_dxgi_getDuplication(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to get description\n")); + WLog_ERR(TAG, "Failed to get description"); return 1; } - _tprintf(_T("Output %d: [%s] [%d]\n"), i, pDesc->DeviceName, pDesc->AttachedToDesktop); + WLog_INFO(TAG, "Output %d: [%s] [%d]", i, pDesc->DeviceName, pDesc->AttachedToDesktop); if (pDesc->AttachedToDesktop) dTop = i; @@ -169,7 +170,7 @@ int wf_dxgi_getDuplication(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to get output\n")); + WLog_ERR(TAG, "Failed to get output"); return 1; } @@ -179,7 +180,7 @@ int wf_dxgi_getDuplication(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to get IDXGIOutput1\n")); + WLog_ERR(TAG, "Failed to get IDXGIOutput1"); return 1; } @@ -191,11 +192,11 @@ int wf_dxgi_getDuplication(wfInfo* wfi) { if (status == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { - _tprintf(_T("There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again.\n")); + WLog_ERR(TAG, "There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again.")); return 1; } - - _tprintf(_T("Failed to get duplicate output. Status = %#X\n"), status); + + WLog_ERR(TAG, "Failed to get duplicate output. Status = %#X", status); return 1; } @@ -267,8 +268,9 @@ int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) { if (status == DXGI_ERROR_ACCESS_LOST) { - _tprintf(_T("Failed to acquire next frame with status=%#X\n"), status); - _tprintf(_T("Trying to reinitialize due to ACCESS LOST...")); + WLog_ERR(TAG, "Failed to acquire next frame with status=%#X", status); + WLog_ERR(TAG, "Trying to reinitialize due to ACCESS LOST..."); + if (gAcquiredDesktopImage) { gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage); @@ -287,13 +289,12 @@ int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) } else { - _tprintf(_T("Failed to acquire next frame with status=%#X\n"), status); - + WLog_ERR(TAG, "Failed to acquire next frame with status=%#X", status); status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication); if (FAILED(status)) { - _tprintf(_T("Failed to release frame with status=%d\n"), status); + WLog_ERR(TAG, "Failed to release frame with status=%d", status); } return 1; @@ -317,7 +318,7 @@ int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) if (FAILED(status)) { - _tprintf(_T("Failed to release frame with status=%d\n"), status); + WLog_ERR(TAG, "Failed to release frame with status=%d", status); } } @@ -354,7 +355,7 @@ int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data, int* pitch, RECT* invalid) if (FAILED(status)) { - _tprintf(_T("Failed to create staging surface\n")); + WLog_ERR(TAG, "Failed to create staging surface"); exit(1); return 1; } @@ -365,7 +366,7 @@ int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data, int* pitch, RECT* invalid) if (FAILED(status)) { - _tprintf(_T("Failed to QI staging surface\n")); + WLog_ERR(TAG, "Failed to QI staging surface"); exit(1); return 1; } @@ -374,7 +375,7 @@ int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data, int* pitch, RECT* invalid) if (FAILED(status)) { - _tprintf(_T("Failed to map staging surface\n")); + WLog_ERR(TAG, "Failed to map staging surface"); exit(1); return 1; } @@ -399,7 +400,7 @@ int wf_dxgi_releasePixelData(wfInfo* wfi) if (FAILED(status)) { - _tprintf(_T("Failed to release frame\n")); + WLog_ERR(TAG, "Failed to release frame"); return 1; } @@ -440,7 +441,7 @@ int wf_dxgi_getInvalidRegion(RECT* invalid) if (!DataBuffer) { DataBufferSize = 0; - _tprintf(_T("Failed to allocate memory for metadata\n")); + WLog_ERR(TAG, "Failed to allocate memory for metadata"); exit(1); } @@ -453,7 +454,7 @@ int wf_dxgi_getInvalidRegion(RECT* invalid) if (FAILED(status)) { - _tprintf(_T("Failed to get frame move rects\n")); + WLog_ERR(TAG, "Failed to get frame move rects"); return 1; } @@ -464,7 +465,7 @@ int wf_dxgi_getInvalidRegion(RECT* invalid) if (FAILED(status)) { - _tprintf(_T("Failed to get frame dirty rects\n")); + WLog_ERR(TAG, "Failed to get frame dirty rects"); return 1; } dirty = BufSize / sizeof(RECT); diff --git a/server/Windows/wf_info.c b/server/Windows/wf_info.c index c49d352df..f8263e1bb 100644 --- a/server/Windows/wf_info.c +++ b/server/Windows/wf_info.c @@ -1,47 +1,50 @@ -/** -* FreeRDP: A Remote Desktop Protocol Client -* FreeRDP Windows Server -* -* Copyright 2012 Corey Clayton -* -* 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. -*/ +/** +* FreeRDP: A Remote Desktop Protocol Client +* FreeRDP Windows Server +* +* Copyright 2012 Corey Clayton +* +* 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 "wf_info.h" +#include "wf_update.h" +#include "wf_mirage.h" +#include "wf_dxgi.h" + +#include +#define TAG SERVER_TAG("windows") + +static wfInfo* wfInfoInstance = NULL; +static int _IDcount = 0; + +int wf_info_lock(wfInfo* wfi) +{ + DWORD dRes; -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include - -#include "wf_info.h" -#include "wf_update.h" -#include "wf_mirage.h" -#include "wf_dxgi.h" - -static wfInfo* wfInfoInstance = NULL; -static int _IDcount = 0; - -int wf_info_lock(wfInfo* wfi) -{ - DWORD dRes; - - dRes = WaitForSingleObject(wfi->mutex, INFINITE); - - switch (dRes) - { + dRes = WaitForSingleObject(wfi->mutex, INFINITE); + + switch (dRes) + { case WAIT_ABANDONED: case WAIT_OBJECT_0: return TRUE; @@ -52,22 +55,22 @@ int wf_info_lock(wfInfo* wfi) break; case WAIT_FAILED: - printf("wf_info_lock failed with 0x%08X\n", GetLastError()); + WLog_ERR(TAG, "wf_info_lock failed with 0x%08X", GetLastError()); return -1; break; - } + } + + return -1; +} + +int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds) +{ + DWORD dRes; - return -1; -} - -int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds) -{ - DWORD dRes; - - dRes = WaitForSingleObject(wfi->mutex, dwMilliseconds); - - switch (dRes) - { + dRes = WaitForSingleObject(wfi->mutex, dwMilliseconds); + + switch (dRes) + { case WAIT_ABANDONED: case WAIT_OBJECT_0: return TRUE; @@ -78,293 +81,291 @@ int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds) break; case WAIT_FAILED: - printf("wf_info_try_lock failed with 0x%08X\n", GetLastError()); + WLog_ERR(TAG, "wf_info_try_lock failed with 0x%08X", GetLastError()); return -1; break; - } + } + + return -1; +} + +int wf_info_unlock(wfInfo* wfi) +{ + if (ReleaseMutex(wfi->mutex) == 0) + { + WLog_ERR(TAG, "wf_info_unlock failed with 0x%08X", GetLastError()); + return -1; + } + + return TRUE; +} + +wfInfo* wf_info_init() +{ + wfInfo* wfi; - return -1; -} - -int wf_info_unlock(wfInfo* wfi) -{ - if (ReleaseMutex(wfi->mutex) == 0) - { - printf("wf_info_unlock failed with 0x%08X\n", GetLastError()); - return -1; - } - - return TRUE; -} - -wfInfo* wf_info_init() -{ - wfInfo* wfi; - - wfi = (wfInfo*) malloc(sizeof(wfInfo)); - ZeroMemory(wfi, sizeof(wfInfo)); - - if (wfi != NULL) - { - HKEY hKey; - LONG status; - DWORD dwType; - DWORD dwSize; - DWORD dwValue; - - wfi->mutex = CreateMutex(NULL, FALSE, NULL); + wfi = (wfInfo*) malloc(sizeof(wfInfo)); + ZeroMemory(wfi, sizeof(wfInfo)); + + if (wfi != NULL) + { + HKEY hKey; + LONG status; + DWORD dwType; + DWORD dwSize; + DWORD dwValue; + wfi->mutex = CreateMutex(NULL, FALSE, NULL); + if (wfi->mutex == NULL) - { - _tprintf(_T("CreateMutex error: %d\n"), GetLastError()); - } + { + WLog_ERR(TAG, "CreateMutex error: %d", GetLastError()); + } + + wfi->updateSemaphore = CreateSemaphore(NULL, 0, 32, NULL); - wfi->updateSemaphore = CreateSemaphore(NULL, 0, 32, NULL); + wfi->updateThread = CreateThread(NULL, 0, wf_update_thread, wfi, CREATE_SUSPENDED, NULL); + + if (!wfi->updateThread) + { + WLog_ERR(TAG, "Failed to create update thread"); + } + + wfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * WF_INFO_MAXPEERS); + memset(wfi->peers, 0, sizeof(freerdp_peer*) * WF_INFO_MAXPEERS); - wfi->updateThread = CreateThread(NULL, 0, wf_update_thread, wfi, CREATE_SUSPENDED, NULL); + //Set FPS + wfi->framesPerSecond = WF_INFO_DEFAULT_FPS; - if (!wfi->updateThread) - { - _tprintf(_T("Failed to create update thread\n")); - } - - wfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * WF_INFO_MAXPEERS); - memset(wfi->peers, 0, sizeof(freerdp_peer*) * WF_INFO_MAXPEERS); - - //Set FPS - wfi->framesPerSecond = WF_INFO_DEFAULT_FPS; - - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - if (status == ERROR_SUCCESS) - { - if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (status == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) wfi->framesPerSecond = dwValue; - } + } RegCloseKey(hKey); + + //Set input toggle + wfi->input_disabled = FALSE; - //Set input toggle - wfi->input_disabled = FALSE; + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (status == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) + { + if (dwValue != 0) + wfi->input_disabled = TRUE; + } + } + RegCloseKey(hKey); + } + + return wfi; +} + +wfInfo* wf_info_get_instance() +{ + if (wfInfoInstance == NULL) + wfInfoInstance = wf_info_init(); + + return wfInfoInstance; +} + +void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context) +{ + if (wf_info_lock(wfi) > 0) + { + int i; + int peerId; + if (wfi->peerCount == WF_INFO_MAXPEERS) + { + context->socketClose = TRUE; + wf_info_unlock(wfi); + return; + } + + context->info = wfi; + context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - if (status == ERROR_SUCCESS) - { - if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) - { - if (dwValue != 0) - wfi->input_disabled = TRUE; - } - } - RegCloseKey(hKey); - } - - return wfi; -} - -wfInfo* wf_info_get_instance() -{ - if (wfInfoInstance == NULL) - wfInfoInstance = wf_info_init(); - - return wfInfoInstance; -} - -void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context) -{ - if (wf_info_lock(wfi) > 0) - { - int i; - int peerId; - if (wfi->peerCount == WF_INFO_MAXPEERS) - { - context->socketClose = TRUE; - wf_info_unlock(wfi); - return; - } - - context->info = wfi; - context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - //get the offset of the top left corner of selected screen - EnumDisplayMonitors(NULL, NULL, wf_info_monEnumCB, 0); - _IDcount = 0; - -#ifdef WITH_WIN8 - if (wfi->peerCount == 0) - wf_dxgi_init(wfi); -#else - if (wf_mirror_driver_activate(wfi) == FALSE) - { - context->socketClose = TRUE; - wf_info_unlock(wfi); - return; - } -#endif - //look trhough the array of peers until an empty slot + //get the offset of the top left corner of selected screen + EnumDisplayMonitors(NULL, NULL, wf_info_monEnumCB, 0); + _IDcount = 0; + +#ifdef WITH_DXGI_1_2 + if (wfi->peerCount == 0) + wf_dxgi_init(wfi); +#else + if (wf_mirror_driver_activate(wfi) == FALSE) + { + context->socketClose = TRUE; + wf_info_unlock(wfi); + return; + } +#endif + //look trhough the array of peers until an empty slot for(i=0; ipeers[i] == NULL) - { - peerId = i; - break; - } - } + { + //empty index will be our peer id + if (wfi->peers[i] == NULL) + { + peerId = i; + break; + } + } + + wfi->peers[peerId] = ((rdpContext*) context)->peer; + wfi->peers[peerId]->pId = peerId; + wfi->peerCount++; + WLog_INFO(TAG, "Registering Peer: id=%d #=%d", peerId, wfi->peerCount); + wf_info_unlock(wfi); - wfi->peers[peerId] = ((rdpContext*) context)->peer; - wfi->peers[peerId]->pId = peerId; - wfi->peerCount++; - printf("Registering Peer: id=%d #=%d\n", peerId, wfi->peerCount); + wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_CONNECT); + } +} + +void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context) +{ + if (wf_info_lock(wfi) > 0) + { + int peerId; - wf_info_unlock(wfi); + peerId = ((rdpContext*) context)->peer->pId; + wfi->peers[peerId] = NULL; + wfi->peerCount--; + CloseHandle(context->updateEvent); + WLog_INFO(TAG, "Unregistering Peer: id=%d, #=%d", peerId, wfi->peerCount); + +#ifdef WITH_DXGI_1_2 + if (wfi->peerCount == 0) + wf_dxgi_cleanup(wfi); +#endif + + wf_info_unlock(wfi); - wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_CONNECT); - } -} - -void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context) -{ - if (wf_info_lock(wfi) > 0) - { - int peerId; - - peerId = ((rdpContext*) context)->peer->pId; - wfi->peers[peerId] = NULL; - wfi->peerCount--; - CloseHandle(context->updateEvent); - - printf("Unregistering Peer: id=%d, #=%d\n", peerId, wfi->peerCount); - -#ifdef WITH_WIN8 - if (wfi->peerCount == 0) - wf_dxgi_cleanup(wfi); -#endif - - wf_info_unlock(wfi); - - wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_DISCONNECT); - } -} - -BOOL wf_info_have_updates(wfInfo* wfi) -{ -#ifdef WITH_WIN8 + wfreerdp_server_peer_callback_event(peerId, WF_SRV_CALLBACK_EVENT_DISCONNECT); + } +} + +BOOL wf_info_have_updates(wfInfo* wfi) +{ +#ifdef WITH_DXGI_1_2 if(wfi->framesWaiting == 0) - return FALSE; -#else - if (wfi->nextUpdate == wfi->lastUpdate) - return FALSE; -#endif - return TRUE; -} + return FALSE; +#else + if (wfi->nextUpdate == wfi->lastUpdate) + return FALSE; +#endif + return TRUE; +} + +void wf_info_update_changes(wfInfo* wfi) +{ +#ifdef WITH_DXGI_1_2 + wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000); +#else + GETCHANGESBUF* buf; -void wf_info_update_changes(wfInfo* wfi) -{ -#ifdef WITH_WIN8 - wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000); -#else - GETCHANGESBUF* buf; + buf = (GETCHANGESBUF*) wfi->changeBuffer; + wfi->nextUpdate = buf->buffer->counter; +#endif +} + +void wf_info_find_invalid_region(wfInfo* wfi) +{ +#ifdef WITH_DXGI_1_2 + wf_dxgi_getInvalidRegion(&wfi->invalid); +#else + int i; + GETCHANGESBUF* buf; - buf = (GETCHANGESBUF*) wfi->changeBuffer; - wfi->nextUpdate = buf->buffer->counter; -#endif -} - -void wf_info_find_invalid_region(wfInfo* wfi) -{ -#ifdef WITH_WIN8 - wf_dxgi_getInvalidRegion(&wfi->invalid); -#else - int i; - GETCHANGESBUF* buf; - - buf = (GETCHANGESBUF*) wfi->changeBuffer; - - for (i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF) - { - LPRECT lpR = &buf->buffer->pointrect[i].rect; - - //need to make sure we only get updates from the selected screen + buf = (GETCHANGESBUF*) wfi->changeBuffer; + + for (i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF) + { + LPRECT lpR = &buf->buffer->pointrect[i].rect; + + //need to make sure we only get updates from the selected screen if ( (lpR->left >= wfi->servscreen_xoffset) && (lpR->right <= (wfi->servscreen_xoffset + wfi->servscreen_width) ) && (lpR->top >= wfi->servscreen_yoffset) && (lpR->bottom <= (wfi->servscreen_yoffset + wfi->servscreen_height) ) ) - { - UnionRect(&wfi->invalid, &wfi->invalid, lpR); - } - else - { - continue; - } - } -#endif + { + UnionRect(&wfi->invalid, &wfi->invalid, lpR); + } + else + { + continue; + } + } +#endif + + if (wfi->invalid.left < 0) + wfi->invalid.left = 0; + + if (wfi->invalid.top < 0) + wfi->invalid.top = 0; + + if (wfi->invalid.right >= wfi->servscreen_width) + wfi->invalid.right = wfi->servscreen_width - 1; + + if (wfi->invalid.bottom >= wfi->servscreen_height) + wfi->invalid.bottom = wfi->servscreen_height - 1; + + //WLog_DBG(TAG, "invalid region: (%d, %d), (%d, %d)", wfi->invalid.left, wfi->invalid.top, wfi->invalid.right, wfi->invalid.bottom); +} + +void wf_info_clear_invalid_region(wfInfo* wfi) +{ + wfi->lastUpdate = wfi->nextUpdate; + SetRectEmpty(&wfi->invalid); +} + +void wf_info_invalidate_full_screen(wfInfo* wfi) +{ + SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height); +} + +BOOL wf_info_have_invalid_region(wfInfo* wfi) +{ + return IsRectEmpty(&wfi->invalid); +} + +void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch) +{ + *width = (wfi->invalid.right - wfi->invalid.left); + *height = (wfi->invalid.bottom - wfi->invalid.top); - if (wfi->invalid.left < 0) - wfi->invalid.left = 0; +#ifdef WITH_DXGI_1_2 + wf_dxgi_getPixelData(wfi, pBits, pitch, &wfi->invalid); +#else + { + long offset; + GETCHANGESBUF* changes; + changes = (GETCHANGESBUF*) wfi->changeBuffer; - if (wfi->invalid.top < 0) - wfi->invalid.top = 0; + *width += 1; + *height += 1; - if (wfi->invalid.right >= wfi->servscreen_width) - wfi->invalid.right = wfi->servscreen_width - 1; - - if (wfi->invalid.bottom >= wfi->servscreen_height) - wfi->invalid.bottom = wfi->servscreen_height - 1; - - //printf("invalid region: (%d, %d), (%d, %d)\n", wfi->invalid.left, wfi->invalid.top, wfi->invalid.right, wfi->invalid.bottom); -} - -void wf_info_clear_invalid_region(wfInfo* wfi) -{ - wfi->lastUpdate = wfi->nextUpdate; - SetRectEmpty(&wfi->invalid); -} - -void wf_info_invalidate_full_screen(wfInfo* wfi) -{ - SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height); -} - -BOOL wf_info_have_invalid_region(wfInfo* wfi) -{ - return IsRectEmpty(&wfi->invalid); -} - -void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch) -{ - *width = (wfi->invalid.right - wfi->invalid.left); - *height = (wfi->invalid.bottom - wfi->invalid.top); - -#ifdef WITH_WIN8 - wf_dxgi_getPixelData(wfi, pBits, pitch, &wfi->invalid); -#else - { - long offset; - GETCHANGESBUF* changes; - changes = (GETCHANGESBUF*) wfi->changeBuffer; - - *width += 1; - *height += 1; - - offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4); + offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4); *pBits = ((BYTE*) (changes->Userbuffer)) + offset; - *pitch = wfi->virtscreen_width * 4; - } -#endif -} - -BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ + *pitch = wfi->virtscreen_width * 4; + } +#endif +} + +BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ wfInfo * wfi; - wfi = wf_info_get_instance(); - + wfi = wf_info_get_instance(); + if(_IDcount == wfi->screenID) - { - wfi->servscreen_xoffset = lprcMonitor->left; - wfi->servscreen_yoffset = lprcMonitor->top; - } + { + wfi->servscreen_xoffset = lprcMonitor->left; + wfi->servscreen_yoffset = lprcMonitor->top; + } _IDcount++; - - return TRUE; -} + + return TRUE; +} diff --git a/server/Windows/wf_info.h b/server/Windows/wf_info.h index d1dc44f2b..38a3ae6c6 100644 --- a/server/Windows/wf_info.h +++ b/server/Windows/wf_info.h @@ -1,45 +1,45 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Windows Server - * - * Copyright 2012 Corey Clayton - * - * 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 WF_INFO_H -#define WF_INFO_H - -#include "wf_interface.h" - -#define WF_INFO_DEFAULT_FPS 24 -#define WF_INFO_MAXPEERS 32 - -int wf_info_lock(wfInfo* wfi); -int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds); -int wf_info_unlock(wfInfo* wfi); - -wfInfo* wf_info_get_instance(void); -void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context); -void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context); - -BOOL wf_info_have_updates(wfInfo* wfi); -void wf_info_update_changes(wfInfo* wfi); -void wf_info_find_invalid_region(wfInfo* wfi); -void wf_info_clear_invalid_region(wfInfo* wfi); -void wf_info_invalidate_full_screen(wfInfo* wfi); -BOOL wf_info_have_invalid_region(wfInfo* wfi); -void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch); -BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); - -#endif /* WF_INFO_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Windows Server + * + * Copyright 2012 Corey Clayton + * + * 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 WF_INFO_H +#define WF_INFO_H + +#include "wf_interface.h" + +#define WF_INFO_DEFAULT_FPS 24 +#define WF_INFO_MAXPEERS 32 + +int wf_info_lock(wfInfo* wfi); +int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds); +int wf_info_unlock(wfInfo* wfi); + +wfInfo* wf_info_get_instance(void); +void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context); +void wf_info_peer_unregister(wfInfo* wfi, wfPeerContext* context); + +BOOL wf_info_have_updates(wfInfo* wfi); +void wf_info_update_changes(wfInfo* wfi); +void wf_info_find_invalid_region(wfInfo* wfi); +void wf_info_clear_invalid_region(wfInfo* wfi); +void wf_info_invalidate_full_screen(wfInfo* wfi); +BOOL wf_info_have_invalid_region(wfInfo* wfi); +void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch); +BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); + +#endif /* WF_INFO_H */ diff --git a/server/Windows/wf_input.c b/server/Windows/wf_input.c index 06b9f5350..7c70748fa 100644 --- a/server/Windows/wf_input.c +++ b/server/Windows/wf_input.c @@ -158,8 +158,6 @@ void wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1 x += wfi->servscreen_xoffset; y += wfi->servscreen_yoffset; - //mouse_event.mi.dx = x * (0xFFFF / width); - //mouse_event.mi.dy = y * (0xFFFF / height); mouse_event.mi.dx = (LONG) ((float) x * (65535.0f / width)); mouse_event.mi.dy = (LONG) ((float) y * (65535.0f / height)); mouse_event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; diff --git a/server/Windows/wf_interface.c b/server/Windows/wf_interface.c index ea0e98d46..e2ece59b3 100644 --- a/server/Windows/wf_interface.c +++ b/server/Windows/wf_interface.c @@ -102,7 +102,7 @@ DWORD WINAPI wf_server_main_loop(LPVOID lpParam) if (instance->GetFileDescriptor(instance, rfds, &rcount) != TRUE) { - printf("Failed to get FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } @@ -127,13 +127,12 @@ DWORD WINAPI wf_server_main_loop(LPVOID lpParam) if (instance->CheckFileDescriptor(instance) != TRUE) { - printf("Failed to check FreeRDP file descriptor\n"); + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } } - printf("wf_server_main_loop terminating\n"); - + WLog_INFO(TAG, "wf_server_main_loop terminating"); instance->Close(instance); return 0; @@ -163,8 +162,7 @@ BOOL wfreerdp_server_stop(wfServer* server) wfInfo* wfi; wfi = wf_info_get_instance(); - - printf("Stopping server\n"); + WLog_INFO(TAG, "Stopping server"); wfi->force_all_disconnect = TRUE; server->instance->Close(server->instance); return TRUE; @@ -210,7 +208,7 @@ FREERDP_API BOOL wfreerdp_server_is_running(wfServer* server) bRet = GetExitCodeThread(server->thread, &tStatus); if (bRet == 0) { - printf("Error in call to GetExitCodeThread\n"); + WLog_ERR(TAG, "Error in call to GetExitCodeThread"); return FALSE; } @@ -245,7 +243,7 @@ FREERDP_API UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr) } else { - printf("nonexistent peer id=%d\n", pId); + WLog_WARN(TAG, "nonexistent peer id=%d", pId); return 0; } } diff --git a/server/Windows/wf_interface.h b/server/Windows/wf_interface.h index dc3af1c7f..6ab6b6f3e 100644 --- a/server/Windows/wf_interface.h +++ b/server/Windows/wf_interface.h @@ -32,6 +32,10 @@ #include +#if _WIN32_WINNT >= 0x0602 +#define WITH_DXGI_1_2 1 +#endif + #define WF_SRV_CALLBACK_EVENT_CONNECT 1 #define WF_SRV_CALLBACK_EVENT_DISCONNECT 2 #define WF_SRV_CALLBACK_EVENT_ACTIVATE 4 @@ -52,8 +56,6 @@ struct wf_info int servscreen_height; int servscreen_xoffset; int servscreen_yoffset; - //int width; - //int height; int frame_idx; int bitsPerPixel; diff --git a/server/Windows/wf_mirage.c b/server/Windows/wf_mirage.c index baafd031f..b3fa6c504 100644 --- a/server/Windows/wf_mirage.c +++ b/server/Windows/wf_mirage.c @@ -1,366 +1,368 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Windows Server - * - * Copyright 2012 Marc-Andre Moreau - * Copyright 2012-2013 Corey Clayton - * - * 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. - */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Windows Server + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2012-2013 Corey Clayton + * + * 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 +#include + +#include "wf_mirage.h" + +#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\") +/* +This function will iterate over the loaded display devices until it finds +the mirror device we want to load. If found, it will then copy the registry +key corresponding to the device to the wfi and returns TRUE. Otherwise +the function returns FALSE. +*/ +BOOL wf_mirror_driver_find_display_device(wfInfo* wfi) +{ + BOOL result; + BOOL devFound; + DWORD deviceNumber; + DISPLAY_DEVICE deviceInfo; -#include -#include + devFound = FALSE; + deviceNumber = 0; + deviceInfo.cb = sizeof(deviceInfo); + + while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0)) + { + if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0) + { + int deviceKeyLength; + int deviceKeyPrefixLength; -#include "wf_mirage.h" + deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX); + + if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0) + { + deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength; + wfi->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR)); -#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\") -/* -This function will iterate over the loaded display devices until it finds -the mirror device we want to load. If found, it will then copy the registry -key corresponding to the device to the wfi and returns TRUE. Otherwise -the function returns FALSE. -*/ -BOOL wf_mirror_driver_find_display_device(wfInfo* wfi) -{ - BOOL result; - BOOL devFound; - DWORD deviceNumber; - DISPLAY_DEVICE deviceInfo; - - devFound = FALSE; - deviceNumber = 0; - deviceInfo.cb = sizeof(deviceInfo); - - while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0)) - { - if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0) - { - int deviceKeyLength; - int deviceKeyPrefixLength; - - deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX); - - if (_tcsnicmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0) - { - deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength; - wfi->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR)); - - _tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1, + _tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1, &deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength); - } - - _tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName)); - return TRUE; - } - - deviceNumber++; - } - - return FALSE; -} - -/** - * This function will attempt to access the the windows registry using the device - * key stored in the current wfi. It will attempt to read the value of the - * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to + } + + _tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName)); + return TRUE; + } + + deviceNumber++; + } + + return FALSE; +} + +/** + * This function will attempt to access the the windows registry using the device + * key stored in the current wfi. It will attempt to read the value of the + * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to * val. If unable to read the subkey, this function will return FALSE. If the * subkey is not set to val it will then attempt to set it to val and return TRUE. If * unsuccessful or an unexpected value is encountered, the function returns - * FALSE. - */ + * FALSE. + */ + +BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode) +{ + HKEY hKey; + LONG status; + DWORD dwType; + DWORD dwSize; + DWORD dwValue; -BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode) -{ - HKEY hKey; - LONG status; - DWORD dwType; - DWORD dwSize; - DWORD dwValue; - - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey); - - if (status != ERROR_SUCCESS) - { - printf("Error opening RegKey: status=%0X\n", status); - if (status == ERROR_ACCESS_DENIED) - printf("access denied. Do you have admin privleges?\n"); - return FALSE; - } - - dwSize = sizeof(DWORD); - status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error opening RegKey: status=%0X", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + return FALSE; + } + + dwSize = sizeof(DWORD); + status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), NULL, &dwType, (BYTE*) &dwValue, &dwSize); + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error querying RegKey: status=%0X", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + return FALSE; + } + + if (dwValue ^ mode) //only if we want to change modes + { + dwValue = mode; + dwSize = sizeof(DWORD); - if (status != ERROR_SUCCESS) - { - printf("Error querying RegKey: status=%0X\n", status); - if (status == ERROR_ACCESS_DENIED) - printf("access denied. Do you have admin privleges?\n"); - return FALSE; - } - - if (dwValue ^ mode) //only if we want to change modes - { - dwValue = mode; - dwSize = sizeof(DWORD); - - status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), + status = RegSetValueEx(hKey, _T("Attach.ToDesktop"), 0, REG_DWORD, (BYTE*) &dwValue, dwSize); + + if (status != ERROR_SUCCESS) + { + WLog_DBG(TAG, "Error writing registry key: %d ", status); + + if (status == ERROR_ACCESS_DENIED) + WLog_DBG(TAG, "access denied. Do you have admin privleges?"); + + WLog_DBG(TAG, ""); + return FALSE; + } + } + + return TRUE; +} + +void wf_mirror_driver_print_display_change_status(LONG status) +{ + TCHAR disp_change[64]; + + switch (status) + { + case DISP_CHANGE_SUCCESSFUL: + _tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL")); + break; - if (status != ERROR_SUCCESS) - { - printf("Error writing registry key: %d ", status); - if (status == ERROR_ACCESS_DENIED) - printf("access denied. Do you have admin privleges?"); - printf("\n"); - return FALSE; - } - } + case DISP_CHANGE_BADDUALVIEW: + _tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW")); + break; - return TRUE; -} + case DISP_CHANGE_BADFLAGS: + _tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS")); + break; -void wf_mirror_driver_print_display_change_status(LONG status) -{ - TCHAR disp_change[64]; + case DISP_CHANGE_BADMODE: + _tcscpy(disp_change, _T("DISP_CHANGE_BADMODE")); + break; - switch (status) - { - case DISP_CHANGE_SUCCESSFUL: - _tcscpy(disp_change, _T("DISP_CHANGE_SUCCESSFUL")); - break; + case DISP_CHANGE_BADPARAM: + _tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM")); + break; - case DISP_CHANGE_BADDUALVIEW: - _tcscpy(disp_change, _T("DISP_CHANGE_BADDUALVIEW")); - break; + case DISP_CHANGE_FAILED: + _tcscpy(disp_change, _T("DISP_CHANGE_FAILED")); + break; - case DISP_CHANGE_BADFLAGS: - _tcscpy(disp_change, _T("DISP_CHANGE_BADFLAGS")); - break; + case DISP_CHANGE_NOTUPDATED: + _tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED")); + break; - case DISP_CHANGE_BADMODE: - _tcscpy(disp_change, _T("DISP_CHANGE_BADMODE")); - break; + case DISP_CHANGE_RESTART: + _tcscpy(disp_change, _T("DISP_CHANGE_RESTART")); + break; - case DISP_CHANGE_BADPARAM: - _tcscpy(disp_change, _T("DISP_CHANGE_BADPARAM")); - break; - - case DISP_CHANGE_FAILED: - _tcscpy(disp_change, _T("DISP_CHANGE_FAILED")); - break; - - case DISP_CHANGE_NOTUPDATED: - _tcscpy(disp_change, _T("DISP_CHANGE_NOTUPDATED")); - break; - - case DISP_CHANGE_RESTART: - _tcscpy(disp_change, _T("DISP_CHANGE_RESTART")); - break; - - default: - _tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN")); - break; - } - - if (status != DISP_CHANGE_SUCCESSFUL) - _tprintf(_T("ChangeDisplaySettingsEx() failed with %s (%d)\n"), disp_change, status); - else - _tprintf(_T("ChangeDisplaySettingsEx() succeeded with %s (%d)\n"), disp_change, status); -} - -/** + default: + _tcscpy(disp_change, _T("DISP_CHANGE_UNKNOWN")); + break; + } + + if (status != DISP_CHANGE_SUCCESSFUL) + WLog_ERR(TAG, "ChangeDisplaySettingsEx() failed with %s (%d)", disp_change, status); + else + WLog_INFO(TAG, "ChangeDisplaySettingsEx() succeeded with %s (%d)", disp_change, status); +} + +/** * This function will attempt to apply the currently configured display settings * in the registry to the display driver. It will return TRUE if successful - * otherwise it returns FALSE. - * If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself. - */ - -BOOL wf_mirror_driver_update(wfInfo* wfi, int mode) -{ - HDC dc; - BOOL status; - DWORD* extHdr; - WORD drvExtraSaved; - DEVMODE* deviceMode; - LONG disp_change_status; - DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE; - + * otherwise it returns FALSE. + * If mode is MIRROR_UNLOAD then the the driver will be asked to remove itself. + */ + +BOOL wf_mirror_driver_update(wfInfo* wfi, int mode) +{ + HDC dc; + BOOL status; + DWORD* extHdr; + WORD drvExtraSaved; + DEVMODE* deviceMode; + LONG disp_change_status; + DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE; + if ( (mode != MIRROR_LOAD) && (mode != MIRROR_UNLOAD) ) - { - printf("Invalid mirror mode!\n"); - return FALSE; - } + { + WLog_DBG(TAG, "Invalid mirror mode!"); + return FALSE; + } - deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); - deviceMode->dmDriverExtra = 2 * sizeof(DWORD); + deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); + deviceMode->dmDriverExtra = 2 * sizeof(DWORD); extHdr = (DWORD*)((BYTE*) &deviceMode + sizeof(DEVMODE)); - extHdr[0] = dmf_devmodewext_magic_sig; - extHdr[1] = 0; + extHdr[0] = dmf_devmodewext_magic_sig; + extHdr[1] = 0; - drvExtraSaved = deviceMode->dmDriverExtra; - memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); - deviceMode->dmSize = sizeof(DEVMODE); - deviceMode->dmDriverExtra = drvExtraSaved; + drvExtraSaved = deviceMode->dmDriverExtra; + memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); + deviceMode->dmSize = sizeof(DEVMODE); + deviceMode->dmDriverExtra = drvExtraSaved; + + if (mode == MIRROR_LOAD) + { + wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - if (mode == MIRROR_LOAD) - { - wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + deviceMode->dmPelsWidth = wfi->virtscreen_width; + deviceMode->dmPelsHeight = wfi->virtscreen_height; + deviceMode->dmBitsPerPel = wfi->bitsPerPixel; + deviceMode->dmPosition.x = wfi->servscreen_xoffset; + deviceMode->dmPosition.y = wfi->servscreen_yoffset; + } + + deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; - deviceMode->dmPelsWidth = wfi->virtscreen_width; - deviceMode->dmPelsHeight = wfi->virtscreen_height; - deviceMode->dmBitsPerPel = wfi->bitsPerPixel; - deviceMode->dmPosition.x = wfi->servscreen_xoffset; - deviceMode->dmPosition.y = wfi->servscreen_yoffset; - } + _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName)); - deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; + disp_change_status = ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL); - _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName)); - - disp_change_status = ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL); - - status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE; - - if (!status) - wf_mirror_driver_print_display_change_status(disp_change_status); + status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE; + + if (!status) + wf_mirror_driver_print_display_change_status(disp_change_status); - return status; -} + return status; +} + +BOOL wf_mirror_driver_map_memory(wfInfo* wfi) +{ + int status; -BOOL wf_mirror_driver_map_memory(wfInfo* wfi) -{ - int status; - - wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL); - - if (wfi->driverDC == NULL) - { - _tprintf(_T("Could not create device driver context!\n")); - - { - LPVOID lpMsgBuf; + wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL); + + if (wfi->driverDC == NULL) + { + WLog_ERR(TAG, "Could not create device driver context!"); + { + LPVOID lpMsgBuf; DWORD dw = GetLastError(); - FormatMessage( + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL ); - // Display the error message and exit the process + // Display the error message and exit the process + WLog_ERR(TAG, "CreateDC failed on device [%s] with error %d: %s", wfi->deviceName, dw, lpMsgBuf); + LocalFree(lpMsgBuf); + } - _tprintf(_T("CreateDC failed on device [%s] with error %d: %s\n"), wfi->deviceName, dw, lpMsgBuf); + return FALSE; + } + + wfi->changeBuffer = malloc(sizeof(GETCHANGESBUF)); + ZeroMemory(wfi->changeBuffer, sizeof(GETCHANGESBUF)); - LocalFree(lpMsgBuf); - } + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer); + + if (status <= 0) + { + WLog_ERR(TAG, "Failed to map shared memory from the driver! code %d", status); + return FALSE; + } + + return TRUE; +} + +/* Unmap the shared memory and release the DC */ + +BOOL wf_mirror_driver_cleanup(wfInfo* wfi) +{ + int status; - return FALSE; - } - - wfi->changeBuffer = malloc(sizeof(GETCHANGESBUF)); - ZeroMemory(wfi->changeBuffer, sizeof(GETCHANGESBUF)); - - status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer); - - if (status <= 0) - { - _tprintf(_T("Failed to map shared memory from the driver! code %d\n"), status); - return FALSE; - } - - return TRUE; -} - -/* Unmap the shared memory and release the DC */ - -BOOL wf_mirror_driver_cleanup(wfInfo* wfi) -{ - int status; - - status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer, 0, 0); + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer, 0, 0); - if (status <= 0) - { - _tprintf(_T("Failed to unmap shared memory from the driver! code %d\n"), status); - } + if (status <= 0) + { + WLog_ERR(TAG, "Failed to unmap shared memory from the driver! code %d", status); + } + + if (wfi->driverDC != NULL) + { + status = DeleteDC(wfi->driverDC); + + if (status == 0) + { + WLog_ERR(TAG, "Failed to release DC!")); + } + } + + free(wfi->changeBuffer); - if (wfi->driverDC != NULL) - { - status = DeleteDC(wfi->driverDC); - - if (status == 0) - { - _tprintf(_T("Failed to release DC!\n")); - } - } - - free(wfi->changeBuffer); - - return TRUE; -} - -BOOL wf_mirror_driver_activate(wfInfo* wfi) -{ - if (!wfi->mirrorDriverActive) - { - printf("Activating Mirror Driver\n"); - - if (wf_mirror_driver_find_display_device(wfi) == FALSE) - { - printf("Could not find dfmirage mirror driver! Is it installed?\n"); - return FALSE; - } - - if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE) - { - printf("Could not attach display device!\n"); - return FALSE; - } - - if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE) - { - printf("could not update system with new display settings!\n"); - return FALSE; - } - - if (wf_mirror_driver_map_memory(wfi) == FALSE) - { - printf("Unable to map memory for mirror driver!\n"); - return FALSE; - } - wfi->mirrorDriverActive = TRUE; - } - - return TRUE; -} - -void wf_mirror_driver_deactivate(wfInfo* wfi) -{ - if (wfi->mirrorDriverActive) - { - printf("Deactivating Mirror Driver\n"); - - wf_mirror_driver_cleanup(wfi); - wf_mirror_driver_display_device_attach(wfi, 0); - wf_mirror_driver_update(wfi, MIRROR_UNLOAD); - wfi->mirrorDriverActive = FALSE; - } + return TRUE; +} + +BOOL wf_mirror_driver_activate(wfInfo* wfi) +{ + if (!wfi->mirrorDriverActive) + { + WLog_DBG(TAG, "Activating Mirror Driver"); + + if (wf_mirror_driver_find_display_device(wfi) == FALSE) + { + WLog_DBG(TAG, "Could not find dfmirage mirror driver! Is it installed?"); + return FALSE; + } + + if (wf_mirror_driver_display_device_attach(wfi, 1) == FALSE) + { + WLog_DBG(TAG, "Could not attach display device!"); + return FALSE; + } + + if (wf_mirror_driver_update(wfi, MIRROR_LOAD) == FALSE) + { + WLog_DBG(TAG, "could not update system with new display settings!"); + return FALSE; + } + + if (wf_mirror_driver_map_memory(wfi) == FALSE) + { + WLog_DBG(TAG, "Unable to map memory for mirror driver!"); + return FALSE; + } + wfi->mirrorDriverActive = TRUE; + } + + return TRUE; +} + +void wf_mirror_driver_deactivate(wfInfo* wfi) +{ + if (wfi->mirrorDriverActive) + { + WLog_DBG(TAG, "Deactivating Mirror Driver"); + wf_mirror_driver_cleanup(wfi); + wf_mirror_driver_display_device_attach(wfi, 0); + wf_mirror_driver_update(wfi, MIRROR_UNLOAD); + wfi->mirrorDriverActive = FALSE; + } } \ No newline at end of file diff --git a/server/Windows/wf_mirage.h b/server/Windows/wf_mirage.h index 9ddfb8096..372e02bbe 100644 --- a/server/Windows/wf_mirage.h +++ b/server/Windows/wf_mirage.h @@ -1,221 +1,221 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Windows Server - * - * Copyright 2012 Marc-Andre Moreau - * Copyright 2012-2013 Corey Clayton - * - * 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 WF_MIRAGE_H -#define WF_MIRAGE_H - -#include "wf_interface.h" - -enum -{ - MIRROR_LOAD = 0, - MIRROR_UNLOAD = 1 -}; - - - -enum -{ - DMF_ESCAPE_BASE_1_VB = 1030, - DMF_ESCAPE_BASE_2_VB = 1026, - DMF_ESCAPE_BASE_3_VB = 24 -}; - -#ifdef _WIN64 - -#define CLIENT_64BIT 0x8000 - -enum -{ - DMF_ESCAPE_BASE_1 = CLIENT_64BIT | DMF_ESCAPE_BASE_1_VB, - DMF_ESCAPE_BASE_2 = CLIENT_64BIT | DMF_ESCAPE_BASE_2_VB, - DMF_ESCAPE_BASE_3 = CLIENT_64BIT | DMF_ESCAPE_BASE_3_VB, -}; - -#else - -enum -{ - DMF_ESCAPE_BASE_1 = DMF_ESCAPE_BASE_1_VB, - DMF_ESCAPE_BASE_2 = DMF_ESCAPE_BASE_2_VB, - DMF_ESCAPE_BASE_3 = DMF_ESCAPE_BASE_3_VB, -}; - -#endif - -typedef enum -{ - dmf_esc_qry_ver_info = DMF_ESCAPE_BASE_2 + 0, - dmf_esc_usm_pipe_map = DMF_ESCAPE_BASE_1 + 0, - dmf_esc_usm_pipe_unmap = DMF_ESCAPE_BASE_1 + 1, - dmf_esc_test = DMF_ESCAPE_BASE_1 + 20, - dmf_esc_usm_pipe_mapping_test = DMF_ESCAPE_BASE_1 + 21, - dmf_esc_pointer_shape_get = DMF_ESCAPE_BASE_3, - -} dmf_escape; - -#define CLIP_LIMIT 50 -#define MAXCHANGES_BUF 20000 - -typedef enum -{ - dmf_dfo_IGNORE = 0, - dmf_dfo_FROM_SCREEN = 1, - dmf_dfo_FROM_DIB = 2, - dmf_dfo_TO_SCREEN = 3, - dmf_dfo_SCREEN_SCREEN = 11, - dmf_dfo_BLIT = 12, - dmf_dfo_SOLIDFILL = 13, - dmf_dfo_BLEND = 14, - dmf_dfo_TRANS = 15, - dmf_dfo_PLG = 17, - dmf_dfo_TEXTOUT = 18, - dmf_dfo_Ptr_Shape = 19, - dmf_dfo_Ptr_Engage = 48, - dmf_dfo_Ptr_Avert = 49, - dmf_dfn_assert_on = 64, - dmf_dfn_assert_off = 65, -} dmf_UpdEvent; - -#define NOCACHE 1 -#define OLDCACHE 2 -#define NEWCACHE 3 - -typedef struct -{ - ULONG type; - RECT rect; -#ifndef DFMIRAGE_LEAN - RECT origrect; - POINT point; - ULONG color; - ULONG refcolor; -#endif -} CHANGES_RECORD; - -typedef CHANGES_RECORD* PCHANGES_RECORD; - -typedef struct -{ - ULONG counter; - CHANGES_RECORD pointrect[MAXCHANGES_BUF]; -} CHANGES_BUF; - -#define EXT_DEVMODE_SIZE_MAX 3072 -#define DMF_PIPE_SEC_SIZE_DEFAULT ALIGN64K(sizeof(CHANGES_BUF)) - -typedef struct -{ - CHANGES_BUF* buffer; - PVOID Userbuffer; -} GETCHANGESBUF; - -#define dmf_sprb_ERRORMASK 0x07FF -#define dmf_sprb_STRICTSESSION_AFF 0x1FFF - -typedef enum -{ - dmf_sprb_internal_error = 0x0001, - dmf_sprb_miniport_gen_error = 0x0004, - dmf_sprb_memory_alloc_failed = 0x0008, - dmf_sprb_pipe_buff_overflow = 0x0010, - dmf_sprb_pipe_buff_insufficient = 0x0020, - dmf_sprb_pipe_not_ready = 0x0040, - dmf_sprb_gdi_err = 0x0100, - dmf_sprb_owner_died = 0x0400, - dmf_sprb_tgtwnd_gone = 0x0800, - dmf_sprb_pdev_detached = 0x2000, -} dmf_session_prob_status; - -#define DMF_ESC_RET_FAILF 0x80000000 -#define DMF_ESC_RET_SSTMASK 0x0000FFFF -#define DMF_ESC_RET_IMMMASK 0x7FFF0000 - -typedef enum -{ - dmf_escret_generic_ok = 0x00010000, - dmf_escret_bad_state = 0x00100000, - dmf_escret_access_denied = 0x00200000, - dmf_escret_bad_buffer_size = 0x00400000, - dmf_escret_internal_err = 0x00800000, - dmf_escret_out_of_memory = 0x02000000, - dmf_escret_already_connected = 0x04000000, - dmf_escret_oh_boy_too_late = 0x08000000, - dmf_escret_bad_window = 0x10000000, - dmf_escret_drv_ver_higher = 0x20000000, - dmf_escret_drv_ver_lower = 0x40000000, -} dmf_esc_retcode; - -typedef struct -{ - ULONG cbSize; - ULONG app_actual_version; - ULONG display_minreq_version; - ULONG connect_options; -} Esc_dmf_Qvi_IN; - -enum -{ - esc_qvi_prod_name_max = 16, -}; - -#define ESC_QVI_PROD_MIRAGE "MIRAGE" -#define ESC_QVI_PROD_QUASAR "QUASAR" - -typedef struct -{ - ULONG cbSize; - ULONG display_actual_version; - ULONG miniport_actual_version; - ULONG app_minreq_version; - ULONG display_buildno; - ULONG miniport_buildno; - char prod_name[esc_qvi_prod_name_max]; -} Esc_dmf_Qvi_OUT; - -typedef struct -{ - ULONG cbSize; - char* pDstBmBuf; - ULONG nDstBmBufSize; -} Esc_dmf_pointer_shape_get_IN; - -typedef struct -{ - ULONG cbSize; - POINTL BmSize; - char* pMaskBm; - ULONG nMaskBmSize; - char* pColorBm; - ULONG nColorBmSize; - char* pColorBmPal; - ULONG nColorBmPalEntries; -} Esc_dmf_pointer_shape_get_OUT; - -BOOL wf_mirror_driver_find_display_device(wfInfo* wfi); -BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode); -BOOL wf_mirror_driver_update(wfInfo* wfi, int mode); -BOOL wf_mirror_driver_map_memory(wfInfo* wfi); -BOOL wf_mirror_driver_cleanup(wfInfo* wfi); - -BOOL wf_mirror_driver_activate(wfInfo* wfi); -void wf_mirror_driver_deactivate(wfInfo* wfi); - -#endif /* WF_MIRAGE_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Windows Server + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2012-2013 Corey Clayton + * + * 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 WF_MIRAGE_H +#define WF_MIRAGE_H + +#include "wf_interface.h" + +enum +{ + MIRROR_LOAD = 0, + MIRROR_UNLOAD = 1 +}; + + + +enum +{ + DMF_ESCAPE_BASE_1_VB = 1030, + DMF_ESCAPE_BASE_2_VB = 1026, + DMF_ESCAPE_BASE_3_VB = 24 +}; + +#ifdef _WIN64 + +#define CLIENT_64BIT 0x8000 + +enum +{ + DMF_ESCAPE_BASE_1 = CLIENT_64BIT | DMF_ESCAPE_BASE_1_VB, + DMF_ESCAPE_BASE_2 = CLIENT_64BIT | DMF_ESCAPE_BASE_2_VB, + DMF_ESCAPE_BASE_3 = CLIENT_64BIT | DMF_ESCAPE_BASE_3_VB, +}; + +#else + +enum +{ + DMF_ESCAPE_BASE_1 = DMF_ESCAPE_BASE_1_VB, + DMF_ESCAPE_BASE_2 = DMF_ESCAPE_BASE_2_VB, + DMF_ESCAPE_BASE_3 = DMF_ESCAPE_BASE_3_VB, +}; + +#endif + +typedef enum +{ + dmf_esc_qry_ver_info = DMF_ESCAPE_BASE_2 + 0, + dmf_esc_usm_pipe_map = DMF_ESCAPE_BASE_1 + 0, + dmf_esc_usm_pipe_unmap = DMF_ESCAPE_BASE_1 + 1, + dmf_esc_test = DMF_ESCAPE_BASE_1 + 20, + dmf_esc_usm_pipe_mapping_test = DMF_ESCAPE_BASE_1 + 21, + dmf_esc_pointer_shape_get = DMF_ESCAPE_BASE_3, + +} dmf_escape; + +#define CLIP_LIMIT 50 +#define MAXCHANGES_BUF 20000 + +typedef enum +{ + dmf_dfo_IGNORE = 0, + dmf_dfo_FROM_SCREEN = 1, + dmf_dfo_FROM_DIB = 2, + dmf_dfo_TO_SCREEN = 3, + dmf_dfo_SCREEN_SCREEN = 11, + dmf_dfo_BLIT = 12, + dmf_dfo_SOLIDFILL = 13, + dmf_dfo_BLEND = 14, + dmf_dfo_TRANS = 15, + dmf_dfo_PLG = 17, + dmf_dfo_TEXTOUT = 18, + dmf_dfo_Ptr_Shape = 19, + dmf_dfo_Ptr_Engage = 48, + dmf_dfo_Ptr_Avert = 49, + dmf_dfn_assert_on = 64, + dmf_dfn_assert_off = 65, +} dmf_UpdEvent; + +#define NOCACHE 1 +#define OLDCACHE 2 +#define NEWCACHE 3 + +typedef struct +{ + ULONG type; + RECT rect; +#ifndef DFMIRAGE_LEAN + RECT origrect; + POINT point; + ULONG color; + ULONG refcolor; +#endif +} CHANGES_RECORD; + +typedef CHANGES_RECORD* PCHANGES_RECORD; + +typedef struct +{ + ULONG counter; + CHANGES_RECORD pointrect[MAXCHANGES_BUF]; +} CHANGES_BUF; + +#define EXT_DEVMODE_SIZE_MAX 3072 +#define DMF_PIPE_SEC_SIZE_DEFAULT ALIGN64K(sizeof(CHANGES_BUF)) + +typedef struct +{ + CHANGES_BUF* buffer; + PVOID Userbuffer; +} GETCHANGESBUF; + +#define dmf_sprb_ERRORMASK 0x07FF +#define dmf_sprb_STRICTSESSION_AFF 0x1FFF + +typedef enum +{ + dmf_sprb_internal_error = 0x0001, + dmf_sprb_miniport_gen_error = 0x0004, + dmf_sprb_memory_alloc_failed = 0x0008, + dmf_sprb_pipe_buff_overflow = 0x0010, + dmf_sprb_pipe_buff_insufficient = 0x0020, + dmf_sprb_pipe_not_ready = 0x0040, + dmf_sprb_gdi_err = 0x0100, + dmf_sprb_owner_died = 0x0400, + dmf_sprb_tgtwnd_gone = 0x0800, + dmf_sprb_pdev_detached = 0x2000, +} dmf_session_prob_status; + +#define DMF_ESC_RET_FAILF 0x80000000 +#define DMF_ESC_RET_SSTMASK 0x0000FFFF +#define DMF_ESC_RET_IMMMASK 0x7FFF0000 + +typedef enum +{ + dmf_escret_generic_ok = 0x00010000, + dmf_escret_bad_state = 0x00100000, + dmf_escret_access_denied = 0x00200000, + dmf_escret_bad_buffer_size = 0x00400000, + dmf_escret_internal_err = 0x00800000, + dmf_escret_out_of_memory = 0x02000000, + dmf_escret_already_connected = 0x04000000, + dmf_escret_oh_boy_too_late = 0x08000000, + dmf_escret_bad_window = 0x10000000, + dmf_escret_drv_ver_higher = 0x20000000, + dmf_escret_drv_ver_lower = 0x40000000, +} dmf_esc_retcode; + +typedef struct +{ + ULONG cbSize; + ULONG app_actual_version; + ULONG display_minreq_version; + ULONG connect_options; +} Esc_dmf_Qvi_IN; + +enum +{ + esc_qvi_prod_name_max = 16, +}; + +#define ESC_QVI_PROD_MIRAGE "MIRAGE" +#define ESC_QVI_PROD_QUASAR "QUASAR" + +typedef struct +{ + ULONG cbSize; + ULONG display_actual_version; + ULONG miniport_actual_version; + ULONG app_minreq_version; + ULONG display_buildno; + ULONG miniport_buildno; + char prod_name[esc_qvi_prod_name_max]; +} Esc_dmf_Qvi_OUT; + +typedef struct +{ + ULONG cbSize; + char* pDstBmBuf; + ULONG nDstBmBufSize; +} Esc_dmf_pointer_shape_get_IN; + +typedef struct +{ + ULONG cbSize; + POINTL BmSize; + char* pMaskBm; + ULONG nMaskBmSize; + char* pColorBm; + ULONG nColorBmSize; + char* pColorBmPal; + ULONG nColorBmPalEntries; +} Esc_dmf_pointer_shape_get_OUT; + +BOOL wf_mirror_driver_find_display_device(wfInfo* wfi); +BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode); +BOOL wf_mirror_driver_update(wfInfo* wfi, int mode); +BOOL wf_mirror_driver_map_memory(wfInfo* wfi); +BOOL wf_mirror_driver_cleanup(wfInfo* wfi); + +BOOL wf_mirror_driver_activate(wfInfo* wfi); +void wf_mirror_driver_deactivate(wfInfo* wfi); + +#endif /* WF_MIRAGE_H */ diff --git a/server/Windows/wf_peer.c b/server/Windows/wf_peer.c index e214a007d..c8cb3847f 100644 --- a/server/Windows/wf_peer.c +++ b/server/Windows/wf_peer.c @@ -1,339 +1,329 @@ -/** -* FreeRDP: A Remote Desktop Protocol Client -* FreeRDP Windows Server -* -* Copyright 2012 Marc-Andre Moreau -* Copyright 2012 Corey Clayton -* -* 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. -*/ +/** +* FreeRDP: A Remote Desktop Protocol Client +* FreeRDP Windows Server +* +* Copyright 2012 Marc-Andre Moreau +* Copyright 2012 Corey Clayton +* +* 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 +#include + +#include "wf_info.h" +#include "wf_input.h" +#include "wf_mirage.h" +#include "wf_update.h" +#include "wf_settings.h" +#include "wf_rdpsnd.h" + +#include "wf_peer.h" + +void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context) +{ + context->info = wf_info_get_instance(); + context->vcm = WTSOpenServerA((LPSTR) client->context); + wf_info_peer_register(context->info, context); +} + +void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context) +{ + wf_info_peer_unregister(context->info, context); + + if (context->rdpsnd) + { + wf_rdpsnd_lock(); + context->info->snd_stop = TRUE; + rdpsnd_server_context_free(context->rdpsnd); + wf_rdpsnd_unlock(); + } + + WTSCloseServer(context->vcm); +} + +void wf_peer_init(freerdp_peer* client) +{ + client->ContextSize = sizeof(wfPeerContext); + client->ContextNew = (psPeerContextNew) wf_peer_context_new; + client->ContextFree = (psPeerContextFree) wf_peer_context_free; -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif + freerdp_peer_context_new(client); +} + +BOOL wf_peer_post_connect(freerdp_peer* client) +{ + int i; + wfInfo* wfi; + rdpSettings* settings; + wfPeerContext* context = (wfPeerContext*) client->context; -#include -#include -#include - -#include -#include - -#include "wf_info.h" -#include "wf_input.h" -#include "wf_mirage.h" -#include "wf_update.h" -#include "wf_settings.h" -#include "wf_rdpsnd.h" - -#include "wf_peer.h" - -void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context) -{ - context->info = wf_info_get_instance(); - context->vcm = WTSOpenServerA((LPSTR) client->context); - wf_info_peer_register(context->info, context); -} - -void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context) -{ - wf_info_peer_unregister(context->info, context); - - if (context->rdpsnd) - { - wf_rdpsnd_lock(); - context->info->snd_stop = TRUE; - rdpsnd_server_context_free(context->rdpsnd); - wf_rdpsnd_unlock(); - } - - WTSCloseServer(context->vcm); -} - -void wf_peer_init(freerdp_peer* client) -{ - client->ContextSize = sizeof(wfPeerContext); - client->ContextNew = (psPeerContextNew) wf_peer_context_new; - client->ContextFree = (psPeerContextFree) wf_peer_context_free; - - freerdp_peer_context_new(client); -} - -BOOL wf_peer_post_connect(freerdp_peer* client) -{ - int i; - wfInfo* wfi; - rdpSettings* settings; - wfPeerContext* context = (wfPeerContext*) client->context; - - wfi = context->info; - settings = client->settings; - - if ((get_screen_info(wfi->screenID, NULL, &wfi->servscreen_width, &wfi->servscreen_height, &wfi->bitsPerPixel) == 0) || + wfi = context->info; + settings = client->settings; + + if ((get_screen_info(wfi->screenID, NULL, &wfi->servscreen_width, &wfi->servscreen_height, &wfi->bitsPerPixel) == 0) || (wfi->servscreen_width == 0) || (wfi->servscreen_height == 0) || (wfi->bitsPerPixel == 0) ) - { - _tprintf(_T("postconnect: error getting screen info for screen %d\n"), wfi->screenID); - _tprintf(_T("\t%dx%dx%d\n"), wfi->servscreen_height, wfi->servscreen_width, wfi->bitsPerPixel); - return FALSE; - } + { + WLog_ERR(TAG, "postconnect: error getting screen info for screen %d", wfi->screenID); + WLog_ERR(TAG, "\t%dx%dx%d", wfi->servscreen_height, wfi->servscreen_width, wfi->bitsPerPixel); + return FALSE; + } + + if ((settings->DesktopWidth != wfi->servscreen_width) || (settings->DesktopHeight != wfi->servscreen_height)) + { + /* + WLog_DBG(TAG, "Client requested resolution %dx%d, but will resize to %dx%d", + settings->DesktopWidth, settings->DesktopHeight, wfi->servscreen_width, wfi->servscreen_height); + */ - if ((settings->DesktopWidth != wfi->servscreen_width) || (settings->DesktopHeight != wfi->servscreen_height)) - { - /* - printf("Client requested resolution %dx%d, but will resize to %dx%d\n", - settings->DesktopWidth, settings->DesktopHeight, wfi->servscreen_width, wfi->servscreen_height); - */ + settings->DesktopWidth = wfi->servscreen_width; + settings->DesktopHeight = wfi->servscreen_height; + settings->ColorDepth = wfi->bitsPerPixel; - settings->DesktopWidth = wfi->servscreen_width; - settings->DesktopHeight = wfi->servscreen_height; - settings->ColorDepth = wfi->bitsPerPixel; + client->update->DesktopResize(client->update->context); + } + + if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) + { + wf_peer_rdpsnd_init(context); /* Audio Output */ + } + + return TRUE; +} + +BOOL wf_peer_activate(freerdp_peer* client) +{ + wfInfo* wfi; + wfPeerContext* context = (wfPeerContext*) client->context; - client->update->DesktopResize(client->update->context); - } + wfi = context->info; + client->activated = TRUE; + wf_update_peer_activate(wfi, context); - if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) - { - wf_peer_rdpsnd_init(context); /* Audio Output */ - } + wfreerdp_server_peer_callback_event(((rdpContext*) context)->peer->pId, WF_SRV_CALLBACK_EVENT_ACTIVATE); - return TRUE; -} + return TRUE; +} + +BOOL wf_peer_logon(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic) +{ + wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH); + return TRUE; +} + +void wf_peer_synchronize_event(rdpInput* input, UINT32 flags) +{ -BOOL wf_peer_activate(freerdp_peer* client) -{ - wfInfo* wfi; - wfPeerContext* context = (wfPeerContext*) client->context; +} + +void wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + CreateThread(NULL, 0, wf_peer_main_loop, client, 0, NULL); +} + +DWORD WINAPI wf_peer_socket_listener(LPVOID lpParam) +{ + int i, fds; + int rcount; + int max_fds; + void* rfds[32]; + fd_set rfds_set; + wfPeerContext* context; + freerdp_peer* client = (freerdp_peer*) lpParam; - wfi = context->info; - client->activated = TRUE; - wf_update_peer_activate(wfi, context); + ZeroMemory(rfds, sizeof(rfds)); + context = (wfPeerContext*) client->context; + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) + { + WLog_ERR(TAG, "Failed to get peer file descriptor"); + break; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + select(max_fds + 1, &rfds_set, NULL, NULL, NULL); - wfreerdp_server_peer_callback_event(((rdpContext*) context)->peer->pId, WF_SRV_CALLBACK_EVENT_ACTIVATE); + SetEvent(context->socketEvent); + WaitForSingleObject(context->socketSemaphore, INFINITE); + + if (context->socketClose) + break; + } + + return 0; +} + +void wf_peer_read_settings(freerdp_peer* client) +{ + if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("CertificateFile"), &(client->settings->CertificateFile))) + client->settings->CertificateFile = _strdup("server.crt"); + + if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("PrivateKeyFile"), &(client->settings->PrivateKeyFile))) + client->settings->PrivateKeyFile = _strdup("server.key"); +} + +DWORD WINAPI wf_peer_main_loop(LPVOID lpParam) +{ + wfInfo* wfi; + DWORD nCount; + DWORD status; + HANDLE handles[32]; + rdpSettings* settings; + wfPeerContext* context; + freerdp_peer* client = (freerdp_peer*) lpParam; + + if (!getenv("HOME")) + { + char home[MAX_PATH * 2] = "HOME="; + strcat(home, getenv("HOMEDRIVE")); + strcat(home, getenv("HOMEPATH")); + _putenv(home); + } + + wf_peer_init(client); - return TRUE; -} + settings = client->settings; + settings->RemoteFxCodec = TRUE; + settings->ColorDepth = 32; + settings->NSCodec = FALSE; + settings->JpegCodec = FALSE; + wf_peer_read_settings(client); -BOOL wf_peer_logon(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic) -{ - /* - if (automatic) - { - _tprintf(_T("Logon: User:%s Domain:%s Password:%s\n"), - identity->User, identity->Domain, identity->Password); - } - */ + client->PostConnect = wf_peer_post_connect; + client->Activate = wf_peer_activate; + client->Logon = wf_peer_logon; - wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH); - return TRUE; -} + client->input->SynchronizeEvent = wf_peer_synchronize_event; + client->input->KeyboardEvent = wf_peer_keyboard_event; + client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event; + client->input->MouseEvent = wf_peer_mouse_event; + client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event; -void wf_peer_synchronize_event(rdpInput* input, UINT32 flags) -{ - -} - -void wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) -{ - CreateThread(NULL, 0, wf_peer_main_loop, client, 0, NULL); -} - -DWORD WINAPI wf_peer_socket_listener(LPVOID lpParam) -{ - int i, fds; - int rcount; - int max_fds; - void* rfds[32]; - fd_set rfds_set; - wfPeerContext* context; - freerdp_peer* client = (freerdp_peer*) lpParam; - - ZeroMemory(rfds, sizeof(rfds)); - context = (wfPeerContext*) client->context; - - while (1) - { - rcount = 0; - - if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) - { - //printf("Failed to get peer file descriptor\n"); - break; - } - - max_fds = 0; - FD_ZERO(&rfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - select(max_fds + 1, &rfds_set, NULL, NULL, NULL); - - SetEvent(context->socketEvent); - WaitForSingleObject(context->socketSemaphore, INFINITE); - - if (context->socketClose) - break; - } - - return 0; -} - -void wf_peer_read_settings(freerdp_peer* client) -{ - if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("CertificateFile"), &(client->settings->CertificateFile))) - client->settings->CertificateFile = _strdup("server.crt"); - - if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("PrivateKeyFile"), &(client->settings->PrivateKeyFile))) - client->settings->PrivateKeyFile = _strdup("server.key"); -} - -DWORD WINAPI wf_peer_main_loop(LPVOID lpParam) -{ - wfInfo* wfi; - DWORD nCount; - DWORD status; - HANDLE handles[32]; - rdpSettings* settings; - wfPeerContext* context; - freerdp_peer* client = (freerdp_peer*) lpParam; - - if (!getenv("HOME")) - { - char home[MAX_PATH * 2] = "HOME="; - strcat(home, getenv("HOMEDRIVE")); - strcat(home, getenv("HOMEPATH")); - _putenv(home); - } - - wf_peer_init(client); - - settings = client->settings; - settings->RemoteFxCodec = TRUE; - settings->ColorDepth = 32; - settings->NSCodec = FALSE; - settings->JpegCodec = FALSE; - wf_peer_read_settings(client); - - client->PostConnect = wf_peer_post_connect; - client->Activate = wf_peer_activate; - client->Logon = wf_peer_logon; - - client->input->SynchronizeEvent = wf_peer_synchronize_event; - client->input->KeyboardEvent = wf_peer_keyboard_event; - client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event; - client->input->MouseEvent = wf_peer_mouse_event; - client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event; - - client->Initialize(client); - context = (wfPeerContext*) client->context; - - if (context->socketClose) - return 0; - - wfi = context->info; - - if (wfi->input_disabled) - { - printf("client input is disabled\n"); - client->input->KeyboardEvent = wf_peer_keyboard_event_dummy; - client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event_dummy; - client->input->MouseEvent = wf_peer_mouse_event_dummy; - client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event_dummy; - } - - context->socketEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + client->Initialize(client); + context = (wfPeerContext*) client->context; + + if (context->socketClose) + return 0; + + wfi = context->info; + + if (wfi->input_disabled) + { + WLog_INFO(TAG, "client input is disabled"); + client->input->KeyboardEvent = wf_peer_keyboard_event_dummy; + client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event_dummy; + client->input->MouseEvent = wf_peer_mouse_event_dummy; + client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event_dummy; + } + + context->socketEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - context->socketSemaphore = CreateSemaphore(NULL, 0, 1, NULL); - context->socketThread = CreateThread(NULL, 0, wf_peer_socket_listener, client, 0, NULL); + context->socketSemaphore = CreateSemaphore(NULL, 0, 1, NULL); + context->socketThread = CreateThread(NULL, 0, wf_peer_socket_listener, client, 0, NULL); + WLog_INFO(TAG, "We've got a client %s", client->local ? "(local)" : client->hostname); + nCount = 0; + handles[nCount++] = context->updateEvent; + handles[nCount++] = context->socketEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); + + if ((status == WAIT_FAILED) || (status == WAIT_TIMEOUT)) + { + WLog_ERR(TAG, "WaitForMultipleObjects failed"); + break; + } + + if (WaitForSingleObject(context->updateEvent, 0) == 0) + { + if (client->activated) + wf_update_peer_send(wfi, context); + + ResetEvent(context->updateEvent); + ReleaseSemaphore(wfi->updateSemaphore, 1, NULL); + } + + if (WaitForSingleObject(context->socketEvent, 0) == 0) + { + if (client->CheckFileDescriptor(client) != TRUE) + { + WLog_ERR(TAG, "Failed to check peer file descriptor"); + context->socketClose = TRUE; + } + + ResetEvent(context->socketEvent); + ReleaseSemaphore(context->socketSemaphore, 1, NULL); + + if (context->socketClose) + break; + } + + //force disconnect + if (wfi->force_all_disconnect == TRUE) + { + WLog_INFO(TAG, "Forcing Disconnect -> "); + break; + } + + /* FIXME: we should wait on this, instead of calling it every time */ + if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) + break; + } + + WLog_INFO(TAG, "Client %s disconnected.", client->local ? "(local)" : client->hostname); + + if (WaitForSingleObject(context->updateEvent, 0) == 0) + { + ResetEvent(context->updateEvent); + ReleaseSemaphore(wfi->updateSemaphore, 1, NULL); + } + + wf_update_peer_deactivate(wfi, context); - printf("We've got a client %s\n", client->local ? "(local)" : client->hostname); + client->Disconnect(client); - nCount = 0; - handles[nCount++] = context->updateEvent; - handles[nCount++] = context->socketEvent; + freerdp_peer_context_free(client); + freerdp_peer_free(client); - while (1) - { - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - - if ((status == WAIT_FAILED) || (status == WAIT_TIMEOUT)) - { - printf("WaitForMultipleObjects failed\n"); - break; - } - - if (WaitForSingleObject(context->updateEvent, 0) == 0) - { - if (client->activated) - wf_update_peer_send(wfi, context); - - ResetEvent(context->updateEvent); - ReleaseSemaphore(wfi->updateSemaphore, 1, NULL); - } - - if (WaitForSingleObject(context->socketEvent, 0) == 0) - { - if (client->CheckFileDescriptor(client) != TRUE) - { - //printf("Failed to check peer file descriptor\n"); - context->socketClose = TRUE; - } - - ResetEvent(context->socketEvent); - ReleaseSemaphore(context->socketSemaphore, 1, NULL); - - if (context->socketClose) - break; - } - - //force disconnect - if (wfi->force_all_disconnect == TRUE) - { - printf("Forcing Disconnect -> "); - break; - } - - /* FIXME: we should wait on this, instead of calling it every time */ - if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) - break; - } - - printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname); - - if (WaitForSingleObject(context->updateEvent, 0) == 0) - { - ResetEvent(context->updateEvent); - ReleaseSemaphore(wfi->updateSemaphore, 1, NULL); - } - - wf_update_peer_deactivate(wfi, context); - - client->Disconnect(client); - - freerdp_peer_context_free(client); - freerdp_peer_free(client); - - return 0; -} + return 0; +} diff --git a/server/Windows/wf_peer.h b/server/Windows/wf_peer.h index a825b9652..7d96d9146 100644 --- a/server/Windows/wf_peer.h +++ b/server/Windows/wf_peer.h @@ -1,51 +1,51 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Windows Server - * - * Copyright 2012 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 WF_PEER_H -#define WF_PEER_H - -#include "wf_interface.h" - -#include - - - -void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context); -void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context); - -void wf_peer_init(freerdp_peer* client); - -void wf_dxgi_encode(freerdp_peer* client, UINT timeout); -void wf_rfx_encode(freerdp_peer* client); - -BOOL wf_peer_post_connect(freerdp_peer* client); -BOOL wf_peer_activate(freerdp_peer* client); - -void wf_peer_synchronize_event(rdpInput* input, UINT32 flags); - -void wf_peer_send_changes(freerdp_peer* client); - -void wf_detect_win_ver(void); - -void wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); - -DWORD WINAPI wf_peer_main_loop(LPVOID lpParam); - - -#endif /* WF_PEER_H */ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Windows Server + * + * Copyright 2012 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 WF_PEER_H +#define WF_PEER_H + +#include "wf_interface.h" + +#include + + + +void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context); +void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context); + +void wf_peer_init(freerdp_peer* client); + +void wf_dxgi_encode(freerdp_peer* client, UINT timeout); +void wf_rfx_encode(freerdp_peer* client); + +BOOL wf_peer_post_connect(freerdp_peer* client); +BOOL wf_peer_activate(freerdp_peer* client); + +void wf_peer_synchronize_event(rdpInput* input, UINT32 flags); + +void wf_peer_send_changes(freerdp_peer* client); + +void wf_detect_win_ver(void); + +void wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); + +DWORD WINAPI wf_peer_main_loop(LPVOID lpParam); + + +#endif /* WF_PEER_H */ diff --git a/server/Windows/wf_rdpsnd.c b/server/Windows/wf_rdpsnd.c index 0a4362d43..d9d7f465a 100644 --- a/server/Windows/wf_rdpsnd.c +++ b/server/Windows/wf_rdpsnd.c @@ -54,8 +54,9 @@ static void wf_peer_rdpsnd_activated(RdpsndServerContext* context) wfi = wf_info_get_instance(); wfi->agreed_format = NULL; - printf("Client supports the following %d formats: \n", context->num_client_formats); - for(i = 0; i < context->num_client_formats; i++) + WLog_DBG(TAG, "Client supports the following %d formats:", context->num_client_formats); + + for (i = 0; i < context->num_client_formats; i++) { //TODO: improve the way we agree on a format for (j = 0; j < context->num_server_formats; j++) @@ -64,7 +65,7 @@ static void wf_peer_rdpsnd_activated(RdpsndServerContext* context) (context->client_formats[i].nChannels == context->server_formats[j].nChannels) && (context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec)) { - printf("agreed on format!\n"); + WLog_DBG(TAG, "agreed on format!"); wfi->agreed_format = (AUDIO_FORMAT*) &context->server_formats[j]; break; } @@ -76,7 +77,7 @@ static void wf_peer_rdpsnd_activated(RdpsndServerContext* context) if (wfi->agreed_format == NULL) { - printf("Could not agree on a audio format with the server\n"); + WLog_ERR(TAG, "Could not agree on a audio format with the server"); return; } @@ -116,7 +117,7 @@ int wf_rdpsnd_lock() break; case WAIT_FAILED: - printf("wf_rdpsnd_lock failed with 0x%08X\n", GetLastError()); + WLog_ERR(TAG, "wf_rdpsnd_lock failed with 0x%08X", GetLastError()); return -1; break; } @@ -132,7 +133,7 @@ int wf_rdpsnd_unlock() if (ReleaseMutex(wfi->snd_mutex) == 0) { - printf("wf_rdpsnd_unlock failed with 0x%08X\n", GetLastError()); + WLog_DBG(TAG, "wf_rdpsnd_unlock failed with 0x%08X", GetLastError()); return -1; } @@ -160,7 +161,7 @@ BOOL wf_peer_rdpsnd_init(wfPeerContext* context) context->rdpsnd->Activated = wf_peer_rdpsnd_activated; - context->rdpsnd->Initialize(context->rdpsnd); + context->rdpsnd->Initialize(context->rdpsnd, TRUE); wf_rdpsnd_set_latest_peer(context); diff --git a/server/Windows/wf_update.c b/server/Windows/wf_update.c index a8488557f..0c7991773 100644 --- a/server/Windows/wf_update.c +++ b/server/Windows/wf_update.c @@ -62,8 +62,7 @@ DWORD WINAPI wf_update_thread(LPVOID lpParam) if (wf_info_have_updates(wfi)) { wf_update_encode(wfi); - - //printf("Start of parallel sending\n"); + //WLog_DBG(TAG, "Start of parallel sending"); index = 0; for (peerindex = 0; peerindex < wfi->peerCount; peerindex++) { @@ -71,7 +70,7 @@ DWORD WINAPI wf_update_thread(LPVOID lpParam) { if (wfi->peers[index] && wfi->peers[index]->activated) { - //printf("Setting event for %d of %d\n", index + 1, wfi->activePeerCount); + //WLog_DBG(TAG, "Setting event for %d of %d", index + 1, wfi->activePeerCount); SetEvent(((wfPeerContext*) wfi->peers[index]->context)->updateEvent); } } @@ -80,13 +79,12 @@ DWORD WINAPI wf_update_thread(LPVOID lpParam) for (index = 0; index < wfi->activePeerCount; index++) { - //printf("Waiting for %d of %d\n", index + 1, wfi->activePeerCount); + //WLog_DBG(TAG, "Waiting for %d of %d", index + 1, wfi->activePeerCount); //WaitForSingleObject(wfi->updateSemaphore, INFINITE); WaitForSingleObject(wfi->updateSemaphore, 1000); } - //printf("End of parallel sending\n"); - + //WLog_DBG(TAG, "End of parallel sending"); wf_info_clear_invalid_region(wfi); } } @@ -103,8 +101,7 @@ DWORD WINAPI wf_update_thread(LPVOID lpParam) } } - //printf("Exiting Update Thread\n"); - + //WLog_DBG(TAG, "Exiting Update Thread"); return 0; } @@ -129,9 +126,7 @@ void wf_update_encode(wfInfo* wfi) rect.y = 0; rect.width = (UINT16) width; rect.height = (UINT16) height; - - //printf("x:%d y:%d w:%d h:%d\n", wfi->invalid.left, wfi->invalid.top, width, height); - + //WLog_DBG(TAG, "x:%d y:%d w:%d h:%d", wfi->invalid.left, wfi->invalid.top, width, height); Stream_Clear(wfi->s); rfx_compose_message(wfi->rfx_context, wfi->s, &rect, 1, @@ -175,9 +170,8 @@ void wf_update_peer_send(wfInfo* wfi, wfPeerContext* context) return; /* This is an unexpected error condition */ - - printf("Unexpected Frame Index: Actual: %d Expected: %d\n", - wfi->frame_idx, context->frame_idx + 1); + WLog_DBG(TAG, "Unexpected Frame Index: Actual: %d Expected: %d", + wfi->frame_idx, context->frame_idx + 1); } wfi->cmd.codecID = client->settings->RemoteFxCodecId; @@ -189,7 +183,7 @@ void wf_update_encoder_reset(wfInfo* wfi) { if (wf_info_lock(wfi) > 0) { - printf("Resetting encoder\n"); + WLog_DBG(TAG, "Resetting encoder"); if (wfi->rfx_context) { @@ -217,7 +211,7 @@ void wf_update_peer_activate(wfInfo* wfi, wfPeerContext* context) { if (wfi->activePeerCount < 1) { -#ifndef WITH_WIN8 +#ifndef WITH_DXGI_1_2 wf_mirror_driver_activate(wfi); #endif ResumeThread(wfi->updateThread); @@ -225,9 +219,7 @@ void wf_update_peer_activate(wfInfo* wfi, wfPeerContext* context) wf_update_encoder_reset(wfi); wfi->activePeerCount++; - - printf("Activating Peer Updates: %d\n", wfi->activePeerCount); - + WLog_DBG(TAG, "Activating Peer Updates: %d", wfi->activePeerCount); wf_info_unlock(wfi); } } @@ -247,8 +239,7 @@ void wf_update_peer_deactivate(wfInfo* wfi, wfPeerContext* context) client->activated = FALSE; wfi->activePeerCount--; - - printf("Deactivating Peer Updates: %d\n", wfi->activePeerCount); + WLog_DBG(TAG, "Deactivating Peer Updates: %d", wfi->activePeerCount); } wf_info_unlock(wfi); diff --git a/server/Windows/wf_wasapi.c b/server/Windows/wf_wasapi.c index 722ac71f8..58275fd34 100644 --- a/server/Windows/wf_wasapi.c +++ b/server/Windows/wf_wasapi.c @@ -41,12 +41,11 @@ int wf_wasapi_activate(RdpsndServerContext* context) if (devStr == NULL) { - _tprintf(_T("Failed to match for output device! Disabling rdpsnd.\n")); + WLog_ERR(TAG, "Failed to match for output device! Disabling rdpsnd."); return 1; } - printf("RDPSND (WASAPI) Activated\n"); - + WLog_DBG(TAG, "RDPSND (WASAPI) Activated"); CreateThread(NULL, 0, wf_rdpsnd_wasapi_thread, latestPeer, 0, NULL); return 0; @@ -66,23 +65,23 @@ int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **) &pEnumerator); if (FAILED(hr)) { - _tprintf(_T("Failed to cocreate device enumerator\n")); + WLog_ERR(TAG, "Failed to cocreate device enumerator"); exit(1); } hr = pEnumerator->lpVtbl->EnumAudioEndpoints(pEnumerator, eCapture, DEVICE_STATE_ACTIVE, &pCollection); if ( FAILED(hr) ) { - _tprintf(_T("Failed to create endpoint collection\n")); + WLog_ERR(TAG, "Failed to create endpoint collection"); exit(1); } pCollection->lpVtbl->GetCount(pCollection, &count); - _tprintf(_T("Num endpoints: %d\n"), count); + WLog_INFO(TAG, "Num endpoints: %d", count); if (count == 0) { - _tprintf(_T("No endpoints!\n")); + WLog_ERR(TAG, "No endpoints!"); exit(1); } @@ -94,28 +93,28 @@ int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr) hr = pCollection->lpVtbl->Item(pCollection, i, &pEndpoint); if ( FAILED(hr) ) { - _tprintf(_T("Failed to get endpoint %d\n"), i); + WLog_ERR(TAG, "Failed to get endpoint %d", i); exit(1); } hr = pEndpoint->lpVtbl->GetId(pEndpoint, &pwszID); if ( FAILED(hr) ) { - _tprintf(_T("Failed to get endpoint ID\n")); + WLog_ERR(TAG, "Failed to get endpoint ID"); exit(1); } hr = pEndpoint->lpVtbl->OpenPropertyStore(pEndpoint, STGM_READ, &pProps); if ( FAILED(hr) ) { - _tprintf(_T("Failed to open property store\n")); + WLog_ERR(TAG, "Failed to open property store"); exit(1); } hr = pProps->lpVtbl->GetValue(pProps, &PKEY_Device_FriendlyName, &nameVar); if ( FAILED(hr) ) { - _tprintf(_T("Failed to get device friendly name\n")); + WLog_ERR(TAG, "Failed to get device friendly name"); exit(1); } @@ -123,9 +122,8 @@ int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr) if (wcscmp(pattern, nameVar.pwszVal) < 0) { unsigned int devStrLen; - _tprintf(_T("Using sound ouput endpoint: [%s] (%s)\n"), nameVar.pwszVal, pwszID); - //_tprintf(_T("matched %d characters\n"), wcscmp(pattern, nameVar.pwszVal)); - + WLog_INFO(TAG, "Using sound ouput endpoint: [%s] (%s)", nameVar.pwszVal, pwszID); + //WLog_INFO(TAG, "matched %d characters", wcscmp(pattern, nameVar.pwszVal); devStrLen = wcslen(pwszID); *deviceStr = (LPWSTR) malloc((devStrLen * 2) + 2); ZeroMemory(*deviceStr, (devStrLen * 2) + 2); @@ -179,28 +177,28 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **) &pEnumerator); if (FAILED(hr)) { - _tprintf(_T("Failed to cocreate device enumerator\n")); + WLog_ERR(TAG, "Failed to cocreate device enumerator"); exit(1); } hr = pEnumerator->lpVtbl->GetDevice(pEnumerator, devStr, &pDevice); if (FAILED(hr)) { - _tprintf(_T("Failed to cocreate get device\n")); + WLog_ERR(TAG, "Failed to cocreate get device"); exit(1); } hr = pDevice->lpVtbl->Activate(pDevice, &IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&pAudioClient); if (FAILED(hr)) { - _tprintf(_T("Failed to activate audio client\n")); + WLog_ERR(TAG, "Failed to activate audio client"); exit(1); } hr = pAudioClient->lpVtbl->GetMixFormat(pAudioClient, &pwfx); if (FAILED(hr)) { - _tprintf(_T("Failed to get mix format\n")); + WLog_ERR(TAG, "Failed to get mix format"); exit(1); } @@ -218,21 +216,21 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) if (FAILED(hr)) { - _tprintf(_T("Failed to initialize the audio client\n")); + WLog_ERR(TAG, "Failed to initialize the audio client"); exit(1); } hr = pAudioClient->lpVtbl->GetBufferSize(pAudioClient, &bufferFrameCount); if (FAILED(hr)) { - _tprintf(_T("Failed to get buffer size\n")); + WLog_ERR(TAG, "Failed to get buffer size"); exit(1); } hr = pAudioClient->lpVtbl->GetService(pAudioClient, &IID_IAudioCaptureClient, (void **) &pCaptureClient); if (FAILED(hr)) { - _tprintf(_T("Failed to get the capture client\n")); + WLog_ERR(TAG, "Failed to get the capture client"); exit(1); } @@ -241,12 +239,13 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) hr = pAudioClient->lpVtbl->Start(pAudioClient); if (FAILED(hr)) { - _tprintf(_T("Failed to start capture\n")); + WLog_ERR(TAG, "Failed to start capture"); exit(1); } dCount = 0; - while(wfi->snd_stop == FALSE) + + while (wfi->snd_stop == FALSE) { DWORD flags; @@ -255,7 +254,7 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength); if (FAILED(hr)) { - _tprintf(_T("Failed to get packet length\n")); + WLog_ERR(TAG, "Failed to get packet length"); exit(1); } @@ -264,7 +263,7 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) hr = pCaptureClient->lpVtbl->GetBuffer(pCaptureClient, &pData, &numFramesAvailable, &flags, NULL, NULL); if (FAILED(hr)) { - _tprintf(_T("Failed to get buffer\n")); + WLog_ERR(TAG, "Failed to get buffer"); exit(1); } @@ -276,14 +275,14 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) hr = pCaptureClient->lpVtbl->ReleaseBuffer(pCaptureClient, numFramesAvailable); if (FAILED(hr)) { - _tprintf(_T("Failed to release buffer\n")); + WLog_ERR(TAG, "Failed to release buffer"); exit(1); } hr = pCaptureClient->lpVtbl->GetNextPacketSize(pCaptureClient, &packetLength); if (FAILED(hr)) { - _tprintf(_T("Failed to get packet length\n")); + WLog_ERR(TAG, "Failed to get packet length"); exit(1); } } @@ -292,7 +291,7 @@ DWORD WINAPI wf_rdpsnd_wasapi_thread(LPVOID lpParam) pAudioClient->lpVtbl->Stop(pAudioClient); if (FAILED(hr)) { - _tprintf(_T("Failed to stop audio client\n")); + WLog_ERR(TAG, "Failed to stop audio client"); exit(1); } diff --git a/server/X11/CMakeLists.txt b/server/X11/CMakeLists.txt deleted file mode 100644 index 2af6f8f2e..000000000 --- a/server/X11/CMakeLists.txt +++ /dev/null @@ -1,167 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# FreeRDP X11 Server cmake build script -# -# Copyright 2012 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. - -set(MODULE_NAME "xfreerdp-server") -set(MODULE_PREFIX "FREERDP_SERVER_X11_CONTROL") - -include_directories(${X11_INCLUDE_DIRS}) -include_directories("../../winpr/tools/makecert") - -set(${MODULE_PREFIX}_SRCS - xf_peer.c - xf_peer.h - xf_input.c - xf_input.h - xf_encode.c - xf_encode.h - xf_update.c - xf_update.h - xf_cursor.c - xf_cursor.h - xf_monitors.c - xf_monitors.h - xf_interface.c - xf_interface.h - xfreerdp.h) - -if(WITH_SERVER_INTERFACE) - if(SERVER_INTERFACE_SHARED) - add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) - else() - add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - endif() - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") -else() - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/xfreerdp.c) - add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "xfreerdp-server") -endif() - -set(XEXT_FEATURE_TYPE "RECOMMENDED") -set(XEXT_FEATURE_PURPOSE "X11 extension") -set(XEXT_FEATURE_DESCRIPTION "X11 core extensions") - -set(XSHM_FEATURE_TYPE "RECOMMENDED") -set(XSHM_FEATURE_PURPOSE "X11 shared memory") -set(XSHM_FEATURE_DESCRIPTION "X11 shared memory extension") - -set(XINERAMA_FEATURE_TYPE "RECOMMENDED") -set(XINERAMA_FEATURE_PURPOSE "multi-monitor") -set(XINERAMA_FEATURE_DESCRIPTION "X11 multi-monitor extension") - -set(XTEST_FEATURE_TYPE "RECOMMENDED") -set(XTEST_FEATURE_PURPOSE "X11 input event injection") -set(XTEST_FEATURE_DESCRIPTION "X11 input event injection extension") - -set(XCURSOR_FEATURE_TYPE "RECOMMENDED") -set(XCURSOR_FEATURE_PURPOSE "cursor") -set(XCURSOR_FEATURE_DESCRIPTION "X11 cursor extension") - -set(XFIXES_FEATURE_TYPE "RECOMMENDED") -set(XFIXES_FEATURE_PURPOSE "X11 region") -set(XFIXES_FEATURE_DESCRIPTION "X11 region fix extension") - -set(XRANDR_FEATURE_TYPE "RECOMMENDED") -set(XRANDR_FEATURE_PURPOSE "X11 resize, rotate and reflect") -set(XRANDR_FEATURE_DESCRIPTION "X11 resize, rotate and reflect extension") - -set(XDAMAGE_FEATURE_TYPE "RECOMMENDED") -set(XDAMAGE_FEATURE_PURPOSE "X11 region damage") -set(XDAMAGE_FEATURE_DESCRIPTION "X11 region damage extension") - -find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION}) -find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION}) -find_feature(XTest ${XTEST_FEATURE_TYPE} ${XTEST_FEATURE_PURPOSE} ${XTEST_FEATURE_DESCRIPTION}) -find_feature(Xfixes ${XFIXES_FEATURE_TYPE} ${XFIXES_FEATURE_PURPOSE} ${XFIXES_FEATURE_DESCRIPTION}) -find_feature(XRandR ${XRANDR_FEATURE_TYPE} ${XRANDR_FEATURE_PURPOSE} ${XRANDR_FEATURE_DESCRIPTION}) -find_feature(Xdamage ${XDAMAGE_FEATURE_TYPE} ${XDAMAGE_FEATURE_PURPOSE} ${XDAMAGE_FEATURE_DESCRIPTION}) -find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSOR_FEATURE_DESCRIPTION}) -find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION}) - -if(WITH_XSHM) - add_definitions(-DWITH_XSHM) - include_directories(${XSHM_INCLUDE_DIRS}) -endif() - -if(WITH_XEXT) - add_definitions(-DWITH_XEXT) - include_directories(${XEXT_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XEXT_LIBRARIES}) -endif() - -if(WITH_XINERAMA) - add_definitions(-DWITH_XINERAMA) - include_directories(${XINERAMA_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XINERAMA_LIBRARIES}) -endif() - -if(WITH_XCURSOR) - add_definitions(-DWITH_XCURSOR) - include_directories(${XCURSOR_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XCURSOR_LIBRARIES}) -endif() - -if(WITH_XDAMAGE) - add_definitions(-DWITH_XDAMAGE) - include_directories(${XDAMAGE_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XDAMAGE_LIBRARIES}) -endif() - -if(WITH_XFIXES) - add_definitions(-DWITH_XFIXES) - include_directories(${XFIXES_INCLUDE_DIRS}) - target_link_libraries(${MODULE_NAME} ${XFIXES_LIBRARIES}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XFIXES_LIBRARIES}) -endif() - -if(WITH_XTEST) - add_definitions(-DWITH_XTEST) - include_directories(${XTEST_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XTEST_LIBRARIES}) -endif() - -if(WITH_XRANDR) - add_definitions(-DWITH_XRANDR) - include_directories(${XRANDR_INCLUDE_DIRS}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRANDR_LIBRARIES}) -endif() - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${X11_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE freerdp - MODULES freerdp-core freerdp-common freerdp-codec freerdp-primitives freerdp-utils freerdp-gdi freerdp-crypto freerdp-locale) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sspi winpr-crt winpr-utils winpr-input winpr-sysinfo) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr-makecert-tool) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -if(WITH_SERVER_INTERFACE) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) - add_subdirectory(cli) -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/X11") - diff --git a/server/X11/ModuleOptions.cmake b/server/X11/ModuleOptions.cmake deleted file mode 100644 index fcba05934..000000000 --- a/server/X11/ModuleOptions.cmake +++ /dev/null @@ -1,4 +0,0 @@ - -set(FREERDP_SERVER_NAME "xfreerdp-server") -set(FREERDP_SERVER_PLATFORM "X11") -set(FREERDP_SERVER_VENDOR "FreeRDP") diff --git a/server/X11/rfx_test.pcap b/server/X11/rfx_test.pcap deleted file mode 100644 index 768c3960f..000000000 Binary files a/server/X11/rfx_test.pcap and /dev/null differ diff --git a/server/X11/server.crt b/server/X11/server.crt deleted file mode 100644 index 7ce931c26..000000000 --- a/server/X11/server.crt +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICyzCCAbOgAwIBAgIJANbqtAWwlQZuMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV -BAMTB0ZyZWVSRFAwHhcNMDkxMDI5MDA0MTQ5WhcNMDkxMTI4MDA0MTQ5WjASMRAw -DgYDVQQDEwdGcmVlUkRQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -q7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1TptzXTcmfDrDslTGwcEY -hTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2SXvTiaV26VPPxddGb -o6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJLd2SU4ItWHj8zjz1f -eGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsjgvz4yP7I3TL8+GsN -MjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdymrulJSIhoOVfKkwi -ptTe43FgwxVRIygJP9HjHQIDAQABoyQwIjATBgNVHSUEDDAKBggrBgEFBQcDATAL -BgNVHQ8EBAMCBDAwDQYJKoZIhvcNAQEFBQADggEBAIOdEDhOX2kbl02znltd9hCr -nV4kRPKm979RKwBNkrEuwYSlcsjAHg5MZ5itH3wFOUo2s5pjt7/vMOAg+6rOBbIa -nqr22/gKBtOmuaJLG1yjxDC2vfez7f3B26pKgxa/krM8oxiFdT9n8QbdxdkN7/D9 -3RLU/aCfgrMzXxRus7eq3kR00jnSs6ggnAfE1E9gric3vFgr1wCzdcriRXmXDfUb -hRq+4VG+ZWk16TwCofV5GVU39XWCv5HNO2swAdjkNXgI5e3tQbV3wWLZLqqYzBco -iWulAXtoCGmE81+u1Ms7hLLzpXitLZSGPu1r+sDdkKPLCmOvkAaljDQ4nBz7fIA= ------END CERTIFICATE----- diff --git a/server/X11/server.key b/server/X11/server.key deleted file mode 100644 index 5c2f2c803..000000000 --- a/server/X11/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAq7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1Tptz -XTcmfDrDslTGwcEYhTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2S -XvTiaV26VPPxddGbo6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJL -d2SU4ItWHj8zjz1feGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsj -gvz4yP7I3TL8+GsNMjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdy -mrulJSIhoOVfKkwiptTe43FgwxVRIygJP9HjHQIDAQABAoIBAAVv5K54xtc1JtBR -1lfdPbSqDlnjx8aOnVIPg5TnqMp3sR8jBt0NsPc/+RA9ZOmfjoIxFAEJaZ9zSDJC -5BqmnxC5R1mfCQkSd2haQ+4pdFvWyrv4Bblh8YU6hXrJGn0LfO0KlIcywtAvKpsi -LtTyZkWmaW2HeF/+pO32jYygw38R1wd8Tl6GwjOXwTF6lFACJXOT4YAzcfp3FKSB -AiKBIGuMzozoSND7KPFNRrhGhNumJpdS5A8Fb8D2c/ZMv6Cq5IbwOgTfKun+Bz+s -mFbnzeb1uWRqQbsVXOBBW/zHfuG3SU5qeZsaAyuu4DTy+LE1oAHF9uhBSHuT5C6i -vCJ8A8ECgYEA1iaOmiEJYBrs25iAc4SjCKqhY0mwR3wtu3I06vmgUoML5fhPMv36 -SvYQIqDyNw3p7TE6mZtw9+G+kK3PqhuJhogwSwg0a6o51RdKnhXH3/68oNWtKCLC -1AmR8q/Gd3FwAR3b49CuOIZ9uOiJrc/ejzKdFEJTDR1/TX1frWfZznECgYEAzUiz -XxFf7YrGel7JgmfRD2eZRYngOoteFlg5Tee42UjeAY2Pt2aiDLk+2TqQEdI9+Xg7 -LcFdBqcSNd8bh33xSzgNthIkX+lTDzx0SmKGfyxfFBJcY8nzsLvvnNt3YeuMeaJQ -CPszwoZ0jcD46jTCjbrKhaLyEWmUkDp1O71NTW0CgYAXKF49Xpsz8FVyvcAOPeaf -dkwzf3F3mX8ciRId4taqdY9g1AREgGCDoK5IAF2RBIkqZCtxFvUVaS0BWjpdq9Ko -YKvQQVfh2KueVoF0LOjLWTGutsydzXyCD3Lf6pAstHCnPkJcFWHxrOGFkGfrCtKH -a7K+0RlIDsuIZqllCBjukQKBgA31+MTpYJW+D1t5IMkumEgs6n6RLt+sZLyuSU9k -B+03CGogn3qAj1rAKmcJlYywuKhDpfqpoNL3/8QMJUokpYlRCZWtTC39pzltCheY -9b6mXNz3lrLupBUL4vLO9iKBq28GO90wgEelbz3ItuTuq6CJ6IYIG+BVRtY8M4bZ -i+1NAoGANXZjYnJYDnh8Je9SDxDSc5byzK7ddkQoId64RCIfNHqNKH63P81vjgnH -YBIPtagY75ZVVNxujCF7m8Rety+d8tEFwfQKDin2EVI7PD2rOJra385/izp7HuBR -vqxvLzG9Xv3cNOU2l7PttVw4Pa2i5E37atKi3V3Zp2kMW+KaKPQ= ------END RSA PRIVATE KEY----- diff --git a/server/X11/xf_cursor.c b/server/X11/xf_cursor.c deleted file mode 100644 index 00e4abb3c..000000000 --- a/server/X11/xf_cursor.c +++ /dev/null @@ -1,57 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Cursor - * - * Copyright 2013 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 - -#ifdef WITH_XCURSOR -#include -#endif - -#ifdef WITH_XFIXES -#include -#endif - -#include - -#include "xf_cursor.h" - -int xf_cursor_init(xfInfo* xfi) -{ -#ifdef WITH_XFIXES - int event; - int error; - - if (!XFixesQueryExtension(xfi->display, &event, &error)) - { - fprintf(stderr, "XFixesQueryExtension failed\n"); - return -1; - } - - xfi->xfixes_notify_event = event + XFixesCursorNotify; - - XFixesSelectCursorInput(xfi->display, DefaultRootWindow(xfi->display), XFixesDisplayCursorNotifyMask); -#endif - - return 0; -} diff --git a/server/X11/xf_encode.c b/server/X11/xf_encode.c deleted file mode 100644 index 54830f5cf..000000000 --- a/server/X11/xf_encode.c +++ /dev/null @@ -1,149 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 RemoteFX Encoder - * - * Copyright 2011 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 - -#include - -#include "xf_encode.h" - -XImage* xf_snapshot(xfPeerContext* xfp, int x, int y, int width, int height) -{ - XImage* image; - xfInfo* xfi = xfp->info; - - if (xfi->use_xshm) - { - XCopyArea(xfi->display, xfi->root_window, xfi->fb_pixmap, xfi->xdamage_gc, x, y, width, height, x, y); - image = xfi->fb_image; - } - else - { - image = XGetImage(xfi->display, xfi->root_window, x, y, width, height, AllPlanes, ZPixmap); - } - - return image; -} - -void xf_xdamage_subtract_region(xfPeerContext* xfp, int x, int y, int width, int height) -{ - XRectangle region; - xfInfo* xfi = xfp->info; - - region.x = x; - region.y = y; - region.width = width; - region.height = height; - -#ifdef WITH_XFIXES - XFixesSetRegion(xfi->display, xfi->xdamage_region, ®ion, 1); - XDamageSubtract(xfi->display, xfi->xdamage, xfi->xdamage_region, None); -#endif -} - -int xf_update_encode(freerdp_peer* client, int x, int y, int width, int height) -{ - wStream* s; - BYTE* data; - xfInfo* xfi; - RFX_RECT rect; - XImage* image; - rdpUpdate* update; - xfPeerContext* xfp; - SURFACE_BITS_COMMAND* cmd; - - update = client->update; - xfp = (xfPeerContext*) client->context; - cmd = &update->surface_bits_command; - xfi = xfp->info; - - if (width * height <= 0) - { - cmd->bitmapDataLength = 0; - return -1; - } - - s = xfp->s; - Stream_Clear(s); - Stream_SetPosition(s, 0); - - if (xfi->use_xshm) - { - /** - * Passing an offset source rectangle to rfx_compose_message() - * leads to protocol errors, so offset the data pointer instead. - */ - - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - - image = xf_snapshot(xfp, x, y, width, height); - - data = (BYTE*) image->data; - data = &data[(y * image->bytes_per_line) + (x * image->bits_per_pixel / 8)]; - - rfx_compose_message(xfp->rfx_context, s, &rect, 1, data, - width, height, image->bytes_per_line); - - cmd->destLeft = x; - cmd->destTop = y; - cmd->destRight = x + width; - cmd->destBottom = y + height; - } - else - { - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - - image = xf_snapshot(xfp, x, y, width, height); - - data = (BYTE*) image->data; - - rfx_compose_message(xfp->rfx_context, s, &rect, 1, data, - width, height, image->bytes_per_line); - - cmd->destLeft = x; - cmd->destTop = y; - cmd->destRight = x + width; - cmd->destBottom = y + height; - - XDestroyImage(image); - } - - cmd->bpp = 32; - cmd->codecID = client->settings->RemoteFxCodecId; - cmd->width = width; - cmd->height = height; - cmd->bitmapDataLength = Stream_GetPosition(s); - cmd->bitmapData = Stream_Buffer(s); - - return 0; -} diff --git a/server/X11/xf_input.c b/server/X11/xf_input.c deleted file mode 100644 index c47e996da..000000000 --- a/server/X11/xf_input.c +++ /dev/null @@ -1,155 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Input - * - * Copyright 2011 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 - -#include "xf_peer.h" - -#include "xf_input.h" - -void xf_input_synchronize_event(rdpInput* input, UINT32 flags) -{ - fprintf(stderr, "Client sent a synchronize event (flags:0x%X)\n", flags); -} - -void xf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ -#ifdef WITH_XTEST - DWORD vkcode; - DWORD keycode; - BOOL extended = FALSE; - xfPeerContext* xfp = (xfPeerContext*) input->context; - xfInfo* xfi = xfp->info; - - if (flags & KBD_FLAGS_EXTENDED) - extended = TRUE; - - if (extended) - code |= KBDEXT; - - vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4); - keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_EVDEV); - - if (keycode != 0) - { - XTestGrabControl(xfi->display, True); - - if (flags & KBD_FLAGS_DOWN) - XTestFakeKeyEvent(xfi->display, keycode, True, 0); - else if (flags & KBD_FLAGS_RELEASE) - XTestFakeKeyEvent(xfi->display, keycode, False, 0); - - XTestGrabControl(xfi->display, False); - } -#endif -} - -void xf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ - fprintf(stderr, "Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code); -} - -void xf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ -#ifdef WITH_XTEST - xfPeerContext* xfp = (xfPeerContext*) input->context; - int button = 0; - BOOL down = FALSE; - xfInfo* xfi = xfp->info; - - XTestGrabControl(xfi->display, True); - - if (flags & PTR_FLAGS_WHEEL) - { - BOOL negative = FALSE; - - if (flags & PTR_FLAGS_WHEEL_NEGATIVE) - negative = TRUE; - - button = (negative) ? 5 : 4; - - XTestFakeButtonEvent(xfi->display, button, True, 0); - XTestFakeButtonEvent(xfi->display, button, False, 0); - } - else - { - if (flags & PTR_FLAGS_MOVE) - XTestFakeMotionEvent(xfi->display, 0, x, y, 0); - - if (flags & PTR_FLAGS_BUTTON1) - button = 1; - else if (flags & PTR_FLAGS_BUTTON2) - button = 3; - else if (flags & PTR_FLAGS_BUTTON3) - button = 2; - - if (flags & PTR_FLAGS_DOWN) - down = TRUE; - - if (button != 0) - XTestFakeButtonEvent(xfi->display, button, down, 0); - } - - XTestGrabControl(xfi->display, False); -#endif -} - -void xf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ -#ifdef WITH_XTEST - xfPeerContext* xfp = (xfPeerContext*) input->context; - int button = 0; - BOOL down = FALSE; - xfInfo* xfi = xfp->info; - - XTestGrabControl(xfi->display, True); - XTestFakeMotionEvent(xfi->display, 0, x, y, CurrentTime); - - if (flags & PTR_XFLAGS_BUTTON1) - button = 8; - else if (flags & PTR_XFLAGS_BUTTON2) - button = 9; - - if (flags & PTR_XFLAGS_DOWN) - down = TRUE; - - if (button != 0) - XTestFakeButtonEvent(xfi->display, button, down, 0); - - XTestGrabControl(xfi->display, False); -#endif -} - -void xf_input_register_callbacks(rdpInput* input) -{ - input->SynchronizeEvent = xf_input_synchronize_event; - input->KeyboardEvent = xf_input_keyboard_event; - input->UnicodeKeyboardEvent = xf_input_unicode_keyboard_event; - input->MouseEvent = xf_input_mouse_event; - input->ExtendedMouseEvent = xf_input_extended_mouse_event; -} diff --git a/server/X11/xf_input.h b/server/X11/xf_input.h deleted file mode 100644 index 201b21b53..000000000 --- a/server/X11/xf_input.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Input - * - * Copyright 2011 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 __XF_INPUT_H -#define __XF_INPUT_H - -#include - -#include "xfreerdp.h" - -void xf_input_synchronize_event(rdpInput* input, UINT32 flags); -void xf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); -void xf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); -void xf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); -void xf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); -void xf_input_register_callbacks(rdpInput* input); - -#endif /* __XF_INPUT_H */ diff --git a/server/X11/xf_interface.c b/server/X11/xf_interface.c deleted file mode 100644 index c251b3297..000000000 --- a/server/X11/xf_interface.c +++ /dev/null @@ -1,173 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP X11 Server Interface - * - * Copyright 2013 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xf_peer.h" -#include "xfreerdp.h" - -#include "xf_interface.h" - -void* xf_server_thread(void* param) -{ - int i; - int fds; - int max_fds; - int rcount; - void* rfds[32]; - fd_set rfds_set; - xfServer* server; - freerdp_listener* listener; - - server = (xfServer*) param; - listener = server->listener; - - while (1) - { - rcount = 0; - - ZeroMemory(rfds, sizeof(rfds)); - if (listener->GetFileDescriptor(listener, rfds, &rcount) != TRUE) - { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); - break; - } - - max_fds = 0; - FD_ZERO(&rfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - fprintf(stderr, "select failed\n"); - break; - } - } - - if (listener->CheckFileDescriptor(listener) != TRUE) - { - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); - break; - } - } - - ExitThread(0); - - return NULL; -} - -int freerdp_server_global_init() -{ - /* - * ignore SIGPIPE, otherwise an SSL_write failure could crash the server - */ - signal(SIGPIPE, SIG_IGN); - - return 0; -} - -int freerdp_server_global_uninit() -{ - return 0; -} - -int freerdp_server_start(xfServer* server) -{ - assert(NULL != server); - - server->thread = NULL; - if (server->listener->Open(server->listener, NULL, 3389)) - { - server->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) - xf_server_thread, (void*) server, 0, NULL); - } - - return 0; -} - -int freerdp_server_stop(xfServer* server) -{ - if (server->thread) - { - /* ATTENTION: Terminate thread kills a thread, assure - * no resources are allocated during thread execution, - * as they will not be freed! */ - TerminateThread(server->thread, 0); - WaitForSingleObject(server->thread, INFINITE); - CloseHandle(server->thread); - - server->listener->Close(server->listener); - } - return 0; -} - -HANDLE freerdp_server_get_thread(xfServer* server) -{ - return server->thread; -} - -xfServer* freerdp_server_new(int argc, char** argv) -{ - xfServer* server; - - server = (xfServer*) malloc(sizeof(xfServer)); - - if (server) - { - server->listener = freerdp_listener_new(); - server->listener->PeerAccepted = xf_peer_accepted; - } - - return server; -} - -void freerdp_server_free(xfServer* server) -{ - if (server) - { - freerdp_listener_free(server->listener); - free(server); - } -} diff --git a/server/X11/xf_interface.h b/server/X11/xf_interface.h deleted file mode 100644 index f62d36450..000000000 --- a/server/X11/xf_interface.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP X11 Server Interface - * - * Copyright 2013 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 XFREERDP_SERVER_INTERFACE_H -#define XFREERDP_SERVER_INTERFACE_H - -#include - -#include -#include - -typedef struct xf_info xfInfo; -typedef struct xf_server xfServer; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Server Interface - */ - -FREERDP_API int freerdp_server_global_init(); -FREERDP_API int freerdp_server_global_uninit(); - -FREERDP_API int freerdp_server_start(xfServer* server); -FREERDP_API int freerdp_server_stop(xfServer* server); - -FREERDP_API HANDLE freerdp_server_get_thread(xfServer* server); - -FREERDP_API xfServer* freerdp_server_new(int argc, char** argv); -FREERDP_API void freerdp_server_free(xfServer* server); - -#ifdef __cplusplus -} -#endif - -#endif /* XFREERDP_SERVER_INTERFACE_H */ diff --git a/server/X11/xf_monitors.c b/server/X11/xf_monitors.c deleted file mode 100644 index 2bf5d51f1..000000000 --- a/server/X11/xf_monitors.c +++ /dev/null @@ -1,68 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Monitors - * - * Copyright 2013 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 - -#ifdef WITH_XINERAMA -#include -#endif - -#include "xf_monitors.h" - -int xf_list_monitors(xfInfo* xfi) -{ -#ifdef WITH_XINERAMAZ - int i, nmonitors = 0; - int ignored, ignored2; - XineramaScreenInfo* screen = NULL; - - if (XineramaQueryExtension(xfi->display, &ignored, &ignored2)) - { - if (XineramaIsActive(xfi->display)) - { - screen = XineramaQueryScreens(xfi->display, &nmonitors); - - for (i = 0; i < nmonitors; i++) - { - printf(" %s [%d] %dx%d\t+%d+%d\n", - (i == 0) ? "*" : " ", i, - screen[i].width, screen[i].height, - screen[i].x_org, screen[i].y_org); - } - - XFree(screen); - } - } -#else - Screen* screen; - - screen = ScreenOfDisplay(xfi->display, DefaultScreen(xfi->display)); - printf(" * [0] %dx%d\t+%d+%d\n", WidthOfScreen(screen), HeightOfScreen(screen), 0, 0); -#endif - - return 0; -} - diff --git a/server/X11/xf_peer.c b/server/X11/xf_peer.c deleted file mode 100644 index 140dcd662..000000000 --- a/server/X11/xf_peer.c +++ /dev/null @@ -1,634 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Peer - * - * Copyright 2011 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "xf_input.h" -#include "xf_cursor.h" -#include "xf_encode.h" -#include "xf_update.h" -#include "xf_monitors.h" - -#include - -#include "xf_peer.h" - -#ifdef WITH_XDAMAGE - -void xf_xdamage_init(xfInfo* xfi) -{ - int damage_event; - int damage_error; - int major, minor; - XGCValues values; - - if (XDamageQueryExtension(xfi->display, &damage_event, &damage_error) == 0) - { - fprintf(stderr, "XDamageQueryExtension failed\n"); - return; - } - - XDamageQueryVersion(xfi->display, &major, &minor); - - if (XDamageQueryVersion(xfi->display, &major, &minor) == 0) - { - fprintf(stderr, "XDamageQueryVersion failed\n"); - return; - } - else if (major < 1) - { - fprintf(stderr, "XDamageQueryVersion failed: major:%d minor:%d\n", major, minor); - return; - } - - xfi->xdamage_notify_event = damage_event + XDamageNotify; - xfi->xdamage = XDamageCreate(xfi->display, xfi->root_window, XDamageReportDeltaRectangles); - - if (xfi->xdamage == None) - { - fprintf(stderr, "XDamageCreate failed\n"); - return; - } - -#ifdef WITH_XFIXES - xfi->xdamage_region = XFixesCreateRegion(xfi->display, NULL, 0); - - if (xfi->xdamage_region == None) - { - fprintf(stderr, "XFixesCreateRegion failed\n"); - XDamageDestroy(xfi->display, xfi->xdamage); - xfi->xdamage = None; - return; - } -#endif - - values.subwindow_mode = IncludeInferiors; - xfi->xdamage_gc = XCreateGC(xfi->display, xfi->root_window, GCSubwindowMode, &values); - XSetFunction(xfi->display, xfi->xdamage_gc, GXcopy); -} - -#endif - -int xf_xshm_init(xfInfo* xfi) -{ - Bool pixmaps; - int major, minor; - - if (XShmQueryExtension(xfi->display) != False) - { - XShmQueryVersion(xfi->display, &major, &minor, &pixmaps); - - if (pixmaps != True) - { - fprintf(stderr, "XShmQueryVersion failed\n"); - return -1; - } - } - else - { - fprintf(stderr, "XShmQueryExtension failed\n"); - return -1; - } - - xfi->fb_shm_info.shmid = -1; - xfi->fb_shm_info.shmaddr = (char*) -1; - - xfi->fb_image = XShmCreateImage(xfi->display, xfi->visual, xfi->depth, - ZPixmap, NULL, &(xfi->fb_shm_info), xfi->width, xfi->height); - - if (!xfi->fb_image) - { - fprintf(stderr, "XShmCreateImage failed\n"); - return -1; - } - - xfi->fb_shm_info.shmid = shmget(IPC_PRIVATE, - xfi->fb_image->bytes_per_line * xfi->fb_image->height, IPC_CREAT | 0600); - - if (xfi->fb_shm_info.shmid == -1) - { - fprintf(stderr, "shmget failed\n"); - return -1; - } - - xfi->fb_shm_info.readOnly = False; - xfi->fb_shm_info.shmaddr = shmat(xfi->fb_shm_info.shmid, 0, 0); - xfi->fb_image->data = xfi->fb_shm_info.shmaddr; - - if (xfi->fb_shm_info.shmaddr == ((char*) -1)) - { - fprintf(stderr, "shmat failed\n"); - return -1; - } - - XShmAttach(xfi->display, &(xfi->fb_shm_info)); - XSync(xfi->display, False); - - shmctl(xfi->fb_shm_info.shmid, IPC_RMID, 0); - - fprintf(stderr, "display: %p root_window: %p width: %d height: %d depth: %d\n", - xfi->display, (void*) xfi->root_window, xfi->fb_image->width, xfi->fb_image->height, xfi->fb_image->depth); - - xfi->fb_pixmap = XShmCreatePixmap(xfi->display, - xfi->root_window, xfi->fb_image->data, &(xfi->fb_shm_info), - xfi->fb_image->width, xfi->fb_image->height, xfi->fb_image->depth); - - return 0; -} - -void xf_info_free(xfInfo *info) -{ - assert(NULL != info); - - if (info->display) - XCloseDisplay(info->display); - - freerdp_clrconv_free(info->clrconv); - free(info); -} - -xfInfo* xf_info_init() -{ - int i; - xfInfo* xfi; - int pf_count; - int vi_count; - XVisualInfo* vi; - XVisualInfo* vis; - XVisualInfo template; - XPixmapFormatValues* pf; - XPixmapFormatValues* pfs; - - xfi = (xfInfo*) malloc(sizeof(xfInfo)); - ZeroMemory(xfi, sizeof(xfInfo)); - - /** - * Recent X11 servers drop support for shared pixmaps - * To see if your X11 server supports shared pixmaps, use: - * xdpyinfo -ext MIT-SHM | grep "shared pixmaps" - */ - xfi->use_xshm = TRUE; - - setenv("DISPLAY", ":0", 1); /* Set DISPLAY variable if not already set */ - - if (!XInitThreads()) - fprintf(stderr, "warning: XInitThreads() failure\n"); - - xfi->display = XOpenDisplay(NULL); - - if (!xfi->display) - { - fprintf(stderr, "failed to open display: %s\n", XDisplayName(NULL)); - exit(1); - } - - xf_list_monitors(xfi); - - xfi->xfds = ConnectionNumber(xfi->display); - xfi->number = DefaultScreen(xfi->display); - xfi->screen = ScreenOfDisplay(xfi->display, xfi->number); - xfi->depth = DefaultDepthOfScreen(xfi->screen); - xfi->width = WidthOfScreen(xfi->screen); - xfi->height = HeightOfScreen(xfi->screen); - xfi->root_window = DefaultRootWindow(xfi->display); - - pfs = XListPixmapFormats(xfi->display, &pf_count); - - if (!pfs) - { - fprintf(stderr, "XListPixmapFormats failed\n"); - exit(1); - } - - for (i = 0; i < pf_count; i++) - { - pf = pfs + i; - - if (pf->depth == xfi->depth) - { - xfi->bpp = pf->bits_per_pixel; - xfi->scanline_pad = pf->scanline_pad; - break; - } - } - XFree(pfs); - - ZeroMemory(&template, sizeof(template)); - template.class = TrueColor; - template.screen = xfi->number; - - vis = XGetVisualInfo(xfi->display, VisualClassMask | VisualScreenMask, &template, &vi_count); - - if (!vis) - { - fprintf(stderr, "XGetVisualInfo failed\n"); - exit(1); - } - - for (i = 0; i < vi_count; i++) - { - vi = vis + i; - - if (vi->depth == xfi->depth) - { - xfi->visual = vi->visual; - break; - } - } - XFree(vis); - - xfi->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA | CLRCONV_INVERT); - - XSelectInput(xfi->display, xfi->root_window, SubstructureNotifyMask); - - if (xfi->use_xshm) - { - if (xf_xshm_init(xfi) < 0) - xfi->use_xshm = FALSE; - } - - if (xfi->use_xshm) - printf("Using X Shared Memory Extension (XShm)\n"); - -#ifdef WITH_XDAMAGE - xf_xdamage_init(xfi); -#endif - - xf_cursor_init(xfi); - - xfi->bytesPerPixel = 4; - xfi->activePeerCount = 0; - - freerdp_keyboard_init(0); - - return xfi; -} - -void xf_peer_context_new(freerdp_peer* client, xfPeerContext* context) -{ - context->info = xf_info_init(); - context->rfx_context = rfx_context_new(TRUE); - context->rfx_context->mode = RLGR3; - context->rfx_context->width = context->info->width; - context->rfx_context->height = context->info->height; - - rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - - context->s = Stream_New(NULL, 65536); - Stream_Clear(context->s); - - context->updateReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - context->updateSentEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -} - -void xf_peer_context_free(freerdp_peer* client, xfPeerContext* context) -{ - if (context) - { - xf_info_free(context->info); - - CloseHandle(context->updateReadyEvent); - CloseHandle(context->updateSentEvent); - - Stream_Free(context->s, TRUE); - rfx_context_free(context->rfx_context); - } -} - -void xf_peer_init(freerdp_peer* client) -{ - xfInfo* xfi; - xfPeerContext* xfp; - - client->ContextSize = sizeof(xfPeerContext); - client->ContextNew = (psPeerContextNew) xf_peer_context_new; - client->ContextFree = (psPeerContextFree) xf_peer_context_free; - freerdp_peer_context_new(client); - - xfp = (xfPeerContext*) client->context; - - xfp->fps = 16; - xfi = xfp->info; - - xfp->mutex = CreateMutex(NULL, FALSE, NULL); -} - -void xf_peer_send_update(freerdp_peer* client) -{ - rdpUpdate* update; - SURFACE_BITS_COMMAND* cmd; - - update = client->update; - cmd = &update->surface_bits_command; - - if (cmd->bitmapDataLength) - update->SurfaceBits(update->context, cmd); -} - -BOOL xf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) -{ - int fds; - HANDLE event; - xfPeerContext* xfp = (xfPeerContext*) client->context; - - event = xfp->updateReadyEvent; - fds = GetEventFileDescriptor(event); - rfds[*rcount] = (void*) (long) fds; - (*rcount)++; - - return TRUE; -} - -BOOL xf_peer_check_fds(freerdp_peer* client) -{ - xfInfo* xfi; - xfPeerContext* xfp; - - xfp = (xfPeerContext*) client->context; - xfi = xfp->info; - - if (WaitForSingleObject(xfp->updateReadyEvent, 0) == WAIT_OBJECT_0) - { - if (!xfp->activated) - return TRUE; - - xf_peer_send_update(client); - - ResetEvent(xfp->updateReadyEvent); - SetEvent(xfp->updateSentEvent); - } - - return TRUE; -} - -BOOL xf_peer_capabilities(freerdp_peer* client) -{ - return TRUE; -} - -BOOL xf_peer_post_connect(freerdp_peer* client) -{ - xfInfo* xfi; - xfPeerContext* xfp; - - xfp = (xfPeerContext*) client->context; - xfi = (xfInfo*) xfp->info; - - /** - * This callback is called when the entire connection sequence is done, i.e. we've received the - * Font List PDU from the client and sent out the Font Map PDU. - * The server may start sending graphics output and receiving keyboard/mouse input after this - * callback returns. - */ - fprintf(stderr, "Client %s is activated", client->hostname); - if (client->settings->AutoLogonEnabled) - { - fprintf(stderr, " and wants to login automatically as %s\\%s", - client->settings->Domain ? client->settings->Domain : "", - client->settings->Username); - - /* A real server may perform OS login here if NLA is not executed previously. */ - } - fprintf(stderr, "\n"); - - fprintf(stderr, "Client requested desktop: %dx%dx%d\n", - client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); - - if (!client->settings->RemoteFxCodec) - { - fprintf(stderr, "Client does not support RemoteFX\n"); - return FALSE; - } - - /* A real server should tag the peer as activated here and start sending updates in main loop. */ - - client->settings->DesktopWidth = xfi->width; - client->settings->DesktopHeight = xfi->height; - - client->update->DesktopResize(client->update->context); - - /* Return FALSE here would stop the execution of the peer main loop. */ - return TRUE; -} - -BOOL xf_peer_activate(freerdp_peer* client) -{ - xfPeerContext* xfp = (xfPeerContext*) client->context; - - rfx_context_reset(xfp->rfx_context); - xfp->activated = TRUE; - - xfp->info->activePeerCount++; - - xfp->monitorThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) xf_update_thread, (void*) client, 0, NULL); - - return TRUE; -} - -const char* makecert_argv[4] = -{ - "makecert", - "-rdp", - "-live", - "-silent" -}; - -int makecert_argc = (sizeof(makecert_argv) / sizeof(char*)); - -int xf_generate_certificate(rdpSettings* settings) -{ - char* server_file_path; - MAKECERT_CONTEXT* context; - - server_file_path = GetCombinedPath(settings->ConfigPath, "server"); - - if (!PathFileExistsA(server_file_path)) - CreateDirectoryA(server_file_path, 0); - - settings->CertificateFile = GetCombinedPath(server_file_path, "server.crt"); - settings->PrivateKeyFile = GetCombinedPath(server_file_path, "server.key"); - - if ((!PathFileExistsA(settings->CertificateFile)) || - (!PathFileExistsA(settings->PrivateKeyFile))) - { - context = makecert_context_new(); - - makecert_context_process(context, makecert_argc, (char**) makecert_argv); - - makecert_context_set_output_file_name(context, "server"); - - if (!PathFileExistsA(settings->CertificateFile)) - makecert_context_output_certificate_file(context, server_file_path); - - if (!PathFileExistsA(settings->PrivateKeyFile)) - makecert_context_output_private_key_file(context, server_file_path); - - makecert_context_free(context); - } - - free(server_file_path); - - return 0; -} - -static void* xf_peer_main_loop(void* arg) -{ - int i; - int fds; - int max_fds; - int rcount; - void* rfds[32]; - fd_set rfds_set; - rdpSettings* settings; - xfPeerContext* xfp; - struct timeval timeout; - freerdp_peer* client = (freerdp_peer*) arg; - - assert(NULL != client); - - ZeroMemory(rfds, sizeof(rfds)); - ZeroMemory(&timeout, sizeof(struct timeval)); - - fprintf(stderr, "We've got a client %s\n", client->hostname); - - xf_peer_init(client); - xfp = (xfPeerContext*) client->context; - settings = client->settings; - - xf_generate_certificate(settings); - - settings->RemoteFxCodec = TRUE; - settings->ColorDepth = 32; - - settings->NlaSecurity = FALSE; - settings->TlsSecurity = TRUE; - settings->RdpSecurity = FALSE; - - client->Capabilities = xf_peer_capabilities; - client->PostConnect = xf_peer_post_connect; - client->Activate = xf_peer_activate; - - xf_input_register_callbacks(client->input); - - client->Initialize(client); - - while (1) - { - rcount = 0; - - if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) - { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); - break; - } - - if (xf_peer_get_fds(client, rfds, &rcount) != TRUE) - { - fprintf(stderr, "Failed to get xfreerdp file descriptor\n"); - break; - } - - max_fds = 0; - FD_ZERO(&rfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - timeout.tv_sec = 0; - timeout.tv_usec = 100; - - if (select(max_fds + 1, &rfds_set, NULL, NULL, &timeout) == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - fprintf(stderr, "select failed\n"); - break; - } - } - - if (client->CheckFileDescriptor(client) != TRUE) - { - fprintf(stderr, "Failed to check freerdp file descriptor\n"); - break; - } - - if ((xf_peer_check_fds(client)) != TRUE) - { - fprintf(stderr, "Failed to check xfreerdp file descriptor\n"); - break; - } - } - - fprintf(stderr, "Client %s disconnected.\n", client->hostname); - - client->Disconnect(client); - - freerdp_peer_context_free(client); - freerdp_peer_free(client); - - ExitThread(0); - - return NULL; -} - -void xf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) -{ - HANDLE thread; - - thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_peer_main_loop, client, 0, NULL); -} diff --git a/server/X11/xf_peer.h b/server/X11/xf_peer.h deleted file mode 100644 index e6febd68d..000000000 --- a/server/X11/xf_peer.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Peer - * - * Copyright 2011 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 __XF_PEER_H -#define __XF_PEER_H - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -typedef struct xf_peer_context xfPeerContext; - -#include "xfreerdp.h" - -#define PeerEvent_Base 0 - -#define PeerEvent_Class (PeerEvent_Base + 1) - -#define PeerEvent_EncodeRegion 1 - -struct xf_peer_context -{ - rdpContext _p; - - int fps; - wStream* s; - xfInfo* info; - HANDLE mutex; - BOOL activated; - HANDLE monitorThread; - HANDLE updateReadyEvent; - HANDLE updateSentEvent; - RFX_CONTEXT* rfx_context; -}; - -void xf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); - -#endif /* __XF_PEER_H */ diff --git a/server/X11/xf_update.c b/server/X11/xf_update.c deleted file mode 100644 index 67addb550..000000000 --- a/server/X11/xf_update.c +++ /dev/null @@ -1,100 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * X11 Server Graphical Updates - * - * Copyright 2013 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 - -#include "xf_peer.h" -#include "xf_encode.h" - -#include "xf_update.h" - -void* xf_update_thread(void* param) -{ - xfInfo* xfi; - HANDLE event; - XEvent xevent; - DWORD beg, end; - DWORD diff, rate; - xfPeerContext* xfp; - freerdp_peer* client; - int x, y, width, height; - XDamageNotifyEvent* notify; - - client = (freerdp_peer*) param; - xfp = (xfPeerContext*) client->context; - xfi = xfp->info; - - rate = 1000 / xfp->fps; - - event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfi->xfds); - - while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) - { - beg = GetTickCount(); - - while (XPending(xfi->display) > 0) - { - ZeroMemory(&xevent, sizeof(xevent)); - XNextEvent(xfi->display, &xevent); - - if (xevent.type == xfi->xdamage_notify_event) - { - notify = (XDamageNotifyEvent*) &xevent; - - x = notify->area.x; - y = notify->area.y; - width = notify->area.width; - height = notify->area.height; - - if (xf_update_encode(client, x, y, width, height) >= 0) - { - xf_xdamage_subtract_region(xfp, x, y, width, height); - - SetEvent(xfp->updateReadyEvent); - - WaitForSingleObject(xfp->updateSentEvent, INFINITE); - ResetEvent(xfp->updateSentEvent); - } - } -#ifdef WITH_XFIXES - else if (xevent.type == xfi->xfixes_notify_event) - { - XFixesCursorImage* ci = XFixesGetCursorImage(xfi->display); - XFree(ci); - } -#endif - } - - end = GetTickCount(); - diff = end - beg; - - if (diff < rate) - Sleep(rate - diff); - } - - return NULL; -} diff --git a/server/common/CMakeLists.txt b/server/common/CMakeLists.txt index 22869430d..90ac794bd 100644 --- a/server/common/CMakeLists.txt +++ b/server/common/CMakeLists.txt @@ -32,7 +32,10 @@ endif() add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) +endif() +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${FREERDP_CHANNELS_SERVER_LIBS}) diff --git a/server/shadow/.gitignore b/server/shadow/.gitignore new file mode 100644 index 000000000..662d7d541 --- /dev/null +++ b/server/shadow/.gitignore @@ -0,0 +1,2 @@ +freerdp-shadow + diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt new file mode 100644 index 000000000..35dcb41e7 --- /dev/null +++ b/server/shadow/CMakeLists.txt @@ -0,0 +1,245 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP Shadow Server 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. + +set(MODULE_NAME "freerdp-shadow") +set(MODULE_PREFIX "FREERDP_SERVER_SHADOW") + +if(WIN32) + set(WITH_SHADOW_WIN 1) +elseif(X11_FOUND AND NOT APPLE) + set(WITH_SHADOW_X11 1) +elseif(APPLE AND NOT IOS) + set(WITH_SHADOW_MAC 1) +endif() + +# Authentication + +if(WITH_SHADOW_X11 OR WITH_SHADOW_MAC) + set(PAM_FEATURE_TYPE "RECOMMENDED") + set(PAM_FEATURE_PURPOSE "authentication") + set(PAM_FEATURE_DESCRIPTION "user authentication") + + find_feature(PAM ${PAM_FEATURE_TYPE} ${PAM_FEATURE_PURPOSE} ${PAM_FEATURE_DESCRIPTION}) + + if(PAM_FOUND) + add_definitions(-DWITH_PAM) + include_directories(${PAM_INCLUDE_DIR}) + list(APPEND ${MODULE_PREFIX}_AUTH_LIBS ${PAM_LIBRARY}) + endif() +endif() + +if(WITH_SHADOW_X11) + set(XEXT_FEATURE_TYPE "RECOMMENDED") + set(XEXT_FEATURE_PURPOSE "X11 extension") + set(XEXT_FEATURE_DESCRIPTION "X11 core extensions") + + set(XSHM_FEATURE_TYPE "RECOMMENDED") + set(XSHM_FEATURE_PURPOSE "X11 shared memory") + set(XSHM_FEATURE_DESCRIPTION "X11 shared memory extension") + + set(XINERAMA_FEATURE_TYPE "RECOMMENDED") + set(XINERAMA_FEATURE_PURPOSE "multi-monitor") + set(XINERAMA_FEATURE_DESCRIPTION "X11 multi-monitor extension") + + set(XTEST_FEATURE_TYPE "RECOMMENDED") + set(XTEST_FEATURE_PURPOSE "X11 input event injection") + set(XTEST_FEATURE_DESCRIPTION "X11 input event injection extension") + + set(XCURSOR_FEATURE_TYPE "RECOMMENDED") + set(XCURSOR_FEATURE_PURPOSE "cursor") + set(XCURSOR_FEATURE_DESCRIPTION "X11 cursor extension") + + set(XFIXES_FEATURE_TYPE "RECOMMENDED") + set(XFIXES_FEATURE_PURPOSE "X11 region") + set(XFIXES_FEATURE_DESCRIPTION "X11 region fix extension") + + set(XRANDR_FEATURE_TYPE "RECOMMENDED") + set(XRANDR_FEATURE_PURPOSE "X11 resize, rotate and reflect") + set(XRANDR_FEATURE_DESCRIPTION "X11 resize, rotate and reflect extension") + + set(XDAMAGE_FEATURE_TYPE "RECOMMENDED") + set(XDAMAGE_FEATURE_PURPOSE "X11 region damage") + set(XDAMAGE_FEATURE_DESCRIPTION "X11 region damage extension") + + find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION}) + find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION}) + find_feature(XTest ${XTEST_FEATURE_TYPE} ${XTEST_FEATURE_PURPOSE} ${XTEST_FEATURE_DESCRIPTION}) + find_feature(Xfixes ${XFIXES_FEATURE_TYPE} ${XFIXES_FEATURE_PURPOSE} ${XFIXES_FEATURE_DESCRIPTION}) + find_feature(XRandR ${XRANDR_FEATURE_TYPE} ${XRANDR_FEATURE_PURPOSE} ${XRANDR_FEATURE_DESCRIPTION}) + find_feature(Xdamage ${XDAMAGE_FEATURE_TYPE} ${XDAMAGE_FEATURE_PURPOSE} ${XDAMAGE_FEATURE_DESCRIPTION}) + find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSOR_FEATURE_DESCRIPTION}) + find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION}) + + if(WITH_X11) + add_definitions(-DWITH_X11) + include_directories(${X11_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${X11_LIBRARIES}) + endif() + + if(WITH_XSHM) + add_definitions(-DWITH_XSHM) + include_directories(${XSHM_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XSHM_LIBRARIES}) + endif() + + if(WITH_XEXT) + add_definitions(-DWITH_XEXT) + include_directories(${XEXT_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XEXT_LIBRARIES}) + endif() + + if(WITH_XINERAMA) + add_definitions(-DWITH_XINERAMA) + include_directories(${XINERAMA_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XINERAMA_LIBRARIES}) + endif() + + if(WITH_XCURSOR) + add_definitions(-DWITH_XCURSOR) + include_directories(${XCURSOR_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XCURSOR_LIBRARIES}) + endif() + + if(WITH_XDAMAGE) + add_definitions(-DWITH_XDAMAGE) + include_directories(${XDAMAGE_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XDAMAGE_LIBRARIES}) + endif() + + if(WITH_XFIXES) + add_definitions(-DWITH_XFIXES) + include_directories(${XFIXES_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XFIXES_LIBRARIES}) + endif() + + if(WITH_XTEST) + add_definitions(-DWITH_XTEST) + include_directories(${XTEST_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XTEST_LIBRARIES}) + endif() + + if(WITH_XRANDR) + add_definitions(-DWITH_XRANDR) + include_directories(${XRANDR_INCLUDE_DIRS}) + list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XRANDR_LIBRARIES}) + endif() +endif() + +if(WITH_SHADOW_MAC) + find_library(IOKIT IOKit) + find_library(IOSURFACE IOSurface) + find_library(CARBON Carbon) + list(APPEND ${MODULE_PREFIX}_MAC_LIBS ${IOKIT} ${IOSURFACE} ${CARBON}) +endif() + +include_directories(${OPENSSL_INCLUDE_DIR}) + +set(${MODULE_PREFIX}_SRCS + shadow_client.c + shadow_client.h + shadow_lobby.c + shadow_lobby.h + shadow_input.c + shadow_input.h + shadow_screen.c + shadow_screen.h + shadow_surface.c + shadow_surface.h + shadow_encoder.c + shadow_encoder.h + shadow_capture.c + shadow_capture.h + shadow_channels.c + shadow_channels.h + shadow_encomsp.c + shadow_encomsp.h + shadow_remdesk.c + shadow_remdesk.h + shadow_subsystem.c + shadow_subsystem.h + shadow_server.c + shadow.h) + +set(${MODULE_PREFIX}_WIN_SRCS + Win/win_rdp.c + Win/win_rdp.h + Win/win_wds.c + Win/win_wds.h + Win/win_dxgi.c + Win/win_dxgi.h + Win/win_shadow.c + Win/win_shadow.h) + +set(${MODULE_PREFIX}_X11_SRCS + X11/x11_shadow.c + X11/x11_shadow.h) + +set(${MODULE_PREFIX}_MAC_SRCS + Mac/mac_shadow.c + Mac/mac_shadow.h) + +if(WITH_SHADOW_WIN) + add_definitions(-DWITH_SHADOW_WIN) + list(APPEND ${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_WIN_SRCS}) + list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_WIN_LIBS}) +elseif(WITH_SHADOW_X11) + add_definitions(-DWITH_SHADOW_X11) + list(APPEND ${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_X11_SRCS}) + list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_X11_LIBS}) +elseif(WITH_SHADOW_MAC) + add_definitions(-DWITH_SHADOW_MAC) + list(APPEND ${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_MAC_SRCS}) + list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_MAC_LIBS}) +endif() + +list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_AUTH_LIBS}) + +add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +list(APPEND ${MODULE_PREFIX}_LIBS freerdp) +list(APPEND ${MODULE_PREFIX}_LIBS freerdp-server) +list(APPEND ${MODULE_PREFIX}_LIBS freerdp-client) + +list(APPEND ${MODULE_PREFIX}_LIBS winpr) +list(APPEND ${MODULE_PREFIX}_LIBS winpr-makecert-tool) + +list(APPEND ${MODULE_PREFIX}_LIBS rdtk) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT server) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow") + +# command-line executable + +set(MODULE_NAME "freerdp-shadow-cli") +set(MODULE_PREFIX "FREERDP_SERVER_SHADOW_CLI") + +set(${MODULE_PREFIX}_SRCS + shadow.c) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) +set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "freerdp-shadow") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow") diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c new file mode 100644 index 000000000..7efd78b30 --- /dev/null +++ b/server/shadow/Mac/mac_shadow.c @@ -0,0 +1,676 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-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. + */ + +#include +#include +#include +#include + +#include +#include + +#include "../shadow_screen.h" +#include "../shadow_client.h" +#include "../shadow_surface.h" +#include "../shadow_capture.h" +#include "../shadow_encoder.h" +#include "../shadow_subsystem.h" + +#include "mac_shadow.h" + +static macShadowSubsystem* g_Subsystem = NULL; + +void mac_shadow_input_synchronize_event(macShadowSubsystem* subsystem, UINT32 flags) +{ + +} + +void mac_shadow_input_keyboard_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ + DWORD vkcode; + DWORD keycode; + BOOL extended; + CGEventRef kbdEvent; + CGEventSourceRef source; + + extended = (flags & KBD_FLAGS_EXTENDED) ? TRUE : FALSE; + + if (extended) + code |= KBDEXT; + + vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4); + + if (extended) + vkcode |= KBDEXT; + + keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_APPLE); + + if (keycode < 8) + return; + + keycode -= 8; + + source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + + if (flags & KBD_FLAGS_DOWN) + { + kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, TRUE); + CGEventPost(kCGHIDEventTap, kbdEvent); + CFRelease(kbdEvent); + } + else if (flags & KBD_FLAGS_RELEASE) + { + kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, FALSE); + CGEventPost(kCGHIDEventTap, kbdEvent); + CFRelease(kbdEvent); + } + + CFRelease(source); +} + +void mac_shadow_input_unicode_keyboard_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ + +} + +void mac_shadow_input_mouse_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ + UINT32 scrollX = 0; + UINT32 scrollY = 0; + CGWheelCount wheelCount = 2; + + if (flags & PTR_FLAGS_WHEEL) + { + scrollY = flags & WheelRotationMask; + + if (flags & PTR_FLAGS_WHEEL_NEGATIVE) + { + scrollY = -(flags & WheelRotationMask) / 392; + } + else + { + scrollY = (flags & WheelRotationMask) / 120; + } + + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventRef scroll = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine, + wheelCount, scrollY, scrollX); + CGEventPost(kCGHIDEventTap, scroll); + + CFRelease(scroll); + CFRelease(source); + } + else + { + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventType mouseType = kCGEventNull; + CGMouseButton mouseButton = kCGMouseButtonLeft; + + if (flags & PTR_FLAGS_MOVE) + { + if (subsystem->mouseDownLeft) + mouseType = kCGEventLeftMouseDragged; + else if (subsystem->mouseDownRight) + mouseType = kCGEventRightMouseDragged; + else if (subsystem->mouseDownOther) + mouseType = kCGEventOtherMouseDragged; + else + mouseType = kCGEventMouseMoved; + + CGEventRef move = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton); + CGEventPost(kCGHIDEventTap, move); + CFRelease(move); + } + + if (flags & PTR_FLAGS_BUTTON1) + { + mouseButton = kCGMouseButtonLeft; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventLeftMouseDown; + subsystem->mouseDownLeft = TRUE; + } + else + { + mouseType = kCGEventLeftMouseUp; + subsystem->mouseDownLeft = FALSE; + } + } + else if (flags & PTR_FLAGS_BUTTON2) + { + mouseButton = kCGMouseButtonRight; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventRightMouseDown; + subsystem->mouseDownRight = TRUE; + } + else + { + mouseType = kCGEventRightMouseUp; + subsystem->mouseDownRight = FALSE; + } + + } + else if (flags & PTR_FLAGS_BUTTON3) + { + mouseButton = kCGMouseButtonCenter; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventOtherMouseDown; + subsystem->mouseDownOther = TRUE; + } + else + { + mouseType = kCGEventOtherMouseUp; + subsystem->mouseDownOther = FALSE; + } + } + + CGEventRef mouseEvent = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton); + CGEventPost(kCGHIDEventTap, mouseEvent); + + CFRelease(mouseEvent); + CFRelease(source); + } +} + +void mac_shadow_input_extended_mouse_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ + +} + +int mac_shadow_detect_monitors(macShadowSubsystem* subsystem) +{ + size_t wide, high; + MONITOR_DEF* monitor; + CGDirectDisplayID displayId; + + displayId = CGMainDisplayID(); + + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + + subsystem->pixelWidth = CGDisplayModeGetPixelWidth(mode); + subsystem->pixelHeight = CGDisplayModeGetPixelHeight(mode); + + wide = CGDisplayPixelsWide(displayId); + high = CGDisplayPixelsHigh(displayId); + + CGDisplayModeRelease(mode); + + subsystem->retina = ((subsystem->pixelWidth / wide) == 2) ? TRUE : FALSE; + + if (subsystem->retina) + { + subsystem->width = wide; + subsystem->height = high; + } + else + { + subsystem->width = subsystem->pixelWidth; + subsystem->height = subsystem->pixelHeight; + } + + subsystem->numMonitors = 1; + + monitor = &(subsystem->monitors[0]); + + monitor->left = 0; + monitor->top = 0; + monitor->right = subsystem->width; + monitor->bottom = subsystem->height; + monitor->flags = 1; + + return 1; +} + +int mac_shadow_capture_start(macShadowSubsystem* subsystem) +{ + CGError err; + + err = CGDisplayStreamStart(subsystem->stream); + + if (err != kCGErrorSuccess) + return -1; + + return 1; +} + +int mac_shadow_capture_stop(macShadowSubsystem* subsystem) +{ + CGError err; + + err = CGDisplayStreamStop(subsystem->stream); + + if (err != kCGErrorSuccess) + return -1; + + return 1; +} + +int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem) +{ + size_t index; + size_t numRects; + const CGRect* rects; + RECTANGLE_16 invalidRect; + + rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects, &numRects); + + if (!numRects) + return -1; + + for (index = 0; index < numRects; index++) + { + invalidRect.left = (UINT16) rects[index].origin.x; + invalidRect.top = (UINT16) rects[index].origin.y; + invalidRect.right = invalidRect.left + (UINT16) rects[index].size.width; + invalidRect.bottom = invalidRect.top + (UINT16) rects[index].size.height; + + if (subsystem->retina) + { + /* scale invalid rect */ + invalidRect.left /= 2; + invalidRect.top /= 2; + invalidRect.right /= 2; + invalidRect.bottom /= 2; + } + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + } + + return 0; +} + +void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) = + ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) +{ + int x, y; + int count; + int width; + int height; + int nSrcStep; + BYTE* pSrcData; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16* extents; + macShadowSubsystem* subsystem = g_Subsystem; + rdpShadowServer* server = subsystem->server; + rdpShadowSurface* surface = server->surface; + + count = ArrayList_Count(server->clients); + + if (count < 1) + return; + + if ((count == 1) && subsystem->suppressOutput) + return; + + mac_shadow_capture_get_dirty_region(subsystem); + + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = surface->width; + surfaceRect.bottom = surface->height; + + region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + + if (!region16_is_empty(&(subsystem->invalidRegion))) + { + extents = region16_extents(&(subsystem->invalidRegion)); + + x = extents->left; + y = extents->top; + width = extents->right - extents->left; + height = extents->bottom - extents->top; + + IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL); + + pSrcData = (BYTE*) IOSurfaceGetBaseAddress(frameSurface); + nSrcStep = (int) IOSurfaceGetBytesPerRow(frameSurface); + + if (subsystem->retina) + { + freerdp_image_copy_from_retina(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + x, y, width, height, pSrcData, nSrcStep, x, y); + } + else + { + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + x, y, width, height, pSrcData, PIXEL_FORMAT_XRGB32, nSrcStep, x, y, NULL); + } + + IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL); + + ArrayList_Lock(server->clients); + + count = ArrayList_Count(server->clients); + + InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); + + SetEvent(subsystem->updateEvent); + + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + + DeleteSynchronizationBarrier(&(subsystem->barrier)); + + if (count == 1) + { + rdpShadowClient* client; + + client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0); + + if (client) + { + subsystem->captureFrameRate = client->encoder->fps; + } + } + + ResetEvent(subsystem->updateEvent); + + ArrayList_Unlock(server->clients); + + region16_clear(&(subsystem->invalidRegion)); + } + + if (status != kCGDisplayStreamFrameStatusFrameComplete) + { + switch (status) + { + case kCGDisplayStreamFrameStatusFrameIdle: + break; + + case kCGDisplayStreamFrameStatusStopped: + break; + + case kCGDisplayStreamFrameStatusFrameBlank: + break; + + default: + break; + } + } + else if (!subsystem->lastUpdate) + { + CFRetain(updateRef); + subsystem->lastUpdate = updateRef; + } + else + { + CGDisplayStreamUpdateRef tmpRef = subsystem->lastUpdate; + subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef); + CFRelease(tmpRef); + } +}; + +int mac_shadow_capture_init(macShadowSubsystem* subsystem) +{ + void* keys[2]; + void* values[2]; + CFDictionaryRef opts; + CGDirectDisplayID displayId; + + displayId = CGMainDisplayID(); + + subsystem->updateBuffer = (BYTE*) malloc(subsystem->pixelWidth * subsystem->pixelHeight * 4); + + if (!subsystem->updateBuffer) + return -1; + + subsystem->captureQueue = dispatch_queue_create("mac.shadow.capture", NULL); + + keys[0] = (void*) kCGDisplayStreamShowCursor; + values[0] = (void*) kCFBooleanFalse; + + opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 1, NULL, NULL); + + subsystem->stream = CGDisplayStreamCreateWithDispatchQueue(displayId, subsystem->pixelWidth, subsystem->pixelHeight, + 'BGRA', opts, subsystem->captureQueue, mac_capture_stream_handler); + + CFRelease(opts); + + return 1; +} + +int mac_shadow_screen_grab(macShadowSubsystem* subsystem) +{ + return 1; +} + +int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message) +{ + if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID) + { + UINT32 index; + SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; + + if (msg->numRects) + { + for (index = 0; index < msg->numRects; index++) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &msg->rects[index]); + } + } + else + { + RECTANGLE_16 refreshRect; + + refreshRect.left = 0; + refreshRect.top = 0; + refreshRect.right = subsystem->width; + refreshRect.bottom = subsystem->height; + + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &refreshRect); + } + } + else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID) + { + SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; + + subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE; + + if (msg->allow) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &(msg->rect)); + } + } + + if (message->Free) + message->Free(message); + + return 1; +} + +void* mac_shadow_subsystem_thread(macShadowSubsystem* subsystem) +{ + DWORD status; + DWORD nCount; + UINT64 cTime; + DWORD dwTimeout; + DWORD dwInterval; + UINT64 frameTime; + HANDLE events[32]; + wMessage message; + wMessagePipe* MsgPipe; + + MsgPipe = subsystem->MsgPipe; + + nCount = 0; + events[nCount++] = MessageQueue_Event(MsgPipe->In); + + subsystem->captureFrameRate = 16; + dwInterval = 1000 / subsystem->captureFrameRate; + frameTime = GetTickCount64() + dwInterval; + + while (1) + { + cTime = GetTickCount64(); + dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime; + + status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout); + + if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0) + { + if (MessageQueue_Peek(MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + mac_shadow_subsystem_process_message(subsystem, &message); + } + } + + if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) + { + mac_shadow_screen_grab(subsystem); + + dwInterval = 1000 / subsystem->captureFrameRate; + frameTime += dwInterval; + } + } + + ExitThread(0); + return NULL; +} + +int mac_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors) +{ + int index; + size_t wide, high; + int numMonitors = 0; + MONITOR_DEF* monitor; + CGDirectDisplayID displayId; + + displayId = CGMainDisplayID(); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + + wide = CGDisplayPixelsWide(displayId); + high = CGDisplayPixelsHigh(displayId); + + CGDisplayModeRelease(mode); + + index = 0; + numMonitors = 1; + + monitor = &monitors[index]; + + monitor->left = 0; + monitor->top = 0; + monitor->right = (int) wide; + monitor->bottom = (int) high; + monitor->flags = 1; + + return numMonitors; +} + +int mac_shadow_subsystem_init(macShadowSubsystem* subsystem) +{ + g_Subsystem = subsystem; + + mac_shadow_detect_monitors(subsystem); + + mac_shadow_capture_init(subsystem); + + return 1; +} + +int mac_shadow_subsystem_uninit(macShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + if (subsystem->lastUpdate) + { + CFRelease(subsystem->lastUpdate); + subsystem->lastUpdate = NULL; + } + + return 1; +} + +int mac_shadow_subsystem_start(macShadowSubsystem* subsystem) +{ + HANDLE thread; + + if (!subsystem) + return -1; + + mac_shadow_capture_start(subsystem); + + thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) mac_shadow_subsystem_thread, + (void*) subsystem, 0, NULL); + + return 1; +} + +int mac_shadow_subsystem_stop(macShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + return 1; +} + +void mac_shadow_subsystem_free(macShadowSubsystem* subsystem) +{ + if (!subsystem) + return; + + mac_shadow_subsystem_uninit(subsystem); + + free(subsystem); +} + +macShadowSubsystem* mac_shadow_subsystem_new() +{ + macShadowSubsystem* subsystem; + + subsystem = (macShadowSubsystem*) calloc(1, sizeof(macShadowSubsystem)); + + if (!subsystem) + return NULL; + + subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) mac_shadow_input_synchronize_event; + subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) mac_shadow_input_keyboard_event; + subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) mac_shadow_input_unicode_keyboard_event; + subsystem->MouseEvent = (pfnShadowMouseEvent) mac_shadow_input_mouse_event; + subsystem->ExtendedMouseEvent = (pfnShadowExtendedMouseEvent) mac_shadow_input_extended_mouse_event; + + return subsystem; +} + +int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +{ + pEntryPoints->New = (pfnShadowSubsystemNew) mac_shadow_subsystem_new; + pEntryPoints->Free = (pfnShadowSubsystemFree) mac_shadow_subsystem_free; + + pEntryPoints->Init = (pfnShadowSubsystemInit) mac_shadow_subsystem_init; + pEntryPoints->Uninit = (pfnShadowSubsystemInit) mac_shadow_subsystem_uninit; + + pEntryPoints->Start = (pfnShadowSubsystemStart) mac_shadow_subsystem_start; + pEntryPoints->Stop = (pfnShadowSubsystemStop) mac_shadow_subsystem_stop; + + pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) mac_shadow_enum_monitors; + + return 1; +} diff --git a/server/shadow/Mac/mac_shadow.h b/server/shadow/Mac/mac_shadow.h new file mode 100644 index 000000000..6acdd8b05 --- /dev/null +++ b/server/shadow/Mac/mac_shadow.h @@ -0,0 +1,66 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-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 FREERDP_SHADOW_SERVER_MAC_H +#define FREERDP_SHADOW_SERVER_MAC_H + +#include + +typedef struct mac_shadow_subsystem macShadowSubsystem; + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct mac_shadow_subsystem +{ + RDP_SHADOW_SUBSYSTEM_COMMON(); + + int width; + int height; + BOOL retina; + int pixelWidth; + int pixelHeight; + BOOL mouseDownLeft; + BOOL mouseDownRight; + BOOL mouseDownOther; + BYTE* updateBuffer; + CGDisplayStreamRef stream; + dispatch_queue_t captureQueue; + CGDisplayStreamUpdateRef lastUpdate; +}; + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_MAC_H */ diff --git a/server/shadow/Win/win_dxgi.c b/server/shadow/Win/win_dxgi.c new file mode 100644 index 000000000..bd2f5d62b --- /dev/null +++ b/server/shadow/Win/win_dxgi.c @@ -0,0 +1,727 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "win_dxgi.h" + +#define TAG SERVER_TAG("shadow.win") + +#ifdef WITH_DXGI_1_2 + +static D3D_DRIVER_TYPE DriverTypes[] = +{ + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE, +}; + +static UINT NumDriverTypes = ARRAYSIZE(DriverTypes); + +static D3D_FEATURE_LEVEL FeatureLevels[] = +{ + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_1 +}; + +static UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels); + +static HMODULE d3d11_module = NULL; + +typedef HRESULT (WINAPI * fnD3D11CreateDevice)( + IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, + CONST D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, + ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext); + +static fnD3D11CreateDevice pfnD3D11CreateDevice = NULL; + +#undef DEFINE_GUID +#define INITGUID + +#include + +/* d3d11.h GUIDs */ + +DEFINE_GUID(IID_ID3D11DeviceChild,0x1841e5c8,0x16b0,0x489b,0xbc,0xc8,0x44,0xcf,0xb0,0xd5,0xde,0xae); +DEFINE_GUID(IID_ID3D11DepthStencilState,0x03823efb,0x8d8f,0x4e1c,0x9a,0xa2,0xf6,0x4b,0xb2,0xcb,0xfd,0xf1); +DEFINE_GUID(IID_ID3D11BlendState,0x75b68faa,0x347d,0x4159,0x8f,0x45,0xa0,0x64,0x0f,0x01,0xcd,0x9a); +DEFINE_GUID(IID_ID3D11RasterizerState,0x9bb4ab81,0xab1a,0x4d8f,0xb5,0x06,0xfc,0x04,0x20,0x0b,0x6e,0xe7); +DEFINE_GUID(IID_ID3D11Resource,0xdc8e63f3,0xd12b,0x4952,0xb4,0x7b,0x5e,0x45,0x02,0x6a,0x86,0x2d); +DEFINE_GUID(IID_ID3D11Buffer,0x48570b85,0xd1ee,0x4fcd,0xa2,0x50,0xeb,0x35,0x07,0x22,0xb0,0x37); +DEFINE_GUID(IID_ID3D11Texture1D,0xf8fb5c27,0xc6b3,0x4f75,0xa4,0xc8,0x43,0x9a,0xf2,0xef,0x56,0x4c); +DEFINE_GUID(IID_ID3D11Texture2D,0x6f15aaf2,0xd208,0x4e89,0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c); +DEFINE_GUID(IID_ID3D11Texture3D,0x037e866e,0xf56d,0x4357,0xa8,0xaf,0x9d,0xab,0xbe,0x6e,0x25,0x0e); +DEFINE_GUID(IID_ID3D11View,0x839d1216,0xbb2e,0x412b,0xb7,0xf4,0xa9,0xdb,0xeb,0xe0,0x8e,0xd1); +DEFINE_GUID(IID_ID3D11ShaderResourceView,0xb0e06fe0,0x8192,0x4e1a,0xb1,0xca,0x36,0xd7,0x41,0x47,0x10,0xb2); +DEFINE_GUID(IID_ID3D11RenderTargetView,0xdfdba067,0x0b8d,0x4865,0x87,0x5b,0xd7,0xb4,0x51,0x6c,0xc1,0x64); +DEFINE_GUID(IID_ID3D11DepthStencilView,0x9fdac92a,0x1876,0x48c3,0xaf,0xad,0x25,0xb9,0x4f,0x84,0xa9,0xb6); +DEFINE_GUID(IID_ID3D11UnorderedAccessView,0x28acf509,0x7f5c,0x48f6,0x86,0x11,0xf3,0x16,0x01,0x0a,0x63,0x80); +DEFINE_GUID(IID_ID3D11VertexShader,0x3b301d64,0xd678,0x4289,0x88,0x97,0x22,0xf8,0x92,0x8b,0x72,0xf3); +DEFINE_GUID(IID_ID3D11HullShader,0x8e5c6061,0x628a,0x4c8e,0x82,0x64,0xbb,0xe4,0x5c,0xb3,0xd5,0xdd); +DEFINE_GUID(IID_ID3D11DomainShader,0xf582c508,0x0f36,0x490c,0x99,0x77,0x31,0xee,0xce,0x26,0x8c,0xfa); +DEFINE_GUID(IID_ID3D11GeometryShader,0x38325b96,0xeffb,0x4022,0xba,0x02,0x2e,0x79,0x5b,0x70,0x27,0x5c); +DEFINE_GUID(IID_ID3D11PixelShader,0xea82e40d,0x51dc,0x4f33,0x93,0xd4,0xdb,0x7c,0x91,0x25,0xae,0x8c); +DEFINE_GUID(IID_ID3D11ComputeShader,0x4f5b196e,0xc2bd,0x495e,0xbd,0x01,0x1f,0xde,0xd3,0x8e,0x49,0x69); +DEFINE_GUID(IID_ID3D11InputLayout,0xe4819ddc,0x4cf0,0x4025,0xbd,0x26,0x5d,0xe8,0x2a,0x3e,0x07,0xb7); +DEFINE_GUID(IID_ID3D11SamplerState,0xda6fea51,0x564c,0x4487,0x98,0x10,0xf0,0xd0,0xf9,0xb4,0xe3,0xa5); +DEFINE_GUID(IID_ID3D11Asynchronous,0x4b35d0cd,0x1e15,0x4258,0x9c,0x98,0x1b,0x13,0x33,0xf6,0xdd,0x3b); +DEFINE_GUID(IID_ID3D11Query,0xd6c00747,0x87b7,0x425e,0xb8,0x4d,0x44,0xd1,0x08,0x56,0x0a,0xfd); +DEFINE_GUID(IID_ID3D11Predicate,0x9eb576dd,0x9f77,0x4d86,0x81,0xaa,0x8b,0xab,0x5f,0xe4,0x90,0xe2); +DEFINE_GUID(IID_ID3D11Counter,0x6e8c49fb,0xa371,0x4770,0xb4,0x40,0x29,0x08,0x60,0x22,0xb7,0x41); +DEFINE_GUID(IID_ID3D11ClassInstance,0xa6cd7faa,0xb0b7,0x4a2f,0x94,0x36,0x86,0x62,0xa6,0x57,0x97,0xcb); +DEFINE_GUID(IID_ID3D11ClassLinkage,0xddf57cba,0x9543,0x46e4,0xa1,0x2b,0xf2,0x07,0xa0,0xfe,0x7f,0xed); +DEFINE_GUID(IID_ID3D11CommandList,0xa24bc4d1,0x769e,0x43f7,0x80,0x13,0x98,0xff,0x56,0x6c,0x18,0xe2); +DEFINE_GUID(IID_ID3D11DeviceContext,0xc0bfa96c,0xe089,0x44fb,0x8e,0xaf,0x26,0xf8,0x79,0x61,0x90,0xda); +DEFINE_GUID(IID_ID3D11VideoDecoder,0x3C9C5B51,0x995D,0x48d1,0x9B,0x8D,0xFA,0x5C,0xAE,0xDE,0xD6,0x5C); +DEFINE_GUID(IID_ID3D11VideoProcessorEnumerator,0x31627037,0x53AB,0x4200,0x90,0x61,0x05,0xFA,0xA9,0xAB,0x45,0xF9); +DEFINE_GUID(IID_ID3D11VideoProcessor,0x1D7B0652,0x185F,0x41c6,0x85,0xCE,0x0C,0x5B,0xE3,0xD4,0xAE,0x6C); +DEFINE_GUID(IID_ID3D11AuthenticatedChannel,0x3015A308,0xDCBD,0x47aa,0xA7,0x47,0x19,0x24,0x86,0xD1,0x4D,0x4A); +DEFINE_GUID(IID_ID3D11CryptoSession,0x9B32F9AD,0xBDCC,0x40a6,0xA3,0x9D,0xD5,0xC8,0x65,0x84,0x57,0x20); +DEFINE_GUID(IID_ID3D11VideoDecoderOutputView,0xC2931AEA,0x2A85,0x4f20,0x86,0x0F,0xFB,0xA1,0xFD,0x25,0x6E,0x18); +DEFINE_GUID(IID_ID3D11VideoProcessorInputView,0x11EC5A5F,0x51DC,0x4945,0xAB,0x34,0x6E,0x8C,0x21,0x30,0x0E,0xA5); +DEFINE_GUID(IID_ID3D11VideoProcessorOutputView,0xA048285E,0x25A9,0x4527,0xBD,0x93,0xD6,0x8B,0x68,0xC4,0x42,0x54); +DEFINE_GUID(IID_ID3D11VideoContext,0x61F21C45,0x3C0E,0x4a74,0x9C,0xEA,0x67,0x10,0x0D,0x9A,0xD5,0xE4); +DEFINE_GUID(IID_ID3D11VideoDevice,0x10EC4D5B,0x975A,0x4689,0xB9,0xE4,0xD0,0xAA,0xC3,0x0F,0xE3,0x33); +DEFINE_GUID(IID_ID3D11Device,0xdb6f6ddb,0xac77,0x4e88,0x82,0x53,0x81,0x9d,0xf9,0xbb,0xf1,0x40); + +/* dxgi.h GUIDs */ + +DEFINE_GUID(IID_IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a, 0x2e); +DEFINE_GUID(IID_IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29, 0x92, 0xf1, 0xa6); +DEFINE_GUID(IID_IDXGIResource, 0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96, 0x0b); +DEFINE_GUID(IID_IDXGIKeyedMutex, 0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a, 0xf8, 0x5d); +DEFINE_GUID(IID_IDXGISurface, 0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60, 0xec); +DEFINE_GUID(IID_IDXGISurface1, 0x4AE63092, 0x6327, 0x4c1b, 0x80, 0xAE, 0xBF, 0xE1, 0x2E, 0xA3, 0x2B, 0x86); +DEFINE_GUID(IID_IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d, 0xc0); +DEFINE_GUID(IID_IDXGIOutput, 0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13, 0xaa); +DEFINE_GUID(IID_IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8, 0x88, 0x6a); +DEFINE_GUID(IID_IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69); +DEFINE_GUID(IID_IDXGIDevice, 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c); +DEFINE_GUID(IID_IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87); +DEFINE_GUID(IID_IDXGIAdapter1, 0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05); +DEFINE_GUID(IID_IDXGIDevice1, 0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c); + +/* dxgi1_2.h GUIDs */ + +DEFINE_GUID(IID_IDXGIDisplayControl, 0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38, 0xf3, 0x0c); +DEFINE_GUID(IID_IDXGIOutputDuplication, 0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4, 0x28, 0x31, 0x9c); +DEFINE_GUID(IID_IDXGISurface2, 0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f, 0xa2); +DEFINE_GUID(IID_IDXGIResource1, 0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e, 0xe0, 0xc1); +DEFINE_GUID(IID_IDXGIDevice2, 0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6, 0xa9); +DEFINE_GUID(IID_IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6, 0xf4, 0xaa); +DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0); +DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC, 0xB5); +DEFINE_GUID(IID_IDXGIOutput1, 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66, 0xcc); + +const char* GetDxgiErrorString(HRESULT hr) +{ + switch (hr) + { + case DXGI_STATUS_OCCLUDED: + return "DXGI_STATUS_OCCLUDED"; + case DXGI_STATUS_CLIPPED: + return "DXGI_STATUS_CLIPPED"; + case DXGI_STATUS_NO_REDIRECTION: + return "DXGI_STATUS_NO_REDIRECTION"; + case DXGI_STATUS_NO_DESKTOP_ACCESS: + return "DXGI_STATUS_NO_DESKTOP_ACCESS"; + case DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: + return "DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"; + case DXGI_STATUS_MODE_CHANGED: + return "DXGI_STATUS_MODE_CHANGED"; + case DXGI_STATUS_MODE_CHANGE_IN_PROGRESS: + return "DXGI_STATUS_MODE_CHANGE_IN_PROGRESS"; + case DXGI_ERROR_INVALID_CALL: + return "DXGI_ERROR_INVALID_CALL"; + case DXGI_ERROR_NOT_FOUND: + return "DXGI_ERROR_NOT_FOUND"; + case DXGI_ERROR_MORE_DATA: + return "DXGI_ERROR_MORE_DATA"; + case DXGI_ERROR_UNSUPPORTED: + return "DXGI_ERROR_UNSUPPORTED"; + case DXGI_ERROR_DEVICE_REMOVED: + return "DXGI_ERROR_DEVICE_REMOVED"; + case DXGI_ERROR_DEVICE_HUNG: + return "DXGI_ERROR_DEVICE_HUNG"; + case DXGI_ERROR_DEVICE_RESET: + return "DXGI_ERROR_DEVICE_RESET"; + case DXGI_ERROR_WAS_STILL_DRAWING: + return "DXGI_ERROR_WAS_STILL_DRAWING"; + case DXGI_ERROR_FRAME_STATISTICS_DISJOINT: + return "DXGI_ERROR_FRAME_STATISTICS_DISJOINT"; + case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE: + return "DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE"; + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + return "DXGI_ERROR_DRIVER_INTERNAL_ERROR"; + case DXGI_ERROR_NONEXCLUSIVE: + return "DXGI_ERROR_NONEXCLUSIVE"; + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE"; + case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED: + return "DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED"; + case DXGI_ERROR_REMOTE_OUTOFMEMORY: + return "DXGI_ERROR_REMOTE_OUTOFMEMORY"; + case DXGI_ERROR_ACCESS_LOST: + return "DXGI_ERROR_ACCESS_LOST"; + case DXGI_ERROR_WAIT_TIMEOUT: + return "DXGI_ERROR_WAIT_TIMEOUT"; + case DXGI_ERROR_SESSION_DISCONNECTED: + return "DXGI_ERROR_SESSION_DISCONNECTED"; + case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE: + return "DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE"; + case DXGI_ERROR_CANNOT_PROTECT_CONTENT: + return "DXGI_ERROR_CANNOT_PROTECT_CONTENT"; + case DXGI_ERROR_ACCESS_DENIED: + return "DXGI_ERROR_ACCESS_DENIED"; + case DXGI_ERROR_NAME_ALREADY_EXISTS: + return "DXGI_ERROR_NAME_ALREADY_EXISTS"; + case DXGI_ERROR_SDK_COMPONENT_MISSING: + return "DXGI_ERROR_SDK_COMPONENT_MISSING"; + case DXGI_STATUS_UNOCCLUDED: + return "DXGI_STATUS_UNOCCLUDED"; + case DXGI_STATUS_DDA_WAS_STILL_DRAWING: + return "DXGI_STATUS_DDA_WAS_STILL_DRAWING"; + case DXGI_ERROR_MODE_CHANGE_IN_PROGRESS: + return "DXGI_ERROR_MODE_CHANGE_IN_PROGRESS"; + case DXGI_DDI_ERR_WASSTILLDRAWING: + return "DXGI_DDI_ERR_WASSTILLDRAWING"; + case DXGI_DDI_ERR_UNSUPPORTED: + return "DXGI_DDI_ERR_UNSUPPORTED"; + case DXGI_DDI_ERR_NONEXCLUSIVE: + return "DXGI_DDI_ERR_NONEXCLUSIVE"; + case 0x80070005: + return "DXGI_ERROR_ACCESS_DENIED"; + } + + return "DXGI_ERROR_UNKNOWN"; +} + +static void win_shadow_d3d11_module_init() +{ + if (d3d11_module) + return; + + d3d11_module = LoadLibraryA("d3d11.dll"); + + if (!d3d11_module) + return; + + pfnD3D11CreateDevice = (fnD3D11CreateDevice) GetProcAddress(d3d11_module, "D3D11CreateDevice"); +} + +int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem) +{ + HRESULT hr; + UINT dTop, i = 0; + IDXGIOutput* pOutput; + DXGI_OUTPUT_DESC outputDesc; + DXGI_OUTPUT_DESC* pOutputDesc; + D3D11_TEXTURE2D_DESC textureDesc; + IDXGIDevice* dxgiDevice = NULL; + IDXGIAdapter* dxgiAdapter = NULL; + IDXGIOutput* dxgiOutput = NULL; + IDXGIOutput1* dxgiOutput1 = NULL; + + hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, + &IID_IDXGIDevice, (void**) &dxgiDevice); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**) &dxgiAdapter); + + if (dxgiDevice) + { + dxgiDevice->lpVtbl->Release(dxgiDevice); + dxgiDevice = NULL; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + pOutput = NULL; + ZeroMemory(&outputDesc, sizeof(outputDesc)); + + while (dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND) + { + pOutputDesc = &outputDesc; + + hr = pOutput->lpVtbl->GetDesc(pOutput, pOutputDesc); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutput::GetDesc failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + if (pOutputDesc->AttachedToDesktop) + dTop = i; + + pOutput->lpVtbl->Release(pOutput); + i++; + } + + dTop = 0; /* screen id */ + + hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, dTop, &dxgiOutput); + + if (dxgiAdapter) + { + dxgiAdapter->lpVtbl->Release(dxgiAdapter); + dxgiAdapter = NULL; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIAdapter::EnumOutputs failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + hr = dxgiOutput->lpVtbl->QueryInterface(dxgiOutput, &IID_IDXGIOutput1, (void**) &dxgiOutput1); + + if (dxgiOutput) + { + dxgiOutput->lpVtbl->Release(dxgiOutput); + dxgiOutput = NULL; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutput::QueryInterface(IDXGIOutput1) failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + hr = dxgiOutput1->lpVtbl->DuplicateOutput(dxgiOutput1, (IUnknown*) subsystem->dxgiDevice, + &(subsystem->dxgiOutputDuplication)); + + if (dxgiOutput1) + { + dxgiOutput1->lpVtbl->Release(dxgiOutput1); + dxgiOutput1 = NULL; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutput1::DuplicateOutput failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + textureDesc.Width = subsystem->width; + textureDesc.Height = subsystem->height; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_STAGING; + textureDesc.BindFlags = 0; + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.MiscFlags = 0; + + hr = subsystem->dxgiDevice->lpVtbl->CreateTexture2D(subsystem->dxgiDevice, + &textureDesc, NULL, &(subsystem->dxgiStage)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "ID3D11Device::CreateTexture2D failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + return 1; +} + +int win_shadow_dxgi_init(winShadowSubsystem* subsystem) +{ + UINT i = 0; + HRESULT hr; + int status; + UINT DriverTypeIndex; + IDXGIDevice* DxgiDevice = NULL; + IDXGIAdapter* DxgiAdapter = NULL; + IDXGIOutput* DxgiOutput = NULL; + IDXGIOutput1* DxgiOutput1 = NULL; + + win_shadow_d3d11_module_init(); + + if (!pfnD3D11CreateDevice) + return -1; + + for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex) + { + hr = pfnD3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, 0, FeatureLevels, + NumFeatureLevels, D3D11_SDK_VERSION, &(subsystem->dxgiDevice), &(subsystem->featureLevel), + &(subsystem->dxgiDeviceContext)); + + if (SUCCEEDED(hr)) + break; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "D3D11CreateDevice failure: 0x%04X", hr); + return -1; + } + + status = win_shadow_dxgi_init_duplication(subsystem); + + return status; +} + +int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem) +{ + if (subsystem->dxgiStage) + { + subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage); + subsystem->dxgiStage = NULL; + } + + if (subsystem->dxgiDesktopImage) + { + subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage); + subsystem->dxgiDesktopImage = NULL; + } + + if (subsystem->dxgiOutputDuplication) + { + subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication); + subsystem->dxgiOutputDuplication = NULL; + } + + if (subsystem->dxgiDeviceContext) + { + subsystem->dxgiDeviceContext->lpVtbl->Release(subsystem->dxgiDeviceContext); + subsystem->dxgiDeviceContext = NULL; + } + + if (subsystem->dxgiDevice) + { + subsystem->dxgiDevice->lpVtbl->Release(subsystem->dxgiDevice); + subsystem->dxgiDevice = NULL; + } + + return 1; +} + +int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, + BYTE** ppDstData, int* pnDstStep, int x, int y, int width, int height) +{ + int status; + HRESULT hr; + D3D11_BOX Box; + DXGI_MAPPED_RECT mappedRect; + + if ((width * height) < 1) + return 0; + + Box.top = x; + Box.left = y; + Box.right = x + width; + Box.bottom = y + height; + Box.front = 0; + Box.back = 1; + + subsystem->dxgiDeviceContext->lpVtbl->CopySubresourceRegion(subsystem->dxgiDeviceContext, + (ID3D11Resource*) subsystem->dxgiStage, 0, 0, 0, 0, (ID3D11Resource*) subsystem->dxgiDesktopImage, 0, &Box); + + hr = subsystem->dxgiStage->lpVtbl->QueryInterface(subsystem->dxgiStage, + &IID_IDXGISurface, (void**) &(subsystem->dxgiSurface)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%04X", + GetDxgiErrorString(hr), hr); + return -1; + } + + hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGISurface::Map failure: %s 0x%04X", + GetDxgiErrorString(hr), hr); + + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + win_shadow_dxgi_uninit(subsystem); + + status = win_shadow_dxgi_init(subsystem); + + if (status < 0) + return -1; + + return 0; + } + + return -1; + } + + subsystem->dxgiSurfaceMapped = TRUE; + + *ppDstData = mappedRect.pBits; + *pnDstStep = mappedRect.Pitch; + + return 1; +} + +int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem) +{ + if (subsystem->dxgiSurface) + { + if (subsystem->dxgiSurfaceMapped) + { + subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface); + subsystem->dxgiSurfaceMapped = FALSE; + } + + subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface); + subsystem->dxgiSurface = NULL; + } + + if (subsystem->dxgiOutputDuplication) + { + if (subsystem->dxgiFrameAcquired) + { + subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); + subsystem->dxgiFrameAcquired = FALSE; + } + } + + subsystem->pendingFrames = 0; + + return 1; +} + +int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem) +{ + UINT i = 0; + int status; + HRESULT hr = 0; + UINT timeout = 15; + UINT DataBufferSize = 0; + BYTE* DataBuffer = NULL; + + if (subsystem->dxgiFrameAcquired) + { + win_shadow_dxgi_release_frame_data(subsystem); + } + + if (subsystem->dxgiDesktopImage) + { + subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage); + subsystem->dxgiDesktopImage = NULL; + } + + hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(subsystem->dxgiOutputDuplication, + timeout, &(subsystem->dxgiFrameInfo), &(subsystem->dxgiResource)); + + if (SUCCEEDED(hr)) + { + subsystem->dxgiFrameAcquired = TRUE; + subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames; + } + + if (hr == DXGI_ERROR_WAIT_TIMEOUT) + return 0; + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + + if (hr == DXGI_ERROR_ACCESS_LOST) + { + win_shadow_dxgi_release_frame_data(subsystem); + + if (subsystem->dxgiDesktopImage) + { + subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage); + subsystem->dxgiDesktopImage = NULL; + } + + if (subsystem->dxgiOutputDuplication) + { + subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication); + subsystem->dxgiOutputDuplication = NULL; + } + + status = win_shadow_dxgi_init_duplication(subsystem); + + if (status < 0) + return -1; + + return 0; + } + else if (hr == DXGI_ERROR_INVALID_CALL) + { + win_shadow_dxgi_uninit(subsystem); + + status = win_shadow_dxgi_init(subsystem); + + if (status < 0) + return -1; + + return 0; + } + + return -1; + } + + hr = subsystem->dxgiResource->lpVtbl->QueryInterface(subsystem->dxgiResource, + &IID_ID3D11Texture2D, (void**) &(subsystem->dxgiDesktopImage)); + + if (subsystem->dxgiResource) + { + subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource); + subsystem->dxgiResource = NULL; + } + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%04X)", + GetDxgiErrorString(hr), hr); + return -1; + } + + return 1; +} + +int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) +{ + UINT i; + HRESULT hr; + POINT* pSrcPt; + RECT* pDstRect; + RECT* pDirtyRect; + UINT numMoveRects; + UINT numDirtyRects; + UINT UsedBufferSize; + RECTANGLE_16 invalidRect; + UINT MetadataBufferSize; + UINT MoveRectsBufferSize; + UINT DirtyRectsBufferSize; + RECT* pDirtyRectsBuffer; + DXGI_OUTDUPL_MOVE_RECT* pMoveRect; + DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer; + + if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0) + return 0; + + if (subsystem->dxgiFrameInfo.TotalMetadataBufferSize == 0) + return 0; + + MetadataBufferSize = subsystem->dxgiFrameInfo.TotalMetadataBufferSize; + + if (MetadataBufferSize > subsystem->MetadataBufferSize) + { + subsystem->MetadataBuffer = (BYTE*) realloc(subsystem->MetadataBuffer, MetadataBufferSize); + + if (!subsystem->MetadataBuffer) + return -1; + + subsystem->MetadataBufferSize = MetadataBufferSize; + } + + /* GetFrameMoveRects */ + + UsedBufferSize = 0; + + MoveRectsBufferSize = MetadataBufferSize - UsedBufferSize; + pMoveRectBuffer = (DXGI_OUTDUPL_MOVE_RECT*) &(subsystem->MetadataBuffer[UsedBufferSize]); + + hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameMoveRects(subsystem->dxgiOutputDuplication, + MoveRectsBufferSize, pMoveRectBuffer, &MoveRectsBufferSize); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%04X) Size: %d Total %d Used: %d", + GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize, UsedBufferSize); + return -1; + } + + /* GetFrameDirtyRects */ + + UsedBufferSize += MoveRectsBufferSize; + + DirtyRectsBufferSize = MetadataBufferSize - UsedBufferSize; + pDirtyRectsBuffer = (RECT*) &(subsystem->MetadataBuffer[UsedBufferSize]); + + hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameDirtyRects(subsystem->dxgiOutputDuplication, + DirtyRectsBufferSize, pDirtyRectsBuffer, &DirtyRectsBufferSize); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%04X) Size: %d Total %d Used: %d", + GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize, UsedBufferSize); + return -1; + } + + numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT); + + for (i = 0; i < numMoveRects; i++) + { + pMoveRect = &pMoveRectBuffer[i]; + pSrcPt = &(pMoveRect->SourcePoint); + pDstRect = &(pMoveRect->DestinationRect); + + invalidRect.left = (UINT16) pDstRect->left; + invalidRect.top = (UINT16) pDstRect->top; + invalidRect.right = (UINT16) pDstRect->right; + invalidRect.bottom = (UINT16) pDstRect->bottom; + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + } + + numDirtyRects = DirtyRectsBufferSize / sizeof(RECT); + + for (i = 0; i < numDirtyRects; i++) + { + pDirtyRect = &pDirtyRectsBuffer[i]; + + invalidRect.left = (UINT16) pDirtyRect->left; + invalidRect.top = (UINT16) pDirtyRect->top; + invalidRect.right = (UINT16) pDirtyRect->right; + invalidRect.bottom = (UINT16) pDirtyRect->bottom; + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + } + + return 1; +} + +#endif diff --git a/server/shadow/Win/win_dxgi.h b/server/shadow/Win/win_dxgi.h new file mode 100644 index 000000000..1dcdf7ac8 --- /dev/null +++ b/server/shadow/Win/win_dxgi.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_WIN_DXGI_H +#define FREERDP_SHADOW_SERVER_WIN_DXGI_H + +#if _WIN32_WINNT >= 0x0602 +//#define WITH_DXGI_1_2 1 +#endif + +#ifdef WITH_DXGI_1_2 + +#ifndef CINTERFACE +#define CINTERFACE +#endif + +#include +#include + +#endif + +#include "win_shadow.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WITH_DXGI_1_2 + +int win_shadow_dxgi_init(winShadowSubsystem* subsystem); +int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem); + +int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, + BYTE** ppDstData, int* pnDstStep, int x, int y, int width, int height); + +int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem); +int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_WIN_DXGI_H */ diff --git a/server/shadow/Win/win_rdp.c b/server/shadow/Win/win_rdp.c new file mode 100644 index 000000000..55f7382f0 --- /dev/null +++ b/server/shadow/Win/win_rdp.c @@ -0,0 +1,431 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "win_rdp.h" + +#define TAG SERVER_TAG("shadow.win") + +void shw_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) +{ + shwContext* shw = (shwContext*) context; + + WLog_INFO(TAG, "OnChannelConnected: %s", e->name); +} + +void shw_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) +{ + shwContext* shw = (shwContext*) context; + + WLog_INFO(TAG, "OnChannelDisconnected: %s", e->name); +} + +void shw_begin_paint(rdpContext* context) +{ + shwContext* shw; + rdpGdi* gdi = context->gdi; + + shw = (shwContext*) context; + + gdi->primary->hdc->hwnd->invalid->null = 1; + gdi->primary->hdc->hwnd->ninvalid = 0; +} + +void shw_end_paint(rdpContext* context) +{ + int index; + int ninvalid; + HGDI_RGN cinvalid; + RECTANGLE_16 invalidRect; + rdpGdi* gdi = context->gdi; + shwContext* shw = (shwContext*) context; + winShadowSubsystem* subsystem = shw->subsystem; + + ninvalid = gdi->primary->hdc->hwnd->ninvalid; + cinvalid = gdi->primary->hdc->hwnd->cinvalid; + + for (index = 0; index < ninvalid; index++) + { + invalidRect.left = cinvalid[index].x; + invalidRect.top = cinvalid[index].y; + invalidRect.right = cinvalid[index].x + cinvalid[index].w; + invalidRect.bottom = cinvalid[index].y + cinvalid[index].h; + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + } + + SetEvent(subsystem->RdpUpdateEnterEvent); + WaitForSingleObject(subsystem->RdpUpdateLeaveEvent, INFINITE); + ResetEvent(subsystem->RdpUpdateLeaveEvent); +} + +void shw_desktop_resize(rdpContext* context) +{ + +} + +void shw_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surfaceFrameMarker) +{ + shwContext* shw = (shwContext*) context; +} + +BOOL shw_authenticate(freerdp* instance, char** username, char** password, char** domain) +{ + return TRUE; +} + +BOOL shw_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +{ + return TRUE; +} + +int shw_verify_x509_certificate(freerdp* instance, BYTE* data, int length, const char* hostname, int port, DWORD flags) +{ + return 1; +} + +void shw_OnConnectionResultEventHandler(rdpContext* context, ConnectionResultEventArgs* e) +{ + shwContext* shw = (shwContext*) context; + WLog_INFO(TAG, "OnConnectionResult: %d", e->result); +} + +BOOL shw_pre_connect(freerdp* instance) +{ + shwContext* shw; + rdpContext* context = instance->context; + + shw = (shwContext*) context; + + PubSub_SubscribeConnectionResult(context->pubSub, + (pConnectionResultEventHandler) shw_OnConnectionResultEventHandler); + + PubSub_SubscribeChannelConnected(context->pubSub, + (pChannelConnectedEventHandler) shw_OnChannelConnectedEventHandler); + + PubSub_SubscribeChannelDisconnected(context->pubSub, + (pChannelDisconnectedEventHandler) shw_OnChannelDisconnectedEventHandler); + + freerdp_client_load_addins(context->channels, instance->settings); + + freerdp_channels_pre_connect(context->channels, instance); + + return TRUE; +} + +BOOL shw_post_connect(freerdp* instance) +{ + rdpGdi* gdi; + shwContext* shw; + rdpSettings* settings; + + shw = (shwContext*) instance->context; + settings = instance->settings; + + gdi_init(instance, CLRBUF_32BPP, NULL); + gdi = instance->context->gdi; + + instance->update->BeginPaint = shw_begin_paint; + instance->update->EndPaint = shw_end_paint; + instance->update->DesktopResize = shw_desktop_resize; + instance->update->SurfaceFrameMarker = shw_surface_frame_marker; + + freerdp_channels_post_connect(instance->context->channels, instance); + + return TRUE; +} + +void* shw_client_thread(void* arg) +{ + int index; + int rcount; + int wcount; + BOOL bSuccess; + void* rfds[32]; + void* wfds[32]; + int fds_count; + HANDLE fds[64]; + shwContext* shw; + rdpContext* context; + rdpChannels* channels; + freerdp* instance = (freerdp*) arg; + + ZeroMemory(rfds, sizeof(rfds)); + ZeroMemory(wfds, sizeof(wfds)); + + context = (rdpContext*) instance->context; + shw = (shwContext*) context; + + bSuccess = freerdp_connect(instance); + + WLog_INFO(TAG, "freerdp_connect: %d", bSuccess); + + if (!bSuccess) + { + ExitThread(0); + return NULL; + } + + channels = instance->context->channels; + + while (1) + { + rcount = 0; + wcount = 0; + + if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount)) + { + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); + break; + } + + if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount)) + { + WLog_ERR(TAG, "Failed to get channels file descriptor"); + break; + } + + fds_count = 0; + + for (index = 0; index < rcount; index++) + fds[fds_count++] = rfds[index]; + + for (index = 0; index < wcount; index++) + fds[fds_count++] = wfds[index]; + + if (MsgWaitForMultipleObjects(fds_count, fds, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED) + { + WLog_ERR(TAG, "MsgWaitForMultipleObjects failure: 0x%08X", GetLastError()); + break; + } + + if (!freerdp_check_fds(instance)) + { + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); + break; + } + + if (freerdp_shall_disconnect(instance)) + { + break; + } + + if (!freerdp_channels_check_fds(channels, instance)) + { + WLog_ERR(TAG, "Failed to check channels file descriptor"); + break; + } + } + + freerdp_free(instance); + + ExitThread(0); + return NULL; +} + +/** + * Client Interface + */ + +void shw_freerdp_client_global_init(void) +{ + +} + +void shw_freerdp_client_global_uninit(void) +{ + +} + +int shw_freerdp_client_start(rdpContext* context) +{ + shwContext* shw; + freerdp* instance = context->instance; + + shw = (shwContext*) context; + + shw->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) shw_client_thread, + instance, 0, NULL); + + return 0; +} + +int shw_freerdp_client_stop(rdpContext* context) +{ + shwContext* shw = (shwContext*) context; + + SetEvent(shw->StopEvent); + + return 0; +} + +int shw_freerdp_client_new(freerdp* instance, rdpContext* context) +{ + shwContext* shw; + rdpSettings* settings; + + shw = (shwContext*) instance->context; + + instance->PreConnect = shw_pre_connect; + instance->PostConnect = shw_post_connect; + instance->Authenticate = shw_authenticate; + instance->VerifyCertificate = shw_verify_certificate; + instance->VerifyX509Certificate = shw_verify_x509_certificate; + + context->channels = freerdp_channels_new(); + + shw->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + settings = instance->settings; + shw->settings = instance->context->settings; + + settings->AsyncTransport = FALSE; + settings->AsyncChannels = FALSE; + settings->AsyncUpdate = FALSE; + settings->AsyncInput = FALSE; + + settings->IgnoreCertificate = TRUE; + settings->ExternalCertificateManagement = TRUE; + + settings->RdpSecurity = TRUE; + settings->TlsSecurity = TRUE; + settings->NlaSecurity = FALSE; + + settings->BitmapCacheEnabled = FALSE; + settings->BitmapCacheV3Enabled = FALSE; + settings->OffscreenSupportLevel = FALSE; + settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE; + settings->BrushSupportLevel = FALSE; + + ZeroMemory(settings->OrderSupport, 32); + + settings->FrameMarkerCommandEnabled = TRUE; + settings->SurfaceFrameMarkerEnabled = TRUE; + settings->AltSecFrameMarkerSupport = TRUE; + + settings->ColorDepth = 32; + settings->NSCodec = TRUE; + settings->RemoteFxCodec = TRUE; + settings->FastPathInput = TRUE; + settings->FastPathOutput = TRUE; + settings->LargePointerFlag = TRUE; + + settings->CompressionEnabled = FALSE; + + settings->AutoReconnectionEnabled = FALSE; + settings->NetworkAutoDetect = FALSE; + settings->SupportHeartbeatPdu = FALSE; + settings->SupportMultitransport = FALSE; + settings->ConnectionType = CONNECTION_TYPE_LAN; + + settings->AllowFontSmoothing = TRUE; + settings->AllowDesktopComposition = TRUE; + settings->DisableWallpaper = FALSE; + settings->DisableFullWindowDrag = TRUE; + settings->DisableMenuAnims = TRUE; + settings->DisableThemes = FALSE; + + settings->DeviceRedirection = TRUE; + settings->RedirectClipboard = TRUE; + settings->SupportDynamicChannels = TRUE; + + return 0; +} + +void shw_freerdp_client_free(freerdp* instance, rdpContext* context) +{ + shwContext* shw = (shwContext*) instance->context; +} + +int shw_RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) +{ + pEntryPoints->Version = 1; + pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); + + pEntryPoints->settings = NULL; + + pEntryPoints->ContextSize = sizeof(shwContext); + pEntryPoints->GlobalInit = shw_freerdp_client_global_init; + pEntryPoints->GlobalUninit = shw_freerdp_client_global_uninit; + pEntryPoints->ClientNew = shw_freerdp_client_new; + pEntryPoints->ClientFree = shw_freerdp_client_free; + pEntryPoints->ClientStart = shw_freerdp_client_start; + pEntryPoints->ClientStop = shw_freerdp_client_stop; + + return 0; +} + +int win_shadow_rdp_init(winShadowSubsystem* subsystem) +{ + rdpContext* context; + RDP_CLIENT_ENTRY_POINTS clientEntryPoints; + + ZeroMemory(&clientEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); + clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS); + clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION; + + shw_RdpClientEntry(&clientEntryPoints); + + context = freerdp_client_context_new(&clientEntryPoints); + + subsystem->shw = (shwContext*) context; + subsystem->shw->settings = context->settings; + subsystem->shw->subsystem = subsystem; + + subsystem->RdpUpdateEnterEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + subsystem->RdpUpdateLeaveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + return 1; +} + +int win_shadow_rdp_start(winShadowSubsystem* subsystem) +{ + int status; + shwContext* shw = subsystem->shw; + rdpContext* context = (rdpContext*) shw; + + status = freerdp_client_start(context); + + return status; +} + +int win_shadow_rdp_stop(winShadowSubsystem* subsystem) +{ + int status; + shwContext* shw = subsystem->shw; + rdpContext* context = (rdpContext*) shw; + + status = freerdp_client_stop(context); + + return status; +} + +int win_shadow_rdp_uninit(winShadowSubsystem* subsystem) +{ + win_shadow_rdp_stop(subsystem); + + return 1; +} diff --git a/server/shadow/Win/win_rdp.h b/server/shadow/Win/win_rdp.h new file mode 100644 index 000000000..e48d46e6b --- /dev/null +++ b/server/shadow/Win/win_rdp.h @@ -0,0 +1,56 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_WIN_RDP_H +#define FREERDP_SHADOW_SERVER_WIN_RDP_H + +#include +#include +#include +#include + +typedef struct shw_context shwContext; + +#include "win_shadow.h" + +struct shw_context +{ + rdpContext context; + DEFINE_RDP_CLIENT_COMMON(); + + HANDLE StopEvent; + freerdp* instance; + rdpSettings* settings; + winShadowSubsystem* subsystem; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int win_shadow_rdp_init(winShadowSubsystem* subsystem); +int win_shadow_rdp_uninit(winShadowSubsystem* subsystem); + +int win_shadow_rdp_start(winShadowSubsystem* subsystem); +int win_shadow_rdp_stop(winShadowSubsystem* subsystem); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_WIN_RDP_H */ diff --git a/server/shadow/Win/win_shadow.c b/server/shadow/Win/win_shadow.c new file mode 100644 index 000000000..b70b61f79 --- /dev/null +++ b/server/shadow/Win/win_shadow.c @@ -0,0 +1,545 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-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. + */ + +#include +#include +#include + +#include +#include +#include + +#include "../shadow_screen.h" +#include "../shadow_surface.h" +#include "../shadow_capture.h" +#include "../shadow_subsystem.h" + +#include "win_shadow.h" + +#define TAG SERVER_TAG("shadow.win") + +void win_shadow_input_synchronize_event(winShadowSubsystem* subsystem, UINT32 flags) +{ + +} + +void win_shadow_input_keyboard_event(winShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ + INPUT event; + + event.type = INPUT_KEYBOARD; + event.ki.wVk = 0; + event.ki.wScan = code; + event.ki.dwFlags = KEYEVENTF_SCANCODE; + event.ki.dwExtraInfo = 0; + event.ki.time = 0; + + if (flags & KBD_FLAGS_RELEASE) + event.ki.dwFlags |= KEYEVENTF_KEYUP; + + if (flags & KBD_FLAGS_EXTENDED) + event.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; + + SendInput(1, &event, sizeof(INPUT)); +} + +void win_shadow_input_unicode_keyboard_event(winShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ + INPUT event; + + event.type = INPUT_KEYBOARD; + event.ki.wVk = 0; + event.ki.wScan = code; + event.ki.dwFlags = KEYEVENTF_UNICODE; + event.ki.dwExtraInfo = 0; + event.ki.time = 0; + + if (flags & KBD_FLAGS_RELEASE) + event.ki.dwFlags |= KEYEVENTF_KEYUP; + + SendInput(1, &event, sizeof(INPUT)); +} + +void win_shadow_input_mouse_event(winShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ + INPUT event; + float width; + float height; + + ZeroMemory(&event, sizeof(INPUT)); + + event.type = INPUT_MOUSE; + + if (flags & PTR_FLAGS_WHEEL) + { + event.mi.dwFlags = MOUSEEVENTF_WHEEL; + event.mi.mouseData = flags & WheelRotationMask; + + if (flags & PTR_FLAGS_WHEEL_NEGATIVE) + event.mi.mouseData *= -1; + + SendInput(1, &event, sizeof(INPUT)); + } + else + { + width = (float) GetSystemMetrics(SM_CXSCREEN); + height = (float) GetSystemMetrics(SM_CYSCREEN); + + event.mi.dx = (LONG) ((float) x * (65535.0f / width)); + event.mi.dy = (LONG) ((float) y * (65535.0f / height)); + event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE; + + if (flags & PTR_FLAGS_MOVE) + { + event.mi.dwFlags |= MOUSEEVENTF_MOVE; + SendInput(1, &event, sizeof(INPUT)); + } + + event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE; + + if (flags & PTR_FLAGS_BUTTON1) + { + if (flags & PTR_FLAGS_DOWN) + event.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; + else + event.mi.dwFlags |= MOUSEEVENTF_LEFTUP; + + SendInput(1, &event, sizeof(INPUT)); + } + else if (flags & PTR_FLAGS_BUTTON2) + { + if (flags & PTR_FLAGS_DOWN) + event.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN; + else + event.mi.dwFlags |= MOUSEEVENTF_RIGHTUP; + + SendInput(1, &event, sizeof(INPUT)); + } + else if (flags & PTR_FLAGS_BUTTON3) + { + if (flags & PTR_FLAGS_DOWN) + event.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN; + else + event.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP; + + SendInput(1, &event, sizeof(INPUT)); + } + } +} + +void win_shadow_input_extended_mouse_event(winShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ + INPUT event; + float width; + float height; + + ZeroMemory(&event, sizeof(INPUT)); + + if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2)) + { + event.type = INPUT_MOUSE; + + if (flags & PTR_FLAGS_MOVE) + { + width = (float) GetSystemMetrics(SM_CXSCREEN); + height = (float) GetSystemMetrics(SM_CYSCREEN); + + event.mi.dx = (LONG)((float) x * (65535.0f / width)); + event.mi.dy = (LONG)((float) y * (65535.0f / height)); + event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; + + SendInput(1, &event, sizeof(INPUT)); + } + + event.mi.dx = event.mi.dy = event.mi.dwFlags = 0; + + if (flags & PTR_XFLAGS_DOWN) + event.mi.dwFlags |= MOUSEEVENTF_XDOWN; + else + event.mi.dwFlags |= MOUSEEVENTF_XUP; + + if (flags & PTR_XFLAGS_BUTTON1) + event.mi.mouseData = XBUTTON1; + else if (flags & PTR_XFLAGS_BUTTON2) + event.mi.mouseData = XBUTTON2; + + SendInput(1, &event, sizeof(INPUT)); + } +} + + +int win_shadow_invalidate_region(winShadowSubsystem* subsystem, int x, int y, int width, int height) +{ + rdpShadowServer* server; + rdpShadowScreen* screen; + RECTANGLE_16 invalidRect; + + server = subsystem->server; + screen = server->screen; + + invalidRect.left = x; + invalidRect.top = y; + invalidRect.right = x + width; + invalidRect.bottom = y + height; + + EnterCriticalSection(&(screen->lock)); + region16_union_rect(&(screen->invalidRegion), &(screen->invalidRegion), &invalidRect); + LeaveCriticalSection(&(screen->lock)); + + return 1; +} + +int win_shadow_surface_copy(winShadowSubsystem* subsystem) +{ + int x, y; + int width; + int height; + int count; + int status = 1; + int nDstStep = 0; + BYTE* pDstData = NULL; + rdpShadowServer* server; + rdpShadowSurface* surface; + RECTANGLE_16 surfaceRect; + RECTANGLE_16 invalidRect; + const RECTANGLE_16* extents; + + server = subsystem->server; + surface = server->surface; + + if (ArrayList_Count(server->clients) < 1) + { + region16_clear(&(subsystem->invalidRegion)); + return 1; + } + + surfaceRect.left = surface->x; + surfaceRect.top = surface->y; + surfaceRect.right = surface->x + surface->width; + surfaceRect.bottom = surface->y + surface->height; + + region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + + if (region16_is_empty(&(subsystem->invalidRegion))) + return 1; + + extents = region16_extents(&(subsystem->invalidRegion)); + CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16)); + + shadow_capture_align_clip_rect(&invalidRect, &surfaceRect); + + x = invalidRect.left; + y = invalidRect.top; + width = invalidRect.right - invalidRect.left; + height = invalidRect.bottom - invalidRect.top; + + if (0) + { + x = 0; + y = 0; + width = surface->width; + height = surface->height; + } + + WLog_INFO(TAG, "SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d", + x, y, width, height, x + width, y + height); + +#if defined(WITH_WDS_API) + { + rdpGdi* gdi; + shwContext* shw; + rdpContext* context; + + shw = subsystem->shw; + context = (rdpContext*) shw; + gdi = context->gdi; + + pDstData = gdi->primary_buffer; + nDstStep = gdi->width * 4; + } +#elif defined(WITH_DXGI_1_2) + status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height); +#endif + + if (status <= 0) + return status; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x - surface->x, y - surface->y, width, height, + pDstData, PIXEL_FORMAT_XRGB32, nDstStep, 0, 0, NULL); + + ArrayList_Lock(server->clients); + + count = ArrayList_Count(server->clients); + + InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); + + SetEvent(subsystem->updateEvent); + + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + ResetEvent(subsystem->updateEvent); + + DeleteSynchronizationBarrier(&(subsystem->barrier)); + + ArrayList_Unlock(server->clients); + + region16_clear(&(subsystem->invalidRegion)); + + return 1; +} + +#if defined(WITH_WDS_API) + +void* win_shadow_subsystem_thread(winShadowSubsystem* subsystem) +{ + DWORD status; + DWORD nCount; + HANDLE events[32]; + HANDLE StopEvent; + + StopEvent = subsystem->server->StopEvent; + + nCount = 0; + events[nCount++] = StopEvent; + events[nCount++] = subsystem->RdpUpdateEnterEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (WaitForSingleObject(subsystem->RdpUpdateEnterEvent, 0) == WAIT_OBJECT_0) + { + win_shadow_surface_copy(subsystem); + ResetEvent(subsystem->RdpUpdateEnterEvent); + SetEvent(subsystem->RdpUpdateLeaveEvent); + } + } + + ExitThread(0); + return NULL; +} + +#elif defined(WITH_DXGI_1_2) + +void* win_shadow_subsystem_thread(winShadowSubsystem* subsystem) +{ + int fps; + DWORD status; + DWORD nCount; + UINT64 cTime; + DWORD dwTimeout; + DWORD dwInterval; + UINT64 frameTime; + HANDLE events[32]; + HANDLE StopEvent; + + StopEvent = subsystem->server->StopEvent; + + nCount = 0; + events[nCount++] = StopEvent; + + fps = 16; + dwInterval = 1000 / fps; + frameTime = GetTickCount64() + dwInterval; + + while (1) + { + dwTimeout = INFINITE; + + cTime = GetTickCount64(); + dwTimeout = (DWORD) ((cTime > frameTime) ? 0 : frameTime - cTime); + + status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout); + + if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) + { + int dxgi_status; + + dxgi_status = win_shadow_dxgi_get_next_frame(subsystem); + + if (dxgi_status > 0) + dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem); + + if (dxgi_status > 0) + win_shadow_surface_copy(subsystem); + + dwInterval = 1000 / fps; + frameTime += dwInterval; + } + } + + ExitThread(0); + return NULL; +} + +#endif + +int win_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors) +{ + HDC hdc; + int index; + int desktopWidth; + int desktopHeight; + DWORD iDevNum = 0; + int numMonitors = 0; + MONITOR_DEF* monitor; + MONITOR_DEF* virtualScreen; + DISPLAY_DEVICE displayDevice; + + ZeroMemory(&displayDevice, sizeof(DISPLAY_DEVICE)); + displayDevice.cb = sizeof(DISPLAY_DEVICE); + + if (EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0)) + { + hdc = CreateDC(displayDevice.DeviceName, NULL, NULL, NULL); + + desktopWidth = GetDeviceCaps(hdc, HORZRES); + desktopHeight = GetDeviceCaps(hdc, VERTRES); + + index = 0; + numMonitors = 1; + + monitor = &monitors[index]; + + monitor->left = 0; + monitor->top = 0; + monitor->right = desktopWidth; + monitor->bottom = desktopHeight; + monitor->flags = 1; + + DeleteDC(hdc); + } + + return numMonitors; +} + +int win_shadow_subsystem_init(winShadowSubsystem* subsystem) +{ + int status; + MONITOR_DEF* virtualScreen; + + subsystem->numMonitors = win_shadow_enum_monitors(subsystem->monitors, 16); + +#if defined(WITH_WDS_API) + status = win_shadow_wds_init(subsystem); +#elif defined(WITH_DXGI_1_2) + status = win_shadow_dxgi_init(subsystem); +#endif + + virtualScreen = &(subsystem->virtualScreen); + + virtualScreen->left = 0; + virtualScreen->top = 0; + virtualScreen->right = subsystem->width; + virtualScreen->bottom = subsystem->height; + virtualScreen->flags = 1; + + WLog_INFO(TAG, "width: %d height: %d", subsystem->width, subsystem->height); + + return 1; +} + +int win_shadow_subsystem_uninit(winShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + +#if defined(WITH_WDS_API) + win_shadow_wds_uninit(subsystem); +#elif defined(WITH_DXGI_1_2) + win_shadow_dxgi_uninit(subsystem); +#endif + + return 1; +} + +int win_shadow_subsystem_start(winShadowSubsystem* subsystem) +{ + HANDLE thread; + + if (!subsystem) + return -1; + + thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) win_shadow_subsystem_thread, + (void*) subsystem, 0, NULL); + + return 1; +} + +int win_shadow_subsystem_stop(winShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + return 1; +} + +void win_shadow_subsystem_free(winShadowSubsystem* subsystem) +{ + if (!subsystem) + return; + + win_shadow_subsystem_uninit(subsystem); + + free(subsystem); +} + +winShadowSubsystem* win_shadow_subsystem_new() +{ + winShadowSubsystem* subsystem; + + subsystem = (winShadowSubsystem*) calloc(1, sizeof(winShadowSubsystem)); + + if (!subsystem) + return NULL; + + subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) win_shadow_input_synchronize_event; + subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) win_shadow_input_keyboard_event; + subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) win_shadow_input_unicode_keyboard_event; + subsystem->MouseEvent = (pfnShadowMouseEvent) win_shadow_input_mouse_event; + subsystem->ExtendedMouseEvent = (pfnShadowExtendedMouseEvent) win_shadow_input_extended_mouse_event; + + return subsystem; +} + +int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +{ + pEntryPoints->New = (pfnShadowSubsystemNew) win_shadow_subsystem_new; + pEntryPoints->Free = (pfnShadowSubsystemFree) win_shadow_subsystem_free; + + pEntryPoints->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init; + pEntryPoints->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit; + + pEntryPoints->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start; + pEntryPoints->Stop = (pfnShadowSubsystemStop) win_shadow_subsystem_stop; + + pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) win_shadow_enum_monitors; + + return 1; +} diff --git a/server/shadow/Win/win_shadow.h b/server/shadow/Win/win_shadow.h new file mode 100644 index 000000000..c403bd6f1 --- /dev/null +++ b/server/shadow/Win/win_shadow.h @@ -0,0 +1,90 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-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 FREERDP_SHADOW_SERVER_WIN_H +#define FREERDP_SHADOW_SERVER_WIN_H + +#include + +#include + +typedef struct win_shadow_subsystem winShadowSubsystem; + +#include +#include +#include +#include +#include + +#include "win_rdp.h" +#include "win_wds.h" +#include "win_dxgi.h" + +struct win_shadow_subsystem +{ + RDP_SHADOW_SUBSYSTEM_COMMON(); + + int bpp; + int width; + int height; + +#ifdef WITH_WDS_API + HWND hWnd; + shwContext* shw; + HANDLE RdpUpdateEnterEvent; + HANDLE RdpUpdateLeaveEvent; + rdpAssistanceFile* pAssistanceFile; + _IRDPSessionEvents* pSessionEvents; + IRDPSRAPISharingSession* pSharingSession; + IRDPSRAPIInvitation* pInvitation; + IRDPSRAPIInvitationManager* pInvitationMgr; + IRDPSRAPISessionProperties* pSessionProperties; + IRDPSRAPIVirtualChannelManager* pVirtualChannelMgr; + IRDPSRAPIApplicationFilter* pApplicationFilter; + IRDPSRAPIAttendeeManager* pAttendeeMgr; +#endif + +#ifdef WITH_DXGI_1_2 + UINT pendingFrames; + BYTE* MetadataBuffer; + UINT MetadataBufferSize; + BOOL dxgiSurfaceMapped; + BOOL dxgiFrameAcquired; + ID3D11Device* dxgiDevice; + IDXGISurface* dxgiSurface; + ID3D11Texture2D* dxgiStage; + IDXGIResource* dxgiResource; + D3D_FEATURE_LEVEL featureLevel; + ID3D11Texture2D* dxgiDesktopImage; + DXGI_OUTDUPL_FRAME_INFO dxgiFrameInfo; + ID3D11DeviceContext* dxgiDeviceContext; + IDXGIOutputDuplication* dxgiOutputDuplication; +#endif +}; + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_WIN_H */ diff --git a/server/shadow/Win/win_wds.c b/server/shadow/Win/win_wds.c new file mode 100644 index 000000000..1ec82172f --- /dev/null +++ b/server/shadow/Win/win_wds.c @@ -0,0 +1,885 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "win_rdp.h" + +#include "win_wds.h" + +/** + * Windows Desktop Sharing API: + * http://blogs.msdn.com/b/rds/archive/2007/03/08/windows-desktop-sharing-api.aspx + * + * Windows Desktop Sharing Interfaces: + * http://msdn.microsoft.com/en-us/library/aa373871%28v=vs.85%29.aspx + * + * Offer Remote Assistance Sample C: + * http://msdn.microsoft.com/en-us/library/ms811079.aspx#remoteassistanceapi_topic2b + * + * Remote Assistance in XP: Programmatically establish an RDP session: + * http://www.codeproject.com/Articles/29939/Remote-Assistance-in-XP-Programmatically-establish + */ + +#undef DEFINE_GUID +#define INITGUID + +#include + +#define TAG SERVER_TAG("shadow.win") + +DEFINE_GUID(CLSID_RDPSession,0x9B78F0E6,0x3E05,0x4A5B,0xB2,0xE8,0xE7,0x43,0xA8,0x95,0x6B,0x65); +DEFINE_GUID(DIID__IRDPSessionEvents,0x98a97042,0x6698,0x40e9,0x8e,0xfd,0xb3,0x20,0x09,0x90,0x00,0x4b); +DEFINE_GUID(IID_IRDPSRAPISharingSession,0xeeb20886,0xe470,0x4cf6,0x84,0x2b,0x27,0x39,0xc0,0xec,0x5c,0xfb); +DEFINE_GUID(IID_IRDPSRAPIAttendee,0xec0671b3,0x1b78,0x4b80,0xa4,0x64,0x91,0x32,0x24,0x75,0x43,0xe3); +DEFINE_GUID(IID_IRDPSRAPIAttendeeManager,0xba3a37e8,0x33da,0x4749,0x8d,0xa0,0x07,0xfa,0x34,0xda,0x79,0x44); +DEFINE_GUID(IID_IRDPSRAPISessionProperties,0x339b24f2,0x9bc0,0x4f16,0x9a,0xac,0xf1,0x65,0x43,0x3d,0x13,0xd4); +DEFINE_GUID(CLSID_RDPSRAPIApplicationFilter,0xe35ace89,0xc7e8,0x427e,0xa4,0xf9,0xb9,0xda,0x07,0x28,0x26,0xbd); +DEFINE_GUID(CLSID_RDPSRAPIInvitationManager,0x53d9c9db,0x75ab,0x4271,0x94,0x8a,0x4c,0x4e,0xb3,0x6a,0x8f,0x2b); + +static ULONG Shadow_IRDPSessionEvents_RefCount = 0; + +const char* GetRDPSessionEventString(DISPID id) +{ + switch (id) + { + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED: + return "OnAttendeeConnected"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED: + return "OnAttendeeDisconnected"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE: + return "OnAttendeeUpdate"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_ERROR: + return "OnError"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED: + return "OnConnectionEstablished"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED: + return "OnConnectionTerminated"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED: + return "OnConnectionAuthenticated"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED: + return "OnConnectionFailed"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST: + return "OnControlLevelChangeRequest"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED: + return "OnGraphicsStreamPaused"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED: + return "OnGraphicsStreamResumed"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN: + return "OnChannelJoin"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE: + return "OnChannelLeave"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED: + return "OnChannelDataReceived"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED: + return "OnChannelDataSent"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN: + return "OnApplicationOpen"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE: + return "OnApplicationClose"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE: + return "OnApplicationUpdate"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN: + return "OnWindowOpen"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE: + return "OnWindowClose"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE: + return "OnWindowUpdate"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE: + return "OnAppFilterUpdate"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED: + return "OnSharedRectChanged"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED: + return "OnFocusReleased"; + break; + + case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED: + return "OnSharedDesktopSettingsChanged"; + break; + + case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED: + return "OnViewingSizeChanged"; + break; + } + + return "OnUnknown"; +} + +static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_QueryInterface( + __RPC__in _IRDPSessionEvents * This, + /* [in] */ __RPC__in REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject) +{ + *ppvObject = NULL; + + if (IsEqualIID(riid, &DIID__IRDPSessionEvents) || + IsEqualIID(riid, &IID_IDispatch) || IsEqualIID(riid, &IID_IUnknown)) + { + *ppvObject = This; + } + + if (!(*ppvObject)) + return E_NOINTERFACE; + + This->lpVtbl->AddRef(This); + + return S_OK; +} + +static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_AddRef( + __RPC__in _IRDPSessionEvents * This) +{ + Shadow_IRDPSessionEvents_RefCount++; + return Shadow_IRDPSessionEvents_RefCount; +} + +static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Release( + __RPC__in _IRDPSessionEvents * This) +{ + if (!Shadow_IRDPSessionEvents_RefCount) + return 0; + + Shadow_IRDPSessionEvents_RefCount--; + + return Shadow_IRDPSessionEvents_RefCount; +} + +static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetTypeInfoCount( + __RPC__in _IRDPSessionEvents * This, + /* [out] */ __RPC__out UINT *pctinfo) +{ + WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfoCount"); + *pctinfo = 1; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetTypeInfo( + __RPC__in _IRDPSessionEvents * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) +{ + WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfo"); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetIDsOfNames( + __RPC__in _IRDPSessionEvents * This, + /* [in] */ __RPC__in REFIID riid, + /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, + /* [range][in] */ __RPC__in_range(0,16384) UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) +{ + WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetIDsOfNames"); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Invoke( + _IRDPSessionEvents * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr) +{ + HRESULT hr; + VARIANT vr; + UINT uArgErr; + + WLog_INFO(TAG, "%s (%d)", GetRDPSessionEventString(dispIdMember), dispIdMember); + + switch (dispIdMember) + { + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED: + { + int level; + IDispatch* pDispatch; + IRDPSRAPIAttendee* pAttendee; + + vr.vt = VT_DISPATCH; + vr.pdispVal = NULL; + + hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + pDispatch = vr.pdispVal; + + hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee, (void**) &pAttendee); + + if (FAILED(hr)) + { + WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + level = CTRL_LEVEL_VIEW; + //level = CTRL_LEVEL_INTERACTIVE; + + hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level); + + if (FAILED(hr)) + { + WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + pAttendee->lpVtbl->Release(pAttendee); + } + break; + + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_ERROR: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST: + { + int level; + IDispatch* pDispatch; + IRDPSRAPIAttendee* pAttendee; + + vr.vt = VT_INT; + vr.pdispVal = NULL; + + hr = DispGetParam(pDispParams, 1, VT_INT, &vr, &uArgErr); + + if (FAILED(hr)) + { + WLog_INFO(TAG, "%s DispGetParam(1, VT_INT) failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + level = vr.intVal; + + vr.vt = VT_DISPATCH; + vr.pdispVal = NULL; + + hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + pDispatch = vr.pdispVal; + + hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee, (void**) &pAttendee); + + if (FAILED(hr)) + { + WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level); + + if (FAILED(hr)) + { + WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08X", + GetRDPSessionEventString(dispIdMember), hr); + return hr; + } + + pAttendee->lpVtbl->Release(pAttendee); + } + break; + + case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN: + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN: + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE: + break; + + case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED: + break; + + case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED: + break; + + case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED: + break; + } + + return S_OK; +} + +static _IRDPSessionEventsVtbl Shadow_IRDPSessionEventsVtbl = +{ + /* IUnknown */ + Shadow_IRDPSessionEvents_QueryInterface, + Shadow_IRDPSessionEvents_AddRef, + Shadow_IRDPSessionEvents_Release, + + /* IDispatch */ + Shadow_IRDPSessionEvents_GetTypeInfoCount, + Shadow_IRDPSessionEvents_GetTypeInfo, + Shadow_IRDPSessionEvents_GetIDsOfNames, + Shadow_IRDPSessionEvents_Invoke +}; + +static _IRDPSessionEvents Shadow_IRDPSessionEvents = +{ + &Shadow_IRDPSessionEventsVtbl +}; + +static LRESULT CALLBACK ShadowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + break; + } + + return 0; +} + +int win_shadow_wds_wnd_init(winShadowSubsystem* subsystem) +{ + HMODULE hModule; + HINSTANCE hInstance; + WNDCLASSEX wndClassEx; + + hModule = GetModuleHandle(NULL); + + ZeroMemory(&wndClassEx, sizeof(WNDCLASSEX)); + wndClassEx.cbSize = sizeof(WNDCLASSEX); + wndClassEx.style = 0; + wndClassEx.lpfnWndProc = ShadowWndProc; + wndClassEx.cbClsExtra = 0; + wndClassEx.cbWndExtra = 0; + wndClassEx.hInstance = hModule; + wndClassEx.hIcon = NULL; + wndClassEx.hCursor = NULL; + wndClassEx.hbrBackground = NULL; + wndClassEx.lpszMenuName = _T("ShadowWndMenu"); + wndClassEx.lpszClassName = _T("ShadowWndClass"); + wndClassEx.hIconSm = NULL; + + if (!RegisterClassEx(&wndClassEx)) + { + WLog_ERR(TAG, "RegisterClassEx failure"); + return -1; + } + + hInstance = wndClassEx.hInstance; + + subsystem->hWnd = CreateWindowEx(0, wndClassEx.lpszClassName, + 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance, NULL); + + if (!subsystem->hWnd) + { + WLog_INFO(TAG, "CreateWindowEx failure"); + return -1; + } + + return 1; +} + +int win_shadow_wds_init(winShadowSubsystem* subsystem) +{ + int status; + HRESULT hr; + DWORD dwCookie; + long left, top; + long right, bottom; + long width, height; + IUnknown* pUnknown; + rdpSettings* settings; + BSTR bstrAuthString; + BSTR bstrGroupName; + BSTR bstrPassword; + BSTR bstrConnectionString; + BSTR bstrPropertyName; + VARIANT varPropertyValue; + rdpAssistanceFile* file; + IConnectionPoint* pCP; + IConnectionPointContainer* pCPC; + + win_shadow_wds_wnd_init(subsystem); + + hr = OleInitialize(NULL); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "OleInitialize() failure"); + return -1; + } + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "CoInitialize() failure"); + return -1; + } + + hr = CoCreateInstance(&CLSID_RDPSession, NULL, CLSCTX_ALL, + &IID_IRDPSRAPISharingSession, (void**) &(subsystem->pSharingSession)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "CoCreateInstance(IRDPSRAPISharingSession) failure: 0x%08X", hr); + return -1; + } + + pUnknown = (IUnknown*) subsystem->pSharingSession; + hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IConnectionPointContainer, (void**) &pCPC); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "QueryInterface(IID_IConnectionPointContainer) failure: 0x%08X", hr); + return -1; + } + + pCPC->lpVtbl->FindConnectionPoint(pCPC, &DIID__IRDPSessionEvents, &pCP); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IConnectionPointContainer::FindConnectionPoint(_IRDPSessionEvents) failure: 0x%08X", hr); + return -1; + } + + dwCookie = 0; + subsystem->pSessionEvents = &Shadow_IRDPSessionEvents; + subsystem->pSessionEvents->lpVtbl->AddRef(subsystem->pSessionEvents); + + hr = pCP->lpVtbl->Advise(pCP, (IUnknown*) subsystem->pSessionEvents, &dwCookie); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IConnectionPoint::Advise(Shadow_IRDPSessionEvents) failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->put_ColorDepth(subsystem->pSharingSession, 32); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::put_ColorDepth() failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->GetDesktopSharedRect(subsystem->pSharingSession, + &left, &top, &right, &bottom); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::GetDesktopSharedRect() failure: 0x%08X", hr); + return -1; + } + + width = right - left; + height = bottom - top; + + WLog_INFO(TAG, "GetDesktopSharedRect(): left: %d top: %d right: %d bottom: %d width: %d height: %d", + left, top, right, bottom, width, height); + + hr = subsystem->pSharingSession->lpVtbl->get_VirtualChannelManager(subsystem->pSharingSession, + &(subsystem->pVirtualChannelMgr)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::get_VirtualChannelManager() failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->get_ApplicationFilter(subsystem->pSharingSession, + &(subsystem->pApplicationFilter)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::get_ApplicationFilter() failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->get_Attendees(subsystem->pSharingSession, + &(subsystem->pAttendeeMgr)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Attendees() failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->get_Properties(subsystem->pSharingSession, &(subsystem->pSessionProperties)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Properties() failure: 0x%08X", hr); + return -1; + } + + bstrPropertyName = SysAllocString(L"PortId"); + varPropertyValue.vt = VT_I4; + varPropertyValue.intVal = 40000; + + hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties, + bstrPropertyName, varPropertyValue); + + SysFreeString(bstrPropertyName); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortId) failure: 0x%08X", hr); + return -1; + } + + bstrPropertyName = SysAllocString(L"DrvConAttach"); + varPropertyValue.vt = VT_BOOL; + varPropertyValue.boolVal = VARIANT_TRUE; + + hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties, + bstrPropertyName, varPropertyValue); + + SysFreeString(bstrPropertyName); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(DrvConAttach) failure: 0x%08X", hr); + return -1; + } + + bstrPropertyName = SysAllocString(L"PortProtocol"); + varPropertyValue.vt = VT_I4; + + //varPropertyValue.intVal = 0; // AF_UNSPEC + varPropertyValue.intVal = 2; // AF_INET + //varPropertyValue.intVal = 23; // AF_INET6 + + hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties, + bstrPropertyName, varPropertyValue); + + SysFreeString(bstrPropertyName); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortProtocol) failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->Open(subsystem->pSharingSession); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::Open() failure: 0x%08X", hr); + return -1; + } + + hr = subsystem->pSharingSession->lpVtbl->get_Invitations(subsystem->pSharingSession, + &(subsystem->pInvitationMgr)); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Invitations() failure"); + return -1; + } + + bstrAuthString = SysAllocString(L"Shadow"); + bstrGroupName = SysAllocString(L"ShadowGroup"); + bstrPassword = SysAllocString(L"Shadow123!"); + + hr = subsystem->pInvitationMgr->lpVtbl->CreateInvitation(subsystem->pInvitationMgr, bstrAuthString, + bstrGroupName, bstrPassword, 5, &(subsystem->pInvitation)); + + SysFreeString(bstrAuthString); + SysFreeString(bstrGroupName); + SysFreeString(bstrPassword); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPIInvitationManager::CreateInvitation() failure: 0x%08X", hr); + return -1; + } + + subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation, &bstrConnectionString); + + if (FAILED(hr)) + { + WLog_ERR(TAG, "IRDPSRAPIInvitation::get_ConnectionString() failure: 0x%08X", hr); + return -1; + } + + file = subsystem->pAssistanceFile = freerdp_assistance_file_new(); + + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) bstrConnectionString, + ((UINT32*) bstrConnectionString)[-1], &(file->ConnectionString2), 0, NULL, NULL); + + status = freerdp_assistance_parse_connection_string2(file); + + if (status < 0) + return -1; + + WLog_INFO(TAG, "ConnectionString: %s", file->ConnectionString2); + + if (0) + { + FILE* fp; + size_t size; + + fp = fopen("inv.xml", "w+b"); + + if (fp) + { + size = strlen(file->ConnectionString2); + fwrite(file->ConnectionString2, 1, size, fp); + fwrite("\r\n", 1, 2, fp); + fclose(fp); + } + } + + status = win_shadow_rdp_init(subsystem); + + if (status < 0) + { + WLog_ERR(TAG, "win_shadow_rdp_init() failure: %d", status); + return status; + } + + settings = subsystem->shw->settings; + + freerdp_set_param_bool(settings, FreeRDP_RemoteAssistanceMode, TRUE); + + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceSessionId, file->RASessionId); + + freerdp_set_param_string(settings, FreeRDP_RemoteAssistanceRCTicket, file->ConnectionString2); + + freerdp_set_param_string(settings, FreeRDP_Domain, "RDP"); + freerdp_set_param_string(settings, FreeRDP_Username, "Shadow"); + freerdp_set_param_string(settings, FreeRDP_RemoteAssistancePassword, "Shadow123!"); + freerdp_set_param_bool(settings, FreeRDP_AutoLogonEnabled, TRUE); + + freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->MachineAddress); + freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->MachinePort); + + freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, width); + freerdp_set_param_uint32(settings, FreeRDP_DesktopHeight, height); + + status = win_shadow_rdp_start(subsystem); + + if (status < 0) + { + WLog_ERR(TAG, "win_shadow_rdp_start() failure: %d", status); + return status; + } + + return 1; +} + +int win_shadow_wds_uninit(winShadowSubsystem* subsystem) +{ + if (subsystem->pSharingSession) + { + subsystem->pSharingSession->lpVtbl->Close(subsystem->pSharingSession); + subsystem->pSharingSession->lpVtbl->Release(subsystem->pSharingSession); + subsystem->pSharingSession = NULL; + } + + if (subsystem->pVirtualChannelMgr) + { + subsystem->pVirtualChannelMgr->lpVtbl->Release(subsystem->pVirtualChannelMgr); + subsystem->pVirtualChannelMgr = NULL; + } + + if (subsystem->pApplicationFilter) + { + subsystem->pApplicationFilter->lpVtbl->Release(subsystem->pApplicationFilter); + subsystem->pApplicationFilter = NULL; + } + + if (subsystem->pAttendeeMgr) + { + subsystem->pAttendeeMgr->lpVtbl->Release(subsystem->pAttendeeMgr); + subsystem->pAttendeeMgr = NULL; + } + + if (subsystem->pSessionProperties) + { + subsystem->pSessionProperties->lpVtbl->Release(subsystem->pSessionProperties); + subsystem->pSessionProperties = NULL; + } + + if (subsystem->pInvitationMgr) + { + subsystem->pInvitationMgr->lpVtbl->Release(subsystem->pInvitationMgr); + subsystem->pInvitationMgr = NULL; + } + + if (subsystem->pInvitation) + { + subsystem->pInvitation->lpVtbl->Release(subsystem->pInvitation); + subsystem->pInvitation = NULL; + } + + if (subsystem->pAssistanceFile) + { + freerdp_assistance_file_free(subsystem->pAssistanceFile); + subsystem->pAssistanceFile = NULL; + } + + if (subsystem->hWnd) + { + DestroyWindow(subsystem->hWnd); + subsystem->hWnd = NULL; + } + + if (subsystem->shw) + { + win_shadow_rdp_uninit(subsystem); + subsystem->shw = NULL; + } + + return 1; +} diff --git a/server/shadow/Win/win_wds.h b/server/shadow/Win/win_wds.h new file mode 100644 index 000000000..d8859d706 --- /dev/null +++ b/server/shadow/Win/win_wds.h @@ -0,0 +1,47 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_WIN_WDS_H +#define FREERDP_SHADOW_SERVER_WIN_WDS_H + +#define WITH_WDS_API 1 + +#ifndef CINTERFACE +#define CINTERFACE +#endif + +#include + +#ifndef DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED +#define DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED 340 +#endif + +#include "win_shadow.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int win_shadow_wds_init(winShadowSubsystem* subsystem); +int win_shadow_wds_uninit(winShadowSubsystem* subsystem); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_WIN_WDS_H */ diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c new file mode 100644 index 000000000..943bc0b63 --- /dev/null +++ b/server/shadow/X11/x11_shadow.c @@ -0,0 +1,1289 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../shadow_screen.h" +#include "../shadow_client.h" +#include "../shadow_encoder.h" +#include "../shadow_capture.h" +#include "../shadow_surface.h" +#include "../shadow_subsystem.h" + +#include "x11_shadow.h" + +#define TAG SERVER_TAG("shadow.x11") + +#ifdef WITH_PAM + +#include + +struct _SHADOW_PAM_AUTH_DATA +{ + const char* user; + const char* domain; + const char* password; +}; +typedef struct _SHADOW_PAM_AUTH_DATA SHADOW_PAM_AUTH_DATA; + +struct _SHADOW_PAM_AUTH_INFO +{ + char* service_name; + pam_handle_t* handle; + struct pam_conv pamc; + SHADOW_PAM_AUTH_DATA appdata; +}; +typedef struct _SHADOW_PAM_AUTH_INFO SHADOW_PAM_AUTH_INFO; + +int x11_shadow_pam_conv(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) +{ + int index; + int pam_status = PAM_SUCCESS; + SHADOW_PAM_AUTH_DATA* appdata; + struct pam_response* response; + + appdata = (SHADOW_PAM_AUTH_DATA*) appdata_ptr; + + response = (struct pam_response*) calloc(num_msg, sizeof(struct pam_response)); + + if (!response) + return PAM_CONV_ERR; + + for (index = 0; index < num_msg; index++) + { + switch (msg[index]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + response[index].resp = _strdup(appdata->user); + response[index].resp_retcode = PAM_SUCCESS; + break; + + case PAM_PROMPT_ECHO_OFF: + response[index].resp = _strdup(appdata->password); + response[index].resp_retcode = PAM_SUCCESS; + break; + + default: + pam_status = PAM_CONV_ERR; + break; + } + } + + if (pam_status != PAM_SUCCESS) + { + free(response); + return pam_status; + } + + *resp = response; + + return pam_status; +} + +int x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info) +{ + if (PathFileExistsA("/etc/pam.d/lightdm")) + { + info->service_name = _strdup("lightdm"); + } + else if (PathFileExistsA("/etc/pam.d/gdm")) + { + info->service_name = _strdup("gdm"); + } + else if (PathFileExistsA("/etc/pam.d/xdm")) + { + info->service_name = _strdup("xdm"); + } + else if (PathFileExistsA("/etc/pam.d/login")) + { + info->service_name = _strdup("login"); + } + else if (PathFileExistsA("/etc/pam.d/sshd")) + { + info->service_name = _strdup("sshd"); + } + else + { + return -1; + } + + return 1; +} + +int x11_shadow_pam_authenticate(x11ShadowSubsystem* subsystem, const char* user, const char* domain, const char* password) +{ + int pam_status; + SHADOW_PAM_AUTH_INFO* info; + + info = calloc(1, sizeof(SHADOW_PAM_AUTH_INFO)); + + if (!info) + return PAM_CONV_ERR; + + if (x11_shadow_pam_get_service_name(info) < 0) + return -1; + + info->appdata.user = user; + info->appdata.domain = domain; + info->appdata.password = password; + + info->pamc.conv = &x11_shadow_pam_conv; + info->pamc.appdata_ptr = &(info->appdata); + + pam_status = pam_start(info->service_name, 0, &(info->pamc), &(info->handle)); + + if (pam_status != PAM_SUCCESS) + { + fprintf(stderr, "pam_start failure: %s\n", pam_strerror(info->handle, pam_status)); + free(info); + return -1; + } + + pam_status = pam_authenticate(info->handle, 0); + + if (pam_status != PAM_SUCCESS) + { + fprintf(stderr, "pam_authenticate failure: %s\n", pam_strerror(info->handle, pam_status)); + free(info); + return -1; + } + + pam_status = pam_acct_mgmt(info->handle, 0); + + if (pam_status != PAM_SUCCESS) + { + fprintf(stderr, "pam_acct_mgmt failure: %s\n", pam_strerror(info->handle, pam_status)); + free(info); + return -1; + } + + free(info); + + return 1; +} + +#endif + +void x11_shadow_input_synchronize_event(x11ShadowSubsystem* subsystem, UINT32 flags) +{ + +} + +void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ +#ifdef WITH_XTEST + DWORD vkcode; + DWORD keycode; + BOOL extended = FALSE; + + if (flags & KBD_FLAGS_EXTENDED) + extended = TRUE; + + if (extended) + code |= KBDEXT; + + vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4); + + if (extended) + vkcode |= KBDEXT; + + keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_EVDEV); + + if (keycode != 0) + { + XTestGrabControl(subsystem->display, True); + + if (flags & KBD_FLAGS_DOWN) + XTestFakeKeyEvent(subsystem->display, keycode, True, 0); + else if (flags & KBD_FLAGS_RELEASE) + XTestFakeKeyEvent(subsystem->display, keycode, False, 0); + + XTestGrabControl(subsystem->display, False); + } +#endif +} + +void x11_shadow_input_unicode_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code) +{ + +} + +void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ +#ifdef WITH_XTEST + int button = 0; + BOOL down = FALSE; + rdpShadowServer* server; + rdpShadowSurface* surface; + + server = subsystem->server; + surface = server->surface; + + x += surface->x; + y += surface->y; + + if (server->shareSubRect) + { + x += server->subRect.left; + y += server->subRect.top; + } + + XTestGrabControl(subsystem->display, True); + + if (flags & PTR_FLAGS_WHEEL) + { + BOOL negative = FALSE; + + if (flags & PTR_FLAGS_WHEEL_NEGATIVE) + negative = TRUE; + + button = (negative) ? 5 : 4; + + XTestFakeButtonEvent(subsystem->display, button, True, 0); + XTestFakeButtonEvent(subsystem->display, button, False, 0); + } + else + { + if (flags & PTR_FLAGS_MOVE) + XTestFakeMotionEvent(subsystem->display, 0, x, y, 0); + + if (flags & PTR_FLAGS_BUTTON1) + button = 1; + else if (flags & PTR_FLAGS_BUTTON2) + button = 3; + else if (flags & PTR_FLAGS_BUTTON3) + button = 2; + + if (flags & PTR_FLAGS_DOWN) + down = TRUE; + + if (button) + XTestFakeButtonEvent(subsystem->display, button, down, 0); + } + + XTestGrabControl(subsystem->display, False); +#endif +} + +void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y) +{ +#ifdef WITH_XTEST + int button = 0; + BOOL down = FALSE; + rdpShadowServer* server; + rdpShadowSurface* surface; + + server = subsystem->server; + surface = server->surface; + + x += surface->x; + y += surface->y; + + if (server->shareSubRect) + { + x += server->subRect.left; + y += server->subRect.top; + } + + XTestGrabControl(subsystem->display, True); + + XTestFakeMotionEvent(subsystem->display, 0, x, y, CurrentTime); + + if (flags & PTR_XFLAGS_BUTTON1) + button = 8; + else if (flags & PTR_XFLAGS_BUTTON2) + button = 9; + + if (flags & PTR_XFLAGS_DOWN) + down = TRUE; + + if (button) + XTestFakeButtonEvent(subsystem->display, button, down, 0); + + XTestGrabControl(subsystem->display, False); +#endif +} + +int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) +{ + int x, y, n, k; + rdpShadowServer* server; + rdpShadowSurface* surface; + + server = subsystem->server; + surface = server->surface; + + if (getImage) + { +#ifdef WITH_XFIXES + UINT32* pDstPixel; + XFixesCursorImage* ci; + + ci = XFixesGetCursorImage(subsystem->display); + + x = ci->x; + y = ci->y; + + if (ci->width > subsystem->cursorMaxWidth) + return -1; + + if (ci->height > subsystem->cursorMaxHeight) + return -1; + + subsystem->cursorHotX = ci->xhot; + subsystem->cursorHotY = ci->yhot; + + subsystem->cursorWidth = ci->width; + subsystem->cursorHeight = ci->height; + + subsystem->cursorId = ci->cursor_serial; + + n = ci->width * ci->height; + pDstPixel = (UINT32*) subsystem->cursorPixels; + + for (k = 0; k < n; k++) + { + /* XFixesCursorImage.pixels is in *unsigned long*, which may be 8 bytes */ + *pDstPixel++ = (UINT32) ci->pixels[k]; + } + + XFree(ci); +#endif + } + else + { + UINT32 mask; + int win_x, win_y; + int root_x, root_y; + Window root, child; + + if (!XQueryPointer(subsystem->display, subsystem->root_window, + &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) + { + return -1; + } + + x = root_x; + y = root_y; + } + + subsystem->cursorX = x; + subsystem->cursorY = y; + + return 1; +} + +int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent) +{ + if (xevent->type == MotionNotify) + { + + } + +#ifdef WITH_XFIXES + if (xevent->type == subsystem->xfixes_cursor_notify_event) + { + x11_shadow_query_cursor(subsystem, TRUE); + } +#endif + + return 1; +} + +void x11_shadow_validate_region(x11ShadowSubsystem* subsystem, int x, int y, int width, int height) +{ + XRectangle region; + + if (!subsystem->use_xfixes || !subsystem->use_xdamage) + return; + + region.x = x; + region.y = y; + region.width = width; + region.height = height; + +#ifdef WITH_XFIXES + XFixesSetRegion(subsystem->display, subsystem->xdamage_region, ®ion, 1); + XDamageSubtract(subsystem->display, subsystem->xdamage, subsystem->xdamage_region, None); +#endif +} + +int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem) +{ + int x, y; + int nXSrc; + int nYSrc; + int nXDst; + int nYDst; + int nWidth; + int nHeight; + int nSrcStep; + int nDstStep; + int nSrcPad; + int nDstPad; + BYTE* pSrcData; + BYTE* pDstData; + BYTE* pSrcPixel; + BYTE* pDstPixel; + BYTE A, R, G, B; + rdpShadowSurface* surface; + + surface = subsystem->server->surface; + + nXSrc = 0; + nYSrc = 0; + + nWidth = subsystem->cursorWidth; + nHeight = subsystem->cursorHeight; + + nXDst = subsystem->cursorX - surface->x - subsystem->cursorHotX; + nYDst = subsystem->cursorY - surface->y - subsystem->cursorHotY; + + if (nXDst >= surface->width) + return 1; + + if (nXDst < 0) + { + nXDst *= -1; + + if (nXDst >= nWidth) + return 1; + + nXSrc = nXDst; + nWidth -= nXDst; + nXDst = 0; + } + + if (nYDst >= surface->height) + return 1; + + if (nYDst < 0) + { + nYDst *= -1; + + if (nYDst >= nHeight) + return 1; + + nYSrc = nYDst; + nHeight -= nYDst; + nYDst = 0; + } + + if ((nXDst + nWidth) > surface->width) + nWidth = surface->width - nXDst; + + if ((nYDst + nHeight) > surface->height) + nHeight = surface->height - nYDst; + + pSrcData = subsystem->cursorPixels; + nSrcStep = subsystem->cursorWidth * 4; + + pDstData = surface->data; + nDstStep = surface->scanline; + + nSrcPad = (nSrcStep - (nWidth * 4)); + nDstPad = (nDstStep - (nWidth * 4)); + + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)]; + + for (x = 0; x < nWidth; x++) + { + B = *pSrcPixel++; + G = *pSrcPixel++; + R = *pSrcPixel++; + A = *pSrcPixel++; + + if (A == 0xFF) + { + pDstPixel[0] = B; + pDstPixel[1] = G; + pDstPixel[2] = R; + } + else + { + pDstPixel[0] = B + (pDstPixel[0] * (0xFF - A) + (0xFF / 2)) / 0xFF; + pDstPixel[1] = G + (pDstPixel[1] * (0xFF - A) + (0xFF / 2)) / 0xFF; + pDstPixel[2] = R + (pDstPixel[2] * (0xFF - A) + (0xFF / 2)) / 0xFF; + } + + pDstPixel[3] = 0xFF; + pDstPixel += 4; + } + + pSrcPixel += nSrcPad; + pDstPixel += nDstPad; + } + + return 1; +} + +int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) +{ + int count; + int status; + int x, y; + int width, height; + XImage* image; + rdpShadowScreen* screen; + rdpShadowServer* server; + rdpShadowSurface* surface; + RECTANGLE_16 invalidRect; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16 *extents; + + server = subsystem->server; + surface = server->surface; + screen = server->screen; + + count = ArrayList_Count(server->clients); + + if (count < 1) + return 1; + + if ((count == 1) && subsystem->suppressOutput) + return 1; + + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = surface->width; + surfaceRect.bottom = surface->height; + + XLockDisplay(subsystem->display); + + if (subsystem->use_xshm) + { + image = subsystem->fb_image; + + XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, + subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0); + + status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, + (BYTE*) &(image->data[surface->width * 4]), image->bytes_per_line, &invalidRect); + } + else + { + image = XGetImage(subsystem->display, subsystem->root_window, + surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap); + + status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, + (BYTE*) image->data, image->bytes_per_line, &invalidRect); + } + + XSync(subsystem->display, False); + + XUnlockDisplay(subsystem->display); + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + + if (!region16_is_empty(&(subsystem->invalidRegion))) + { + extents = region16_extents(&(subsystem->invalidRegion)); + + x = extents->left; + y = extents->top; + width = extents->right - extents->left; + height = extents->bottom - extents->top; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x, y, width, height, + (BYTE*) image->data, PIXEL_FORMAT_XRGB32, + image->bytes_per_line, x, y, NULL); + + x11_shadow_blend_cursor(subsystem); + + count = ArrayList_Count(server->clients); + + InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); + + SetEvent(subsystem->updateEvent); + + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + + DeleteSynchronizationBarrier(&(subsystem->barrier)); + + if (count == 1) + { + rdpShadowClient* client; + + client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0); + + if (client) + { + subsystem->captureFrameRate = client->encoder->fps; + } + } + + ResetEvent(subsystem->updateEvent); + + region16_clear(&(subsystem->invalidRegion)); + } + + if (!subsystem->use_xshm) + XDestroyImage(image); + + return 1; +} + +int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message) +{ + if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID) + { + UINT32 index; + SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; + + if (msg->numRects) + { + for (index = 0; index < msg->numRects; index++) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &msg->rects[index]); + } + } + else + { + RECTANGLE_16 refreshRect; + + refreshRect.left = 0; + refreshRect.top = 0; + refreshRect.right = subsystem->width; + refreshRect.bottom = subsystem->height; + + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &refreshRect); + } + } + else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID) + { + SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; + + subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE; + + if (msg->allow) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &(msg->rect)); + } + } + + if (message->Free) + message->Free(message); + + return 1; +} + +void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) +{ + XEvent xevent; + DWORD status; + DWORD nCount; + UINT64 cTime; + DWORD dwTimeout; + DWORD dwInterval; + UINT64 frameTime; + HANDLE events[32]; + wMessage message; + wMessagePipe* MsgPipe; + + MsgPipe = subsystem->MsgPipe; + + nCount = 0; + events[nCount++] = subsystem->event; + events[nCount++] = MessageQueue_Event(MsgPipe->In); + + subsystem->captureFrameRate = 16; + dwInterval = 1000 / subsystem->captureFrameRate; + frameTime = GetTickCount64() + dwInterval; + + while (1) + { + cTime = GetTickCount64(); + dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime; + + status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout); + + if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0) + { + if (MessageQueue_Peek(MsgPipe->In, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + x11_shadow_subsystem_process_message(subsystem, &message); + } + } + + if (WaitForSingleObject(subsystem->event, 0) == WAIT_OBJECT_0) + { + if (XEventsQueued(subsystem->display, QueuedAlready)) + { + XNextEvent(subsystem->display, &xevent); + x11_shadow_handle_xevent(subsystem, &xevent); + } + } + + if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) + { + x11_shadow_query_cursor(subsystem, FALSE); + x11_shadow_screen_grab(subsystem); + + dwInterval = 1000 / subsystem->captureFrameRate; + frameTime += dwInterval; + } + } + + ExitThread(0); + return NULL; +} + +int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem) +{ + if (subsystem->display) + return 1; /* initialize once */ + + if (!getenv("DISPLAY")) + setenv("DISPLAY", ":0", 1); + + if (!XInitThreads()) + return -1; + + subsystem->display = XOpenDisplay(NULL); + + if (!subsystem->display) + { + WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL)); + return -1; + } + + subsystem->xfds = ConnectionNumber(subsystem->display); + subsystem->number = DefaultScreen(subsystem->display); + subsystem->screen = ScreenOfDisplay(subsystem->display, subsystem->number); + subsystem->depth = DefaultDepthOfScreen(subsystem->screen); + subsystem->width = WidthOfScreen(subsystem->screen); + subsystem->height = HeightOfScreen(subsystem->screen); + subsystem->root_window = DefaultRootWindow(subsystem->display); + + return 1; +} + +int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem) +{ +#ifdef WITH_XFIXES + int xfixes_event; + int xfixes_error; + int major, minor; + + if (!XFixesQueryExtension(subsystem->display, &xfixes_event, &xfixes_error)) + return -1; + + if (!XFixesQueryVersion(subsystem->display, &major, &minor)) + return -1; + + subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify; + + XFixesSelectCursorInput(subsystem->display, DefaultRootWindow(subsystem->display), XFixesDisplayCursorNotifyMask); + + return 1; +#else + return -1; +#endif +} + +int x11_shadow_xinerama_init(x11ShadowSubsystem* subsystem) +{ +#ifdef WITH_XINERAMA + int major, minor; + int xinerama_event; + int xinerama_error; + + x11_shadow_subsystem_base_init(subsystem); + + if (!XineramaQueryExtension(subsystem->display, &xinerama_event, &xinerama_error)) + return -1; + + if (!XDamageQueryVersion(subsystem->display, &major, &minor)) + return -1; + + if (!XineramaIsActive(subsystem->display)) + return -1; + + return 1; +#else + return -1; +#endif +} + +int x11_shadow_xdamage_init(x11ShadowSubsystem* subsystem) +{ +#ifdef WITH_XDAMAGE + int major, minor; + int damage_event; + int damage_error; + + if (!subsystem->use_xfixes) + return -1; + + if (!XDamageQueryExtension(subsystem->display, &damage_event, &damage_error)) + return -1; + + if (!XDamageQueryVersion(subsystem->display, &major, &minor)) + return -1; + + if (major < 1) + return -1; + + subsystem->xdamage_notify_event = damage_event + XDamageNotify; + subsystem->xdamage = XDamageCreate(subsystem->display, subsystem->root_window, XDamageReportDeltaRectangles); + + if (!subsystem->xdamage) + return -1; + +#ifdef WITH_XFIXES + subsystem->xdamage_region = XFixesCreateRegion(subsystem->display, NULL, 0); + + if (!subsystem->xdamage_region) + return -1; +#endif + + return 1; +#else + return -1; +#endif +} + +int x11_shadow_xshm_init(x11ShadowSubsystem* subsystem) +{ + Bool pixmaps; + int major, minor; + XGCValues values; + + if (!XShmQueryExtension(subsystem->display)) + return -1; + + if (!XShmQueryVersion(subsystem->display, &major, &minor, &pixmaps)) + return -1; + + if (!pixmaps) + return -1; + + subsystem->fb_shm_info.shmid = -1; + subsystem->fb_shm_info.shmaddr = (char*) -1; + subsystem->fb_shm_info.readOnly = False; + + subsystem->fb_image = XShmCreateImage(subsystem->display, subsystem->visual, subsystem->depth, + ZPixmap, NULL, &(subsystem->fb_shm_info), subsystem->width, subsystem->height); + + if (!subsystem->fb_image) + { + WLog_ERR(TAG, "XShmCreateImage failed"); + return -1; + } + + subsystem->fb_shm_info.shmid = shmget(IPC_PRIVATE, + subsystem->fb_image->bytes_per_line * subsystem->fb_image->height, IPC_CREAT | 0600); + + if (subsystem->fb_shm_info.shmid == -1) + { + WLog_ERR(TAG, "shmget failed"); + return -1; + } + + subsystem->fb_shm_info.shmaddr = shmat(subsystem->fb_shm_info.shmid, 0, 0); + subsystem->fb_image->data = subsystem->fb_shm_info.shmaddr; + + if (subsystem->fb_shm_info.shmaddr == ((char*) -1)) + { + WLog_ERR(TAG, "shmat failed"); + return -1; + } + + if (!XShmAttach(subsystem->display, &(subsystem->fb_shm_info))) + return -1; + + XSync(subsystem->display, False); + + shmctl(subsystem->fb_shm_info.shmid, IPC_RMID, 0); + + subsystem->fb_pixmap = XShmCreatePixmap(subsystem->display, + subsystem->root_window, subsystem->fb_image->data, &(subsystem->fb_shm_info), + subsystem->fb_image->width, subsystem->fb_image->height, subsystem->fb_image->depth); + + XSync(subsystem->display, False); + + if (!subsystem->fb_pixmap) + return -1; + + values.subwindow_mode = IncludeInferiors; + values.graphics_exposures = False; + + subsystem->xshm_gc = XCreateGC(subsystem->display, subsystem->root_window, + GCSubwindowMode | GCGraphicsExposures, &values); + + XSetFunction(subsystem->display, subsystem->xshm_gc, GXcopy); + XSync(subsystem->display, False); + + return 1; +} + +int x11_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors) +{ + int index; + Display* display; + int displayWidth; + int displayHeight; + int numMonitors = 0; + MONITOR_DEF* monitor; + + if (!getenv("DISPLAY")) + setenv("DISPLAY", ":0", 1); + + display = XOpenDisplay(NULL); + + if (!display) + { + WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL)); + return -1; + } + + displayWidth = WidthOfScreen(DefaultScreenOfDisplay(display)); + displayHeight = HeightOfScreen(DefaultScreenOfDisplay(display)); + +#ifdef WITH_XINERAMA + { + int major, minor; + int xinerama_event; + int xinerama_error; + XineramaScreenInfo* screen; + XineramaScreenInfo* screens; + + if (XineramaQueryExtension(display, &xinerama_event, &xinerama_error) && + XDamageQueryVersion(display, &major, &minor) && XineramaIsActive(display)) + { + screens = XineramaQueryScreens(display, &numMonitors); + + if (numMonitors > maxMonitors) + numMonitors = maxMonitors; + + if (screens && (numMonitors > 0)) + { + for (index = 0; index < numMonitors; index++) + { + screen = &screens[index]; + monitor = &monitors[index]; + + monitor->left = screen->x_org; + monitor->top = screen->y_org; + monitor->right = monitor->left + screen->width; + monitor->bottom = monitor->top + screen->height; + monitor->flags = (index == 0) ? 1 : 0; + } + } + + XFree(screens); + } + } +#endif + + if (numMonitors < 1) + { + index = 0; + numMonitors = 1; + + monitor = &monitors[index]; + + monitor->left = 0; + monitor->top = 0; + monitor->right = displayWidth; + monitor->bottom = displayHeight; + monitor->flags = 1; + } + + return numMonitors; +} + +int x11_shadow_subsystem_init(x11ShadowSubsystem* subsystem) +{ + int i; + int pf_count; + int vi_count; + int nextensions; + char** extensions; + XVisualInfo* vi; + XVisualInfo* vis; + XVisualInfo template; + XPixmapFormatValues* pf; + XPixmapFormatValues* pfs; + MONITOR_DEF* virtualScreen; + + subsystem->numMonitors = x11_shadow_enum_monitors(subsystem->monitors, 16); + + x11_shadow_subsystem_base_init(subsystem); + + if ((subsystem->depth != 24) && (subsystem->depth != 32)) + { + fprintf(stderr, "x11_shadow_subsystem_init: unsupported X11 server color depth: %d\n", subsystem->depth); + return -1; + } + + extensions = XListExtensions(subsystem->display, &nextensions); + + if (!extensions || (nextensions < 0)) + return -1; + + for (i = 0; i < nextensions; i++) + { + if (strcmp(extensions[i], "Composite") == 0) + subsystem->composite = TRUE; + } + + XFreeExtensionList(extensions); + + if (subsystem->composite) + subsystem->use_xdamage = FALSE; + + pfs = XListPixmapFormats(subsystem->display, &pf_count); + + if (!pfs) + { + WLog_ERR(TAG, "XListPixmapFormats failed"); + return -1; + } + + for (i = 0; i < pf_count; i++) + { + pf = pfs + i; + + if (pf->depth == subsystem->depth) + { + subsystem->bpp = pf->bits_per_pixel; + subsystem->scanline_pad = pf->scanline_pad; + break; + } + } + XFree(pfs); + + ZeroMemory(&template, sizeof(template)); + template.class = TrueColor; + template.screen = subsystem->number; + + vis = XGetVisualInfo(subsystem->display, VisualClassMask | VisualScreenMask, &template, &vi_count); + + if (!vis) + { + WLog_ERR(TAG, "XGetVisualInfo failed"); + return -1; + } + + for (i = 0; i < vi_count; i++) + { + vi = vis + i; + + if (vi->depth == subsystem->depth) + { + subsystem->visual = vi->visual; + break; + } + } + XFree(vis); + + XSelectInput(subsystem->display, subsystem->root_window, SubstructureNotifyMask); + + subsystem->cursorMaxWidth = 256; + subsystem->cursorMaxHeight = 256; + subsystem->cursorPixels = _aligned_malloc(subsystem->cursorMaxWidth * subsystem->cursorMaxHeight * 4, 16); + + if (!subsystem->cursorPixels) + return -1; + + x11_shadow_query_cursor(subsystem, TRUE); + + if (subsystem->use_xfixes) + { + if (x11_shadow_xfixes_init(subsystem) < 0) + subsystem->use_xfixes = FALSE; + } + + if (subsystem->use_xinerama) + { + if (x11_shadow_xinerama_init(subsystem) < 0) + subsystem->use_xinerama = FALSE; + } + + if (subsystem->use_xshm) + { + if (x11_shadow_xshm_init(subsystem) < 0) + subsystem->use_xshm = FALSE; + } + + if (subsystem->use_xdamage) + { + if (x11_shadow_xdamage_init(subsystem) < 0) + subsystem->use_xdamage = FALSE; + } + + subsystem->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds); + + virtualScreen = &(subsystem->virtualScreen); + + virtualScreen->left = 0; + virtualScreen->top = 0; + virtualScreen->right = subsystem->width; + virtualScreen->bottom = subsystem->height; + virtualScreen->flags = 1; + + WLog_INFO(TAG, "X11 Extensions: XFixes: %d Xinerama: %d XDamage: %d XShm: %d", + subsystem->use_xfixes, subsystem->use_xinerama, subsystem->use_xdamage, subsystem->use_xshm); + + return 1; +} + +int x11_shadow_subsystem_uninit(x11ShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + if (subsystem->display) + { + XCloseDisplay(subsystem->display); + subsystem->display = NULL; + } + + if (subsystem->event) + { + CloseHandle(subsystem->event); + subsystem->event = NULL; + } + + if (subsystem->cursorPixels) + { + _aligned_free(subsystem->cursorPixels); + subsystem->cursorPixels = NULL; + } + + return 1; +} + +int x11_shadow_subsystem_start(x11ShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + subsystem->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) x11_shadow_subsystem_thread, + (void*) subsystem, 0, NULL); + + return 1; +} + +int x11_shadow_subsystem_stop(x11ShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + if (subsystem->thread) + { + MessageQueue_PostQuit(subsystem->MsgPipe->In, 0); + WaitForSingleObject(subsystem->thread, INFINITE); + CloseHandle(subsystem->thread); + subsystem->thread = NULL; + } + + return 1; +} + +x11ShadowSubsystem* x11_shadow_subsystem_new() +{ + x11ShadowSubsystem* subsystem; + + subsystem = (x11ShadowSubsystem*) calloc(1, sizeof(x11ShadowSubsystem)); + + if (!subsystem) + return NULL; + +#ifdef WITH_PAM + subsystem->Authenticate = (pfnShadowAuthenticate) x11_shadow_pam_authenticate; +#endif + + subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) x11_shadow_input_synchronize_event; + subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) x11_shadow_input_keyboard_event; + subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) x11_shadow_input_unicode_keyboard_event; + subsystem->MouseEvent = (pfnShadowMouseEvent) x11_shadow_input_mouse_event; + subsystem->ExtendedMouseEvent = (pfnShadowExtendedMouseEvent) x11_shadow_input_extended_mouse_event; + + subsystem->composite = FALSE; + subsystem->use_xshm = FALSE; /* temporarily disabled */ + subsystem->use_xfixes = TRUE; + subsystem->use_xdamage = FALSE; + subsystem->use_xinerama = TRUE; + + return subsystem; +} + +void x11_shadow_subsystem_free(x11ShadowSubsystem* subsystem) +{ + if (!subsystem) + return; + + x11_shadow_subsystem_uninit(subsystem); + + free(subsystem); +} + +int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +{ + pEntryPoints->New = (pfnShadowSubsystemNew) x11_shadow_subsystem_new; + pEntryPoints->Free = (pfnShadowSubsystemFree) x11_shadow_subsystem_free; + + pEntryPoints->Init = (pfnShadowSubsystemInit) x11_shadow_subsystem_init; + pEntryPoints->Uninit = (pfnShadowSubsystemInit) x11_shadow_subsystem_uninit; + + pEntryPoints->Start = (pfnShadowSubsystemStart) x11_shadow_subsystem_start; + pEntryPoints->Stop = (pfnShadowSubsystemStop) x11_shadow_subsystem_stop; + + pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) x11_shadow_enum_monitors; + + return 1; +} diff --git a/server/X11/xfreerdp.h b/server/shadow/X11/x11_shadow.h similarity index 59% rename from server/X11/xfreerdp.h rename to server/shadow/X11/x11_shadow.h index db6231893..31233e233 100644 --- a/server/X11/xfreerdp.h +++ b/server/shadow/X11/x11_shadow.h @@ -1,8 +1,7 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP X11 Server * - * Copyright 2011 Marc-Andre Moreau + * Copyright 2011-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. @@ -17,15 +16,18 @@ * limitations under the License. */ -#ifndef __XFREERDP_H -#define __XFREERDP_H +#ifndef FREERDP_SHADOW_SERVER_X11_H +#define FREERDP_SHADOW_SERVER_X11_H -#include "xf_interface.h" +#include -#include -#include -#include -#include +typedef struct x11_shadow_subsystem x11ShadowSubsystem; + +#include +#include +#include +#include +#include #include @@ -45,8 +47,16 @@ #include #endif -struct xf_info +#ifdef WITH_XINERAMA +#include +#endif + +struct x11_shadow_subsystem { + RDP_SHADOW_SUBSYSTEM_COMMON(); + + HANDLE thread; + int bpp; int xfds; int depth; @@ -58,35 +68,49 @@ struct xf_info Visual* visual; Display* display; int scanline_pad; - int bytesPerPixel; - HCLRCONV clrconv; + BOOL composite; + BOOL use_xshm; - int activePeerCount; + BOOL use_xfixes; + BOOL use_xdamage; + BOOL use_xinerama; XImage* fb_image; Pixmap fb_pixmap; Window root_window; XShmSegmentInfo fb_shm_info; + int cursorX; + int cursorY; + int cursorHotX; + int cursorHotY; + int cursorWidth; + int cursorHeight; + UINT32 cursorId; + BYTE* cursorPixels; + int cursorMaxWidth; + int cursorMaxHeight; + #ifdef WITH_XDAMAGE - GC xdamage_gc; + GC xshm_gc; Damage xdamage; int xdamage_notify_event; XserverRegion xdamage_region; #endif #ifdef WITH_XFIXES - int xfixes_notify_event; + int xfixes_cursor_notify_event; #endif }; -struct xf_server -{ - DWORD port; - HANDLE thread; - freerdp_listener* listener; -}; +#ifdef __cplusplus +extern "C" { +#endif -void* xf_server_thread(void* param); -#endif /* __XFREERDP_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_X11_H */ diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c new file mode 100644 index 000000000..fa59c799b --- /dev/null +++ b/server/shadow/shadow.c @@ -0,0 +1,82 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 +#include +#include + +#include + +#ifdef _WIN32 +static BOOL g_MessagePump = TRUE; +#else +static BOOL g_MessagePump = FALSE; +#endif + +#include + +int main(int argc, char** argv) +{ + MSG msg; + int status; + DWORD dwExitCode; + rdpShadowServer* server; + + server = shadow_server_new(); + + if (!server) + return 0; + + status = shadow_server_parse_command_line(server, argc, argv); + + status = shadow_server_command_line_status_print(server, argc, argv, status); + + if (status < 0) + return 0; + + if (shadow_server_init(server) < 0) + return 0; + + if (shadow_server_start(server) < 0) + return 0; + + if (g_MessagePump) + { + while (GetMessage(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + WaitForSingleObject(server->thread, INFINITE); + + GetExitCodeThread(server->thread, &dwExitCode); + + shadow_server_free(server); + + return 0; +} + diff --git a/server/shadow/shadow.h b/server/shadow/shadow.h new file mode 100644 index 000000000..bc3e97983 --- /dev/null +++ b/server/shadow/shadow.h @@ -0,0 +1,45 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_H +#define FREERDP_SHADOW_SERVER_H + +#include + +#include "shadow_client.h" +#include "shadow_input.h" +#include "shadow_screen.h" +#include "shadow_surface.h" +#include "shadow_encoder.h" +#include "shadow_capture.h" +#include "shadow_channels.h" +#include "shadow_subsystem.h" +#include "shadow_lobby.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_H */ + diff --git a/server/shadow/shadow_capture.c b/server/shadow/shadow_capture.c new file mode 100644 index 000000000..6b1ffeb76 --- /dev/null +++ b/server/shadow/shadow_capture.c @@ -0,0 +1,245 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow_surface.h" + +#include "shadow_capture.h" + +#define TAG SERVER_TAG("shadow") + +int shadow_capture_align_clip_rect(RECTANGLE_16* rect, RECTANGLE_16* clip) +{ + int dx, dy; + + dx = (rect->left % 16); + + if (dx != 0) + { + rect->left -= dx; + rect->right += dx; + } + + dx = (rect->right % 16); + + if (dx != 0) + { + rect->right += (16 - dx); + } + + dy = (rect->top % 16); + + if (dy != 0) + { + rect->top -= dy; + rect->bottom += dy; + } + + dy = (rect->bottom % 16); + + if (dy != 0) + { + rect->bottom += (16 - dy); + } + + if (rect->left < clip->left) + rect->left = clip->left; + + if (rect->top < clip->top) + rect->top = clip->top; + + if (rect->right > clip->right) + rect->right = clip->right; + + if (rect->bottom > clip->bottom) + rect->bottom = clip->bottom; + + return 1; +} + +int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BYTE* pData2, int nStep2, RECTANGLE_16* rect) +{ + BOOL equal; + BOOL allEqual; + int tw, th; + int tx, ty, k; + int nrow, ncol; + int l, t, r, b; + BYTE *p1, *p2; + BOOL rows[1024]; + BOOL cols[1024]; + BOOL grid[1024][1024]; + + allEqual = TRUE; + FillMemory(rows, sizeof(rows), 0xFF); + FillMemory(cols, sizeof(cols), 0xFF); + FillMemory(grid, sizeof(grid), 0xFF); + ZeroMemory(rect, sizeof(RECTANGLE_16)); + + nrow = (nHeight + 15) / 16; + ncol = (nWidth + 15) / 16; + + l = ncol + 1; + r = -1; + + t = nrow + 1; + b = -1; + + for (ty = 0; ty < nrow; ty++) + { + th = ((ty + 1) == nrow) ? (nHeight % 16) : 16; + + if (!th) + th = 16; + + for (tx = 0; tx < ncol; tx++) + { + equal = TRUE; + + tw = ((tx + 1) == ncol) ? (nWidth % 16) : 16; + + if (!tw) + tw = 16; + + p1 = &pData1[(ty * 16 * nStep1) + (tx * 16 * 4)]; + p2 = &pData2[(ty * 16 * nStep2) + (tx * 16 * 4)]; + + for (k = 0; k < th; k++) + { + if (memcmp(p1, p2, tw * 4) != 0) + { + equal = FALSE; + break; + } + + p1 += nStep1; + p2 += nStep2; + } + + if (!equal) + { + grid[ty][tx] = FALSE; + rows[ty] = FALSE; + cols[tx] = FALSE; + + if (l > tx) + l = tx; + + if (r < tx) + r = tx; + } + } + + if (!rows[ty]) + { + allEqual = FALSE; + + if (t > ty) + t = ty; + + if (b < ty) + b = ty; + } + } + + if (allEqual) + return 0; + + rect->left = l * 16; + rect->top = t * 16; + rect->right = (r + 1) * 16; + rect->bottom = (b + 1) * 16; + + if (rect->right > nWidth) + rect->right = nWidth; + + if (rect->bottom > nHeight) + rect->bottom = nHeight; + + if (0) + { + char *col_str = calloc(ncol + 1, sizeof(char)); + if (!col_str) + { + WLog_ERR(TAG, "calloc failed!"); + return 1; + } + + for (tx = 0; tx < ncol; tx++) + sprintf(&col_str[tx], "-"); + WLog_INFO(TAG, "%s", col_str); + + for (tx = 0; tx < ncol; tx++) + sprintf(&col_str[tx], "%c", cols[tx] ? 'O' : 'X'); + WLog_INFO(TAG, "%s", col_str); + + for (tx = 0; tx < ncol; tx++) + sprintf(&col_str[tx], "-"); + WLog_INFO(TAG, "%s", col_str); + + for (ty = 0; ty < nrow; ty++) + { + for (tx = 0; tx < ncol; tx++) + sprintf(&col_str[tx], "%c", cols[tx] ? 'O' : 'X'); + WLog_INFO(TAG, "%s", col_str); + WLog_INFO(TAG, "|%s|", rows[ty] ? "O" : "X"); + } + + WLog_INFO(TAG, "left: %d top: %d right: %d bottom: %d ncol: %d nrow: %d", + l, t, r, b, ncol, nrow); + free(col_str); + } + + return 1; +} + +rdpShadowCapture* shadow_capture_new(rdpShadowServer* server) +{ + rdpShadowCapture* capture; + + capture = (rdpShadowCapture*) calloc(1, sizeof(rdpShadowCapture)); + + if (!capture) + return NULL; + + capture->server = server; + + if (!InitializeCriticalSectionAndSpinCount(&(capture->lock), 4000)) + return NULL; + + return capture; +} + +void shadow_capture_free(rdpShadowCapture* capture) +{ + if (!capture) + return; + + DeleteCriticalSection(&(capture->lock)); + + free(capture); +} + diff --git a/server/shadow/shadow_capture.h b/server/shadow/shadow_capture.h new file mode 100644 index 000000000..3ce3cddb0 --- /dev/null +++ b/server/shadow/shadow_capture.h @@ -0,0 +1,51 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_CAPTURE_H +#define FREERDP_SHADOW_SERVER_CAPTURE_H + +#include + +#include +#include + +struct rdp_shadow_capture +{ + rdpShadowServer* server; + + int width; + int height; + + CRITICAL_SECTION lock; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_capture_align_clip_rect(RECTANGLE_16* rect, RECTANGLE_16* clip); +int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BYTE* pData2, int nStep2, RECTANGLE_16* rect); + +rdpShadowCapture* shadow_capture_new(rdpShadowServer* server); +void shadow_capture_free(rdpShadowCapture* capture); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_CAPTURE_H */ diff --git a/server/X11/cli/xfreerdp.c b/server/shadow/shadow_channels.c similarity index 56% rename from server/X11/cli/xfreerdp.c rename to server/shadow/shadow_channels.c index bd3b27729..5a2e4bb03 100644 --- a/server/X11/cli/xfreerdp.c +++ b/server/shadow/shadow_channels.c @@ -1,8 +1,7 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP X11 Server * - * Copyright 2011 Marc-Andre Moreau + * 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. @@ -21,32 +20,21 @@ #include "config.h" #endif -#include "xf_interface.h" +#include "shadow.h" -int main(int argc, char* argv[]) +#include "shadow_channels.h" + +int shadow_client_channels_post_connect(rdpShadowClient* client) { - HANDLE thread; - xfServer* server; - DWORD dwExitCode; + if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, ENCOMSP_SVC_CHANNEL_NAME)) + { + shadow_client_encomsp_init(client); + } - freerdp_server_global_init(); + if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, REMDESK_SVC_CHANNEL_NAME)) + { + shadow_client_remdesk_init(client); + } - server = freerdp_server_new(argc, argv); - - if (!server) - return 0; - - freerdp_server_start(server); - - thread = freerdp_server_get_thread(server); - - WaitForSingleObject(thread, INFINITE); - - GetExitCodeThread(thread, &dwExitCode); - - freerdp_server_free(server); - - freerdp_server_global_uninit(); - - return 0; + return 1; } diff --git a/server/X11/xf_encode.h b/server/shadow/shadow_channels.h similarity index 57% rename from server/X11/xf_encode.h rename to server/shadow/shadow_channels.h index fb7d98562..7c11eb84e 100644 --- a/server/X11/xf_encode.h +++ b/server/shadow/shadow_channels.h @@ -1,8 +1,7 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * X11 RemoteFX Encoder * - * Copyright 2011 Marc-Andre Moreau + * 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. @@ -17,15 +16,25 @@ * limitations under the License. */ -#ifndef __XF_ENCODE_H -#define __XF_ENCODE_H +#ifndef FREERDP_SHADOW_SERVER_CHANNELS_H +#define FREERDP_SHADOW_SERVER_CHANNELS_H -#include "xfreerdp.h" +#include -#include "xf_peer.h" +#include +#include -XImage* xf_snapshot(xfPeerContext* xfp, int x, int y, int width, int height); -void xf_xdamage_subtract_region(xfPeerContext* xfp, int x, int y, int width, int height); -int xf_update_encode(freerdp_peer* client, int x, int y, int width, int height); +#include "shadow_encomsp.h" +#include "shadow_remdesk.h" -#endif /* __XF_ENCODE_H */ +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_channels_post_connect(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_CHANNELS_H */ diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c new file mode 100644 index 000000000..2c7d35272 --- /dev/null +++ b/server/shadow/shadow_client.c @@ -0,0 +1,831 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 +#include +#include + +#include + +#include "shadow.h" + +#define TAG CLIENT_TAG("shadow") + +void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) +{ + rdpSettings* settings; + rdpShadowServer* server; + + server = (rdpShadowServer*) peer->ContextExtra; + client->server = server; + client->subsystem = server->subsystem; + + settings = peer->settings; + + settings->ColorDepth = 32; + settings->NSCodec = TRUE; + settings->RemoteFxCodec = TRUE; + settings->BitmapCacheV3Enabled = TRUE; + settings->FrameMarkerCommandEnabled = TRUE; + settings->SurfaceFrameMarkerEnabled = TRUE; + settings->SupportGraphicsPipeline = FALSE; + + settings->DrawAllowSkipAlpha = TRUE; + settings->DrawAllowColorSubsampling = TRUE; + settings->DrawAllowDynamicColorFidelity = TRUE; + + settings->RdpSecurity = TRUE; + settings->TlsSecurity = TRUE; + settings->NlaSecurity = FALSE; + + settings->CertificateFile = _strdup(server->CertificateFile); + settings->PrivateKeyFile = _strdup(server->PrivateKeyFile); + + settings->RdpKeyFile = _strdup(settings->PrivateKeyFile); + + client->inLobby = TRUE; + client->mayView = server->mayView; + client->mayInteract = server->mayInteract; + + InitializeCriticalSectionAndSpinCount(&(client->lock), 4000); + + region16_init(&(client->invalidRegion)); + + client->vcm = WTSOpenServerA((LPSTR) peer->context); + + client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + client->encoder = shadow_encoder_new(client); + + ArrayList_Add(server->clients, (void*) client); +} + +void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) +{ + rdpShadowServer* server = client->server; + + ArrayList_Remove(server->clients, (void*) client); + + DeleteCriticalSection(&(client->lock)); + + region16_uninit(&(client->invalidRegion)); + + WTSCloseServer((HANDLE) client->vcm); + + CloseHandle(client->StopEvent); + + if (client->lobby) + { + shadow_surface_free(client->lobby); + client->lobby = NULL; + } + + if (client->encoder) + { + shadow_encoder_free(client->encoder); + client->encoder = NULL; + } +} + +void shadow_client_message_free(wMessage* message) +{ + if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID) + { + SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; + + free(wParam->rects); + free(wParam); + } + else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID) + { + SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; + free(wParam); + } +} + +BOOL shadow_client_capabilities(freerdp_peer* peer) +{ + return TRUE; +} + +BOOL shadow_client_post_connect(freerdp_peer* peer) +{ + int authStatus; + int width, height; + rdpSettings* settings; + rdpShadowClient* client; + rdpShadowServer* server; + RECTANGLE_16 invalidRect; + rdpShadowSubsystem* subsystem; + + client = (rdpShadowClient*) peer->context; + settings = peer->settings; + server = client->server; + subsystem = server->subsystem; + + if (!server->shareSubRect) + { + width = server->screen->width; + height = server->screen->height; + } + else + { + width = server->subRect.right - server->subRect.left; + height = server->subRect.bottom - server->subRect.top; + } + + settings->DesktopWidth = width; + settings->DesktopHeight = height; + + if (settings->ColorDepth == 24) + settings->ColorDepth = 16; /* disable 24bpp */ + + WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)", + peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); + + peer->update->DesktopResize(peer->update->context); + + shadow_client_channels_post_connect(client); + + invalidRect.left = 0; + invalidRect.top = 0; + invalidRect.right = width; + invalidRect.bottom = height; + + region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect); + + shadow_client_init_lobby(client); + + authStatus = -1; + + if (settings->Username && settings->Password) + settings->AutoLogonEnabled = TRUE; + + if (settings->AutoLogonEnabled && server->authentication) + { + if (subsystem->Authenticate) + { + authStatus = subsystem->Authenticate(subsystem, + settings->Username, settings->Domain, settings->Password); + } + } + + if (server->authentication) + { + if (authStatus < 0) + { + WLog_ERR(TAG, "client authentication failure: %d", authStatus); + return FALSE; + } + } + + return TRUE; +} + +void shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas) +{ + wMessage message = { 0 }; + SHADOW_MSG_IN_REFRESH_OUTPUT* wParam; + wMessagePipe* MsgPipe = client->subsystem->MsgPipe; + + wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT)); + + if (!wParam) + return; + + wParam->numRects = (UINT32) count; + + if (wParam->numRects) + { + wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16)); + + if (!wParam->rects) + return; + } + + CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16)); + + message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID; + message.wParam = (void*) wParam; + message.lParam = NULL; + message.context = (void*) client; + message.Free = shadow_client_message_free; + + MessageQueue_Dispatch(MsgPipe->In, &message); +} + +void shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area) +{ + wMessage message = { 0 }; + SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam; + wMessagePipe* MsgPipe = client->subsystem->MsgPipe; + + wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT)); + + if (!wParam) + return; + + wParam->allow = (UINT32) allow; + + if (area) + CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16)); + + message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID; + message.wParam = (void*) wParam; + message.lParam = NULL; + message.context = (void*) client; + message.Free = shadow_client_message_free; + + MessageQueue_Dispatch(MsgPipe->In, &message); +} + +BOOL shadow_client_activate(freerdp_peer* peer) +{ + rdpSettings* settings = peer->settings; + rdpShadowClient* client = (rdpShadowClient*) peer->context; + + if (strcmp(settings->ClientDir, "librdp") == 0) + { + /* Hack for Mac/iOS/Android Microsoft RDP clients */ + + settings->RemoteFxCodec = FALSE; + + settings->NSCodec = FALSE; + settings->NSCodecAllowSubsampling = FALSE; + + settings->SurfaceFrameMarkerEnabled = FALSE; + } + + client->activated = TRUE; + client->inLobby = client->mayView ? FALSE : TRUE; + + shadow_encoder_reset(client->encoder); + + shadow_client_refresh_rect(client, 0, NULL); + + return TRUE; +} + +void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId) +{ + SURFACE_FRAME* frame; + wListDictionary* frameList; + + frameList = client->encoder->frameList; + frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId); + + if (frame) + { + ListDictionary_Remove(frameList, (void*) (size_t) frameId); + free(frame); + } +} + +int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id) +{ + SURFACE_FRAME_MARKER surfaceFrameMarker; + rdpContext* context = (rdpContext*) client; + rdpUpdate* update = context->update; + + surfaceFrameMarker.frameAction = action; + surfaceFrameMarker.frameId = id; + + IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker); + + return 1; +} + +int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight) +{ + int i; + BOOL first; + BOOL last; + wStream* s; + int nSrcStep; + BYTE* pSrcData; + int numMessages; + UINT32 frameId = 0; + rdpUpdate* update; + rdpContext* context; + rdpSettings* settings; + rdpShadowServer* server; + rdpShadowEncoder* encoder; + SURFACE_BITS_COMMAND cmd; + + context = (rdpContext*) client; + update = context->update; + settings = context->settings; + + server = client->server; + encoder = client->encoder; + + pSrcData = surface->data; + nSrcStep = surface->scanline; + + if (server->shareSubRect) + { + int subX, subY; + int subWidth, subHeight; + + subX = server->subRect.left; + subY = server->subRect.top; + subWidth = server->subRect.right - server->subRect.left; + subHeight = server->subRect.bottom - server->subRect.top; + + nXSrc -= subX; + nYSrc -= subY; + pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; + } + + if (encoder->frameAck) + frameId = (UINT32) shadow_encoder_create_frame_id(encoder); + + if (settings->RemoteFxCodec) + { + RFX_RECT rect; + RFX_MESSAGE* messages; + + shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX); + + s = encoder->bs; + + rect.x = nXSrc; + rect.y = nYSrc; + rect.width = nWidth; + rect.height = nHeight; + + messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData, + surface->width, surface->height, nSrcStep, &numMessages, + settings->MultifragMaxRequestSize); + + cmd.codecID = settings->RemoteFxCodecId; + + cmd.destLeft = 0; + cmd.destTop = 0; + cmd.destRight = surface->width; + cmd.destBottom = surface->height; + + cmd.bpp = 32; + cmd.width = surface->width; + cmd.height = surface->height; + + for (i = 0; i < numMessages; i++) + { + Stream_SetPosition(s, 0); + rfx_write_message(encoder->rfx, s, &messages[i]); + rfx_message_free(encoder->rfx, &messages[i]); + + cmd.bitmapDataLength = Stream_GetPosition(s); + cmd.bitmapData = Stream_Buffer(s); + + first = (i == 0) ? TRUE : FALSE; + last = ((i + 1) == numMessages) ? TRUE : FALSE; + + if (!encoder->frameAck) + IFCALL(update->SurfaceBits, update->context, &cmd); + else + IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId); + } + + free(messages); + } + else if (settings->NSCodec) + { + shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC); + + s = encoder->bs; + Stream_SetPosition(s, 0); + + pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + + nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep); + + cmd.bpp = 32; + cmd.codecID = settings->NSCodecId; + cmd.destLeft = nXSrc; + cmd.destTop = nYSrc; + cmd.destRight = cmd.destLeft + nWidth; + cmd.destBottom = cmd.destTop + nHeight; + cmd.width = nWidth; + cmd.height = nHeight; + + cmd.bitmapDataLength = Stream_GetPosition(s); + cmd.bitmapData = Stream_Buffer(s); + + first = TRUE; + last = TRUE; + + if (!encoder->frameAck) + IFCALL(update->SurfaceBits, update->context, &cmd); + else + IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId); + } + + return 1; +} + +int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight) +{ + BYTE* data; + BYTE* buffer; + int yIdx, xIdx, k; + int rows, cols; + int nSrcStep; + BYTE* pSrcData; + UINT32 DstSize; + UINT32 SrcFormat; + BITMAP_DATA* bitmap; + rdpUpdate* update; + rdpContext* context; + rdpSettings* settings; + UINT32 maxUpdateSize; + UINT32 totalBitmapSize; + UINT32 updateSizeEstimate; + BITMAP_DATA* bitmapData; + BITMAP_UPDATE bitmapUpdate; + rdpShadowServer* server; + rdpShadowEncoder* encoder; + + context = (rdpContext*) client; + update = context->update; + settings = context->settings; + + server = client->server; + encoder = client->encoder; + + maxUpdateSize = settings->MultifragMaxRequestSize; + + if (settings->ColorDepth < 32) + shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED); + else + shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR); + + pSrcData = surface->data; + nSrcStep = surface->scanline; + SrcFormat = PIXEL_FORMAT_RGB32; + + if ((nXSrc % 4) != 0) + { + nWidth += (nXSrc % 4); + nXSrc -= (nXSrc % 4); + } + + if ((nYSrc % 4) != 0) + { + nHeight += (nYSrc % 4); + nYSrc -= (nYSrc % 4); + } + + rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0); + cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0); + + k = 0; + totalBitmapSize = 0; + + bitmapUpdate.count = bitmapUpdate.number = rows * cols; + bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number); + bitmapUpdate.rectangles = bitmapData; + + if (!bitmapData) + return -1; + + if ((nWidth % 4) != 0) + { + nXSrc -= (nWidth % 4); + nWidth += (nWidth % 4); + } + + if ((nHeight % 4) != 0) + { + nYSrc -= (nHeight % 4); + nHeight += (nHeight % 4); + } + + for (yIdx = 0; yIdx < rows; yIdx++) + { + for (xIdx = 0; xIdx < cols; xIdx++) + { + bitmap = &bitmapData[k]; + + bitmap->width = 64; + bitmap->height = 64; + bitmap->destLeft = nXSrc + (xIdx * 64); + bitmap->destTop = nYSrc + (yIdx * 64); + + if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth)) + bitmap->width = (nXSrc + nWidth) - bitmap->destLeft; + + if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight)) + bitmap->height = (nYSrc + nHeight) - bitmap->destTop; + + bitmap->destRight = bitmap->destLeft + bitmap->width - 1; + bitmap->destBottom = bitmap->destTop + bitmap->height - 1; + bitmap->compressed = TRUE; + + if ((bitmap->width < 4) || (bitmap->height < 4)) + continue; + + if (settings->ColorDepth < 32) + { + int bitsPerPixel = settings->ColorDepth; + int bytesPerPixel = (bitsPerPixel + 7) / 8; + + DstSize = 64 * 64 * 4; + buffer = encoder->grid[k]; + + interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, + pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel); + + bitmap->bitmapDataStream = buffer; + bitmap->bitmapLength = DstSize; + bitmap->bitsPerPixel = bitsPerPixel; + bitmap->cbScanWidth = bitmap->width * bytesPerPixel; + bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel; + } + else + { + int dstSize; + + buffer = encoder->grid[k]; + data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)]; + + buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, + bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize); + + bitmap->bitmapDataStream = buffer; + bitmap->bitmapLength = dstSize; + bitmap->bitsPerPixel = 32; + bitmap->cbScanWidth = bitmap->width * 4; + bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4; + } + + bitmap->cbCompFirstRowSize = 0; + bitmap->cbCompMainBodySize = bitmap->bitmapLength; + + totalBitmapSize += bitmap->bitmapLength; + k++; + } + } + + bitmapUpdate.count = bitmapUpdate.number = k; + + updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16; + + if (updateSizeEstimate > maxUpdateSize) + { + fprintf(stderr, "update size estimate larger than maximum update size\n"); + } + + IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + + free(bitmapData); + + return 1; +} + +int shadow_client_send_surface_update(rdpShadowClient* client) +{ + int status = -1; + int nXSrc, nYSrc; + int nWidth, nHeight; + rdpContext* context; + rdpSettings* settings; + rdpShadowServer* server; + rdpShadowSurface* surface; + rdpShadowEncoder* encoder; + REGION16 invalidRegion; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16* extents; + + context = (rdpContext*) client; + settings = context->settings; + server = client->server; + encoder = client->encoder; + + surface = client->inLobby ? client->lobby : server->surface; + + EnterCriticalSection(&(client->lock)); + + region16_init(&invalidRegion); + region16_copy(&invalidRegion, &(client->invalidRegion)); + region16_clear(&(client->invalidRegion)); + + LeaveCriticalSection(&(client->lock)); + + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = surface->width; + surfaceRect.bottom = surface->height; + + region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect); + + if (server->shareSubRect) + { + region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)); + } + + if (region16_is_empty(&invalidRegion)) + { + region16_uninit(&invalidRegion); + return 1; + } + + extents = region16_extents(&invalidRegion); + + nXSrc = extents->left - 0; + nYSrc = extents->top - 0; + nWidth = extents->right - extents->left; + nHeight = extents->bottom - extents->top; + + //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d", + // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight); + + if (settings->RemoteFxCodec || settings->NSCodec) + { + status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight); + } + else + { + status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight); + } + + region16_uninit(&invalidRegion); + + return status; +} + +int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) +{ + int index; + int numRects = 0; + const RECTANGLE_16* rects; + + EnterCriticalSection(&(client->lock)); + + rects = region16_rects(region, &numRects); + + for (index = 0; index < numRects; index++) + { + region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); + } + + LeaveCriticalSection(&(client->lock)); + + return 1; +} + +void* shadow_client_thread(rdpShadowClient* client) +{ + DWORD status; + DWORD nCount; + HANDLE events[32]; + HANDLE StopEvent; + HANDLE ClientEvent; + HANDLE ChannelEvent; + HANDLE UpdateEvent; + freerdp_peer* peer; + rdpContext* context; + rdpSettings* settings; + rdpShadowServer* server; + rdpShadowScreen* screen; + rdpShadowEncoder* encoder; + rdpShadowSubsystem* subsystem; + + server = client->server; + screen = server->screen; + encoder = client->encoder; + subsystem = server->subsystem; + + context = (rdpContext*) client; + peer = context->peer; + settings = peer->settings; + + peer->Capabilities = shadow_client_capabilities; + peer->PostConnect = shadow_client_post_connect; + peer->Activate = shadow_client_activate; + + shadow_input_register_callbacks(peer->input); + + peer->Initialize(peer); + + peer->update->RefreshRect = (pRefreshRect) shadow_client_refresh_rect; + peer->update->SuppressOutput = (pSuppressOutput) shadow_client_suppress_output; + peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge) shadow_client_surface_frame_acknowledge; + + StopEvent = client->StopEvent; + UpdateEvent = subsystem->updateEvent; + ClientEvent = peer->GetEventHandle(peer); + ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm); + + while (1) + { + nCount = 0; + events[nCount++] = StopEvent; + events[nCount++] = UpdateEvent; + events[nCount++] = ClientEvent; + events[nCount++] = ChannelEvent; + + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0) + { + if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0) + { + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + } + + break; + } + + if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0) + { + if (client->activated) + { + int index; + int numRects = 0; + const RECTANGLE_16* rects; + + rects = region16_rects(&(subsystem->invalidRegion), &numRects); + + for (index = 0; index < numRects; index++) + { + region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); + } + + shadow_client_send_surface_update(client); + } + + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + + while (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0); + } + + if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0) + { + if (!peer->CheckFileDescriptor(peer)) + { + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); + break; + } + } + + if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0) + { + if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE) + { + WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure"); + break; + } + } + } + + peer->Disconnect(peer); + + freerdp_peer_context_free(peer); + freerdp_peer_free(peer); + + ExitThread(0); + + return NULL; +} + +void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer) +{ + rdpShadowClient* client; + rdpShadowServer* server; + + server = (rdpShadowServer*) listener->info; + + peer->ContextExtra = (void*) server; + peer->ContextSize = sizeof(rdpShadowClient); + peer->ContextNew = (psPeerContextNew) shadow_client_context_new; + peer->ContextFree = (psPeerContextFree) shadow_client_context_free; + freerdp_peer_context_new(peer); + + client = (rdpShadowClient*) peer->context; + + client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) + shadow_client_thread, client, 0, NULL); +} diff --git a/server/shadow/shadow_client.h b/server/shadow/shadow_client.h new file mode 100644 index 000000000..d067554f0 --- /dev/null +++ b/server/shadow/shadow_client.h @@ -0,0 +1,35 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_CLIENT_H +#define FREERDP_SHADOW_SERVER_CLIENT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_surface_update(rdpShadowClient* client, REGION16* region); +void shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_CLIENT_H */ diff --git a/server/shadow/shadow_encoder.c b/server/shadow/shadow_encoder.c new file mode 100644 index 000000000..1e200ee40 --- /dev/null +++ b/server/shadow/shadow_encoder.c @@ -0,0 +1,423 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_encoder.h" + +int shadow_encoder_create_frame_id(rdpShadowEncoder* encoder) +{ + UINT32 frameId; + int inFlightFrames; + SURFACE_FRAME* frame; + + inFlightFrames = ListDictionary_Count(encoder->frameList); + + if (inFlightFrames > encoder->frameAck) + { + encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100; + } + else + { + encoder->fps += 2; + + if (encoder->fps > encoder->maxFps) + encoder->fps = encoder->maxFps; + } + + if (encoder->fps < 1) + encoder->fps = 1; + + frame = (SURFACE_FRAME*) malloc(sizeof(SURFACE_FRAME)); + + if (!frame) + return -1; + + frameId = frame->frameId = ++encoder->frameId; + ListDictionary_Add(encoder->frameList, (void*) (size_t) frame->frameId, frame); + + return (int) frame->frameId; +} + +int shadow_encoder_init_grid(rdpShadowEncoder* encoder) +{ + int i, j, k; + int tileSize; + int tileCount; + + encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth); + encoder->gridHeight = ((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight); + + tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4; + tileCount = encoder->gridWidth * encoder->gridHeight; + + encoder->gridBuffer = (BYTE*) malloc(tileSize * tileCount); + + if (!encoder->gridBuffer) + return -1; + + encoder->grid = (BYTE**) malloc(tileCount * sizeof(BYTE*)); + + if (!encoder->grid) + return -1; + + for (i = 0; i < encoder->gridHeight; i++) + { + for (j = 0; j < encoder->gridWidth; j++) + { + k = (i * encoder->gridWidth) + j; + encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]); + } + } + + return 0; +} + +int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder) +{ + if (encoder->gridBuffer) + { + free(encoder->gridBuffer); + encoder->gridBuffer = NULL; + } + + if (encoder->grid) + { + free(encoder->grid); + encoder->grid = NULL; + } + + encoder->gridWidth = 0; + encoder->gridHeight = 0; + + return 0; +} + +int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) +{ + rdpContext* context = (rdpContext*) encoder->client; + rdpSettings* settings = context->settings; + + if (!encoder->rfx) + encoder->rfx = rfx_context_new(TRUE); + + if (!encoder->rfx) + return -1; + + encoder->rfx->mode = RLGR3; + encoder->rfx->width = encoder->width; + encoder->rfx->height = encoder->height; + + rfx_context_set_pixel_format(encoder->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); + + if (!encoder->frameList) + { + encoder->fps = 16; + encoder->maxFps = 32; + encoder->frameId = 0; + encoder->frameList = ListDictionary_New(TRUE); + encoder->frameAck = settings->SurfaceFrameMarkerEnabled; + } + + encoder->codecs |= FREERDP_CODEC_REMOTEFX; + + return 1; +} + +int shadow_encoder_init_nsc(rdpShadowEncoder* encoder) +{ + rdpContext* context = (rdpContext*) encoder->client; + rdpSettings* settings = context->settings; + + if (!encoder->nsc) + encoder->nsc = nsc_context_new(); + + if (!encoder->nsc) + return -1; + + nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); + + if (!encoder->frameList) + { + encoder->fps = 16; + encoder->maxFps = 32; + encoder->frameId = 0; + encoder->frameList = ListDictionary_New(TRUE); + encoder->frameAck = settings->SurfaceFrameMarkerEnabled; + } + + encoder->nsc->ColorLossLevel = settings->NSCodecColorLossLevel; + encoder->nsc->ChromaSubsamplingLevel = settings->NSCodecAllowSubsampling ? 1 : 0; + encoder->nsc->DynamicColorFidelity = settings->NSCodecAllowDynamicColorFidelity; + + encoder->codecs |= FREERDP_CODEC_NSCODEC; + + return 1; +} + +int shadow_encoder_init_planar(rdpShadowEncoder* encoder) +{ + DWORD planarFlags = 0; + rdpContext* context = (rdpContext*) encoder->client; + rdpSettings* settings = context->settings; + + if (settings->DrawAllowSkipAlpha) + planarFlags |= PLANAR_FORMAT_HEADER_NA; + + planarFlags |= PLANAR_FORMAT_HEADER_RLE; + + if (!encoder->planar) + { + encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, + encoder->maxTileWidth, encoder->maxTileHeight); + } + + if (!encoder->planar) + return -1; + + encoder->codecs |= FREERDP_CODEC_PLANAR; + + return 1; +} + +int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder) +{ + if (!encoder->interleaved) + encoder->interleaved = bitmap_interleaved_context_new(TRUE); + + if (!encoder->interleaved) + return -1; + + encoder->codecs |= FREERDP_CODEC_INTERLEAVED; + + return 1; +} + +int shadow_encoder_init(rdpShadowEncoder* encoder) +{ + encoder->maxTileWidth = 64; + encoder->maxTileHeight = 64; + + shadow_encoder_init_grid(encoder); + + if (!encoder->bs) + encoder->bs = Stream_New(NULL, encoder->maxTileWidth * encoder->maxTileHeight * 4); + + if (!encoder->bs) + return -1; + + return 1; +} + +int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder) +{ + if (encoder->rfx) + { + rfx_context_free(encoder->rfx); + encoder->rfx = NULL; + } + + if (encoder->frameList) + { + ListDictionary_Free(encoder->frameList); + encoder->frameList = NULL; + } + + encoder->codecs &= ~FREERDP_CODEC_REMOTEFX; + + return 1; +} + +int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder) +{ + if (encoder->nsc) + { + nsc_context_free(encoder->nsc); + encoder->nsc = NULL; + } + + if (encoder->frameList) + { + ListDictionary_Free(encoder->frameList); + encoder->frameList = NULL; + } + + encoder->codecs &= ~FREERDP_CODEC_NSCODEC; + + return 1; +} + +int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder) +{ + if (encoder->planar) + { + freerdp_bitmap_planar_context_free(encoder->planar); + encoder->planar = NULL; + } + + encoder->codecs &= ~FREERDP_CODEC_PLANAR; + + return 1; +} + +int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder) +{ + if (encoder->interleaved) + { + bitmap_interleaved_context_free(encoder->interleaved); + encoder->interleaved = NULL; + } + + encoder->codecs &= ~FREERDP_CODEC_INTERLEAVED; + + return 1; +} + +int shadow_encoder_uninit(rdpShadowEncoder* encoder) +{ + shadow_encoder_uninit_grid(encoder); + + if (encoder->bs) + { + Stream_Free(encoder->bs, TRUE); + encoder->bs = NULL; + } + + if (encoder->codecs & FREERDP_CODEC_REMOTEFX) + { + shadow_encoder_uninit_rfx(encoder); + } + + if (encoder->codecs & FREERDP_CODEC_NSCODEC) + { + shadow_encoder_uninit_nsc(encoder); + } + + if (encoder->codecs & FREERDP_CODEC_PLANAR) + { + shadow_encoder_uninit_planar(encoder); + } + + if (encoder->codecs & FREERDP_CODEC_INTERLEAVED) + { + shadow_encoder_uninit_interleaved(encoder); + } + + return 1; +} + +int shadow_encoder_reset(rdpShadowEncoder* encoder) +{ + int status; + UINT32 codecs = encoder->codecs; + + status = shadow_encoder_uninit(encoder); + + if (status < 0) + return -1; + + status = shadow_encoder_init(encoder); + + if (status < 0) + return -1; + + status = shadow_encoder_prepare(encoder, codecs); + + if (status < 0) + return -1; + + return 1; +} + +int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs) +{ + int status; + + if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX)) + { + status = shadow_encoder_init_rfx(encoder); + + if (status < 0) + return -1; + } + + if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC)) + { + status = shadow_encoder_init_nsc(encoder); + + if (status < 0) + return -1; + } + + if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR)) + { + status = shadow_encoder_init_planar(encoder); + + if (status < 0) + return -1; + } + + if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED)) + { + status = shadow_encoder_init_interleaved(encoder); + + if (status < 0) + return -1; + } + + return 1; +} + +rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client) +{ + rdpShadowEncoder* encoder; + rdpShadowServer* server = client->server; + + encoder = (rdpShadowEncoder*) calloc(1, sizeof(rdpShadowEncoder)); + + if (!encoder) + return NULL; + + encoder->client = client; + encoder->server = server; + + encoder->fps = 16; + encoder->maxFps = 32; + + encoder->width = server->screen->width; + encoder->height = server->screen->height; + + if (shadow_encoder_init(encoder) < 0) + return NULL; + + return encoder; +} + +void shadow_encoder_free(rdpShadowEncoder* encoder) +{ + if (!encoder) + return; + + shadow_encoder_uninit(encoder); + + free(encoder); +} diff --git a/server/shadow/shadow_encoder.h b/server/shadow/shadow_encoder.h new file mode 100644 index 000000000..34b8d0ef5 --- /dev/null +++ b/server/shadow/shadow_encoder.h @@ -0,0 +1,75 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_ENCODER_H +#define FREERDP_SHADOW_SERVER_ENCODER_H + +#include +#include + +#include +#include + +#include + +struct rdp_shadow_encoder +{ + rdpShadowClient* client; + rdpShadowServer* server; + + int width; + int height; + UINT32 codecs; + + BYTE** grid; + int gridWidth; + int gridHeight; + BYTE* gridBuffer; + int maxTileWidth; + int maxTileHeight; + + wStream* bs; + + RFX_CONTEXT* rfx; + NSC_CONTEXT* nsc; + BITMAP_PLANAR_CONTEXT* planar; + BITMAP_INTERLEAVED_CONTEXT* interleaved; + + int fps; + int maxFps; + BOOL frameAck; + UINT32 frameId; + wListDictionary* frameList; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_encoder_reset(rdpShadowEncoder* encoder); +int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs); +int shadow_encoder_create_frame_id(rdpShadowEncoder* encoder); + +rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client); +void shadow_encoder_free(rdpShadowEncoder* encoder); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_ENCODER_H */ diff --git a/server/shadow/shadow_encomsp.c b/server/shadow/shadow_encomsp.c new file mode 100644 index 000000000..ad0be4870 --- /dev/null +++ b/server/shadow/shadow_encomsp.c @@ -0,0 +1,111 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_encomsp.h" + +#define TAG SERVER_TAG("shadow") + +static int encomsp_change_participant_control_level(EncomspServerContext* context, + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu) +{ + BOOL inLobby; + BOOL mayView; + BOOL mayInteract; + rdpShadowClient* client = (rdpShadowClient*) context->custom; + + WLog_INFO(TAG, "ChangeParticipantControlLevel: ParticipantId: %d Flags: 0x%04X", + pdu->ParticipantId, pdu->Flags); + + mayView = (pdu->Flags & ENCOMSP_MAY_VIEW) ? TRUE : FALSE; + mayInteract = (pdu->Flags & ENCOMSP_MAY_INTERACT) ? TRUE : FALSE; + + if (mayInteract && !mayView) + mayView = TRUE; /* may interact implies may view */ + + if (mayInteract) + { + if (!client->mayInteract) + { + /* request interact + view */ + client->mayInteract = TRUE; + client->mayView = TRUE; + } + } + else if (mayView) + { + if (client->mayInteract) + { + /* release interact */ + client->mayInteract = FALSE; + } + else if (!client->mayView) + { + /* request view */ + client->mayView = TRUE; + } + } + else + { + if (client->mayInteract) + { + /* release interact + view */ + client->mayView = FALSE; + client->mayInteract = FALSE; + } + else if (client->mayView) + { + /* release view */ + client->mayView = FALSE; + client->mayInteract = FALSE; + } + } + + inLobby = client->mayView ? FALSE : TRUE; + + if (inLobby != client->inLobby) + { + shadow_encoder_reset(client->encoder); + client->inLobby = inLobby; + } + + return 1; +} + +int shadow_client_encomsp_init(rdpShadowClient* client) +{ + EncomspServerContext* encomsp; + + encomsp = client->encomsp = encomsp_server_context_new(client->vcm); + + encomsp->custom = (void*) client; + + encomsp->ChangeParticipantControlLevel = encomsp_change_participant_control_level; + + if (client->encomsp) + client->encomsp->Start(client->encomsp); + + return 1; +} + diff --git a/server/shadow/shadow_encomsp.h b/server/shadow/shadow_encomsp.h new file mode 100644 index 000000000..d7187b5cb --- /dev/null +++ b/server/shadow/shadow_encomsp.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_ENCOMSP_H +#define FREERDP_SHADOW_SERVER_ENCOMSP_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_encomsp_init(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_ENCOMSP_H */ diff --git a/server/shadow/shadow_input.c b/server/shadow/shadow_input.c new file mode 100644 index 000000000..f5cc078dc --- /dev/null +++ b/server/shadow/shadow_input.c @@ -0,0 +1,102 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +void shadow_input_synchronize_event(rdpInput* input, UINT32 flags) +{ + rdpShadowClient* client = (rdpShadowClient*) input->context; + rdpShadowSubsystem* subsystem = client->server->subsystem; + + if (!client->mayInteract) + return; + + if (subsystem->SynchronizeEvent) + { + subsystem->SynchronizeEvent(subsystem, flags); + } +} + +void shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + rdpShadowClient* client = (rdpShadowClient*) input->context; + rdpShadowSubsystem* subsystem = client->server->subsystem; + + if (!client->mayInteract) + return; + + if (subsystem->KeyboardEvent) + { + subsystem->KeyboardEvent(subsystem, flags, code); + } +} + +void shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + rdpShadowClient* client = (rdpShadowClient*) input->context; + rdpShadowSubsystem* subsystem = client->server->subsystem; + + if (!client->mayInteract) + return; + + if (subsystem->UnicodeKeyboardEvent) + { + subsystem->UnicodeKeyboardEvent(subsystem, flags, code); + } +} + +void shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + rdpShadowClient* client = (rdpShadowClient*) input->context; + rdpShadowSubsystem* subsystem = client->server->subsystem; + + if (!client->mayInteract) + return; + + if (subsystem->MouseEvent) + { + subsystem->MouseEvent(subsystem, flags, x, y); + } +} + +void shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + rdpShadowClient* client = (rdpShadowClient*) input->context; + rdpShadowSubsystem* subsystem = client->server->subsystem; + + if (!client->mayInteract) + return; + + if (subsystem->ExtendedMouseEvent) + { + subsystem->ExtendedMouseEvent(subsystem, flags, x, y); + } +} + +void shadow_input_register_callbacks(rdpInput* input) +{ + input->SynchronizeEvent = shadow_input_synchronize_event; + input->KeyboardEvent = shadow_input_keyboard_event; + input->UnicodeKeyboardEvent = shadow_input_unicode_keyboard_event; + input->MouseEvent = shadow_input_mouse_event; + input->ExtendedMouseEvent = shadow_input_extended_mouse_event; +} diff --git a/include/freerdp/utils/bitmap.h b/server/shadow/shadow_input.h similarity index 68% rename from include/freerdp/utils/bitmap.h rename to server/shadow/shadow_input.h index b9d4dcf94..cc87ffc6e 100644 --- a/include/freerdp/utils/bitmap.h +++ b/server/shadow/shadow_input.h @@ -1,8 +1,7 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Bitmap File Format Utils * - * Copyright 2011 Marc-Andre Moreau + * 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. @@ -17,19 +16,19 @@ * limitations under the License. */ -#ifndef FREERDP_UTILS_BITMAP_H -#define FREERDP_UTILS_BITMAP_H +#ifndef FREERDP_SHADOW_SERVER_INPUT_H +#define FREERDP_SHADOW_SERVER_INPUT_H -#include +#include #ifdef __cplusplus extern "C" { #endif -FREERDP_API void freerdp_bitmap_write(char* filename, void* data, int width, int height, int bpp); +void shadow_input_register_callbacks(rdpInput* input); #ifdef __cplusplus } #endif -#endif /* FREERDP_UTILS_BITMAP_H */ +#endif /* FREERDP_SHADOW_SERVER_INPUT_H */ diff --git a/server/shadow/shadow_lobby.c b/server/shadow/shadow_lobby.c new file mode 100644 index 000000000..0c4a8d6e3 --- /dev/null +++ b/server/shadow/shadow_lobby.c @@ -0,0 +1,69 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_lobby.h" + +int shadow_client_init_lobby(rdpShadowClient* client) +{ + int width; + int height; + rdtkEngine* engine; + rdtkSurface* surface; + RECTANGLE_16 invalidRect; + rdpShadowSurface* lobby; + rdpContext* context = (rdpContext*) client; + rdpSettings* settings = context->settings; + + width = settings->DesktopWidth; + height = settings->DesktopHeight; + + lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height); + + if (!client->lobby) + return -1; + + engine = rdtk_engine_new(); + + surface = rdtk_surface_new(engine, lobby->data, lobby->width, lobby->height, lobby->scanline); + + rdtk_surface_fill(surface, 0, 0, width, height, 0x3BB9FF); + //rdtk_label_draw(surface, 16, 16, 128, 32, NULL, "label", 0, 0); + //rdtk_button_draw(surface, 16, 64, 128, 32, NULL, "button"); + //rdtk_text_field_draw(surface, 16, 128, 128, 32, NULL, "text field"); + + rdtk_surface_free(surface); + + rdtk_engine_free(engine); + + invalidRect.left = 0; + invalidRect.top = 0; + invalidRect.right = width; + invalidRect.bottom = height; + + region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect); + + return 1; +} diff --git a/server/shadow/shadow_lobby.h b/server/shadow/shadow_lobby.h new file mode 100644 index 000000000..3c9313045 --- /dev/null +++ b/server/shadow/shadow_lobby.h @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_LOBBY_H +#define FREERDP_SHADOW_SERVER_LOBBY_H + +#include + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_init_lobby(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_LOBBY_H */ diff --git a/server/shadow/shadow_remdesk.c b/server/shadow/shadow_remdesk.c new file mode 100644 index 000000000..62af21729 --- /dev/null +++ b/server/shadow/shadow_remdesk.c @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_remdesk.h" + +int shadow_client_remdesk_init(rdpShadowClient* client) +{ + RemdeskServerContext* remdesk; + + remdesk = client->remdesk = remdesk_server_context_new(client->vcm); + + remdesk->custom = (void*) client; + + if (client->remdesk) + client->remdesk->Start(client->remdesk); + + return 1; +} diff --git a/server/shadow/shadow_remdesk.h b/server/shadow/shadow_remdesk.h new file mode 100644 index 000000000..f99a42d24 --- /dev/null +++ b/server/shadow/shadow_remdesk.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_REMDESK_H +#define FREERDP_SHADOW_SERVER_REMDESK_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_client_remdesk_init(rdpShadowClient* client); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_REMDESK_H */ diff --git a/server/shadow/shadow_screen.c b/server/shadow/shadow_screen.c new file mode 100644 index 000000000..3182b642c --- /dev/null +++ b/server/shadow/shadow_screen.c @@ -0,0 +1,85 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow_surface.h" + +#include "shadow_screen.h" + +rdpShadowScreen* shadow_screen_new(rdpShadowServer* server) +{ + int x, y; + int width, height; + MONITOR_DEF* primary; + rdpShadowScreen* screen; + rdpShadowSubsystem* subsystem; + + screen = (rdpShadowScreen*) calloc(1, sizeof(rdpShadowScreen)); + + if (!screen) + return NULL; + + screen->server = server; + subsystem = server->subsystem; + + if (!InitializeCriticalSectionAndSpinCount(&(screen->lock), 4000)) + return NULL; + + region16_init(&(screen->invalidRegion)); + + primary = &(subsystem->monitors[subsystem->selectedMonitor]); + + x = primary->left; + y = primary->top; + width = primary->right - primary->left; + height = primary->bottom - primary->top; + + screen->width = width; + screen->height = height; + + screen->primary = shadow_surface_new(server, x, y, width, height); + + if (!screen->primary) + return NULL; + + server->surface = screen->primary; + + return screen; +} + +void shadow_screen_free(rdpShadowScreen* screen) +{ + if (!screen) + return; + + DeleteCriticalSection(&(screen->lock)); + + region16_uninit(&(screen->invalidRegion)); + + if (screen->primary) + { + shadow_surface_free(screen->primary); + screen->primary = NULL; + } + + free(screen); +} + diff --git a/server/shadow/shadow_screen.h b/server/shadow/shadow_screen.h new file mode 100644 index 000000000..2b305e336 --- /dev/null +++ b/server/shadow/shadow_screen.h @@ -0,0 +1,51 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_SCREEN_H +#define FREERDP_SHADOW_SERVER_SCREEN_H + +#include + +#include +#include + +struct rdp_shadow_screen +{ + rdpShadowServer* server; + + int width; + int height; + + CRITICAL_SECTION lock; + REGION16 invalidRegion; + + rdpShadowSurface* primary; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +rdpShadowScreen* shadow_screen_new(rdpShadowServer* server); +void shadow_screen_free(rdpShadowScreen* screen); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_SCREEN_H */ diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c new file mode 100644 index 000000000..48b0192ed --- /dev/null +++ b/server/shadow/shadow_server.c @@ -0,0 +1,644 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 +#include +#include + +#include +#include + +#include + +#ifndef _WIN32 +#include +#include +#endif + +#include "shadow.h" + +#define TAG SERVER_TAG("shadow") + +static COMMAND_LINE_ARGUMENT_A shadow_args[] = +{ + { "port", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Server port" }, + { "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Server IPC socket" }, + { "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", NULL, NULL, -1, NULL, "Select or list monitors" }, + { "rect", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Select rectangle within monitor to share" }, + { "auth", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Clients must authenticate" }, + { "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" }, + { "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" }, + { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" }, + { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } +}; + +int shadow_server_print_command_line_help(int argc, char** argv) +{ + char* str; + int length; + COMMAND_LINE_ARGUMENT_A* arg; + + WLog_INFO(TAG, "Usage: %s [options]", argv[0]); + WLog_INFO(TAG, ""); + + WLog_INFO(TAG, "Syntax:"); + WLog_INFO(TAG, " /flag (enables flag)"); + WLog_INFO(TAG, " /option: (specifies option with value)"); + WLog_INFO(TAG, " +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')"); + WLog_INFO(TAG, ""); + + arg = shadow_args; + + do + { + if (arg->Flags & COMMAND_LINE_VALUE_FLAG) + { + WLog_INFO(TAG, " %s", "/"); + WLog_INFO(TAG, "%-20s", arg->Name); + WLog_INFO(TAG, "\t%s", arg->Text); + } + else if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) || (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)) + { + WLog_INFO(TAG, " %s", "/"); + + if (arg->Format) + { + length = (int) (strlen(arg->Name) + strlen(arg->Format) + 2); + str = (char*) malloc(length + 1); + sprintf_s(str, length + 1, "%s:%s", arg->Name, arg->Format); + WLog_INFO(TAG, "%-20s", str); + free(str); + } + else + { + WLog_INFO(TAG, "%-20s", arg->Name); + } + + WLog_INFO(TAG, "\t%s", arg->Text); + } + else if (arg->Flags & COMMAND_LINE_VALUE_BOOL) + { + length = (int) strlen(arg->Name) + 32; + str = (char*) malloc(length + 1); + sprintf_s(str, length + 1, "%s (default:%s)", arg->Name, + arg->Default ? "on" : "off"); + + WLog_INFO(TAG, " %s", arg->Default ? "-" : "+"); + + WLog_INFO(TAG, "%-20s", str); + free(str); + + WLog_INFO(TAG, "\t%s", arg->Text); + } + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return 1; +} + +int shadow_server_command_line_status_print(rdpShadowServer* server, int argc, char** argv, int status) +{ + if (status == COMMAND_LINE_STATUS_PRINT_VERSION) + { + WLog_INFO(TAG, "FreeRDP version %s (git %s)", FREERDP_VERSION_FULL, GIT_REVISION); + return COMMAND_LINE_STATUS_PRINT_VERSION; + } + else if (status == COMMAND_LINE_STATUS_PRINT) + { + return COMMAND_LINE_STATUS_PRINT; + } + else if (status < 0) + { + shadow_server_print_command_line_help(argc, argv); + return COMMAND_LINE_STATUS_PRINT_HELP; + } + + return 1; +} + +int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** argv) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + + if (argc < 2) + return 1; + + CommandLineClearArgumentsA(shadow_args); + + flags = COMMAND_LINE_SEPARATOR_COLON; + flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS; + + status = CommandLineParseArgumentsA(argc, (const char**) argv, shadow_args, flags, server, NULL, NULL); + + if (status < 0) + return status; + + arg = shadow_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + CommandLineSwitchStart(arg) + + CommandLineSwitchCase(arg, "port") + { + server->port = (DWORD) atoi(arg->Value); + } + CommandLineSwitchCase(arg, "ipc-socket") + { + server->ipcSocket = _strdup(arg->Value); + } + CommandLineSwitchCase(arg, "may-view") + { + server->mayView = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "may-interact") + { + server->mayInteract = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchCase(arg, "rect") + { + char* p; + char* tok[4]; + int x, y, w, h; + char* str = _strdup(arg->Value); + + if (!str) + return -1; + + tok[0] = p = str; + + p = strchr(p + 1, ','); + + if (!p) + return -1; + + *p++ = '\0'; + tok[1] = p; + + p = strchr(p + 1, ','); + + if (!p) + return -1; + + *p++ = '\0'; + tok[2] = p; + + p = strchr(p + 1, ','); + + if (!p) + return -1; + + *p++ = '\0'; + tok[3] = p; + + x = atoi(tok[0]); + y = atoi(tok[1]); + w = atoi(tok[2]); + h = atoi(tok[3]); + + if ((x < 0) || (y < 0) || (w < 1) || (h < 1)) + return -1; + + server->subRect.left = x; + server->subRect.top = y; + server->subRect.right = x + w; + server->subRect.bottom = y + h; + server->shareSubRect = TRUE; + } + CommandLineSwitchCase(arg, "auth") + { + server->authentication = arg->Value ? TRUE : FALSE; + } + CommandLineSwitchDefault(arg) + { + + } + + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + arg = CommandLineFindArgumentA(shadow_args, "monitors"); + + if (arg && (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + { + int index; + int numMonitors; + MONITOR_DEF monitors[16]; + + numMonitors = shadow_enum_monitors(monitors, 16, 0); + + if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) + { + /* Select monitors */ + + index = atoi(arg->Value); + + if (index < 0) + index = 0; + + if (index >= numMonitors) + index = 0; + + server->selectedMonitor = index; + } + else + { + int width, height; + MONITOR_DEF* monitor; + + /* List monitors */ + + for (index = 0; index < numMonitors; index++) + { + monitor = &monitors[index]; + + width = monitor->right - monitor->left; + height = monitor->bottom - monitor->top; + + WLog_INFO(TAG, " %s [%d] %dx%d\t+%d+%d", + (monitor->flags == 1) ? "*" : " ", index, + width, height, monitor->left, monitor->top); + } + + status = COMMAND_LINE_STATUS_PRINT; + } + } + + return status; +} + +void* shadow_server_thread(rdpShadowServer* server) +{ + DWORD status; + DWORD nCount; + HANDLE events[32]; + HANDLE StopEvent; + freerdp_listener* listener; + rdpShadowSubsystem* subsystem; + + listener = server->listener; + StopEvent = server->StopEvent; + subsystem = server->subsystem; + + shadow_subsystem_start(server->subsystem); + + while (1) + { + nCount = 0; + + if (listener->GetEventHandles(listener, events, &nCount) < 0) + { + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); + break; + } + + events[nCount++] = server->StopEvent; + + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(server->StopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (!listener->CheckFileDescriptor(listener)) + { + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); + break; + } + +#ifdef _WIN32 + Sleep(100); /* FIXME: listener event handles */ +#endif + } + + listener->Close(listener); + + shadow_subsystem_stop(server->subsystem); + + ExitThread(0); + + return NULL; +} + +int shadow_server_start(rdpShadowServer* server) +{ + BOOL status; + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + return -1; + +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + + server->screen = shadow_screen_new(server); + + if (!server->screen) + return -1; + + server->capture = shadow_capture_new(server); + + if (!server->capture) + return -1; + + if (!server->ipcSocket) + status = server->listener->Open(server->listener, NULL, (UINT16) server->port); + else + status = server->listener->OpenLocal(server->listener, server->ipcSocket); + + if (status) + { + server->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) + shadow_server_thread, (void*) server, 0, NULL); + } + + return 0; +} + +int shadow_server_stop(rdpShadowServer* server) +{ + if (server->thread) + { + SetEvent(server->StopEvent); + WaitForSingleObject(server->thread, INFINITE); + CloseHandle(server->thread); + server->thread = NULL; + + server->listener->Close(server->listener); + } + + if (server->screen) + { + shadow_screen_free(server->screen); + server->screen = NULL; + } + + if (server->capture) + { + shadow_capture_free(server->capture); + server->capture = NULL; + } + + return 0; +} + +int shadow_server_init_config_path(rdpShadowServer* server) +{ +#ifdef _WIN32 + if (!server->ConfigPath) + { + server->ConfigPath = GetEnvironmentSubPath("LOCALAPPDATA", "freerdp"); + } +#endif + +#ifdef __APPLE__ + if (!server->ConfigPath) + { + char* userLibraryPath; + char* userApplicationSupportPath; + + userLibraryPath = GetKnownSubPath(KNOWN_PATH_HOME, "Library"); + + if (userLibraryPath) + { + if (!PathFileExistsA(userLibraryPath)) + CreateDirectoryA(userLibraryPath, 0); + + userApplicationSupportPath = GetCombinedPath(userLibraryPath, "Application Support"); + + if (userApplicationSupportPath) + { + if (!PathFileExistsA(userApplicationSupportPath)) + CreateDirectoryA(userApplicationSupportPath, 0); + + server->ConfigPath = GetCombinedPath(userApplicationSupportPath, "freerdp"); + } + + free(userLibraryPath); + free(userApplicationSupportPath); + } + } +#endif + + if (!server->ConfigPath) + { + char* configHome; + + configHome = GetKnownPath(KNOWN_PATH_XDG_CONFIG_HOME); + + if (configHome) + { + if (!PathFileExistsA(configHome)) + CreateDirectoryA(configHome, 0); + + server->ConfigPath = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, "freerdp"); + + free(configHome); + } + } + + if (!server->ConfigPath) + return -1; /* no usable config path */ + + return 1; +} + +int shadow_server_init_certificate(rdpShadowServer* server) +{ + char* filepath; + MAKECERT_CONTEXT* makecert; + + const char* makecert_argv[6] = + { + "makecert", + "-rdp", + "-live", + "-silent", + "-y", "5" + }; + + int makecert_argc = (sizeof(makecert_argv) / sizeof(char*)); + + if (!PathFileExistsA(server->ConfigPath)) + CreateDirectoryA(server->ConfigPath, 0); + + filepath = GetCombinedPath(server->ConfigPath, "shadow"); + + if (!filepath) + return -1; + + if (!PathFileExistsA(filepath)) + CreateDirectoryA(filepath, 0); + + server->CertificateFile = GetCombinedPath(filepath, "shadow.crt"); + server->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key"); + + if ((!PathFileExistsA(server->CertificateFile)) || + (!PathFileExistsA(server->PrivateKeyFile))) + { + makecert = makecert_context_new(); + + makecert_context_process(makecert, makecert_argc, (char**) makecert_argv); + + makecert_context_set_output_file_name(makecert, "shadow"); + + if (!PathFileExistsA(server->CertificateFile)) + makecert_context_output_certificate_file(makecert, filepath); + + if (!PathFileExistsA(server->PrivateKeyFile)) + makecert_context_output_private_key_file(makecert, filepath); + + makecert_context_free(makecert); + } + + free(filepath); + + return 1; +} + +int shadow_server_init(rdpShadowServer* server) +{ + int status; + + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); + + WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()); + + server->clients = ArrayList_New(TRUE); + + server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + InitializeCriticalSectionAndSpinCount(&(server->lock), 4000); + + status = shadow_server_init_config_path(server); + + if (status < 0) + return -1; + + status = shadow_server_init_certificate(server); + + if (status < 0) + return -1; + + server->listener = freerdp_listener_new(); + + if (!server->listener) + return -1; + + server->listener->info = (void*) server; + server->listener->PeerAccepted = shadow_client_accepted; + + server->subsystem = shadow_subsystem_new(NULL); + + if (!server->subsystem) + return -1; + + status = shadow_subsystem_init(server->subsystem, server); + + return status; +} + +int shadow_server_uninit(rdpShadowServer* server) +{ + shadow_server_stop(server); + + if (server->listener) + { + freerdp_listener_free(server->listener); + server->listener = NULL; + } + + if (server->CertificateFile) + { + free(server->CertificateFile); + server->CertificateFile = NULL; + } + + if (server->PrivateKeyFile) + { + free(server->PrivateKeyFile); + server->PrivateKeyFile = NULL; + } + + if (server->ipcSocket) + { + free(server->ipcSocket); + server->ipcSocket = NULL; + } + + shadow_subsystem_uninit(server->subsystem); + + return 1; +} + +rdpShadowServer* shadow_server_new() +{ + rdpShadowServer* server; + + server = (rdpShadowServer*) calloc(1, sizeof(rdpShadowServer)); + + if (!server) + return NULL; + + server->port = 3389; + server->mayView = TRUE; + server->mayInteract = TRUE; + +#ifdef WITH_SHADOW_X11 + server->authentication = TRUE; +#else + server->authentication = FALSE; +#endif + + return server; +} + +void shadow_server_free(rdpShadowServer* server) +{ + if (!server) + return; + + DeleteCriticalSection(&(server->lock)); + + if (server->clients) + { + ArrayList_Free(server->clients); + server->clients = NULL; + } + + shadow_subsystem_free(server->subsystem); + + free(server); +} + diff --git a/server/shadow/shadow_subsystem.c b/server/shadow/shadow_subsystem.c new file mode 100644 index 000000000..f0ed9b85b --- /dev/null +++ b/server/shadow/shadow_subsystem.c @@ -0,0 +1,209 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_subsystem.h" + +struct _RDP_SHADOW_SUBSYSTEM +{ + const char* name; + pfnShadowSubsystemEntry entry; +}; +typedef struct _RDP_SHADOW_SUBSYSTEM RDP_SHADOW_SUBSYSTEM; + + +#ifdef WITH_SHADOW_X11 +extern int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + +#ifdef WITH_SHADOW_MAC +extern int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + +#ifdef WITH_SHADOW_WIN +extern int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + + +static RDP_SHADOW_SUBSYSTEM g_Subsystems[] = +{ + +#ifdef WITH_SHADOW_X11 + { "X11", X11_ShadowSubsystemEntry }, +#endif + +#ifdef WITH_SHADOW_MAC + { "Mac", Mac_ShadowSubsystemEntry }, +#endif + +#ifdef WITH_SHADOW_WIN + { "Win", Win_ShadowSubsystemEntry }, +#endif + + { "", NULL } +}; + +static int g_SubsystemCount = (sizeof(g_Subsystems) / sizeof(g_Subsystems[0])); + +pfnShadowSubsystemEntry shadow_subsystem_load_static_entry(const char* name) +{ + int index; + + if (!name) + { + for (index = 0; index < g_SubsystemCount; index++) + { + if (g_Subsystems[index].name) + return g_Subsystems[index].entry; + } + } + + for (index = 0; index < g_SubsystemCount; index++) + { + if (strcmp(name, g_Subsystems[index].name) == 0) + return g_Subsystems[index].entry; + } + + return NULL; +} + +int shadow_subsystem_load_entry_points(RDP_SHADOW_ENTRY_POINTS* pEntryPoints, const char* name) +{ + pfnShadowSubsystemEntry entry; + + entry = shadow_subsystem_load_static_entry(name); + + if (!entry) + return -1; + + ZeroMemory(pEntryPoints, sizeof(RDP_SHADOW_ENTRY_POINTS)); + + if (entry(pEntryPoints) < 0) + return -1; + + return 1; +} + +rdpShadowSubsystem* shadow_subsystem_new(const char* name) +{ + RDP_SHADOW_ENTRY_POINTS ep; + rdpShadowSubsystem* subsystem = NULL; + + shadow_subsystem_load_entry_points(&ep, name); + + if (!ep.New) + return NULL; + + subsystem = ep.New(); + + if (!subsystem) + return NULL; + + CopyMemory(&(subsystem->ep), &ep, sizeof(RDP_SHADOW_ENTRY_POINTS)); + + return subsystem; +} + +void shadow_subsystem_free(rdpShadowSubsystem* subsystem) +{ + if (subsystem->ep.Free) + subsystem->ep.Free(subsystem); +} + +int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server) +{ + int status; + + subsystem->server = server; + subsystem->selectedMonitor = server->selectedMonitor; + + subsystem->MsgPipe = MessagePipe_New(); + subsystem->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + region16_init(&(subsystem->invalidRegion)); + + if (!subsystem->ep.Init) + return -1; + + status = subsystem->ep.Init(subsystem); + + return status; +} + +void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem) +{ + if (subsystem->ep.Uninit) + subsystem->ep.Uninit(subsystem); + + if (subsystem->MsgPipe) + { + MessagePipe_Free(subsystem->MsgPipe); + subsystem->MsgPipe = NULL; + } + + if (subsystem->updateEvent) + { + CloseHandle(subsystem->updateEvent); + subsystem->updateEvent = NULL; + } + + if (subsystem->invalidRegion.data) + region16_uninit(&(subsystem->invalidRegion)); +} + +int shadow_subsystem_start(rdpShadowSubsystem* subsystem) +{ + int status; + + if (!subsystem->ep.Start) + return -1; + + status = subsystem->ep.Start(subsystem); + + return status; +} + +int shadow_subsystem_stop(rdpShadowSubsystem* subsystem) +{ + int status; + + if (!subsystem->ep.Stop) + return -1; + + status = subsystem->ep.Stop(subsystem); + + return status; +} + +int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, const char* name) +{ + int numMonitors = 0; + RDP_SHADOW_ENTRY_POINTS ep; + + if (shadow_subsystem_load_entry_points(&ep, name) < 0) + return -1; + + numMonitors = ep.EnumMonitors(monitors, maxMonitors); + + return numMonitors; +} diff --git a/server/shadow/shadow_subsystem.h b/server/shadow/shadow_subsystem.h new file mode 100644 index 000000000..2ddbce864 --- /dev/null +++ b/server/shadow/shadow_subsystem.h @@ -0,0 +1,62 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_SUBSYSTEM_H +#define FREERDP_SHADOW_SERVER_SUBSYSTEM_H + +#include + +#include +#include + +#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001 +#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002 + +struct _SHADOW_MSG_IN_REFRESH_OUTPUT +{ + UINT32 numRects; + RECTANGLE_16* rects; +}; +typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT; + +struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT +{ + BOOL allow; + RECTANGLE_16 rect; +}; +typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT; + +#ifdef __cplusplus +extern "C" { +#endif + +rdpShadowSubsystem* shadow_subsystem_new(const char* name); +void shadow_subsystem_free(rdpShadowSubsystem* subsystem); + +int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server); +void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem); + +int shadow_subsystem_start(rdpShadowSubsystem* subsystem); +int shadow_subsystem_stop(rdpShadowSubsystem* subsystem); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_SUBSYSTEM_H */ + diff --git a/server/shadow/shadow_surface.c b/server/shadow/shadow_surface.c new file mode 100644 index 000000000..9c581422b --- /dev/null +++ b/server/shadow/shadow_surface.c @@ -0,0 +1,71 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 "shadow.h" + +#include "shadow_surface.h" + +rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int x, int y, int width, int height) +{ + rdpShadowSurface* surface; + + surface = (rdpShadowSurface*) calloc(1, sizeof(rdpShadowSurface)); + + if (!surface) + return NULL; + + surface->server = server; + + surface->x = x; + surface->y = y; + surface->width = width; + surface->height = height; + surface->scanline = (surface->width + (surface->width % 4)) * 4; + + surface->data = (BYTE*) malloc(surface->scanline * surface->height); + + if (!surface->data) + return NULL; + + ZeroMemory(surface->data, surface->scanline * surface->height); + + if (!InitializeCriticalSectionAndSpinCount(&(surface->lock), 4000)) + return NULL; + + region16_init(&(surface->invalidRegion)); + + return surface; +} + +void shadow_surface_free(rdpShadowSurface* surface) +{ + if (!surface) + return; + + free(surface->data); + + DeleteCriticalSection(&(surface->lock)); + + region16_uninit(&(surface->invalidRegion)); + + free(surface); +} diff --git a/server/shadow/shadow_surface.h b/server/shadow/shadow_surface.h new file mode 100644 index 000000000..2f6bc8300 --- /dev/null +++ b/server/shadow/shadow_surface.h @@ -0,0 +1,53 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * 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 FREERDP_SHADOW_SERVER_SURFACE_H +#define FREERDP_SHADOW_SERVER_SURFACE_H + +#include + +#include +#include + +struct rdp_shadow_surface +{ + rdpShadowServer* server; + + int x; + int y; + int width; + int height; + int scanline; + BYTE* data; + + CRITICAL_SECTION lock; + REGION16 invalidRegion; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int x, int y, int width, int height); +void shadow_surface_free(rdpShadowSurface* surface); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_SURFACE_H */ diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index d53744418..99a6d413c 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -38,7 +38,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/) # Check for cmake compatibility (enable/disable features) include(CheckCmakeCompat) include(FindFeature) -include(ComplexLibrary) include(AutoVersioning) include(ConfigOptions) include(CheckCCompilerFlag) @@ -51,6 +50,7 @@ set(WINPR_VERSION_MINOR "1") set(WINPR_VERSION_REVISION "0") set(WINPR_VERSION "${WINPR_VERSION_MAJOR}.${WINPR_VERSION_MINOR}") set(WINPR_VERSION_FULL "${WINPR_VERSION}.${WINPR_VERSION_REVISION}") +set(WINPR_VERSION_FULL ${WINPR_VERSION_FULL} PARENT_SCOPE) # Default to release build type if(NOT CMAKE_BUILD_TYPE) @@ -84,7 +84,8 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") set(WINPR_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/WinPR") set(WINPR_INCLUDE_DIR "include") - set(WINPR_MONOLITHIC_BUILD ${MONOLITHIC_BUILD}) + # Keep this for legacy builds + set(WINPR_MONOLITHIC_BUILD OFF) configure_package_config_file(WinPRConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/WinPRConfig.cmake INSTALL_DESTINATION ${WINPR_CMAKE_INSTALL_DIR} diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h index b77a1dc97..21d3a90db 100644 --- a/winpr/include/winpr/bitstream.h +++ b/winpr/include/winpr/bitstream.h @@ -24,14 +24,15 @@ #include #include +#include struct _wBitStream { - BYTE* buffer; + const BYTE* buffer; BYTE* pointer; - DWORD position; - DWORD length; - DWORD capacity; + int position; + int length; + int capacity; UINT32 mask; UINT32 offset; UINT32 prefetch; @@ -47,90 +48,103 @@ extern "C" { #endif #define BitStream_Prefetch(_bs) do { \ - (_bs->prefetch) = 0; \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 4)) \ - (_bs->prefetch) |= (*(_bs->pointer + 4) << 24); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 5)) \ - (_bs->prefetch) |= (*(_bs->pointer + 5) << 16); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 6)) \ - (_bs->prefetch) |= (*(_bs->pointer + 6) << 8); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 7)) \ - (_bs->prefetch) |= (*(_bs->pointer + 7) << 0); \ -} while(0) + (_bs->prefetch) = 0; \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 4)) \ + (_bs->prefetch) |= (*(_bs->pointer + 4) << 24); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 5)) \ + (_bs->prefetch) |= (*(_bs->pointer + 5) << 16); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 6)) \ + (_bs->prefetch) |= (*(_bs->pointer + 6) << 8); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 7)) \ + (_bs->prefetch) |= (*(_bs->pointer + 7) << 0); \ + } while(0) #define BitStream_Fetch(_bs) do { \ - (_bs->accumulator) = 0; \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 0)) \ - (_bs->accumulator) |= (*(_bs->pointer + 0) << 24); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 1)) \ - (_bs->accumulator) |= (*(_bs->pointer + 1) << 16); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 2)) \ - (_bs->accumulator) |= (*(_bs->pointer + 2) << 8); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) <(_bs->capacity + 3)) \ - (_bs->accumulator) |= (*(_bs->pointer + 3) << 0); \ - BitStream_Prefetch(_bs); \ -} while(0) + (_bs->accumulator) = 0; \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 0)) \ + (_bs->accumulator) |= (*(_bs->pointer + 0) << 24); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 1)) \ + (_bs->accumulator) |= (*(_bs->pointer + 1) << 16); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 2)) \ + (_bs->accumulator) |= (*(_bs->pointer + 2) << 8); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) <(_bs->capacity + 3)) \ + (_bs->accumulator) |= (*(_bs->pointer + 3) << 0); \ + BitStream_Prefetch(_bs); \ + } while(0) #define BitStream_Flush(_bs) do { \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 0)) \ - *(_bs->pointer + 0) = (_bs->accumulator >> 24); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 1)) \ - *(_bs->pointer + 1) = (_bs->accumulator >> 16); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 2)) \ - *(_bs->pointer + 2) = (_bs->accumulator >> 8); \ - if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 3)) \ - *(_bs->pointer + 3) = (_bs->accumulator >> 0); \ -} while(0) + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 0)) \ + *(_bs->pointer + 0) = (_bs->accumulator >> 24); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 1)) \ + *(_bs->pointer + 1) = (_bs->accumulator >> 16); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 2)) \ + *(_bs->pointer + 2) = (_bs->accumulator >> 8); \ + if (((UINT32) (_bs->pointer - _bs->buffer)) < (_bs->capacity + 3)) \ + *(_bs->pointer + 3) = (_bs->accumulator >> 0); \ + } while(0) #define BitStream_Shift(_bs, _nbits) do { \ - _bs->accumulator <<= _nbits; \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset < 32) { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - } else { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - _bs->offset -= 32; \ - _bs->pointer += 4; \ - BitStream_Prefetch(_bs); \ - if (_bs->offset) { \ - _bs->mask = ((1 << _bs->offset) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ - _bs->prefetch <<= _bs->offset; \ + if (_nbits == 0) { \ + } else if ((_nbits > 0) && (_nbits < 32)) { \ + _bs->accumulator <<= _nbits; \ + _bs->position += _nbits; \ + _bs->offset += _nbits; \ + if (_bs->offset < 32) { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + } else { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + _bs->offset -= 32; \ + _bs->pointer += 4; \ + BitStream_Prefetch(_bs); \ + if (_bs->offset) { \ + _bs->mask = ((1 << _bs->offset) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ + _bs->prefetch <<= _bs->offset; \ + } \ + } \ + } else { \ + WLog_WARN("com.winpr.bitstream", "warning: BitStream_Shift(%d)", _nbits); \ } \ - } \ -} while(0) + } while(0) + +#define BitStream_Shift32(_bs) do { \ + BitStream_Shift(_bs, 16); \ + BitStream_Shift(_bs, 16); \ + } while(0) #define BitStream_Write_Bits(_bs, _bits, _nbits) do { \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset < 32) { \ - _bs->accumulator |= (_bits << (32 - _bs->offset)); \ - } else { \ - _bs->offset -= 32; \ - _bs->mask = ((1 << (_nbits - _bs->offset)) - 1); \ - _bs->accumulator |= ((_bits >> _bs->offset) & _bs->mask); \ - BitStream_Flush(bs); \ - _bs->accumulator = 0; \ - _bs->pointer += 4; \ - if (_bs->offset) { \ - _bs->mask = ((1 << _bs->offset) - 1); \ - _bs->accumulator |= ((_bits & _bs->mask) << (32 - _bs->offset)); \ + _bs->position += _nbits; \ + _bs->offset += _nbits; \ + if (_bs->offset < 32) { \ + _bs->accumulator |= (_bits << (32 - _bs->offset)); \ + } else { \ + _bs->offset -= 32; \ + _bs->mask = ((1 << (_nbits - _bs->offset)) - 1); \ + _bs->accumulator |= ((_bits >> _bs->offset) & _bs->mask); \ + BitStream_Flush(bs); \ + _bs->accumulator = 0; \ + _bs->pointer += 4; \ + if (_bs->offset) { \ + _bs->mask = ((1 << _bs->offset) - 1); \ + _bs->accumulator |= ((_bits & _bs->mask) << (32 - _bs->offset)); \ + } \ } \ - } \ -} while(0) + } while(0) -WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); -WINPR_API UINT32 ReverseBits32(UINT32 bits, UINT32 nbits); +#define BitStream_GetRemainingLength(_bs) \ + (_bs->length - _bs->position) -WINPR_API void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity); + WINPR_API void BitDump(const char* tag, int level, const BYTE* buffer, UINT32 length, UINT32 flags); + WINPR_API UINT32 ReverseBits32(UINT32 bits, UINT32 nbits); -WINPR_API wBitStream* BitStream_New(); -WINPR_API void BitStream_Free(wBitStream* bs); + WINPR_API void BitStream_Attach(wBitStream* bs, const BYTE* buffer, UINT32 capacity); + + WINPR_API wBitStream* BitStream_New(); + WINPR_API void BitStream_Free(wBitStream* bs); #ifdef __cplusplus } diff --git a/winpr/include/winpr/clipboard.h b/winpr/include/winpr/clipboard.h new file mode 100644 index 000000000..8ff60e692 --- /dev/null +++ b/winpr/include/winpr/clipboard.h @@ -0,0 +1,64 @@ +/** + * 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 void* (*CLIPBOARD_SYNTHESIZE_FN)(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize); + +#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 ClipboardCountRegisteredFormats(wClipboard* clipboard); +WINPR_API UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** ppFormatIds); +WINPR_API UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name); + +WINPR_API BOOL ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, + UINT32 syntheticId, CLIPBOARD_SYNTHESIZE_FN pfnSynthesize); + +WINPR_API UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name); +WINPR_API const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId); +WINPR_API 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/include/winpr/collections.h b/winpr/include/winpr/collections.h index f56a556d8..884723e01 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -138,6 +138,7 @@ typedef struct _wArrayList wArrayList; WINPR_API int ArrayList_Capacity(wArrayList* arrayList); WINPR_API int ArrayList_Count(wArrayList* arrayList); +WINPR_API int ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems); WINPR_API BOOL ArrayList_IsFixedSized(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsReadOnly(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsSynchronized(wArrayList* arrayList); @@ -247,10 +248,10 @@ WINPR_API void* LinkedList_Last(wLinkedList* list); WINPR_API BOOL LinkedList_Contains(wLinkedList* list, void* value); WINPR_API void LinkedList_Clear(wLinkedList* list); -WINPR_API void LinkedList_AddFirst(wLinkedList* list, void* value); -WINPR_API void LinkedList_AddLast(wLinkedList* list, void* value); +WINPR_API BOOL LinkedList_AddFirst(wLinkedList* list, void* value); +WINPR_API BOOL LinkedList_AddLast(wLinkedList* list, void* value); -WINPR_API void LinkedList_Remove(wLinkedList* list, void* value); +WINPR_API BOOL LinkedList_Remove(wLinkedList* list, void* value); WINPR_API void LinkedList_RemoveFirst(wLinkedList* list); WINPR_API void LinkedList_RemoveLast(wLinkedList* list); @@ -326,27 +327,33 @@ WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown); /* Hash Table */ -typedef void (*KEY_VALUE_FREE_FN)(void* context, void* key, void* value); +typedef UINT32 (*HASH_TABLE_HASH_FN)(void* key); +typedef BOOL (*HASH_TABLE_KEY_COMPARE_FN)(void* key1, void* key2); +typedef BOOL (*HASH_TABLE_VALUE_COMPARE_FN)(void* value1, void* value2); +typedef void* (*HASH_TABLE_KEY_CLONE_FN)(void* key); +typedef void* (*HASH_TABLE_VALUE_CLONE_FN)(void* value); +typedef void (*HASH_TABLE_KEY_FREE_FN)(void* key); +typedef void (*HASH_TABLE_VALUE_FREE_FN)(void* value); struct _wHashTable { BOOL synchronized; CRITICAL_SECTION lock; - long numOfBuckets; - long numOfElements; + int numOfBuckets; + int numOfElements; float idealRatio; float lowerRehashThreshold; float upperRehashThreshold; wKeyValuePair** bucketArray; - int (*keycmp)(void* key1, void* key2); - int (*valuecmp)(void* value1, void* value2); - unsigned long (*hashFunction)(void* key); - void (*keyDeallocator)(void* key); - void (*valueDeallocator)(void* value); - void* context; - KEY_VALUE_FREE_FN pfnKeyValueFree; + HASH_TABLE_HASH_FN hash; + HASH_TABLE_KEY_COMPARE_FN keyCompare; + HASH_TABLE_VALUE_COMPARE_FN valueCompare; + HASH_TABLE_KEY_CLONE_FN keyClone; + HASH_TABLE_VALUE_CLONE_FN valueClone; + HASH_TABLE_KEY_FREE_FN keyFree; + HASH_TABLE_VALUE_FREE_FN valueFree; }; typedef struct _wHashTable wHashTable; @@ -359,9 +366,16 @@ WINPR_API BOOL HashTable_ContainsKey(wHashTable* table, void* key); WINPR_API BOOL HashTable_ContainsValue(wHashTable* table, void* value); WINPR_API void* HashTable_GetItemValue(wHashTable* table, void* key); WINPR_API BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value); -WINPR_API void HashTable_SetFreeFunction(wHashTable* table, void* context, KEY_VALUE_FREE_FN pfnKeyValueFree); WINPR_API int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys); +WINPR_API UINT32 HashTable_PointerHash(void* pointer); +WINPR_API BOOL HashTable_PointerCompare(void* pointer1, void* pointer2); + +WINPR_API UINT32 HashTable_StringHash(void* key); +WINPR_API BOOL HashTable_StringCompare(void* string1, void* string2); +WINPR_API void* HashTable_StringClone(void* str); +WINPR_API void HashTable_StringFree(void* str); + WINPR_API wHashTable* HashTable_New(BOOL synchronized); WINPR_API void HashTable_Free(wHashTable* table); diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h new file mode 100644 index 000000000..6f0a23077 --- /dev/null +++ b/winpr/include/winpr/comm.h @@ -0,0 +1,566 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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_COMM_H +#define WINPR_COMM_H + +#include +#include +#include +#include + + +#if defined __linux__ && !defined ANDROID + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 + +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#ifndef IGNORE +#define IGNORE 0 +#endif + +#define CBR_110 110 +#define CBR_300 300 +#define CBR_600 600 +#define CBR_1200 1200 +#define CBR_2400 2400 +#define CBR_4800 4800 +#define CBR_9600 9600 +#define CBR_14400 14400 +#define CBR_19200 19200 +#define CBR_38400 38400 +#define CBR_56000 56000 +#define CBR_57600 57600 +#define CBR_115200 115200 +#define CBR_128000 128000 +#define CBR_256000 256000 + +#define CE_RXOVER 0x0001 +#define CE_OVERRUN 0x0002 +#define CE_RXPARITY 0x0004 +#define CE_FRAME 0x0008 +#define CE_BREAK 0x0010 +#define CE_TXFULL 0x0100 +#define CE_PTO 0x0200 +#define CE_IOE 0x0400 +#define CE_DNS 0x0800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID (-1) +#define IE_OPEN (-2) +#define IE_NOPEN (-3) +#define IE_MEMORY (-4) +#define IE_DEFAULT (-5) +#define IE_HARDWARE (-10) +#define IE_BYTESIZE (-11) +#define IE_BAUDRATE (-12) + +#define EV_RXCHAR 0x0001 +#define EV_RXFLAG 0x0002 +#define EV_TXEMPTY 0x0004 +#define EV_CTS 0x0008 +#define EV_DSR 0x0010 +#define EV_RLSD 0x0020 +#define EV_BREAK 0x0040 +#define EV_ERR 0x0080 +#define EV_RING 0x0100 +#define EV_PERR 0x0200 +#define EV_RX80FULL 0x0400 +#define EV_EVENT1 0x0800 +#define EV_EVENT2 0x1000 + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define PURGE_TXABORT 0x0001 +#define PURGE_RXABORT 0x0002 +#define PURGE_TXCLEAR 0x0004 +#define PURGE_RXCLEAR 0x0008 + +#define LPTx 0x80 + +#define MS_CTS_ON ((DWORD)0x0010) +#define MS_DSR_ON ((DWORD)0x0020) +#define MS_RING_ON ((DWORD)0x0040) +#define MS_RLSD_ON ((DWORD)0x0080) + +#define SP_SERIALCOMM ((DWORD)0x00000001) + +#define PST_UNSPECIFIED ((DWORD)0x00000000) +#define PST_RS232 ((DWORD)0x00000001) +#define PST_PARALLELPORT ((DWORD)0x00000002) +#define PST_RS422 ((DWORD)0x00000003) +#define PST_RS423 ((DWORD)0x00000004) +#define PST_RS449 ((DWORD)0x00000005) +#define PST_MODEM ((DWORD)0x00000006) +#define PST_FAX ((DWORD)0x00000021) +#define PST_SCANNER ((DWORD)0x00000022) +#define PST_NETWORK_BRIDGE ((DWORD)0x00000100) +#define PST_LAT ((DWORD)0x00000101) +#define PST_TCPIP_TELNET ((DWORD)0x00000102) +#define PST_X25 ((DWORD)0x00000103) + +#define PCF_DTRDSR ((DWORD)0x0001) +#define PCF_RTSCTS ((DWORD)0x0002) +#define PCF_RLSD ((DWORD)0x0004) +#define PCF_PARITY_CHECK ((DWORD)0x0008) +#define PCF_XONXOFF ((DWORD)0x0010) +#define PCF_SETXCHAR ((DWORD)0x0020) +#define PCF_TOTALTIMEOUTS ((DWORD)0x0040) +#define PCF_INTTIMEOUTS ((DWORD)0x0080) +#define PCF_SPECIALCHARS ((DWORD)0x0100) +#define PCF_16BITMODE ((DWORD)0x0200) + +#define SP_PARITY ((DWORD)0x0001) +#define SP_BAUD ((DWORD)0x0002) +#define SP_DATABITS ((DWORD)0x0004) +#define SP_STOPBITS ((DWORD)0x0008) +#define SP_HANDSHAKING ((DWORD)0x0010) +#define SP_PARITY_CHECK ((DWORD)0x0020) +#define SP_RLSD ((DWORD)0x0040) + +#define BAUD_075 ((DWORD)0x00000001) +#define BAUD_110 ((DWORD)0x00000002) +#define BAUD_134_5 ((DWORD)0x00000004) +#define BAUD_150 ((DWORD)0x00000008) +#define BAUD_300 ((DWORD)0x00000010) +#define BAUD_600 ((DWORD)0x00000020) +#define BAUD_1200 ((DWORD)0x00000040) +#define BAUD_1800 ((DWORD)0x00000080) +#define BAUD_2400 ((DWORD)0x00000100) +#define BAUD_4800 ((DWORD)0x00000200) +#define BAUD_7200 ((DWORD)0x00000400) +#define BAUD_9600 ((DWORD)0x00000800) +#define BAUD_14400 ((DWORD)0x00001000) +#define BAUD_19200 ((DWORD)0x00002000) +#define BAUD_38400 ((DWORD)0x00004000) +#define BAUD_56K ((DWORD)0x00008000) +#define BAUD_128K ((DWORD)0x00010000) +#define BAUD_115200 ((DWORD)0x00020000) +#define BAUD_57600 ((DWORD)0x00040000) +#define BAUD_USER ((DWORD)0x10000000) + +#define DATABITS_5 ((WORD)0x0001) +#define DATABITS_6 ((WORD)0x0002) +#define DATABITS_7 ((WORD)0x0004) +#define DATABITS_8 ((WORD)0x0008) +#define DATABITS_16 ((WORD)0x0010) +#define DATABITS_16X ((WORD)0x0020) + +#define STOPBITS_10 ((WORD)0x0001) +#define STOPBITS_15 ((WORD)0x0002) +#define STOPBITS_20 ((WORD)0x0004) + +#define PARITY_NONE ((WORD)0x0100) +#define PARITY_ODD ((WORD)0x0200) +#define PARITY_EVEN ((WORD)0x0400) +#define PARITY_MARK ((WORD)0x0800) +#define PARITY_SPACE ((WORD)0x1000) + +#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) + +#define DTR_CONTROL_DISABLE 0x00 +#define DTR_CONTROL_ENABLE 0x01 +#define DTR_CONTROL_HANDSHAKE 0x02 + +#define RTS_CONTROL_DISABLE 0x00 +#define RTS_CONTROL_ENABLE 0x01 +#define RTS_CONTROL_HANDSHAKE 0x02 +#define RTS_CONTROL_TOGGLE 0x03 + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx +typedef struct _DCB +{ + DWORD DCBlength; + DWORD BaudRate; + DWORD fBinary:1; + DWORD fParity:1; + DWORD fOutxCtsFlow:1; + DWORD fOutxDsrFlow:1; + DWORD fDtrControl:2; + DWORD fDsrSensitivity:1; + DWORD fTXContinueOnXoff:1; + DWORD fOutX:1; + DWORD fInX:1; + DWORD fErrorChar:1; + DWORD fNull:1; + DWORD fRtsControl:2; + DWORD fAbortOnError:1; + DWORD fDummy2:17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; + WORD wReserved1; +} DCB, *LPDCB; + +typedef struct _COMM_CONFIG +{ + DWORD dwSize; + WORD wVersion; + WORD wReserved; + DCB dcb; + DWORD dwProviderSubType; + DWORD dwProviderOffset; + DWORD dwProviderSize; + WCHAR wcProviderData[1]; +} COMMCONFIG, *LPCOMMCONFIG; + +typedef struct _COMMPROP +{ + WORD wPacketLength; + WORD wPacketVersion; + DWORD dwServiceMask; + DWORD dwReserved1; + DWORD dwMaxTxQueue; + DWORD dwMaxRxQueue; + DWORD dwMaxBaud; + DWORD dwProvSubType; + DWORD dwProvCapabilities; + DWORD dwSettableParams; + DWORD dwSettableBaud; + WORD wSettableData; + WORD wSettableStopParity; + DWORD dwCurrentTxQueue; + DWORD dwCurrentRxQueue; + DWORD dwProvSpec1; + DWORD dwProvSpec2; + WCHAR wcProvChar[1]; +} COMMPROP, *LPCOMMPROP; + +typedef struct _COMMTIMEOUTS +{ + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; +} COMMTIMEOUTS, *LPCOMMTIMEOUTS; + +typedef struct _COMSTAT +{ + DWORD fCtsHold:1; + DWORD fDsrHold:1; + DWORD fRlsdHold:1; + DWORD fXoffHold:1; + DWORD fXoffSent:1; + DWORD fEof:1; + DWORD fTxim:1; + DWORD fReserved:25; + DWORD cbInQue; + DWORD cbOutQue; +} COMSTAT, *LPCOMSTAT; + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB); +WINPR_API BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB); + +WINPR_API BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts); +WINPR_API BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts); + +WINPR_API BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC); +WINPR_API BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC); + +WINPR_API BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); +WINPR_API BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize); + +WINPR_API BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask); +WINPR_API BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask); + +WINPR_API BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat); +WINPR_API BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp); + +WINPR_API BOOL GetCommState(HANDLE hFile, LPDCB lpDCB); +WINPR_API BOOL SetCommState(HANDLE hFile, LPDCB lpDCB); + +WINPR_API BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); +WINPR_API BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts); + +WINPR_API BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); +WINPR_API BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize); + +WINPR_API BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize); +WINPR_API BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize); + +WINPR_API BOOL SetCommBreak(HANDLE hFile); +WINPR_API BOOL ClearCommBreak(HANDLE hFile); +WINPR_API BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat); + +WINPR_API BOOL PurgeComm(HANDLE hFile, DWORD dwFlags); +WINPR_API BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue); + +WINPR_API BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc); + +WINPR_API BOOL TransmitCommChar(HANDLE hFile, char cChar); + +WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped); + +#ifdef UNICODE +#define BuildCommDCB BuildCommDCBW +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW +#define CommConfigDialog CommConfigDialogW +#define GetDefaultCommConfig GetDefaultCommConfigW +#define SetDefaultCommConfig SetDefaultCommConfigW +#else +#define BuildCommDCB BuildCommDCBA +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA +#define CommConfigDialog CommConfigDialogA +#define GetDefaultCommConfig GetDefaultCommConfigA +#define SetDefaultCommConfig SetDefaultCommConfigA +#endif + +/* Extended API */ + +/* FIXME: MAXULONG should be defined arround winpr/limits.h */ +#ifndef MAXULONG +#define MAXULONG (4294967295UL) +#endif + + +/** + * IOCTLs table according the server's serial driver: + * http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx + */ +typedef enum _SERIAL_DRIVER_ID +{ + SerialDriverUnknown = 0, + SerialDriverSerialSys, + SerialDriverSerCxSys, + SerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */ +} SERIAL_DRIVER_ID; + + +/* + * About DefineCommDevice() / QueryDosDevice() + * + * Did something close to QueryDosDevice() and DefineDosDevice() but with + * folowing constraints: + * - mappings are stored in a static array. + * - QueryCommDevice returns only the mappings that have been defined through DefineCommDevice() + */ +WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath); +WINPR_API DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax); +WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName); + +/** + * A handle can only be created on defined devices with DefineCommDevice(). This + * also ensures that CommCreateFileA() has been registered through + * RegisterHandleCreator(). + */ +WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + + + +#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004 +#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050 +#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C +#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054 +#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C +#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020 +/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */ +#define IOCTL_SERIAL_GET_CHARS 0x001B0058 +#define IOCTL_SERIAL_SET_CHARS 0x001B005C + +#define IOCTL_SERIAL_SET_DTR 0x001B0024 +#define IOCTL_SERIAL_CLR_DTR 0x001B0028 +#define IOCTL_SERIAL_RESET_DEVICE 0x001B002C +#define IOCTL_SERIAL_SET_RTS 0x001B0030 +#define IOCTL_SERIAL_CLR_RTS 0x001B0034 +#define IOCTL_SERIAL_SET_XOFF 0x001B0038 +#define IOCTL_SERIAL_SET_XON 0x001B003C +#define IOCTL_SERIAL_SET_BREAK_ON 0x001B0010 +#define IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014 +#define IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008 +#define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 +#define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 +#define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 +#define IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 +#define IOCTL_SERIAL_PURGE 0x001B004C +#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 +#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 +#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 +#define IOCTL_SERIAL_GET_DTRRTS 0x001B0078 + +/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */ +#define IOCTL_SERIAL_GET_COMMSTATUS 0x001B006C + +#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074 +/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */ +/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */ +#define IOCTL_SERIAL_CONFIG_SIZE 0x001B0080 +/* IOCTL_SERIAL_GET_STATS 0x001B008C */ +/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */ +/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */ +/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */ +/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */ + +/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */ +/* IOCTL_PAR_SET_INFORMATION 0x00160008 */ +/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */ +/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */ +/* IOCTL_IEEE1284_GET_MODE 0x00160014 */ +/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */ +/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */ +/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */ +/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */ +/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */ +/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */ +/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */ + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */ +#define IOCTL_USBPRINT_GET_1284_ID 0x220034 + + +typedef struct __SERIAL_IOCTL_NAME +{ + ULONG number; + const char* name; +} _SERIAL_IOCTL_NAME; + +static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = +{ + {IOCTL_SERIAL_SET_BAUD_RATE, "IOCTL_SERIAL_SET_BAUD_RATE"}, + {IOCTL_SERIAL_GET_BAUD_RATE, "IOCTL_SERIAL_GET_BAUD_RATE"}, + {IOCTL_SERIAL_SET_LINE_CONTROL, "IOCTL_SERIAL_SET_LINE_CONTROL"}, + {IOCTL_SERIAL_GET_LINE_CONTROL, "IOCTL_SERIAL_GET_LINE_CONTROL"}, + {IOCTL_SERIAL_SET_TIMEOUTS, "IOCTL_SERIAL_SET_TIMEOUTS"}, + {IOCTL_SERIAL_GET_TIMEOUTS, "IOCTL_SERIAL_GET_TIMEOUTS"}, + {IOCTL_SERIAL_GET_CHARS, "IOCTL_SERIAL_GET_CHARS"}, + {IOCTL_SERIAL_SET_CHARS, "IOCTL_SERIAL_SET_CHARS"}, + {IOCTL_SERIAL_SET_DTR, "IOCTL_SERIAL_SET_DTR"}, + {IOCTL_SERIAL_CLR_DTR, "IOCTL_SERIAL_CLR_DTR"}, + {IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"}, + {IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"}, + {IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"}, + {IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"}, + {IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"}, + {IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"}, + {IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"}, + {IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"}, + {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, + {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, + {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, + {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, + {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, + {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, + {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, + {IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"}, + {IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"}, + {IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"}, + {IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"}, + // {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"}, + // {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"}, + {IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"}, + // {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"}, + // {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"}, + // {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"}, + // {IOCTL_SERIAL_SET_MODEM_CONTROL,"IOCTL_SERIAL_SET_MODEM_CONTROL"}, + // {IOCTL_SERIAL_SET_FIFO_CONTROL, "IOCTL_SERIAL_SET_FIFO_CONTROL"}, + + // {IOCTL_PAR_QUERY_INFORMATION, "IOCTL_PAR_QUERY_INFORMATION"}, + // {IOCTL_PAR_SET_INFORMATION, "IOCTL_PAR_SET_INFORMATION"}, + // {IOCTL_PAR_QUERY_DEVICE_ID, "IOCTL_PAR_QUERY_DEVICE_ID"}, + // {IOCTL_PAR_QUERY_DEVICE_ID_SIZE,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE"}, + // {IOCTL_IEEE1284_GET_MODE, "IOCTL_IEEE1284_GET_MODE"}, + // {IOCTL_IEEE1284_NEGOTIATE, "IOCTL_IEEE1284_NEGOTIATE"}, + // {IOCTL_PAR_SET_WRITE_ADDRESS, "IOCTL_PAR_SET_WRITE_ADDRESS"}, + // {IOCTL_PAR_SET_READ_ADDRESS, "IOCTL_PAR_SET_READ_ADDRESS"}, + // {IOCTL_PAR_GET_DEVICE_CAPS, "IOCTL_PAR_GET_DEVICE_CAPS"}, + // {IOCTL_PAR_GET_DEFAULT_MODES, "IOCTL_PAR_GET_DEFAULT_MODES"}, + // {IOCTL_PAR_QUERY_RAW_DEVICE_ID, "IOCTL_PAR_QUERY_RAW_DEVICE_ID"}, + // {IOCTL_PAR_IS_PORT_FREE, "IOCTL_PAR_IS_PORT_FREE"}, + + {IOCTL_USBPRINT_GET_1284_ID, "IOCTL_USBPRINT_GET_1284_ID"}, + + {0, NULL} +}; + +/** + * FIXME: got a proper function name and place + */ +const char* _comm_serial_ioctl_name(ULONG number); + +/** + * FIXME: got a proper function name and place + */ +void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); + +/** + * FIXME: got a proper function name and place + * + * permissive mode is disabled by default. + */ +BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); + + +/** + * FIXME: to be moved in comm_ioctl.h + */ +BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + +/** + * FIXME: to be moved in comm_io.h + */ +BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); + +/** + * FIXME: to be moved in comm_io.h + */ +BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); + +#ifdef __cplusplus +} +#endif + +#endif /* __linux__ */ + +#endif /* WINPR_COMM_H */ + diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h index 6da3f4b16..4172be83f 100644 --- a/winpr/include/winpr/crt.h +++ b/winpr/include/winpr/crt.h @@ -82,6 +82,47 @@ static INLINE UINT64 _rotr64(UINT64 value, int shift) { #endif +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + */ + +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) + +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + * + * Beware: the result of __builtin_clz(0) is undefined + */ + +static INLINE UINT32 __lzcnt(UINT32 _val32) { + return _val32 ? ((UINT32) __builtin_clz(_val32)) : 32; +} + +static INLINE UINT16 __lzcnt16(UINT16 _val16) { + return _val16 ? ((UINT16) (__builtin_clz((UINT32) _val16) - 16)) : 16; +} + +#else + +static INLINE UINT32 __lzcnt(UINT32 x) { + unsigned y; + int n = 32; + y = x >> 16; if (y != 0) { n = n - 16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + return n - x; +} + +static INLINE UINT16 __lzcnt16(UINT16 x) { + return ((UINT16) __lzcnt((UINT32) x)); +} + +#endif + #endif #ifndef _WIN32 diff --git a/winpr/include/winpr/debug.h b/winpr/include/winpr/debug.h new file mode 100644 index 000000000..1d1123a80 --- /dev/null +++ b/winpr/include/winpr/debug.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * 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_DEBUG_H +#define WINPR_DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void *winpr_backtrace(DWORD size); +void winpr_backtrace_free(void *buffer); +char **winpr_backtrace_symbols(void *buffer, size_t *used); +void winpr_backtrace_symbols_fd(void *buffer, int fd); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_WLOG_H */ + diff --git a/winpr/include/winpr/environment.h b/winpr/include/winpr/environment.h index 15ac44e3b..71bdc056c 100644 --- a/winpr/include/winpr/environment.h +++ b/winpr/include/winpr/environment.h @@ -73,16 +73,10 @@ WINPR_API DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSi WINPR_API BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock); WINPR_API BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock); -WINPR_API LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge); - -WINPR_API DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize); -WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR lpValue); - #ifdef __cplusplus } #endif - #ifdef UNICODE #define GetCurrentDirectory GetCurrentDirectoryW #define SetCurrentDirectory SetCurrentDirectoryW @@ -111,5 +105,18 @@ WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR #endif +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge); + +WINPR_API DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize); +WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue); + +#ifdef __cplusplus +} +#endif + #endif /* WINPR_ENVIRONMENT_H */ diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 59979b6ce..80f89507f 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -311,10 +311,23 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu #define CreateDirectory CreateDirectoryA #endif -#endif /* Extra Functions */ +typedef BOOL (*pcIsFileHandled)(LPCSTR lpFileName); +typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +typedef struct _HANDLE_CREATOR +{ + pcIsFileHandled IsHandled; + pcCreateFileA CreateFileA; +} HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; + +BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator); + +#endif /* _WIN32 */ + #define WILDCARD_STAR 0x00000001 #define WILDCARD_QM 0x00000002 #define WILDCARD_DOS 0x00000100 @@ -331,6 +344,7 @@ WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags); WINPR_API int UnixChangeFileMode(const char* filename, int flags); +WINPR_API BOOL IsNamedPipeFileNameA(LPCSTR lpName); WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(void); WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); @@ -342,4 +356,3 @@ WINPR_API int GetNamePipeFileDescriptor(HANDLE hNamedPipe); #endif #endif /* WINPR_FILE_H */ - diff --git a/winpr/include/winpr/handle.h b/winpr/include/winpr/handle.h index c418427e8..3a278e93a 100644 --- a/winpr/include/winpr/handle.h +++ b/winpr/include/winpr/handle.h @@ -33,6 +33,9 @@ extern "C" { #ifndef _WIN32 +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 + #define HANDLE_FLAG_INHERIT 0x00000001 #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 diff --git a/winpr/include/winpr/image.h b/winpr/include/winpr/image.h new file mode 100644 index 000000000..ecdba60cf --- /dev/null +++ b/winpr/include/winpr/image.h @@ -0,0 +1,99 @@ +/** + * WinPR: Windows Portable Runtime + * Image Utils + * + * 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_IMAGE_H +#define WINPR_IMAGE_H + +#include +#include + +#pragma pack(push, 1) + +struct _WINPR_BITMAP_FILE_HEADER +{ + BYTE bfType[2]; + UINT32 bfSize; + UINT16 bfReserved1; + UINT16 bfReserved2; + UINT32 bfOffBits; +}; +typedef struct _WINPR_BITMAP_FILE_HEADER WINPR_BITMAP_FILE_HEADER; + +struct _WINPR_BITMAP_INFO_HEADER +{ + UINT32 biSize; + INT32 biWidth; + INT32 biHeight; + UINT16 biPlanes; + UINT16 biBitCount; + UINT32 biCompression; + UINT32 biSizeImage; + INT32 biXPelsPerMeter; + INT32 biYPelsPerMeter; + UINT32 biClrUsed; + UINT32 biClrImportant; +}; +typedef struct _WINPR_BITMAP_INFO_HEADER WINPR_BITMAP_INFO_HEADER; + +struct _WINPR_BITMAP_CORE_HEADER +{ + UINT32 bcSize; + UINT16 bcWidth; + UINT16 bcHeight; + UINT16 bcPlanes; + UINT16 bcBitCount; +}; +typedef struct _WINPR_BITMAP_CORE_HEADER WINPR_BITMAP_CORE_HEADER; + +#pragma pack(pop) + +#define WINPR_IMAGE_BITMAP 0 +#define WINPR_IMAGE_PNG 1 + +struct _wImage +{ + int type; + int width; + int height; + BYTE* data; + int scanline; + int bitsPerPixel; + int bytesPerPixel; +}; +typedef struct _wImage wImage; + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, int bpp); + +WINPR_API int winpr_image_write(wImage* image, const char* filename); +WINPR_API int winpr_image_read(wImage* image, const char* filename); + +WINPR_API int winpr_image_read_buffer(wImage* image, BYTE* buffer, int size); + +WINPR_API wImage* winpr_image_new(); +WINPR_API void winpr_image_free(wImage* image, BOOL bFreeBuffer); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_IMAGE_H */ diff --git a/winpr/include/winpr/ini.h b/winpr/include/winpr/ini.h index 89b14ebbe..78ad38f4a 100644 --- a/winpr/include/winpr/ini.h +++ b/winpr/include/winpr/ini.h @@ -58,14 +58,20 @@ typedef struct _wIniFile wIniFile; extern "C" { #endif -WINPR_API int IniFile_Parse(wIniFile* ini, const char* filename); -WINPR_API int IniFile_ParseString(wIniFile* ini, const char* iniString); +WINPR_API int IniFile_ReadBuffer(wIniFile* ini, const char* buffer); +WINPR_API int IniFile_ReadFile(wIniFile* ini, const char* filename); + +WINPR_API char* IniFile_WriteBuffer(wIniFile* ini); +WINPR_API int IniFile_WriteFile(wIniFile* ini, const char* filename); WINPR_API char** IniFile_GetSectionNames(wIniFile* ini, int* count); WINPR_API char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count); -WINPR_API char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key); -WINPR_API UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key); +WINPR_API const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key); +WINPR_API int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key); + +WINPR_API int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key, const char* value); +WINPR_API int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value); WINPR_API wIniFile* IniFile_New(); WINPR_API void IniFile_Free(wIniFile* ini); diff --git a/winpr/include/winpr/interlocked.h b/winpr/include/winpr/interlocked.h index e96a2b62f..83c462568 100644 --- a/winpr/include/winpr/interlocked.h +++ b/winpr/include/winpr/interlocked.h @@ -154,10 +154,20 @@ WINPR_API LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value); WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand); +WINPR_API PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination, PVOID Exchange, PVOID Comperand); + #endif /* _WIN32 */ +#if (!defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0502))) +#define WINPR_INTERLOCKED_COMPARE_EXCHANGE64 1 +#endif + +#ifdef WINPR_INTERLOCKED_COMPARE_EXCHANGE64 + WINPR_API LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG Exchange, LONGLONG Comperand); +#endif + /* Doubly-Linked List */ WINPR_API VOID InitializeListHead(PLIST_ENTRY ListHead); diff --git a/winpr/include/winpr/pack.h b/winpr/include/winpr/pack.h new file mode 100644 index 000000000..198d26ae9 --- /dev/null +++ b/winpr/include/winpr/pack.h @@ -0,0 +1,101 @@ +/** + * WinPR: Windows Portable Runtime + * Pragma Pack + * + * 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. + */ + +/** + * This header is meant to be repeatedly included + * after defining the operation to be done: + * + * #define WINPR_PACK_PUSH + * #include // enables packing + * + * #define WINPR_PACK_POP + * #include // disables packing + * + * On each include, WINPR_PACK_* macros are undefined. + */ + +#if !defined(__APPLE__) + #ifndef WINPR_PRAGMA_PACK_EXT + #define WINPR_PRAGMA_PACK_EXT + #endif +#endif + +#ifdef PRAGMA_PACK_PUSH + #ifndef PRAGMA_PACK_PUSH1 + #define PRAGMA_PACK_PUSH1 + #endif +#undef PRAGMA_PACK_PUSH +#endif + +#ifdef PRAGMA_PACK_PUSH1 + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(push, 1) + #else + #pragma pack(1) + #endif +#undef PRAGMA_PACK_PUSH1 +#endif + +#ifdef PRAGMA_PACK_PUSH2 + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(push, 2) + #else + #pragma pack(2) + #endif +#undef PRAGMA_PACK_PUSH2 +#endif + +#ifdef PRAGMA_PACK_PUSH4 + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(push, 4) + #else + #pragma pack(4) + #endif +#undef PRAGMA_PACK_PUSH4 +#endif + +#ifdef PRAGMA_PACK_PUSH8 + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(push, 8) + #else + #pragma pack(8) + #endif +#undef PRAGMA_PACK_PUSH8 +#endif + +#ifdef PRAGMA_PACK_PUSH16 + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(push, 16) + #else + #pragma pack(16) + #endif +#undef PRAGMA_PACK_PUSH16 +#endif + +#ifdef PRAGMA_PACK_POP + #ifdef WINPR_PRAGMA_PACK_EXT + #pragma pack(pop) + #else + #pragma pack() + #endif +#undef PRAGMA_PACK_POP +#endif + +#undef WINPR_PRAGMA_PACK_EXT + diff --git a/winpr/include/winpr/path.h b/winpr/include/winpr/path.h index a69867d02..36333e9b6 100644 --- a/winpr/include/winpr/path.h +++ b/winpr/include/winpr/path.h @@ -281,10 +281,10 @@ extern "C" { WINPR_API char* GetKnownPath(int id); WINPR_API char* GetKnownSubPath(int id, const char* path); +WINPR_API char* GetEnvironmentPath(char* name); +WINPR_API char* GetEnvironmentSubPath(char* name, const char* path); WINPR_API char* GetCombinedPath(const char* basePath, const char* subPath); -//#ifndef _WIN32 - WINPR_API BOOL PathFileExistsA(LPCSTR pszPath); WINPR_API BOOL PathFileExistsW(LPCWSTR pszPath); @@ -298,6 +298,4 @@ WINPR_API BOOL PathFileExistsW(LPCWSTR pszPath); #define PathFileExists PathFileExistsA #endif -//#endif - #endif /* WINPR_PATH_H */ diff --git a/winpr/include/winpr/pool.h b/winpr/include/winpr/pool.h index 8ff2ff855..8dc335084 100644 --- a/winpr/include/winpr/pool.h +++ b/winpr/include/winpr/pool.h @@ -81,7 +81,6 @@ typedef struct _TP_CALLBACK_ENVIRON_V1 /* Non-Windows and pre Windows 7 */ #if ((!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601))) -//#if !defined(_WIN32_WINNT_VISTA) typedef struct _TP_CALLBACK_ENVIRON_V3 { @@ -121,7 +120,9 @@ typedef struct _TP_WAIT TP_WAIT, *PTP_WAIT; typedef struct _TP_IO TP_IO, *PTP_IO; +#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601)) typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON; +#endif #ifndef _WIN32 @@ -152,13 +153,18 @@ typedef VOID (*PTP_WIN32_IO_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Cont #endif +#if (!defined(_WIN32) || ((defined(_WIN32) && (_WIN32_WINNT < 0x0601)))) +#define WINPR_THREAD_POOL 1 +#endif + #ifdef __cplusplus extern "C" { #endif - /* Synch */ +#ifdef WINPR_THREAD_POOL + WINPR_API PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnwa, PVOID pv, PTP_CALLBACK_ENVIRON pcbe); WINPR_API VOID CloseThreadpoolWait(PTP_WAIT pwa); WINPR_API VOID SetThreadpoolWait(PTP_WAIT pwa, HANDLE h, PFILETIME pftTimeout); @@ -225,6 +231,8 @@ WINPR_API VOID LeaveCriticalSectionWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci WINPR_API VOID FreeLibraryWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HMODULE mod); WINPR_API VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci); +#endif + /* Dummy */ WINPR_API void winpr_pool_dummy(void); diff --git a/winpr/include/winpr/print.h b/winpr/include/winpr/print.h index c7ffecd5c..f93f65414 100644 --- a/winpr/include/winpr/print.h +++ b/winpr/include/winpr/print.h @@ -33,14 +33,14 @@ extern "C" { #endif -WINPR_API void winpr_HexDump(const BYTE* data, int length); -WINPR_API void winpr_CArrayDump(const BYTE* data, int length, int width); +WINPR_API void winpr_HexDump(const char* tag, int lvl, const BYTE* data, int length); +WINPR_API void winpr_CArrayDump(const char* tag, int lvl, const BYTE* data, int length, int width); WINPR_API char* winpr_BinToHexString(const BYTE* data, int length, BOOL space); -WINPR_API int wprintfx(const char *fmt, ...); -WINPR_API int wvprintfx(const char *fmt, va_list args); -WINPR_API int wvsnprintfx(char *buffer, size_t bufferSize, const char* fmt, va_list args); +WINPR_API int wprintfx(const char* fmt, ...); +WINPR_API int wvprintfx(const char* fmt, va_list args); +WINPR_API int wvsnprintfx(char* buffer, size_t bufferSize, const char* fmt, va_list args); #ifdef __cplusplus } diff --git a/winpr/include/winpr/smartcard.h b/winpr/include/winpr/smartcard.h index 1eb246229..fa6cbfcd8 100644 --- a/winpr/include/winpr/smartcard.h +++ b/winpr/include/winpr/smartcard.h @@ -227,11 +227,7 @@ #define SCARD_NEGOTIABLE 5 #define SCARD_SPECIFIC 6 -#if defined(__APPLE__) | defined(sun) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif typedef struct _SCARD_IO_REQUEST { @@ -557,11 +553,7 @@ typedef struct SCARDHANDLE hCardHandle; } OPENCARDNAMEW, *POPENCARDNAMEW, *LPOPENCARDNAMEW; -#if defined(__APPLE__) | defined(sun) -#pragma pack() -#else #pragma pack(pop) -#endif #ifdef UNICODE #define LPOCNCONNPROC LPOCNCONNPROCW diff --git a/winpr/include/winpr/spec.h b/winpr/include/winpr/spec.h index 9dbf394db..bd97220a2 100644 --- a/winpr/include/winpr/spec.h +++ b/winpr/include/winpr/spec.h @@ -73,24 +73,6 @@ #endif #endif -#if defined(_WIN32) || defined(__CYGWIN__) - #ifdef __GNUC__ - #define DECLSPEC_EXPORT __attribute__((dllexport)) - #define DECLSPEC_IMPORT __attribute__((dllimport)) - #else - #define DECLSPEC_EXPORT __declspec(dllexport) - #define DECLSPEC_IMPORT __declspec(dllimport) - #endif -#else - #if defined(__GNUC__) && __GNUC__ >= 4 - #define DECLSPEC_EXPORT __attribute__ ((visibility("default"))) - #define DECLSPEC_IMPORT - #else - #define DECLSPEC_EXPORT - #define DECLSPEC_IMPORT - #endif -#endif - #ifndef DECLSPEC_NORETURN #if (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__)) #define DECLSPEC_NORETURN __declspec(noreturn) @@ -971,5 +953,23 @@ char (*__countof_helper(_CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; #endif +#if defined(_WIN32) || defined(__CYGWIN__) + #ifdef __GNUC__ + #define DECLSPEC_EXPORT __attribute__((dllexport)) + #define DECLSPEC_IMPORT __attribute__((dllimport)) + #else + #define DECLSPEC_EXPORT __declspec(dllexport) + #define DECLSPEC_IMPORT __declspec(dllimport) + #endif +#else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DECLSPEC_EXPORT __attribute__ ((visibility("default"))) + #define DECLSPEC_IMPORT + #else + #define DECLSPEC_EXPORT + #define DECLSPEC_IMPORT + #endif +#endif + #endif /* WINPR_SPEC_H */ diff --git a/winpr/include/winpr/ssl.h b/winpr/include/winpr/ssl.h new file mode 100644 index 000000000..647c0e478 --- /dev/null +++ b/winpr/include/winpr/ssl.h @@ -0,0 +1,45 @@ +/** + * WinPR: Windows Portable Runtime + * OpenSSL Library Initialization + * + * Copyright 2014 Thincast Technologies GmbH + * Copyright 2014 Norbert Federa + * + * 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_SSL_H +#define WINPR_SSL_H + +#include + +#define WINPR_SSL_INIT_DEFAULT 0x00 +#define WINPR_SSL_INIT_ALREADY_INITIALIZED 0x01 +#define WINPR_SSL_INIT_ENABLE_LOCKING 0x2 + +#define WINPR_SSL_CLEANUP_GLOBAL 0x01 +#define WINPR_SSL_CLEANUP_THREAD 0x02 + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API BOOL winpr_InitializeSSL(DWORD flags); +WINPR_API BOOL winpr_CleanupSSL(DWORD flags); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_SSL_H */ + diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 6da3fcde6..a90df7724 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -181,6 +181,11 @@ WINPR_API int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteS WINPR_API int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); +WINPR_API void ByteSwapUnicode(WCHAR* wstr, int length); + +WINPR_API int ConvertLineEndingToLF(char* str, int size); +WINPR_API char* ConvertLineEndingToCRLF(const char* str, int* size); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index 00b979a69..88e37457e 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -3,6 +3,8 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Thincast Technologies GmbH + * Copyright 2014 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -102,22 +104,6 @@ WINPR_API BOOL ResetEvent(HANDLE hEvent); #define OpenEvent OpenEventA #endif -/* One-Time Initialization */ - -typedef union _RTL_RUN_ONCE -{ - PVOID Ptr; -} RTL_RUN_ONCE, *PRTL_RUN_ONCE; - -typedef PRTL_RUN_ONCE PINIT_ONCE; -typedef PRTL_RUN_ONCE LPINIT_ONCE; -typedef BOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context); - -WINPR_API BOOL InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID* lpContext); -WINPR_API BOOL InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext); -WINPR_API BOOL InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID* Context); -WINPR_API VOID InitOnceInitialize(PINIT_ONCE InitOnce); - /* Slim Reader/Writer (SRW) Lock */ typedef PVOID RTL_SRWLOCK; @@ -176,15 +162,6 @@ WINPR_API VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); WINPR_API VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -/* Synchronization Barrier */ - -typedef PVOID RTL_SYNCHRONIZATION_BARRIER; -typedef RTL_SYNCHRONIZATION_BARRIER SYNCHRONIZATION_BARRIER, *PSYNCHRONIZATION_BARRIER, *LPSYNCHRONIZATION_BARRIER; - -WINPR_API BOOL InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); -WINPR_API BOOL EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); -WINPR_API BOOL DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); - /* Sleep */ WINPR_API VOID Sleep(DWORD dwMilliseconds); @@ -297,12 +274,63 @@ WINPR_API BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE Com #endif -#if ((defined _WIN32) && (_WIN32_WINNT < 0x0403)) +#if (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) WINPR_API BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags); #endif +#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) + +/* One-Time Initialization */ + +typedef struct _RTL_RUN_ONCE +{ + PVOID Ptr; +} RTL_RUN_ONCE, *PRTL_RUN_ONCE; + +#define RTL_RUN_ONCE_INIT { 0 } +#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT + +typedef RTL_RUN_ONCE INIT_ONCE; +typedef PRTL_RUN_ONCE PINIT_ONCE; +typedef PRTL_RUN_ONCE LPINIT_ONCE; +typedef BOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context); + +WINPR_API BOOL InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID* lpContext); +WINPR_API BOOL InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext); +WINPR_API BOOL InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID* Context); +WINPR_API VOID InitOnceInitialize(PINIT_ONCE InitOnce); + +#endif + +/* Synchronization Barrier */ + +#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) + +typedef struct _RTL_BARRIER +{ + DWORD Reserved1; + DWORD Reserved2; + ULONG_PTR Reserved3[2]; + DWORD Reserved4; + DWORD Reserved5; +} RTL_BARRIER, *PRTL_BARRIER; + +typedef RTL_BARRIER SYNCHRONIZATION_BARRIER; +typedef PRTL_BARRIER PSYNCHRONIZATION_BARRIER; +typedef PRTL_BARRIER LPSYNCHRONIZATION_BARRIER; + +#define SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY 0x01 +#define SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY 0x02 +#define SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE 0x04 + +WINPR_API BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); +WINPR_API BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); +WINPR_API BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); + +#endif + /* Extended API */ WINPR_API VOID USleep(DWORD dwMicroseconds); diff --git a/winpr/include/winpr/sysinfo.h b/winpr/include/winpr/sysinfo.h index eca980a27..120009a08 100644 --- a/winpr/include/winpr/sysinfo.h +++ b/winpr/include/winpr/sysinfo.h @@ -298,20 +298,21 @@ WINPR_API ULONGLONG GetTickCount64(void); WINPR_API BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature); /* extended flags */ -#define PF_EX_3DNOW_PREFETCH 1 -#define PF_EX_SSSE3 2 -#define PF_EX_SSE41 3 -#define PF_EX_SSE42 4 -#define PF_EX_AVX 5 -#define PF_EX_FMA 6 -#define PF_EX_AVX_AES 7 -#define PF_EX_AVX2 8 -#define PF_EX_ARM_VFP1 9 -#define PF_EX_ARM_VFP3D16 10 -#define PF_EX_ARM_VFP4 11 -#define PF_EX_ARM_IDIVA 12 -#define PF_EX_ARM_IDIVT 13 -#define PF_EX_AVX_PCLMULQDQ 14 +#define PF_EX_LZCNT 1 +#define PF_EX_3DNOW_PREFETCH 2 +#define PF_EX_SSSE3 3 +#define PF_EX_SSE41 4 +#define PF_EX_SSE42 5 +#define PF_EX_AVX 6 +#define PF_EX_FMA 7 +#define PF_EX_AVX_AES 8 +#define PF_EX_AVX2 9 +#define PF_EX_ARM_VFP1 10 +#define PF_EX_ARM_VFP3D16 11 +#define PF_EX_ARM_VFP4 12 +#define PF_EX_ARM_IDIVA 13 +#define PF_EX_ARM_IDIVT 14 +#define PF_EX_AVX_PCLMULQDQ 15 /* * some "aliases" for the standard defines diff --git a/winpr/include/winpr/tchar.h b/winpr/include/winpr/tchar.h index 7390ed5f3..f3525bc66 100644 --- a/winpr/include/winpr/tchar.h +++ b/winpr/include/winpr/tchar.h @@ -40,6 +40,7 @@ typedef CHAR TCHAR; #define _tcslen _wcslen #define _tcsdup _wcsdup #define _tcscmp wcscmp +#define _tcsncmp wcsncmp #define _tcscpy wcscpy #define _tcscat wcscat #define _tcschr wcschr @@ -51,6 +52,7 @@ typedef CHAR TCHAR; #define _tcslen strlen #define _tcsdup _strdup #define _tcscmp strcmp +#define _tcsncmp strncmp #define _tcscpy strcpy #define _tcscat strcat #define _tcschr strchr diff --git a/winpr/include/winpr/user.h b/winpr/include/winpr/user.h new file mode 100644 index 000000000..0401f3d90 --- /dev/null +++ b/winpr/include/winpr/user.h @@ -0,0 +1,244 @@ +/** + * WinPR: Windows Portable Runtime + * User Environment + * + * 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_USER_H +#define WINPR_USER_H + +#include +#include + +/** + * Standard Clipboard Formats + */ + +#ifndef _WIN32 + +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_UNICODETEXT 13 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_DIBV5 17 +#define CF_MAX 18 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 +#define CF_DSPENHMETAFILE 0x008E + +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF + +#endif + +/** + * Bitmap Definitions + */ + +#ifndef _WIN32 + +#pragma pack(push, 1) + +typedef LONG FXPT16DOT16, FAR *LPFXPT16DOT16; +typedef LONG FXPT2DOT30, FAR *LPFXPT2DOT30; + +typedef struct tagCIEXYZ +{ + FXPT2DOT30 ciexyzX; + FXPT2DOT30 ciexyzY; + FXPT2DOT30 ciexyzZ; +} CIEXYZ; + +typedef CIEXYZ FAR *LPCIEXYZ; + +typedef struct tagICEXYZTRIPLE +{ + CIEXYZ ciexyzRed; + CIEXYZ ciexyzGreen; + CIEXYZ ciexyzBlue; +} CIEXYZTRIPLE; + +typedef CIEXYZTRIPLE FAR *LPCIEXYZTRIPLE; + +typedef struct tagBITMAP +{ + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + LPVOID bmBits; +} BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP; + +typedef struct tagRGBTRIPLE +{ + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +} RGBTRIPLE, *PRGBTRIPLE, NEAR *NPRGBTRIPLE, FAR *LPRGBTRIPLE; + +typedef struct tagRGBQUAD +{ + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} RGBQUAD; + +typedef RGBQUAD FAR* LPRGBQUAD; + +#define BI_RGB 0 +#define BI_RLE8 1 +#define BI_RLE4 2 +#define BI_BITFIELDS 3 +#define BI_JPEG 4 +#define BI_PNG 5 + +#define PROFILE_LINKED 'LINK' +#define PROFILE_EMBEDDED 'MBED' + +typedef struct tagBITMAPCOREHEADER +{ + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; +} BITMAPCOREHEADER, FAR *LPBITMAPCOREHEADER, *PBITMAPCOREHEADER; + +typedef struct tagBITMAPINFOHEADER +{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; + +typedef struct +{ + DWORD bV4Size; + LONG bV4Width; + LONG bV4Height; + WORD bV4Planes; + WORD bV4BitCount; + DWORD bV4V4Compression; + DWORD bV4SizeImage; + LONG bV4XPelsPerMeter; + LONG bV4YPelsPerMeter; + DWORD bV4ClrUsed; + DWORD bV4ClrImportant; + DWORD bV4RedMask; + DWORD bV4GreenMask; + DWORD bV4BlueMask; + DWORD bV4AlphaMask; + DWORD bV4CSType; + CIEXYZTRIPLE bV4Endpoints; + DWORD bV4GammaRed; + DWORD bV4GammaGreen; + DWORD bV4GammaBlue; +} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER; + +typedef struct +{ + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; +} BITMAPV5HEADER, FAR *LPBITMAPV5HEADER, *PBITMAPV5HEADER; + +typedef struct tagBITMAPINFO +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO; + +typedef struct tagBITMAPCOREINFO +{ + BITMAPCOREHEADER bmciHeader; + RGBTRIPLE bmciColors[1]; +} BITMAPCOREINFO, FAR *LPBITMAPCOREINFO, *PBITMAPCOREINFO; + +typedef struct tagBITMAPFILEHEADER +{ + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; + +#pragma pack(pop) + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_USER_H */ + diff --git a/winpr/include/winpr/winsock.h b/winpr/include/winpr/winsock.h index bb2eb7129..e8e85450d 100644 --- a/winpr/include/winpr/winsock.h +++ b/winpr/include/winpr/winsock.h @@ -71,6 +71,7 @@ PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize); #include #include #include +#include #include #include @@ -79,6 +80,10 @@ PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize); typedef UINT_PTR SOCKET; typedef struct sockaddr_storage SOCKADDR_STORAGE; +#ifndef INVALID_SOCKET +#define INVALID_SOCKET (SOCKET)(~0) +#endif + #define WSADESCRIPTION_LEN 256 #define WSASYS_STATUS_LEN 128 diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h index 1a149786b..f50baf41b 100644 --- a/winpr/include/winpr/wlog.h +++ b/winpr/include/winpr/wlog.h @@ -25,6 +25,7 @@ extern "C" { #endif #include +#include #include #include @@ -127,6 +128,7 @@ typedef int (*WLOG_APPENDER_WRITE_PACKET_MESSAGE_FN)(wLog* log, wLogAppender* ap DWORD State; \ wLogLayout* Layout; \ CRITICAL_SECTION lock; \ + BOOL recursive; \ void* TextMessageContext; \ void* DataMessageContext; \ void* ImageMessageContext; \ @@ -210,58 +212,89 @@ struct _wLog }; WINPR_API void WLog_PrintMessage(wLog* log, wLogMessage* message, ...); +WINPR_API int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args); #define WLog_Print(_log, _log_level, _fmt, ...) \ - if (_log_level >= WLog_GetLogLevel(_log)) { \ - wLogMessage _log_message; \ - _log_message.Type = WLOG_MESSAGE_TEXT; \ - _log_message.Level = _log_level; \ - _log_message.FormatString = _fmt; \ - _log_message.LineNumber = __LINE__; \ - _log_message.FileName = __FILE__; \ - _log_message.FunctionName = __FUNCTION__; \ - WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ - } + do { \ + if (_log_level >= WLog_GetLogLevel(_log)) { \ + wLogMessage _log_message; \ + _log_message.Type = WLOG_MESSAGE_TEXT; \ + _log_message.Level = _log_level; \ + _log_message.FormatString = _fmt; \ + _log_message.LineNumber = __LINE__; \ + _log_message.FileName = __FILE__; \ + _log_message.FunctionName = __FUNCTION__; \ + WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ + } \ + } while (0) + +#define WLog_PrintVA(_log, _log_level, _fmt, _args) \ + do { \ + if (_log_level >= WLog_GetLogLevel(_log)) { \ + wLogMessage _log_message; \ + _log_message.Type = WLOG_MESSAGE_TEXT; \ + _log_message.Level = _log_level; \ + _log_message.FormatString = _fmt; \ + _log_message.LineNumber = __LINE__; \ + _log_message.FileName = __FILE__; \ + _log_message.FunctionName = __FUNCTION__; \ + WLog_PrintMessageVA(_log, &(_log_message), _args); \ + } \ + } while (0) #define WLog_Data(_log, _log_level, ...) \ - if (_log_level >= WLog_GetLogLevel(_log)) { \ - wLogMessage _log_message; \ - _log_message.Type = WLOG_MESSAGE_DATA; \ - _log_message.Level = _log_level; \ - _log_message.FormatString = NULL; \ - _log_message.LineNumber = __LINE__; \ - _log_message.FileName = __FILE__; \ - _log_message.FunctionName = __FUNCTION__; \ - WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ - } + do { \ + if (_log_level >= WLog_GetLogLevel(_log)) { \ + wLogMessage _log_message; \ + _log_message.Type = WLOG_MESSAGE_DATA; \ + _log_message.Level = _log_level; \ + _log_message.FormatString = NULL; \ + _log_message.LineNumber = __LINE__; \ + _log_message.FileName = __FILE__; \ + _log_message.FunctionName = __FUNCTION__; \ + WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ + } \ + } while (0) #define WLog_Image(_log, _log_level, ...) \ - if (_log_level >= WLog_GetLogLevel(_log)) { \ - wLogMessage _log_message; \ - _log_message.Type = WLOG_MESSAGE_IMAGE; \ - _log_message.Level = _log_level; \ - _log_message.FormatString = NULL; \ - _log_message.LineNumber = __LINE__; \ - _log_message.FileName = __FILE__; \ - _log_message.FunctionName = __FUNCTION__; \ - WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ - } + do { \ + if (_log_level >= WLog_GetLogLevel(_log)) { \ + wLogMessage _log_message; \ + _log_message.Type = WLOG_MESSAGE_IMAGE; \ + _log_message.Level = _log_level; \ + _log_message.FormatString = NULL; \ + _log_message.LineNumber = __LINE__; \ + _log_message.FileName = __FILE__; \ + _log_message.FunctionName = __FUNCTION__; \ + WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ + } \ + } while (0) #define WLog_Packet(_log, _log_level, ...) \ - if (_log_level >= WLog_GetLogLevel(_log)) { \ - wLogMessage _log_message; \ - _log_message.Type = WLOG_MESSAGE_PACKET; \ - _log_message.Level = _log_level; \ - _log_message.FormatString = NULL; \ - _log_message.LineNumber = __LINE__; \ - _log_message.FileName = __FILE__; \ - _log_message.FunctionName = __FUNCTION__; \ - WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ - } + do { \ + if (_log_level >= WLog_GetLogLevel(_log)) { \ + wLogMessage _log_message; \ + _log_message.Type = WLOG_MESSAGE_PACKET; \ + _log_message.Level = _log_level; \ + _log_message.FormatString = NULL; \ + _log_message.LineNumber = __LINE__; \ + _log_message.FileName = __FILE__; \ + _log_message.FunctionName = __FUNCTION__; \ + WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \ + } \ + } while (0) #define WLog_IsLevelActive(_log, _log_level) \ (_log_level >= WLog_GetLogLevel(_log)) +#define WLog_LVL(tag, lvl, fmt, ...) WLog_Print(WLog_Get(tag), lvl, fmt, ## __VA_ARGS__) +#define WLog_VRB(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_TRACE, fmt, ## __VA_ARGS__) +#define WLog_DBG(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_DEBUG, fmt, ## __VA_ARGS__) +#define WLog_INFO(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_INFO, fmt, ## __VA_ARGS__) +#define WLog_WARN(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_WARN, fmt, ## __VA_ARGS__) +#define WLog_ERR(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_ERROR, fmt, ## __VA_ARGS__) +#define WLog_FATAL(tag, fmt, ...) WLog_Print(WLog_Get(tag), WLOG_FATAL, fmt, ## __VA_ARGS__) + WINPR_API DWORD WLog_GetLogLevel(wLog* log); WINPR_API void WLog_SetLogLevel(wLog* log, DWORD logLevel); diff --git a/winpr/include/winpr/wnd.h b/winpr/include/winpr/wnd.h index 8b1cdc0df..f09995913 100644 --- a/winpr/include/winpr/wnd.h +++ b/winpr/include/winpr/wnd.h @@ -410,8 +410,6 @@ typedef struct tagWTSSESSION_NOTIFICATION #define WTS_SESSION_LOCK 0x7 #define WTS_SESSION_UNLOCK 0x8 #define WTS_SESSION_REMOTE_CONTROL 0x9 -#define WTS_SESSION_CREATE 0xA -#define WTS_SESSION_TERMINATE 0xB #ifdef __cplusplus extern "C" { @@ -453,10 +451,12 @@ WINPR_API HWND WINAPI CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +#ifndef WINPR_NO_CREATE_WINDOW #define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) \ CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) #define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) \ CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) +#endif WINPR_API HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName); WINPR_API HWND WINAPI FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName); @@ -519,7 +519,9 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR #define RegisterClass RegisterClassW #define RegisterClassEx RegisterClassExW #define UnregisterClass UnregisterClassW +#ifndef WINPR_NO_CREATE_WINDOW #define CreateWindow CreateWindowW +#endif #define CreateWindowEx CreateWindowExW #define FindWindow FindWindowW #define FindWindowEx FindWindowExW @@ -540,7 +542,9 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR #define RegisterClass RegisterClassA #define RegisterClassEx RegisterClassExA #define UnregisterClass UnregisterClassA +#ifndef WINPR_NO_CREATE_WINDOW #define CreateWindow CreateWindowA +#endif #define CreateWindowEx CreateWindowExA #define FindWindow FindWindowA #define FindWindowEx FindWindowExA @@ -561,5 +565,13 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR #endif +#ifndef WTS_SESSION_CREATE +#define WTS_SESSION_CREATE 0xA +#endif + +#ifndef WTS_SESSION_TERMINATE +#define WTS_SESSION_TERMINATE 0xB +#endif + #endif /* WINPR_WND_H */ diff --git a/winpr/include/winpr/wtypes.h b/winpr/include/winpr/wtypes.h index 2f184b256..b0ff505ee 100644 --- a/winpr/include/winpr/wtypes.h +++ b/winpr/include/winpr/wtypes.h @@ -379,4 +379,6 @@ typedef WORD LANGID; #endif +#include + #endif /* WINPR_WTYPES_H */ diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index c2eabedda..13d864efb 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -15,48 +15,92 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr") -set(MODULE_PREFIX "WINPR") - if (APPLE) # flat_namespace should be avoided, but is required for -undefined warning. Since WinPR currently has # a lot of undefined symbols in use, use this hack until they're filled out. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-flat_namespace,-undefined,warning") endif() -if(MONOLITHIC_BUILD) - set(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif() +set(WINPR_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(WINPR_SRCS "") +set(WINPR_LIBS "") +set(WINPR_INCLUDES "") +set(WINPR_DEFINITIONS "") -set(FILENAME "ModuleOptions.cmake") -file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}") +macro (winpr_module_add) + file (RELATIVE_PATH _relPath "${WINPR_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") + foreach (_src ${ARGN}) + if (_relPath) + list (APPEND WINPR_SRCS "${_relPath}/${_src}") + else() + list (APPEND WINPR_SRCS "${_src}") + endif() + endforeach() + if (_relPath) + set (WINPR_SRCS ${WINPR_SRCS} PARENT_SCOPE) + endif() +endmacro() -foreach(FILEPATH ${FILEPATHS}) - if(${FILEPATH} MATCHES "^([^/]*)//${FILENAME}") - string(REGEX REPLACE "^([^/]*)//${FILENAME}" "\\1" ${MODULE_PREFIX}_SUBMODULE ${FILEPATH}) - set(${MODULE_PREFIX}_SUBMODULES ${${MODULE_PREFIX}_SUBMODULES} ${${MODULE_PREFIX}_SUBMODULE}) - endif() -endforeach(FILEPATH) +macro (winpr_include_directory_add) + file (RELATIVE_PATH _relPath "${WINPR_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") + foreach (_inc ${ARGN}) + if (IS_ABSOLUTE ${_inc}) + list (APPEND WINPR_INCLUDES "${_inc}") + else() + if (_relPath) + list (APPEND WINPR_INCLUDES "${_relPath}/${_inc}") + else() + list (APPEND WINPR_INCLUDES "${_inc}") + endif() + endif() + endforeach() + if (_relPath) + set (WINPR_INCLUDES ${WINPR_INCLUDES} PARENT_SCOPE) + endif() +endmacro() -foreach(${MODULE_PREFIX}_SUBMODULE ${${MODULE_PREFIX}_SUBMODULES}) - add_subdirectory(${${MODULE_PREFIX}_SUBMODULE}) +macro (winpr_library_add) + foreach (_lib ${ARGN}) + list (APPEND WINPR_LIBS "${_lib}") + endforeach() + set (WINPR_LIBS ${WINPR_LIBS} PARENT_SCOPE) +endmacro() + +macro (winpr_definition_add) + foreach (_define ${ARGN}) + list (APPEND WINPR_DEFINITIONS "${_define}") + endforeach() + set (WINPR_DEFINITIONS ${WINPR_DEFINITIONS} PARENT_SCOPE) +endmacro() + +# Level "1" API as defined for MinCore.lib +set(WINPR_CORE synch locale library file comm pipe interlocked security + environment crypto registry credentials path io memory input + heap utils error com timezone sysinfo pool handle thread) + +foreach(DIR ${WINPR_CORE}) + add_subdirectory(${DIR}) endforeach() -if(MONOLITHIC_BUILD) +set(WINPR_LEVEL2 winsock sspi winhttp asn1 sspicli crt bcrypt rpc credui + wtsapi dsparse wnd smartcard nt clipboard) - foreach(${MODULE_PREFIX}_SUBMODULE ${${MODULE_PREFIX}_SUBMODULES}) - set(${MODULE_PREFIX}_OBJECTS ${${MODULE_PREFIX}_OBJECTS} "$") - endforeach() +foreach(DIR ${WINPR_LEVEL2}) + add_subdirectory(${DIR}) +endforeach() - add_library(${MODULE_NAME} dummy.c ${${MODULE_PREFIX}_OBJECTS}) - - set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C) - set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - - list(REMOVE_DUPLICATES WINPR_LIBS) - target_link_libraries(${MODULE_NAME} ${WINPR_LIBS}) - - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT WinPRTargets) - - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr") +set(MODULE_NAME winpr) +list(REMOVE_DUPLICATES WINPR_DEFINITIONS) +list(REMOVE_DUPLICATES WINPR_LIBS) +list(REMOVE_DUPLICATES WINPR_INCLUDES) +include_directories(${WINPR_INCLUDES}) +add_library(${MODULE_NAME} ${WINPR_SRCS}) +set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C) +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION}) endif() +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "lib") +add_definitions(${WINPR_DEFINITIONS}) +target_link_libraries(${MODULE_NAME} ${WINPR_LIBS}) +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT WinPRTargets) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr") diff --git a/winpr/libwinpr/asn1/CMakeLists.txt b/winpr/libwinpr/asn1/CMakeLists.txt index 920e8001c..214f52801 100644 --- a/winpr/libwinpr/asn1/CMakeLists.txt +++ b/winpr/libwinpr/asn1/CMakeLists.txt @@ -15,30 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-asn1") -set(MODULE_PREFIX "WINPR_ASN1") - -set(${MODULE_PREFIX}_SRCS - asn1.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(asn1.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/asn1/test/CMakeLists.txt b/winpr/libwinpr/asn1/test/CMakeLists.txt index 60e967906..22b8eb50f 100644 --- a/winpr/libwinpr/asn1/test/CMakeLists.txt +++ b/winpr/libwinpr/asn1/test/CMakeLists.txt @@ -24,12 +24,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-asn1) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/bcrypt/CMakeLists.txt b/winpr/libwinpr/bcrypt/CMakeLists.txt index b70d9bf85..24c2206c4 100644 --- a/winpr/libwinpr/bcrypt/CMakeLists.txt +++ b/winpr/libwinpr/bcrypt/CMakeLists.txt @@ -15,35 +15,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-bcrypt") -set(MODULE_PREFIX "WINPR_BCRYPT") +winpr_module_add(bcrypt.c) -set(${MODULE_PREFIX}_SRCS - bcrypt.c) +winpr_include_directory_add( + ${OPENSSL_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIRS}) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -include_directories(${OPENSSL_INCLUDE_DIR}) -include_directories(${ZLIB_INCLUDE_DIRS}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${ZLIB_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-utils) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_library_add(${ZLIB_LIBRARIES}) diff --git a/winpr/libwinpr/clipboard/CMakeLists.txt b/winpr/libwinpr/clipboard/CMakeLists.txt new file mode 100644 index 000000000..a5be7cb59 --- /dev/null +++ b/winpr/libwinpr/clipboard/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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( + synthetic.c + clipboard.c + clipboard.h) + +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..7c0333e78 --- /dev/null +++ b/winpr/libwinpr/clipboard/clipboard.c @@ -0,0 +1,498 @@ +/** + * 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/ + */ + +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; +} + +wClipboardSynthesizer* ClipboardFindSynthesizer(wClipboardFormat* format, UINT32 formatId) +{ + UINT32 index; + wClipboardSynthesizer* synthesizer; + + if (!format) + return NULL; + + if (format->numSynthesizers < 1) + return NULL; + + for (index = 0; index < format->numSynthesizers; index++) + { + synthesizer = &(format->synthesizers[index]); + + if (formatId == synthesizer->syntheticId) + return synthesizer; + } + + return NULL; +} + +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 ClipboardCountRegisteredFormats(wClipboard* clipboard) +{ + return clipboard->numFormats; +} + +UINT32 ClipboardGetRegisteredFormatIds(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 ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, + UINT32 syntheticId, CLIPBOARD_SYNTHESIZE_FN pfnSynthesize) +{ + UINT32 index; + wClipboardFormat* format; + wClipboardSynthesizer* synthesizer; + + format = ClipboardFindFormat(clipboard, formatId, NULL); + + if (!format) + return FALSE; + + if (format->formatId == syntheticId) + return FALSE; + + synthesizer = ClipboardFindSynthesizer(format, formatId); + + if (!synthesizer) + { + index = format->numSynthesizers++; + + format->synthesizers = (wClipboardSynthesizer*) realloc(format->synthesizers, + format->numSynthesizers * sizeof(wClipboardSynthesizer)); + + if (!format->synthesizers) + return FALSE; + + synthesizer = &(format->synthesizers[index]); + } + + ZeroMemory(synthesizer, sizeof(wClipboardSynthesizer)); + + synthesizer->syntheticId = syntheticId; + synthesizer->pfnSynthesize = pfnSynthesize; + + return TRUE; +} + +UINT32 ClipboardCountFormats(wClipboard* clipboard) +{ + UINT32 count; + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, clipboard->formatId, NULL); + + if (!format) + return 0; + + count = 1 + format->numSynthesizers; + + return count; +} + +UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds) +{ + UINT32 index; + UINT32 count; + UINT32* pFormatIds; + wClipboardFormat* format; + wClipboardSynthesizer* synthesizer; + + format = ClipboardFindFormat(clipboard, clipboard->formatId, NULL); + + if (!format) + return 0; + + count = 1 + format->numSynthesizers; + + if (!ppFormatIds) + return 0; + + pFormatIds = *ppFormatIds; + + if (!pFormatIds) + { + pFormatIds = malloc(count * sizeof(UINT32)); + + if (!pFormatIds) + return 0; + + *ppFormatIds = pFormatIds; + } + + pFormatIds[0] = format->formatId; + + for (index = 1; index < count; index++) + { + synthesizer = &(format->synthesizers[index - 1]); + pFormatIds[index] = synthesizer->syntheticId; + } + + return count; +} + +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; + } + + ClipboardInitSynthesizers(clipboard); + + return TRUE; +} + +UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name) +{ + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, 0, name); + + if (!format) + return 0; + + return format->formatId; +} + +const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId) +{ + wClipboardFormat* format; + + format = ClipboardFindFormat(clipboard, formatId, NULL); + + if (!format) + return NULL; + + return format->formatName; +} + +void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize) +{ + UINT32 SrcSize = 0; + UINT32 DstSize = 0; + void* pSrcData = NULL; + void* pDstData = NULL; + wClipboardFormat* format; + wClipboardSynthesizer* synthesizer; + + if (!pSize) + return NULL; + + format = ClipboardFindFormat(clipboard, clipboard->formatId, NULL); + + if (!format) + return NULL; + + SrcSize = clipboard->size; + pSrcData = (void*) clipboard->data; + + if (formatId == format->formatId) + { + DstSize = SrcSize; + + pDstData = malloc(DstSize); + + if (!pDstData) + return NULL; + + CopyMemory(pDstData, pSrcData, SrcSize); + *pSize = DstSize; + } + else + { + synthesizer = ClipboardFindSynthesizer(format, formatId); + + if (!synthesizer || !synthesizer->pfnSynthesize) + return NULL; + + DstSize = SrcSize; + pDstData = synthesizer->pfnSynthesize(clipboard, format->formatId, pSrcData, &DstSize); + + *pSize = DstSize; + } + + return pDstData; +} + +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); + + if (format->synthesizers) + { + free(format->synthesizers); + format->synthesizers = NULL; + format->numSynthesizers = 0; + } + } + + 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..76d65266b --- /dev/null +++ b/winpr/libwinpr/clipboard/clipboard.h @@ -0,0 +1,68 @@ +/** + * 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 + +#include + +typedef struct _wClipboardFormat wClipboardFormat; +typedef struct _wClipboardSynthesizer wClipboardSynthesizer; + +struct _wClipboardFormat +{ + UINT32 formatId; + const char* formatName; + + UINT32 numSynthesizers; + wClipboardSynthesizer* synthesizers; +}; + +struct _wClipboardSynthesizer +{ + UINT32 syntheticId; + CLIPBOARD_SYNTHESIZE_FN pfnSynthesize; +}; + +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; +}; + +BOOL ClipboardInitSynthesizers(wClipboard* clipboard); + +#endif /* WINPR_CLIPBOARD_PRIVATE_H */ diff --git a/winpr/libwinpr/clipboard/synthetic.c b/winpr/libwinpr/clipboard/synthetic.c new file mode 100644 index 000000000..2878cb92b --- /dev/null +++ b/winpr/libwinpr/clipboard/synthetic.c @@ -0,0 +1,669 @@ +/** + * 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 "clipboard.h" + +/** + * Standard Clipboard Formats: + * http://msdn.microsoft.com/en-us/library/windows/desktop/ff729168/ + */ + +/** + * "CF_TEXT": + * + * Null-terminated ANSI text with CR/LF line endings. + */ + +static void* clipboard_synthesize_cf_text(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + int size; + char* pDstData = NULL; + + if (formatId == CF_UNICODETEXT) + { + char* str = NULL; + + size = (int) *pSize; + size = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) data, + size / 2, (CHAR**) &str, 0, NULL, NULL); + + if (!str) + return NULL; + + pDstData = ConvertLineEndingToCRLF((const char*) str, &size); + free(str); + + *pSize = size; + + return pDstData; + } + else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || + (formatId == ClipboardGetFormatId(clipboard, "UTF8_STRING")) || + (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || + (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || + (formatId == ClipboardGetFormatId(clipboard, "STRING"))) + { + size = (int) *pSize; + pDstData = ConvertLineEndingToCRLF((const char*) data, &size); + + if (!pDstData) + return NULL; + + *pSize = size; + + return pDstData; + } + + return NULL; +} + +/** + * "CF_OEMTEXT": + * + * Null-terminated OEM text with CR/LF line endings. + */ + +static void* clipboard_synthesize_cf_oemtext(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + return clipboard_synthesize_cf_text(clipboard, formatId, data, pSize); +} + +/** + * "CF_LOCALE": + * + * System locale identifier associated with CF_TEXT + */ + +static void* clipboard_synthesize_cf_locale(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + UINT32* pDstData = NULL; + + pDstData = (UINT32*) malloc(sizeof(UINT32)); + *pDstData = 0x0409; /* English - United States */ + + return (void*) pDstData; +} + +/** + * "CF_UNICODETEXT": + * + * Null-terminated UTF-16 text with CR/LF line endings. + */ + +static void* clipboard_synthesize_cf_unicodetext(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + int size; + int status; + char* crlfStr = NULL; + WCHAR* pDstData = NULL; + + if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || + (formatId == ClipboardGetFormatId(clipboard, "UTF8_STRING")) || + (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || + (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || + (formatId == ClipboardGetFormatId(clipboard, "STRING"))) + { + size = (int) *pSize; + crlfStr = ConvertLineEndingToCRLF((char*) data, &size); + + if (!crlfStr) + return NULL; + + status = ConvertToUnicode(CP_UTF8, 0, crlfStr, size, &pDstData, 0); + free(crlfStr); + + if (status <= 0) + return NULL; + + *pSize = ((status + 1) * 2); + } + + return (void*) pDstData; +} + +/** + * "UTF8_STRING": + * + * Null-terminated UTF-8 string with LF line endings. + */ + +static void* clipboard_synthesize_utf8_string(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + int size; + char* pDstData = NULL; + + if (formatId == CF_UNICODETEXT) + { + size = (int) *pSize; + size = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) data, + size / 2, (CHAR**) &pDstData, 0, NULL, NULL); + + if (!pDstData) + return NULL; + + size = ConvertLineEndingToLF(pDstData, size); + + *pSize = size; + + return pDstData; + } + else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || + (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || + (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || + (formatId == ClipboardGetFormatId(clipboard, "STRING"))) + { + size = (int) *pSize; + pDstData = (char*) malloc(size); + + if (!pDstData) + return NULL; + + CopyMemory(pDstData, data, size); + + size = ConvertLineEndingToLF((char*) pDstData, size); + + *pSize = size; + + return pDstData; + } + + return NULL; +} + +/** + * "CF_DIB": + * + * BITMAPINFO structure followed by the bitmap bits. + */ + +static void* clipboard_synthesize_cf_dib(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + + SrcSize = *pSize; + + if (formatId == CF_DIBV5) + { + + } + else if (formatId == ClipboardGetFormatId(clipboard, "image/bmp")) + { + BITMAPFILEHEADER* pFileHeader; + + if (SrcSize < (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) + return NULL; + + pFileHeader = (BITMAPFILEHEADER*) data; + + if (pFileHeader->bfType != 0x4D42) + return NULL; + + DstSize = SrcSize - sizeof(BITMAPFILEHEADER); + pDstData = (BYTE*) malloc(DstSize); + + if (!pDstData) + return NULL; + + data = (void*) &((BYTE*) data)[sizeof(BITMAPFILEHEADER)]; + + CopyMemory(pDstData, data, DstSize); + *pSize = DstSize; + + return pDstData; + } + + return NULL; +} + +/** + * "CF_DIBV5": + * + * BITMAPV5HEADER structure followed by the bitmap color space information and the bitmap bits. + */ + +static void* clipboard_synthesize_cf_dibv5(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + if (formatId == CF_DIB) + { + + } + else if (formatId == ClipboardGetFormatId(clipboard, "image/bmp")) + { + + } + + return NULL; +} + +/** + * "image/bmp": + * + * Bitmap file format. + */ + +static void* clipboard_synthesize_image_bmp(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData; + + SrcSize = *pSize; + + if (formatId == CF_DIB) + { + BYTE* pDst; + BITMAPINFOHEADER* pInfoHeader; + BITMAPFILEHEADER* pFileHeader; + + if (SrcSize < sizeof(BITMAPINFOHEADER)) + return NULL; + + pInfoHeader = (BITMAPINFOHEADER*) data; + + if ((pInfoHeader->biBitCount < 1) || (pInfoHeader->biBitCount > 32)) + return NULL; + + DstSize = sizeof(BITMAPFILEHEADER) + SrcSize; + pDstData = (BYTE*) malloc(DstSize); + + if (!pDstData) + return NULL; + + pFileHeader = (BITMAPFILEHEADER*) pDstData; + pFileHeader->bfType = 0x4D42; + pFileHeader->bfSize = DstSize; + pFileHeader->bfReserved1 = 0; + pFileHeader->bfReserved2 = 0; + pFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + pDst = &pDstData[sizeof(BITMAPFILEHEADER)]; + CopyMemory(pDst, data, SrcSize); + *pSize = DstSize; + + return pDstData; + } + else if (formatId == CF_DIBV5) + { + + } + + return NULL; +} + +/** + * "HTML Format": + * + * HTML clipboard format: msdn.microsoft.com/en-us/library/windows/desktop/ms649015/ + */ + +static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + char* pSrcData = NULL; + char* pDstData = NULL; + int SrcSize = (int) *pSize; + + if (formatId == ClipboardGetFormatId(clipboard, "text/html")) + { + char* body; + BYTE bom[2]; + char num[11]; + + if (SrcSize > 2) + { + CopyMemory(bom, data, 2); + + if ((bom[0] == 0xFE) && (bom[1] == 0xFF)) + { + ByteSwapUnicode((WCHAR*) data, SrcSize / 2); + } + + if ((bom[0] == 0xFF) && (bom[1] == 0xFE)) + { + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) (data + 2), + (SrcSize - 2) / 2, &pSrcData, 0, NULL, NULL); + } + } + + if (!pSrcData) + { + pSrcData = (char*) calloc(1, SrcSize + 1); + CopyMemory(pSrcData, data, SrcSize); + } + + pDstData = (char*) calloc(1, SrcSize + 200); + + strcpy(pDstData, + "Version:0.9\r\n" + "StartHTML:0000000000\r\n" + "EndHTML:0000000000\r\n" + "StartFragment:0000000000\r\n" + "EndFragment:0000000000\r\n"); + + body = strstr(pSrcData, ""); + + strcat(pDstData, ""); + + /* StartFragment */ + sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + CopyMemory(&pDstData[69], num, 10); + strcat(pDstData, pSrcData); + + /* EndFragment */ + sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + CopyMemory(&pDstData[93], num, 10); + strcat(pDstData, ""); + + if (!body) + strcat(pDstData, ""); + + /* EndHTML */ + sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + CopyMemory(&pDstData[43], num, 10); + + *pSize = (UINT32) strlen(pDstData) + 1; + free(pSrcData); + } + + return pDstData; +} + +/** + * "text/html": + * + * HTML text format. + */ + +static void* clipboard_synthesize_text_html(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) +{ + int beg; + int end; + char* str; + char* begStr; + char* endStr; + int SrcSize; + int DstSize = -1; + BYTE* pDstData = NULL; + + if (formatId == ClipboardGetFormatId(clipboard, "HTML Format")) + { + str = (char*) data; + SrcSize = (int) *pSize; + + begStr = strstr(str, "StartHTML:"); + endStr = strstr(str, "EndHTML:"); + + if (!begStr || !endStr) + return NULL; + + beg = atoi(&begStr[10]); + end = atoi(&endStr[8]); + + if ((beg > SrcSize) || (end > SrcSize) || (beg >= end)) + return NULL; + + DstSize = end - beg; + pDstData = (BYTE*) malloc(SrcSize - beg + 1); + + if (!pDstData) + return NULL; + + CopyMemory(pDstData, &str[beg], DstSize); + DstSize = ConvertLineEndingToLF((char*) pDstData, DstSize); + *pSize = (UINT32) DstSize; + } + + return (void*) pDstData; +} + +BOOL ClipboardInitSynthesizers(wClipboard* clipboard) +{ + UINT32 formatId; + UINT32 altFormatId; + + /** + * CF_TEXT + */ + + ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, CF_TEXT, CF_LOCALE, + clipboard_synthesize_cf_locale); + + altFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING"); + + ClipboardRegisterSynthesizer(clipboard, CF_TEXT, altFormatId, + clipboard_synthesize_utf8_string); + + /** + * CF_OEMTEXT + */ + + ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, CF_LOCALE, + clipboard_synthesize_cf_locale); + + altFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING"); + + ClipboardRegisterSynthesizer(clipboard, CF_OEMTEXT, altFormatId, + clipboard_synthesize_utf8_string); + + /** + * CF_UNICODETEXT + */ + + ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, CF_LOCALE, + clipboard_synthesize_cf_locale); + + altFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING"); + + ClipboardRegisterSynthesizer(clipboard, CF_UNICODETEXT, altFormatId, + clipboard_synthesize_utf8_string); + + /** + * UTF8_STRING + */ + + formatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING"); + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE, + clipboard_synthesize_cf_locale); + } + + /** + * text/plain + */ + + formatId = ClipboardRegisterFormat(clipboard, "text/plain"); + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE, + clipboard_synthesize_cf_locale); + } + + /** + * TEXT + */ + + formatId = ClipboardRegisterFormat(clipboard, "TEXT"); + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE, + clipboard_synthesize_cf_locale); + } + + /** + * STRING + */ + + formatId = ClipboardRegisterFormat(clipboard, "STRING"); + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, formatId, CF_TEXT, + clipboard_synthesize_cf_text); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_OEMTEXT, + clipboard_synthesize_cf_oemtext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_UNICODETEXT, + clipboard_synthesize_cf_unicodetext); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_LOCALE, + clipboard_synthesize_cf_locale); + } + + /** + * CF_DIB + */ + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, CF_DIB, CF_DIBV5, + clipboard_synthesize_cf_dibv5); + + altFormatId = ClipboardRegisterFormat(clipboard, "image/bmp"); + + ClipboardRegisterSynthesizer(clipboard, CF_DIB, altFormatId, + clipboard_synthesize_image_bmp); + } + + /** + * CF_DIBV5 + */ + + if (formatId && 0) + { + ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, CF_DIB, + clipboard_synthesize_cf_dib); + + altFormatId = ClipboardRegisterFormat(clipboard, "image/bmp"); + + ClipboardRegisterSynthesizer(clipboard, CF_DIBV5, altFormatId, + clipboard_synthesize_image_bmp); + } + + /** + * image/bmp + */ + + formatId = ClipboardRegisterFormat(clipboard, "image/bmp"); + + if (formatId) + { + ClipboardRegisterSynthesizer(clipboard, formatId, CF_DIB, + clipboard_synthesize_cf_dib); + + ClipboardRegisterSynthesizer(clipboard, formatId, CF_DIBV5, + clipboard_synthesize_cf_dibv5); + } + + /** + * HTML Format + */ + + formatId = ClipboardRegisterFormat(clipboard, "HTML Format"); + + if (formatId) + { + altFormatId = ClipboardRegisterFormat(clipboard, "text/html"); + + ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId, + clipboard_synthesize_text_html); + } + + /** + * text/html + */ + + formatId = ClipboardRegisterFormat(clipboard, "text/html"); + + if (formatId) + { + altFormatId = ClipboardRegisterFormat(clipboard, "HTML Format"); + + ClipboardRegisterSynthesizer(clipboard, formatId, altFormatId, + clipboard_synthesize_html_format); + } + + return TRUE; +} 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..2242bcd2a --- /dev/null +++ b/winpr/libwinpr/clipboard/test/TestClipboardFormats.c @@ -0,0 +1,94 @@ + +#include +#include +#include + +int TestClipboardFormats(int argc, char* argv[]) +{ + UINT32 index; + UINT32 count; + UINT32 formatId; + UINT32* pFormatIds; + const char* formatName; + wClipboard* clipboard; + UINT32 utf8StringFormatId; + + clipboard = ClipboardCreate(); + + formatId = ClipboardRegisterFormat(clipboard, "text/html"); + formatId = ClipboardRegisterFormat(clipboard, "image/bmp"); + formatId = ClipboardRegisterFormat(clipboard, "image/png"); + utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING"); + + pFormatIds = NULL; + count = ClipboardGetRegisteredFormatIds(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); + + if (1) + { + BOOL bSuccess; + UINT32 SrcSize; + UINT32 DstSize; + char* pSrcData; + char* pDstData; + + pSrcData = _strdup("this is a test string"); + SrcSize = (UINT32) (strlen(pSrcData) + 1); + + bSuccess = ClipboardSetData(clipboard, utf8StringFormatId, (void*) pSrcData, SrcSize); + + fprintf(stderr, "ClipboardSetData: %d\n", bSuccess); + + DstSize = 0; + pDstData = (char*) ClipboardGetData(clipboard, utf8StringFormatId, &DstSize); + + fprintf(stderr, "ClipboardGetData: %s\n", pDstData); + + free(pDstData); + } + + if (1) + { + UINT32 DstSize; + char* pSrcData; + WCHAR* pDstData; + + DstSize = 0; + pDstData = (WCHAR*) ClipboardGetData(clipboard, CF_UNICODETEXT, &DstSize); + + pSrcData = NULL; + ConvertFromUnicode(CP_UTF8, 0, pDstData, -1, &pSrcData, 0, NULL, NULL); + + fprintf(stderr, "ClipboardGetData (synthetic): %s\n", pSrcData); + + free(pDstData); + free(pSrcData); + } + + 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; +} + diff --git a/winpr/libwinpr/com/CMakeLists.txt b/winpr/libwinpr/com/CMakeLists.txt index f00507be4..1b82dbc69 100644 --- a/winpr/libwinpr/com/CMakeLists.txt +++ b/winpr/libwinpr/com/CMakeLists.txt @@ -15,35 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-com") -set(MODULE_PREFIX "WINPR_COM") - -set(${MODULE_PREFIX}_SRCS - com.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} credui) -endif() - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(com.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/com/test/CMakeLists.txt b/winpr/libwinpr/com/test/CMakeLists.txt index 94e42c352..ac6c1c008 100644 --- a/winpr/libwinpr/com/test/CMakeLists.txt +++ b/winpr/libwinpr/com/test/CMakeLists.txt @@ -1,4 +1,3 @@ - set(MODULE_NAME "TestCom") set(MODULE_PREFIX "TEST_COM") @@ -13,13 +12,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-com) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") foreach(test ${${MODULE_PREFIX}_TESTS}) @@ -28,4 +21,3 @@ foreach(test ${${MODULE_PREFIX}_TESTS}) endforeach() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") - diff --git a/winpr/libwinpr/comm/CMakeLists.txt b/winpr/libwinpr/comm/CMakeLists.txt new file mode 100644 index 000000000..0fe9f566f --- /dev/null +++ b/winpr/libwinpr/comm/CMakeLists.txt @@ -0,0 +1,40 @@ +# WinPR: Windows Portable Runtime +# libwinpr-comm 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. + +set(MODULE_NAME "winpr-comm") +set(MODULE_PREFIX "WINPR_COMM") + +if(UNIX AND NOT WIN32 AND NOT APPLE) + set(${MODULE_PREFIX}_SRCS + comm.c + comm.h + comm_io.c + comm_ioctl.c + comm_ioctl.h + comm_serial_sys.c + comm_serial_sys.h + comm_sercx_sys.c + comm_sercx_sys.h + comm_sercx2_sys.c + comm_sercx2_sys.h) + + winpr_module_add(${${MODULE_PREFIX}_SRCS}) + + if(BUILD_TESTING) + add_subdirectory(test) + endif() +endif() diff --git a/winpr/libwinpr/comm/ModuleOptions.cmake b/winpr/libwinpr/comm/ModuleOptions.cmake new file mode 100644 index 000000000..40955892a --- /dev/null +++ b/winpr/libwinpr/comm/ModuleOptions.cmake @@ -0,0 +1,9 @@ + +set(MINWIN_LAYER "1") +set(MINWIN_GROUP "core") +set(MINWIN_MAJOR_VERSION "1") +set(MINWIN_MINOR_VERSION "0") +set(MINWIN_SHORT_NAME "comm") +set(MINWIN_LONG_NAME "Serial Communication API") +set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}") + diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c new file mode 100644 index 000000000..5aa213894 --- /dev/null +++ b/winpr/libwinpr/comm/comm.c @@ -0,0 +1,1510 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#if defined __linux__ && !defined ANDROID + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "comm_ioctl.h" + + +/** + * Communication Resources: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363196/ + */ + +#include "comm.h" + + +static wLog *_Log = NULL; + +struct comm_device +{ + LPTSTR name; + LPTSTR path; +}; + +typedef struct comm_device COMM_DEVICE; + + +/* FIXME: get a clever data structure, see also io.h functions */ +/* _CommDevices is a NULL-terminated array with a maximun of COMM_DEVICE_MAX COMM_DEVICE */ +#define COMM_DEVICE_MAX 128 +static COMM_DEVICE **_CommDevices = NULL; +static CRITICAL_SECTION _CommDevicesLock; + +static HANDLE_CREATOR *_CommHandleCreator = NULL; +static HANDLE_CLOSE_CB *_CommHandleCloseCb = NULL; + +static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT; +static void _CommInit() +{ + /* NB: error management to be done outside of this function */ + + assert(_Log == NULL); + assert(_CommDevices == NULL); + assert(_CommHandleCreator == NULL); + assert(_CommHandleCloseCb == NULL); + + _Log = WLog_Get("com.winpr.comm"); + + _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); + InitializeCriticalSection(&_CommDevicesLock); + + _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); + if (_CommHandleCreator) + { + _CommHandleCreator->IsHandled = IsCommDevice; + _CommHandleCreator->CreateFileA = CommCreateFileA; + + RegisterHandleCreator(_CommHandleCreator); + } + + _CommHandleCloseCb = (HANDLE_CLOSE_CB*)malloc(sizeof(HANDLE_CLOSE_CB)); + if (_CommHandleCloseCb) + { + _CommHandleCloseCb->IsHandled = CommIsHandled; + _CommHandleCloseCb->CloseHandle = CommCloseHandle; + + RegisterHandleCloseCb(_CommHandleCloseCb); + } + + assert(_Log != NULL); + assert(_CommDevices != NULL); + assert(_CommHandleCreator != NULL); + assert(_CommHandleCloseCb != NULL); +} + + +/** + * Returns TRUE when the comm module is correctly intialized, FALSE otherwise + * with ERROR_DLL_INIT_FAILED set as the last error. + */ +static BOOL CommInitialized() +{ + if (pthread_once(&_CommInitialized, _CommInit) != 0) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + return TRUE; +} + + +void CommLog_Print(int level, char *fmt, ...) +{ + if (!CommInitialized()) + return; + + va_list ap; + va_start(ap, fmt); + WLog_PrintVA(_Log, level, fmt, ap); + va_end(ap); +} + + +BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hCommDev; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hCommDev; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +/** + * ERRORS: + * ERROR_DLL_INIT_FAILED + * ERROR_INVALID_HANDLE + */ +BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, lpCommProp, sizeof(COMMPROP), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommProperties failure."); + return FALSE; + } + + return TRUE; +} + + + +/** + * + * + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_INVALID_DATA + * ERROR_IO_DEVICE + * ERROR_OUTOFMEMORY + */ +BOOL GetCommState(HANDLE hFile, LPDCB lpDCB) +{ + DCB *lpLocalDcb; + struct termios currentState; + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!lpDCB) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (lpDCB->DCBlength < sizeof(DCB)) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + lpLocalDcb = (DCB*)calloc(1, lpDCB->DCBlength); + if (lpLocalDcb == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + /* error_handle */ + + lpLocalDcb->DCBlength = lpDCB->DCBlength; + + SERIAL_BAUD_RATE baudRate; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &baudRate, sizeof(SERIAL_BAUD_RATE), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the baud rate."); + goto error_handle; + } + lpLocalDcb->BaudRate = baudRate.BaudRate; + + lpLocalDcb->fBinary = (currentState.c_cflag & ICANON) == 0; + if (!lpLocalDcb->fBinary) + { + CommLog_Print(WLOG_WARN, "Unexpected nonbinary mode, consider to unset the ICANON flag."); + } + + lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0; + + SERIAL_HANDFLOW handflow; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow, sizeof(SERIAL_HANDFLOW), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the handflow settings."); + goto error_handle; + } + + lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0; + + lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0; + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE; + } + else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL) + { + lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE; + } + else + { + lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE; + } + + lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0; + + lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0; + + lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0; + + lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0; + + lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0; + + lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE; + } + else if (handflow.FlowReplace & SERIAL_RTS_CONTROL) + { + lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE; + } + else + { + lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE; + } + + // FIXME: how to get the RTS_CONTROL_TOGGLE state? Does it match the UART 16750's Autoflow Control Enabled bit in its Modem Control Register (MCR) + + + lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0; + + /* lpLocalDcb->fDummy2 not used */ + + lpLocalDcb->wReserved = 0; /* must be zero */ + + lpLocalDcb->XonLim = handflow.XonLimit; + + lpLocalDcb->XoffLim = handflow.XoffLimit; + + SERIAL_LINE_CONTROL lineControl; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl, sizeof(SERIAL_LINE_CONTROL), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the control settings."); + goto error_handle; + } + + lpLocalDcb->ByteSize = lineControl.WordLength; + + lpLocalDcb->Parity = lineControl.Parity; + + lpLocalDcb->StopBits = lineControl.StopBits; + + + SERIAL_CHARS serialChars; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommState failure: could not get the serial chars."); + goto error_handle; + } + + lpLocalDcb->XonChar = serialChars.XonChar; + + lpLocalDcb->XoffChar = serialChars.XoffChar; + + lpLocalDcb->ErrorChar = serialChars.ErrorChar; + + lpLocalDcb->EofChar = serialChars.EofChar; + + lpLocalDcb->EvtChar = serialChars.EventChar; + + + memcpy(lpDCB, lpLocalDcb, lpDCB->DCBlength); + return TRUE; + + + error_handle: + if (lpLocalDcb) + free(lpLocalDcb); + + return FALSE; +} + + +/** + * @return TRUE on success, FALSE otherwise. + * + * As of today, SetCommState() can fail half-way with some settings + * applied and some others not. SetCommState() returns on the first + * failure met. FIXME: or is it correct? + * + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_IO_DEVICE + */ +BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) +{ + struct termios upcomingTermios; + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + /* FIXME: validate changes according GetCommProperties? */ + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!lpDCB) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + /* NB: did the choice to call ioctls first when available and + then to setup upcomingTermios. Don't mix both stages. */ + + /** ioctl calls stage **/ + + SERIAL_BAUD_RATE baudRate; + baudRate.BaudRate = lpDCB->BaudRate; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, sizeof(SERIAL_BAUD_RATE), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the baud rate."); + return FALSE; + } + + SERIAL_CHARS serialChars; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) /* as of today, required for BreakChar */ + { + CommLog_Print(WLOG_WARN, "SetCommState failure: could not get the initial serial chars."); + return FALSE; + } + serialChars.XonChar = lpDCB->XonChar; + serialChars.XoffChar = lpDCB->XoffChar; + serialChars.ErrorChar = lpDCB->ErrorChar; + serialChars.EofChar = lpDCB->EofChar; + serialChars.EventChar = lpDCB->EvtChar; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the serial chars."); + return FALSE; + } + + SERIAL_LINE_CONTROL lineControl; + lineControl.StopBits = lpDCB->StopBits; + lineControl.Parity = lpDCB->Parity; + lineControl.WordLength = lpDCB->ByteSize; + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_LINE_CONTROL, &lineControl, sizeof(SERIAL_LINE_CONTROL), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the control settings."); + return FALSE; + } + + + SERIAL_HANDFLOW handflow; + ZeroMemory(&handflow, sizeof(SERIAL_HANDFLOW)); + + if (lpDCB->fOutxCtsFlow) + { + handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE; + } + + + if (lpDCB->fOutxDsrFlow) + { + handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE; + } + + switch (lpDCB->fDtrControl) + { + case SERIAL_DTR_HANDSHAKE: + handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE; + break; + + case SERIAL_DTR_CONTROL: + handflow.ControlHandShake |= DTR_CONTROL_ENABLE; + break; + + case DTR_CONTROL_DISABLE: + /* do nothing since handflow is init-zeroed */ + break; + + default: + CommLog_Print(WLOG_WARN, "Unexpected fDtrControl value: %d\n", lpDCB->fDtrControl); + return FALSE; + } + + if (lpDCB->fDsrSensitivity) + { + handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY; + } + + if (lpDCB->fTXContinueOnXoff) + { + handflow.FlowReplace |= SERIAL_XOFF_CONTINUE; + } + + if (lpDCB->fOutX) + { + handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT; + } + + if (lpDCB->fInX) + { + handflow.FlowReplace |= SERIAL_AUTO_RECEIVE; + } + + if (lpDCB->fErrorChar) + { + handflow.FlowReplace |= SERIAL_ERROR_CHAR; + } + + if (lpDCB->fNull) + { + handflow.FlowReplace |= SERIAL_NULL_STRIPPING; + } + + switch (lpDCB->fRtsControl) + { + case RTS_CONTROL_TOGGLE: + CommLog_Print(WLOG_WARN, "Unsupported RTS_CONTROL_TOGGLE feature"); + // FIXME: see also GetCommState() + return FALSE; + + case RTS_CONTROL_HANDSHAKE: + handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE; + break; + + case RTS_CONTROL_ENABLE: + handflow.FlowReplace |= SERIAL_RTS_CONTROL; + break; + + case RTS_CONTROL_DISABLE: + /* do nothing since handflow is init-zeroed */ + break; + + default: + CommLog_Print(WLOG_WARN, "Unexpected fRtsControl value: %d\n", lpDCB->fRtsControl); + return FALSE; + } + + if (lpDCB->fAbortOnError) + { + handflow.ControlHandShake |= SERIAL_ERROR_ABORT; + } + + /* lpDCB->fDummy2 not used */ + + /* lpLocalDcb->wReserved ignored */ + + handflow.XonLimit = lpDCB->XonLim; + + handflow.XoffLimit = lpDCB->XoffLim; + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow, sizeof(SERIAL_HANDFLOW), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommState failure: could not set the handflow settings."); + return FALSE; + } + + + /** upcomingTermios stage **/ + + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (lpDCB->fBinary) + { + upcomingTermios.c_lflag &= ~ICANON; + } + else + { + upcomingTermios.c_lflag |= ICANON; + CommLog_Print(WLOG_WARN, "Unexpected nonbinary mode, consider to unset the ICANON flag."); + } + + if (lpDCB->fParity) + { + upcomingTermios.c_iflag |= INPCK; + } + else + { + upcomingTermios.c_iflag &= ~INPCK; + } + + + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363423%28v=vs.85%29.aspx + * + * The SetCommState function reconfigures the communications + * resource, but it does not affect the internal output and + * input buffers of the specified driver. The buffers are not + * flushed, and pending read and write operations are not + * terminated prematurely. + * + * TCSANOW matches the best this definition + */ + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + + return TRUE; +} + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + */ +BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + /* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */ + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, lpCommTimeouts, sizeof(COMMTIMEOUTS), &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "GetCommTimeouts failure."); + return FALSE; + } + + return TRUE; +} + + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + */ +BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + /* as of today, SERIAL_TIMEOUTS and COMMTIMEOUTS structures are identical */ + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_TIMEOUTS, lpCommTimeouts, sizeof(COMMTIMEOUTS), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommTimeouts failure."); + return FALSE; + } + + return TRUE; +} + +BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize) +{ + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + return TRUE; +} + +BOOL SetCommBreak(HANDLE hFile) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL ClearCommBreak(HANDLE hFile) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + + +BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + DWORD bytesReturned = 0; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_PURGE, &dwFlags, sizeof(DWORD), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "PurgeComm failure."); + return FALSE; + } + + return TRUE; +} + + +BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + SERIAL_QUEUE_SIZE queueSize; + DWORD bytesReturned = 0; + + if (!CommInitialized()) + return FALSE; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + queueSize.InSize = dwInQueue; + queueSize.OutSize = dwOutQueue; + + if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_QUEUE_SIZE, &queueSize, sizeof(SERIAL_QUEUE_SIZE), NULL, 0, &bytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "SetCommTimeouts failure."); + return FALSE; + } + + return TRUE; +} + +BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL TransmitCommChar(HANDLE hFile, char cChar) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + +BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hFile; + + if (!CommInitialized()) + return FALSE; + + /* TODO: not implemented */ + + if (!pComm) + return FALSE; + + return TRUE; +} + + +/* Extended API */ + +static BOOL _IsReservedCommDeviceName(LPCTSTR lpName) +{ + int i; + + if (!CommInitialized()) + return FALSE; + + /* Serial ports, COM1-9 */ + for (i=1; i<10; i++) + { + TCHAR genericName[5]; + if (_stprintf_s(genericName, 5, _T("COM%d"), i) < 0) + { + return FALSE; + } + + if (_tcscmp(genericName, lpName) == 0) + return TRUE; + } + + /* Parallel ports, LPT1-9 */ + for (i=1; i<10; i++) + { + TCHAR genericName[5]; + if (_stprintf_s(genericName, 5, _T("LPT%d"), i) < 0) + { + return FALSE; + } + + if (_tcscmp(genericName, lpName) == 0) + return TRUE; + } + + /* FIXME: what about PRN ? */ + + return FALSE; +} + + +/** + * Returns TRUE on success, FALSE otherwise. To get extended error + * information, call GetLastError. + * + * ERRORS: + * ERROR_DLL_INIT_FAILED + * ERROR_OUTOFMEMORY was not possible to get mappings. + * ERROR_INVALID_DATA was not possible to add the device. + */ +BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath) +{ + int i = 0; + LPTSTR storedDeviceName = NULL; + LPTSTR storedTargetPath = NULL; + + if (!CommInitialized()) + return FALSE; + + EnterCriticalSection(&_CommDevicesLock); + + if (_CommDevices == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + goto error_handle; + } + + if (_tcsncmp(lpDeviceName, _T("\\\\.\\"), 4) != 0) + { + if (!_IsReservedCommDeviceName(lpDeviceName)) + { + SetLastError(ERROR_INVALID_DATA); + goto error_handle; + } + } + + storedDeviceName = _tcsdup(lpDeviceName); + if (storedDeviceName == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + storedTargetPath = _tcsdup(lpTargetPath); + if (storedTargetPath == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + for (i=0; iname, storedDeviceName) == 0) + { + /* take over the emplacement */ + free(_CommDevices[i]->name); + free(_CommDevices[i]->path); + _CommDevices[i]->name = storedDeviceName; + _CommDevices[i]->path = storedTargetPath; + + break; + } + } + else + { + /* new emplacement */ + _CommDevices[i] = (COMM_DEVICE*)calloc(1, sizeof(COMM_DEVICE)); + if (_CommDevices[i] == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + _CommDevices[i]->name = storedDeviceName; + _CommDevices[i]->path = storedTargetPath; + break; + } + } + + if (i == COMM_DEVICE_MAX) + { + SetLastError(ERROR_OUTOFMEMORY); + goto error_handle; + } + + LeaveCriticalSection(&_CommDevicesLock); + return TRUE; + + + error_handle: + if (storedDeviceName != NULL) + free(storedDeviceName); + + if (storedTargetPath != NULL) + free(storedTargetPath); + + LeaveCriticalSection(&_CommDevicesLock); + return FALSE; +} + + +/** + * Returns the number of target paths in the buffer pointed to by + * lpTargetPath. + * + * The current implementation returns in any case 0 and 1 target + * path. A NULL lpDeviceName is not supported yet to get all the + * paths. + * + * ERRORS: + * ERROR_SUCCESS + * ERROR_DLL_INIT_FAILED + * ERROR_OUTOFMEMORY was not possible to get mappings. + * ERROR_NOT_SUPPORTED equivalent QueryDosDevice feature not supported. + * ERROR_INVALID_DATA was not possible to retrieve any device information. + * ERROR_INSUFFICIENT_BUFFER too small lpTargetPath + */ +DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax) +{ + int i; + LPTSTR storedTargetPath; + + SetLastError(ERROR_SUCCESS); + + if (!CommInitialized()) + return 0; + + if (_CommDevices == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return 0; + } + + if (lpDeviceName == NULL || lpTargetPath == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + EnterCriticalSection(&_CommDevicesLock); + + storedTargetPath = NULL; + for (i=0; iname, lpDeviceName) == 0) + { + storedTargetPath = _CommDevices[i]->path; + break; + } + + continue; + } + + break; + } + + LeaveCriticalSection(&_CommDevicesLock); + + if (storedTargetPath == NULL) + { + SetLastError(ERROR_INVALID_DATA); + return 0; + } + + if (_tcslen(storedTargetPath) + 2 > ucchMax) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + _tcscpy(lpTargetPath, storedTargetPath); + lpTargetPath[_tcslen(storedTargetPath) + 1] = '\0'; /* 2nd final '\0' */ + + return _tcslen(lpTargetPath) + 2; +} + +/** + * Checks whether lpDeviceName is a valid and registered Communication device. + */ +BOOL IsCommDevice(LPCTSTR lpDeviceName) +{ + TCHAR lpTargetPath[MAX_PATH]; + + if (!CommInitialized()) + return FALSE; + + if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0) + { + return TRUE; + } + + return FALSE; +} + + +/** + * Sets + */ +void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID driverId) +{ + ULONG Type; + PVOID Object; + WINPR_COMM* pComm; + + if (!CommInitialized()) + return; + + if (!winpr_Handle_GetInfo(hComm, &Type, &Object)) + { + CommLog_Print(WLOG_WARN, "_comm_setServerSerialDriver failure"); + return; + } + + pComm = (WINPR_COMM*)Object; + pComm->serverSerialDriverId = driverId; +} + + +/** + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363198%28v=vs.85%29.aspx + * + * @param lpDeviceName e.g. COM1, \\.\COM1, ... + * + * @param dwDesiredAccess expects GENERIC_READ | GENERIC_WRITE, a + * warning message is printed otherwise. TODO: better support. + * + * @param dwShareMode must be zero, INVALID_HANDLE_VALUE is returned + * otherwise and GetLastError() should return ERROR_SHARING_VIOLATION. + * + * @param lpSecurityAttributes NULL expected, a warning message is printed + * otherwise. TODO: better support. + * + * @param dwCreationDisposition must be OPEN_EXISTING. If the + * communication device doesn't exist INVALID_HANDLE_VALUE is returned + * and GetLastError() returns ERROR_FILE_NOT_FOUND. + * + * @param dwFlagsAndAttributes zero expected, a warning message is + * printed otherwise. + * + * @param hTemplateFile must be NULL. + * + * @return INVALID_HANDLE_VALUE on error. + */ +HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + CHAR devicePath[MAX_PATH]; + struct stat deviceStat; + WINPR_COMM* pComm = NULL; + struct termios upcomingTermios; + + if (!CommInitialized()) + return INVALID_HANDLE_VALUE; + + if (dwDesiredAccess != (GENERIC_READ | GENERIC_WRITE)) + { + CommLog_Print(WLOG_WARN, "unexpected access to the device: 0x%lX", dwDesiredAccess); + } + + if (dwShareMode != 0) + { + SetLastError(ERROR_SHARING_VIOLATION); + return INVALID_HANDLE_VALUE; + } + + /* TODO: Prevents other processes from opening a file or + * device if they request delete, read, or write access. */ + + if (lpSecurityAttributes != NULL) + { + CommLog_Print(WLOG_WARN, "unexpected security attributes, nLength=%lu", lpSecurityAttributes->nLength); + } + + if (dwCreationDisposition != OPEN_EXISTING) + { + SetLastError(ERROR_FILE_NOT_FOUND); /* FIXME: ERROR_NOT_SUPPORTED better? */ + return INVALID_HANDLE_VALUE; + } + + if (QueryCommDevice(lpDeviceName, devicePath, MAX_PATH) <= 0) + { + /* SetLastError(GetLastError()); */ + return INVALID_HANDLE_VALUE; + } + + if (stat(devicePath, &deviceStat) < 0) + { + CommLog_Print(WLOG_WARN, "device not found %s", devicePath); + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + + if (!S_ISCHR(deviceStat.st_mode)) + { + CommLog_Print(WLOG_WARN, "bad device %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + return INVALID_HANDLE_VALUE; + } + + if (dwFlagsAndAttributes != 0) + { + CommLog_Print(WLOG_WARN, "unexpected flags and attributes: 0x%lX", dwFlagsAndAttributes); + } + + if (hTemplateFile != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); /* FIXME: other proper error? */ + return INVALID_HANDLE_VALUE; + } + + pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM)); + if (pComm == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return INVALID_HANDLE_VALUE; + } + + WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM); + + /* error_handle */ + + pComm->fd = open(devicePath, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (pComm->fd < 0) + { + CommLog_Print(WLOG_WARN, "failed to open device %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK); + if (pComm->fd_read < 0) + { + CommLog_Print(WLOG_WARN, "failed to open fd_read, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + pComm->fd_read_event = eventfd(0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */ + if (pComm->fd_read_event < 0) + { + CommLog_Print(WLOG_WARN, "failed to open fd_read_event, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + InitializeCriticalSection(&pComm->ReadLock); + + pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK); + if (pComm->fd_write < 0) + { + CommLog_Print(WLOG_WARN, "failed to open fd_write, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + pComm->fd_write_event = eventfd(0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */ + if (pComm->fd_write_event < 0) + { + CommLog_Print(WLOG_WARN, "failed to open fd_write_event, device: %s", devicePath); + SetLastError(ERROR_BAD_DEVICE); + goto error_handle; + } + + InitializeCriticalSection(&pComm->WriteLock); + + /* can also be setup later on with _comm_setServerSerialDriver() */ + pComm->serverSerialDriverId = SerialDriverUnknown; + + InitializeCriticalSection(&pComm->EventsLock); + + if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } + + + /* The binary/raw mode is required for the redirection but + * only flags that are not handle somewhere-else, except + * ICANON, are forced here. */ + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } + + upcomingTermios.c_iflag &= ~(/*IGNBRK |*/ BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL /*| IXON*/); + upcomingTermios.c_oflag = 0; /* <=> &= ~OPOST */ + upcomingTermios.c_lflag = 0; /* <=> &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); */ + /* upcomingTermios.c_cflag &= ~(CSIZE | PARENB); */ + /* upcomingTermios.c_cflag |= CS8; */ + + /* About missing flags recommended by termios(3): + * + * IGNBRK and IXON, see: IOCTL_SERIAL_SET_HANDFLOW + * CSIZE, PARENB and CS8, see: IOCTL_SERIAL_SET_LINE_CONTROL + */ + + /* a few more settings required for the redirection */ + upcomingTermios.c_cflag |= CLOCAL | CREAD; + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + goto error_handle; + } + + return (HANDLE)pComm; + + + error_handle: + if (pComm != NULL) + { + CloseHandle(pComm); + } + + + return INVALID_HANDLE_VALUE; +} + + +BOOL CommIsHandled(HANDLE handle) +{ + WINPR_COMM *pComm; + + if (!CommInitialized()) + return FALSE; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + + +BOOL CommCloseHandle(HANDLE handle) +{ + WINPR_COMM *pComm; + + if (!CommInitialized()) + return FALSE; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + { + ULONG WaitMask = 0; + DWORD BytesReturned = 0; + + /* ensures to gracefully stop the WAIT_ON_MASK's loop */ + if (!CommDeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK, &WaitMask, sizeof(ULONG), NULL, 0, &BytesReturned, NULL)) + { + CommLog_Print(WLOG_WARN, "failure to WAIT_ON_MASK's loop!"); + } + } + + DeleteCriticalSection(&pComm->ReadLock); + DeleteCriticalSection(&pComm->WriteLock); + DeleteCriticalSection(&pComm->EventsLock); + + if (pComm->fd > 0) + close(pComm->fd); + + if (pComm->fd_write > 0) + close(pComm->fd_write); + + if (pComm->fd_write_event > 0) + close(pComm->fd_write_event); + + if (pComm->fd_read > 0) + close(pComm->fd_read); + + if (pComm->fd_read_event > 0) + close(pComm->fd_read_event); + + free(pComm); + + return TRUE; +} + +#ifdef __UCLIBC__ +int eventfd_read(int fd, eventfd_t* value) +{ + return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1; +} + +int eventfd_write(int fd, eventfd_t value) +{ + return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1; +} +#endif + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h new file mode 100644 index 000000000..772e62803 --- /dev/null +++ b/winpr/libwinpr/comm/comm.h @@ -0,0 +1,107 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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_COMM_PRIVATE_H +#define WINPR_COMM_PRIVATE_H + +#if defined __linux__ && !defined ANDROID + +#include +#include + +#include + +#include "../handle/handle.h" + +struct winpr_comm +{ + WINPR_HANDLE_DEF(); + + int fd; + + int fd_read; + int fd_read_event; /* as of today, only used by _purge() */ + CRITICAL_SECTION ReadLock; + + int fd_write; + int fd_write_event; /* as of today, only used by _purge() */ + CRITICAL_SECTION WriteLock; + + /* permissive mode on errors. If TRUE (default is FALSE) + * CommDeviceIoControl always return TRUE. + * + * Not all features are supported yet and an error is then returned when + * an application turns them on (e.g: i/o buffers > 4096). It appeared + * though that devices and applications can be still functional on such + * errors. + * + * see also: comm_ioctl.c + * + * FIXME: getting rid of this flag once all features supported. + */ + BOOL permissive; + + SERIAL_DRIVER_ID serverSerialDriverId; + + COMMTIMEOUTS timeouts; + + CRITICAL_SECTION EventsLock; /* protects counters, WaitEventMask and PendingEvents */ + struct serial_icounter_struct counters; + ULONG WaitEventMask; + ULONG PendingEvents; + + /* NB: CloseHandle() has to free resources */ +}; + +typedef struct winpr_comm WINPR_COMM; + +#define SERIAL_EV_RXCHAR 0x0001 +#define SERIAL_EV_RXFLAG 0x0002 +#define SERIAL_EV_TXEMPTY 0x0004 +#define SERIAL_EV_CTS 0x0008 +#define SERIAL_EV_DSR 0x0010 +#define SERIAL_EV_RLSD 0x0020 +#define SERIAL_EV_BREAK 0x0040 +#define SERIAL_EV_ERR 0x0080 +#define SERIAL_EV_RING 0x0100 +#define SERIAL_EV_PERR 0x0200 +#define SERIAL_EV_RX80FULL 0x0400 +#define SERIAL_EV_EVENT1 0x0800 +#define SERIAL_EV_EVENT2 0x1000 +#define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit today unused by other SERIAL_EV_* */ +#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit today unused by other SERIAL_EV_* */ + +#define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ +#define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ + + +void CommLog_Print(int wlog_level, char *fmt, ...); + +BOOL CommIsHandled(HANDLE handle); +BOOL CommCloseHandle(HANDLE handle); + +#ifdef __UCLIBC__ +int eventfd_read(int fd, eventfd_t* value); +int eventfd_write(int fd, eventfd_t value); +#endif + +#endif /* __linux__ */ + +#endif /* WINPR_COMM_PRIVATE_H */ diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c new file mode 100644 index 000000000..c7033a655 --- /dev/null +++ b/winpr/libwinpr/comm/comm_io.c @@ -0,0 +1,550 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#if defined __linux__ && !defined ANDROID + +#include +#include +#include +#include + +#include +#include +#include + +#include "comm.h" + +BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + pComm->permissive = permissive; + return TRUE; +} + + +/* Computes VMIN in deciseconds from Ti in milliseconds */ +static UCHAR _vtime(ULONG Ti) +{ + /* FIXME: look for an equivalent math function otherwise let + * do the compiler do the optimization */ + if (Ti == 0) + return 0; + else if (Ti < 100) + return 1; + else if (Ti > 25500) + return 255; /* 0xFF */ + else + return Ti/100; +} + + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_NOT_SUPPORTED + * ERROR_INVALID_PARAMETER + * ERROR_TIMEOUT + * ERROR_IO_DEVICE + * ERROR_BAD_DEVICE + */ +BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + int biggestFd = -1; + fd_set read_set; + int nbFds; + COMMTIMEOUTS *pTimeouts; + UCHAR vmin = 0; + UCHAR vtime = 0; + ULONGLONG Tmax = 0; + struct timeval tmaxTimeout, *pTmaxTimeout; + struct termios currentTermios; + + EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */ + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + goto return_false; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + goto return_false; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + goto return_false; + } + + if (lpNumberOfBytesRead == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ + goto return_false; + } + + *lpNumberOfBytesRead = 0; /* will be ajusted if required ... */ + + if (nNumberOfBytesToRead <= 0) /* N */ + { + goto return_true; /* FIXME: or FALSE? */ + } + + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + + if (currentTermios.c_lflag & ICANON) + { + CommLog_Print(WLOG_WARN, "Canonical mode not supported"); /* the timeout could not be set */ + SetLastError(ERROR_NOT_SUPPORTED); + goto return_false; + } + + /* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx + * http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx + * + * ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME | TMAX | + * 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available. + * 0< Ti fd_read_event, O_NONBLOCK) doesn't conflict with above use cases */ + + pTimeouts = &(pComm->timeouts); + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant == MAXULONG)) + { + CommLog_Print(WLOG_WARN, "ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); + SetLastError(ERROR_INVALID_PARAMETER); + goto return_false; + } + + /* VMIN */ + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + { + vmin = 0; + } + else + { + /* N */ + /* vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255;*/ /* 0xFF */ + + /* NB: we might wait endlessly with vmin=N, prefer to + * force vmin=1 and return with bytes + * available. FIXME: is a feature disarded here? */ + vmin = 1; + } + + + /* VTIME */ + + if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG)) + { + /* Ti */ + vtime = _vtime(pTimeouts->ReadIntervalTimeout); + } + + + /* TMAX */ + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG)) + { + /* Tc */ + Tmax = pTimeouts->ReadTotalTimeoutConstant; + } + else + { + /* Tmax */ + Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant; + } + + if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime)) + { + currentTermios.c_cc[VMIN] = vmin; + currentTermios.c_cc[VTIME] = vtime; + + if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0) + { + CommLog_Print(WLOG_WARN, "CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + } + + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ + if (Tmax > 0) + { + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); + + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + + pTmaxTimeout = &tmaxTimeout; + } + + + /* FIXME: had expected eventfd_write() to return EAGAIN when + * there is no eventfd_read() but this not the case. */ + /* discard a possible and no more relevant event */ + eventfd_read(pComm->fd_read_event, NULL); + + biggestFd = pComm->fd_read; + if (pComm->fd_read_event > biggestFd) + biggestFd = pComm->fd_read_event; + + FD_ZERO(&read_set); + + assert(pComm->fd_read_event < FD_SETSIZE); + assert(pComm->fd_read < FD_SETSIZE); + + FD_SET(pComm->fd_read_event, &read_set); + FD_SET(pComm->fd_read, &read_set); + + nbFds = select(biggestFd+1, &read_set, NULL, NULL, pTmaxTimeout); + if (nbFds < 0) + { + CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + + if (nbFds == 0) + { + /* timeout */ + + SetLastError(ERROR_TIMEOUT); + goto return_false; + } + + + /* read_set */ + + if (FD_ISSET(pComm->fd_read_event, &read_set)) + { + eventfd_t event = 0; + + if (eventfd_read(pComm->fd_read_event, &event) < 0) + { + if (errno == EAGAIN) + { + assert(FALSE); /* not quite sure this should ever happen */ + /* keep on */ + } + else + { + CommLog_Print(WLOG_WARN, "unexpected error on reading fd_read_event, errno=[%d] %s\n", errno, strerror(errno)); + /* FIXME: goto return_false ? */ + } + + assert(errno == EAGAIN); + } + + if (event == FREERDP_PURGE_RXABORT) + { + SetLastError(ERROR_CANCELLED); + goto return_false; + } + + assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */ + } + + if (FD_ISSET(pComm->fd_read, &read_set)) + { + ssize_t nbRead = 0; + + nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead); + if (nbRead < 0) + { + CommLog_Print(WLOG_WARN, "CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u", + pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant, + currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]); + CommLog_Print(WLOG_WARN, "CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno)); + + if (errno == EAGAIN) + { + /* keep on */ + goto return_true; /* expect a read-loop to be implemented on the server side */ + } + else if (errno == EBADF) + { + SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ + goto return_false; + } + else + { + assert(FALSE); + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + } + + if (nbRead == 0) + { + /* termios timeout */ + SetLastError(ERROR_TIMEOUT); + goto return_false; + } + + *lpNumberOfBytesRead = nbRead; + goto return_true; + } + + assert(FALSE); + *lpNumberOfBytesRead = 0; + + return_false: + LeaveCriticalSection(&pComm->ReadLock); + return FALSE; + + return_true: + LeaveCriticalSection(&pComm->ReadLock); + return TRUE; +} + + +/** + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_NOT_SUPPORTED + * ERROR_INVALID_PARAMETER + * ERROR_BAD_DEVICE + */ +BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + struct timeval tmaxTimeout, *pTmaxTimeout; + + EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */ + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + goto return_false; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + goto return_false; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + goto return_false; + } + + if (lpNumberOfBytesWritten == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ + goto return_false; + } + + *lpNumberOfBytesWritten = 0; /* will be ajusted if required ... */ + + if (nNumberOfBytesToWrite <= 0) + { + goto return_true; /* FIXME: or FALSE? */ + } + + /* FIXME: had expected eventfd_write() to return EAGAIN when + * there is no eventfd_read() but this not the case. */ + /* discard a possible and no more relevant event */ + eventfd_read(pComm->fd_write_event, NULL); + + + /* ms */ + ULONGLONG Tmax = nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier + pComm->timeouts.WriteTotalTimeoutConstant; + + /* NB: select() may update the timeout argument to indicate + * how much time was left. Keep the timeout variable out of + * the while() */ + + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ + if (Tmax > 0) + { + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); + + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + + pTmaxTimeout = &tmaxTimeout; + } + + while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) + { + int biggestFd = -1; + fd_set event_set, write_set; + int nbFds; + + biggestFd = pComm->fd_write; + if (pComm->fd_write_event > biggestFd) + biggestFd = pComm->fd_write_event; + + FD_ZERO(&event_set); + FD_ZERO(&write_set); + + assert(pComm->fd_write_event < FD_SETSIZE); + assert(pComm->fd_write < FD_SETSIZE); + + FD_SET(pComm->fd_write_event, &event_set); + FD_SET(pComm->fd_write, &write_set); + + nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTmaxTimeout); + if (nbFds < 0) + { + CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + + if (nbFds == 0) + { + /* timeout */ + + SetLastError(ERROR_TIMEOUT); + goto return_false; + } + + + /* event_set */ + + if (FD_ISSET(pComm->fd_write_event, &event_set)) + { + eventfd_t event = 0; + + if (eventfd_read(pComm->fd_write_event, &event) < 0) + { + if (errno == EAGAIN) + { + assert(FALSE); /* not quite sure this should ever happen */ + /* keep on */ + } + else + { + CommLog_Print(WLOG_WARN, "unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); + /* FIXME: goto return_false ? */ + } + + assert(errno == EAGAIN); + } + + if (event == FREERDP_PURGE_TXABORT) + { + SetLastError(ERROR_CANCELLED); + goto return_false; + } + + assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */ + } + + + /* write_set */ + + if (FD_ISSET(pComm->fd_write, &write_set)) + { + ssize_t nbWritten; + + nbWritten = write(pComm->fd_write, + lpBuffer + (*lpNumberOfBytesWritten), + nNumberOfBytesToWrite - (*lpNumberOfBytesWritten)); + + if (nbWritten < 0) + { + CommLog_Print(WLOG_WARN, "CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno)); + + if (errno == EAGAIN) + { + /* keep on */ + continue; + } + else if (errno == EBADF) + { + SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ + goto return_false; + } + else + { + assert(FALSE); + SetLastError(ERROR_IO_DEVICE); + goto return_false; + } + } + + *lpNumberOfBytesWritten += nbWritten; + } + + } /* while */ + + + /* FIXME: this call to tcdrain() doesn't look correct and + * might hide a bug but was required while testing a serial + * printer. Its driver was expecting the modem line status + * SERIAL_MSR_DSR true after the sending which was never + * happenning otherwise. A purge was also done before each + * Write operation. The serial port was oppened with: + * DesiredAccess=0x0012019F. The printer worked fine with + * mstsc. */ + tcdrain(pComm->fd_write); + + + return_true: + LeaveCriticalSection(&pComm->WriteLock); + return TRUE; + + return_false: + LeaveCriticalSection(&pComm->WriteLock); + return FALSE; +} + + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c new file mode 100644 index 000000000..09c1e0e6e --- /dev/null +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -0,0 +1,739 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#if defined __linux__ && !defined ANDROID + + +#include +#include + +#include + +#include "comm.h" +#include "comm_ioctl.h" +#include "comm_serial_sys.h" +#include "comm_sercx_sys.h" +#include "comm_sercx2_sys.h" + + +/* NB: MS-RDPESP's recommendation: + * + * <2> Section 3.2.5.1.6: Windows Implementations use IOCTL constants + * for IoControlCode values. The content and values of the IOCTLs are + * opaque to the protocol. On the server side, the data contained in + * an IOCTL is simply packaged and sent to the client side. For + * maximum compatibility between the different versions of the Windows + * operating system, the client implementation only singles out + * critical IOCTLs and invokes the applicable Win32 port API. The + * other IOCTLS are passed directly to the client-side driver, and the + * processing of this value depends on the drivers installed on the + * client side. The values and parameters for these IOCTLS can be + * found in [MSFT-W2KDDK] Volume 2, Part 2—Serial and Parallel + * Drivers, and in [MSDN-PORTS]. + */ + + +const char* _comm_serial_ioctl_name(ULONG number) +{ + int i; + + for (i=0; _SERIAL_IOCTL_NAMES[i].number != 0; i++) + { + if (_SERIAL_IOCTL_NAMES[i].number == number) + { + return _SERIAL_IOCTL_NAMES[i].name; + } + } + + return "(unknown ioctl name)"; +} + + +static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + SERIAL_DRIVER* pServerSerialDriver = NULL; + + /* clear any previous last error */ + SetLastError(ERROR_SUCCESS); + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (lpOverlapped != NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + if (lpBytesReturned == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ + return FALSE; + } + + *lpBytesReturned = 0; /* will be ajusted if required ... */ + + CommLog_Print(WLOG_DEBUG, "CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode); + + /* remoteSerialDriver to be use ... + * + * FIXME: might prefer to use an automatic rather than static structure + */ + switch (pComm->serverSerialDriverId) + { + case SerialDriverSerialSys: + pServerSerialDriver = SerialSys_s(); + break; + + case SerialDriverSerCxSys: + pServerSerialDriver = SerCxSys_s(); + break; + + case SerialDriverSerCx2Sys: + pServerSerialDriver = SerCx2Sys_s(); + break; + + case SerialDriverUnknown: + default: + CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%d), using SerCx2.sys", pComm->serverSerialDriverId); + pServerSerialDriver = SerCx2Sys_s(); + break; + } + + assert(pServerSerialDriver != NULL); + + switch (dwIoControlCode) + { + case IOCTL_USBPRINT_GET_1284_ID: + { + /* FIXME: http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */ + *lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + case IOCTL_SERIAL_SET_BAUD_RATE: + { + if (pServerSerialDriver->set_baud_rate) + { + SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_BAUD_RATE)); + if (nInBufferSize < sizeof(SERIAL_BAUD_RATE)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_baud_rate(pComm, pBaudRate); + } + break; + } + case IOCTL_SERIAL_GET_BAUD_RATE: + { + if (pServerSerialDriver->get_baud_rate) + { + SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE)); + if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_BAUD_RATE); + return TRUE; + } + break; + } + case IOCTL_SERIAL_GET_PROPERTIES: + { + if (pServerSerialDriver->get_properties) + { + COMMPROP *pProperties = (COMMPROP*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(COMMPROP)); + if (nOutBufferSize < sizeof(COMMPROP)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_properties(pComm, pProperties)) + return FALSE; + + *lpBytesReturned = sizeof(COMMPROP); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_CHARS: + { + if (pServerSerialDriver->set_serial_chars) + { + SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_CHARS)); + if (nInBufferSize < sizeof(SERIAL_CHARS)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_serial_chars(pComm, pSerialChars); + } + break; + } + case IOCTL_SERIAL_GET_CHARS: + { + if (pServerSerialDriver->get_serial_chars) + { + SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_CHARS)); + if (nOutBufferSize < sizeof(SERIAL_CHARS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_CHARS); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_LINE_CONTROL: + { + if (pServerSerialDriver->set_line_control) + { + SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL)); + if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_line_control(pComm, pLineControl); + } + break; + } + case IOCTL_SERIAL_GET_LINE_CONTROL: + { + if (pServerSerialDriver->get_line_control) + { + SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL)); + if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_line_control(pComm, pLineControl)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_LINE_CONTROL); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_HANDFLOW: + { + if (pServerSerialDriver->set_handflow) + { + SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_HANDFLOW)); + if (nInBufferSize < sizeof(SERIAL_HANDFLOW)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_handflow(pComm, pHandflow); + } + break; + } + case IOCTL_SERIAL_GET_HANDFLOW: + { + if (pServerSerialDriver->get_handflow) + { + SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_HANDFLOW)); + if (nOutBufferSize < sizeof(SERIAL_HANDFLOW)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_handflow(pComm, pHandflow)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_HANDFLOW); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_TIMEOUTS: + { + if (pServerSerialDriver->set_timeouts) + { + SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_TIMEOUTS)); + if (nInBufferSize < sizeof(SERIAL_TIMEOUTS)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_timeouts(pComm, pHandflow); + } + break; + } + case IOCTL_SERIAL_GET_TIMEOUTS: + { + if (pServerSerialDriver->get_timeouts) + { + SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS)); + if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_timeouts(pComm, pHandflow)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_TIMEOUTS); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_DTR: + { + if (pServerSerialDriver->set_dtr) + { + return pServerSerialDriver->set_dtr(pComm); + } + break; + } + case IOCTL_SERIAL_CLR_DTR: + { + if (pServerSerialDriver->clear_dtr) + { + return pServerSerialDriver->clear_dtr(pComm); + } + break; + } + case IOCTL_SERIAL_SET_RTS: + { + if (pServerSerialDriver->set_rts) + { + return pServerSerialDriver->set_rts(pComm); + } + break; + } + case IOCTL_SERIAL_CLR_RTS: + { + if (pServerSerialDriver->clear_rts) + { + return pServerSerialDriver->clear_rts(pComm); + } + break; + } + case IOCTL_SERIAL_GET_MODEMSTATUS: + { + if (pServerSerialDriver->get_modemstatus) + { + ULONG *pRegister = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_modemstatus(pComm, pRegister)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_WAIT_MASK: + { + if (pServerSerialDriver->set_wait_mask) + { + ULONG *pWaitMask = (ULONG*)lpInBuffer; + + assert(nInBufferSize >= sizeof(ULONG)); + if (nInBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_wait_mask(pComm, pWaitMask); + } + break; + } + case IOCTL_SERIAL_GET_WAIT_MASK: + { + if (pServerSerialDriver->get_wait_mask) + { + ULONG *pWaitMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } + case IOCTL_SERIAL_WAIT_ON_MASK: + { + if (pServerSerialDriver->wait_on_mask) + { + ULONG *pOutputMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask)) + { + *lpBytesReturned = sizeof(ULONG); + return FALSE; + } + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_QUEUE_SIZE: + { + if (pServerSerialDriver->set_queue_size) + { + SERIAL_QUEUE_SIZE *pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer; + + assert(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE)); + if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->set_queue_size(pComm, pQueueSize); + } + break; + } + case IOCTL_SERIAL_PURGE: + { + if (pServerSerialDriver->purge) + { + ULONG *pPurgeMask = (ULONG*)lpInBuffer; + + assert(nInBufferSize >= sizeof(ULONG)); + if (nInBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->purge(pComm, pPurgeMask); + } + break; + } + case IOCTL_SERIAL_GET_COMMSTATUS: + { + if (pServerSerialDriver->get_commstatus) + { + SERIAL_STATUS *pCommstatus = (SERIAL_STATUS*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(SERIAL_STATUS)); + if (nOutBufferSize < sizeof(SERIAL_STATUS)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus)) + return FALSE; + + *lpBytesReturned = sizeof(SERIAL_STATUS); + return TRUE; + } + break; + } + case IOCTL_SERIAL_SET_BREAK_ON: + { + if (pServerSerialDriver->set_break_on) + { + return pServerSerialDriver->set_break_on(pComm); + } + break; + } + case IOCTL_SERIAL_SET_BREAK_OFF: + { + if (pServerSerialDriver->set_break_off) + { + return pServerSerialDriver->set_break_off(pComm); + } + break; + } + case IOCTL_SERIAL_SET_XOFF: + { + if (pServerSerialDriver->set_xoff) + { + return pServerSerialDriver->set_xoff(pComm); + } + break; + } + case IOCTL_SERIAL_SET_XON: + { + if (pServerSerialDriver->set_xon) + { + return pServerSerialDriver->set_xon(pComm); + } + break; + } + case IOCTL_SERIAL_GET_DTRRTS: + { + if (pServerSerialDriver->get_dtrrts) + { + ULONG *pMask = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->get_dtrrts(pComm, pMask)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + + } + case IOCTL_SERIAL_CONFIG_SIZE: + { + if (pServerSerialDriver->config_size) + { + ULONG *pSize = (ULONG*)lpOutBuffer; + + assert(nOutBufferSize >= sizeof(ULONG)); + if (nOutBufferSize < sizeof(ULONG)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + if (!pServerSerialDriver->config_size(pComm, pSize)) + return FALSE; + + *lpBytesReturned = sizeof(ULONG); + return TRUE; + } + break; + + } + case IOCTL_SERIAL_IMMEDIATE_CHAR: + { + if (pServerSerialDriver->immediate_char) + { + UCHAR *pChar = (UCHAR*)lpInBuffer; + + assert(nInBufferSize >= sizeof(UCHAR)); + if (nInBufferSize < sizeof(UCHAR)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pServerSerialDriver->immediate_char(pComm, pChar); + } + break; + } + case IOCTL_SERIAL_RESET_DEVICE: + { + if (pServerSerialDriver->reset_device) + { + return pServerSerialDriver->reset_device(pComm); + } + break; + } + } + + CommLog_Print(WLOG_WARN, _T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */ + return FALSE; + +} + + +/** + * FIXME: to be used through winpr-io's DeviceIoControl + * + * Any previous error as returned by GetLastError is cleared. + * + * ERRORS: + * ERROR_INVALID_HANDLE + * ERROR_INVALID_PARAMETER + * ERROR_NOT_SUPPORTED lpOverlapped is not supported + * ERROR_INSUFFICIENT_BUFFER + * ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl + */ +BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + WINPR_COMM* pComm = (WINPR_COMM*) hDevice; + BOOL result; + + if (hDevice == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd ) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + result = _CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + + if (lpBytesReturned && *lpBytesReturned != nOutBufferSize) + { + /* This might be a hint for a bug, especially when result==TRUE */ + CommLog_Print(WLOG_WARN, "lpBytesReturned=%ld and nOutBufferSize=%ld are different!", *lpBytesReturned, nOutBufferSize); + } + + if (pComm->permissive) + { + if (!result) + { + CommLog_Print(WLOG_WARN, "[permissive]: whereas it failed, made to succeed IoControlCode=[0x%lX] %s, last-error: 0x%lX", + dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError()); + } + + return TRUE; /* always! */ + } + + return result; +} + +int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) +{ + int result; + struct termios currentState; + + if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0) + { + CommLog_Print(WLOG_WARN, "tcsetattr failure, errno: %d", errno); + return result; + } + + /* NB: tcsetattr() can succeed even if not all changes have been applied. */ + ZeroMemory(¤tState, sizeof(struct termios)); + if ((result = tcgetattr(fd, ¤tState)) < 0) + { + CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno); + return result; + } + + if (memcmp(¤tState, &termios_p, sizeof(struct termios)) != 0) + { + CommLog_Print(WLOG_DEBUG, "all termios parameters are not set yet, doing a second attempt..."); + if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0) + { + CommLog_Print(WLOG_WARN, "2nd tcsetattr failure, errno: %d", errno); + return result; + } + + ZeroMemory(¤tState, sizeof(struct termios)); + if ((result = tcgetattr(fd, ¤tState)) < 0) + { + CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno); + return result; + } + + if (memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) + { + CommLog_Print(WLOG_WARN, "Failure: all termios parameters are still not set on a second attempt"); + return -1; + } + } + + return 0; +} + + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h new file mode 100644 index 000000000..8abdc1012 --- /dev/null +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -0,0 +1,244 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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_COMM_IOCTL_H_ +#define WINPR_COMM_IOCTL_H_ + +#if defined __linux__ && !defined ANDROID + +#include + +#include +#include +#include + +#include "comm.h" + +/* Serial I/O Request Interface: http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx + * Ntddser.h http://msdn.microsoft.com/en-us/cc308432.aspx + * Ntddpar.h http://msdn.microsoft.com/en-us/cc308431.aspx + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: defines and types below are very similar to those in comm.h, keep only + * those that differ more than the names */ + +#define STOP_BIT_1 0 +#define STOP_BITS_1_5 1 +#define STOP_BITS_2 2 + +#define NO_PARITY 0 +#define ODD_PARITY 1 +#define EVEN_PARITY 2 +#define MARK_PARITY 3 +#define SPACE_PARITY 4 + + +typedef struct _SERIAL_BAUD_RATE +{ + ULONG BaudRate; +} SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE; + + +typedef struct _SERIAL_CHARS +{ + UCHAR EofChar; + UCHAR ErrorChar; + UCHAR BreakChar; + UCHAR EventChar; + UCHAR XonChar; + UCHAR XoffChar; +} SERIAL_CHARS, *PSERIAL_CHARS; + + +typedef struct _SERIAL_LINE_CONTROL +{ + UCHAR StopBits; + UCHAR Parity; + UCHAR WordLength; +} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL; + + +typedef struct _SERIAL_HANDFLOW +{ + ULONG ControlHandShake; + ULONG FlowReplace; + LONG XonLimit; + LONG XoffLimit; +} SERIAL_HANDFLOW, *PSERIAL_HANDFLOW; + + +#define SERIAL_DTR_MASK ((ULONG)0x03) +#define SERIAL_DTR_CONTROL ((ULONG)0x01) +#define SERIAL_DTR_HANDSHAKE ((ULONG)0x02) +#define SERIAL_CTS_HANDSHAKE ((ULONG)0x08) +#define SERIAL_DSR_HANDSHAKE ((ULONG)0x10) +#define SERIAL_DCD_HANDSHAKE ((ULONG)0x20) +#define SERIAL_OUT_HANDSHAKEMASK ((ULONG)0x38) +#define SERIAL_DSR_SENSITIVITY ((ULONG)0x40) +#define SERIAL_ERROR_ABORT ((ULONG)0x80000000) +#define SERIAL_CONTROL_INVALID ((ULONG)0x7fffff84) +#define SERIAL_AUTO_TRANSMIT ((ULONG)0x01) +#define SERIAL_AUTO_RECEIVE ((ULONG)0x02) +#define SERIAL_ERROR_CHAR ((ULONG)0x04) +#define SERIAL_NULL_STRIPPING ((ULONG)0x08) +#define SERIAL_BREAK_CHAR ((ULONG)0x10) +#define SERIAL_RTS_MASK ((ULONG)0xc0) +#define SERIAL_RTS_CONTROL ((ULONG)0x40) +#define SERIAL_RTS_HANDSHAKE ((ULONG)0x80) +#define SERIAL_TRANSMIT_TOGGLE ((ULONG)0xc0) +#define SERIAL_XOFF_CONTINUE ((ULONG)0x80000000) +#define SERIAL_FLOW_INVALID ((ULONG)0x7fffff20) + +#define SERIAL_SP_SERIALCOMM ((ULONG)0x00000001) + +#define SERIAL_SP_UNSPECIFIED ((ULONG)0x00000000) +#define SERIAL_SP_RS232 ((ULONG)0x00000001) +#define SERIAL_SP_PARALLEL ((ULONG)0x00000002) +#define SERIAL_SP_RS422 ((ULONG)0x00000003) +#define SERIAL_SP_RS423 ((ULONG)0x00000004) +#define SERIAL_SP_RS449 ((ULONG)0x00000005) +#define SERIAL_SP_MODEM ((ULONG)0X00000006) +#define SERIAL_SP_FAX ((ULONG)0x00000021) +#define SERIAL_SP_SCANNER ((ULONG)0x00000022) +#define SERIAL_SP_BRIDGE ((ULONG)0x00000100) +#define SERIAL_SP_LAT ((ULONG)0x00000101) +#define SERIAL_SP_TELNET ((ULONG)0x00000102) +#define SERIAL_SP_X25 ((ULONG)0x00000103) + + +typedef struct _SERIAL_TIMEOUTS +{ + ULONG ReadIntervalTimeout; + ULONG ReadTotalTimeoutMultiplier; + ULONG ReadTotalTimeoutConstant; + ULONG WriteTotalTimeoutMultiplier; + ULONG WriteTotalTimeoutConstant; +} SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS; + + +#define SERIAL_MSR_DCTS 0x01 +#define SERIAL_MSR_DDSR 0x02 +#define SERIAL_MSR_TERI 0x04 +#define SERIAL_MSR_DDCD 0x08 +#define SERIAL_MSR_CTS 0x10 +#define SERIAL_MSR_DSR 0x20 +#define SERIAL_MSR_RI 0x40 +#define SERIAL_MSR_DCD 0x80 + +typedef struct _SERIAL_QUEUE_SIZE +{ + ULONG InSize; + ULONG OutSize; +} SERIAL_QUEUE_SIZE, *PSERIAL_QUEUE_SIZE; + + +#define SERIAL_PURGE_TXABORT 0x00000001 +#define SERIAL_PURGE_RXABORT 0x00000002 +#define SERIAL_PURGE_TXCLEAR 0x00000004 +#define SERIAL_PURGE_RXCLEAR 0x00000008 + +typedef struct _SERIAL_STATUS +{ + ULONG Errors; + ULONG HoldReasons; + ULONG AmountInInQueue; + ULONG AmountInOutQueue; + BOOLEAN EofReceived; + BOOLEAN WaitForImmediate; +} SERIAL_STATUS, *PSERIAL_STATUS; + +#define SERIAL_TX_WAITING_FOR_CTS ((ULONG)0x00000001) +#define SERIAL_TX_WAITING_FOR_DSR ((ULONG)0x00000002) +#define SERIAL_TX_WAITING_FOR_DCD ((ULONG)0x00000004) +#define SERIAL_TX_WAITING_FOR_XON ((ULONG)0x00000008) +#define SERIAL_TX_WAITING_XOFF_SENT ((ULONG)0x00000010) +#define SERIAL_TX_WAITING_ON_BREAK ((ULONG)0x00000020) +#define SERIAL_RX_WAITING_FOR_DSR ((ULONG)0x00000040) + +#define SERIAL_ERROR_BREAK ((ULONG)0x00000001) +#define SERIAL_ERROR_FRAMING ((ULONG)0x00000002) +#define SERIAL_ERROR_OVERRUN ((ULONG)0x00000004) +#define SERIAL_ERROR_QUEUEOVERRUN ((ULONG)0x00000008) +#define SERIAL_ERROR_PARITY ((ULONG)0x00000010) + +#define SERIAL_DTR_STATE ((ULONG)0x00000001) +#define SERIAL_RTS_STATE ((ULONG)0x00000002) +#define SERIAL_CTS_STATE ((ULONG)0x00000010) +#define SERIAL_DSR_STATE ((ULONG)0x00000020) +#define SERIAL_RI_STATE ((ULONG)0x00000040) +#define SERIAL_DCD_STATE ((ULONG)0x00000080) + +/** + * A function might be NULL if not supported by the underlying driver. + * + * FIXME: better have to use input and output buffers for all functions? + */ +typedef struct _SERIAL_DRIVER +{ + SERIAL_DRIVER_ID id; + TCHAR *name; + BOOL (*set_baud_rate)(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate); + BOOL (*get_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate); + BOOL (*get_properties)(WINPR_COMM *pComm, COMMPROP *pProperties); + BOOL (*set_serial_chars)(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars); + BOOL (*get_serial_chars)(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars); + BOOL (*set_line_control)(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLineControl); + BOOL (*get_line_control)(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineControl); + BOOL (*set_handflow)(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow); + BOOL (*get_handflow)(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow); + BOOL (*set_timeouts)(WINPR_COMM *pComm, const SERIAL_TIMEOUTS *pTimeouts); + BOOL (*get_timeouts)(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts); + BOOL (*set_dtr)(WINPR_COMM *pComm); + BOOL (*clear_dtr)(WINPR_COMM *pComm); + BOOL (*set_rts)(WINPR_COMM *pComm); + BOOL (*clear_rts)(WINPR_COMM *pComm); + BOOL (*get_modemstatus)(WINPR_COMM *pComm, ULONG *pRegister); + BOOL (*set_wait_mask)(WINPR_COMM *pComm, const ULONG *pWaitMask); + BOOL (*get_wait_mask)(WINPR_COMM *pComm, ULONG *pWaitMask); + BOOL (*wait_on_mask)(WINPR_COMM *pComm, ULONG *pOutputMask); + BOOL (*set_queue_size)(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize); + BOOL (*purge)(WINPR_COMM *pComm, const ULONG *pPurgeMask); + BOOL (*get_commstatus)(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus); + BOOL (*set_break_on)(WINPR_COMM *pComm); + BOOL (*set_break_off)(WINPR_COMM *pComm); + BOOL (*set_xoff)(WINPR_COMM *pComm); + BOOL (*set_xon)(WINPR_COMM *pComm); + BOOL (*get_dtrrts)(WINPR_COMM *pComm, ULONG *pMask); + BOOL (*config_size)(WINPR_COMM *pComm, ULONG *pSize); + BOOL (*immediate_char)(WINPR_COMM *pComm, const UCHAR *pChar); + BOOL (*reset_device)(WINPR_COMM *pComm); + +} SERIAL_DRIVER; + + +int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); + +#ifdef __cplusplus +} +#endif + +#endif /* __linux__ */ + +#endif /* WINPR_COMM_IOCTL_H_ */ diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c new file mode 100644 index 000000000..8bdffbe97 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -0,0 +1,207 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +#if defined __linux__ && !defined ANDROID + +#include + +#include "comm_serial_sys.h" +#include "comm_sercx_sys.h" + +#include "comm_sercx2_sys.h" + + +/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx + * + * SerCx2 does not support special characters. SerCx2 always completes + * an IOCTL_SERIAL_SET_CHARS request with a STATUS_SUCCESS status + * code, but does not set any special characters or perform any other + * operation in response to this request. For an + * IOCTL_SERIAL_GET_CHARS request, SerCx2 sets all the character + * values in the SERIAL_CHARS structure to null, and completes the + * request with a STATUS_SUCCESS status code. + */ + +static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars) +{ + return TRUE; +} + + +static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars) +{ + ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); + return TRUE; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ +/* FIXME: only using the Serial.sys' events, complete the support of the remaining events */ +static const ULONG _SERCX2_SYS_SUPPORTED_EV_MASK = + SERIAL_EV_RXCHAR | + SERIAL_EV_RXFLAG | + SERIAL_EV_TXEMPTY | + SERIAL_EV_CTS | + SERIAL_EV_DSR | + SERIAL_EV_RLSD | + SERIAL_EV_BREAK | + SERIAL_EV_ERR | + SERIAL_EV_RING | + /* SERIAL_EV_PERR | */ + SERIAL_EV_RX80FULL /*| + SERIAL_EV_EVENT1 | + SERIAL_EV_EVENT2*/; + +/* use Serial.sys for basis (not SerCx.sys) */ +static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) +{ + ULONG possibleMask; + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + CommLog_Print(WLOG_WARN, "Not all wait events supported (SerCx2.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->WaitEventMask = possibleMask; + return FALSE; + } + + /* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/ + return pSerialSys->set_wait_mask(pComm, pWaitMask); +} + + +static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) +{ + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */ + + if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT)) + { + CommLog_Print(WLOG_WARN, "Expecting SERIAL_PURGE_RXABORT since SERIAL_PURGE_RXCLEAR is set"); + SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER); + return FALSE; + } + + + if ((*pPurgeMask & SERIAL_PURGE_TXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_TXABORT)) + { + CommLog_Print(WLOG_WARN, "Expecting SERIAL_PURGE_TXABORT since SERIAL_PURGE_TXCLEAR is set"); + SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER); + return FALSE; + } + + + return pSerialSys->purge(pComm, pPurgeMask); +} + + +/* specific functions only */ +static SERIAL_DRIVER _SerCx2Sys = +{ + .id = SerialDriverSerCx2Sys, + .name = _T("SerCx2.sys"), + .set_baud_rate = NULL, + .get_baud_rate = NULL, + .get_properties = NULL, + .set_serial_chars = _set_serial_chars, + .get_serial_chars = _get_serial_chars, + .set_line_control = NULL, + .get_line_control = NULL, + .set_handflow = NULL, + .get_handflow = NULL, + .set_timeouts = NULL, + .get_timeouts = NULL, + .set_dtr = NULL, + .clear_dtr = NULL, + .set_rts = NULL, + .clear_rts = NULL, + .get_modemstatus = NULL, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = NULL, + .wait_on_mask = NULL, + .set_queue_size = NULL, + .purge = _purge, + .get_commstatus = NULL, + .set_break_on = NULL, + .set_break_off = NULL, + .set_xoff = NULL, /* not supported by SerCx2.sys */ + .set_xon = NULL, /* not supported by SerCx2.sys */ + .get_dtrrts = NULL, + .config_size = NULL, /* not supported by SerCx2.sys */ + .immediate_char = NULL, /* not supported by SerCx2.sys */ + .reset_device = NULL, /* not supported by SerCx2.sys */ +}; + + +SERIAL_DRIVER* SerCx2Sys_s() +{ + /* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */ + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + SERIAL_DRIVER* pSerCxSys = SerCxSys_s(); + + _SerCx2Sys.set_baud_rate = pSerialSys->set_baud_rate; + _SerCx2Sys.get_baud_rate = pSerialSys->get_baud_rate; + + _SerCx2Sys.get_properties = pSerialSys->get_properties; + + _SerCx2Sys.set_line_control = pSerCxSys->set_line_control; + _SerCx2Sys.get_line_control = pSerCxSys->get_line_control; + + /* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really required by SerCx2.sys + * http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx + */ + _SerCx2Sys.set_handflow = pSerialSys->set_handflow; + _SerCx2Sys.get_handflow = pSerialSys->get_handflow; + + _SerCx2Sys.set_timeouts = pSerialSys->set_timeouts; + _SerCx2Sys.get_timeouts = pSerialSys->get_timeouts; + + _SerCx2Sys.set_dtr = pSerialSys->set_dtr; + _SerCx2Sys.clear_dtr = pSerialSys->clear_dtr; + + _SerCx2Sys.set_rts = pSerialSys->set_rts; + _SerCx2Sys.clear_rts = pSerialSys->clear_rts; + + _SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus; + + _SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask; + _SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask; + _SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask; + + _SerCx2Sys.set_queue_size = pSerialSys->set_queue_size; + + _SerCx2Sys.get_commstatus = pSerialSys->get_commstatus; + + _SerCx2Sys.set_break_on = pSerialSys->set_break_on; + _SerCx2Sys.set_break_off = pSerialSys->set_break_off; + + _SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts; + + return &_SerCx2Sys; +} + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.h b/winpr/libwinpr/comm/comm_sercx2_sys.h new file mode 100644 index 000000000..49e9da672 --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx2_sys.h @@ -0,0 +1,39 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 COMM_SERCX2_SYS_H +#define COMM_SERCX2_SYS_H + +#if defined __linux__ && !defined ANDROID + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SERIAL_DRIVER* SerCx2Sys_s(); + +#ifdef __cplusplus +} +#endif + +#endif /* __linux__ */ + +#endif /* COMM_SERCX2_SYS_H */ diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c new file mode 100644 index 000000000..7d392d31e --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -0,0 +1,259 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +#if defined __linux__ && !defined ANDROID + +#include +#include + +#include + +#include "comm_serial_sys.h" + + +static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) +{ + SERIAL_HANDFLOW SerCxHandflow; + BOOL result = TRUE; + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW)); + + /* filter out unsupported bits by SerCx.sys + * + * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx + */ + + SerCxHandflow.ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE); + SerCxHandflow.FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE); + + if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake) + { + if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) + { + CommLog_Print(WLOG_WARN, "SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + { + CommLog_Print(WLOG_WARN, "SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) + { + CommLog_Print(WLOG_WARN, "SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys"); + } + + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; + } + + if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace) + { + if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT) + { + CommLog_Print(WLOG_WARN, "SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE) + { + CommLog_Print(WLOG_WARN, "SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR) + { + CommLog_Print(WLOG_WARN, "SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING) + { + CommLog_Print(WLOG_WARN, "SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR) + { + CommLog_Print(WLOG_WARN, "SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys"); + } + + if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE) + { + CommLog_Print(WLOG_WARN, "SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys"); + } + + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + result = FALSE; + } + + if (!pSerialSys->set_handflow(pComm, &SerCxHandflow)) + return FALSE; + + return result; +} + + +static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) +{ + BOOL result; + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + result = pSerialSys->get_handflow(pComm, pHandflow); + + /* filter out unsupported bits by SerCx.sys + * + * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx + */ + + pHandflow->ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE); + pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE); + + return result; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ +static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK = + SERIAL_EV_RXCHAR | + /* SERIAL_EV_RXFLAG | */ + SERIAL_EV_TXEMPTY | + SERIAL_EV_CTS | + SERIAL_EV_DSR | + SERIAL_EV_RLSD | + SERIAL_EV_BREAK | + SERIAL_EV_ERR | + SERIAL_EV_RING /* | + SERIAL_EV_PERR | + SERIAL_EV_RX80FULL | + SERIAL_EV_EVENT1 | + SERIAL_EV_EVENT2*/; + + +static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) +{ + ULONG possibleMask; + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + CommLog_Print(WLOG_WARN, "Not all wait events supported (SerCx.sys), requested events= 0x%lX, possible events= 0x%lX", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->WaitEventMask = possibleMask; + return FALSE; + } + + /* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/ + return pSerialSys->set_wait_mask(pComm, pWaitMask); +} + + +/* specific functions only */ +static SERIAL_DRIVER _SerCxSys = +{ + .id = SerialDriverSerCxSys, + .name = _T("SerCx.sys"), + .set_baud_rate = NULL, + .get_baud_rate = NULL, + .get_properties = NULL, + .set_serial_chars = NULL, + .get_serial_chars = NULL, + .set_line_control = NULL, + .get_line_control = NULL, + .set_handflow = _set_handflow, + .get_handflow = _get_handflow, + .set_timeouts = NULL, + .get_timeouts = NULL, + .set_dtr = NULL, + .clear_dtr = NULL, + .set_rts = NULL, + .clear_rts = NULL, + .get_modemstatus = NULL, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = NULL, + .wait_on_mask = NULL, + .set_queue_size = NULL, + .purge = NULL, + .get_commstatus = NULL, + .set_break_on = NULL, + .set_break_off = NULL, + .set_xoff = NULL, + .set_xon = NULL, + .get_dtrrts = NULL, + .config_size = NULL, /* not supported by SerCx.sys */ + .immediate_char = NULL, + .reset_device = NULL, /* not supported by SerCx.sys */ +}; + + + +SERIAL_DRIVER* SerCxSys_s() +{ + /* _SerCxSys completed with inherited functions from SerialSys */ + SERIAL_DRIVER* pSerialSys = SerialSys_s(); + + _SerCxSys.set_baud_rate = pSerialSys->set_baud_rate; + _SerCxSys.get_baud_rate = pSerialSys->get_baud_rate; + + _SerCxSys.get_properties = pSerialSys->get_properties; + + _SerCxSys.set_serial_chars = pSerialSys->set_serial_chars; + _SerCxSys.get_serial_chars = pSerialSys->get_serial_chars; + _SerCxSys.set_line_control = pSerialSys->set_line_control; + _SerCxSys.get_line_control = pSerialSys->get_line_control; + + _SerCxSys.set_timeouts = pSerialSys->set_timeouts; + _SerCxSys.get_timeouts = pSerialSys->get_timeouts; + + _SerCxSys.set_dtr = pSerialSys->set_dtr; + _SerCxSys.clear_dtr = pSerialSys->clear_dtr; + + _SerCxSys.set_rts = pSerialSys->set_rts; + _SerCxSys.clear_rts = pSerialSys->clear_rts; + + _SerCxSys.get_modemstatus = pSerialSys->get_modemstatus; + + _SerCxSys.set_wait_mask = pSerialSys->set_wait_mask; + _SerCxSys.get_wait_mask = pSerialSys->get_wait_mask; + _SerCxSys.wait_on_mask = pSerialSys->wait_on_mask; + + _SerCxSys.set_queue_size = pSerialSys->set_queue_size; + + _SerCxSys.purge = pSerialSys->purge; + + _SerCxSys.get_commstatus = pSerialSys->get_commstatus; + + _SerCxSys.set_break_on = pSerialSys->set_break_on; + _SerCxSys.set_break_off = pSerialSys->set_break_off; + + + _SerCxSys.set_xoff = pSerialSys->set_xoff; + _SerCxSys.set_xon = pSerialSys->set_xon; + + _SerCxSys.get_dtrrts = pSerialSys->get_dtrrts; + + _SerCxSys.immediate_char = pSerialSys->immediate_char; + + return &_SerCxSys; +} + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm_sercx_sys.h b/winpr/libwinpr/comm/comm_sercx_sys.h new file mode 100644 index 000000000..2a235743f --- /dev/null +++ b/winpr/libwinpr/comm/comm_sercx_sys.h @@ -0,0 +1,41 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 COMM_SERCX_SYS_H +#define COMM_SERCX_SYS_H + +#if defined __linux__ && !defined ANDROID + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SERIAL_DRIVER* SerCxSys_s(); + +#ifdef __cplusplus +} +#endif + + +#endif /* __linux__ */ + + +#endif /* COMM_SERCX_SYS_H */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c new file mode 100644 index 000000000..223bf5c03 --- /dev/null +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -0,0 +1,1593 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2011 O.S. Systems Software Ltda. + * Copyright 2011 Eduardo Fiss Beloni + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +#if defined __linux__ && !defined ANDROID + +#include +#include +#include +#include +#include +#include + +#include "comm_serial_sys.h" +#ifdef __UCLIBC__ +#include "comm.h" +#endif + +#include +#include + +/* hard-coded in N_TTY */ +#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ +#define TTY_THRESHOLD_UNTHROTTLE 128 +#define N_TTY_BUF_SIZE 4096 + + +#define _BAUD_TABLE_END 0010020 /* __MAX_BAUD + 1 */ + +/* 0: B* (Linux termios) + * 1: CBR_* or actual baud rate + * 2: BAUD_* (identical to SERIAL_BAUD_*) + */ +static const speed_t _BAUD_TABLE[][3] = { +#ifdef B0 + {B0, 0, 0}, /* hang up */ +#endif +#ifdef B50 + {B50, 50, 0}, +#endif +#ifdef B75 + {B75, 75, BAUD_075}, +#endif +#ifdef B110 + {B110, CBR_110, BAUD_110}, +#endif +#ifdef B134 + {B134, 134, 0 /*BAUD_134_5*/}, +#endif +#ifdef B150 + {B150, 150, BAUD_150}, +#endif +#ifdef B200 + {B200, 200, 0}, +#endif +#ifdef B300 + {B300, CBR_300, BAUD_300}, +#endif +#ifdef B600 + {B600, CBR_600, BAUD_600}, +#endif +#ifdef B1200 + {B1200, CBR_1200, BAUD_1200}, +#endif +#ifdef B1800 + {B1800, 1800, BAUD_1800}, +#endif +#ifdef B2400 + {B2400, CBR_2400, BAUD_2400}, +#endif +#ifdef B4800 + {B4800, CBR_4800, BAUD_4800}, +#endif + /* {, ,BAUD_7200} */ +#ifdef B9600 + {B9600, CBR_9600, BAUD_9600}, +#endif + /* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */ +#ifdef B19200 + {B19200, CBR_19200, BAUD_19200}, +#endif +#ifdef B38400 + {B38400, CBR_38400, BAUD_38400}, +#endif + /* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */ +#ifdef B57600 + {B57600, CBR_57600, BAUD_57600}, +#endif +#ifdef B115200 + {B115200, CBR_115200, BAUD_115200}, +#endif + /* {, CBR_128000, BAUD_128K}, /\* unsupported on Linux *\/ */ + /* {, CBR_256000, BAUD_USER}, /\* unsupported on Linux *\/ */ +#ifdef B230400 + {B230400, 230400, BAUD_USER}, +#endif +#ifdef B460800 + {B460800, 460800, BAUD_USER}, +#endif +#ifdef B500000 + {B500000, 500000, BAUD_USER}, +#endif +#ifdef B576000 + {B576000, 576000, BAUD_USER}, +#endif +#ifdef B921600 + {B921600, 921600, BAUD_USER}, +#endif +#ifdef B1000000 + {B1000000, 1000000, BAUD_USER}, +#endif +#ifdef B1152000 + {B1152000, 1152000, BAUD_USER}, +#endif +#ifdef B1500000 + {B1500000, 1500000, BAUD_USER}, +#endif +#ifdef B2000000 + {B2000000, 2000000, BAUD_USER}, +#endif +#ifdef B2500000 + {B2500000, 2500000, BAUD_USER}, +#endif +#ifdef B3000000 + {B3000000, 3000000, BAUD_USER}, +#endif +#ifdef B3500000 + {B3500000, 3500000, BAUD_USER}, +#endif +#ifdef B4000000 + {B4000000, 4000000, BAUD_USER}, /* __MAX_BAUD */ +#endif + {_BAUD_TABLE_END, 0, 0} +}; + + +static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties) +{ + int i; + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680684%28v=vs.85%29.aspx + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363189%28v=vs.85%29.aspx + */ + + /* FIXME: properties should be better probed. The current + * implementation just relies on the Linux' implementation. + */ + + if (pProperties->dwProvSpec1 != COMMPROP_INITIALIZED) + { + ZeroMemory(pProperties, sizeof(COMMPROP)); + pProperties->wPacketLength = sizeof(COMMPROP); + } + + pProperties->wPacketVersion = 2; + + pProperties->dwServiceMask = SERIAL_SP_SERIALCOMM; + + /* pProperties->Reserved1; not used */ + + /* FIXME: could be implemented on top of N_TTY */ + pProperties->dwMaxTxQueue = N_TTY_BUF_SIZE; + pProperties->dwMaxRxQueue = N_TTY_BUF_SIZE; + + /* FIXME: to be probe on the device? */ + pProperties->dwMaxBaud = BAUD_USER; + + /* FIXME: what about PST_RS232? see also: serial_struct */ + pProperties->dwProvSubType = PST_UNSPECIFIED; + + /* TODO: to be finalized */ + pProperties->dwProvCapabilities = + /*PCF_16BITMODE |*/ PCF_DTRDSR | PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD |*/ + PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS |*/ PCF_TOTALTIMEOUTS | PCF_XONXOFF; + + /* TODO: double check SP_RLSD */ + pProperties->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY | SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS; + + pProperties->dwSettableBaud = 0; + for (i=0; _BAUD_TABLE[i][0]<_BAUD_TABLE_END; i++) + { + pProperties->dwSettableBaud |= _BAUD_TABLE[i][2]; + } + + pProperties->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 /*| DATABITS_16 | DATABITS_16X*/; + + pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE; + + /* FIXME: additional input and output buffers could be implemented on top of N_TTY */ + pProperties->dwCurrentTxQueue = N_TTY_BUF_SIZE; + pProperties->dwCurrentRxQueue = N_TTY_BUF_SIZE; + + /* pProperties->ProvSpec1; see above */ + /* pProperties->ProvSpec2; ignored */ + /* pProperties->ProvChar[1]; ignored */ + + return TRUE; +} + +static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t newSpeed; + struct termios futureState; + + ZeroMemory(&futureState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */ + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + for (i=0; _BAUD_TABLE[i][0]<_BAUD_TABLE_END; i++) + { + if (_BAUD_TABLE[i][1] == pBaudRate->BaudRate) + { + newSpeed = _BAUD_TABLE[i][0]; + if (cfsetspeed(&futureState, newSpeed) < 0) + { + CommLog_Print(WLOG_WARN, "failed to set speed 0x%x (%lu)", newSpeed, pBaudRate->BaudRate); + return FALSE; + } + + assert(cfgetispeed(&futureState) == newSpeed); + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0) + { + CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); + return FALSE; + } + + return TRUE; + } + } + + CommLog_Print(WLOG_WARN, "could not find a matching speed for the baud rate %lu", pBaudRate->BaudRate); + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + + +static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate) +{ + int i; + speed_t currentSpeed; + struct termios currentState; + + ZeroMemory(¤tState, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tState) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + currentSpeed = cfgetispeed(¤tState); + + for (i=0; _BAUD_TABLE[i][0]<_BAUD_TABLE_END; i++) + { + if (_BAUD_TABLE[i][0] == currentSpeed) + { + pBaudRate->BaudRate = _BAUD_TABLE[i][1]; + return TRUE; + } + } + + CommLog_Print(WLOG_WARN, "could not find a matching baud rate for the speed 0x%x", currentSpeed); + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + + +/** + * NOTE: Only XonChar and XoffChar are plenty supported with the Linux + * N_TTY line discipline. + * + * ERRORS: + * ERROR_IO_DEVICE + * ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same; + * ERROR_NOT_SUPPORTED + */ +static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + if (pSerialChars->XonChar == pSerialChars->XoffChar) + { + /* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546688%28v=vs.85%29.aspx */ + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* termios(3): (..) above symbolic subscript values are all + * different, except that VTIME, VMIN may have the same value + * as VEOL, VEOF, respectively. In noncanonical mode the + * special character meaning is replaced by the timeout + * meaning. + * + * EofChar and c_cc[VEOF] are not quite the same, prefer to + * don't use c_cc[VEOF] at all. + * + * FIXME: might be implemented during read/write I/O + */ + if (pSerialChars->EofChar != '\0') + { + CommLog_Print(WLOG_WARN, "EofChar='%c' cannot be set\n", pSerialChars->EofChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* According the Linux's n_tty discipline, charaters with a + * parity error can only be let unchanged, replaced by \0 or + * get the prefix the prefix \377 \0 + */ + + /* FIXME: see also: _set_handflow() */ + if (pSerialChars->ErrorChar != '\0') + { + CommLog_Print(WLOG_WARN, "ErrorChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->ErrorChar, pSerialChars->ErrorChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* FIXME: see also: _set_handflow() */ + if (pSerialChars->BreakChar != '\0') + { + CommLog_Print(WLOG_WARN, "BreakChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->BreakChar, pSerialChars->BreakChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* FIXME: could be implemented during read/write I/O. What about ISIG? */ + if (pSerialChars->EventChar != '\0') + { + CommLog_Print(WLOG_WARN, "EventChar='%c' (0x%x) cannot be set\n", pSerialChars->EventChar, pSerialChars->EventChar); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar; + + upcomingTermios.c_cc[VSTOP] = pSerialChars->XoffChar; + + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); + return FALSE; + } + + return result; +} + + +static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS)); + + /* EofChar unsupported */ + + /* ErrorChar unsupported */ + + /* BreakChar unsupported */ + + /* FIXME: see also: _set_serial_chars() */ + /* EventChar */ + + pSerialChars->XonChar = currentTermios.c_cc[VSTART]; + + pSerialChars->XoffChar = currentTermios.c_cc[VSTOP]; + + return TRUE; +} + + +static BOOL _set_line_control(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLineControl) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx + * + * The use of 5 data bits with 2 stop bits is an invalid + * combination, as is 6, 7, or 8 data bits with 1.5 stop bits. + * + * FIXME: prefered to let the underlying driver to deal with + * this issue. At least produce a warning message? + */ + + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* FIXME: use of a COMMPROP to validate new settings? */ + + switch (pLineControl->StopBits) + { + case STOP_BIT_1: + upcomingTermios.c_cflag &= ~CSTOPB; + break; + + case STOP_BITS_1_5: + CommLog_Print(WLOG_WARN, "Unsupported one and a half stop bits."); + break; + + case STOP_BITS_2: + upcomingTermios.c_cflag |= CSTOPB; + break; + + default: + CommLog_Print(WLOG_WARN, "unexpected number of stop bits: %d\n", pLineControl->StopBits); + result = FALSE; /* but keep on */ + break; + } + + + switch (pLineControl->Parity) + { + case NO_PARITY: + upcomingTermios.c_cflag &= ~(PARENB | PARODD | CMSPAR); + break; + + case ODD_PARITY: + upcomingTermios.c_cflag &= ~CMSPAR; + upcomingTermios.c_cflag |= PARENB | PARODD; + break; + + case EVEN_PARITY: + upcomingTermios.c_cflag &= ~(PARODD | CMSPAR); + upcomingTermios.c_cflag |= PARENB; + break; + + case MARK_PARITY: + upcomingTermios.c_cflag |= PARENB | PARODD | CMSPAR; + break; + + case SPACE_PARITY: + upcomingTermios.c_cflag &= ~PARODD; + upcomingTermios.c_cflag |= PARENB | CMSPAR; + break; + + default: + CommLog_Print(WLOG_WARN, "unexpected type of parity: %d\n", pLineControl->Parity); + result = FALSE; /* but keep on */ + break; + } + + switch (pLineControl->WordLength) + { + case 5: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS5; + break; + + case 6: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS6; + break; + + case 7: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS7; + break; + + case 8: + upcomingTermios.c_cflag &= ~CSIZE; + upcomingTermios.c_cflag |= CS8; + break; + + default: + CommLog_Print(WLOG_WARN, "unexpected number od data bits per character: %d\n", pLineControl->WordLength); + result = FALSE; /* but keep on */ + break; + } + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); + return FALSE; + } + + return result; +} + + +static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineControl) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + pLineControl->StopBits = (currentTermios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BIT_1; + + if (!(currentTermios.c_cflag & PARENB)) + { + pLineControl->Parity = NO_PARITY; + } + else if (currentTermios.c_cflag & CMSPAR) + { + pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? MARK_PARITY : SPACE_PARITY; + } + else + { + /* PARENB is set */ + pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY; + } + + switch (currentTermios.c_cflag & CSIZE) + { + case CS5: + pLineControl->WordLength = 5; + break; + case CS6: + pLineControl->WordLength = 6; + break; + case CS7: + pLineControl->WordLength = 7; + break; + default: + pLineControl->WordLength = 8; + break; + } + + return TRUE; +} + + +static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow) +{ + BOOL result = TRUE; + struct termios upcomingTermios; + + ZeroMemory(&upcomingTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, &upcomingTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + /* HUPCL */ + + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) || + ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL))) + { + CommLog_Print(WLOG_WARN, "SERIAL_DTR_CONTROL:%s and SERIAL_RTS_CONTROL:%s cannot be different, HUPCL will be set since it is claimed for one of the both lines.", + (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) ? "ON" : "OFF"); + } + + if ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) || (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) + { + upcomingTermios.c_cflag |= HUPCL; + } + else + { + upcomingTermios.c_cflag &= ~HUPCL; + + /* FIXME: is the DTR line also needs to be forced to a disable state according SERIAL_DTR_CONTROL? */ + /* FIXME: is the RTS line also needs to be forced to a disable state according SERIAL_RTS_CONTROL? */ + } + + + /* CRTSCTS */ + + /* logical XOR */ + if ((!(pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) || + ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) && !(pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE))) + { + CommLog_Print(WLOG_WARN, "SERIAL_CTS_HANDSHAKE:%s and SERIAL_RTS_HANDSHAKE:%s cannot be different, CRTSCTS will be set since it is claimed for one of the both lines.", + (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ? "ON" : "OFF", + (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) ? "ON" : "OFF"); + } + + if ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) || (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) + { + upcomingTermios.c_cflag |= CRTSCTS; + } + else + { + upcomingTermios.c_cflag &= ~CRTSCTS; + } + + + /* ControlHandShake */ + + if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + + if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE) + { + /* DTR/DSR flow control not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) + { + /* DCD flow control not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DCD_HANDSHAKE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + // FIXME: could be implemented during read/write I/O + if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) + { + /* DSR line control not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DSR_SENSITIVITY feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + // FIXME: could be implemented during read/write I/O + if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) + { + /* Aborting operations on error not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_ERROR_ABORT feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* FlowReplace */ + + if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT) + { + upcomingTermios.c_iflag |= IXON; + } + else + { + upcomingTermios.c_iflag &= ~IXON; + } + + if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE) + { + upcomingTermios.c_iflag |= IXOFF; + } + else + { + upcomingTermios.c_iflag &= ~IXOFF; + } + + // FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0' + if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR) + { + /* errors will be replaced by the character '\0'. */ + upcomingTermios.c_iflag &= ~IGNPAR; + } + else + { + upcomingTermios.c_iflag |= IGNPAR; + } + + if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING) + { + upcomingTermios.c_iflag |= IGNBRK; + } + else + { + upcomingTermios.c_iflag &= ~IGNBRK; + } + + // FIXME: could be implemented during read/write I/O + if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR) + { + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_BREAK_CHAR feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + // FIXME: could be implemented during read/write I/O + if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE) + { + /* not supported on Linux */ + CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_XOFF_CONTINUE feature."); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* XonLimit */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE) + { + CommLog_Print(WLOG_WARN, "Attempt to set XonLimit with an unsupported value: %lu", pHandflow->XonLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + /* XoffChar */ + + // FIXME: could be implemented during read/write I/O + if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE) + { + CommLog_Print(WLOG_WARN, "Attempt to set XoffLimit with an unsupported value: %lu", pHandflow->XoffLimit); + SetLastError(ERROR_NOT_SUPPORTED); + result = FALSE; /* but keep on */ + } + + + if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0) + { + CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError()); + return FALSE; + } + + return result; +} + + +static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow) +{ + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(pComm->fd, ¤tTermios) < 0) + { + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + + /* ControlHandShake */ + + pHandflow->ControlHandShake = 0; + + if (currentTermios.c_cflag & HUPCL) + pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL; + + /* SERIAL_DTR_HANDSHAKE unsupported */ + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE; + + /* SERIAL_DSR_HANDSHAKE unsupported */ + + /* SERIAL_DCD_HANDSHAKE unsupported */ + + /* SERIAL_DSR_SENSITIVITY unsupported */ + + /* SERIAL_ERROR_ABORT unsupported */ + + + /* FlowReplace */ + + pHandflow->FlowReplace = 0; + + if (currentTermios.c_iflag & IXON) + pHandflow->FlowReplace |= SERIAL_AUTO_TRANSMIT; + + if (currentTermios.c_iflag & IXOFF) + pHandflow->FlowReplace |= SERIAL_AUTO_RECEIVE; + + if (!(currentTermios.c_iflag & IGNPAR)) + pHandflow->FlowReplace |= SERIAL_ERROR_CHAR; + + if (currentTermios.c_iflag & IGNBRK) + pHandflow->FlowReplace |= SERIAL_NULL_STRIPPING; + + /* SERIAL_BREAK_CHAR unsupported */ + + if (currentTermios.c_cflag & HUPCL) + pHandflow->FlowReplace |= SERIAL_RTS_CONTROL; + + if (currentTermios.c_cflag & CRTSCTS) + pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE; + + /* SERIAL_XOFF_CONTINUE unsupported */ + + + /* XonLimit */ + + pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE; + + + /* XoffLimit */ + + pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE; + + return TRUE; +} + +static BOOL _set_timeouts(WINPR_COMM *pComm, const SERIAL_TIMEOUTS *pTimeouts) +{ + /* NB: timeouts are applied on system during read/write I/O */ + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx */ + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant == MAXULONG)) + { + CommLog_Print(WLOG_WARN, "ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + pComm->timeouts.ReadIntervalTimeout = pTimeouts->ReadIntervalTimeout; + pComm->timeouts.ReadTotalTimeoutMultiplier = pTimeouts->ReadTotalTimeoutMultiplier; + pComm->timeouts.ReadTotalTimeoutConstant = pTimeouts->ReadTotalTimeoutConstant; + pComm->timeouts.WriteTotalTimeoutMultiplier = pTimeouts->WriteTotalTimeoutMultiplier; + pComm->timeouts.WriteTotalTimeoutConstant = pTimeouts->WriteTotalTimeoutConstant; + + return TRUE; +} + +static BOOL _get_timeouts(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts) +{ + pTimeouts->ReadIntervalTimeout = pComm->timeouts.ReadIntervalTimeout; + pTimeouts->ReadTotalTimeoutMultiplier = pComm->timeouts.ReadTotalTimeoutMultiplier; + pTimeouts->ReadTotalTimeoutConstant = pComm->timeouts.ReadTotalTimeoutConstant; + pTimeouts->WriteTotalTimeoutMultiplier = pComm->timeouts.WriteTotalTimeoutMultiplier; + pTimeouts->WriteTotalTimeoutConstant = pComm->timeouts.WriteTotalTimeoutConstant; + + return TRUE; +} + + +static BOOL _set_lines(WINPR_COMM *pComm, UINT32 lines) +{ + if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCMBIS ioctl failed, lines=0x%X, errno=[%d] %s", lines, errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _clear_lines(WINPR_COMM *pComm, UINT32 lines) +{ + if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCMBIC ioctl failed, lines=0x%X, errno=[%d] %s", lines, errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_dtr(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + /* SERIAL_DTR_HANDSHAKE not supported as of today */ + assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0); + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _set_lines(pComm, TIOCM_DTR); +} + +static BOOL _clear_dtr(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + /* SERIAL_DTR_HANDSHAKE not supported as of today */ + assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0); + + if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _clear_lines(pComm, TIOCM_DTR); +} + +static BOOL _set_rts(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _set_lines(pComm, TIOCM_RTS); +} + +static BOOL _clear_rts(WINPR_COMM *pComm) +{ + SERIAL_HANDFLOW handflow; + if (!_get_handflow(pComm, &handflow)) + return FALSE; + + if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return _clear_lines(pComm, TIOCM_RTS); +} + + + +static BOOL _get_modemstatus(WINPR_COMM *pComm, ULONG *pRegister) +{ + UINT32 lines=0; + if (ioctl(pComm->fd, TIOCMGET, &lines) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + ZeroMemory(pRegister, sizeof(ULONG)); + + /* FIXME: Is the last read of the MSR register available or + * cached somewhere? Not quite sure we need to return the 4 + * LSBits anyway. A direct access to the register -- which + * would reset the register -- is likely not expected from + * this function. + */ + + /* #define SERIAL_MSR_DCTS 0x01 */ + /* #define SERIAL_MSR_DDSR 0x02 */ + /* #define SERIAL_MSR_TERI 0x04 */ + /* #define SERIAL_MSR_DDCD 0x08 */ + + if (lines & TIOCM_CTS) + *pRegister |= SERIAL_MSR_CTS; + if (lines & TIOCM_DSR) + *pRegister |= SERIAL_MSR_DSR; + if (lines & TIOCM_RI) + *pRegister |= SERIAL_MSR_RI; + if (lines & TIOCM_CD) + *pRegister |= SERIAL_MSR_DCD; + + return TRUE; +} + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ +static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK = + SERIAL_EV_RXCHAR | + SERIAL_EV_RXFLAG | + SERIAL_EV_TXEMPTY | + SERIAL_EV_CTS | + SERIAL_EV_DSR | + SERIAL_EV_RLSD | + SERIAL_EV_BREAK | + SERIAL_EV_ERR | + SERIAL_EV_RING | + /* SERIAL_EV_PERR | */ + SERIAL_EV_RX80FULL /*| + SERIAL_EV_EVENT1 | + SERIAL_EV_EVENT2*/; + + +static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask) +{ + ULONG possibleMask; + + + /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + { + /* FIXME: any doubt on reading PendingEvents out of a critical section? */ + + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP; + LeaveCriticalSection(&pComm->EventsLock); + + /* waiting the end of the pending _wait_on_mask() */ + while (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + Sleep(10); /* 10ms */ + } + + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); + + if (*pWaitMask == 0) + { + /* clearing pending events */ + + if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + pComm->PendingEvents = 0; + } + + possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK; + + if (possibleMask != *pWaitMask) + { + CommLog_Print(WLOG_WARN, "Not all wait events supported (Serial.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask); + + /* FIXME: shall we really set the possibleMask and return FALSE? */ + pComm->WaitEventMask = possibleMask; + + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + pComm->WaitEventMask = possibleMask; + + LeaveCriticalSection(&pComm->EventsLock); + return TRUE; +} + + +static BOOL _get_wait_mask(WINPR_COMM *pComm, ULONG *pWaitMask) +{ + *pWaitMask = pComm->WaitEventMask; + return TRUE; +} + + + +static BOOL _set_queue_size(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize) +{ + if ((pQueueSize->InSize <= N_TTY_BUF_SIZE) && (pQueueSize->OutSize <= N_TTY_BUF_SIZE)) + return TRUE; /* nothing to do */ + + /* FIXME: could be implemented on top of N_TTY */ + + if (pQueueSize->InSize > N_TTY_BUF_SIZE) + CommLog_Print(WLOG_WARN, "Requested an incompatible input buffer size: %lu, keeping on with a %d bytes buffer.", pQueueSize->InSize, N_TTY_BUF_SIZE); + + if (pQueueSize->OutSize > N_TTY_BUF_SIZE) + CommLog_Print(WLOG_WARN, "Requested an incompatible output buffer size: %lu, keeping on with a %d bytes buffer.", pQueueSize->OutSize, N_TTY_BUF_SIZE); + + SetLastError(ERROR_CANCELLED); + return FALSE; +} + + +static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask) +{ + if ((*pPurgeMask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)) > 0) + { + CommLog_Print(WLOG_WARN, "Invalid purge mask: 0x%lX\n", *pPurgeMask); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* FIXME: currently relying too much on the fact the server + * sends a single IRP_MJ_WRITE or IRP_MJ_READ at a time + * (taking care though that one IRP_MJ_WRITE and one + * IRP_MJ_READ can be sent simultaneously) */ + + if (*pPurgeMask & SERIAL_PURGE_TXABORT) + { + /* Purges all write (IRP_MJ_WRITE) requests. */ + + if (eventfd_write(pComm->fd_write_event, FREERDP_PURGE_TXABORT) < 0) + { + if (errno != EAGAIN) + { + CommLog_Print(WLOG_WARN, "eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); + } + + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_WRITE */ + } + } + + if (*pPurgeMask & SERIAL_PURGE_RXABORT) + { + /* Purges all read (IRP_MJ_READ) requests. */ + + if (eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT) < 0) + { + if (errno != EAGAIN) + { + CommLog_Print(WLOG_WARN, "eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); + } + + assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */ + } + } + + if (*pPurgeMask & SERIAL_PURGE_TXCLEAR) + { + /* Purges the transmit buffer, if one exists. */ + + if (tcflush(pComm->fd, TCOFLUSH) < 0) + { + CommLog_Print(WLOG_WARN, "tcflush(TCOFLUSH) failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_CANCELLED); + return FALSE; + } + } + + + if (*pPurgeMask & SERIAL_PURGE_RXCLEAR) + { + /* Purges the receive buffer, if one exists. */ + + if (tcflush(pComm->fd, TCIFLUSH) < 0) + { + CommLog_Print(WLOG_WARN, "tcflush(TCIFLUSH) failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_CANCELLED); + return FALSE; + } + } + + return TRUE; +} + +/* NB: _get_commstatus also produces most of the events consumed by _wait_on_mask(). Exceptions: + * - SERIAL_EV_RXFLAG: FIXME: once EventChar supported + * + */ +static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) +{ + /* http://msdn.microsoft.com/en-us/library/jj673022%28v=vs.85%29.aspx */ + + struct serial_icounter_struct currentCounters; + + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); + + ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS)); + + ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct)); + if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + /* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* > pComm->counters.*) thinking the counters can loop */ + + /* Errors */ + + if (currentCounters.buf_overrun != pComm->counters.buf_overrun) + { + pCommstatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN; + } + + if (currentCounters.overrun != pComm->counters.overrun) + { + pCommstatus->Errors |= SERIAL_ERROR_OVERRUN; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + if (currentCounters.brk != pComm->counters.brk) + { + pCommstatus->Errors |= SERIAL_ERROR_BREAK; + pComm->PendingEvents |= SERIAL_EV_BREAK; + } + + if (currentCounters.parity != pComm->counters.parity) + { + pCommstatus->Errors |= SERIAL_ERROR_PARITY; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + if (currentCounters.frame != pComm->counters.frame) + { + pCommstatus->Errors |= SERIAL_ERROR_FRAMING; + pComm->PendingEvents |= SERIAL_EV_ERR; + } + + + /* HoldReasons */ + + + /* TODO: SERIAL_TX_WAITING_FOR_CTS */ + + /* TODO: SERIAL_TX_WAITING_FOR_DSR */ + + /* TODO: SERIAL_TX_WAITING_FOR_DCD */ + + /* TODO: SERIAL_TX_WAITING_FOR_XON */ + + /* TODO: SERIAL_TX_WAITING_ON_BREAK, see LCR's bit 6 */ + + /* TODO: SERIAL_TX_WAITING_XOFF_SENT */ + + + + /* AmountInInQueue */ + + if (ioctl(pComm->fd, TIOCINQ, &(pCommstatus->AmountInInQueue)) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + + /* AmountInOutQueue */ + + if (ioctl(pComm->fd, TIOCOUTQ, &(pCommstatus->AmountInOutQueue)) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + /* BOOLEAN EofReceived; FIXME: once EofChar supported */ + + + /* BOOLEAN WaitForImmediate; TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR fully supported */ + + + /* other events based on counters */ + + if (currentCounters.rx != pComm->counters.rx) + { + pComm->PendingEvents |= SERIAL_EV_RXCHAR; + } + + if ((currentCounters.tx != pComm->counters.tx) && /* at least a transmission occurred AND ...*/ + (pCommstatus->AmountInOutQueue == 0)) /* output bufer is now empty */ + { + pComm->PendingEvents |= SERIAL_EV_TXEMPTY; + } + else + { + /* FIXME: "now empty" from the specs is ambiguous, need to track previous completed transmission? */ + pComm->PendingEvents &= ~SERIAL_EV_TXEMPTY; + } + + if (currentCounters.cts != pComm->counters.cts) + { + pComm->PendingEvents |= SERIAL_EV_CTS; + } + + if (currentCounters.dsr != pComm->counters.dsr) + { + pComm->PendingEvents |= SERIAL_EV_DSR; + } + + if (currentCounters.dcd != pComm->counters.dcd) + { + pComm->PendingEvents |= SERIAL_EV_RLSD; + } + + if (currentCounters.rng != pComm->counters.rng) + { + pComm->PendingEvents |= SERIAL_EV_RING; + } + + if (pCommstatus->AmountInInQueue > (0.8 * N_TTY_BUF_SIZE)) + { + pComm->PendingEvents |= SERIAL_EV_RX80FULL; + } + else + { + /* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously occured? */ + pComm->PendingEvents &= ~SERIAL_EV_RX80FULL; + } + + + pComm->counters = currentCounters; + + LeaveCriticalSection(&pComm->EventsLock); + return TRUE; +} + +static BOOL _refresh_PendingEvents(WINPR_COMM *pComm) +{ + SERIAL_STATUS serialStatus; + + /* NB: also ensures PendingEvents to be up to date */ + ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS)); + if (!_get_commstatus(pComm, &serialStatus)) + { + return FALSE; + } + + return TRUE; +} + + +static void _consume_event(WINPR_COMM *pComm, ULONG *pOutputMask, ULONG event) +{ + if ((pComm->WaitEventMask & event) && (pComm->PendingEvents & event)) + { + pComm->PendingEvents &= ~event; /* consumed */ + *pOutputMask |= event; + } +} + +/* + * NB: see also: _set_wait_mask() + */ +static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask) +{ + assert(*pOutputMask == 0); + + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents |= SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + + + while (TRUE) + { + /* NB: EventsLock also used by _refresh_PendingEvents() */ + if (!_refresh_PendingEvents(pComm)) + { + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + return FALSE; + } + + /* NB: ensure to leave the critical section before to return */ + EnterCriticalSection(&pComm->EventsLock); + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP) + { + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP; + + /* pOutputMask must remain empty but should + * not have been modified. + * + * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx + */ + assert(*pOutputMask == 0); + + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + return TRUE; + } + + _consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG); + _consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY); + _consume_event(pComm, pOutputMask, SERIAL_EV_CTS); + _consume_event(pComm, pOutputMask, SERIAL_EV_DSR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RLSD); + _consume_event(pComm, pOutputMask, SERIAL_EV_BREAK); + _consume_event(pComm, pOutputMask, SERIAL_EV_ERR); + _consume_event(pComm, pOutputMask, SERIAL_EV_RING ); + _consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL); + + LeaveCriticalSection(&pComm->EventsLock); + + /* NOTE: PendingEvents can be modified from now on but + * not pOutputMask */ + + if (*pOutputMask != 0) + { + /* at least an event occurred */ + + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + return TRUE; + } + + + /* waiting for a modification of PendingEvents. + * + * NOTE: previously used a semaphore but used + * sem_timedwait() anyway. Finally preferred a simpler + * solution with Sleep() whithout the burden of the + * semaphore initialization and destroying. + */ + + Sleep(100); /* 100 ms */ + } + + CommLog_Print(WLOG_WARN, "_wait_on_mask, unexpected return, WaitEventMask=0X%lX", pComm->WaitEventMask); + EnterCriticalSection(&pComm->EventsLock); + pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING; + LeaveCriticalSection(&pComm->EventsLock); + assert(FALSE); + return FALSE; +} + +static BOOL _set_break_on(WINPR_COMM *pComm) +{ + if (ioctl(pComm->fd, TIOCSBRK, NULL) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_break_off(WINPR_COMM *pComm) +{ + if (ioctl(pComm->fd, TIOCCBRK, NULL) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_xoff(WINPR_COMM *pComm) +{ + if (tcflow(pComm->fd, TCIOFF) < 0) + { + CommLog_Print(WLOG_WARN, "TCIOFF failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +static BOOL _set_xon(WINPR_COMM *pComm) +{ + if (tcflow(pComm->fd, TCION) < 0) + { + CommLog_Print(WLOG_WARN, "TCION failure, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + return TRUE; +} + + +BOOL _get_dtrrts(WINPR_COMM *pComm, ULONG *pMask) +{ + UINT32 lines=0; + if (ioctl(pComm->fd, TIOCMGET, &lines) < 0) + { + CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno)); + SetLastError(ERROR_IO_DEVICE); + return FALSE; + } + + *pMask = 0; + + if (!(lines & TIOCM_DTR)) + *pMask |= SERIAL_DTR_STATE; + if (!(lines & TIOCM_RTS)) + *pMask |= SERIAL_RTS_STATE; + + return TRUE; +} + + +BOOL _config_size(WINPR_COMM *pComm, ULONG *pSize) +{ + /* http://msdn.microsoft.com/en-us/library/ff546548%28v=vs.85%29.aspx */ + pSize = 0; + return TRUE; +} + + +BOOL _immediate_char(WINPR_COMM *pComm, const UCHAR *pChar) +{ + BOOL result; + DWORD nbBytesWritten = -1; + + /* FIXME: CommWriteFile uses a critical section, shall it be + * interrupted? + * + * FIXME: see also _get_commstatus()'s WaitForImmediate boolean + */ + + result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL); + + assert(nbBytesWritten == 1); + + return result; +} + + +BOOL _reset_device(WINPR_COMM *pComm) +{ + /* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx */ + return TRUE; +} + +static SERIAL_DRIVER _SerialSys = +{ + .id = SerialDriverSerialSys, + .name = _T("Serial.sys"), + .set_baud_rate = _set_baud_rate, + .get_baud_rate = _get_baud_rate, + .get_properties = _get_properties, + .set_serial_chars = _set_serial_chars, + .get_serial_chars = _get_serial_chars, + .set_line_control = _set_line_control, + .get_line_control = _get_line_control, + .set_handflow = _set_handflow, + .get_handflow = _get_handflow, + .set_timeouts = _set_timeouts, + .get_timeouts = _get_timeouts, + .set_dtr = _set_dtr, + .clear_dtr = _clear_dtr, + .set_rts = _set_rts, + .clear_rts = _clear_rts, + .get_modemstatus = _get_modemstatus, + .set_wait_mask = _set_wait_mask, + .get_wait_mask = _get_wait_mask, + .wait_on_mask = _wait_on_mask, + .set_queue_size = _set_queue_size, + .purge = _purge, + .get_commstatus = _get_commstatus, + .set_break_on = _set_break_on, + .set_break_off = _set_break_off, + .set_xoff = _set_xoff, + .set_xon = _set_xon, + .get_dtrrts = _get_dtrrts, + .config_size = _config_size, + .immediate_char = _immediate_char, + .reset_device = _reset_device, +}; + + +SERIAL_DRIVER* SerialSys_s() +{ + return &_SerialSys; +} + +#endif /* __linux__ */ diff --git a/winpr/libwinpr/comm/comm_serial_sys.h b/winpr/libwinpr/comm/comm_serial_sys.h new file mode 100644 index 000000000..bef1fbfe9 --- /dev/null +++ b/winpr/libwinpr/comm/comm_serial_sys.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 COMM_SERIAL_SYS_H +#define COMM_SERIAL_SYS_H + +#if defined __linux__ && !defined ANDROID + +#include "comm_ioctl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SERIAL_DRIVER* SerialSys_s(); + +#ifdef __cplusplus +} +#endif + + +#endif /* __linux__ */ + +#endif /* COMM_SERIAL_SYS_H */ diff --git a/winpr/libwinpr/comm/module.def b/winpr/libwinpr/comm/module.def new file mode 100644 index 000000000..44feb6f4e --- /dev/null +++ b/winpr/libwinpr/comm/module.def @@ -0,0 +1,3 @@ +LIBRARY "libwinpr" +EXPORTS + diff --git a/winpr/libwinpr/comm/test/.gitignore b/winpr/libwinpr/comm/test/.gitignore new file mode 100644 index 000000000..78bb24b78 --- /dev/null +++ b/winpr/libwinpr/comm/test/.gitignore @@ -0,0 +1,2 @@ +TestComm +TestComm.c diff --git a/winpr/libwinpr/comm/test/CMakeLists.txt b/winpr/libwinpr/comm/test/CMakeLists.txt new file mode 100644 index 000000000..8b9c07c88 --- /dev/null +++ b/winpr/libwinpr/comm/test/CMakeLists.txt @@ -0,0 +1,34 @@ + +set(MODULE_NAME "TestComm") +set(MODULE_PREFIX "TEST_COMM") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestCommDevice.c + TestCommConfig.c + TestGetCommState.c + TestSetCommState.c + TestSerialChars.c + TestControlSettings.c + TestHandflow.c + TestTimeouts.c + TestCommMonitor.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/comm/test/TestCommConfig.c b/winpr/libwinpr/comm/test/TestCommConfig.c new file mode 100644 index 000000000..4d667ee7e --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommConfig.c @@ -0,0 +1,149 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#include +#include +#include +#include +#include + +int TestCommConfig(int argc, char* argv[]) +{ + DCB dcb; + HANDLE hComm; + BOOL success; + LPCSTR lpFileName = "\\\\.\\COM1"; + COMMPROP commProp; + struct stat statbuf; + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + if (hComm && (hComm != INVALID_HANDLE_VALUE)) + { + fprintf(stderr, "CreateFileA failure: could create a handle on a not yet defined device: %s\n", lpFileName); + return EXIT_FAILURE; + } + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + success = DefineCommDevice(lpFileName, "/dev/ttyS0"); + if(!success) + { + fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName); + return EXIT_FAILURE; + } + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, /* invalid parmaeter */ + NULL, + CREATE_NEW, /* invalid parameter */ + 0, + (HANDLE)1234); /* invalid parmaeter */ + if (hComm != INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName); + return EXIT_FAILURE; + } + + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + if (!hComm || (hComm == INVALID_HANDLE_VALUE)) + { + fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%08x\n", lpFileName, GetLastError()); + return EXIT_FAILURE; + } + + /* TODO: a second call to CreateFileA should failed and + * GetLastError should return ERROR_SHARING_VIOLATION */ + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + success = GetCommState(hComm, &dcb); + if (!success) + { + fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError()); + return EXIT_FAILURE; + } + + fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + + ZeroMemory(&commProp, sizeof(COMMPROP)); + if (!GetCommProperties(hComm, &commProp)) + { + fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + if ((commProp.dwSettableBaud & BAUD_57600) <= 0) + { + fprintf(stderr, "BAUD_57600 unsupported!\n"); + return EXIT_FAILURE; + } + + if ((commProp.dwSettableBaud & BAUD_14400) > 0) + { + fprintf(stderr, "BAUD_14400 supported!\n"); + return EXIT_FAILURE; + } + + dcb.BaudRate = CBR_57600; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + + success = SetCommState(hComm, &dcb); + + if (!success) + { + fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); + return EXIT_FAILURE; + } + + success = GetCommState(hComm, &dcb); + + if (!success) + { + fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError()); + return 0; + } + + if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) || (dcb.StopBits != ONESTOPBIT)) + { + fprintf(stderr, "Got an unexpeted value among: BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n", + (int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits); + } + + CloseHandle(hComm); + + return 0; +} diff --git a/winpr/libwinpr/comm/test/TestCommDevice.c b/winpr/libwinpr/comm/test/TestCommDevice.c new file mode 100644 index 000000000..96d000391 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommDevice.c @@ -0,0 +1,115 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#include +#include + +static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult) +{ + BOOL result; + TCHAR lpTargetPath[MAX_PATH]; + DWORD tcslen; + + result = DefineCommDevice(lpDeviceName, _T("/dev/test")); + if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */ + { + _tprintf(_T("DefineCommDevice failure: device name: %s, expected result: %s, result: %s\n"), + lpDeviceName, + (expectedResult ? "TRUE" : "FALSE"), + (result ? "TRUE" : "FALSE")); + + return FALSE; + } + + result = IsCommDevice(lpDeviceName); + if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */ + { + _tprintf(_T("IsCommDevice failure: device name: %s, expected result: %s, result: %s\n"), + lpDeviceName, + (expectedResult ? "TRUE" : "FALSE"), + (result ? "TRUE" : "FALSE")); + + return FALSE; + } + + tcslen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH); + if (expectedResult) + { + if (tcslen <= _tcslen(lpTargetPath)) /* at least 2 more TCHAR are expected */ + { + _tprintf(_T("QueryCommDevice failure: didn't found the device name: %s\n"), lpDeviceName); + return FALSE; + } + + if (_tcscmp(_T("/dev/test"), lpTargetPath) != 0) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"), + lpDeviceName, _T("/dev/test"), lpTargetPath); + + return FALSE; + } + + if (lpTargetPath[_tcslen(lpTargetPath) + 1] != 0) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, the second NULL character is missing at the end of the buffer\n"), lpDeviceName); + return FALSE; + } + } + else + { + if (tcslen > 0) + { + _tprintf(_T("QueryCommDevice failure: device name: %s, expected result: , result: %d %s\n"), + lpDeviceName, tcslen, lpTargetPath); + + return FALSE; + } + } + + return TRUE; +} + + +int TestCommDevice(int argc, char* argv[]) +{ + if (!test_CommDevice(_T("COM0"), FALSE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("COM1"), TRUE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("COM1"), TRUE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("COM10"), FALSE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE)) + return EXIT_FAILURE; + + if (!test_CommDevice(_T("\\\\.COM10"), FALSE)) + return EXIT_FAILURE; + + return 0; +} diff --git a/winpr/libwinpr/comm/test/TestCommMonitor.c b/winpr/libwinpr/comm/test/TestCommMonitor.c new file mode 100644 index 000000000..1154b2789 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestCommMonitor.c @@ -0,0 +1,69 @@ + +#include +#include +#include +#include +#include + +int TestCommMonitor(int argc, char* argv[]) +{ + HANDLE hComm; + DWORD dwError; + BOOL fSuccess; + DWORD dwEvtMask; + OVERLAPPED overlapped; + LPCSTR lpFileName = "\\\\.\\COM1"; + + hComm = CreateFileA(lpFileName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (!hComm || (hComm == INVALID_HANDLE_VALUE)) + { + printf("CreateFileA failure: %s\n", lpFileName); + return 0; + } + + fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR); + + if (!fSuccess) + { + printf("SetCommMask failure: GetLastError() = %d\n", (int) GetLastError()); + return 0; + } + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (WaitCommEvent(hComm, &dwEvtMask, &overlapped)) + { + if (dwEvtMask & EV_DSR) + { + printf("EV_DSR\n"); + } + + if (dwEvtMask & EV_CTS) + { + printf("EV_CTS\n"); + } + } + else + { + dwError = GetLastError(); + + if (dwError == ERROR_IO_PENDING) + { + printf("ERROR_IO_PENDING\n"); + } + else + { + printf("WaitCommEvent failure: GetLastError() = %d\n", (int) dwError); + return 0; + } + } + + CloseHandle(hComm); + + return 0; +} + diff --git a/winpr/libwinpr/comm/test/TestControlSettings.c b/winpr/libwinpr/comm/test/TestControlSettings.c new file mode 100644 index 000000000..07b70117f --- /dev/null +++ b/winpr/libwinpr/comm/test/TestControlSettings.c @@ -0,0 +1,129 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 + +#include + +#include +#include + +#include "../comm.h" + +int TestControlSettings(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + DCB dcb; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + /* Test 1 */ + + dcb.ByteSize = 5; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = MARKPARITY; + + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY)) + { + fprintf(stderr, "test1 failed.\n"); + return FALSE; + } + + + /* Test 2 */ + + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = NOPARITY; + + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY)) + { + fprintf(stderr, "test2 failed.\n"); + return FALSE; + } + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestGetCommState.c b/winpr/libwinpr/comm/test/TestGetCommState.c new file mode 100644 index 000000000..2a80a5219 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestGetCommState.c @@ -0,0 +1,137 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 +#include + +#include +#include + +#include "../comm.h" + +static BOOL test_generic(HANDLE hComm) +{ + DCB dcb, *pDcb; + BOOL result; + + ZeroMemory(&dcb, sizeof(DCB)); + result = GetCommState(hComm, &dcb); + if (result) + { + printf("GetCommState failure, should have returned false because dcb.DCBlength has been let uninitialized\n"); + return FALSE; + } + + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB) / 2; /* improper value */ + result = GetCommState(hComm, &dcb); + if (result) + { + printf("GetCommState failure, should have return false because dcb.DCBlength was not correctly initialized\n"); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + result = GetCommState(hComm, &dcb); + if (!result) + { + printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError()); + return FALSE; + } + + pDcb = (DCB*)calloc(1, sizeof(DCB) * 2); + pDcb->DCBlength = sizeof(DCB) * 2; + result = GetCommState(hComm, pDcb); + result = result && (pDcb->DCBlength == sizeof(DCB) * 2); + free(pDcb); + if (!result) + { + printf("GetCommState failure: 0x%x, with bigger DCBlength\n", GetLastError()); + return FALSE; + } + + return TRUE; +} + +int TestGetCommState(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + printf("DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFileA("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + + if (hComm == INVALID_HANDLE_VALUE) + { + printf("CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + if (!test_generic(hComm)) + { + printf("test_generic failure (SerialDriverUnknown)\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); + if (!test_generic(hComm)) + { + printf("test_generic failure (SerialDriverSerialSys)\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); + if (!test_generic(hComm)) + { + printf("test_generic failure (SerialDriverSerCxSys)\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); + if (!test_generic(hComm)) + { + printf("test_generic failure (SerialDriverSerCx2Sys)\n"); + return EXIT_FAILURE; + } + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestHandflow.c b/winpr/libwinpr/comm/test/TestHandflow.c new file mode 100644 index 000000000..10cb20a13 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestHandflow.c @@ -0,0 +1,96 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 +#include + +#ifndef _WIN32 +#include +#endif + +#include +#include + +#include "../comm.h" + +static BOOL test_SerialSys(HANDLE hComm) +{ + // TMP: TODO: + return TRUE; +} + + +int TestHandflow(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); + if (!test_SerialSys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + /* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */ + /* if (!test_SerCxSys(hComm)) */ + /* { */ + /* fprintf(stderr, "test_SerCxSys failure\n"); */ + /* return EXIT_FAILURE; */ + /* } */ + + /* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */ + /* if (!test_SerCx2Sys(hComm)) */ + /* { */ + /* fprintf(stderr, "test_SerCxSys failure\n"); */ + /* return EXIT_FAILURE; */ + /* } */ + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestSerialChars.c b/winpr/libwinpr/comm/test/TestSerialChars.c new file mode 100644 index 000000000..50912bb09 --- /dev/null +++ b/winpr/libwinpr/comm/test/TestSerialChars.c @@ -0,0 +1,183 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 +#include + +#ifndef _WIN32 +#include +#endif + +#include +#include + +#include "../comm.h" + +static BOOL test_SerCxSys(HANDLE hComm) +{ + DCB dcb; + UCHAR XonChar, XoffChar; + + struct termios currentTermios; + + ZeroMemory(¤tTermios, sizeof(struct termios)); + if (tcgetattr(((WINPR_COMM*)hComm)->fd, ¤tTermios) < 0) + { + fprintf(stderr, "tcgetattr failure.\n"); + return FALSE; + } + + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError()); + return FALSE; + } + + if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0')) + { + fprintf(stderr, "test_SerCxSys failure, expected XonChar and XoffChar to be set\n"); + return FALSE; + } + + + /* retrieve Xon/Xoff chars */ + if ((dcb.XonChar != currentTermios.c_cc[VSTART]) || (dcb.XoffChar != currentTermios.c_cc[VSTOP])) + { + fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n"); + return FALSE; + } + + /* swap XonChar/XoffChar */ + + XonChar = dcb.XonChar; + XoffChar = dcb.XoffChar; + dcb.XonChar = XoffChar; + dcb.XoffChar = XonChar; + if (!SetCommState(hComm, &dcb)) + { + fprintf(stderr, "SetCommState failure, GetLastError(): 0x%08x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError()); + return FALSE; + } + + if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar)) + { + fprintf(stderr, "test_SerCxSys, expected XonChar and XoffChar to be swapped\n"); + return FALSE; + } + + /* same XonChar / XoffChar */ + dcb.XonChar = dcb.XoffChar; + if (SetCommState(hComm, &dcb)) + { + fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed because XonChar and XoffChar are the same\n"); + return FALSE; + } + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed with GetLastError()=ERROR_INVALID_PARAMETER\n"); + return FALSE; + } + + return TRUE; +} + + +static BOOL test_SerCx2Sys(HANDLE hComm) +{ + DCB dcb; + + ZeroMemory(&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!GetCommState(hComm, &dcb)) + { + fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError()); + return FALSE; + } + + if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') || (dcb.XonChar != '\0') || (dcb.XoffChar != '\0')) + { + fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n"); + return FALSE; + } + + return TRUE; +} + +int TestSerialChars(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); + if (!test_SerCxSys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); + if (!test_SerCx2Sys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestSetCommState.c b/winpr/libwinpr/comm/test/TestSetCommState.c new file mode 100644 index 000000000..85fb8159a --- /dev/null +++ b/winpr/libwinpr/comm/test/TestSetCommState.c @@ -0,0 +1,332 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 +#include + +#include +#include + +#include "../comm.h" + +static void init_empty_dcb(DCB *pDcb) +{ + ZeroMemory(pDcb, sizeof(DCB)); + pDcb->DCBlength = sizeof(DCB); + pDcb->XonChar = 1; + pDcb->XoffChar = 2; +} + +static BOOL test_fParity(HANDLE hComm) +{ + DCB dcb; + BOOL result; + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + /* test 1 */ + dcb.fParity = TRUE; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + if (!dcb.fParity) + { + fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return FALSE; + } + + /* test 2 */ + dcb.fParity = FALSE; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + if (dcb.fParity) + { + fprintf(stderr, "unexpected fParity: %d instead of FALSE\n", dcb.fParity); + return FALSE; + } + + /* test 3 (redo test 1) */ + dcb.fParity = TRUE; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + if (!dcb.fParity) + { + fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity); + return FALSE; + } + + return TRUE; +} + + +static BOOL test_SerialSys(HANDLE hComm) +{ + DCB dcb; + BOOL result; + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + /* Test 1 */ + dcb.BaudRate = CBR_115200; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError()); + return FALSE; + } + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != CBR_115200) + { + fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n", CBR_115200); + return FALSE; + } + + /* Test 2 using a defferent baud rate */ + + dcb.BaudRate = CBR_57600; + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + if (dcb.BaudRate != CBR_57600) + { + fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_57600)\n", CBR_57600); + return FALSE; + } + + /* Test 3 using an unsupported baud rate on Linux */ + dcb.BaudRate = CBR_128000; + result = SetCommState(hComm, &dcb); + if (result) + { + fprintf(stderr, "SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n", CBR_128000); + return FALSE; + } + + return TRUE; +} + +static BOOL test_SerCxSys(HANDLE hComm) +{ + /* as of today there is no difference */ + return test_SerialSys(hComm); +} + +static BOOL test_SerCx2Sys(HANDLE hComm) +{ + /* as of today there is no difference */ + return test_SerialSys(hComm); +} + +static BOOL test_generic(HANDLE hComm) +{ + DCB dcb, dcb2; + BOOL result; + + init_empty_dcb(&dcb); + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + /* Checks whether we get the same information before and after SetCommState */ + memcpy(&dcb2, &dcb, sizeof(DCB)); + result = SetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError()); + return FALSE; + } + + result = GetCommState(hComm, &dcb); + if (!result) + { + fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError()); + return FALSE; + } + + if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0) + { + fprintf(stderr, "DCB is different after SetCommState() whereas it should have not changed\n"); + return FALSE; + } + + // TODO: a more complete and generic test using GetCommProperties() + + /* TMP: TODO: fBinary tests */ + + /* fParity tests */ + if (!test_fParity(hComm)) + { + fprintf(stderr, "test_fParity failure\n"); + return FALSE; + } + + return TRUE; +} + + +int TestSetCommState(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + if (!test_generic(hComm)) + { + fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n"); + return EXIT_FAILURE; + } + if (!test_SerialSys(hComm)) + { + fprintf(stderr, "test_SerialSys failure\n"); + return EXIT_FAILURE; + } + + + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n"); + return EXIT_FAILURE; + } + if (!test_SerCxSys(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n"); + return EXIT_FAILURE; + } + if (!test_SerCx2Sys(hComm)) + { + fprintf(stderr, "test_SerCx2Sys failure\n"); + return EXIT_FAILURE; + } + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/comm/test/TestTimeouts.c b/winpr/libwinpr/comm/test/TestTimeouts.c new file mode 100644 index 000000000..0ddf2775a --- /dev/null +++ b/winpr/libwinpr/comm/test/TestTimeouts.c @@ -0,0 +1,136 @@ +/** + * WinPR: Windows Portable Runtime + * Serial Communication API + * + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * + * 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 +#include + +#ifndef _WIN32 +#include +#endif + +#include +#include + +#include "../comm.h" + +static BOOL test_generic(HANDLE hComm) +{ + COMMTIMEOUTS timeouts, timeouts2; + + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 2; + timeouts.ReadTotalTimeoutConstant = 3; + timeouts.WriteTotalTimeoutMultiplier = 4; + timeouts.WriteTotalTimeoutConstant = 5; + + if (!SetCommTimeouts(hComm, &timeouts)) + { + fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError()); + return FALSE; + } + + ZeroMemory(&timeouts2, sizeof(COMMTIMEOUTS)); + if (!GetCommTimeouts(hComm, &timeouts2)) + { + fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError()); + return FALSE; + } + + if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0) + { + fprintf(stderr, "TestTimeouts failure, didn't get back the same timeouts.\n"); + return FALSE; + } + + /* not supported combination */ + timeouts.ReadIntervalTimeout = MAXULONG; + timeouts.ReadTotalTimeoutConstant = MAXULONG; + if (SetCommTimeouts(hComm, &timeouts)) + { + fprintf(stderr, "SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant set to MAXULONG. GetLastError: 0x%08x\n", GetLastError()); + return FALSE; + } + + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + fprintf(stderr, "SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER and got: 0x%08x\n", GetLastError()); + return FALSE; + } + + return TRUE; +} + + +int TestTimeouts(int argc, char* argv[]) +{ + struct stat statbuf; + BOOL result; + HANDLE hComm; + + if (stat("/dev/ttyS0", &statbuf) < 0) + { + fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n"); + return EXIT_SUCCESS; + } + + result = DefineCommDevice("COM1", "/dev/ttyS0"); + if (!result) + { + fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + hComm = CreateFile("COM1", + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (hComm == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError()); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerialSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerialSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerCxSys failure\n"); + return EXIT_FAILURE; + } + + _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); + if (!test_generic(hComm)) + { + fprintf(stderr, "test_SerCx2Sys failure\n"); + return EXIT_FAILURE; + } + + if (!CloseHandle(hComm)) + { + fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/winpr/libwinpr/credentials/CMakeLists.txt b/winpr/libwinpr/credentials/CMakeLists.txt index 588f28c98..80140c42b 100644 --- a/winpr/libwinpr/credentials/CMakeLists.txt +++ b/winpr/libwinpr/credentials/CMakeLists.txt @@ -15,28 +15,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-credentials") -set(MODULE_PREFIX "WINPR_CREDENTIALS") - -set(${MODULE_PREFIX}_SRCS - credentials.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(credentials.c) diff --git a/winpr/libwinpr/credui/CMakeLists.txt b/winpr/libwinpr/credui/CMakeLists.txt index cb5a86ba5..b1a06638f 100644 --- a/winpr/libwinpr/credui/CMakeLists.txt +++ b/winpr/libwinpr/credui/CMakeLists.txt @@ -15,41 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-credui") -set(MODULE_PREFIX "WINPR_CREDUI") - -set(${MODULE_PREFIX}_SRCS - credui.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") +winpr_module_add(credui.c) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} credui) + winpr_library_add(credui) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-utils) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/credui/test/CMakeLists.txt b/winpr/libwinpr/credui/test/CMakeLists.txt index 95a2462ab..e615e3a32 100644 --- a/winpr/libwinpr/credui/test/CMakeLists.txt +++ b/winpr/libwinpr/credui/test/CMakeLists.txt @@ -16,12 +16,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-credui) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index 6acb1c303..3fd7e0511 100644 --- a/winpr/libwinpr/crt/CMakeLists.txt +++ b/winpr/libwinpr/crt/CMakeLists.txt @@ -15,10 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-crt") -set(MODULE_PREFIX "WINPR_CRT") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( alignment.c conversion.c buffer.c @@ -28,30 +25,6 @@ set(${MODULE_PREFIX}_SRCS utf.c utf.h) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-error) - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/crt/alignment.c b/winpr/libwinpr/crt/alignment.c index a172cad9c..2c1194b7e 100644 --- a/winpr/libwinpr/crt/alignment.c +++ b/winpr/libwinpr/crt/alignment.c @@ -27,6 +27,11 @@ #ifndef _WIN32 +#define WINPR_ALIGNED_MEM_SIGNATURE 0x0BA0BAB + +#define WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(_memptr) \ + (WINPR_ALIGNED_MEM*) (((size_t)(((BYTE*) _memptr) - sizeof(WINPR_ALIGNED_MEM)))); + #include #ifdef __APPLE__ @@ -37,11 +42,16 @@ #include #endif -struct _aligned_meminfo +#include "../log.h" +#define TAG WINPR_TAG("crt") + +struct winpr_aligned_mem { + UINT32 sig; size_t size; void* base_addr; }; +typedef struct winpr_aligned_mem WINPR_ALIGNED_MEM; void* _aligned_malloc(size_t size, size_t alignment) { @@ -55,13 +65,14 @@ void* _aligned_realloc(void* memblock, size_t size, size_t alignment) void* _aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment) { - return NULL; + return _aligned_offset_recalloc(memblock, num, size, alignment, 0); } void* _aligned_offset_malloc(size_t size, size_t alignment, size_t offset) { - void* memptr, *tmpptr; - struct _aligned_meminfo *ameminfo; + void* base; + void* memblock; + WINPR_ALIGNED_MEM* pMem; /* alignment must be a power of 2 */ if (alignment % 2 == 1) @@ -76,24 +87,25 @@ void* _aligned_offset_malloc(size_t size, size_t alignment, size_t offset) alignment = sizeof(void*); /* malloc size + alignment to make sure we can align afterwards */ - tmpptr = malloc(size + alignment + sizeof(struct _aligned_meminfo)); + base = malloc(size + alignment + sizeof(WINPR_ALIGNED_MEM)); - if (!tmpptr) + if (!base) return NULL; - memptr = (void *)((((size_t)((PBYTE)tmpptr + alignment + offset + sizeof(struct _aligned_meminfo)) & ~(alignment - 1)) - offset)); - - ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memptr - sizeof(struct _aligned_meminfo)))); - ameminfo->base_addr = tmpptr; - ameminfo->size = size; - - return memptr; + memblock = (void*)((((size_t)(((BYTE*) base) + alignment + offset + sizeof(WINPR_ALIGNED_MEM)) & ~(alignment - 1)) - offset)); + pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); + pMem->sig = WINPR_ALIGNED_MEM_SIGNATURE; + pMem->base_addr = base; + pMem->size = size; + return memblock; } void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset) { - void* newmem; - struct _aligned_meminfo* ameminfo; + size_t copySize; + void* newMemblock; + WINPR_ALIGNED_MEM* pMem; + WINPR_ALIGNED_MEM* pNewMem; if (!memblock) return _aligned_offset_malloc(size, alignment, offset); @@ -104,39 +116,94 @@ void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, siz return NULL; } - /* The following is not very performant but a simple and working solution */ - newmem = _aligned_offset_malloc(size, alignment, offset); + newMemblock = _aligned_offset_malloc(size, alignment, offset); - if (!newmem) + if (!newMemblock) return NULL; - ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo)))); - CopyMemory(newmem, memblock, ameminfo->size); - _aligned_free(memblock); + pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); + pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); - return newmem; + if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) + { + WLog_ERR(TAG, "_aligned_offset_realloc: memory block was not allocated by _aligned_malloc!"); + return NULL; + } + + copySize = (pNewMem->size < pMem->size) ? pNewMem->size : pMem->size; + CopyMemory(newMemblock, memblock, copySize); + _aligned_free(memblock); + return newMemblock; } void* _aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment, size_t offset) { - return NULL; + void* newMemblock; + WINPR_ALIGNED_MEM* pMem; + WINPR_ALIGNED_MEM* pNewMem; + + if (!memblock) + return _aligned_offset_malloc(size, alignment, offset); + + if (size == 0) + { + _aligned_free(memblock); + return NULL; + } + + newMemblock = _aligned_offset_malloc(size, alignment, offset); + + if (!newMemblock) + return NULL; + + pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); + pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); + + if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) + { + WLog_ERR(TAG, "_aligned_offset_recalloc: memory block was not allocated by _aligned_malloc!"); + return NULL; + } + + ZeroMemory(newMemblock, pNewMem->size); + _aligned_free(memblock); + return newMemblock; } size_t _aligned_msize(void* memblock, size_t alignment, size_t offset) { - return 0; + WINPR_ALIGNED_MEM* pMem; + + if (!memblock) + return 0; + + pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); + + if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) + { + WLog_ERR(TAG, "_aligned_msize: memory block was not allocated by _aligned_malloc!"); + return 0; + } + + return pMem->size; } void _aligned_free(void* memblock) { - struct _aligned_meminfo* ameminfo; + WINPR_ALIGNED_MEM* pMem; if (!memblock) return; - ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo)))); + pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock); - free(ameminfo->base_addr); + if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE) + { + WLog_ERR(TAG, "_aligned_free: memory block was not allocated by _aligned_malloc!"); + return; + } + + free(pMem->base_addr); } #endif diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index 0ecdc6a42..0fca34cdf 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -32,6 +32,9 @@ #include "casing.c" +#include "../log.h" +#define TAG WINPR_TAG("crt") + char* _strdup(const char* strSource) { char* strDestination; @@ -42,7 +45,7 @@ char* _strdup(const char* strSource) strDestination = strdup(strSource); if (strDestination == NULL) - perror("strdup"); + WLog_ERR(TAG,"strdup"); return strDestination; } @@ -54,19 +57,20 @@ WCHAR* _wcsdup(const WCHAR* strSource) if (strSource == NULL) return NULL; -#if sun +#if defined(sun) && sun strDestination = wsdup(strSource); #elif defined(__APPLE__) && defined(__MACH__) || defined(ANDROID) strDestination = malloc(wcslen((wchar_t*)strSource)); if (strDestination != NULL) wcscpy((wchar_t*)strDestination, (const wchar_t*)strSource); + #else strDestination = (WCHAR*) wcsdup((wchar_t*) strSource); #endif if (strDestination == NULL) - perror("wcsdup"); + WLog_ERR(TAG,"wcsdup"); return strDestination; } @@ -148,7 +152,6 @@ WCHAR* wcstok_s(WCHAR* strToken, const WCHAR* strDelimit, WCHAR** context) *strToken++ = 0; *context = strToken; - return nextToken; } @@ -165,6 +168,7 @@ LPSTR CharUpperA(LPSTR lpsz) return NULL; length = strlen(lpsz); + if (length < 1) return (LPSTR) NULL; @@ -176,7 +180,6 @@ LPSTR CharUpperA(LPSTR lpsz) c = c - 32; *lpsz = c; - return lpsz; } @@ -191,8 +194,7 @@ LPSTR CharUpperA(LPSTR lpsz) LPWSTR CharUpperW(LPWSTR lpsz) { - fprintf(stderr, "CharUpperW unimplemented!\n"); - + WLog_ERR(TAG, "CharUpperW unimplemented!"); return (LPWSTR) NULL; } @@ -245,7 +247,6 @@ LPSTR CharLowerA(LPSTR lpsz) c = c + 32; *lpsz = c; - return lpsz; } @@ -260,8 +261,7 @@ LPSTR CharLowerA(LPSTR lpsz) LPWSTR CharLowerW(LPWSTR lpsz) { - fprintf(stderr, "CharLowerW unimplemented!\n"); - + WLog_ERR(TAG, "CharLowerW unimplemented!"); return (LPWSTR) NULL; } @@ -303,7 +303,7 @@ BOOL IsCharAlphaA(CHAR ch) BOOL IsCharAlphaW(WCHAR ch) { - fprintf(stderr, "IsCharAlphaW unimplemented!\n"); + WLog_ERR(TAG, "IsCharAlphaW unimplemented!"); return 0; } @@ -318,7 +318,7 @@ BOOL IsCharAlphaNumericA(CHAR ch) BOOL IsCharAlphaNumericW(WCHAR ch) { - fprintf(stderr, "IsCharAlphaNumericW unimplemented!\n"); + WLog_ERR(TAG, "IsCharAlphaNumericW unimplemented!"); return 0; } @@ -332,7 +332,7 @@ BOOL IsCharUpperA(CHAR ch) BOOL IsCharUpperW(WCHAR ch) { - fprintf(stderr, "IsCharUpperW unimplemented!\n"); + WLog_ERR(TAG, "IsCharUpperW unimplemented!"); return 0; } @@ -346,7 +346,7 @@ BOOL IsCharLowerA(CHAR ch) BOOL IsCharLowerW(WCHAR ch) { - fprintf(stderr, "IsCharLowerW unimplemented!\n"); + WLog_ERR(TAG, "IsCharLowerW unimplemented!"); return 0; } @@ -387,3 +387,81 @@ int lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2) } #endif + +int ConvertLineEndingToLF(char* str, int size) +{ + int status; + char* end; + char* pInput; + char* pOutput; + + end = &str[size]; + pInput = pOutput = str; + + while (pInput < end) + { + if ((pInput[0] == '\r') && (pInput[1] == '\n')) + { + *pOutput++ = '\n'; + pInput += 2; + } + else + { + *pOutput++ = *pInput++; + } + } + + status = pOutput - str; + + return status; +} + +char* ConvertLineEndingToCRLF(const char* str, int* size) +{ + int count; + char* newStr; + char* pOutput; + const char* end; + const char* pInput; + + end = &str[*size]; + + count = 0; + pInput = str; + + while (pInput < end) + { + if (*pInput == '\n') + count++; + + pInput++; + } + + newStr = (char*) malloc(*size + (count * 2) + 1); + + if (!newStr) + return NULL; + + pInput = str; + pOutput = newStr; + + while (pInput < end) + { + if ((*pInput == '\n') && ((pInput > str) && (pInput[-1] != '\r'))) + { + *pOutput++ = '\r'; + *pOutput++ = '\n'; + } + else + { + *pOutput++ = *pInput; + } + + pInput++; + } + + *size = pOutput - newStr; + + return newStr; +} + diff --git a/winpr/libwinpr/crt/test/CMakeLists.txt b/winpr/libwinpr/crt/test/CMakeLists.txt index acb6b98d9..4bccde151 100644 --- a/winpr/libwinpr/crt/test/CMakeLists.txt +++ b/winpr/libwinpr/crt/test/CMakeLists.txt @@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS TestTypes.c TestAlignment.c TestString.c + TestIntrinsics.c TestUnicodeConversion.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS @@ -16,12 +17,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-error) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/crt/test/TestIntrinsics.c b/winpr/libwinpr/crt/test/TestIntrinsics.c new file mode 100644 index 000000000..5bbf915f9 --- /dev/null +++ b/winpr/libwinpr/crt/test/TestIntrinsics.c @@ -0,0 +1,88 @@ + +#include +#include +#include + +static BOOL g_LZCNT = FALSE; + +static INLINE UINT32 lzcnt_s(UINT32 x) +{ + if (!x) + return 32; + + if (!g_LZCNT) + { + UINT32 y; + int n = 32; + y = x >> 16; if (y != 0) { n = n - 16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + return n - x; + } + + return __lzcnt(x); +} + +int test_lzcnt() +{ + if (lzcnt_s(0x1) != 31) { + fprintf(stderr, "__lzcnt(0x1) != 31: %d\n", __lzcnt(0x1)); + return -1; + } + + if (lzcnt_s(0xFF) != 24) { + fprintf(stderr, "__lzcnt(0xFF) != 24\n"); + return -1; + } + + if (lzcnt_s(0xFFFF) != 16) { + fprintf(stderr, "__lzcnt(0xFFFF) != 16\n"); + return -1; + } + + if (lzcnt_s(0xFFFFFF) != 8) { + fprintf(stderr, "__lzcnt(0xFFFFFF) != 8\n"); + return -1; + } + + if (lzcnt_s(0xFFFFFFFF) != 0) { + fprintf(stderr, "__lzcnt(0xFFFFFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int test_lzcnt16() +{ + if (__lzcnt16(0x1) != 15) { + fprintf(stderr, "__lzcnt16(0x1) != 15\n"); + return -1; + } + + if (__lzcnt16(0xFF) != 8) { + fprintf(stderr, "__lzcnt16(0xFF) != 8\n"); + return -1; + } + + if (__lzcnt16(0xFFFF) != 0) { + fprintf(stderr, "__lzcnt16(0xFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int TestIntrinsics(int argc, char* argv[]) +{ + g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT); + + printf("LZCNT available: %d\n", g_LZCNT); + + test_lzcnt(); + //test_lzcnt16(); + + return 0; +} diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index 325017f53..fc5134f55 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -376,3 +376,18 @@ int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int return status; } + +/** + * Swap Unicode byte order (UTF16LE <-> UTF16BE) + */ + +void ByteSwapUnicode(WCHAR* wstr, int length) +{ + WCHAR* end = &wstr[length]; + + while (wstr < end) + { + *wstr = _byteswap_ushort(*wstr); + wstr++; + } +} diff --git a/winpr/libwinpr/crt/utf.c b/winpr/libwinpr/crt/utf.c index 10af41040..45fb938be 100644 --- a/winpr/libwinpr/crt/utf.c +++ b/winpr/libwinpr/crt/utf.c @@ -1,8 +1,8 @@ /* * Copyright 2001-2004 Unicode, Inc. - * + * * Disclaimer - * + * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine @@ -10,9 +10,9 @@ * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. - * + * * Limitations on Rights to Redistribute This Code - * + * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form @@ -52,108 +52,156 @@ static const DWORD halfMask = 0x3FFUL; /* --------------------------------------------------------------------- */ -ConversionResult ConvertUTF32toUTF16 ( - const DWORD** sourceStart, const DWORD* sourceEnd, - WCHAR** targetStart, WCHAR* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const DWORD* source = *sourceStart; - WCHAR* target = *targetStart; - while (source < sourceEnd) { - DWORD ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (WCHAR)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (WCHAR)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (WCHAR)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; +ConversionResult ConvertUTF32toUTF16( + const DWORD** sourceStart, const DWORD* sourceEnd, + WCHAR** targetStart, WCHAR* targetEnd, ConversionFlags flags) +{ + ConversionResult result = conversionOK; + const DWORD* source = *sourceStart; + WCHAR* target = *targetStart; + + while (source < sourceEnd) + { + DWORD ch; + + if (target >= targetEnd) + { + result = targetExhausted; + break; + } + + ch = *source++; + + if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */ + { + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + { + if (flags == strictConversion) + { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + else + { + *target++ = UNI_REPLACEMENT_CHAR; + } + } + else + { + *target++ = (WCHAR)ch; /* normal case */ + } + } + else if (ch > UNI_MAX_LEGAL_UTF32) + { + if (flags == strictConversion) + { + result = sourceIllegal; + } + else + { + *target++ = UNI_REPLACEMENT_CHAR; + } + } + else + { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) + { + --source; /* Back up source pointer! */ + result = targetExhausted; + break; + } + + ch -= halfBase; + *target++ = (WCHAR)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (WCHAR)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ -ConversionResult ConvertUTF16toUTF32 ( - const WCHAR** sourceStart, const WCHAR* sourceEnd, - DWORD** targetStart, DWORD* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const WCHAR* source = *sourceStart; - DWORD* target = *targetStart; - DWORD ch, ch2; - while (source < sourceEnd) { - const WCHAR* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; +ConversionResult ConvertUTF16toUTF32( + const WCHAR** sourceStart, const WCHAR* sourceEnd, + DWORD** targetStart, DWORD* targetEnd, ConversionFlags flags) +{ + ConversionResult result = conversionOK; + const WCHAR* source = *sourceStart; + DWORD* target = *targetStart; + DWORD ch, ch2; + + while (source < sourceEnd) + { + const WCHAR* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) + { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) + { + ch2 = *source; + + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) + { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } + else if (flags == strictConversion) /* it's an unpaired high surrogate */ + { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + else /* We don't have the 16 bits following the high surrogate. */ + { + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } + else if (flags == strictConversion) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) + { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + + if (target >= targetEnd) + { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; + break; + } + + *target++ = ch; + } + + *sourceStart = source; + *targetStart = target; #ifdef CVTUTF_DEBUG -if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); -} + + if (result == sourceIllegal) + { + WLOG_WARN(TAG, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + } + #endif - return result; + return result; } /* --------------------------------------------------------------------- */ @@ -165,15 +213,16 @@ if (result == sourceIllegal) { * left as-is for anyone who may want to do such conversion, which was * allowed in earlier algorithms. */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +static const char trailingBytesForUTF8[256] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /* @@ -181,8 +230,9 @@ static const char trailingBytesForUTF8[256] = { * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ -static const DWORD offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; +static const DWORD offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL + }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed @@ -213,9 +263,7 @@ ConversionResult ConvertUTF16toUTF8( const WCHAR* source; BOOL computeLength; ConversionResult result; - computeLength = (!targetEnd) ? TRUE : FALSE; - source = *sourceStart; target = *targetStart; result = conversionOK; @@ -227,22 +275,21 @@ ConversionResult ConvertUTF16toUTF8( const DWORD byteMask = 0xBF; const DWORD byteMark = 0x80; const WCHAR* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { DWORD ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; + + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) @@ -309,17 +356,19 @@ ConversionResult ConvertUTF16toUTF8( { switch (bytesToWrite) { - /* note: everything falls through. */ - + /* note: everything falls through. */ case 4: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (BYTE)(ch | firstByteMark[bytesToWrite]); } @@ -328,8 +377,7 @@ ConversionResult ConvertUTF16toUTF8( { switch (bytesToWrite) { - /* note: everything falls through. */ - + /* note: everything falls through. */ case 4: --target; ch >>= 6; @@ -352,7 +400,6 @@ ConversionResult ConvertUTF16toUTF8( *sourceStart = source; *targetStart = target; - return result; } @@ -369,32 +416,55 @@ ConversionResult ConvertUTF16toUTF8( * definition of UTF-8 goes up to 4-byte sequences. */ -static BOOL isLegalUTF8(const BYTE *source, int length) +static BOOL isLegalUTF8(const BYTE* source, int length) { BYTE a; - const BYTE *srcptr = source + length; + const BYTE* srcptr = source + length; switch (length) { default: return FALSE; - /* Everything else falls through when "TRUE"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return FALSE; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return FALSE; - case 2: if ((a = (*--srcptr)) > 0xBF) return FALSE; + /* Everything else falls through when "TRUE"... */ + case 4: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return FALSE; + + case 3: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return FALSE; + + case 2: + if ((a = (*--srcptr)) > 0xBF) return FALSE; switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return FALSE; break; - case 0xED: if (a > 0x9F) return FALSE; break; - case 0xF0: if (a < 0x90) return FALSE; break; - case 0xF4: if (a > 0x8F) return FALSE; break; - default: if (a < 0x80) return FALSE; + /* no fall-through in this inner switch */ + case 0xE0: + if (a < 0xA0) return FALSE; + + break; + + case 0xED: + if (a > 0x9F) return FALSE; + + break; + + case 0xF0: + if (a < 0x90) return FALSE; + + break; + + case 0xF4: + if (a > 0x8F) return FALSE; + + break; + + default: + if (a < 0x80) return FALSE; } - case 1: if (*source >= 0x80 && *source < 0xC2) return FALSE; + case 1: + if (*source >= 0x80 && *source < 0xC2) return FALSE; } if (*source > 0xF4) @@ -409,7 +479,7 @@ static BOOL isLegalUTF8(const BYTE *source, int length) * Exported function to return whether a UTF-8 sequence is legal or not. * This is not used here; it's just exported. */ -BOOL isLegalUTF8Sequence(const BYTE *source, const BYTE *sourceEnd) +BOOL isLegalUTF8Sequence(const BYTE* source, const BYTE* sourceEnd) { int length = trailingBytesForUTF8[*source] + 1; @@ -429,9 +499,7 @@ ConversionResult ConvertUTF8toUTF16( const BYTE* source; BOOL computeLength; ConversionResult result; - computeLength = (!targetEnd) ? TRUE : FALSE; - result = conversionOK; source = *sourceStart; target = *targetStart; @@ -459,12 +527,28 @@ ConversionResult ConvertUTF8toUTF16( */ switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; + case 5: + ch += *source++; + ch <<= 6; /* remember, illegal UTF-8 */ + + case 4: + ch += *source++; + ch <<= 6; /* remember, illegal UTF-8 */ + + case 3: + ch += *source++; + ch <<= 6; + + case 2: + ch += *source++; + ch <<= 6; + + case 1: + ch += *source++; + ch <<= 6; + + case 0: + ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; @@ -480,7 +564,6 @@ ConversionResult ConvertUTF8toUTF16( { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) @@ -524,7 +607,6 @@ ConversionResult ConvertUTF8toUTF16( else { /* target is a character in range 0xFFFF - 0x10FFFF. */ - if ((target + 1 >= targetEnd) && (!computeLength)) { source -= (extraBytesToRead + 1); /* Back up source pointer! */ @@ -549,123 +631,201 @@ ConversionResult ConvertUTF8toUTF16( *sourceStart = source; *targetStart = target; - return result; } /* --------------------------------------------------------------------- */ -ConversionResult ConvertUTF32toUTF8 ( - const DWORD** sourceStart, const DWORD* sourceEnd, - BYTE** targetStart, BYTE* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const DWORD* source = *sourceStart; - BYTE* target = *targetStart; - while (source < sourceEnd) { - DWORD ch; - unsigned short bytesToWrite = 0; - const DWORD byteMask = 0xBF; - const DWORD byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (DWORD)0x80) { bytesToWrite = 1; - } else if (ch < (DWORD)0x800) { bytesToWrite = 2; - } else if (ch < (DWORD)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } +ConversionResult ConvertUTF32toUTF8( + const DWORD** sourceStart, const DWORD* sourceEnd, + BYTE** targetStart, BYTE* targetEnd, ConversionFlags flags) +{ + ConversionResult result = conversionOK; + const DWORD* source = *sourceStart; + BYTE* target = *targetStart; - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (BYTE)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (BYTE) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; + while (source < sourceEnd) + { + DWORD ch; + unsigned short bytesToWrite = 0; + const DWORD byteMask = 0xBF; + const DWORD byteMark = 0x80; + ch = *source++; + + if (flags == strictConversion) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (DWORD)0x80) + { + bytesToWrite = 1; + } + else if (ch < (DWORD)0x800) + { + bytesToWrite = 2; + } + else if (ch < (DWORD)0x10000) + { + bytesToWrite = 3; + } + else if (ch <= UNI_MAX_LEGAL_UTF32) + { + bytesToWrite = 4; + } + else + { + bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + + if (target > targetEnd) + { + --source; /* Back up source pointer! */ + target -= bytesToWrite; + result = targetExhausted; + break; + } + + switch (bytesToWrite) /* note: everything falls through. */ + { + case 4: + *--target = (BYTE)((ch | byteMark) & byteMask); + ch >>= 6; + + case 3: + *--target = (BYTE)((ch | byteMark) & byteMask); + ch >>= 6; + + case 2: + *--target = (BYTE)((ch | byteMark) & byteMask); + ch >>= 6; + + case 1: + *--target = (BYTE)(ch | firstByteMark[bytesToWrite]); + } + + target += bytesToWrite; + } + + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ -ConversionResult ConvertUTF8toUTF32 ( - const BYTE** sourceStart, const BYTE* sourceEnd, - DWORD** targetStart, DWORD* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const BYTE* source = *sourceStart; - DWORD* target = *targetStart; - while (source < sourceEnd) { - DWORD ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; +ConversionResult ConvertUTF8toUTF32( + const BYTE** sourceStart, const BYTE* sourceEnd, + DWORD** targetStart, DWORD* targetEnd, ConversionFlags flags) +{ + ConversionResult result = conversionOK; + const BYTE* source = *sourceStart; + DWORD* target = *targetStart; - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; + while (source < sourceEnd) + { + DWORD ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + + if (source + extraBytesToRead >= sourceEnd) + { + result = sourceExhausted; + break; + } + + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) + { + result = sourceIllegal; + break; + } + + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) + { + case 5: + ch += *source++; + ch <<= 6; + + case 4: + ch += *source++; + ch <<= 6; + + case 3: + ch += *source++; + ch <<= 6; + + case 2: + ch += *source++; + ch <<= 6; + + case 1: + ch += *source++; + ch <<= 6; + + case 0: + ch += *source++; + } + + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) + { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; + break; + } + + if (ch <= UNI_MAX_LEGAL_UTF32) + { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) + { + if (flags == strictConversion) + { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + else + { + *target++ = UNI_REPLACEMENT_CHAR; + } + } + else + { + *target++ = ch; + } + } + else /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + { + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt index 0c7cca6aa..c81b8f657 100644 --- a/winpr/libwinpr/crypto/CMakeLists.txt +++ b/winpr/libwinpr/crypto/CMakeLists.txt @@ -15,49 +15,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-crypto") -set(MODULE_PREFIX "WINPR_CRYPTO") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( crypto.c crypto.h cert.c) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -include_directories(${ZLIB_INCLUDE_DIRS}) -include_directories(${OPENSSL_INCLUDE_DIR}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${ZLIB_LIBRARIES} - ${OPENSSL_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-utils) - if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} crypt32) + winpr_library_add(crypt32) endif() -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/crypto/test/CMakeLists.txt b/winpr/libwinpr/crypto/test/CMakeLists.txt index 58a29cdb7..382831d1a 100644 --- a/winpr/libwinpr/crypto/test/CMakeLists.txt +++ b/winpr/libwinpr/crypto/test/CMakeLists.txt @@ -19,12 +19,7 @@ if(WIN32) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} secur32 crypt32 cryptui) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-crypto winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") @@ -34,4 +29,3 @@ foreach(test ${${MODULE_PREFIX}_TESTS}) endforeach() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") - diff --git a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c index 75b461adb..88b5077a3 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c +++ b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c @@ -2,6 +2,7 @@ #include #include #include +#include static const char* SECRET_PASSWORD_TEST = "MySecretPassword123!"; @@ -11,13 +12,10 @@ int TestCryptoProtectMemory(int argc, char* argv[]) int cbCipherText; char* pPlainText; BYTE* pCipherText; - pPlainText = (char*) SECRET_PASSWORD_TEST; cbPlainText = strlen(pPlainText) + 1; - cbCipherText = cbPlainText + (CRYPTPROTECTMEMORY_BLOCK_SIZE - (cbPlainText % CRYPTPROTECTMEMORY_BLOCK_SIZE)); printf("cbPlainText: %d cbCipherText: %d\n", cbPlainText, cbCipherText); - pCipherText = (BYTE*) malloc(cbCipherText); CopyMemory(pCipherText, pPlainText, cbPlainText); ZeroMemory(&pCipherText[cbPlainText], (cbCipherText - cbPlainText)); @@ -29,8 +27,7 @@ int TestCryptoProtectMemory(int argc, char* argv[]) } printf("PlainText: %s (cbPlainText = %d, cbCipherText = %d)\n", pPlainText, cbPlainText, cbCipherText); - - winpr_HexDump(pCipherText, cbCipherText); + winpr_HexDump("crypto.test", WLOG_DEBUG, pCipherText, cbCipherText); if (!CryptUnprotectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS)) { @@ -39,9 +36,7 @@ int TestCryptoProtectMemory(int argc, char* argv[]) } printf("Decrypted CipherText: %s\n", pCipherText); - SecureZeroMemory(pCipherText, cbCipherText); free(pCipherText); - return 0; } diff --git a/winpr/libwinpr/dsparse/CMakeLists.txt b/winpr/libwinpr/dsparse/CMakeLists.txt index 1567d82fc..0703523a7 100644 --- a/winpr/libwinpr/dsparse/CMakeLists.txt +++ b/winpr/libwinpr/dsparse/CMakeLists.txt @@ -15,36 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-dsparse") -set(MODULE_PREFIX "WINPR_DSPARSE") - -set(${MODULE_PREFIX}_SRCS - dsparse.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") +winpr_module_add(dsparse.c) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ntdsapi) + winpr_library_add(ntdsapi) endif() -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/dsparse/test/CMakeLists.txt b/winpr/libwinpr/dsparse/test/CMakeLists.txt index e7efe6513..eb7699d87 100644 --- a/winpr/libwinpr/dsparse/test/CMakeLists.txt +++ b/winpr/libwinpr/dsparse/test/CMakeLists.txt @@ -14,12 +14,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-dsparse) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/environment/CMakeLists.txt b/winpr/libwinpr/environment/CMakeLists.txt index 66c1c1b4b..53c28181a 100644 --- a/winpr/libwinpr/environment/CMakeLists.txt +++ b/winpr/libwinpr/environment/CMakeLists.txt @@ -15,36 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-environment") -set(MODULE_PREFIX "WINPR_ENVIRONMENT") - -set(${MODULE_PREFIX}_SRCS - environment.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-error) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(environment.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c index 2dc6087ee..f473bcd96 100644 --- a/winpr/libwinpr/environment/environment.c +++ b/winpr/libwinpr/environment/environment.c @@ -167,63 +167,6 @@ DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) return length; } -DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) -{ - int vLength = 0; - char* env = NULL; - const char * penvb = envBlock; - char *foundEquals; - int nLength, fLength, lpNameLength; - - if (!lpName || NULL == envBlock) - return 0; - - lpNameLength = strlen(lpName); - if (0 == lpNameLength) - return 0; - - while (*penvb && *(penvb+1)) - { - fLength = strlen(penvb); - foundEquals = strstr(penvb,"="); - if (foundEquals == NULL) - { - /* if no = sign is found the envBlock is broken */ - return 0; - } - nLength = foundEquals - penvb; - if (nLength != lpNameLength) - { - penvb += (fLength +1); - continue; - } -#ifdef _WIN32 - if (strnicmp(penvb,lpName,nLength) == 0) -#else - if (strncmp(penvb,lpName,nLength) == 0) -#endif - { - env = foundEquals + 1; - break; - } - penvb += (fLength +1); - } - - if (!env) - return 0; - - vLength = strlen(env); - - if ((vLength + 1 > nSize) || (!lpBuffer)) - return vLength + 1; - - CopyMemory(lpBuffer, env, vLength + 1); - - return vLength; -} - - - DWORD GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize) { return 0; @@ -248,38 +191,6 @@ BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue) return TRUE; } -BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR lpValue) -{ - int length; - char* envstr; - char* newEB; - - - if (!lpName) - return FALSE; - - if (lpValue) - { - length = strlen(lpName) + strlen(lpValue) + 2; /* +2 because of = and \0 */ - envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ - sprintf_s(envstr, length, "%s=%s", lpName, lpValue); - } - else - { - length = strlen(lpName) + 2; /* +2 because of = and \0 */ - envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ - sprintf_s(envstr, length, "%s=", lpName); - } - envstr[length] = '\0'; - newEB = MergeEnvironmentStrings((LPCSTR)*envBlock,envstr); - free(envstr); - if (*envBlock != NULL) - free(*envBlock); - *envBlock = newEB; - return TRUE; -} - - BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue) { return TRUE; @@ -342,137 +253,6 @@ LPCH GetEnvironmentStrings(VOID) return lpszEnvironmentBlock; } -LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge) -{ - - const char * cp; - char* p; - int offset; - int length; - const char* envp; - DWORD cchEnvironmentBlock; - LPCH lpszEnvironmentBlock; - const char **mergeStrings; - int mergeStringLenth; - int mergeArraySize = 128; - int run; - int mergeLength; - int foundMerge; - char * foundEquals; - // first build an char ** of the merge env strings - - mergeStrings = (LPCSTR*) malloc(mergeArraySize * sizeof(char *)); - ZeroMemory(mergeStrings,mergeArraySize * sizeof(char *)); - mergeStringLenth = 0; - - cp = merge; - while( *cp && *(cp+1)) { - length = strlen(cp); - if (mergeStringLenth == mergeArraySize ) { - mergeArraySize += 128; - mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char *)); - - } - mergeStrings[mergeStringLenth] = cp; - cp += length + 1; - mergeStringLenth++; - } - - offset = 0; - - cchEnvironmentBlock = 128; - lpszEnvironmentBlock = (LPCH) malloc(cchEnvironmentBlock * sizeof(CHAR)); - - envp = original; - - while ((original != NULL) && (*envp && *(envp+1))) - { - length = strlen(envp); - - while ((offset + length + 8) > cchEnvironmentBlock) - { - cchEnvironmentBlock *= 2; - lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); - } - - p = &(lpszEnvironmentBlock[offset]); - - // check if this value is in the mergeStrings - foundMerge = 0; - for (run = 0; run < mergeStringLenth; run ++) { - if (mergeStrings[run] == NULL) { - continue; - } - mergeLength =strlen(mergeStrings[run]); - foundEquals = strstr(mergeStrings[run],"="); - if (foundEquals == NULL) { - continue; - } -#ifdef _WIN32 - if (strnicmp(envp,mergeStrings[run],foundEquals - mergeStrings[run] + 1) == 0) { -#else - if (strncmp(envp,mergeStrings[run],foundEquals - mergeStrings[run] + 1) == 0) { -#endif - // found variable in merge list ... use this .... - if (*(foundEquals + 1) == '\0') { - // check if the argument is set ... if not remove variable ... - foundMerge = 1; - } else { - - while ((offset + mergeLength + 8) > cchEnvironmentBlock) - { - cchEnvironmentBlock *= 2; - lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); - } - foundMerge = 1; - CopyMemory(p, mergeStrings[run], mergeLength); - mergeStrings[run] = NULL; - p[mergeLength] = '\0'; - offset += (mergeLength + 1); - } - } - } - - - if (foundMerge == 0) { - CopyMemory(p, envp, length * sizeof(CHAR)); - p[length] = '\0'; - offset += (length + 1); - } - envp += (length +1); - } - - // now merge the not already merged env - for (run = 0; run < mergeStringLenth; run ++) { - if (mergeStrings[run] == NULL) { - continue; - } - - mergeLength =strlen(mergeStrings[run]); - - while ((offset + mergeLength + 8) > cchEnvironmentBlock) - { - cchEnvironmentBlock *= 2; - lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); - } - - p = &(lpszEnvironmentBlock[offset]); - - CopyMemory(p, mergeStrings[run], mergeLength); - mergeStrings[run] = NULL; - p[mergeLength] = '\0'; - offset += (mergeLength + 1); - } - - - lpszEnvironmentBlock[offset] = '\0'; - - free(mergeStrings); - - return lpszEnvironmentBlock; -} - - LPWCH GetEnvironmentStringsW(VOID) { return NULL; @@ -513,3 +293,256 @@ BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock) #endif +LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge) +{ + const char* cp; + char* p; + int offset; + int length; + const char* envp; + DWORD cchEnvironmentBlock; + LPCH lpszEnvironmentBlock; + const char** mergeStrings; + int mergeStringLength; + int mergeArraySize = 128; + int run; + int mergeLength; + int foundMerge; + char* foundEquals; + + mergeStrings = (LPCSTR*) calloc(mergeArraySize, sizeof(char*)); + + if (!mergeStrings) + return NULL; + + mergeStringLength = 0; + + cp = merge; + + while (*cp && *(cp + 1)) + { + length = strlen(cp); + + if (mergeStringLength == mergeArraySize) + { + mergeArraySize += 128; + mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char*)); + + if (!mergeStrings) + return NULL; + } + + mergeStrings[mergeStringLength] = cp; + cp += length + 1; + mergeStringLength++; + } + + offset = 0; + + cchEnvironmentBlock = 128; + lpszEnvironmentBlock = (LPCH) malloc(cchEnvironmentBlock * sizeof(CHAR)); + + if (!lpszEnvironmentBlock) + return NULL; + + envp = original; + + while ((original != NULL) && (*envp && *(envp+1))) + { + length = strlen(envp); + + while ((offset + length + 8) > cchEnvironmentBlock) + { + cchEnvironmentBlock *= 2; + lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); + + if (!lpszEnvironmentBlock) + return NULL; + } + + p = &(lpszEnvironmentBlock[offset]); + + // check if this value is in the mergeStrings + foundMerge = 0; + + for (run = 0; run < mergeStringLength; run ++) + { + if (!mergeStrings[run]) + continue; + + mergeLength = strlen(mergeStrings[run]); + foundEquals = strstr(mergeStrings[run], "="); + + if (!foundEquals) + continue; + + if (strncmp(envp, mergeStrings[run], foundEquals - mergeStrings[run] + 1) == 0) + { + // found variable in merge list ... use this .... + if (*(foundEquals + 1) == '\0') + { + // check if the argument is set ... if not remove variable ... + foundMerge = 1; + } + else + { + while ((offset + mergeLength + 8) > cchEnvironmentBlock) + { + cchEnvironmentBlock *= 2; + lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); + + if (!lpszEnvironmentBlock) + return NULL; + } + + foundMerge = 1; + CopyMemory(p, mergeStrings[run], mergeLength); + mergeStrings[run] = NULL; + p[mergeLength] = '\0'; + offset += (mergeLength + 1); + } + } + } + + if (foundMerge == 0) + { + CopyMemory(p, envp, length * sizeof(CHAR)); + p[length] = '\0'; + offset += (length + 1); + } + + envp += (length +1); + } + + // now merge the not already merged env + for (run = 0; run < mergeStringLength; run ++) + { + if (!mergeStrings[run]) + continue; + + mergeLength = strlen(mergeStrings[run]); + + while ((offset + mergeLength + 8) > cchEnvironmentBlock) + { + cchEnvironmentBlock *= 2; + lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR)); + + if (!lpszEnvironmentBlock) + return NULL; + } + + p = &(lpszEnvironmentBlock[offset]); + + CopyMemory(p, mergeStrings[run], mergeLength); + mergeStrings[run] = NULL; + p[mergeLength] = '\0'; + offset += (mergeLength + 1); + } + + lpszEnvironmentBlock[offset] = '\0'; + + free(mergeStrings); + + return lpszEnvironmentBlock; +} + +DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) +{ + int vLength = 0; + char* env = NULL; + char* foundEquals; + const char* penvb = envBlock; + int nLength, fLength, lpNameLength; + + if (!lpName || NULL == envBlock) + return 0; + + lpNameLength = strlen(lpName); + + if (lpNameLength < 1) + return 0; + + while (*penvb && *(penvb + 1)) + { + fLength = strlen(penvb); + foundEquals = strstr(penvb,"="); + + if (!foundEquals) + { + /* if no = sign is found the envBlock is broken */ + return 0; + } + + nLength = foundEquals - penvb; + + if (nLength != lpNameLength) + { + penvb += (fLength +1); + continue; + } + + if (strncmp(penvb, lpName, nLength) == 0) + { + env = foundEquals + 1; + break; + } + + penvb += (fLength +1); + } + + if (!env) + return 0; + + vLength = strlen(env); + + if ((vLength + 1 > nSize) || (!lpBuffer)) + return vLength + 1; + + CopyMemory(lpBuffer, env, vLength + 1); + + return vLength; +} + +BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue) +{ + int length; + char* envstr; + char* newEB; + + if (!lpName) + return FALSE; + + if (lpValue) + { + length = strlen(lpName) + strlen(lpValue) + 2; /* +2 because of = and \0 */ + envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ + + if (!envstr) + return FALSE; + + sprintf_s(envstr, length, "%s=%s", lpName, lpValue); + } + else + { + length = strlen(lpName) + 2; /* +2 because of = and \0 */ + envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ + + if (!envstr) + return FALSE; + + sprintf_s(envstr, length, "%s=", lpName); + } + + envstr[length] = '\0'; + + newEB = MergeEnvironmentStrings((LPCSTR) *envBlock, envstr); + + free(envstr); + + if (*envBlock) + free(*envBlock); + + *envBlock = newEB; + + return TRUE; +} diff --git a/winpr/libwinpr/environment/test/CMakeLists.txt b/winpr/libwinpr/environment/test/CMakeLists.txt index aee38e777..459d42528 100644 --- a/winpr/libwinpr/environment/test/CMakeLists.txt +++ b/winpr/libwinpr/environment/test/CMakeLists.txt @@ -16,12 +16,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-environment) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/error/CMakeLists.txt b/winpr/libwinpr/error/CMakeLists.txt index 795240802..a2401310d 100644 --- a/winpr/libwinpr/error/CMakeLists.txt +++ b/winpr/libwinpr/error/CMakeLists.txt @@ -15,36 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-error") -set(MODULE_PREFIX "WINPR_ERROR") - -set(${MODULE_PREFIX}_SRCS - error.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-nt) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(error.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/error/test/CMakeLists.txt b/winpr/libwinpr/error/test/CMakeLists.txt index ecec7093f..83b16e163 100644 --- a/winpr/libwinpr/error/test/CMakeLists.txt +++ b/winpr/libwinpr/error/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-thread winpr-error) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/file/CMakeLists.txt b/winpr/libwinpr/file/CMakeLists.txt index d374cab99..034d5c1c0 100644 --- a/winpr/libwinpr/file/CMakeLists.txt +++ b/winpr/libwinpr/file/CMakeLists.txt @@ -15,33 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-file") -set(MODULE_PREFIX "WINPR_FILE") - -set(${MODULE_PREFIX}_SRCS - file.c - pattern.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-handle winpr-path winpr-error winpr-synch) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(file.c pattern.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 1d339fe8c..3beb05221 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -3,6 +3,7 @@ * File Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +28,7 @@ #include #include #include +#include #include @@ -38,9 +40,12 @@ #include #endif +#include "../log.h" +#define TAG WINPR_TAG("file") + /** * api-ms-win-core-file-l1-2-0.dll: - * + * * CreateFileA * CreateFileW * CreateFile2 @@ -148,8 +153,10 @@ #include #endif +#include #include #include +#include #include #include #include @@ -184,13 +191,73 @@ #include "../pipe/pipe.h" +/* TODO: FIXME: use of a wArrayList and split winpr-utils with + * winpr-collections to avoid a circular dependency + * _HandleCreators = ArrayList_New(TRUE); + */ +/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ +#define HANDLE_CREATOR_MAX 128 +static HANDLE_CREATOR** _HandleCreators = NULL; +static CRITICAL_SECTION _HandleCreatorsLock; + +static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT; +static void _HandleCreatorsInit() +{ + /* NB: error management to be done outside of this function */ + assert(_HandleCreators == NULL); + _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*)); + InitializeCriticalSection(&_HandleCreatorsLock); + assert(_HandleCreators != NULL); +} + +/** + * Returns TRUE on success, FALSE otherwise. + * + * ERRORS: + * ERROR_DLL_INIT_FAILED + * ERROR_INSUFFICIENT_BUFFER _HandleCreators full + */ +BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator) +{ + int i; + + if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + if (_HandleCreators == NULL) + { + SetLastError(ERROR_DLL_INIT_FAILED); + return FALSE; + } + + EnterCriticalSection(&_HandleCreatorsLock); + + for (i=0; iIsHandled(lpFileName)) + { + HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + LeaveCriticalSection(&_HandleCreatorsLock); + return newHandle; + } + } + + LeaveCriticalSection(&_HandleCreatorsLock); + + /* TODO: use of a HANDLE_CREATOR for named pipes as well */ + + if (!IsNamedPipeFileNameA(lpFileName)) + return INVALID_HANDLE_VALUE; + name = GetNamedPipeNameWithoutPrefixA(lpFileName); if (!name) return INVALID_HANDLE_VALUE; free(name); - pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE)); hNamedPipe = (HANDLE) pNamedPipe; - WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); - pNamedPipe->name = _strdup(lpFileName); pNamedPipe->dwOpenMode = 0; pNamedPipe->dwPipeMode = 0; @@ -247,18 +342,14 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, pNamedPipe->nInBufferSize = 0; pNamedPipe->nDefaultTimeOut = 0; pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes; - pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); - pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); pNamedPipe->serverfd = -1; pNamedPipe->ServerMode = FALSE; - ZeroMemory(&s, sizeof(struct sockaddr_un)); s.sun_family = AF_UNIX; strcpy(s.sun_path, pNamedPipe->lpFilePath); - status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); if (status != 0) @@ -278,6 +369,7 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, if (flags != -1) fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK); + #endif } @@ -285,7 +377,7 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, } HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { return NULL; } @@ -293,9 +385,7 @@ HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, BOOL DeleteFileA(LPCSTR lpFileName) { int status; - status = unlink(lpFileName); - return (status != -1) ? TRUE : FALSE; } @@ -305,13 +395,14 @@ BOOL DeleteFileW(LPCWSTR lpFileName) } BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { ULONG Type; PVOID Object; BOOL status = TRUE; - if (hFile == INVALID_HANDLE_VALUE) { + if (hFile == INVALID_HANDLE_VALUE) + { return FALSE; } @@ -330,7 +421,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { int io_status; WINPR_PIPE* pipe; - pipe = (WINPR_PIPE*) Object; do @@ -360,7 +450,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { int io_status; WINPR_NAMED_PIPE* pipe; - pipe = (WINPR_NAMED_PIPE*) Object; if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)) @@ -388,6 +477,7 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, case EWOULDBLOCK: SetLastError(ERROR_NO_DATA); break; + default: SetLastError(ERROR_BROKEN_PIPE); break; @@ -399,7 +489,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, else { /* Overlapped I/O */ - if (!lpOverlapped) return FALSE; @@ -407,27 +496,21 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, return FALSE; pipe->lpOverlapped = lpOverlapped; - #ifdef HAVE_AIO_H { int aio_status; struct aiocb cb; - ZeroMemory(&cb, sizeof(struct aiocb)); cb.aio_fildes = pipe->clientfd; cb.aio_buf = lpBuffer; cb.aio_nbytes = nNumberOfBytesToRead; cb.aio_offset = lpOverlapped->Offset; - cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; cb.aio_sigevent.sigev_signo = SIGIO; cb.aio_sigevent.sigev_value.sival_ptr = (void*) lpOverlapped; - InstallAioSignalHandler(); - aio_status = aio_read(&cb); - - printf("aio_read status: %d\n", aio_status); + WLog_DBG(TAG, "aio_read status: %d", aio_status); if (aio_status < 0) status = FALSE; @@ -435,15 +518,11 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, return status; } #else - /* synchronous behavior */ - lpOverlapped->Internal = 0; lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToRead; lpOverlapped->Pointer = (PVOID) lpBuffer; - SetEvent(lpOverlapped->hEvent); - #endif } @@ -454,25 +533,26 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { return TRUE; } BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], - DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) { return TRUE; } BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { ULONG Type; PVOID Object; BOOL status = TRUE; - if (hFile == INVALID_HANDLE_VALUE) { + if (hFile == INVALID_HANDLE_VALUE) + { return FALSE; } @@ -483,7 +563,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, { int io_status; WINPR_PIPE* pipe; - pipe = (WINPR_PIPE*) Object; do @@ -496,14 +575,12 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, io_status = 0; *lpNumberOfBytesWritten = io_status; - return TRUE; } else if (Type == HANDLE_TYPE_NAMED_PIPE) { int io_status; WINPR_NAMED_PIPE* pipe; - pipe = (WINPR_NAMED_PIPE*) Object; if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)) @@ -523,12 +600,13 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, { *lpNumberOfBytesWritten = 0; - switch(errno) + switch (errno) { case EWOULDBLOCK: io_status = 0; status = TRUE; break; + default: status = FALSE; } @@ -540,7 +618,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, else { /* Overlapped I/O */ - if (!lpOverlapped) return FALSE; @@ -548,26 +625,20 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return FALSE; pipe->lpOverlapped = lpOverlapped; - #ifdef HAVE_AIO_H { struct aiocb cb; - ZeroMemory(&cb, sizeof(struct aiocb)); cb.aio_fildes = pipe->clientfd; cb.aio_buf = (void*) lpBuffer; cb.aio_nbytes = nNumberOfBytesToWrite; cb.aio_offset = lpOverlapped->Offset; - cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; cb.aio_sigevent.sigev_signo = SIGIO; cb.aio_sigevent.sigev_value.sival_ptr = (void*) lpOverlapped; - InstallAioSignalHandler(); - io_status = aio_write(&cb); - - printf("aio_write status: %d\n", io_status); + WLog_DBG("aio_write status: %d", io_status); if (io_status < 0) status = FALSE; @@ -575,15 +646,11 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return status; } #else - /* synchronous behavior */ - lpOverlapped->Internal = 1; lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToWrite; lpOverlapped->Pointer = (PVOID) lpBuffer; - SetEvent(lpOverlapped->hEvent); - #endif } @@ -594,13 +661,13 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, } BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { return TRUE; } BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], - DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) { return TRUE; } @@ -616,37 +683,37 @@ BOOL SetEndOfFile(HANDLE hFile) } DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, - PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) + PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { return TRUE; } BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) + PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { return TRUE; } BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh) + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh) { return TRUE; } BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, - DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) { return TRUE; } BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) + DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) { return TRUE; } BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, - DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped) { return TRUE; } @@ -667,14 +734,10 @@ HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) int length; struct stat fileStat; WIN32_FILE_SEARCH* pFileSearch; - ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA)); - pFileSearch = (WIN32_FILE_SEARCH*) malloc(sizeof(WIN32_FILE_SEARCH)); ZeroMemory(pFileSearch, sizeof(WIN32_FILE_SEARCH)); - /* Separate lpFileName into path and pattern components */ - p = strrchr(lpFileName, '/'); if (!p) @@ -685,7 +748,6 @@ HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) pFileSearch->lpPath = (LPSTR) malloc(length + 1); CopyMemory(pFileSearch->lpPath, lpFileName, length); pFileSearch->lpPath[length] = '\0'; - length = strlen(lpFileName) - index; pFileSearch->lpPattern = (LPSTR) malloc(length + 1); CopyMemory(pFileSearch->lpPattern, &lpFileName[index + 1], length); @@ -706,7 +768,6 @@ HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) } /* Open directory for reading */ - pFileSearch->pDir = opendir(pFileSearch->lpPath); if (!pFileSearch->pDir) @@ -740,13 +801,13 @@ HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) } HANDLE FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, - FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) + FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) { return NULL; } HANDLE FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, - FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) + FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags) { return NULL; } @@ -783,19 +844,20 @@ BOOL FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) BOOL FindClose(HANDLE hFindFile) { WIN32_FILE_SEARCH* pFileSearch; - pFileSearch = (WIN32_FILE_SEARCH*) hFindFile; if (pFileSearch) { if (pFileSearch->lpPath) free(pFileSearch->lpPath); + if (pFileSearch->lpPattern) free(pFileSearch->lpPattern); + if (pFileSearch->pDir) closedir(pFileSearch->pDir); - free(pFileSearch); + free(pFileSearch); return TRUE; } @@ -821,6 +883,14 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib #define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" +BOOL IsNamedPipeFileNameA(LPCSTR lpName) +{ + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return FALSE; + + return TRUE; +} + char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) { char* lpFileName; @@ -828,11 +898,10 @@ char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) if (!lpName) return NULL; - if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + if (!IsNamedPipeFileNameA(lpName)) return NULL; lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); - return lpFileName; } @@ -840,12 +909,9 @@ char* GetNamedPipeUnixDomainSocketBaseFilePathA() { char* lpTempPath; char* lpPipePath; - lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); - free(lpTempPath); - return lpPipePath; } @@ -854,15 +920,11 @@ char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) char* lpPipePath; char* lpFileName; char* lpFilePath; - lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); - lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); - free(lpPipePath); free(lpFileName); - return lpFilePath; } @@ -871,14 +933,12 @@ int GetNamePipeFileDescriptor(HANDLE hNamedPipe) #ifndef _WIN32 int fd; WINPR_NAMED_PIPE* pNamedPipe; - pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE) return -1; fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd; - return fd; #else return -1; @@ -889,7 +949,6 @@ int UnixChangeFileMode(const char* filename, int flags) { #ifndef _WIN32 mode_t fl = 0; - fl |= (flags & 0x4000) ? S_ISUID : 0; fl |= (flags & 0x2000) ? S_ISGID : 0; fl |= (flags & 0x1000) ? S_ISVTX : 0; @@ -902,7 +961,6 @@ int UnixChangeFileMode(const char* filename, int flags) fl |= (flags & 0x0004) ? S_IROTH : 0; fl |= (flags & 0x0002) ? S_IWOTH : 0; fl |= (flags & 0x0001) ? S_IXOTH : 0; - return chmod(filename, fl); #else return 0; diff --git a/winpr/libwinpr/file/pattern.c b/winpr/libwinpr/file/pattern.c index 8e158058b..ec4e18bb1 100644 --- a/winpr/libwinpr/file/pattern.c +++ b/winpr/libwinpr/file/pattern.c @@ -34,6 +34,9 @@ #include #endif +#include "../log.h" +#define TAG WINPR_TAG("file") + /** * File System Behavior in the Microsoft Windows Environment: * http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf @@ -42,7 +45,6 @@ LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags) { LPSTR lpWildcard; - *pFlags = 0; lpWildcard = strpbrk(lpPattern, "*?~"); @@ -82,7 +84,7 @@ LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags) } BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, - LPCSTR lpX, size_t cchX, LPCSTR lpY, size_t cchY, LPCSTR lpWildcard, LPSTR* ppMatchEnd) + LPCSTR lpX, size_t cchX, LPCSTR lpY, size_t cchY, LPCSTR lpWildcard, LPSTR* ppMatchEnd) { LPSTR lpMatch; @@ -101,7 +103,6 @@ BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, /* * State 0: match 'X' */ - if (_strnicmp(lpFileName, lpX, cchX) != 0) return FALSE; @@ -134,9 +135,7 @@ BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, /** * State 3: final state */ - *ppMatchEnd = (LPSTR) &lpMatch[cchY]; - return TRUE; } else if (*lpWildcard == '?') @@ -149,7 +148,6 @@ BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, /* * State 0: match 'X' */ - if (cchFileName < cchX) return FALSE; @@ -174,7 +172,7 @@ BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, if (_strnicmp(lpMatch, lpY, cchY) != 0) return FALSE; - } + } else { if ((cchX + 1) > cchFileName) @@ -186,15 +184,12 @@ BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, /** * State 3: final state */ - *ppMatchEnd = (LPSTR) &lpMatch[cchY]; - return TRUE; } else if (*lpWildcard == '~') { - fprintf(stderr, "warning: unimplemented '~' pattern match\n"); - + WLog_ERR(TAG, "warning: unimplemented '~' pattern match"); return TRUE; } @@ -264,7 +259,6 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) if (!FilePatternFindNextWildcardA(lpTail, &dwFlags)) { /* tail contains no wildcards */ - if (cchFileName < cchTail) return FALSE; @@ -308,7 +302,6 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) * ^EOF of .^ * */ - lpWildcard = FilePatternFindNextWildcardA(lpPattern, &dwFlags); if (lpWildcard) @@ -324,13 +317,10 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) size_t cchSubFileName; size_t cchWildcard; size_t cchNextWildcard; - cchSubPattern = cchPattern; lpSubPattern = (LPSTR) lpPattern; - cchSubFileName = cchFileName; lpSubFileName = (LPSTR) lpFileName; - cchWildcard = ((dwFlags & WILDCARD_DOS) ? 2 : 1); lpNextWildcard = FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags); @@ -338,13 +328,10 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) { lpX = (LPSTR) lpSubPattern; cchX = (lpWildcard - lpSubPattern); - lpY = (LPSTR) &lpSubPattern[cchX + cchWildcard]; cchY = (cchSubPattern - (lpY - lpSubPattern)); - match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, - lpX, cchX, lpY, cchY, lpWildcard, &lpMatchEnd); - + lpX, cchX, lpY, cchY, lpWildcard, &lpMatchEnd); return match; } else @@ -353,25 +340,20 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) { cchSubFileName = cchFileName - (lpSubFileName - lpFileName); cchNextWildcard = ((dwNextFlags & WILDCARD_DOS) ? 2 : 1); - lpX = (LPSTR) lpSubPattern; cchX = (lpWildcard - lpSubPattern); - lpY = (LPSTR) &lpSubPattern[cchX + cchWildcard]; cchY = (lpNextWildcard - lpWildcard) - cchWildcard; - match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, - lpX, cchX, lpY, cchY, lpWildcard, &lpMatchEnd); + lpX, cchX, lpY, cchY, lpWildcard, &lpMatchEnd); if (!match) return FALSE; lpSubFileName = lpMatchEnd; - cchWildcard = cchNextWildcard; lpWildcard = lpNextWildcard; dwFlags = dwNextFlags; - lpNextWildcard = FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags); } @@ -381,7 +363,6 @@ BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern) else { /* no wildcard characters */ - if (_stricmp(lpFileName, lpPattern) == 0) return TRUE; } diff --git a/winpr/libwinpr/file/test/CMakeLists.txt b/winpr/libwinpr/file/test/CMakeLists.txt index 3b88b7e71..f23bde6e9 100644 --- a/winpr/libwinpr/file/test/CMakeLists.txt +++ b/winpr/libwinpr/file/test/CMakeLists.txt @@ -20,12 +20,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-file winpr-path) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/handle/CMakeLists.txt b/winpr/libwinpr/handle/CMakeLists.txt index 93d112bcd..d58ff5a37 100644 --- a/winpr/libwinpr/handle/CMakeLists.txt +++ b/winpr/libwinpr/handle/CMakeLists.txt @@ -15,37 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-handle") -set(MODULE_PREFIX "WINPR_HANDLE") - -set(${MODULE_PREFIX}_SRCS - handle.c - handle.h) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS}) +winpr_module_add(handle.c handle.h) if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index a8b9d3fa4..a634eb7ab 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -25,9 +25,13 @@ #ifndef _WIN32 +#include +#include + #include "../synch/synch.h" #include "../thread/thread.h" #include "../pipe/pipe.h" +#include "../comm/comm.h" #include "../security/security.h" #ifdef HAVE_UNISTD_H @@ -38,48 +42,122 @@ #include "../handle/handle.h" +/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ +#define HANDLE_CLOSE_CB_MAX 128 +static HANDLE_CLOSE_CB** _HandleCloseCbs = NULL; +static CRITICAL_SECTION _HandleCloseCbsLock; + +static pthread_once_t _HandleCloseCbsInitialized = PTHREAD_ONCE_INIT; +static void _HandleCloseCbsInit() +{ + /* NB: error management to be done outside of this function */ + assert(_HandleCloseCbs == NULL); + _HandleCloseCbs = (HANDLE_CLOSE_CB**)calloc(HANDLE_CLOSE_CB_MAX+1, sizeof(HANDLE_CLOSE_CB*)); + InitializeCriticalSection(&_HandleCloseCbsLock); + assert(_HandleCloseCbs != NULL); +} + +/** + * Returns TRUE on success, FALSE otherwise. + */ +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB* pHandleCloseCb) +{ + int i; + + if (pthread_once(&_HandleCloseCbsInitialized, _HandleCloseCbsInit) != 0) + { + return FALSE; + } + + if (_HandleCloseCbs == NULL) + { + return FALSE; + } + + EnterCriticalSection(&_HandleCloseCbsLock); + + for (i=0; iIsHandled(hObject)) + { + BOOL result = close_cb->CloseHandle(hObject); + LeaveCriticalSection(&_HandleCloseCbsLock); + return result; + } + } + + LeaveCriticalSection(&_HandleCloseCbsLock); + if (Type == HANDLE_TYPE_THREAD) { WINPR_THREAD* thread; - thread = (WINPR_THREAD*) Object; - free(thread); + if (thread->started) + { + pthread_detach(thread->thread); + } + + free(thread); return TRUE; } else if (Type == HANDLE_TYPE_PROCESS) { WINPR_PROCESS* process; - process = (WINPR_PROCESS*) Object; free(process); - return TRUE; } else if (Type == HANDLE_TYPE_MUTEX) { WINPR_MUTEX* mutex; - mutex = (WINPR_MUTEX*) Object; - pthread_mutex_destroy(&mutex->mutex); - free(Object); - return TRUE; } else if (Type == HANDLE_TYPE_EVENT) { WINPR_EVENT* event; - event = (WINPR_EVENT*) Object; if (!event->bAttached) @@ -89,6 +167,7 @@ BOOL CloseHandle(HANDLE hObject) close(event->pipe_fd[0]); event->pipe_fd[0] = -1; } + if (event->pipe_fd[1] != -1) { close(event->pipe_fd[1]); @@ -97,15 +176,12 @@ BOOL CloseHandle(HANDLE hObject) } free(Object); - return TRUE; } else if (Type == HANDLE_TYPE_SEMAPHORE) { WINPR_SEMAPHORE* semaphore; - semaphore = (WINPR_SEMAPHORE*) Object; - #ifdef WINPR_PIPE_SEMAPHORE if (semaphore->pipe_fd[0] != -1) @@ -121,37 +197,31 @@ BOOL CloseHandle(HANDLE hObject) } #else - #if defined __APPLE__ semaphore_destroy(mach_task_self(), *((winpr_sem_t*) semaphore->sem)); #else sem_destroy((winpr_sem_t*) semaphore->sem); #endif - #endif free(Object); - return TRUE; } else if (Type == HANDLE_TYPE_TIMER) { WINPR_TIMER* timer; - timer = (WINPR_TIMER*) Object; - #ifdef __linux__ + if (timer->fd != -1) close(timer->fd); + #endif - free(Object); - return TRUE; } else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { WINPR_PIPE* pipe; - pipe = (WINPR_PIPE*) Object; if (pipe->fd != -1) @@ -160,19 +230,21 @@ BOOL CloseHandle(HANDLE hObject) } free(Object); - return TRUE; } else if (Type == HANDLE_TYPE_NAMED_PIPE) { WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*) Object; - if (pNamedPipe->clientfd != -1) { - //fprintf(stderr, "%s: closing clientfd %d\n", __FUNCTION__, pNamedPipe->clientfd); + if (pNamedPipe->clientfd != -1) + { + //WLOG_DBG(TAG, "%s: closing clientfd %d\n", __FUNCTION__, pNamedPipe->clientfd); close(pNamedPipe->clientfd); } - if (pNamedPipe->serverfd != -1) { - //fprintf(stderr, "%s: closing serverfd %d\n", __FUNCTION__, pNamedPipe->serverfd); + + if (pNamedPipe->serverfd != -1) + { + //WLOG_DBG(TAG, "%s: closing serverfd %d\n", __FUNCTION__, pNamedPipe->serverfd); close(pNamedPipe->serverfd); } @@ -183,13 +255,11 @@ BOOL CloseHandle(HANDLE hObject) free((void*)pNamedPipe->lpFilePath); free((void*)pNamedPipe->name); free(pNamedPipe); - return TRUE; } else if (Type == HANDLE_TYPE_ACCESS_TOKEN) { WINPR_ACCESS_TOKEN* token; - token = (WINPR_ACCESS_TOKEN*) Object; if (token->Username) @@ -199,14 +269,16 @@ BOOL CloseHandle(HANDLE hObject) free(token->Domain); free(token); + return TRUE; } return FALSE; } BOOL DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, - LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) + LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) { + *((ULONG_PTR*) lpTargetHandle) = (ULONG_PTR) hSourceHandle; return TRUE; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 2537a5e13..91a3e9452 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -36,6 +36,7 @@ #define HANDLE_TYPE_FILE 10 #define HANDLE_TYPE_TIMER_QUEUE 11 #define HANDLE_TYPE_TIMER_QUEUE_TIMER 12 +#define HANDLE_TYPE_COMM 13 #define WINPR_HANDLE_DEF() \ ULONG Type @@ -49,7 +50,7 @@ typedef struct winpr_handle WINPR_HANDLE; #define WINPR_HANDLE_SET_TYPE(_handle, _type) \ _handle->Type = _type -static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObject) +static INLINE BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObject) { WINPR_HANDLE* wHandle; @@ -64,4 +65,15 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj return TRUE; } +typedef BOOL (*pcIsHandled)(HANDLE handle); +typedef BOOL (*pcCloseHandle)(HANDLE handle); + +typedef struct _HANDLE_CLOSE_CB +{ + pcIsHandled IsHandled; + pcCloseHandle CloseHandle; +} HANDLE_CLOSE_CB; + +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleClose); + #endif /* WINPR_HANDLE_PRIVATE_H */ diff --git a/winpr/libwinpr/heap/CMakeLists.txt b/winpr/libwinpr/heap/CMakeLists.txt index 40d69e2c0..4c44bab22 100644 --- a/winpr/libwinpr/heap/CMakeLists.txt +++ b/winpr/libwinpr/heap/CMakeLists.txt @@ -15,27 +15,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-heap") -set(MODULE_PREFIX "WINPR_HEAP") - -set(${MODULE_PREFIX}_SRCS - heap.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(heap.c) diff --git a/winpr/libwinpr/input/CMakeLists.txt b/winpr/libwinpr/input/CMakeLists.txt index 5913c29a1..b23754a60 100644 --- a/winpr/libwinpr/input/CMakeLists.txt +++ b/winpr/libwinpr/input/CMakeLists.txt @@ -15,32 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-input") -set(MODULE_PREFIX "WINPR_INPUT") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( virtualkey.c scancode.c keycode.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - diff --git a/winpr/libwinpr/interlocked/CMakeLists.txt b/winpr/libwinpr/interlocked/CMakeLists.txt index aa8a2948a..7f164151c 100644 --- a/winpr/libwinpr/interlocked/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/CMakeLists.txt @@ -15,40 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-interlocked") -set(MODULE_PREFIX "WINPR_INTERLOCKED") - -set(${MODULE_PREFIX}_SRCS - interlocked.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - if (${CMAKE_SYSTEM_VERSION} GREATER "5.1") - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) - else() - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module_5.1.def) - endif() -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-handle) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(interlocked.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/interlocked/interlocked.c b/winpr/libwinpr/interlocked/interlocked.c index 044c36684..6490bb6f1 100644 --- a/winpr/libwinpr/interlocked/interlocked.c +++ b/winpr/libwinpr/interlocked/interlocked.c @@ -234,13 +234,22 @@ LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG #endif } +PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination, PVOID Exchange, PVOID Comperand) +{ +#ifdef __GNUC__ + return __sync_val_compare_and_swap(Destination, Comperand, Exchange); +#else + return 0; +#endif +} + #endif /* _WIN32 */ -#if defined(_WIN64) +#if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64) /* InterlockedCompareExchange64 already defined */ -#elif (_WIN32 && (_WIN32_WINNT < 0x0502)) +#elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64) static volatile HANDLE mutex = NULL; @@ -249,7 +258,7 @@ int static_mutex_lock(volatile HANDLE* static_mutex) if (*static_mutex == NULL) { HANDLE handle = CreateMutex(NULL, FALSE, NULL); - + if (InterlockedCompareExchangePointer((PVOID*) static_mutex, (PVOID) handle, NULL) != NULL) CloseHandle(handle); } @@ -257,8 +266,6 @@ int static_mutex_lock(volatile HANDLE* static_mutex) return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_FAILED); } -/* Not available in XP */ - LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG Exchange, LONGLONG Comperand) { LONGLONG previousValue = 0; @@ -275,7 +282,7 @@ LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG E return previousValue; } -#elif ANDROID || (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) +#elif (defined(ANDROID) && ANDROID) || (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) #include diff --git a/winpr/libwinpr/interlocked/test/CMakeLists.txt b/winpr/libwinpr/interlocked/test/CMakeLists.txt index 8b20b7bb4..116641080 100644 --- a/winpr/libwinpr/interlocked/test/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/test/CMakeLists.txt @@ -15,12 +15,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-interlocked) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/io/CMakeLists.txt b/winpr/libwinpr/io/CMakeLists.txt index 1100af791..c7050d4a3 100644 --- a/winpr/libwinpr/io/CMakeLists.txt +++ b/winpr/libwinpr/io/CMakeLists.txt @@ -15,38 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-io") -set(MODULE_PREFIX "WINPR_IO") - -set(${MODULE_PREFIX}_SRCS - device.c - io.c - io.h) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-path) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(device.c io.c io.h) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/io/test/CMakeLists.txt b/winpr/libwinpr/io/test/CMakeLists.txt index 2de6e7ef7..96c484820 100644 --- a/winpr/libwinpr/io/test/CMakeLists.txt +++ b/winpr/libwinpr/io/test/CMakeLists.txt @@ -14,12 +14,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-io winpr-nt) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/library/CMakeLists.txt b/winpr/libwinpr/library/CMakeLists.txt index cebaa144d..9db7d0d13 100644 --- a/winpr/libwinpr/library/CMakeLists.txt +++ b/winpr/libwinpr/library/CMakeLists.txt @@ -15,33 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-library") -set(MODULE_PREFIX "WINPR_LIBRARY") - -set(${MODULE_PREFIX}_SRCS - library.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(library.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/library/library.c b/winpr/libwinpr/library/library.c index 4d9d3716b..c714dbd00 100644 --- a/winpr/libwinpr/library/library.c +++ b/winpr/libwinpr/library/library.c @@ -26,6 +26,9 @@ #include +#include "../log.h" +#define TAG WINPR_TAG("library") + /** * api-ms-win-core-libraryloader-l1-1-1.dll: * @@ -92,12 +95,11 @@ BOOL SetDefaultDllDirectories(DWORD DirectoryFlags) HMODULE LoadLibraryA(LPCSTR lpLibFileName) { HMODULE library; - library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY); if (!library) { - fprintf(stderr, "LoadLibraryA: %s\n", dlerror()); + WLog_ERR(TAG, "LoadLibraryA: %s", dlerror()); return NULL; } @@ -112,12 +114,11 @@ HMODULE LoadLibraryW(LPCWSTR lpLibFileName) HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HMODULE library; - library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY); if (!library) { - fprintf(stderr, "LoadLibraryExA: failed to open %s: %s\n", lpLibFileName, dlerror()); + WLog_ERR(TAG, "LoadLibraryExA: failed to open %s: %s", lpLibFileName, dlerror()); return NULL; } @@ -132,12 +133,11 @@ HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName) { FARPROC proc; - proc = dlsym(hModule, lpProcName); if (proc == NULL) { - fprintf(stderr, "GetProcAddress: could not find procedure %s: %s\n", lpProcName, dlerror()); + WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror()); return (FARPROC) NULL; } @@ -147,7 +147,6 @@ FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName) BOOL FreeLibrary(HMODULE hLibModule) { int status; - status = dlclose(hLibModule); if (status != 0) @@ -180,7 +179,7 @@ DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) } DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) -{ +{ #if defined(__linux__) int status; int length; @@ -189,16 +188,13 @@ DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) if (!hModule) { char buffer[4096]; - sprintf(path, "/proc/%d/exe", getpid()); - status = readlink(path, buffer, sizeof(buffer)); if (status < 0) return 0; buffer[status] = '\0'; - length = strlen(buffer); if (length < nSize) @@ -214,33 +210,31 @@ DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) return 0; } + #elif defined(__MACOSX__) int status; int length; - + if (!hModule) { char path[4096]; char buffer[4096]; uint32_t size = sizeof(path); - status = _NSGetExecutablePath(path, &size); - + if (status != 0) { /* path too small */ return 0; } - + /* * _NSGetExecutablePath may not return the canonical path, * so use realpath to find the absolute, canonical path. */ - realpath(path, buffer); - length = strlen(buffer); - + if (length < nSize) { CopyMemory(lpFilename, buffer, length); @@ -251,11 +245,11 @@ DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) CopyMemory(lpFilename, buffer, nSize - 1); lpFilename[nSize - 1] = '\0'; } - + return 0; } -#endif +#endif return 0; } diff --git a/winpr/libwinpr/library/test/CMakeLists.txt b/winpr/libwinpr/library/test/CMakeLists.txt index f49956c98..2962663c2 100644 --- a/winpr/libwinpr/library/test/CMakeLists.txt +++ b/winpr/libwinpr/library/test/CMakeLists.txt @@ -19,12 +19,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-library winpr-path) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/locale/CMakeLists.txt b/winpr/libwinpr/locale/CMakeLists.txt index 6b1ee22fd..826ea68c9 100644 --- a/winpr/libwinpr/locale/CMakeLists.txt +++ b/winpr/libwinpr/locale/CMakeLists.txt @@ -15,36 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-locale") -set(MODULE_PREFIX "WINPR_LOCALE") - -set(${MODULE_PREFIX}_SRCS - locale.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") +winpr_module_add(locale.c) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ntdsapi) + winpr_library_add(ntdsapi) endif() -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/locale/test/CMakeLists.txt b/winpr/libwinpr/locale/test/CMakeLists.txt index 33025b56b..47b94f5e2 100644 --- a/winpr/libwinpr/locale/test/CMakeLists.txt +++ b/winpr/libwinpr/locale/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-locale) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/client/Windows/wf_window.h b/winpr/libwinpr/log.h similarity index 73% rename from client/Windows/wf_window.h rename to winpr/libwinpr/log.h index 5db681525..f11fd68b7 100644 --- a/client/Windows/wf_window.h +++ b/winpr/libwinpr/log.h @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Windows RAIL + * Winpr log defines * - * Copyright 2012 Jason Champion + * Copyright 2014 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,11 @@ * limitations under the License. */ -#ifndef __WF_WINDOW_H -#define __WF_WINDOW_H +#ifndef WINPR_LOG_PRIV_H +#define WINPR_LOG_PRIV_H -#include +#include -#include "wf_interface.h" +#define WINPR_TAG(tag) "com.winpr." tag -#endif +#endif /* FREERDP_UTILS_DEBUG_H */ diff --git a/winpr/libwinpr/memory/CMakeLists.txt b/winpr/libwinpr/memory/CMakeLists.txt index 02139b575..5e28d3c1e 100644 --- a/winpr/libwinpr/memory/CMakeLists.txt +++ b/winpr/libwinpr/memory/CMakeLists.txt @@ -15,37 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-memory") -set(MODULE_PREFIX "WINPR_MEMORY") - -set(${MODULE_PREFIX}_SRCS - memory.c - memory.h) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(memory.c memory.h) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/memory/test/CMakeLists.txt b/winpr/libwinpr/memory/test/CMakeLists.txt index b143d3f82..861ef6c03 100644 --- a/winpr/libwinpr/memory/test/CMakeLists.txt +++ b/winpr/libwinpr/memory/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/nt/CMakeLists.txt b/winpr/libwinpr/nt/CMakeLists.txt index 89698ab31..e2988cf42 100644 --- a/winpr/libwinpr/nt/CMakeLists.txt +++ b/winpr/libwinpr/nt/CMakeLists.txt @@ -15,45 +15,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-nt") -set(MODULE_PREFIX "WINPR_NT") +winpr_module_add(nt.c) -set(${MODULE_PREFIX}_SRCS - nt.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS +winpr_library_add( ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/nt/nt.c b/winpr/libwinpr/nt/nt.c index d4fbafb31..40769f6f4 100644 --- a/winpr/libwinpr/nt/nt.c +++ b/winpr/libwinpr/nt/nt.c @@ -366,6 +366,8 @@ typedef NTSTATUS (WINAPI * NT_DEVICE_IO_CONTROL_FILE_FN)(HANDLE FileHandle, HAND typedef NTSTATUS (WINAPI * NT_CLOSE_FN)(HANDLE Handle); +typedef NTSTATUS (WINAPI * NT_WAIT_FOR_SINGLE_OBJECT_FN)(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout); + static RTL_INIT_ANSI_STRING_FN pRtlInitAnsiString = NULL; static RTL_INIT_UNICODE_STRING_FN pRtlInitUnicodeString = NULL; static RTL_ANSI_STRING_TO_UNICODE_STRING_FN pRtlAnsiStringToUnicodeString = NULL; @@ -377,6 +379,7 @@ static NT_READ_FILE_FN pNtReadFile = NULL; static NT_WRITE_FILE_FN pNtWriteFile = NULL; static NT_DEVICE_IO_CONTROL_FILE_FN pNtDeviceIoControlFile = NULL; static NT_CLOSE_FN pNtClose = NULL; +static NT_WAIT_FOR_SINGLE_OBJECT_FN pNtWaitForSingleObject = NULL; static void NtdllModuleInit() { @@ -402,6 +405,7 @@ static void NtdllModuleInit() pNtWriteFile = (NT_WRITE_FILE_FN) GetProcAddress(NtdllModule, "NtWriteFile"); pNtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE_FN) GetProcAddress(NtdllModule, "NtDeviceIoControlFile"); pNtClose = (NT_CLOSE_FN) GetProcAddress(NtdllModule, "NtClose"); + pNtWaitForSingleObject = (NT_WAIT_FOR_SINGLE_OBJECT_FN) GetProcAddress(NtdllModule, "NtWaitForSingleObject"); } VOID _RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString) @@ -533,5 +537,15 @@ NTSTATUS _NtClose(HANDLE Handle) return pNtClose(Handle); } +NTSTATUS _NtWaitForSingleObject(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout) +{ + NtdllModuleInit(); + + if (!pNtWaitForSingleObject) + return STATUS_INTERNAL_ERROR; + + return pNtWaitForSingleObject(Handle, Alertable, Timeout); +} + #endif diff --git a/winpr/libwinpr/nt/test/CMakeLists.txt b/winpr/libwinpr/nt/test/CMakeLists.txt index b3fcb8bab..6e26faea3 100644 --- a/winpr/libwinpr/nt/test/CMakeLists.txt +++ b/winpr/libwinpr/nt/test/CMakeLists.txt @@ -14,12 +14,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-nt) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/path/CMakeLists.txt b/winpr/libwinpr/path/CMakeLists.txt index 9342f4d54..dd8393ae6 100644 --- a/winpr/libwinpr/path/CMakeLists.txt +++ b/winpr/libwinpr/path/CMakeLists.txt @@ -15,33 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-path") -set(MODULE_PREFIX "WINPR_PATH") - -set(${MODULE_PREFIX}_SRCS - path.c - shell.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-heap winpr-environment) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(path.c shell.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/path/shell.c b/winpr/libwinpr/path/shell.c index 10f7b7d9d..d66a18b95 100644 --- a/winpr/libwinpr/path/shell.c +++ b/winpr/libwinpr/path/shell.c @@ -271,6 +271,39 @@ char* GetKnownSubPath(int id, const char* path) return subPath; } +char* GetEnvironmentPath(char* name) +{ + char* env = NULL; + DWORD nSize; + + nSize = GetEnvironmentVariableA(name, NULL, 0); + + if (nSize) + { + env = (LPSTR) malloc(nSize); + nSize = GetEnvironmentVariableA(name, env, nSize); + } + + return env; +} + +char* GetEnvironmentSubPath(char* name, const char* path) +{ + char* env; + char* subpath; + + env = GetEnvironmentPath(name); + + if (!env) + return NULL; + + subpath = GetCombinedPath(env, path); + + free(env); + + return subpath; +} + char* GetCombinedPath(const char* basePath, const char* subPath) { int length; @@ -309,8 +342,6 @@ char* GetCombinedPath(const char* basePath, const char* subPath) return path; } -//#ifndef _WIN32 - BOOL PathFileExistsA(LPCSTR pszPath) { struct stat stat_info; @@ -326,4 +357,3 @@ BOOL PathFileExistsW(LPCWSTR pszPath) return FALSE; } -//#endif diff --git a/winpr/libwinpr/path/test/CMakeLists.txt b/winpr/libwinpr/path/test/CMakeLists.txt index 6f9120af3..8d0bc0ac9 100644 --- a/winpr/libwinpr/path/test/CMakeLists.txt +++ b/winpr/libwinpr/path/test/CMakeLists.txt @@ -35,12 +35,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-path) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/pipe/CMakeLists.txt b/winpr/libwinpr/pipe/CMakeLists.txt index 4b2f53263..a78b98af3 100644 --- a/winpr/libwinpr/pipe/CMakeLists.txt +++ b/winpr/libwinpr/pipe/CMakeLists.txt @@ -15,37 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-pipe") -set(MODULE_PREFIX "WINPR_PIPE") - -set(${MODULE_PREFIX}_SRCS - pipe.c - pipe.h) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-synch winpr-handle winpr-file) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(pipe.c pipe.h) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index c232d79e1..5c4f012aa 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -45,6 +45,9 @@ #include "pipe.h" +#include "../log.h" +#define TAG WINPR_TAG("pipe") + /* * Since the WinPR implementation of named pipes makes use of UNIX domain * sockets, it is not possible to bind the same name more than once (i.e., @@ -85,13 +88,12 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP int pipe_fd[2]; WINPR_PIPE* pReadPipe; WINPR_PIPE* pWritePipe; - pipe_fd[0] = -1; pipe_fd[1] = -1; if (pipe(pipe_fd) < 0) { - printf("CreatePipe: failed to create pipe\n"); + WLog_ERR(TAG, "failed to create pipe"); return FALSE; } @@ -111,13 +113,10 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP pReadPipe->fd = pipe_fd[0]; pWritePipe->fd = pipe_fd[1]; - WINPR_HANDLE_SET_TYPE(pReadPipe, HANDLE_TYPE_ANONYMOUS_PIPE); *((ULONG_PTR*) hReadPipe) = (ULONG_PTR) pReadPipe; - WINPR_HANDLE_SET_TYPE(pWritePipe, HANDLE_TYPE_ANONYMOUS_PIPE); *((ULONG_PTR*) hWritePipe) = (ULONG_PTR) pWritePipe; - return TRUE; } @@ -128,43 +127,46 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe) { int index; - NamedPipeServerSocketEntry *baseSocket; + NamedPipeServerSocketEntry* baseSocket; if (!pNamedPipe) return; assert(pNamedPipe->name); assert(g_NamedPipeServerSockets); - - //fprintf(stderr, "%s: %p (%s)\n", __FUNCTION__, pNamedPipe, pNamedPipe->name); - + //WLog_VRB(TAG, "%s: %p (%s)", __FUNCTION__, pNamedPipe, pNamedPipe->name); ArrayList_Lock(g_NamedPipeServerSockets); + for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++) { baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem( - g_NamedPipeServerSockets, index); + g_NamedPipeServerSockets, index); assert(baseSocket->name); + if (!strcmp(baseSocket->name, pNamedPipe->name)) { assert(baseSocket->references > 0); assert(baseSocket->serverfd != -1); + if (--baseSocket->references == 0) { - //fprintf(stderr, "%s: removing shared server socked resource\n", __FUNCTION__); - //fprintf(stderr, "%s: closing shared serverfd %d\n", __FUNCTION__, baseSocket->serverfd); + //WLog_DBG(TAG, "%s: removing shared server socked resource", __FUNCTION__); + //WLog_DBG(TAG, "%s: closing shared serverfd %d", __FUNCTION__, baseSocket->serverfd); ArrayList_Remove(g_NamedPipeServerSockets, baseSocket); close(baseSocket->serverfd); free(baseSocket->name); free(baseSocket); } + break; } } + ArrayList_Unlock(g_NamedPipeServerSockets); } HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, - DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { int index; HANDLE hNamedPipe = INVALID_HANDLE_VALUE; @@ -172,23 +174,24 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD struct sockaddr_un s; WINPR_NAMED_PIPE* pNamedPipe = NULL; int serverfd = -1; - NamedPipeServerSocketEntry *baseSocket = NULL; + NamedPipeServerSocketEntry* baseSocket = NULL; if (!lpName) return INVALID_HANDLE_VALUE; InitWinPRPipeModule(); - pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE)); - WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); if (!(pNamedPipe->name = _strdup(lpName))) goto out; + if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName))) goto out; + if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName))) goto out; + pNamedPipe->dwOpenMode = dwOpenMode; pNamedPipe->dwPipeMode = dwPipeMode; pNamedPipe->nMaxInstances = nMaxInstances; @@ -196,20 +199,19 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD pNamedPipe->nInBufferSize = nInBufferSize; pNamedPipe->nDefaultTimeOut = nDefaultTimeOut; pNamedPipe->dwFlagsAndAttributes = dwOpenMode; - pNamedPipe->clientfd = -1; pNamedPipe->ServerMode = TRUE; - ArrayList_Lock(g_NamedPipeServerSockets); for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++) { baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem( - g_NamedPipeServerSockets, index); + g_NamedPipeServerSockets, index); + if (!strcmp(baseSocket->name, lpName)) { serverfd = baseSocket->serverfd; - //fprintf(stderr, "using shared socked resource for pipe %p (%s)\n", pNamedPipe, lpName); + //WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", pNamedPipe, lpName); break; } } @@ -236,7 +238,7 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - fprintf(stderr, "CreateNamedPipeA: socket error, %s\n", strerror(errno)); + WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s", strerror(errno)); goto out; } @@ -246,34 +248,35 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD if (bind(serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)) == -1) { - fprintf(stderr, "CreateNamedPipeA: bind error, %s\n", strerror(errno)); + WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s", strerror(errno)); goto out; } if (listen(serverfd, 2) == -1) { - fprintf(stderr, "CreateNamedPipeA: listen error, %s\n", strerror(errno)); + WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s", strerror(errno)); goto out; } UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF); - if (!(baseSocket = (NamedPipeServerSocketEntry *) malloc(sizeof(NamedPipeServerSocketEntry)))) + if (!(baseSocket = (NamedPipeServerSocketEntry*) malloc(sizeof(NamedPipeServerSocketEntry)))) goto out; + if (!(baseSocket->name = _strdup(lpName))) { free(baseSocket); goto out; } + baseSocket->serverfd = serverfd; baseSocket->references = 0; ArrayList_Add(g_NamedPipeServerSockets, baseSocket); - //fprintf(stderr, "created shared socked resource for pipe %p (%s). base serverfd = %d\n", pNamedPipe, lpName, serverfd); - + //WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d", pNamedPipe, lpName, serverfd); } pNamedPipe->serverfd = dup(baseSocket->serverfd); - //fprintf(stderr, "using serverfd %d (duplicated from %d)\n", pNamedPipe->serverfd, baseSocket->serverfd); + //WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd, baseSocket->serverfd); pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe; baseSocket->references++; @@ -284,12 +287,13 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD if (flags != -1) fcntl(pNamedPipe->serverfd, F_SETFL, flags | O_NONBLOCK); + #endif } hNamedPipe = (HANDLE) pNamedPipe; - out: + if (hNamedPipe == INVALID_HANDLE_VALUE) { if (pNamedPipe) @@ -299,15 +303,17 @@ out: free((void*)pNamedPipe->lpFilePath); free(pNamedPipe); } + if (serverfd != -1) close(serverfd); } + ArrayList_Unlock(g_NamedPipeServerSockets); return hNamedPipe; } HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, - DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { return NULL; } @@ -328,12 +334,11 @@ BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) { length = sizeof(struct sockaddr_un); ZeroMemory(&s, sizeof(struct sockaddr_un)); - status = accept(pNamedPipe->serverfd, (struct sockaddr*) &s, &length); if (status < 0) { - fprintf(stderr, "ConnectNamedPipe: accept error\n"); + WLog_ERR(TAG, "ConnectNamedPipe: accept error"); return FALSE; } @@ -349,13 +354,10 @@ BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) return FALSE; pNamedPipe->lpOverlapped = lpOverlapped; - /* synchronous behavior */ - lpOverlapped->Internal = 2; lpOverlapped->InternalHigh = (ULONG_PTR) 0; lpOverlapped->Pointer = (PVOID) NULL; - SetEvent(lpOverlapped->hEvent); } @@ -365,7 +367,6 @@ BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) BOOL DisconnectNamedPipe(HANDLE hNamedPipe) { WINPR_NAMED_PIPE* pNamedPipe; - pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; if (pNamedPipe->clientfd != -1) @@ -378,14 +379,16 @@ BOOL DisconnectNamedPipe(HANDLE hNamedPipe) } BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, - LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage) + LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage) { + WLog_ERR(TAG, "Not implemented"); return TRUE; } BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped) + DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped) { + WLog_ERR(TAG, "Not implemented"); return TRUE; } @@ -419,12 +422,14 @@ BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut) break; } } + free(lpFilePath); return status; } BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut) { + WLog_ERR(TAG, "Not implemented"); return TRUE; } @@ -433,13 +438,11 @@ BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCol int fd; int flags; WINPR_NAMED_PIPE* pNamedPipe; - pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; if (lpMode) { pNamedPipe->dwPipeMode = *lpMode; - fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd; if (fd == -1) @@ -457,12 +460,10 @@ BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCol if (lpMaxCollectionCount) { - } if (lpCollectDataTimeout) { - } return TRUE; @@ -470,16 +471,19 @@ BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCol BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe) { + WLog_ERR(TAG, "Not implemented"); return FALSE; } BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength) { + WLog_ERR(TAG, "Not implemented"); return FALSE; } BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength) { + WLog_ERR(TAG, "Not implemented"); return FALSE; } diff --git a/winpr/libwinpr/pipe/test/CMakeLists.txt b/winpr/libwinpr/pipe/test/CMakeLists.txt index c7b9b5a3d..b9bf68560 100644 --- a/winpr/libwinpr/pipe/test/CMakeLists.txt +++ b/winpr/libwinpr/pipe/test/CMakeLists.txt @@ -15,12 +15,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-pipe winpr-io winpr-synch winpr-thread winpr-error winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c index 7727925f5..3ee19ca68 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #ifndef _WIN32 #include @@ -32,9 +33,7 @@ static void* named_pipe_client_thread(void* arg) DWORD nNumberOfBytesToWrite; DWORD lpNumberOfBytesRead; DWORD lpNumberOfBytesWritten; - WaitForSingleObject(ReadyEvent, INFINITE); - hNamedPipe = CreateFile(lpszPipeNameMt, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (!hNamedPipe) @@ -63,11 +62,10 @@ static void* named_pipe_client_thread(void* arg) lpNumberOfBytesWritten = 0; nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; - FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) || - lpNumberOfBytesWritten != nNumberOfBytesToWrite) + lpNumberOfBytesWritten != nNumberOfBytesToWrite) { printf("%s: Client NamedPipe WriteFile failure\n", __FUNCTION__); goto out; @@ -75,26 +73,26 @@ static void* named_pipe_client_thread(void* arg) lpNumberOfBytesRead = 0; nNumberOfBytesToRead = PIPE_BUFFER_SIZE; - ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) || - lpNumberOfBytesRead != nNumberOfBytesToRead) + lpNumberOfBytesRead != nNumberOfBytesToRead) { printf("%s: Client NamedPipe ReadFile failure\n", __FUNCTION__); goto out; } printf("Client ReadFile (%d):\n", lpNumberOfBytesRead); - winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, lpNumberOfBytesRead); fSuccess = TRUE; - out: free(lpReadBuffer); free(lpWriteBuffer); CloseHandle(hNamedPipe); + if (!fSuccess) - testFailed = TRUE; + testFailed = TRUE; + return NULL; } @@ -109,10 +107,9 @@ static void* named_pipe_server_thread(void* arg) DWORD nNumberOfBytesToWrite; DWORD lpNumberOfBytesRead; DWORD lpNumberOfBytesWritten; - hNamedPipe = CreateNamedPipe(lpszPipeNameMt, - PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); if (!hNamedPipe) { @@ -127,7 +124,6 @@ static void* named_pipe_server_thread(void* arg) } SetEvent(ReadyEvent); - fConnected = ConnectNamedPipe(hNamedPipe, NULL); if (!fConnected) @@ -153,38 +149,37 @@ static void* named_pipe_server_thread(void* arg) lpNumberOfBytesRead = 0; nNumberOfBytesToRead = PIPE_BUFFER_SIZE; - ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) || - lpNumberOfBytesRead != nNumberOfBytesToRead) + lpNumberOfBytesRead != nNumberOfBytesToRead) { printf("%s: Server NamedPipe ReadFile failure\n", __FUNCTION__); goto out; } printf("Server ReadFile (%d):\n", lpNumberOfBytesRead); - winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); - + winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, lpNumberOfBytesRead); lpNumberOfBytesWritten = 0; nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; - FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) || - lpNumberOfBytesWritten != nNumberOfBytesToWrite) + lpNumberOfBytesWritten != nNumberOfBytesToWrite) { printf("%s: Server NamedPipe WriteFile failure\n", __FUNCTION__); goto out; } - fSuccess = TRUE; + fSuccess = TRUE; out: free(lpReadBuffer); free(lpWriteBuffer); CloseHandle(hNamedPipe); + if (!fSuccess) - testFailed = TRUE; + testFailed = TRUE; + return NULL; } @@ -203,19 +198,16 @@ static void* named_pipe_single_thread(void* arg) #ifndef _WIN32 WINPR_NAMED_PIPE* p; #endif - numPipes = TESTNUMPIPESST; - memset(servers, 0, sizeof(servers)); memset(clients, 0, sizeof(clients)); - WaitForSingleObject(ReadyEvent, INFINITE); for (i = 0; i < numPipes; i++) { if (!(servers[i] = CreateNamedPipe(lpszPipeNameSt, - PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL))) + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL))) { printf("%s: CreateNamedPipe #%d failed\n", __FUNCTION__, i); goto out; @@ -223,6 +215,7 @@ static void* named_pipe_single_thread(void* arg) } #ifndef _WIN32 + for (i = 0; i < numPipes; i++) { p = (WINPR_NAMED_PIPE*)servers[i]; @@ -230,37 +223,38 @@ static void* named_pipe_single_thread(void* arg) if (strcmp(lpszPipeNameSt, p->name)) { printf("%s: Pipe name mismatch for pipe #%d ([%s] instead of [%s])\n", - __FUNCTION__, i, p->name, lpszPipeNameSt); + __FUNCTION__, i, p->name, lpszPipeNameSt); goto out; } if (p->clientfd != -1) { printf("%s: Unexpected client fd value for pipe #%d (%d instead of -1)\n", - __FUNCTION__, i, p->clientfd); + __FUNCTION__, i, p->clientfd); goto out; } if (p->serverfd < 1) { printf("%s: Unexpected server fd value for pipe #%d (%d is not > 0)\n", - __FUNCTION__, i, p->serverfd); + __FUNCTION__, i, p->serverfd); goto out; } if (p->ServerMode == FALSE) { printf("%s: Unexpected ServerMode value for pipe #%d (0 instead of 1)\n", - __FUNCTION__, i); + __FUNCTION__, i); goto out; } } + #endif for (i = 0; i < numPipes; i++) { if (!(clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL))) + 0, NULL, OPEN_EXISTING, 0, NULL))) { printf("%s: CreateFile #%d failed\n", __FUNCTION__, i); goto out; @@ -274,6 +268,7 @@ static void* named_pipe_single_thread(void* arg) } #ifndef _WIN32 + for (i = 0; i < numPipes; i++) { p = servers[i]; @@ -281,14 +276,14 @@ static void* named_pipe_single_thread(void* arg) if (p->clientfd < 1) { printf("%s: Unexpected client fd value for pipe #%d (%d is not > 0)\n", - __FUNCTION__, i, p->clientfd); + __FUNCTION__, i, p->clientfd); goto out; } if (p->ServerMode) { printf("%s: Unexpected ServerMode value for pipe #%d (1 instead of 0)\n", - __FUNCTION__, i); + __FUNCTION__, i); goto out; } } @@ -296,22 +291,20 @@ static void* named_pipe_single_thread(void* arg) for (i = 0; i < numPipes; i++) { /* Test writing from clients to servers */ - ZeroMemory(sndbuf, sizeof(sndbuf)); ZeroMemory(rcvbuf, sizeof(rcvbuf)); sprintf_s(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i); - p = servers[i]; if (!WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) || - dwWritten != sizeof(sndbuf)) + dwWritten != sizeof(sndbuf)) { printf("%s: Error writing to client end of pipe #%d\n", __FUNCTION__, i); goto out; } if (!ReadFile(servers[i], rcvbuf, dwWritten, &dwRead, NULL) || - dwRead != dwWritten) + dwRead != dwWritten) { printf("%s: Error reading on server end of pipe #%d\n", __FUNCTION__, i); goto out; @@ -320,26 +313,25 @@ static void* named_pipe_single_thread(void* arg) if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf))) { printf("%s: Error data read on server end of pipe #%d is corrupted\n", - __FUNCTION__, i); + __FUNCTION__, i); goto out; } /* Test writing from servers to clients */ - ZeroMemory(sndbuf, sizeof(sndbuf)); ZeroMemory(rcvbuf, sizeof(rcvbuf)); sprintf_s(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i); - p = servers[i]; + if (!WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) || - dwWritten != sizeof(sndbuf)) + dwWritten != sizeof(sndbuf)) { printf("%s: Error writing to server end of pipe #%d\n", __FUNCTION__, i); goto out; } if (!ReadFile(clients[i], rcvbuf, dwWritten, &dwRead, NULL) || - dwRead != dwWritten) + dwRead != dwWritten) { printf("%s: Error reading on client end of pipe #%d\n", __FUNCTION__, i); goto out; @@ -348,18 +340,17 @@ static void* named_pipe_single_thread(void* arg) if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf))) { printf("%s: Error data read on client end of pipe #%d is corrupted\n", - __FUNCTION__, i); + __FUNCTION__, i); goto out; } } -#endif +#endif /** * After DisconnectNamedPipe on server end * ReadFile/WriteFile must fail on client end */ i = numPipes - 1; - DisconnectNamedPipe(servers[i]); if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL)) @@ -376,16 +367,12 @@ static void* named_pipe_single_thread(void* arg) CloseHandle(servers[i]); CloseHandle(clients[i]); - numPipes--; - - /** * After CloseHandle (without calling DisconnectNamedPipe first) on server end * ReadFile/WriteFile must fail on client end */ i = numPipes - 1; - CloseHandle(servers[i]); if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL)) @@ -401,16 +388,12 @@ static void* named_pipe_single_thread(void* arg) } CloseHandle(clients[i]); - numPipes--; - - /** * After CloseHandle on client end * ReadFile/WriteFile must fail on server end */ i = numPipes - 1; - CloseHandle(clients[i]); if (ReadFile(servers[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL)) @@ -427,7 +410,6 @@ static void* named_pipe_single_thread(void* arg) DisconnectNamedPipe(servers[i]); CloseHandle(servers[i]); - numPipes--; /* Close all remaining pipes */ @@ -437,13 +419,14 @@ static void* named_pipe_single_thread(void* arg) CloseHandle(servers[i]); CloseHandle(clients[i]); } + numPipes = 0; - bSuccess = TRUE; - out: + if (!bSuccess) testFailed = TRUE; + return NULL; } @@ -453,25 +436,19 @@ int TestPipeCreateNamedPipe(int argc, char* argv[]) HANDLE SingleThread; HANDLE ClientThread; HANDLE ServerThread; - #ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); + signal(SIGPIPE, SIG_IGN); #endif - ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - SingleThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_single_thread, NULL, 0, NULL); ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); - WaitForSingleObject(SingleThread, INFINITE); WaitForSingleObject(ClientThread, INFINITE); WaitForSingleObject(ServerThread, INFINITE); - CloseHandle(SingleThread); CloseHandle(ClientThread); CloseHandle(ServerThread); - return testFailed; } diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c index fe71bff6a..8250f1734 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,7 @@ static void* named_pipe_client_thread(void* arg) DWORD nNumberOfBytesToRead; DWORD nNumberOfBytesToWrite; DWORD NumberOfBytesTransferred; - WaitForSingleObject(ReadyEvent, INFINITE); - hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (!hNamedPipe) @@ -46,15 +45,11 @@ static void* named_pipe_client_thread(void* arg) lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); - ZeroMemory(&overlapped, sizeof(OVERLAPPED)); hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); overlapped.hEvent = hEvent; - nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; - FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); - fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); if (!fSuccess) @@ -65,23 +60,17 @@ static void* named_pipe_client_thread(void* arg) printf("Client NamedPipe WriteFile failure: %d\n", GetLastError()); free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); return NULL; } status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); - NumberOfBytesTransferred = 0; fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); - printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); - nNumberOfBytesToRead = PIPE_BUFFER_SIZE; - ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); - fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); if (!fSuccess) @@ -92,28 +81,21 @@ static void* named_pipe_client_thread(void* arg) printf("Client NamedPipe ReadFile failure: %d\n", GetLastError()); free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); return NULL; } status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); - NumberOfBytesTransferred = 0; fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); - printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); - printf("Client ReadFile (%d):\n", NumberOfBytesTransferred); - winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); - + winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, NumberOfBytesTransferred); free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); - return NULL; } @@ -130,10 +112,9 @@ static void* named_pipe_server_thread(void* arg) DWORD nNumberOfBytesToRead; DWORD nNumberOfBytesToWrite; DWORD NumberOfBytesTransferred; - hNamedPipe = CreateNamedPipe(lpszPipeName, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); if (!hNamedPipe) { @@ -148,42 +129,32 @@ static void* named_pipe_server_thread(void* arg) } SetEvent(ReadyEvent); - ZeroMemory(&overlapped, sizeof(OVERLAPPED)); hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); overlapped.hEvent = hEvent; - fConnected = ConnectNamedPipe(hNamedPipe, &overlapped); - printf("ConnectNamedPipe status: %d\n", GetLastError()); if (!fConnected) fConnected = (GetLastError() == ERROR_IO_PENDING); status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); - NumberOfBytesTransferred = 0; fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); - printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); if (!fConnected) { printf("ConnectNamedPipe failure: %d\n", GetLastError()); - CloseHandle(hNamedPipe); CloseHandle(hEvent); - return NULL; } lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); - nNumberOfBytesToRead = PIPE_BUFFER_SIZE; - ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); - fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); if (!fSuccess) @@ -194,27 +165,19 @@ static void* named_pipe_server_thread(void* arg) printf("Server NamedPipe ReadFile failure: %d\n", GetLastError()); free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); - return NULL; } status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); - NumberOfBytesTransferred = 0; fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); - printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); - printf("Server ReadFile (%d):\n", NumberOfBytesTransferred); - winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); - + winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, NumberOfBytesTransferred); nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; - FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); - fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); if (!fSuccess) @@ -223,29 +186,21 @@ static void* named_pipe_server_thread(void* arg) if (!fSuccess) { printf("Server NamedPipe WriteFile failure: %d\n", GetLastError()); - free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); - return NULL; } status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); - NumberOfBytesTransferred = 0; fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); - printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); - free(lpReadBuffer); free(lpWriteBuffer); - CloseHandle(hNamedPipe); CloseHandle(hEvent); - return NULL; } @@ -253,15 +208,11 @@ int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) { HANDLE ClientThread; HANDLE ServerThread; - ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); - WaitForSingleObject(ClientThread, INFINITE); WaitForSingleObject(ServerThread, INFINITE); - return 0; } diff --git a/winpr/libwinpr/pool/CMakeLists.txt b/winpr/libwinpr/pool/CMakeLists.txt index 8044c89e7..fd70d7301 100644 --- a/winpr/libwinpr/pool/CMakeLists.txt +++ b/winpr/libwinpr/pool/CMakeLists.txt @@ -15,10 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-pool") -set(MODULE_PREFIX "WINPR_POOL") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( synch.c work.c timer.c @@ -30,39 +27,14 @@ set(${MODULE_PREFIX}_SRCS callback.c callback_cleanup.c) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS +winpr_library_add( ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-thread winpr-synch winpr-utils) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/pool/callback.c b/winpr/libwinpr/pool/callback.c index f9a600fa8..da959f30b 100644 --- a/winpr/libwinpr/pool/callback.c +++ b/winpr/libwinpr/pool/callback.c @@ -50,6 +50,8 @@ static void module_init() #endif +#ifdef WINPR_THREAD_POOL + BOOL CallbackMayRunLong(PTP_CALLBACK_INSTANCE pci) { #ifdef _WIN32 @@ -61,3 +63,5 @@ BOOL CallbackMayRunLong(PTP_CALLBACK_INSTANCE pci) #endif return FALSE; } + +#endif diff --git a/winpr/libwinpr/pool/callback_cleanup.c b/winpr/libwinpr/pool/callback_cleanup.c index f0653ae98..268b87de5 100644 --- a/winpr/libwinpr/pool/callback_cleanup.c +++ b/winpr/libwinpr/pool/callback_cleanup.c @@ -62,6 +62,8 @@ static void module_init() #endif +#ifdef WINPR_THREAD_POOL + VOID SetEventWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE evt) { #ifdef _WIN32 @@ -128,5 +130,5 @@ VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci) #endif } - +#endif diff --git a/winpr/libwinpr/pool/callback_environment.c b/winpr/libwinpr/pool/callback_environment.c index 93d981777..00ea7898b 100644 --- a/winpr/libwinpr/pool/callback_environment.c +++ b/winpr/libwinpr/pool/callback_environment.c @@ -26,6 +26,8 @@ #include "pool.h" +#ifdef WINPR_THREAD_POOL + VOID InitializeCallbackEnvironment_V1(TP_CALLBACK_ENVIRON_V1* pcbe) { pcbe->Version = 1; @@ -55,6 +57,8 @@ VOID InitializeCallbackEnvironment_V3(TP_CALLBACK_ENVIRON_V3* pcbe) pcbe->Size = sizeof(TP_CALLBACK_ENVIRON); } +#endif + #ifdef _WIN32 static BOOL module_initialized = FALSE; @@ -116,6 +120,8 @@ PTP_CALLBACK_ENVIRON GetDefaultThreadpoolEnvironment() #endif +#ifdef WINPR_THREAD_POOL + VOID InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe) { if (pcbe->Version == 3) @@ -193,3 +199,5 @@ VOID SetThreadpoolCallbackPriority(PTP_CALLBACK_ENVIRON pcbe, TP_CALLBACK_PRIORI #else #endif } + +#endif diff --git a/winpr/libwinpr/pool/cleanup_group.c b/winpr/libwinpr/pool/cleanup_group.c index bd8676df6..db7655701 100644 --- a/winpr/libwinpr/pool/cleanup_group.c +++ b/winpr/libwinpr/pool/cleanup_group.c @@ -56,6 +56,8 @@ static void module_init() #endif +#if WINPR_THREAD_POOL + PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup() { PTP_CLEANUP_GROUP cleanupGroup = NULL; @@ -94,4 +96,5 @@ VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg) #endif } +#endif diff --git a/winpr/libwinpr/pool/io.c b/winpr/libwinpr/pool/io.c index 5327148d9..577d2fb95 100644 --- a/winpr/libwinpr/pool/io.c +++ b/winpr/libwinpr/pool/io.c @@ -24,6 +24,8 @@ #include #include +#ifdef WINPR_THREAD_POOL + PTP_IO CreateThreadpoolIo(HANDLE fl, PTP_WIN32_IO_CALLBACK pfnio, PVOID pv, PTP_CALLBACK_ENVIRON pcbe) { return NULL; @@ -49,3 +51,4 @@ VOID WaitForThreadpoolIoCallbacks(PTP_IO pio, BOOL fCancelPendingCallbacks) } +#endif \ No newline at end of file diff --git a/winpr/libwinpr/pool/pool.c b/winpr/libwinpr/pool/pool.c index 2030646c8..e7c099e39 100644 --- a/winpr/libwinpr/pool/pool.c +++ b/winpr/libwinpr/pool/pool.c @@ -150,6 +150,8 @@ PTP_POOL GetDefaultThreadpool() #endif +#ifdef WINPR_THREAD_POOL + PTP_POOL CreateThreadpool(PVOID reserved) { PTP_POOL pool = NULL; @@ -236,6 +238,8 @@ VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost) #endif } +#endif + /* dummy */ void winpr_pool_dummy() diff --git a/winpr/libwinpr/pool/synch.c b/winpr/libwinpr/pool/synch.c index 5f87c78ff..057c5ee96 100644 --- a/winpr/libwinpr/pool/synch.c +++ b/winpr/libwinpr/pool/synch.c @@ -24,6 +24,8 @@ #include #include +#ifdef WINPR_THREAD_POOL + PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnwa, PVOID pv, PTP_CALLBACK_ENVIRON pcbe) { return NULL; @@ -44,4 +46,4 @@ VOID WaitForThreadpoolWaitCallbacks(PTP_WAIT pwa, BOOL fCancelPendingCallbacks) } - +#endif diff --git a/winpr/libwinpr/pool/test/CMakeLists.txt b/winpr/libwinpr/pool/test/CMakeLists.txt index eb03c0b6f..9758fff05 100644 --- a/winpr/libwinpr/pool/test/CMakeLists.txt +++ b/winpr/libwinpr/pool/test/CMakeLists.txt @@ -17,12 +17,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-pool winpr-interlocked) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/pool/timer.c b/winpr/libwinpr/pool/timer.c index 9867941a6..7ee9f30f6 100644 --- a/winpr/libwinpr/pool/timer.c +++ b/winpr/libwinpr/pool/timer.c @@ -24,6 +24,8 @@ #include #include +#ifdef WINPR_THREAD_POOL + PTP_TIMER CreateThreadpoolTimer(PTP_TIMER_CALLBACK pfnti, PVOID pv, PTP_CALLBACK_ENVIRON pcbe) { return NULL; @@ -49,4 +51,4 @@ VOID WaitForThreadpoolTimerCallbacks(PTP_TIMER pti, BOOL fCancelPendingCallbacks } - +#endif \ No newline at end of file diff --git a/winpr/libwinpr/pool/work.c b/winpr/libwinpr/pool/work.c index 62581650b..297d182aa 100644 --- a/winpr/libwinpr/pool/work.c +++ b/winpr/libwinpr/pool/work.c @@ -25,6 +25,8 @@ #include #include "pool.h" +#include "../log.h" +#define TAG WINPR_TAG("pool") #ifdef _WIN32 @@ -32,11 +34,11 @@ static BOOL module_initialized = FALSE; static BOOL module_available = FALSE; static HMODULE kernel32_module = NULL; -static PTP_WORK (WINAPI * pCreateThreadpoolWork)(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe); -static VOID (WINAPI * pCloseThreadpoolWork)(PTP_WORK pwk); -static VOID (WINAPI * pSubmitThreadpoolWork)(PTP_WORK pwk); -static BOOL (WINAPI * pTrySubmitThreadpoolCallback)(PTP_SIMPLE_CALLBACK pfns, PVOID pv, PTP_CALLBACK_ENVIRON pcbe); -static VOID (WINAPI * pWaitForThreadpoolWorkCallbacks)(PTP_WORK pwk, BOOL fCancelPendingCallbacks); +static PTP_WORK(WINAPI* pCreateThreadpoolWork)(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe); +static VOID (WINAPI* pCloseThreadpoolWork)(PTP_WORK pwk); +static VOID (WINAPI* pSubmitThreadpoolWork)(PTP_WORK pwk); +static BOOL (WINAPI* pTrySubmitThreadpoolCallback)(PTP_SIMPLE_CALLBACK pfns, PVOID pv, PTP_CALLBACK_ENVIRON pcbe); +static VOID (WINAPI* pWaitForThreadpoolWorkCallbacks)(PTP_WORK pwk, BOOL fCancelPendingCallbacks); static void module_init() { @@ -50,7 +52,6 @@ static void module_init() return; module_available = TRUE; - pCreateThreadpoolWork = (void*) GetProcAddress(kernel32_module, "CreateThreadpoolWork"); pCloseThreadpoolWork = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolWork"); pSubmitThreadpoolWork = (void*) GetProcAddress(kernel32_module, "SubmitThreadpoolWork"); @@ -60,15 +61,17 @@ static void module_init() #endif +#ifdef WINPR_THREAD_POOL + PTP_WORK CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe) { PTP_WORK work = NULL; - #ifdef _WIN32 module_init(); if (pCreateThreadpoolWork) return pCreateThreadpoolWork(pfnwk, pv, pcbe); + #else work = (PTP_WORK) malloc(sizeof(TP_WORK)); @@ -82,8 +85,8 @@ PTP_WORK CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_EN work->CallbackEnvironment = pcbe; } -#endif +#endif return work; } @@ -94,6 +97,7 @@ VOID CloseThreadpoolWork(PTP_WORK pwk) if (pCloseThreadpoolWork) pCloseThreadpoolWork(pwk); + #else free(pwk); #endif @@ -106,12 +110,11 @@ VOID SubmitThreadpoolWork(PTP_WORK pwk) if (pSubmitThreadpoolWork) pSubmitThreadpoolWork(pwk); + #else PTP_POOL pool; PTP_CALLBACK_INSTANCE callbackInstance; - pool = pwk->CallbackEnvironment->Pool; - callbackInstance = (PTP_CALLBACK_INSTANCE) malloc(sizeof(TP_CALLBACK_INSTANCE)); if (callbackInstance) @@ -120,6 +123,7 @@ VOID SubmitThreadpoolWork(PTP_WORK pwk) CountdownEvent_AddCount(pool->WorkComplete, 1); Queue_Enqueue(pool->PendingQueue, callbackInstance); } + #endif } @@ -130,6 +134,7 @@ BOOL TrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACK pfns, PVOID pv, PTP_CALLBAC if (pTrySubmitThreadpoolCallback) return pTrySubmitThreadpoolCallback(pfns, pv, pcbe); + #else #endif return FALSE; @@ -142,14 +147,17 @@ VOID WaitForThreadpoolWorkCallbacks(PTP_WORK pwk, BOOL fCancelPendingCallbacks) if (pWaitForThreadpoolWorkCallbacks) pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks); + #else HANDLE event; PTP_POOL pool; - pool = pwk->CallbackEnvironment->Pool; event = CountdownEvent_WaitHandle(pool->WorkComplete); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) - printf("WaitForThreadpoolWorkCallbacks: error waiting on work completion\n"); + WLog_ERR(TAG, "error waiting on work completion"); + #endif } + +#endif diff --git a/winpr/libwinpr/registry/CMakeLists.txt b/winpr/libwinpr/registry/CMakeLists.txt index 3d04e40c9..4400afdd5 100644 --- a/winpr/libwinpr/registry/CMakeLists.txt +++ b/winpr/libwinpr/registry/CMakeLists.txt @@ -15,30 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-registry") -set(MODULE_PREFIX "WINPR_REGISTRY") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( registry_reg.c registry_reg.h registry.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} winpr-utils) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index dafee6ca1..aa05b93da 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -29,6 +29,9 @@ #include "registry_reg.h" +#include "../log.h" +#define TAG WINPR_TAG("registry") + #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" static void reg_print_key(Reg* reg, RegKey* key); @@ -74,11 +77,9 @@ static char* REG_DATA_TYPE_STRINGS[] = static void reg_load_start(Reg* reg) { long int file_size; - fseek(reg->fp, 0, SEEK_END); file_size = ftell(reg->fp); fseek(reg->fp, 0, SEEK_SET); - reg->line = NULL; reg->next_line = NULL; reg->buffer = NULL; @@ -97,7 +98,6 @@ static void reg_load_start(Reg* reg) reg->buffer[file_size] = '\n'; reg->buffer[file_size + 1] = '\0'; - reg->next_line = strtok(reg->buffer, "\n"); } @@ -122,7 +122,6 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) char* type; char* data; RegVal* value; - p[0] = reg->line + 1; p[1] = strstr(p[0], "\"="); p[2] = p[1] + 2; @@ -134,14 +133,11 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) p[3] = strchr(p[2], ':'); data = p[3] + 1; - length = p[1] - p[0]; name = (char*) malloc(length + 1); memcpy(name, p[0], length); name[length] = '\0'; - value = (RegVal*) malloc(sizeof(RegVal)); - value->name = name; value->type = REG_NONE; value->next = value->prev = NULL; @@ -167,7 +163,7 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) } else { - fprintf(stderr, "unimplemented format: %s\n", REG_DATA_TYPE_STRINGS[value->type]); + WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); } if (!key->values) @@ -206,7 +202,6 @@ static char* reg_load_get_next_line(Reg* reg) reg->line = reg->next_line; reg->next_line = strtok(NULL, "\n"); reg->line_length = strlen(reg->line); - return reg->line; } @@ -221,9 +216,7 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) char* path; char* save; int length; - path = _strdup(subkey->name); - name = strtok_s(path, "\\", &save); while (name != NULL) @@ -247,15 +240,11 @@ static RegKey* reg_load_key(Reg* reg, RegKey* key) int length; char* line; RegKey* subkey; - p[0] = reg->line + 1; p[1] = strrchr(p[0], ']'); - subkey = (RegKey*) malloc(sizeof(RegKey)); - subkey->values = NULL; subkey->prev = subkey->next = NULL; - length = p[1] - p[0]; subkey->name = (char*) malloc(length + 1); memcpy(subkey->name, p[0], length); @@ -319,7 +308,6 @@ static void reg_unload_value(Reg* reg, RegVal* value) { if (value->type == REG_DWORD) { - } else if (value->type == REG_SZ) { @@ -327,7 +315,7 @@ static void reg_unload_value(Reg* reg, RegVal* value) } else { - fprintf(stderr, "unimplemented format: %s\n", REG_DATA_TYPE_STRINGS[value->type]); + WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); } free(value); @@ -337,7 +325,6 @@ static void reg_unload_key(Reg* reg, RegKey* key) { RegVal* pValue; RegVal* pValueNext; - pValue = key->values; while (pValue != NULL) @@ -355,7 +342,6 @@ void reg_unload(Reg* reg) { RegKey* pKey; RegKey* pKeyNext; - pKey = reg->root_key->subkeys; while (pKey != NULL) @@ -371,7 +357,6 @@ void reg_unload(Reg* reg) Reg* reg_open(BOOL read_only) { Reg* reg; - reg = (Reg*) malloc(sizeof(Reg)); if (reg) @@ -398,11 +383,9 @@ Reg* reg_open(BOOL read_only) } reg->root_key = (RegKey*) malloc(sizeof(RegKey)); - reg->root_key->values = NULL; reg->root_key->subkeys = NULL; reg->root_key->name = "HKEY_LOCAL_MACHINE"; - reg_load(reg); } @@ -421,29 +404,27 @@ void reg_close(Reg* reg) void reg_print_value(Reg* reg, RegVal* value) { - fprintf(stderr, "\"%s\"=", value->name); + WLog_INFO(TAG, "\"%s\"=", value->name); if (value->type == REG_DWORD) { - fprintf(stderr, "dword:%08X\n", (int) value->data.dword); + WLog_INFO(TAG, "dword:%08X", (int) value->data.dword); } else if (value->type == REG_SZ) { - fprintf(stderr, "%s\"\n", value->data.string); + WLog_INFO(TAG, "%s\"", value->data.string); } else { - fprintf(stderr, "unimplemented format: %s\n", REG_DATA_TYPE_STRINGS[value->type]); + WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); } } void reg_print_key(Reg* reg, RegKey* key) { RegVal* pValue; - pValue = key->values; - - fprintf(stderr, "[%s]\n", key->name); + WLog_INFO(TAG, "[%s]", key->name); while (pValue != NULL) { @@ -455,7 +436,6 @@ void reg_print_key(Reg* reg, RegKey* key) void reg_print(Reg* reg) { RegKey* pKey; - pKey = reg->root_key->subkeys; while (pKey != NULL) diff --git a/winpr/libwinpr/rpc/CMakeLists.txt b/winpr/libwinpr/rpc/CMakeLists.txt index 758a44fca..a9c7c9acd 100644 --- a/winpr/libwinpr/rpc/CMakeLists.txt +++ b/winpr/libwinpr/rpc/CMakeLists.txt @@ -15,10 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-rpc") -set(MODULE_PREFIX "WINPR_RPC") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( rpc.c ndr.c ndr_array.c @@ -41,35 +38,13 @@ set(${MODULE_PREFIX}_SRCS ndr_union.h midl.c) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() +winpr_include_directory_add(${OPENSSL_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIRS}) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -include_directories(${OPENSSL_INCLUDE_DIR}) -include_directories(${ZLIB_INCLUDE_DIRS}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${OPENSSL_LIBRARIES}) +winpr_library_add(${OPENSSL_LIBRARIES}) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rpcrt4) + winpr_library_add(ws2_32 rpcrt4) else() - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ZLIB_LIBRARIES}) + winpr_library_add(${ZLIB_LIBRARIES}) endif() - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") diff --git a/winpr/libwinpr/rpc/ndr.c b/winpr/libwinpr/rpc/ndr.c index efc58d809..5df4e579a 100644 --- a/winpr/libwinpr/rpc/ndr.c +++ b/winpr/libwinpr/rpc/ndr.c @@ -39,6 +39,9 @@ #include "ndr_private.h" +#include "../log.h" +#define TAG WINPR_TAG("rpc") + /** * MSRPC NDR Types Technical Overview: * http://dvlabs.tippingpoint.com/blog/2007/11/24/msrpc-ndr-types/ @@ -47,29 +50,40 @@ void NdrPrintParamAttributes(PARAM_ATTRIBUTES attributes) { if (attributes.ServerAllocSize) - fprintf(stderr, "ServerAllocSize, "); + WLog_INFO(TAG, "ServerAllocSize, "); + if (attributes.SaveForAsyncFinish) - fprintf(stderr, "SaveForAsyncFinish, "); + WLog_INFO(TAG, "SaveForAsyncFinish, "); + if (attributes.IsDontCallFreeInst) - fprintf(stderr, "IsDontCallFreeInst, "); + WLog_INFO(TAG, "IsDontCallFreeInst, "); + if (attributes.IsSimpleRef) - fprintf(stderr, "IsSimpleRef, "); + WLog_INFO(TAG, "IsSimpleRef, "); + if (attributes.IsByValue) - fprintf(stderr, "IsByValue, "); + WLog_INFO(TAG, "IsByValue, "); + if (attributes.IsBasetype) - fprintf(stderr, "IsBaseType, "); + WLog_INFO(TAG, "IsBaseType, "); + if (attributes.IsReturn) - fprintf(stderr, "IsReturn, "); + WLog_INFO(TAG, "IsReturn, "); + if (attributes.IsOut) - fprintf(stderr, "IsOut, "); + WLog_INFO(TAG, "IsOut, "); + if (attributes.IsIn) - fprintf(stderr, "IsIn, "); + WLog_INFO(TAG, "IsIn, "); + if (attributes.IsPipe) - fprintf(stderr, "IsPipe, "); + WLog_INFO(TAG, "IsPipe, "); + if (attributes.MustFree) - fprintf(stderr, "MustFree, "); + WLog_INFO(TAG, "MustFree, "); + if (attributes.MustSize) - fprintf(stderr, "MustSize, "); + WLog_INFO(TAG, "MustSize, "); } void NdrProcessParam(PMIDL_STUB_MESSAGE pStubMsg, NDR_PHASE phase, unsigned char* pMemory, NDR_PARAM* param) @@ -136,21 +150,18 @@ void NdrProcessParams(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, NDR_P PFORMAT_STRING fmt; unsigned char* arg; unsigned char type; - params = (NDR_PARAM*) pFormat; - - fprintf(stderr, "Params = \n{\n"); + WLog_INFO(TAG, "Params = "); for (i = 0; i < numberParams; i++) { #ifdef __x86_64__ float tmp; #endif - arg = pStubMsg->StackTop + params[i].StackOffset; fmt = (PFORMAT_STRING) &pStubMsg->StubDesc->pFormatTypes[params[i].Type.Offset]; - #ifdef __x86_64__ + if ((params[i].Attributes.IsBasetype) && !(params[i].Attributes.IsSimpleRef) && ((params[i].Type.FormatChar) == FC_FLOAT) && !fpuArgs) @@ -158,29 +169,21 @@ void NdrProcessParams(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, NDR_P tmp = *(double*) arg; arg = (unsigned char*) &tmp; } + #endif - - fprintf(stderr, "\t#%d\t", i); - type = (params[i].Attributes.IsBasetype) ? params[i].Type.FormatChar : *fmt; - - fprintf(stderr, " type %s (0x%02X) ", FC_TYPE_STRINGS[type], type); - + WLog_INFO(TAG, "'\t#%d\ttype %s (0x%02X) ", i, FC_TYPE_STRINGS[type], type); NdrPrintParamAttributes(params[i].Attributes); if (params[i].Attributes.IsIn) { NdrProcessParam(pStubMsg, phase, arg, ¶ms[i]); } - - fprintf(stderr, "\n"); } - - fprintf(stderr, "}\n"); } void NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum) + PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum) { pRpcMessage->Handle = NULL; pRpcMessage->RpcFlags = 0; @@ -188,7 +191,6 @@ void NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMs pRpcMessage->DataRepresentation = 0; pRpcMessage->ReservedForRuntime = NULL; pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; - pStubMsg->RpcMsg = pRpcMessage; pStubMsg->BufferStart = NULL; pStubMsg->BufferEnd = NULL; @@ -202,33 +204,43 @@ void NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMs void NdrPrintOptFlags(INTERPRETER_OPT_FLAGS optFlags) { if (optFlags.ClientMustSize) - fprintf(stderr, "ClientMustSize, "); + WLog_INFO(TAG, "ClientMustSize, "); + if (optFlags.ServerMustSize) - fprintf(stderr, "ServerMustSize, "); + WLog_INFO(TAG, "ServerMustSize, "); + if (optFlags.HasAsyncUuid) - fprintf(stderr, "HasAsyncUiid, "); + WLog_INFO(TAG, "HasAsyncUiid, "); + if (optFlags.HasAsyncHandle) - fprintf(stderr, "HasAsyncHandle, "); + WLog_INFO(TAG, "HasAsyncHandle, "); + if (optFlags.HasReturn) - fprintf(stderr, "HasReturn, "); + WLog_INFO(TAG, "HasReturn, "); + if (optFlags.HasPipes) - fprintf(stderr, "HasPipes, "); + WLog_INFO(TAG, "HasPipes, "); + if (optFlags.HasExtensions) - fprintf(stderr, "HasExtensions, "); + WLog_INFO(TAG, "HasExtensions, "); } void NdrPrintExtFlags(INTERPRETER_OPT_FLAGS2 extFlags) { if (extFlags.HasNewCorrDesc) - fprintf(stderr, "HasNewCorrDesc, "); + WLog_INFO(TAG, "HasNewCorrDesc, "); + if (extFlags.ClientCorrCheck) - fprintf(stderr, "ClientCorrCheck, "); + WLog_INFO(TAG, "ClientCorrCheck, "); + if (extFlags.ServerCorrCheck) - fprintf(stderr, "ServerCorrCheck, "); + WLog_INFO(TAG, "ServerCorrCheck, "); + if (extFlags.HasNotify) - fprintf(stderr, "HasNotify, "); + WLog_INFO(TAG, "HasNotify, "); + if (extFlags.HasNotify2) - fprintf(stderr, "HasNotify2, "); + WLog_INFO(TAG, "HasNotify2, "); } CLIENT_CALL_RETURN NdrClientCall(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING pFormat, void** stackTop, void** fpuStack) @@ -244,97 +256,85 @@ CLIENT_CALL_RETURN NdrClientCall(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING NDR_PROC_HEADER* procHeader; NDR_OI2_PROC_HEADER* oi2ProcHeader; CLIENT_CALL_RETURN client_call_return; - procNum = stackSize = numberParams = 0; procHeader = (NDR_PROC_HEADER*) &pFormat[0]; - client_call_return.Pointer = NULL; - handleType = procHeader->HandleType; flags = procHeader->OldOiFlags; procNum = procHeader->ProcNum; stackSize = procHeader->StackSize; pFormat += sizeof(NDR_PROC_HEADER); - /* The Header: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378707/ */ /* Procedure Header Descriptor: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374387/ */ /* Handles: http://msdn.microsoft.com/en-us/library/windows/desktop/aa373932/ */ - - fprintf(stderr, "Oi Header: HandleType: 0x%02X OiFlags: 0x%02X ProcNum: %d StackSize: 0x%04X\n", - handleType, *((unsigned char*) &flags), - (unsigned short) procNum, (unsigned short) stackSize); + WLog_DBG(TAG, "Oi Header: HandleType: 0x%02X OiFlags: 0x%02X ProcNum: %d StackSize: 0x%04X", + handleType, *((unsigned char*) &flags), + (unsigned short) procNum, (unsigned short) stackSize); if (handleType > 0) { /* implicit handle */ - fprintf(stderr, "Implicit Handle\n"); + WLog_INFO(TAG, "Implicit Handle"); oi2ProcHeader = (NDR_OI2_PROC_HEADER*) &pFormat[0]; pFormat += sizeof(NDR_OI2_PROC_HEADER); } else { /* explicit handle */ - fprintf(stderr, "Explicit Handle\n"); + WLog_INFO(TAG, "Explicit Handle"); oi2ProcHeader = (NDR_OI2_PROC_HEADER*) &pFormat[6]; pFormat += sizeof(NDR_OI2_PROC_HEADER) + 6; } optFlags = oi2ProcHeader->Oi2Flags; numberParams = oi2ProcHeader->NumberParams; - - fprintf(stderr, "Oi2 Header: Oi2Flags: 0x%02X, NumberParams: %d ClientBufferSize: %d ServerBufferSize: %d\n", - *((unsigned char*) &optFlags), - (unsigned char) numberParams, - oi2ProcHeader->ClientBufferSize, - oi2ProcHeader->ServerBufferSize); - - fprintf(stderr, "Oi2Flags: "); + WLog_DBG(TAG, "Oi2 Header: Oi2Flags: 0x%02X, NumberParams: %d ClientBufferSize: %d ServerBufferSize: %d", + *((unsigned char*) &optFlags), + (unsigned char) numberParams, + oi2ProcHeader->ClientBufferSize, + oi2ProcHeader->ServerBufferSize); + WLog_INFO(TAG, "Oi2Flags: "); NdrPrintOptFlags(optFlags); - fprintf(stderr, "\n"); - NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDescriptor, procNum); if (optFlags.HasExtensions) { INTERPRETER_OPT_FLAGS2 extFlags; NDR_PROC_HEADER_EXTS* extensions = (NDR_PROC_HEADER_EXTS*) pFormat; - pFormat += extensions->Size; extFlags = extensions->Flags2; - - fprintf(stderr, "Extensions: Size: %d, flags2: 0x%02X\n", - extensions->Size, *((unsigned char*) &extensions->Flags2)); - + WLog_DBG(TAG, "Extensions: Size: %d, flags2: 0x%02X", + extensions->Size, *((unsigned char*) &extensions->Flags2)); #ifdef __x86_64__ + if (extensions->Size > sizeof(*extensions) && fpuStack) { int i; - unsigned short fpuMask = *(unsigned short*) (extensions + 1); + unsigned short fpuMask = *(unsigned short*)(extensions + 1); for (i = 0; i < 4; i++, fpuMask >>= 2) { switch (fpuMask & 3) { - case 1: *(float*) &stackTop[i] = *(float*) &fpuStack[i]; + case 1: + *(float*) &stackTop[i] = *(float*) &fpuStack[i]; break; - case 2: *(double*) &stackTop[i] = *(double*) &fpuStack[i]; + case 2: + *(double*) &stackTop[i] = *(double*) &fpuStack[i]; break; } } } + #endif - fprintf(stderr, "ExtFlags: "); + WLog_INFO(TAG, "ExtFlags: "); NdrPrintExtFlags(extFlags); - fprintf(stderr, "\n"); } stubMsg.StackTop = (unsigned char*) stackTop; - NdrProcessParams(&stubMsg, pFormat, NDR_PHASE_SIZE, fpuStack, numberParams); - - fprintf(stderr, "stubMsg BufferLength: %d\n", (int) stubMsg.BufferLength); - + WLog_DBG(TAG, "stubMsg BufferLength: %d", (int) stubMsg.BufferLength); return client_call_return; } @@ -342,11 +342,9 @@ CLIENT_CALL_RETURN NdrClientCall2(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRIN { va_list args; CLIENT_CALL_RETURN client_call_return; - va_start(args, pFormat); client_call_return = NdrClientCall(pStubDescriptor, pFormat, va_arg(args, void**), NULL); va_end(args); - return client_call_return; } diff --git a/winpr/libwinpr/rpc/ndr_array.c b/winpr/libwinpr/rpc/ndr_array.c index 32503b9d7..496726189 100644 --- a/winpr/libwinpr/rpc/ndr_array.c +++ b/winpr/libwinpr/rpc/ndr_array.c @@ -27,6 +27,7 @@ #include #include "ndr_array.h" +#include "ndr_private.h" #ifndef _WIN32 @@ -41,22 +42,20 @@ void NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pM * element_description<> * FC_END */ - unsigned char type; unsigned char alignment; unsigned short element_size; - type = pFormat[0]; alignment = pFormat[1] + 1; element_size = *(unsigned short*) &pFormat[2]; if (type != FC_CARRAY) { - fprintf(stderr, "error: expected FC_CARRAY, got 0x%02X\n", type); + WLog_ERR(TAG, "error: expected FC_CARRAY, got 0x%02X", type); return; } - fprintf(stderr, "warning: NdrConformantArrayBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrConformantArrayBufferSize unimplemented"); } void NdrConformantVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -71,8 +70,7 @@ void NdrConformantVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned c * element_description<> * FC_END */ - - fprintf(stderr, "warning: NdrConformantVaryingArrayBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrConformantVaryingArrayBufferSize unimplemented"); } void NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -85,7 +83,6 @@ void NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory * element_description<> * FC_END */ - /** * FC_LGFARRAY * alignment<1> @@ -94,8 +91,7 @@ void NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory * element_description<> * FC_END */ - - fprintf(stderr, "warning: NdrFixedArrayBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrFixedArrayBufferSize unimplemented"); } void NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -111,7 +107,6 @@ void NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemo * element_description<> * FC_END */ - /** * FC_LGVARRAY * alignment<1> @@ -123,8 +118,7 @@ void NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemo * element_description<> * FC_END */ - - fprintf(stderr, "warning: NdrVaryingArrayBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrVaryingArrayBufferSize unimplemented"); } void NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -138,8 +132,7 @@ void NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemo * element_description<> * FC_END */ - - fprintf(stderr, "warning: NdrComplexArrayBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrComplexArrayBufferSize unimplemented"); } #endif diff --git a/winpr/libwinpr/rpc/ndr_context.c b/winpr/libwinpr/rpc/ndr_context.c index 7cb2555d5..4a33abc63 100644 --- a/winpr/libwinpr/rpc/ndr_context.c +++ b/winpr/libwinpr/rpc/ndr_context.c @@ -31,6 +31,9 @@ #include "ndr_context.h" #include "ndr_private.h" +#include "../log.h" +#define TAG WINPR_TAG("rpc") + void NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { unsigned char type = *pFormat; @@ -42,8 +45,7 @@ void NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem * flag<1> * offset<2> */ - - fprintf(stderr, "warning: NdrContextHandleBufferSize FC_BIND_PRIMITIVE unimplemented\n"); + WLog_ERR(TAG, "warning: NdrContextHandleBufferSize FC_BIND_PRIMITIVE unimplemented"); } else if (type == FC_BIND_GENERIC) { @@ -54,8 +56,7 @@ void NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem * binding_routine_pair_index<1> * FC_PAD */ - - fprintf(stderr, "warning: NdrContextHandleBufferSize FC_BIND_GENERIC unimplemented\n"); + WLog_ERR(TAG, "warning: NdrContextHandleBufferSize FC_BIND_GENERIC unimplemented"); } else if (type == FC_BIND_CONTEXT) { @@ -66,7 +67,6 @@ void NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem * context_rundown_routine_index<1> * param_num<1> */ - NdrpAlignLength(&(pStubMsg->BufferLength), 4); NdrpIncrementLength(&(pStubMsg->BufferLength), 20); } diff --git a/winpr/libwinpr/rpc/ndr_correlation.c b/winpr/libwinpr/rpc/ndr_correlation.c index 523cf6f1c..f84662f02 100644 --- a/winpr/libwinpr/rpc/ndr_correlation.c +++ b/winpr/libwinpr/rpc/ndr_correlation.c @@ -50,11 +50,9 @@ PFORMAT_STRING NdrpComputeCount(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem unsigned char conformance; unsigned char correlation_type; unsigned char correlation_operator; - correlation_type = pFormat[0]; type = correlation_type & 0x0F; conformance = correlation_type & 0xF0; - correlation_operator = pFormat[1]; offset = *(unsigned short*) & pFormat[2]; @@ -70,7 +68,7 @@ PFORMAT_STRING NdrpComputeCount(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem { ptr = pStubMsg->StackTop; } - else if (conformance == FC_CONSTANT_CONFORMANCE ) + else if (conformance == FC_CONSTANT_CONFORMANCE) { data = offset | ((DWORD) pFormat[1] << 16); *pCount = data; @@ -107,7 +105,7 @@ PFORMAT_STRING NdrpComputeCount(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem case FC_CALLBACK: { - fprintf(stderr, "warning: NdrpComputeConformance FC_CALLBACK unimplemented\n"); + WLog_ERR(TAG, "warning: NdrpComputeConformance FC_CALLBACK unimplemented\n"); } break; } @@ -191,10 +189,8 @@ PFORMAT_STRING NdrpComputeConformance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char PFORMAT_STRING NdrpComputeVariance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { ULONG_PTR ActualCount = pStubMsg->ActualCount; - pFormat = NdrpComputeCount(pStubMsg, pMemory, pFormat, &ActualCount); pStubMsg->ActualCount = (ULONG) ActualCount; - return pFormat; } diff --git a/winpr/libwinpr/rpc/ndr_pointer.c b/winpr/libwinpr/rpc/ndr_pointer.c index 9be782254..d8ae59601 100644 --- a/winpr/libwinpr/rpc/ndr_pointer.c +++ b/winpr/libwinpr/rpc/ndr_pointer.c @@ -62,13 +62,11 @@ PFORMAT_STRING NdrpSkipPointerLayout(PFORMAT_STRING pFormat) * FC_PAD * pointer_instance<8> */ - pFormat += 10; } else if (*pFormat == FC_FIXED_REPEAT) { unsigned short number_of_pointers; - /** * FC_FIXED_REPEAT * FC_PAD @@ -78,7 +76,6 @@ PFORMAT_STRING NdrpSkipPointerLayout(PFORMAT_STRING pFormat) * number_of_pointers<2> * { pointer_instance<8> }* */ - pFormat += 8; number_of_pointers = *(unsigned short*) pFormat; pFormat += 2 + (number_of_pointers * 8); @@ -86,7 +83,6 @@ PFORMAT_STRING NdrpSkipPointerLayout(PFORMAT_STRING pFormat) else if (*pFormat == FC_VARIABLE_REPEAT) { unsigned short number_of_pointers; - /** * FC_VARIABLE_REPEAT (FC_FIXED_OFFSET | FC_VARIABLE_OFFSET) * FC_PAD ?! @@ -95,14 +91,13 @@ PFORMAT_STRING NdrpSkipPointerLayout(PFORMAT_STRING pFormat) * number_of_pointers<2> * { pointer_instance<8> }* */ - pFormat += 6; number_of_pointers = *(unsigned short*) pFormat; pFormat += 2 + (number_of_pointers * 8); } else { - fprintf(stderr, "error: NdrpSkipPointerLayout unexpected 0x%02X\n", *pFormat); + WLog_ERR(TAG, "error: NdrpSkipPointerLayout unexpected 0x%02X", *pFormat); break; } } @@ -131,7 +126,6 @@ void NdrpPointerBufferSize(unsigned char* pMemory, PFORMAT_STRING pFormat, PMIDL unsigned char attributes; PFORMAT_STRING pNextFormat; NDR_TYPE_SIZE_ROUTINE pfnSizeRoutine; - type = pFormat[0]; attributes = pFormat[1]; pFormat += 2; @@ -145,7 +139,6 @@ void NdrpPointerBufferSize(unsigned char* pMemory, PFORMAT_STRING pFormat, PMIDL { case FC_RP: /* Reference Pointer */ break; - case FC_UP: /* Unique Pointer */ case FC_OP: /* Unique Pointer in an object interface */ @@ -153,9 +146,8 @@ void NdrpPointerBufferSize(unsigned char* pMemory, PFORMAT_STRING pFormat, PMIDL return; break; - case FC_FP: /* Full Pointer */ - fprintf(stderr, "warning: FC_FP unimplemented\n"); + WLog_ERR(TAG, "warning: FC_FP unimplemented"); break; } @@ -180,7 +172,6 @@ PFORMAT_STRING NdrpEmbeddedRepeatPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned short pointer_count; unsigned short offset_to_array; unsigned short number_of_pointers; - Memory = pStubMsg->Memory; MemoryCopy = pStubMsg->Memory; @@ -201,22 +192,18 @@ PFORMAT_STRING NdrpEmbeddedRepeatPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, if (pFormat[1] == FC_VARIABLE_OFFSET) { - pMemory += pStubMsg->Offset * *((unsigned short*) &pFormat[1]); + pMemory += pStubMsg->Offset * (*(unsigned short*) &pFormat[1]); } } pFormat += 2; increment = *(unsigned short*) pFormat; - pFormat += 2; offset_to_array = *(unsigned short*) pFormat; pStubMsg->Memory = Memory + offset_to_array; - pFormat += 2; number_of_pointers = *(unsigned short*) pFormat; - pFormat += 2; - pFormatPointers = pFormat; if (MaxCount) @@ -249,7 +236,6 @@ PFORMAT_STRING NdrpEmbeddedRepeatPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, pFormat = pFormatPointers + (number_of_pointers * 8); pStubMsg->Memory = Memory; - return pFormat; } @@ -264,7 +250,6 @@ PFORMAT_STRING NdrpEmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsign unsigned long BufferLengthCopy = 0; unsigned long PointerLength; unsigned char* pMemoryPtr = NULL; - pFormatCopy = pFormat; if (!pStubMsg->IgnoreEmbeddedPointers) @@ -296,7 +281,6 @@ PFORMAT_STRING NdrpEmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsign pStubMsg->Offset = Offset; pStubMsg->MaxCount = MaxCount; - NdrpEmbeddedRepeatPointerBufferSize(pStubMsg, pMemory, pFormat, &pMemoryPtr); } @@ -325,7 +309,7 @@ void NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, P void NdrByteCountPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { - fprintf(stderr, "warning: NdrByteCountPointerBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrByteCountPointerBufferSize unimplemented"); } #endif diff --git a/winpr/libwinpr/rpc/ndr_private.h b/winpr/libwinpr/rpc/ndr_private.h index ed8eb9a45..357857e52 100644 --- a/winpr/libwinpr/rpc/ndr_private.h +++ b/winpr/libwinpr/rpc/ndr_private.h @@ -22,6 +22,9 @@ #include +#include "../log.h" +#define TAG WINPR_TAG("rpc") + #ifndef _WIN32 void NdrpAlignLength(ULONG* length, unsigned int alignment); diff --git a/winpr/libwinpr/rpc/ndr_string.c b/winpr/libwinpr/rpc/ndr_string.c index 3cb0e1129..5c0451691 100644 --- a/winpr/libwinpr/rpc/ndr_string.c +++ b/winpr/libwinpr/rpc/ndr_string.c @@ -29,15 +29,16 @@ #ifndef _WIN32 #include "ndr_string.h" +#include "ndr_private.h" void NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { - fprintf(stderr, "warning: NdrConformantStringBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrConformantStringBufferSize unimplemented"); } void NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { - fprintf(stderr, "warning: NdrNonConformantStringBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrNonConformantStringBufferSize unimplemented"); } #endif diff --git a/winpr/libwinpr/rpc/ndr_structure.c b/winpr/libwinpr/rpc/ndr_structure.c index 06ad9ee1a..bc9fe3a67 100644 --- a/winpr/libwinpr/rpc/ndr_structure.c +++ b/winpr/libwinpr/rpc/ndr_structure.c @@ -43,7 +43,6 @@ void NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemo * member_layout<> * FC_END */ - /** * FC_PSTRUCT * alignment<1> @@ -52,24 +51,20 @@ void NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemo * member_layout<> * FC_END */ - unsigned char type; unsigned char alignment; unsigned short memory_size; - type = pFormat[0]; alignment = pFormat[1] + 1; memory_size = *(unsigned short*) &pFormat[2]; - NdrpAlignLength(&(pStubMsg->BufferLength), alignment); NdrpIncrementLength(&(pStubMsg->BufferLength), memory_size); - pFormat += 4; if (*pFormat == FC_PSTRUCT) NdrpEmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); - fprintf(stderr, "warning: NdrSimpleStructBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrSimpleStructBufferSize unimplemented"); } void NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -81,7 +76,6 @@ void NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* p * member_layout<> * FC_END */ - /** * FC_CPSTRUCT alignment<1> * memory_size<2> @@ -89,8 +83,7 @@ void NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* p * pointer_layout<> * member_layout<> FC_END */ - - fprintf(stderr, "warning: NdrConformantStructBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrConformantStructBufferSize unimplemented"); } void NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) @@ -103,8 +96,7 @@ void NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned * layout<> * FC_END */ - - fprintf(stderr, "warning: NdrConformantVaryingStructBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrConformantVaryingStructBufferSize unimplemented"); } ULONG NdrComplexStructMemberSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) @@ -165,8 +157,10 @@ ULONG NdrComplexStructMemberSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFo case FC_FP: case FC_POINTER: size += sizeof(void*); + if (*pFormat != FC_POINTER) pFormat += 4; + break; case FC_ALIGNM2: @@ -195,11 +189,11 @@ ULONG NdrComplexStructMemberSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFo break; case FC_EMBEDDED_COMPLEX: - fprintf(stderr, "warning: NdrComplexStructMemberSize FC_EMBEDDED_COMPLEX unimplemented\n"); + WLog_ERR(TAG, "warning: NdrComplexStructMemberSize FC_EMBEDDED_COMPLEX unimplemented"); break; default: - fprintf(stderr, "warning: NdrComplexStructMemberSize 0x%02X unimplemented\n", *pFormat); + WLog_ERR(TAG, "warning: NdrComplexStructMemberSize 0x%02X unimplemented", *pFormat); break; } @@ -221,12 +215,10 @@ void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem * FC_END * [pointer_layout<>] */ - ULONG_PTR MaxCount; unsigned long Offset; unsigned long ActualCount; unsigned char* pMemoryCopy; - unsigned char type; unsigned char alignment; unsigned short memory_size; @@ -234,64 +226,55 @@ void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem unsigned char* conformant_array_description; unsigned short offset_to_pointer_layout; unsigned short offset_to_conformant_array_description; - type = pFormat[0]; pMemoryCopy = pMemory; pointer_layout = conformant_array_description = NULL; if (type != FC_BOGUS_STRUCT) { - fprintf(stderr, "error: expected FC_BOGUS_STRUCT, got 0x%02X\n", type); + WLog_ERR(TAG, "error: expected FC_BOGUS_STRUCT, got 0x%02X", type); return; } alignment = pFormat[1] + 1; memory_size = *(unsigned short*) &pFormat[2]; - NdrpAlignLength(&(pStubMsg->BufferLength), alignment); if (!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength) { unsigned long BufferLengthCopy = pStubMsg->BufferLength; int IgnoreEmbeddedPointersCopy = pStubMsg->IgnoreEmbeddedPointers; - pStubMsg->IgnoreEmbeddedPointers = 1; NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat); pStubMsg->IgnoreEmbeddedPointers = IgnoreEmbeddedPointersCopy; - pStubMsg->PointerLength = pStubMsg->BufferLength; pStubMsg->BufferLength = BufferLengthCopy; } pFormat += 4; - offset_to_conformant_array_description = *(unsigned short*) &pFormat[0]; if (offset_to_conformant_array_description) conformant_array_description = (unsigned char*) pFormat + offset_to_conformant_array_description; - pFormat += 2; + pFormat += 2; offset_to_pointer_layout = *(unsigned short*) &pFormat[0]; if (offset_to_pointer_layout) pointer_layout = (unsigned char*) pFormat + offset_to_pointer_layout; - pFormat += 2; + pFormat += 2; pStubMsg->Memory = pMemory; if (conformant_array_description) { ULONG size; unsigned char array_type; - array_type = conformant_array_description[0]; size = NdrComplexStructMemberSize(pStubMsg, pFormat); - - fprintf(stderr, "warning: NdrComplexStructBufferSize array_type: 0x%02X unimplemented\n", array_type); - + WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: 0x%02X unimplemented", array_type); NdrpComputeConformance(pStubMsg, pMemory + size, conformant_array_description); NdrpComputeVariance(pStubMsg, pMemory + size, conformant_array_description); - MaxCount = pStubMsg->MaxCount; ActualCount = pStubMsg->ActualCount; Offset = pStubMsg->Offset; @@ -300,14 +283,11 @@ void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMem if (conformant_array_description) { unsigned char array_type; - array_type = conformant_array_description[0]; - pStubMsg->MaxCount = MaxCount; pStubMsg->ActualCount = ActualCount; pStubMsg->Offset = Offset; - - fprintf(stderr, "warning: NdrComplexStructBufferSize array_type: 0x%02X unimplemented\n", array_type); + WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: 0x%02X unimplemented", array_type); } pStubMsg->Memory = pMemoryCopy; diff --git a/winpr/libwinpr/rpc/ndr_union.c b/winpr/libwinpr/rpc/ndr_union.c index e18851529..788464ad4 100644 --- a/winpr/libwinpr/rpc/ndr_union.c +++ b/winpr/libwinpr/rpc/ndr_union.c @@ -29,15 +29,16 @@ #ifndef _WIN32 #include "ndr_union.h" +#include "ndr_private.h" void NdrEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { - fprintf(stderr, "warning: NdrEncapsulatedUnionBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrEncapsulatedUnionBufferSize unimplemented"); } void NdrNonEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { - fprintf(stderr, "warning: NdrNonEncapsulatedUnionBufferSize unimplemented\n"); + WLog_ERR(TAG, "warning: NdrNonEncapsulatedUnionBufferSize unimplemented"); } #endif diff --git a/winpr/libwinpr/rpc/rpc.c b/winpr/libwinpr/rpc/rpc.c index d82e4fe6c..024a6225c 100644 --- a/winpr/libwinpr/rpc/rpc.c +++ b/winpr/libwinpr/rpc/rpc.c @@ -30,519 +30,619 @@ #include +#include "../log.h" +#define TAG WINPR_TAG("rpc") + RPC_STATUS RpcBindingCopy(RPC_BINDING_HANDLE SourceBinding, RPC_BINDING_HANDLE* DestinationBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingFree(RPC_BINDING_HANDLE* Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetOption(RPC_BINDING_HANDLE hBinding, unsigned long option, ULONG_PTR optionValue) { + WLog_ERR(TAG, "Not implemented"); return 0; } -RPC_STATUS RpcBindingInqOption(RPC_BINDING_HANDLE hBinding, unsigned long option, ULONG_PTR *pOptionValue) +RPC_STATUS RpcBindingInqOption(RPC_BINDING_HANDLE hBinding, unsigned long option, ULONG_PTR* pOptionValue) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingFromStringBindingA(RPC_CSTR StringBinding, RPC_BINDING_HANDLE* Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingFromStringBindingW(RPC_WSTR StringBinding, RPC_BINDING_HANDLE* Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcSsGetContextBinding(void* ContextHandle, RPC_BINDING_HANDLE* Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqObject(RPC_BINDING_HANDLE Binding, UUID* ObjectUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingReset(RPC_BINDING_HANDLE Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetObject(RPC_BINDING_HANDLE Binding, UUID* ObjectUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqDefaultProtectLevel(unsigned long AuthnSvc, unsigned long* AuthnLevel) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingToStringBindingA(RPC_BINDING_HANDLE Binding, RPC_CSTR* StringBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingToStringBindingW(RPC_BINDING_HANDLE Binding, RPC_WSTR* StringBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingVectorFree(RPC_BINDING_VECTOR** BindingVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcStringBindingComposeA(RPC_CSTR ObjUuid, RPC_CSTR Protseq, RPC_CSTR NetworkAddr, - RPC_CSTR Endpoint, RPC_CSTR Options, RPC_CSTR* StringBinding) + RPC_CSTR Endpoint, RPC_CSTR Options, RPC_CSTR* StringBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcStringBindingComposeW(RPC_WSTR ObjUuid, RPC_WSTR Protseq, RPC_WSTR NetworkAddr, - RPC_WSTR Endpoint, RPC_WSTR Options, RPC_WSTR* StringBinding) + RPC_WSTR Endpoint, RPC_WSTR Options, RPC_WSTR* StringBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcStringBindingParseA(RPC_CSTR StringBinding, RPC_CSTR* ObjUuid, RPC_CSTR* Protseq, - RPC_CSTR* NetworkAddr, RPC_CSTR *Endpoint, RPC_CSTR* NetworkOptions) + RPC_CSTR* NetworkAddr, RPC_CSTR* Endpoint, RPC_CSTR* NetworkOptions) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcStringBindingParseW(RPC_WSTR StringBinding, RPC_WSTR* ObjUuid, RPC_WSTR* Protseq, - RPC_WSTR* NetworkAddr, RPC_WSTR *Endpoint, RPC_WSTR* NetworkOptions) + RPC_WSTR* NetworkAddr, RPC_WSTR* Endpoint, RPC_WSTR* NetworkOptions) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcStringFreeA(RPC_CSTR* String) { - free(String); + if (String) + free(*String); + return RPC_S_OK; } RPC_STATUS RpcStringFreeW(RPC_WSTR* String) { - free(String); + if (String) + free(*String); + return RPC_S_OK; } RPC_STATUS RpcIfInqId(RPC_IF_HANDLE RpcIfHandle, RPC_IF_ID* RpcIfId) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNetworkIsProtseqValidA(RPC_CSTR Protseq) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNetworkIsProtseqValidW(RPC_WSTR Protseq) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqComTimeout(RPC_BINDING_HANDLE Binding, unsigned int* Timeout) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtSetComTimeout(RPC_BINDING_HANDLE Binding, unsigned int Timeout) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtSetCancelTimeout(long Timeout) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** ProtseqVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNetworkInqProtseqsW(RPC_PROTSEQ_VECTORW** ProtseqVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcObjectInqType(UUID* ObjUuid, UUID* TypeUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcObjectSetInqFn(RPC_OBJECT_INQ_FN* InquiryFn) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcObjectSetType(UUID* ObjUuid, UUID* TypeUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA** ProtseqVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW** ProtseqVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } -RPC_STATUS RpcServerInqBindings (RPC_BINDING_VECTOR** BindingVector) +RPC_STATUS RpcServerInqBindings(RPC_BINDING_VECTOR** BindingVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerInqIf(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV** MgrEpv) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerListen(unsigned int MinimumCallThreads, unsigned int MaxCalls, unsigned int DontWait) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerRegisterIf(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerRegisterIfEx(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, - unsigned int Flags, unsigned int MaxCalls, RPC_IF_CALLBACK_FN* IfCallback) + unsigned int Flags, unsigned int MaxCalls, RPC_IF_CALLBACK_FN* IfCallback) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerRegisterIf2(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, - unsigned int Flags, unsigned int MaxCalls, unsigned int MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn) + unsigned int Flags, unsigned int MaxCalls, unsigned int MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUnregisterIf(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, unsigned int WaitForCallsToComplete) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUnregisterIfEx(RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseAllProtseqs(unsigned int MaxCalls, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseAllProtseqsEx(unsigned int MaxCalls, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseAllProtseqsIf(unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseAllProtseqsIfEx(unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqExA(RPC_CSTR Protseq, unsigned int MaxCalls, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqExW(RPC_WSTR Protseq, unsigned int MaxCalls, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqEpA(RPC_CSTR Protseq, unsigned int MaxCalls, RPC_CSTR Endpoint, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqEpExA(RPC_CSTR Protseq, unsigned int MaxCalls, RPC_CSTR Endpoint, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqEpW(RPC_WSTR Protseq, unsigned int MaxCalls, RPC_WSTR Endpoint, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqEpExW(RPC_WSTR Protseq, unsigned int MaxCalls, RPC_WSTR Endpoint, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqIfA(RPC_CSTR Protseq, unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqIfExA(RPC_CSTR Protseq, unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqIfW(RPC_WSTR Protseq, unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerUseProtseqIfExW(RPC_WSTR Protseq, unsigned int MaxCalls, RPC_IF_HANDLE IfSpec, void* SecurityDescriptor, PRPC_POLICY Policy) { + WLog_ERR(TAG, "Not implemented"); return 0; } void RpcServerYield() { - + WLog_ERR(TAG, "Not implemented"); } RPC_STATUS RpcMgmtStatsVectorFree(RPC_STATS_VECTOR** StatsVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqStats(RPC_BINDING_HANDLE Binding, RPC_STATS_VECTOR** Statistics) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtStopServerListening(RPC_BINDING_HANDLE Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtWaitServerListen(void) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtSetServerStackSize(unsigned long ThreadStackSize) { + WLog_ERR(TAG, "Not implemented"); return 0; } void RpcSsDontSerializeContext(void) { - + WLog_ERR(TAG, "Not implemented"); } RPC_STATUS RpcMgmtEnableIdleCleanup(void) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR** IfIdVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcIfIdVectorFree(RPC_IF_ID_VECTOR** IfIdVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqServerPrincNameA(RPC_BINDING_HANDLE Binding, unsigned long AuthnSvc, RPC_CSTR* ServerPrincName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtInqServerPrincNameW(RPC_BINDING_HANDLE Binding, unsigned long AuthnSvc, RPC_WSTR* ServerPrincName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerInqDefaultPrincNameA(unsigned long AuthnSvc, RPC_CSTR* PrincName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerInqDefaultPrincNameW(unsigned long AuthnSvc, RPC_WSTR* PrincName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcEpResolveBinding(RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNsBindingInqEntryNameA(RPC_BINDING_HANDLE Binding, unsigned long EntryNameSyntax, RPC_CSTR* EntryName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcNsBindingInqEntryNameW(RPC_BINDING_HANDLE Binding, unsigned long EntryNameSyntax, RPC_WSTR* EntryName) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcRevertToSelf() { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthClientA(RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE* Privs, - RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc) + RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthClientW(RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE* Privs, - RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc) + RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthClientExA(RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE* Privs, - RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc, unsigned long Flags) + RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc, unsigned long Flags) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthClientExW(RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE* Privs, - RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc, unsigned long Flags) + RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, unsigned long* AuthnSvc, unsigned long* AuthzSvc, unsigned long Flags) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthInfoA(RPC_BINDING_HANDLE Binding, RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, - unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc) + unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthInfoW(RPC_BINDING_HANDLE Binding, RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, - unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc) + unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetAuthInfoA(RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, unsigned long AuthnLevel, - unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc) + unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetAuthInfoExA(RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, unsigned long AuthnLevel, - unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc, RPC_SECURITY_QOS* SecurityQos) + unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc, RPC_SECURITY_QOS* SecurityQos) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetAuthInfoW(RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, unsigned long AuthnLevel, - unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc) + unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, unsigned long AuthnLevel, - unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc, RPC_SECURITY_QOS* SecurityQOS) + unsigned long AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, unsigned long AuthzSvc, RPC_SECURITY_QOS* SecurityQOS) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthInfoExA(RPC_BINDING_HANDLE Binding, RPC_CSTR* ServerPrincName, unsigned long* AuthnLevel, - unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc, - unsigned long RpcQosVersion, RPC_SECURITY_QOS* SecurityQOS) + unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc, + unsigned long RpcQosVersion, RPC_SECURITY_QOS* SecurityQOS) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingInqAuthInfoExW(RPC_BINDING_HANDLE Binding, RPC_WSTR* ServerPrincName, unsigned long* AuthnLevel, - unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc, - unsigned long RpcQosVersion, RPC_SECURITY_QOS* SecurityQOS) + unsigned long* AuthnSvc, RPC_AUTH_IDENTITY_HANDLE* AuthIdentity, unsigned long* AuthzSvc, + unsigned long RpcQosVersion, RPC_SECURITY_QOS* SecurityQOS) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerRegisterAuthInfoA(RPC_CSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, void* Arg) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerRegisterAuthInfoW(RPC_WSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, void* Arg) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcBindingServerFromClient(RPC_BINDING_HANDLE ClientBinding, RPC_BINDING_HANDLE* ServerBinding) { + WLog_ERR(TAG, "Not implemented"); return 0; } void RpcRaiseException(RPC_STATUS exception) { - fprintf(stderr, "RpcRaiseException: 0x%08luX\n", exception); + WLog_ERR(TAG, "RpcRaiseException: 0x%08luX", exception); exit((int) exception); } RPC_STATUS RpcTestCancel() { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerTestCancel(RPC_BINDING_HANDLE BindingHandle) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcCancelThread(void* Thread) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcCancelThreadEx(void* Thread, long Timeout) { + WLog_ERR(TAG, "Not implemented"); return 0; } @@ -582,18 +682,17 @@ RPC_STATUS UuidToStringA(UUID* Uuid, RPC_CSTR* StringUuid) * Format is 32 hex digits partitioned in 5 groups: * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ - sprintf_s((char*) *StringUuid, 36 + 1, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - Uuid->Data1, Uuid->Data2, Uuid->Data3, - Uuid->Data4[0], Uuid->Data4[1], - Uuid->Data4[2], Uuid->Data4[3], Uuid->Data4[4], - Uuid->Data4[5], Uuid->Data4[6], Uuid->Data4[7]); - + Uuid->Data1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], + Uuid->Data4[2], Uuid->Data4[3], Uuid->Data4[4], + Uuid->Data4[5], Uuid->Data4[6], Uuid->Data4[7]); return RPC_S_OK; } RPC_STATUS UuidToStringW(UUID* Uuid, RPC_WSTR* StringUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } @@ -630,11 +729,9 @@ RPC_STATUS UuidFromStringA(RPC_CSTR StringUuid, UUID* Uuid) } Uuid->Data1 = ((bin[0] << 28) | (bin[1] << 24) | (bin[2] << 20) | (bin[3] << 16) | - (bin[4] << 12) | (bin[5] << 8) | (bin[6] << 4) | bin[7]); - + (bin[4] << 12) | (bin[5] << 8) | (bin[6] << 4) | bin[7]); Uuid->Data2 = ((bin[9] << 12) | (bin[10] << 8) | (bin[11] << 4) | bin[12]); Uuid->Data3 = ((bin[14] << 12) | (bin[15] << 8) | (bin[16] << 4) | bin[17]); - Uuid->Data4[0] = ((bin[19] << 4) | bin[20]); Uuid->Data4[1] = ((bin[21] << 4) | bin[22]); Uuid->Data4[2] = ((bin[24] << 4) | bin[25]); @@ -643,19 +740,18 @@ RPC_STATUS UuidFromStringA(RPC_CSTR StringUuid, UUID* Uuid) Uuid->Data4[5] = ((bin[30] << 4) | bin[31]); Uuid->Data4[6] = ((bin[32] << 4) | bin[33]); Uuid->Data4[7] = ((bin[34] << 4) | bin[35]); - return RPC_S_OK; } RPC_STATUS UuidFromStringW(RPC_WSTR StringUuid, UUID* Uuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } signed int UuidCompare(UUID* Uuid1, UUID* Uuid2, RPC_STATUS* Status) { int index; - *Status = RPC_S_OK; if (!Uuid1) @@ -695,6 +791,7 @@ int UuidEqual(UUID* Uuid1, UUID* Uuid2, RPC_STATUS* Status) unsigned short UuidHash(UUID* Uuid, RPC_STATUS* Status) { + WLog_ERR(TAG, "Not implemented"); return 0; } @@ -705,78 +802,92 @@ int UuidIsNil(UUID* Uuid, RPC_STATUS* Status) RPC_STATUS RpcEpRegisterNoReplaceA(RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR* BindingVector, UUID_VECTOR* UuidVector, RPC_CSTR Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcEpRegisterNoReplaceW(RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR* BindingVector, UUID_VECTOR* UuidVector, RPC_WSTR Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcEpRegisterA(RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR* BindingVector, UUID_VECTOR* UuidVector, RPC_CSTR Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcEpRegisterW(RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR* BindingVector, UUID_VECTOR* UuidVector, RPC_WSTR Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcEpUnregister(RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR* BindingVector, UUID_VECTOR* UuidVector) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS DceErrorInqTextA(RPC_STATUS RpcStatus, RPC_CSTR ErrorText) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS DceErrorInqTextW(RPC_STATUS RpcStatus, RPC_WSTR ErrorText) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE EpBinding, unsigned long InquiryType, RPC_IF_ID* IfId, - unsigned long VersOption, UUID* ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext) + unsigned long VersOption, UUID* ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtEpEltInqDone(RPC_EP_INQ_HANDLE* InquiryContext) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtEpEltInqNextA(RPC_EP_INQ_HANDLE InquiryContext, RPC_IF_ID* IfId, - RPC_BINDING_HANDLE* Binding, UUID* ObjectUuid, RPC_CSTR* Annotation) + RPC_BINDING_HANDLE* Binding, UUID* ObjectUuid, RPC_CSTR* Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtEpEltInqNextW(RPC_EP_INQ_HANDLE InquiryContext, RPC_IF_ID* IfId, - RPC_BINDING_HANDLE* Binding, UUID* ObjectUuid, RPC_WSTR* Annotation) + RPC_BINDING_HANDLE* Binding, UUID* ObjectUuid, RPC_WSTR* Annotation) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtEpUnregister(RPC_BINDING_HANDLE EpBinding, RPC_IF_ID* IfId, - RPC_BINDING_HANDLE Binding, UUID* ObjectUuid) + RPC_BINDING_HANDLE Binding, UUID* ObjectUuid) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcMgmtSetAuthorizationFn(RPC_MGMT_AUTHORIZATION_FN AuthorizationFn) { + WLog_ERR(TAG, "Not implemented"); return 0; } RPC_STATUS RpcServerInqBindingHandle(RPC_BINDING_HANDLE* Binding) { + WLog_ERR(TAG, "Not implemented"); return 0; } diff --git a/winpr/libwinpr/security/CMakeLists.txt b/winpr/libwinpr/security/CMakeLists.txt index 0630beea1..98141e1a0 100644 --- a/winpr/libwinpr/security/CMakeLists.txt +++ b/winpr/libwinpr/security/CMakeLists.txt @@ -15,30 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-security") -set(MODULE_PREFIX "WINPR_SECURITY") - -set(${MODULE_PREFIX}_SRCS - security.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(security.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/security/test/CMakeLists.txt b/winpr/libwinpr/security/test/CMakeLists.txt index 9365b1c66..d9aacb160 100644 --- a/winpr/libwinpr/security/test/CMakeLists.txt +++ b/winpr/libwinpr/security/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-security) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/smartcard/CMakeLists.txt b/winpr/libwinpr/smartcard/CMakeLists.txt index ec1948d53..3f59e7392 100644 --- a/winpr/libwinpr/smartcard/CMakeLists.txt +++ b/winpr/libwinpr/smartcard/CMakeLists.txt @@ -15,15 +15,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-smartcard") set(MODULE_PREFIX "WINPR_SMARTCARD") if(PCSC_WINPR_FOUND) - add_definitions(-DWITH_WINPR_PCSC) + winpr_definition_add(-DWITH_WINPR_PCSC) endif() if(WITH_SMARTCARD_INSPECT) - add_definitions(-DWITH_SMARTCARD_INSPECT) + winpr_definition_add(-DWITH_SMARTCARD_INSPECT) endif() set(${MODULE_PREFIX}_SRCS @@ -41,35 +40,12 @@ if(WIN32) smartcard_winscard.h) endif() -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-library winpr-environment winpr-utils) +winpr_module_add(${${MODULE_PREFIX}_SRCS}) if(PCSC_WINPR_FOUND) - list(APPEND ${MODULE_PREFIX}_LIBS ${PCSC_WINPR_LIBRARY}) + winpr_library_add(${PCSC_WINPR_LIBRARY}) endif() -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index 75cc5dd36..d9878cf76 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -37,6 +37,9 @@ #include "smartcard_pcsc.h" +#include "../log.h" +#define TAG WINPR_TAG("smartcard") + /** * PC/SC transactions: * http://developersblog.wwpass.com/?p=180 @@ -168,7 +171,8 @@ static wListDictionary* g_MemoryBlocks = NULL; char SMARTCARD_PNP_NOTIFICATION_A[] = "\\\\?PnP?\\Notification"; WCHAR SMARTCARD_PNP_NOTIFICATION_W[] = { '\\','\\','?','P','n','P','?', - '\\','N','o','t','i','f','i','c','a','t','i','o','n','\0' }; + '\\','N','o','t','i','f','i','c','a','t','i','o','n','\0' + }; const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(PCSC_SCARD_IO_REQUEST) }; const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(PCSC_SCARD_IO_REQUEST) }; @@ -189,7 +193,6 @@ LONG PCSC_MapErrorCodeToWinSCard(LONG errorCode) * define SCARD_E_UNSUPPORTED_FEATURE to 0x8010001F, * when the real value should be 0x80100022. */ - if (errorCode == SCARD_E_UNEXPECTED) errorCode = SCARD_E_UNSUPPORTED_FEATURE; @@ -214,7 +217,6 @@ DWORD PCSC_ConvertCardStateToWinSCard(DWORD dwCardState, LONG status) * pcsc-lite also never sets SCARD_SPECIFIC, * which is expected by some windows applications. */ - if (status == SCARD_S_SUCCESS) { if ((dwCardState & PCSC_SCARD_NEGOTIABLE) || (dwCardState & PCSC_SCARD_SPECIFIC)) @@ -223,16 +225,22 @@ DWORD PCSC_ConvertCardStateToWinSCard(DWORD dwCardState, LONG status) if (dwCardState & PCSC_SCARD_POWERED) return SCARD_POWERED; + if (dwCardState & PCSC_SCARD_NEGOTIABLE) return SCARD_NEGOTIABLE; + if (dwCardState & PCSC_SCARD_SPECIFIC) return SCARD_SPECIFIC; + if (dwCardState & PCSC_SCARD_ABSENT) return SCARD_ABSENT; + if (dwCardState & PCSC_SCARD_PRESENT) return SCARD_PRESENT; + if (dwCardState & PCSC_SCARD_SWALLOWED) return SCARD_SWALLOWED; + if (dwCardState & PCSC_SCARD_UNKNOWN) return SCARD_UNKNOWN; @@ -245,7 +253,6 @@ DWORD PCSC_ConvertProtocolsToWinSCard(DWORD dwProtocols) * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW, * and also has SCARD_PROTOCOL_T15 which is not in WinSCard. */ - if (dwProtocols & PCSC_SCARD_PROTOCOL_RAW) { dwProtocols &= ~PCSC_SCARD_PROTOCOL_RAW; @@ -266,7 +273,6 @@ DWORD PCSC_ConvertProtocolsFromWinSCard(DWORD dwProtocols) * pcsc-lite uses a different value for SCARD_PROTOCOL_RAW, * and it does not define WinSCard's SCARD_PROTOCOL_DEFAULT. */ - if (dwProtocols & SCARD_PROTOCOL_RAW) { dwProtocols &= ~SCARD_PROTOCOL_RAW; @@ -313,14 +319,12 @@ PCSC_SCARDCONTEXT* PCSC_GetCardContextData(SCARDCONTEXT hContext) PCSC_SCARDCONTEXT* PCSC_EstablishCardContext(SCARDCONTEXT hContext) { PCSC_SCARDCONTEXT* pContext; - pContext = (PCSC_SCARDCONTEXT*) calloc(1, sizeof(PCSC_SCARDCONTEXT)); if (!pContext) return NULL; pContext->hContext = hContext; - InitializeCriticalSectionAndSpinCount(&(pContext->lock), 4000); if (!g_CardContexts) @@ -333,24 +337,21 @@ PCSC_SCARDCONTEXT* PCSC_EstablishCardContext(SCARDCONTEXT hContext) } ListDictionary_Add(g_CardContexts, (void*) hContext, (void*) pContext); - return pContext; } void PCSC_ReleaseCardContext(SCARDCONTEXT hContext) { PCSC_SCARDCONTEXT* pContext; - pContext = PCSC_GetCardContextData(hContext); if (!pContext) { - printf("PCSC_ReleaseCardContext: null pContext!\n"); + WLog_ERR(TAG, "PCSC_ReleaseCardContext: null pContext!"); return; } DeleteCriticalSection(&(pContext->lock)); - free(pContext); if (!g_CardContexts) @@ -362,34 +363,30 @@ void PCSC_ReleaseCardContext(SCARDCONTEXT hContext) BOOL PCSC_LockCardContext(SCARDCONTEXT hContext) { PCSC_SCARDCONTEXT* pContext; - pContext = PCSC_GetCardContextData(hContext); if (!pContext) { - fprintf(stderr, "PCSC_LockCardContext: invalid context (%p)\n", (void*) hContext); + WLog_ERR(TAG, "PCSC_LockCardContext: invalid context (%p)", (void*) hContext); return FALSE; } EnterCriticalSection(&(pContext->lock)); - return TRUE; } BOOL PCSC_UnlockCardContext(SCARDCONTEXT hContext) { PCSC_SCARDCONTEXT* pContext; - pContext = PCSC_GetCardContextData(hContext); if (!pContext) { - fprintf(stderr, "PCSC_UnlockCardContext: invalid context (%p)\n", (void*) hContext); + WLog_ERR(TAG, "PCSC_UnlockCardContext: invalid context (%p)", (void*) hContext); return FALSE; } LeaveCriticalSection(&(pContext->lock)); - return TRUE; } @@ -411,7 +408,6 @@ PCSC_SCARDHANDLE* PCSC_GetCardHandleData(SCARDHANDLE hCard) SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) @@ -424,12 +420,11 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTE { PCSC_SCARDHANDLE* pCard; PCSC_SCARDCONTEXT* pContext; - pContext = PCSC_GetCardContextData(hSharedContext); if (!pContext) { - printf("PCSC_ConnectCardHandle: null pContext!\n"); + WLog_ERR(TAG, "PCSC_ConnectCardHandle: null pContext!"); return NULL; } @@ -440,16 +435,13 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTE pCard->hSharedContext = hSharedContext; pCard->hPrivateContext = hPrivateContext; - InitializeCriticalSectionAndSpinCount(&(pCard->lock), 4000); - pContext->dwCardHandleCount++; if (!g_CardHandles) g_CardHandles = ListDictionary_New(TRUE); ListDictionary_Add(g_CardHandles, (void*) hCard, (void*) pCard); - return pCard; } @@ -457,18 +449,14 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; PCSC_SCARDCONTEXT* pContext; - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) return; DeleteCriticalSection(&(pCard->lock)); - pContext = PCSC_GetCardContextData(pCard->hSharedContext); - PCSC_SCardReleaseContext_Internal(pCard->hPrivateContext); - free(pCard); if (!g_CardHandles) @@ -478,7 +466,7 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) if (!pContext) { - printf("PCSC_DisconnectCardHandle: null pContext!"); + WLog_ERR(TAG, "PCSC_DisconnectCardHandle: null pContext!"); return; } @@ -488,72 +476,62 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) BOOL PCSC_LockCardHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) { - fprintf(stderr, "PCSC_LockCardHandle: invalid handle (%p)\n", (void*) hCard); + WLog_ERR(TAG, "PCSC_LockCardHandle: invalid handle (%p)", (void*) hCard); return FALSE; } EnterCriticalSection(&(pCard->lock)); - return TRUE; } BOOL PCSC_UnlockCardHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) { - fprintf(stderr, "PCSC_UnlockCardHandle: invalid handle (%p)\n", (void*) hCard); + WLog_ERR(TAG, "PCSC_UnlockCardHandle: invalid handle (%p)", (void*) hCard); return FALSE; } LeaveCriticalSection(&(pCard->lock)); - return TRUE; } BOOL PCSC_LockCardTransaction(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - return TRUE; /* disable for now because it deadlocks */ - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) { - fprintf(stderr, "PCSC_LockCardTransaction: invalid handle (%p)\n", (void*) hCard); + WLog_ERR(TAG, "PCSC_LockCardTransaction: invalid handle (%p)", (void*) hCard); return FALSE; } EnterCriticalSection(&(pCard->lock)); - return TRUE; } BOOL PCSC_UnlockCardTransaction(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - return TRUE; /* disable for now because it deadlocks */ - pCard = PCSC_GetCardHandleData(hCard); if (!pCard) { - fprintf(stderr, "PCSC_UnlockCardTransaction: invalid handle (%p)\n", (void*) hCard); + WLog_ERR(TAG, "PCSC_UnlockCardTransaction: invalid handle (%p)", (void*) hCard); return FALSE; } LeaveCriticalSection(&(pCard->lock)); - return TRUE; } @@ -563,9 +541,7 @@ char* PCSC_GetReaderNameFromAlias(char* nameWinSCard) int count; PCSC_READER* reader; char* namePCSC = NULL; - ArrayList_Lock(g_Readers); - count = ArrayList_Count(g_Readers); for (index = 0; index < count; index++) @@ -580,7 +556,6 @@ char* PCSC_GetReaderNameFromAlias(char* nameWinSCard) } ArrayList_Unlock(g_Readers); - return namePCSC; } @@ -598,9 +573,7 @@ BOOL PCSC_AddReaderNameAlias(char* namePCSC, char* nameWinSCard) reader->namePCSC = _strdup(namePCSC); reader->nameWinSCard = _strdup(nameWinSCard); - ArrayList_Add(g_Readers, reader); - return TRUE; } @@ -628,10 +601,9 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) int length; int ctoken; int ntokens; - char *p, *q; + char* p, *q; char* tokens[64][2]; char* nameWinSCard; - /** * pcsc-lite reader name format: * name [interface] (serial) index slot @@ -672,7 +644,6 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) * the index is a two digit zero-padded integer * the slot is a two digit zero-padded integer */ - length = strlen(name); if (length < 10) @@ -703,11 +674,9 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) slot = index = -1; ctoken = ntokens - 1; - - slot = PCSC_AtoiWithLength(tokens[ctoken][0], (int) (tokens[ctoken][1] - tokens[ctoken][0])); + slot = PCSC_AtoiWithLength(tokens[ctoken][0], (int)(tokens[ctoken][1] - tokens[ctoken][0])); ctoken--; - - index = PCSC_AtoiWithLength(tokens[ctoken][0], (int) (tokens[ctoken][1] - tokens[ctoken][0])); + index = PCSC_AtoiWithLength(tokens[ctoken][0], (int)(tokens[ctoken][1] - tokens[ctoken][0])); ctoken--; if (index < 0) @@ -716,7 +685,7 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) index = slot; ctoken++; } - + if ((index < 0) || (slot < 0)) return NULL; @@ -724,6 +693,7 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) { while ((*(tokens[ctoken][0]) != '(') && (ctoken > 0)) ctoken--; + ctoken--; } @@ -734,6 +704,7 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) { while ((*(tokens[ctoken][0]) != '[') && (ctoken > 0)) ctoken--; + ctoken--; } @@ -742,10 +713,8 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) p = tokens[0][0]; q = tokens[ctoken][1]; - length = (q - p); size = length + 16; - nameWinSCard = (char*) malloc(size); if (!nameWinSCard) @@ -756,20 +725,14 @@ char* PCSC_ConvertReaderNameToWinSCard(const char* name) * while WinSCard uses an index number based on readers of the same name. * Force an index number of 0 for now, fix later. */ - index = 0; - sprintf_s(nameWinSCard, size, "%.*s %d", length, p, index); - - //printf("Smart Card Reader Name Alias: %s -> %s\n", p, nameWinSCard); - return nameWinSCard; } char* PCSC_GetReaderAliasFromName(char* namePCSC) { char* nameWinSCard; - nameWinSCard = PCSC_ConvertReaderNameToWinSCard(namePCSC); if (nameWinSCard) @@ -781,14 +744,12 @@ char* PCSC_GetReaderAliasFromName(char* namePCSC) char* PCSC_ConvertReaderNamesToWinSCard(const char* names, LPDWORD pcchReaders) { int length; - char *p, *q; + char* p, *q; DWORD cchReaders; char* nameWinSCard; char* namesWinSCard; - p = (char*) names; cchReaders = *pcchReaders; - namesWinSCard = (char*) malloc(cchReaders * 2); if (!namesWinSCard) @@ -816,29 +777,24 @@ char* PCSC_ConvertReaderNamesToWinSCard(const char* names, LPDWORD pcchReaders) q += length; *q = '\0'; q++; - p += strlen(p) + 1; } *q = '\0'; q++; - - *pcchReaders = (DWORD) (q - namesWinSCard); - + *pcchReaders = (DWORD)(q - namesWinSCard); return namesWinSCard; } char* PCSC_ConvertReaderNamesToPCSC(const char* names, LPDWORD pcchReaders) { int length; - char *p, *q; + char* p, *q; char* namePCSC; char* namesPCSC; DWORD cchReaders; - p = (char*) names; cchReaders = *pcchReaders; - namesPCSC = (char*) malloc(cchReaders * 2); if (!namesPCSC) @@ -856,19 +812,15 @@ char* PCSC_ConvertReaderNamesToPCSC(const char* names, LPDWORD pcchReaders) length = strlen(namePCSC); CopyMemory(q, namePCSC, length); - q += length; *q = '\0'; q++; - p += strlen(p) + 1; } *q = '\0'; q++; - - *pcchReaders = (DWORD) (q - namesPCSC); - + *pcchReaders = (DWORD)(q - namesPCSC); return namesPCSC; } @@ -891,14 +843,12 @@ void* PCSC_RemoveMemoryBlock(SCARDCONTEXT hContext, void* pvMem) void* PCSC_SCardAllocMemory(SCARDCONTEXT hContext, size_t size) { void* pvMem; - pvMem = malloc(size); if (!pvMem) return NULL; PCSC_AddMemoryBlock(hContext, pvMem); - return pvMem; } @@ -916,10 +866,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope, return SCARD_E_NO_SERVICE; pcsc_dwScope = SCARD_SCOPE_SYSTEM; /* this is the only scope supported by pcsc-lite */ - status = (LONG) g_PCSC.pfnSCardEstablishContext(pcsc_dwScope, pvReserved1, pvReserved2, phContext); status = PCSC_MapErrorCodeToWinSCard(status); - return status; } @@ -927,7 +875,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) { LONG status = SCARD_S_SUCCESS; - status = PCSC_SCardEstablishContext_Internal(dwScope, pvReserved1, pvReserved2, phContext); if (status == SCARD_S_SUCCESS) @@ -945,20 +892,18 @@ WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext) if (!hContext) { - fprintf(stderr, "SCardReleaseContext: null hContext\n"); + WLog_ERR(TAG, "SCardReleaseContext: null hContext"); return status; } status = (LONG) g_PCSC.pfnSCardReleaseContext(hContext); status = PCSC_MapErrorCodeToWinSCard(status); - return status; } WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext) { LONG status = SCARD_S_SUCCESS; - status = PCSC_SCardReleaseContext_Internal(hContext); if (status != SCARD_S_SUCCESS) @@ -976,7 +921,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardIsValidContext(SCARDCONTEXT hContext) status = (LONG) g_PCSC.pfnSCardIsValidContext(hContext); status = PCSC_MapErrorCodeToWinSCard(status); - return status; } @@ -994,7 +938,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReaderGroupsA(SCARDCONTEXT hContext, status = (LONG) g_PCSC.pfnSCardListReaderGroups(hContext, mszGroups, &pcsc_cchGroups); status = PCSC_MapErrorCodeToWinSCard(status); - *pcchGroups = (DWORD) pcsc_cchGroups; if (!PCSC_UnlockCardContext(hContext)) @@ -1017,12 +960,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReaderGroupsW(SCARDCONTEXT hContext, mszGroups = NULL; pcchGroups = 0; - /* FIXME: unicode conversion */ - status = (LONG) g_PCSC.pfnSCardListReaderGroups(hContext, (LPSTR) mszGroups, &pcsc_cchGroups); status = PCSC_MapErrorCodeToWinSCard(status); - *pcchGroups = (DWORD) pcsc_cchGroups; if (!PCSC_UnlockCardContext(hContext)) @@ -1056,7 +996,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReaders_Internal(SCARDCONTEXT hContext, if (pcchReadersAlloc && !g_SCardAutoAllocate) { pcsc_cchReaders = 0; - status = (LONG) g_PCSC.pfnSCardListReaders(hContext, mszGroups, NULL, &pcsc_cchReaders); if (status == SCARD_S_SUCCESS) @@ -1080,7 +1019,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReaders_Internal(SCARDCONTEXT hContext, } status = PCSC_MapErrorCodeToWinSCard(status); - *pcchReaders = (DWORD) pcsc_cchReaders; if (status == SCARD_S_SUCCESS) @@ -1090,7 +1028,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReaders_Internal(SCARDCONTEXT hContext, if (mszReadersWinSCard) { PCSC_SCardFreeMemory_Internal(hContext, *pMszReaders); - *pMszReaders = mszReadersWinSCard; PCSC_AddMemoryBlock(hContext, *pMszReaders); } @@ -1170,7 +1107,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReadersW(SCARDCONTEXT hContext, { *pcchReaders = ConvertToUnicode(CP_UTF8, 0, *pMszReadersA, *pcchReaders, (WCHAR**) mszReaders, 0); PCSC_AddMemoryBlock(hContext, mszReaders); - PCSC_SCardFreeMemory_Internal(hContext, *pMszReadersA); } @@ -1383,7 +1319,6 @@ WINSCARDAPI HANDLE WINAPI PCSC_SCardAccessStartedEvent(void) { LONG status = 0; SCARDCONTEXT hContext = 0; - status = PCSC_SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (status != SCARD_S_SUCCESS) @@ -1401,7 +1336,6 @@ WINSCARDAPI HANDLE WINAPI PCSC_SCardAccessStartedEvent(void) } g_StartedEventRefCount++; - return g_StartedEvent; } @@ -1458,7 +1392,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext if (!g_PCSC.pfnSCardGetStatusChange) return SCARD_E_NO_SERVICE; - + if (!cReaders) return SCARD_S_SUCCESS; @@ -1475,17 +1409,16 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext * To work around this apparent lack of "\\\\?PnP?\\Notification" support, * we have to filter rgReaderStates to exclude the special PnP reader name. */ - map = (int*) calloc(pcsc_cReaders, sizeof(int)); - + if (!map) return SCARD_E_NO_MEMORY; - + states = (PCSC_SCARD_READERSTATE*) calloc(pcsc_cReaders, sizeof(PCSC_SCARD_READERSTATE)); if (!states) return SCARD_E_NO_MEMORY; - + for (i = j = 0; i < pcsc_cReaders; i++) { if (!g_PnP_Notification) @@ -1496,9 +1429,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext continue; } } - + map[i] = j; - states[j].szReader = PCSC_GetReaderNameFromAlias((char*) rgReaderStates[i].szReader); if (!states[j].szReader) @@ -1508,10 +1440,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext states[j].dwEventState = rgReaderStates[i].dwEventState; states[j].cbAtr = rgReaderStates[i].cbAtr; CopyMemory(&(states[j].rgbAtr), &(rgReaderStates[i].rgbAtr), PCSC_MAX_ATR_SIZE); - j++; } - + cMappedReaders = j; /** @@ -1521,9 +1452,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext if (cMappedReaders > 0) { status = (LONG) g_PCSC.pfnSCardGetStatusChange(hContext, - pcsc_dwTimeout ? pcsc_dwTimeout : 1, - states, cMappedReaders); - + pcsc_dwTimeout ? pcsc_dwTimeout : 1, + states, cMappedReaders); status = PCSC_MapErrorCodeToWinSCard(status); } else @@ -1535,16 +1465,13 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext { if (map[i] < 0) continue; /* unmapped */ - + j = map[i]; - rgReaderStates[i].dwCurrentState = states[j].dwCurrentState; rgReaderStates[i].cbAtr = states[j].cbAtr; CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[j].rgbAtr), PCSC_MAX_ATR_SIZE); - /* pcsc-lite puts an event count in the higher bits of dwEventState */ states[j].dwEventState &= 0xFFFF; - dwEventState = states[j].dwEventState & ~SCARD_STATE_CHANGED; if (dwEventState != rgReaderStates[i].dwCurrentState) @@ -1575,7 +1502,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext free(states); free(map); - return status; } @@ -1620,8 +1546,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChangeW(SCARDCONTEXT hContext, { states[index].szReader = NULL; ConvertFromUnicode(CP_UTF8, 0, rgReaderStates[index].szReader, -1, - (char**) &(states[index].szReader), 0, NULL, NULL); - + (char**) &(states[index].szReader), 0, NULL, NULL); states[index].pvUserData = rgReaderStates[index].pvUserData; states[index].dwCurrentState = rgReaderStates[index].dwCurrentState; states[index].dwEventState = rgReaderStates[index].dwEventState; @@ -1658,7 +1583,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardCancel(SCARDCONTEXT hContext) status = (LONG) g_PCSC.pfnSCardCancel(hContext); status = PCSC_MapErrorCodeToWinSCard(status); - return status; } @@ -1687,9 +1611,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext, szReaderPCSC = (char*) szReader; pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols); - status = (LONG) g_PCSC.pfnSCardConnect(hPrivateContext, szReaderPCSC, - pcsc_dwShareMode, pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol); + pcsc_dwShareMode, pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol); status = PCSC_MapErrorCodeToWinSCard(status); if (status == SCARD_S_SUCCESS) @@ -1715,7 +1638,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectA(SCARDCONTEXT hContext, return SCARD_E_INVALID_HANDLE; status = PCSC_SCardConnect_Internal(hContext, szReader, dwShareMode, - dwPreferredProtocols, phCard, pdwActiveProtocol); + dwPreferredProtocols, phCard, pdwActiveProtocol); if (!PCSC_UnlockCardContext(hContext)) return SCARD_E_INVALID_HANDLE; @@ -1737,8 +1660,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectW(SCARDCONTEXT hContext, ConvertFromUnicode(CP_UTF8, 0, szReader, -1, &szReaderA, 0, NULL, NULL); status = PCSC_SCardConnect_Internal(hContext, szReaderA, dwShareMode, - dwPreferredProtocols, phCard, pdwActiveProtocol); - + dwPreferredProtocols, phCard, pdwActiveProtocol); free(szReaderA); if (!PCSC_UnlockCardContext(hContext)) @@ -1760,13 +1682,10 @@ WINSCARDAPI LONG WINAPI PCSC_SCardReconnect(SCARDHANDLE hCard, return SCARD_E_NO_SERVICE; pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols); - status = (LONG) g_PCSC.pfnSCardReconnect(hCard, pcsc_dwShareMode, - pcsc_dwPreferredProtocols, pcsc_dwInitialization, &pcsc_dwActiveProtocol); + pcsc_dwPreferredProtocols, pcsc_dwInitialization, &pcsc_dwActiveProtocol); status = PCSC_MapErrorCodeToWinSCard(status); - *pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD) pcsc_dwActiveProtocol); - return status; } @@ -1818,7 +1737,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard) } pContext->isTransactionLocked = TRUE; - return status; } @@ -1852,7 +1770,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisp } pContext->isTransactionLocked = FALSE; - return status; } @@ -1862,7 +1779,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardCancelTransaction(SCARDHANDLE hCard) } WINSCARDAPI LONG WINAPI PCSC_SCardState(SCARDHANDLE hCard, - LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) + LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) { PCSC_DWORD cchReaderLen; SCARDCONTEXT hContext = 0; @@ -1881,9 +1798,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardState(SCARDHANDLE hCard, return SCARD_E_INVALID_VALUE; cchReaderLen = SCARD_AUTOALLOCATE; - status = (LONG) g_PCSC.pfnSCardStatus(hCard, (LPSTR) &mszReaderNames, &cchReaderLen, - &pcsc_dwState, &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen); + &pcsc_dwState, &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen); status = PCSC_MapErrorCodeToWinSCard(status); if (mszReaderNames) @@ -1892,7 +1808,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardState(SCARDHANDLE hCard, *pdwState = (DWORD) pcsc_dwState; *pdwProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD) pcsc_dwProtocol); *pcbAtrLen = (DWORD) pcsc_cbAtrLen; - return status; } @@ -1939,9 +1854,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatus_Internal(SCARDHANDLE hCard, pcsc_cbAtrLen = 0; status = (LONG) g_PCSC.pfnSCardStatus(hCard, - (pcchReaderLenAlloc) ? NULL : mszReaderNames, &pcsc_cchReaderLen, - &pcsc_dwState, &pcsc_dwProtocol, - (pcbAtrLenAlloc) ? NULL : pbAtr, &pcsc_cbAtrLen); + (pcchReaderLenAlloc) ? NULL : mszReaderNames, &pcsc_cchReaderLen, + &pcsc_dwState, &pcsc_dwProtocol, + (pcbAtrLenAlloc) ? NULL : pbAtr, &pcsc_cbAtrLen); if (status == SCARD_S_SUCCESS) { @@ -1962,9 +1877,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatus_Internal(SCARDHANDLE hCard, } status = (LONG) g_PCSC.pfnSCardStatus(hCard, - *pMszReaderNames, &pcsc_cchReaderLen, - &pcsc_dwState, &pcsc_dwProtocol, - pbAtr, &pcsc_cbAtrLen); + *pMszReaderNames, &pcsc_cchReaderLen, + &pcsc_dwState, &pcsc_dwProtocol, + pbAtr, &pcsc_cbAtrLen); if (status != SCARD_S_SUCCESS) { @@ -1993,30 +1908,24 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatus_Internal(SCARDHANDLE hCard, else { status = (LONG) g_PCSC.pfnSCardStatus(hCard, mszReaderNames, &pcsc_cchReaderLen, - &pcsc_dwState, &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen); + &pcsc_dwState, &pcsc_dwProtocol, pbAtr, &pcsc_cbAtrLen); } status = PCSC_MapErrorCodeToWinSCard(status); - *pcchReaderLen = (DWORD) pcsc_cchReaderLen; - mszReaderNamesWinSCard = PCSC_ConvertReaderNamesToWinSCard(*pMszReaderNames, pcchReaderLen); if (mszReaderNamesWinSCard) { PCSC_SCardFreeMemory_Internal(hContext, *pMszReaderNames); - *pMszReaderNames = mszReaderNamesWinSCard; PCSC_AddMemoryBlock(hContext, *pMszReaderNames); } pcsc_dwState &= 0xFFFF; *pdwState = PCSC_ConvertCardStateToWinSCard((DWORD) pcsc_dwState, status); - *pdwProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD) pcsc_dwProtocol); - *pcbAtrLen = (DWORD) pcsc_cbAtrLen; - return status; } @@ -2025,9 +1934,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatusA(SCARDHANDLE hCard, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen) { LONG status = SCARD_S_SUCCESS; - status = PCSC_SCardStatus_Internal(hCard, mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen); - return status; } @@ -2053,7 +1960,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatusW(SCARDHANDLE hCard, { *pcchReaderLen = ConvertToUnicode(CP_UTF8, 0, mszReaderNamesA, *pcchReaderLen, (WCHAR**) mszReaderNames, 0); PCSC_AddMemoryBlock(hContext, mszReaderNames); - PCSC_SCardFreeMemory_Internal(hContext, mszReaderNamesA); } @@ -2090,12 +1996,10 @@ WINSCARDAPI LONG WINAPI PCSC_SCardTransmit(SCARDHANDLE hCard, PCSC_DWORD cbAtrLen = 0; PCSC_DWORD dwProtocol = 0; PCSC_DWORD cchReaderLen = 0; - /** * pcsc-lite cannot have a null pioSendPci parameter, unlike WinSCard. * Query the current protocol and use default SCARD_IO_REQUEST for it. */ - status = (LONG) g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState, &dwProtocol, NULL, &cbAtrLen); if (status == SCARD_S_SUCCESS) @@ -2118,10 +2022,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardTransmit(SCARDHANDLE hCard, pcsc_pioSendPci->dwProtocol = (PCSC_DWORD) pioSendPci->dwProtocol; pcsc_pioSendPci->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes; - pbExtraBytes = &((BYTE*) pioSendPci)[sizeof(SCARD_IO_REQUEST)]; pcsc_pbExtraBytes = &((BYTE*) pcsc_pioSendPci)[sizeof(PCSC_SCARD_IO_REQUEST)]; - CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes); } @@ -2135,17 +2037,14 @@ WINSCARDAPI LONG WINAPI PCSC_SCardTransmit(SCARDHANDLE hCard, pcsc_pioRecvPci->dwProtocol = (PCSC_DWORD) pioRecvPci->dwProtocol; pcsc_pioRecvPci->cbPciLength = sizeof(PCSC_SCARD_IO_REQUEST) + cbExtraBytes; - pbExtraBytes = &((BYTE*) pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; pcsc_pbExtraBytes = &((BYTE*) pcsc_pioRecvPci)[sizeof(PCSC_SCARD_IO_REQUEST)]; - CopyMemory(pcsc_pbExtraBytes, pbExtraBytes, cbExtraBytes); } status = (LONG) g_PCSC.pfnSCardTransmit(hCard, pcsc_pioSendPci, pbSendBuffer, - pcsc_cbSendLength, pcsc_pioRecvPci, pbRecvBuffer, &pcsc_cbRecvLength); + pcsc_cbSendLength, pcsc_pioRecvPci, pbRecvBuffer, &pcsc_cbRecvLength); status = PCSC_MapErrorCodeToWinSCard(status); - *pcbRecvLength = (DWORD) pcsc_cbRecvLength; if (pioSendPci) @@ -2192,12 +2091,10 @@ WINSCARDAPI LONG WINAPI PCSC_SCardControl(SCARDHANDLE hCard, dwControlCode = PCSC_SCARD_CTL_CODE(IoCtlFunction); pcsc_dwControlCode = (PCSC_DWORD) dwControlCode; - status = (LONG) g_PCSC.pfnSCardControl(hCard, - pcsc_dwControlCode, lpInBuffer, pcsc_cbInBufferSize, - lpOutBuffer, pcsc_cbOutBufferSize, &pcsc_BytesReturned); + pcsc_dwControlCode, lpInBuffer, pcsc_cbInBufferSize, + lpOutBuffer, pcsc_cbOutBufferSize, &pcsc_BytesReturned); status = PCSC_MapErrorCodeToWinSCard(status); - *lpBytesReturned = (DWORD) pcsc_BytesReturned; if (getFeatureRequest) @@ -2206,17 +2103,15 @@ WINSCARDAPI LONG WINAPI PCSC_SCardControl(SCARDHANDLE hCard, PCSC_TLV_STRUCTURE* tlv = (PCSC_TLV_STRUCTURE*) lpOutBuffer; void* lpOutBufferEnd = (void*) &((BYTE*) lpOutBuffer)[*lpBytesReturned]; - for ( ; ((void*) tlv) < lpOutBufferEnd; tlv++) + for (; ((void*) tlv) < lpOutBufferEnd; tlv++) { ioCtlValue = _byteswap_ulong(tlv->value); ioCtlValue -= 0x42000000; /* inverse of PCSC_SCARD_CTL_CODE() */ - IoCtlMethod = METHOD_FROM_CTL_CODE(ioCtlValue); IoCtlFunction = FUNCTION_FROM_CTL_CODE(ioCtlValue); IoCtlAccess = ACCESS_FROM_CTL_CODE(ioCtlValue); IoCtlDeviceType = DEVICE_TYPE_FROM_CTL_CODE(ioCtlValue); ioCtlValue = SCARD_CTL_CODE(IoCtlFunction); - tlv->value = _byteswap_ulong(ioCtlValue); } } @@ -2252,7 +2147,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib_Internal(SCARDHANDLE hCard, DWORD dw if (pcbAttrLenAlloc && !g_SCardAutoAllocate) { pcsc_cbAttrLen = 0; - status = (LONG) g_PCSC.pfnSCardGetAttrib(hCard, pcsc_dwAttrId, NULL, &pcsc_cbAttrLen); if (status == SCARD_S_SUCCESS) @@ -2276,9 +2170,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib_Internal(SCARDHANDLE hCard, DWORD dw } status = PCSC_MapErrorCodeToWinSCard(status); - *pcbAttrLen = (DWORD) pcsc_cbAttrLen; - return status; } @@ -2295,7 +2187,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib_FriendlyName(SCARDHANDLE hCard, DWOR WCHAR* friendlyNameW = NULL; LONG status = SCARD_S_SUCCESS; LPBYTE* pPbAttr = (LPBYTE*) pbAttr; - hContext = PCSC_GetCardContextFromHandle(hCard); if (!hContext) @@ -2303,24 +2194,21 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib_FriendlyName(SCARDHANDLE hCard, DWOR cbAttrLen = *pcbAttrLen; *pcbAttrLen = SCARD_AUTOALLOCATE; - status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A, - (LPBYTE) &pbAttrA, pcbAttrLen); + (LPBYTE) &pbAttrA, pcbAttrLen); if (status != SCARD_S_SUCCESS) { pbAttrA = NULL; *pcbAttrLen = SCARD_AUTOALLOCATE; - status = PCSC_SCardGetAttrib_Internal(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W, - (LPBYTE) &pbAttrW, pcbAttrLen); + (LPBYTE) &pbAttrW, pcbAttrLen); if (status != SCARD_S_SUCCESS) return status; length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) pbAttrW, - *pcbAttrLen, (char**) &pbAttrA, 0, NULL, NULL); - + *pcbAttrLen, (char**) &pbAttrA, 0, NULL, NULL); namePCSC = pbAttrA; PCSC_SCardFreeMemory_Internal(hContext, pbAttrW); } @@ -2353,7 +2241,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib_FriendlyName(SCARDHANDLE hCard, DWOR if (dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W) { length = ConvertToUnicode(CP_UTF8, 0, (char*) friendlyNameA, -1, &friendlyNameW, 0); - free(friendlyNameA); if (!friendlyNameW) @@ -2414,7 +2301,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, L BOOL pcbAttrLenAlloc = FALSE; LONG status = SCARD_S_SUCCESS; LPBYTE* pPbAttr = (LPBYTE*) pbAttr; - cbAttrLen = *pcbAttrLen; if (*pcbAttrLen == SCARD_AUTOALLOCATE) @@ -2449,7 +2335,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, L * pcsc-lite adds a null terminator to the vendor name, * while WinSCard doesn't. Strip the null terminator. */ - if (pcbAttrLenAlloc) *pcbAttrLen = strlen((char*) *pPbAttr); else @@ -2464,7 +2349,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, L PCSC_DWORD cbAtrLen = 0; PCSC_DWORD dwProtocol = 0; PCSC_DWORD cchReaderLen = 0; - status = (LONG) g_PCSC.pfnSCardStatus(hCard, NULL, &cchReaderLen, &dwState, &dwProtocol, NULL, &cbAtrLen); if (status == SCARD_S_SUCCESS) @@ -2480,87 +2364,66 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, L } else if (dwAttrId == SCARD_ATTR_VENDOR_IFD_TYPE) { - } else if (dwAttrId == SCARD_ATTR_CHANNEL_ID) { - } else if (dwAttrId == SCARD_ATTR_DEFAULT_CLK) { - } else if (dwAttrId == SCARD_ATTR_DEFAULT_DATA_RATE) { - } else if (dwAttrId == SCARD_ATTR_MAX_CLK) { - } else if (dwAttrId == SCARD_ATTR_MAX_DATA_RATE) { - } else if (dwAttrId == SCARD_ATTR_MAX_IFSD) { - } else if (dwAttrId == SCARD_ATTR_CHARACTERISTICS) { - } else if (dwAttrId == SCARD_ATTR_DEVICE_SYSTEM_NAME_A) { - } else if (dwAttrId == SCARD_ATTR_DEVICE_UNIT) { - } else if (dwAttrId == SCARD_ATTR_POWER_MGMT_SUPPORT) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_CLK) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_F) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_D) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_N) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_CWT) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_BWT) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_IFSC) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_EBC_ENCODING) { - } else if (dwAttrId == SCARD_ATTR_CURRENT_IFSD) { - } else if (dwAttrId == SCARD_ATTR_ICC_TYPE_PER_ATR) { - } } @@ -2578,7 +2441,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, L status = (LONG) g_PCSC.pfnSCardSetAttrib(hCard, pcsc_dwAttrId, pbAttr, pcsc_cbAttrLen); status = PCSC_MapErrorCodeToWinSCard(status); - return status; } @@ -2777,8 +2639,8 @@ int PCSC_InitializeSCardApi(void) { /* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */ SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1"); - #ifndef DISABLE_PCSC_LINK + if (PCSC_InitializeSCardApi_Link() >= 0) { g_PCSC.pfnSCardEstablishContext = g_PCSC_Link.pfnSCardEstablishContext; @@ -2799,11 +2661,10 @@ int PCSC_InitializeSCardApi(void) g_PCSC.pfnSCardCancel = g_PCSC_Link.pfnSCardCancel; g_PCSC.pfnSCardGetAttrib = g_PCSC_Link.pfnSCardGetAttrib; g_PCSC.pfnSCardSetAttrib = g_PCSC_Link.pfnSCardSetAttrib; - return 1; } + #endif - #ifdef __MACOSX__ g_PCSCModule = LoadLibraryA("/System/Library/Frameworks/PCSC.framework/PCSC"); #else @@ -2811,6 +2672,7 @@ int PCSC_InitializeSCardApi(void) if (!g_PCSCModule) g_PCSCModule = LoadLibraryA("libpcsclite.so"); + #endif if (!g_PCSCModule) @@ -2833,13 +2695,11 @@ int PCSC_InitializeSCardApi(void) g_PCSC.pfnSCardCancel = (void*) GetProcAddress(g_PCSCModule, "SCardCancel"); g_PCSC.pfnSCardGetAttrib = (void*) GetProcAddress(g_PCSCModule, "SCardGetAttrib"); g_PCSC.pfnSCardSetAttrib = (void*) GetProcAddress(g_PCSCModule, "SCardSetAttrib"); - g_PCSC.pfnSCardFreeMemory = NULL; - #ifndef __APPLE__ g_PCSC.pfnSCardFreeMemory = (void*) GetProcAddress(g_PCSCModule, "SCardFreeMemory"); #endif - + if (g_PCSC.pfnSCardFreeMemory) g_SCardAutoAllocate = TRUE; @@ -2847,11 +2707,9 @@ int PCSC_InitializeSCardApi(void) g_PCSC.pfnSCardFreeMemory = NULL; g_SCardAutoAllocate = FALSE; #endif - #ifdef __APPLE__ g_PnP_Notification = FALSE; #endif - return 1; } diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.h b/winpr/libwinpr/smartcard/smartcard_pcsc.h index a53670da2..7c83e2a3c 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.h +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.h @@ -78,9 +78,7 @@ typedef long PCSC_LONG; #define PCSC_SCARD_CTL_CODE(code) (0x42000000 + (code)) #define PCSC_CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400) -#ifdef __APPLE__ -#pragma pack(1) -#endif +#pragma pack(push, 1) typedef struct { @@ -99,16 +97,6 @@ typedef struct PCSC_DWORD cbPciLength; } PCSC_SCARD_IO_REQUEST; -#ifdef __APPLE__ -#pragma pack() -#endif - -#if defined(__APPLE__) | defined(sun) -#pragma pack(1) -#else -#pragma pack(push, 1) -#endif - typedef struct { BYTE tag; @@ -116,11 +104,7 @@ typedef struct UINT32 value; } PCSC_TLV_STRUCTURE; -#if defined(__APPLE__) | defined(sun) -#pragma pack() -#else #pragma pack(pop) -#endif struct _PCSCFunctionTable { diff --git a/winpr/libwinpr/smartcard/test/CMakeLists.txt b/winpr/libwinpr/smartcard/test/CMakeLists.txt index e42f291e6..4d8e1074a 100644 --- a/winpr/libwinpr/smartcard/test/CMakeLists.txt +++ b/winpr/libwinpr/smartcard/test/CMakeLists.txt @@ -13,12 +13,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-smartcard winpr-crt) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/sspi/CMakeLists.txt b/winpr/libwinpr/sspi/CMakeLists.txt index ce8152766..e3e09072e 100644 --- a/winpr/libwinpr/sspi/CMakeLists.txt +++ b/winpr/libwinpr/sspi/CMakeLists.txt @@ -15,7 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-sspi") set(MODULE_PREFIX "WINPR_SSPI") set(${MODULE_PREFIX}_NTLM_SRCS @@ -49,49 +48,22 @@ set(${MODULE_PREFIX}_SRCS sspi.c sspi.h) -set(${MODULE_PREFIX}_SRCS - ${${MODULE_PREFIX}_NTLM_SRCS} +winpr_module_add(${${MODULE_PREFIX}_NTLM_SRCS} ${${MODULE_PREFIX}_KERBEROS_SRCS} ${${MODULE_PREFIX}_NEGOTIATE_SRCS} ${${MODULE_PREFIX}_SCHANNEL_SRCS} ${${MODULE_PREFIX}_SRCS}) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - #set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() +winpr_include_directory_add(${ZLIB_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR}) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -include_directories(${ZLIB_INCLUDE_DIRS}) -include_directories(${OPENSSL_INCLUDE_DIR}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${ZLIB_LIBRARIES} +winpr_library_add(${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) + winpr_library_add(ws2_32) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-sysinfo winpr-registry winpr-crypto winpr-library winpr-utils) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index dc519882d..a1b1a7d8e 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -39,6 +39,9 @@ #include "ntlm_message.h" +#include "../../log.h" +#define TAG WINPR_TAG("sspi.NTLM") + char* NTLM_PACKAGE_NAME = "NTLM"; int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) @@ -50,7 +53,6 @@ int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) if (!Workstation) { GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize); - ws = (char*) malloc(nSize); if (!ws) @@ -67,7 +69,7 @@ int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) if (status <= 0) return -1; - context->Workstation.Length = (USHORT) (status - 1); + context->Workstation.Length = (USHORT)(status - 1); context->Workstation.Length *= 2; if (!Workstation) @@ -92,23 +94,19 @@ int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePr return -1; CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName, context->ServicePrincipalName.Length + 2); - return 1; } int ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName) { int status; - context->ServicePrincipalName.Buffer = NULL; - status = ConvertToUnicode(CP_UTF8, 0, ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0); if (status <= 0) return -1; - context->ServicePrincipalName.Length = (USHORT) ((status - 1) * 2); - + context->ServicePrincipalName.Length = (USHORT)((status - 1) * 2); return 1; } @@ -140,7 +138,7 @@ int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName) if (status <= 0) return -1; - context->TargetName.cbBuffer = (USHORT) ((status - 1) * 2); + context->TargetName.cbBuffer = (USHORT)((status - 1) * 2); if (!TargetName) free(name); @@ -156,7 +154,6 @@ NTLM_CONTEXT* ntlm_ContextNew() DWORD dwSize; DWORD dwValue; NTLM_CONTEXT* context; - context = (NTLM_CONTEXT*) calloc(1, sizeof(NTLM_CONTEXT)); if (!context) @@ -169,7 +166,6 @@ NTLM_CONTEXT* ntlm_ContextNew() context->SendWorkstationName = TRUE; context->NegotiateKeyExchange = TRUE; context->UseSamFileDatabase = TRUE; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); if (status == ERROR_SUCCESS) @@ -213,7 +209,6 @@ NTLM_CONTEXT* ntlm_ContextNew() * but enabling it in WinPR breaks TS Gateway at this point */ context->SuppressExtendedProtection = FALSE; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); if (status == ERROR_SUCCESS) @@ -247,7 +242,6 @@ void ntlm_ContextFree(NTLM_CONTEXT* context) sspi_SecBufferFree(&context->TargetName); sspi_SecBufferFree(&context->NtChallengeResponse); sspi_SecBufferFree(&context->LmChallengeResponse); - free(context->ServicePrincipalName.Buffer); free(context->Workstation.Buffer); free(context); @@ -261,8 +255,8 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal SEC_WINNT_AUTH_IDENTITY* identity; if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && - (fCredentialUse != SECPKG_CRED_INBOUND) && - (fCredentialUse != SECPKG_CRED_BOTH)) + (fCredentialUse != SECPKG_CRED_INBOUND) && + (fCredentialUse != SECPKG_CRED_BOTH)) { return SEC_E_INVALID_PARAMETER; } @@ -275,7 +269,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal credentials->fCredentialUse = fCredentialUse; credentials->pGetKeyFn = pGetKeyFn; credentials->pvGetKeyArgument = pvGetKeyArgument; - identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData; if (identity) @@ -283,7 +276,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials); sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME); - return SEC_E_OK; } @@ -295,8 +287,8 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_WINNT_AUTH_IDENTITY* identity; if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && - (fCredentialUse != SECPKG_CRED_INBOUND) && - (fCredentialUse != SECPKG_CRED_BOTH)) + (fCredentialUse != SECPKG_CRED_INBOUND) && + (fCredentialUse != SECPKG_CRED_BOTH)) { return SEC_E_INVALID_PARAMETER; } @@ -309,7 +301,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, credentials->fCredentialUse = fCredentialUse; credentials->pGetKeyFn = pGetKeyFn; credentials->pvGetKeyArgument = pvGetKeyArgument; - identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData; if (identity) @@ -317,7 +308,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials); sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME); - return SEC_E_OK; } @@ -334,7 +324,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential) return SEC_E_INVALID_HANDLE; sspi_CredentialsFree(credentials); - return SEC_E_OK; } @@ -365,7 +354,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P SSPI_CREDENTIALS* credentials; PSecBuffer input_buffer; PSecBuffer output_buffer; - context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) @@ -382,9 +370,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); context->credentials = credentials; - ntlm_SetContextTargetName(context, NULL); - sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME); } @@ -481,7 +467,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti PSecBuffer input_buffer = NULL; PSecBuffer output_buffer = NULL; PSecBuffer channel_bindings = NULL; - context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) @@ -601,11 +586,11 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredenti } status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq, - Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry); + Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry); if (pszTargetNameW) free(pszTargetNameW); - + return status; } @@ -613,7 +598,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBuff { NTLM_CONTEXT* context; SECURITY_STATUS status = SEC_E_OK; - context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) @@ -632,14 +616,12 @@ SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBuff SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) { NTLM_CONTEXT* context; - context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; ntlm_ContextFree(context); - return SEC_E_OK; } @@ -660,12 +642,10 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, UL if (ulAttribute == SECPKG_ATTR_SIZES) { SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer; - ContextSizes->cbMaxToken = 2010; ContextSizes->cbMaxSignature = 16; ContextSizes->cbBlockSize = 0; ContextSizes->cbSecurityTrailer = 16; - return SEC_E_OK; } else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY) @@ -675,24 +655,21 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, UL char* DomainA = NULL; SSPI_CREDENTIALS* credentials; SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*) pBuffer; - context->UseSamFileDatabase = FALSE; - credentials = context->credentials; ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity)); - UserA = AuthIdentity->User; status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.User, - credentials->identity.UserLength, - &UserA, 256, NULL, NULL); + credentials->identity.UserLength, + &UserA, 256, NULL, NULL); if (status <= 0) return SEC_E_INTERNAL_ERROR; DomainA = AuthIdentity->Domain; status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.Domain, - credentials->identity.DomainLength, - &DomainA, 256, NULL, NULL); + credentials->identity.DomainLength, + &DomainA, 256, NULL, NULL); if (status <= 0) return SEC_E_INTERNAL_ERROR; @@ -784,7 +761,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULON return SEC_E_INVALID_PARAMETER; CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8); - return SEC_E_OK; } else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE) @@ -795,7 +771,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULON return SEC_E_INVALID_PARAMETER; CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8); - return SEC_E_OK; } @@ -826,7 +801,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, NTLM_CONTEXT* context; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; - SeqNo = MessageSeqNo; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); @@ -852,7 +826,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, return SEC_E_INSUFFICIENT_MEMORY; CopyMemory(data, data_buffer->pvBuffer, length); - /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL); @@ -869,34 +842,24 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, CopyMemory(data_buffer->pvBuffer, data, length); #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "Data Buffer (length = %d)\n", length); - winpr_HexDump(data, length); - fprintf(stderr, "\n"); - - fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer); - winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Data Buffer (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, data, length); + WLog_DBG(TAG, "Encrypted Data Buffer (length = %d)", (int) data_buffer->cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer); #endif - free(data); - /* RC4-encrypt first 8 bytes of digest */ RC4(&context->SendRc4Seal, 8, digest, checksum); - signature = (BYTE*) signature_buffer->pvBuffer; - /* Concatenate version, ciphertext and sequence number to build signature */ CopyMemory(signature, (void*) &version, 4); CopyMemory(&signature[4], (void*) checksum, 8); CopyMemory(&signature[12], (void*) &(SeqNo), 4); context->SendSeqNum++; - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "Signature (length = %d)\n", (int) signature_buffer->cbBuffer); - winpr_HexDump(signature_buffer->pvBuffer, signature_buffer->cbBuffer); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Signature (length = %d)", (int) signature_buffer->cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer); #endif - return SEC_E_OK; } @@ -914,7 +877,6 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD BYTE expected_signature[16]; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; - SeqNo = (UINT32) MessageSeqNo; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); @@ -955,22 +917,15 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD HMAC_Update(&hmac, (void*) data_buffer->pvBuffer, data_buffer->cbBuffer); HMAC_Final(&hmac, digest, NULL); HMAC_CTX_cleanup(&hmac); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", length); - winpr_HexDump(data, length); - fprintf(stderr, "\n"); - - fprintf(stderr, "Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer); - winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Encrypted Data Buffer (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, data, length); + WLog_DBG(TAG, "Data Buffer (length = %d)", (int) data_buffer->cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer); #endif - free(data); - /* RC4-encrypt first 8 bytes of digest */ RC4(&context->RecvRc4Seal, 8, digest, checksum); - /* Concatenate version, ciphertext and sequence number to build signature */ CopyMemory(expected_signature, (void*) &version, 4); CopyMemory(&expected_signature[4], (void*) checksum, 8); @@ -980,13 +935,11 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0) { /* signature verification failed! */ - fprintf(stderr, "signature verification failed, something nasty is going on!\n"); - - fprintf(stderr, "Expected Signature:\n"); - winpr_HexDump(expected_signature, 16); - fprintf(stderr, "Actual Signature:\n"); - winpr_HexDump((BYTE*) signature_buffer->pvBuffer, 16); - + WLog_ERR(TAG, "signature verification failed, something nasty is going on!"); + WLog_ERR(TAG, "Expected Signature:"); + winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16); + WLog_ERR(TAG, "Actual Signature:"); + winpr_HexDump(TAG, WLOG_ERROR, (BYTE*) signature_buffer->pvBuffer, 16); return SEC_E_MESSAGE_ALTERED; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c index 7190ceec8..892951516 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c @@ -32,6 +32,9 @@ #include "ntlm_av_pairs.h" +#include "../../log.h" +#define TAG WINPR_TAG("sspi.NTLM") + const char* const AV_PAIR_STRINGS[] = { "MsvAvEOL", @@ -50,7 +53,6 @@ const char* const AV_PAIR_STRINGS[] = void ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList) { NTLM_AV_PAIR* pAvPair = pAvPairList; - pAvPair->AvId = MsvAvEOL; pAvPair->AvLen = 0; } @@ -69,7 +71,6 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList) } length = (pAvPair - pAvPairList) + sizeof(NTLM_AV_PAIR); - return length; } @@ -80,20 +81,16 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList) if (!pAvPair) return; - fprintf(stderr, "AV_PAIRs =\n{\n"); + WLog_INFO(TAG, "AV_PAIRs ="); while (pAvPair->AvId != MsvAvEOL) { - fprintf(stderr, "\t%s AvId: %d AvLen: %d\n", - AV_PAIR_STRINGS[pAvPair->AvId], - pAvPair->AvId, pAvPair->AvLen); - - winpr_HexDump(ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen); - + WLog_INFO(TAG, "\t%s AvId: %d AvLen: %d", + AV_PAIR_STRINGS[pAvPair->AvId], + pAvPair->AvId, pAvPair->AvLen); + winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen); pAvPair = ntlm_av_pair_get_next_pointer(pAvPair); } - - fprintf(stderr, "}\n"); } ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) @@ -114,7 +111,7 @@ int ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair) NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair) { - return (NTLM_AV_PAIR*) ((PBYTE) pAvPair + ntlm_av_pair_get_next_offset(pAvPair)); + return (NTLM_AV_PAIR*)((PBYTE) pAvPair + ntlm_av_pair_get_next_offset(pAvPair)); } NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId) @@ -141,7 +138,6 @@ NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId) NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, UINT16 AvLen) { NTLM_AV_PAIR* pAvPair; - pAvPair = ntlm_av_pair_get(pAvPairList, MsvAvEOL); if (!pAvPair) @@ -149,16 +145,13 @@ NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE pAvPair->AvId = AvId; pAvPair->AvLen = AvLen; - CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen); - return pAvPair; } NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair) { NTLM_AV_PAIR* pAvPairCopy; - pAvPairCopy = ntlm_av_pair_get(pAvPairList, MsvAvEOL); if (!pAvPairCopy) @@ -166,10 +159,8 @@ NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAv pAvPairCopy->AvId = pAvPair->AvId; pAvPairCopy->AvLen = pAvPair->AvLen; - CopyMemory(ntlm_av_pair_get_value_pointer(pAvPairCopy), - ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen); - + ntlm_av_pair_get_value_pointer(pAvPair), pAvPair->AvLen); return pAvPairCopy; } @@ -178,14 +169,12 @@ int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT ty char* name; int status; DWORD nSize = 0; - GetComputerNameExA(type, NULL, &nSize); - name = (char*) malloc(nSize); - + if (!name) return -1; - + if (!GetComputerNameExA(type, name, &nSize)) return -1; @@ -197,11 +186,9 @@ int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT ty if (status <= 0) return status; - pName->Length = (USHORT) ((status - 1) * 2); + pName->Length = (USHORT)((status - 1) * 2); pName->MaximumLength = pName->Length; - free(name); - return 1; } @@ -252,12 +239,10 @@ typedef struct gss_channel_bindings_struct { static void ntlm_md5_update_uint32_be(MD5_CTX* md5, UINT32 num) { BYTE be32[4]; - be32[0] = (num >> 0) & 0xFF; be32[1] = (num >> 8) & 0xFF; be32[2] = (num >> 16) & 0xFF; be32[3] = (num >> 24) & 0xFF; - MD5_Update(md5, be32, 4); } @@ -267,7 +252,6 @@ void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) BYTE* ChannelBindingToken; UINT32 ChannelBindingTokenLength; SEC_CHANNEL_BINDINGS* ChannelBindings; - ZeroMemory(context->ChannelBindingsHash, 16); ChannelBindings = context->Bindings.Bindings; @@ -276,17 +260,13 @@ void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) ChannelBindingTokenLength = context->Bindings.BindingsLength - sizeof(SEC_CHANNEL_BINDINGS); ChannelBindingToken = &((BYTE*) ChannelBindings)[ChannelBindings->dwApplicationDataOffset]; - MD5_Init(&md5); - ntlm_md5_update_uint32_be(&md5, ChannelBindings->dwInitiatorAddrType); ntlm_md5_update_uint32_be(&md5, ChannelBindings->cbInitiatorLength); ntlm_md5_update_uint32_be(&md5, ChannelBindings->dwAcceptorAddrType); ntlm_md5_update_uint32_be(&md5, ChannelBindings->cbAcceptorLength); ntlm_md5_update_uint32_be(&md5, ChannelBindings->cbApplicationDataLength); - MD5_Update(&md5, (void*) ChannelBindingToken, ChannelBindingTokenLength); - MD5_Final(context->ChannelBindingsHash, &md5); } @@ -300,7 +280,6 @@ void ntlm_compute_single_host_data(NTLM_CONTEXT* context) * different or if they are on different hosts, then the information MUST be ignored. * Any fields after the MachineID field MUST be ignored on receipt. */ - context->SingleHostData.Size = 48; context->SingleHostData.Z4 = 0; context->SingleHostData.DataPresent = 1; @@ -319,7 +298,6 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) UNICODE_STRING NbComputerName; UNICODE_STRING DnsDomainName; UNICODE_STRING DnsComputerName; - NbDomainName.Buffer = NULL; if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0) @@ -342,8 +320,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) AvPairsCount = 5; AvPairsLength = NbDomainName.Length + NbComputerName.Length + - DnsDomainName.Length + DnsComputerName.Length + 8; - + DnsDomainName.Length + DnsComputerName.Length + 8; length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength); if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length)) @@ -351,19 +328,16 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) pAvPairList = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer; AvPairListSize = (ULONG) context->ChallengeTargetInfo.cbBuffer; - ntlm_av_pair_list_init(pAvPairList); ntlm_av_pair_add(pAvPairList, MsvAvNbDomainName, (PBYTE) NbDomainName.Buffer, NbDomainName.Length); ntlm_av_pair_add(pAvPairList, MsvAvNbComputerName, (PBYTE) NbComputerName.Buffer, NbComputerName.Length); ntlm_av_pair_add(pAvPairList, MsvAvDnsDomainName, (PBYTE) DnsDomainName.Buffer, DnsDomainName.Length); ntlm_av_pair_add(pAvPairList, MsvAvDnsComputerName, (PBYTE) DnsComputerName.Buffer, DnsComputerName.Length); ntlm_av_pair_add(pAvPairList, MsvAvTimestamp, context->Timestamp, sizeof(context->Timestamp)); - ntlm_free_unicode_string(&NbDomainName); ntlm_free_unicode_string(&NbComputerName); ntlm_free_unicode_string(&DnsDomainName); ntlm_free_unicode_string(&DnsComputerName); - return 1; } @@ -380,11 +354,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) NTLM_AV_PAIR* AvDnsTreeName; NTLM_AV_PAIR* ChallengeTargetInfo; NTLM_AV_PAIR* AuthenticateTargetInfo; - AvPairsCount = 1; AvPairsValueLength = 0; ChallengeTargetInfo = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer; - AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbDomainName); AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbComputerName); AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsDomainName); @@ -449,7 +421,6 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) * SEC_CHANNEL_BINDINGS structure * http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/ */ - AvPairsCount++; /* MsvChannelBindings */ AvPairsValueLength += 16; ntlm_compute_channel_bindings(context); @@ -468,7 +439,6 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size); AuthenticateTargetInfo = (NTLM_AV_PAIR*) context->AuthenticateTargetInfo.pvBuffer; - ntlm_av_pair_list_init(AuthenticateTargetInfo); if (AvNbDomainName) @@ -498,7 +468,7 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) if (context->SendSingleHostData) { ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvSingleHost, - (PBYTE) &context->SingleHostData, context->SingleHostData.Size); + (PBYTE) &context->SingleHostData, context->SingleHostData.Size); } if (!context->SuppressExtendedProtection) @@ -508,15 +478,14 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) if (context->ServicePrincipalName.Length > 0) { ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvTargetName, - (PBYTE) context->ServicePrincipalName.Buffer, - context->ServicePrincipalName.Length); + (PBYTE) context->ServicePrincipalName.Buffer, + context->ServicePrincipalName.Length); } } if (context->NTLMv2) { NTLM_AV_PAIR* AvEOL; - AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL); ZeroMemory((void*) AvEOL, 4); } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index 5cd34758d..178556df6 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -32,6 +32,9 @@ #include "ntlm_compute.h" +#include "../../log.h" +#define TAG WINPR_TAG("sspi.NTLM") + const char LM_MAGIC[] = "KGS!@#$%"; static const char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant"; @@ -40,10 +43,10 @@ static const char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server se static const char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant"; static const BYTE NTLM_NULL_BUFFER[16] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /** - * Populate VERSION structure.\n + * Populate VERSION structure. * VERSION @msdn{cc236654} * @param s */ @@ -51,11 +54,8 @@ static const BYTE NTLM_NULL_BUFFER[16] = void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) { OSVERSIONINFOA osVersionInfo; - osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA(&osVersionInfo); - versionInfo->ProductMajorVersion = (UINT8) osVersionInfo.dwMajorVersion; versionInfo->ProductMinorVersion = (UINT8) osVersionInfo.dwMinorVersion; versionInfo->ProductBuild = (UINT16) osVersionInfo.dwBuildNumber; @@ -64,7 +64,7 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) } /** - * Read VERSION structure.\n + * Read VERSION structure. * VERSION @msdn{cc236654} * @param s */ @@ -79,12 +79,11 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ - return 1; } /** - * Write VERSION structure.\n + * Write VERSION structure. * VERSION @msdn{cc236654} * @param s */ @@ -99,26 +98,25 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) } /** - * Print VERSION structure.\n + * Print VERSION structure. * VERSION @msdn{cc236654} * @param s */ void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo) { - fprintf(stderr, "VERSION =\n{\n"); - fprintf(stderr, "\tProductMajorVersion: %d\n", versionInfo->ProductMajorVersion); - fprintf(stderr, "\tProductMinorVersion: %d\n", versionInfo->ProductMinorVersion); - fprintf(stderr, "\tProductBuild: %d\n", versionInfo->ProductBuild); - fprintf(stderr, "\tReserved: 0x%02X%02X%02X\n", versionInfo->Reserved[0], - versionInfo->Reserved[1], versionInfo->Reserved[2]); - fprintf(stderr, "\tNTLMRevisionCurrent: 0x%02X\n", versionInfo->NTLMRevisionCurrent); + WLog_INFO(TAG, "VERSION ={"); + WLog_INFO(TAG, "\tProductMajorVersion: %d", versionInfo->ProductMajorVersion); + WLog_INFO(TAG, "\tProductMinorVersion: %d", versionInfo->ProductMinorVersion); + WLog_INFO(TAG, "\tProductBuild: %d", versionInfo->ProductBuild); + WLog_INFO(TAG, "\tReserved: 0x%02X%02X%02X", versionInfo->Reserved[0], + versionInfo->Reserved[1], versionInfo->Reserved[2]); + WLog_INFO(TAG, "\tNTLMRevisionCurrent: 0x%02X", versionInfo->NTLMRevisionCurrent); } int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) { size_t size; - Stream_Read_UINT8(s, challenge->RespType); Stream_Read_UINT8(s, challenge->HiRespType); Stream_Read_UINT16(s, challenge->Reserved1); @@ -126,7 +124,6 @@ int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* chal Stream_Read(s, challenge->Timestamp, 8); Stream_Read(s, challenge->ClientChallenge, 8); Stream_Read_UINT32(s, challenge->Reserved3); - size = Stream_Length(s) - Stream_GetPosition(s); challenge->AvPairs = (NTLM_AV_PAIR*) malloc(size); @@ -134,14 +131,12 @@ int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* chal return -1; Stream_Read(s, challenge->AvPairs, size); - return 1; } int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) { ULONG length; - Stream_Write_UINT8(s, challenge->RespType); Stream_Write_UINT8(s, challenge->HiRespType); Stream_Write_UINT16(s, challenge->Reserved1); @@ -149,10 +144,8 @@ int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* cha Stream_Write(s, challenge->Timestamp, 8); Stream_Write(s, challenge->ClientChallenge, 8); Stream_Write_UINT32(s, challenge->Reserved3); - length = ntlm_av_pair_list_length(challenge->AvPairs); Stream_Write(s, challenge->AvPairs, length); - return 1; } @@ -177,12 +170,9 @@ void ntlm_current_time(BYTE* timestamp) { FILETIME filetime; ULARGE_INTEGER time64; - GetSystemTimeAsFileTime(&filetime); - time64.LowPart = filetime.dwLowDateTime; time64.HighPart = filetime.dwHighDateTime; - CopyMemory(timestamp, &(time64.QuadPart), 8); } @@ -204,62 +194,54 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) WINPR_SAM* sam; WINPR_SAM_ENTRY* entry; SSPI_CREDENTIALS* credentials = context->credentials; - sam = SamOpen(TRUE); - + if (!sam) return -1; entry = SamLookupUserW(sam, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2); + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2); if (entry) { #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "NTLM Hash:\n"); - winpr_HexDump(entry->NtHash, 16); + WLog_DBG(TAG, "NTLM Hash:"); + winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); #endif - NTOWFv2FromHashW(entry->NtHash, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, - (BYTE*) hash); - + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, + (BYTE*) hash); SamFreeEntry(sam, entry); SamClose(sam); - return 1; } entry = SamLookupUserW(sam, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, NULL, 0); + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, NULL, 0); if (entry) { #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "NTLM Hash:\n"); - winpr_HexDump(entry->NtHash, 16); + WLog_DBG(TAG, "NTLM Hash:"); + winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); #endif - NTOWFv2FromHashW(entry->NtHash, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, - (BYTE*) hash); - + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, + (BYTE*) hash); SamFreeEntry(sam, entry); SamClose(sam); - return 1; } else { - fprintf(stderr, "Error: Could not find user in SAM database\n"); + WLog_ERR(TAG, "Error: Could not find user in SAM database"); return 0; } SamClose(sam); - return 1; } @@ -270,13 +252,10 @@ int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) char* PasswordHash = NULL; UINT32 PasswordHashLength = 0; SSPI_CREDENTIALS* credentials = context->credentials; - /* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */ - PasswordHashLength = credentials->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR; - status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) credentials->identity.Password, - PasswordHashLength, &PasswordHash, 0, NULL, NULL); + PasswordHashLength, &PasswordHash, 0, NULL, NULL); if (status <= 0) return -1; @@ -291,7 +270,6 @@ int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) } free(PasswordHash); - return 1; } @@ -305,27 +283,26 @@ int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0) { NTOWFv2FromHashW(context->NtlmHash, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, - (BYTE*) hash); + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, + (BYTE*) hash); } else if (credentials->identity.PasswordLength > 256) { /* Special case for WinPR: password hash */ - if (ntlm_convert_password_hash(context, context->NtlmHash) < 0) return -1; NTOWFv2FromHashW(context->NtlmHash, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, - (BYTE*) hash); + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, + (BYTE*) hash); } else if (credentials->identity.PasswordLength > 0) { NTOWFv2W((LPWSTR) credentials->identity.Password, credentials->identity.PasswordLength * 2, - (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash); + (LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, + (LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash); } else if (context->UseSamFileDatabase) { @@ -346,7 +323,6 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) return -1; ZeroMemory(context->LmChallengeResponse.pvBuffer, 24); - return 1; } @@ -363,19 +339,16 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) return -1; response = (BYTE*) context->LmChallengeResponse.pvBuffer; - /* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */ HMAC(EVP_md5(), (void*) context->NtlmV2Hash, 16, (BYTE*) value, 16, (BYTE*) response, NULL); - /* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */ CopyMemory(&response[16], context->ClientChallenge, 8); - return 1; } /** - * Compute NTLMv2 Response.\n - * NTLMv2_RESPONSE @msdn{cc236653}\n + * Compute NTLMv2 Response. + * NTLMv2_RESPONSE @msdn{cc236653} * NTLMv2 Authentication @msdn{cc236700} * @param NTLM context */ @@ -388,7 +361,6 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) SecBuffer ntlm_v2_temp_chal; PSecBuffer TargetInfo; SSPI_CREDENTIALS* credentials; - credentials = context->credentials; TargetInfo = &context->ChallengeTargetInfo; @@ -404,27 +376,17 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) return -1; #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "Password (length = %d)\n", credentials->identity.PasswordLength * 2); - winpr_HexDump((BYTE*) credentials->identity.Password, credentials->identity.PasswordLength * 2); - fprintf(stderr, "\n"); - - fprintf(stderr, "Username (length = %d)\n", credentials->identity.UserLength * 2); - winpr_HexDump((BYTE*) credentials->identity.User, credentials->identity.UserLength * 2); - fprintf(stderr, "\n"); - - fprintf(stderr, "Domain (length = %d)\n", credentials->identity.DomainLength * 2); - winpr_HexDump((BYTE*) credentials->identity.Domain, credentials->identity.DomainLength * 2); - fprintf(stderr, "\n"); - - fprintf(stderr, "Workstation (length = %d)\n", context->Workstation.Length); - winpr_HexDump((BYTE*) context->Workstation.Buffer, context->Workstation.Length); - fprintf(stderr, "\n"); - - fprintf(stderr, "NTOWFv2, NTLMv2 Hash\n"); - winpr_HexDump(context->NtlmV2Hash, 16); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "Password (length = %d)", credentials->identity.PasswordLength * 2); + winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) credentials->identity.Password, credentials->identity.PasswordLength * 2); + WLog_DBG(TAG, "Username (length = %d)", credentials->identity.UserLength * 2); + winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) credentials->identity.User, credentials->identity.UserLength * 2); + WLog_DBG(TAG, "Domain (length = %d)", credentials->identity.DomainLength * 2); + winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) credentials->identity.Domain, credentials->identity.DomainLength * 2); + WLog_DBG(TAG, "Workstation (length = %d)", context->Workstation.Length); + winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) context->Workstation.Buffer, context->Workstation.Length); + WLog_DBG(TAG, "NTOWFv2, NTLMv2 Hash"); + winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, 16); #endif - /* Construct temp */ blob[0] = 1; /* RespType (1 byte) */ blob[1] = 1; /* HighRespType (1 byte) */ @@ -434,11 +396,9 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) CopyMemory(&blob[16], context->ClientChallenge, 8); /* ClientChallenge (8 bytes) */ /* Reserved3 (4 bytes) */ CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "NTLMv2 Response Temp Blob\n"); - winpr_HexDump(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "NTLMv2 Response Temp Blob"); + winpr_HexDump(TAG, WLOG_DEBUG, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); #endif /* Concatenate server challenge with temp */ @@ -449,25 +409,21 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) blob = (BYTE*) ntlm_v2_temp_chal.pvBuffer; CopyMemory(blob, context->ServerChallenge, 8); CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); - HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer, - ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str, NULL); + ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str, NULL); /* NtChallengeResponse, Concatenate NTProofStr with temp */ - + if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16)) return -1; blob = (BYTE*) context->NtChallengeResponse.pvBuffer; CopyMemory(blob, nt_proof_str, 16); CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); - /* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */ HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) nt_proof_str, 16, (BYTE*) context->SessionBaseKey, NULL); - sspi_SecBufferFree(&ntlm_v2_temp); sspi_SecBufferFree(&ntlm_v2_temp_chal); - return 1; } @@ -482,10 +438,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) { RC4_KEY rc4; - /* Initialize RC4 cipher with key */ RC4_set_key(&rc4, 16, (void*) key); - /* Encrypt plaintext with key */ RC4(&rc4, length, (void*) plaintext, (void*) ciphertext); } @@ -498,7 +452,6 @@ void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) void ntlm_generate_client_challenge(NTLM_CONTEXT* context) { /* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */ - if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0) RAND_bytes(context->ClientChallenge, 8); } @@ -515,7 +468,7 @@ void ntlm_generate_server_challenge(NTLM_CONTEXT* context) } /** - * Generate KeyExchangeKey (the 128-bit SessionBaseKey).\n + * Generate KeyExchangeKey (the 128-bit SessionBaseKey). * @msdn{cc236710} * @param NTLM context */ @@ -572,7 +525,6 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) * else * Set RandomSessionKey to KeyExchangeKey */ - if (context->NegotiateKeyExchange) ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey, context->RandomSessionKey); else @@ -580,7 +532,7 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) } /** - * Generate signing key.\n + * Generate signing key. * @msdn{cc236711} * @param exported_session_key ExportedSessionKey * @param sign_magic Sign magic string @@ -592,7 +544,6 @@ int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, int length; BYTE* value; MD5_CTX md5; - length = 16 + sign_magic->cbBuffer; value = (BYTE*) malloc(length); @@ -602,18 +553,15 @@ int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, /* Concatenate ExportedSessionKey with sign magic */ CopyMemory(value, exported_session_key, 16); CopyMemory(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer); - MD5_Init(&md5); MD5_Update(&md5, value, length); MD5_Final(signing_key, &md5); - free(value); - return 1; } /** - * Generate client signing key (ClientSigningKey).\n + * Generate client signing key (ClientSigningKey). * @msdn{cc236711} * @param NTLM context */ @@ -621,15 +569,13 @@ int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) { SecBuffer signMagic; - signMagic.pvBuffer = (void*) NTLM_CLIENT_SIGN_MAGIC; signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey); } /** - * Generate server signing key (ServerSigningKey).\n + * Generate server signing key (ServerSigningKey). * @msdn{cc236711} * @param NTLM context */ @@ -637,15 +583,13 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) void ntlm_generate_server_signing_key(NTLM_CONTEXT* context) { SecBuffer signMagic; - signMagic.pvBuffer = (void*) NTLM_SERVER_SIGN_MAGIC; signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey); } /** - * Generate sealing key.\n + * Generate sealing key. * @msdn{cc236712} * @param exported_session_key ExportedSessionKey * @param seal_magic Seal magic string @@ -662,22 +606,18 @@ int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, return -1; p = (BYTE*) buffer.pvBuffer; - /* Concatenate ExportedSessionKey with seal magic */ CopyMemory(p, exported_session_key, 16); CopyMemory(&p[16], seal_magic->pvBuffer, seal_magic->cbBuffer); - MD5_Init(&md5); MD5_Update(&md5, buffer.pvBuffer, buffer.cbBuffer); MD5_Final(sealing_key, &md5); - sspi_SecBufferFree(&buffer); - return 1; } /** - * Generate client sealing key (ClientSealingKey).\n + * Generate client sealing key (ClientSealingKey). * @msdn{cc236712} * @param NTLM context */ @@ -685,15 +625,13 @@ int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) { SecBuffer sealMagic; - sealMagic.pvBuffer = (void*) NTLM_CLIENT_SEAL_MAGIC; sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey); } /** - * Generate server sealing key (ServerSealingKey).\n + * Generate server sealing key (ServerSealingKey). * @msdn{cc236712} * @param NTLM context */ @@ -701,10 +639,8 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) { SecBuffer sealMagic; - sealMagic.pvBuffer = (void*) NTLM_SERVER_SEAL_MAGIC; sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey); } @@ -738,12 +674,10 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context) { HMAC_CTX hmac_ctx; - /* * Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE, * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey */ - HMAC_CTX_init(&hmac_ctx); HMAC_Init_ex(&hmac_ctx, context->ExportedSessionKey, 16, EVP_md5(), NULL); HMAC_Update(&hmac_ctx, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 927e10cbb..c1da55605 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -33,6 +33,9 @@ #include "ntlm_message.h" +#include "../log.h" +#define TAG WINPR_TAG("sspi.NTLM") + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; static const char* const NTLM_NEGOTIATE_STRINGS[] = @@ -75,19 +78,16 @@ void ntlm_print_negotiate_flags(UINT32 flags) { int i; const char* str; - - fprintf(stderr, "negotiateFlags \"0x%08X\"{\n", flags); + WLog_INFO(TAG, "negotiateFlags \"0x%08X\"", flags); for (i = 31; i >= 0; i--) { if ((flags >> i) & 1) { str = NTLM_NEGOTIATE_STRINGS[(31 - i)]; - fprintf(stderr, "\t%s (%d),\n", str, (31 - i)); + WLog_INFO(TAG, "\t%s (%d),", str, (31 - i)); } } - - fprintf(stderr, "}\n"); } int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) @@ -124,7 +124,6 @@ int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ - return 1; } @@ -173,7 +172,6 @@ void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) if (fields->Buffer) { free(fields->Buffer); - fields->Len = 0; fields->MaxLen = 0; fields->Buffer = NULL; @@ -184,13 +182,11 @@ void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) { - fprintf(stderr, "%s (Len: %d MaxLen: %d BufferOffset: %d)\n", - name, fields->Len, fields->MaxLen, fields->BufferOffset); + WLog_DBG(TAG, "%s (Len: %d MaxLen: %d BufferOffset: %d)", + name, fields->Len, fields->MaxLen, fields->BufferOffset); if (fields->Len > 0) - winpr_HexDump(fields->Buffer, fields->Len); - - fprintf(stderr, "\n"); + winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len); } SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) @@ -198,10 +194,8 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf wStream* s; int length; NTLM_NEGOTIATE_MESSAGE* message; - message = &context->NEGOTIATE_MESSAGE; ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) @@ -217,7 +211,6 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) && (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) && - (message->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) && (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE))) { Stream_Free(s, FALSE); @@ -250,22 +243,17 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "NEGOTIATE_MESSAGE (length = %d)\n", (int) context->NegotiateMessage.cbBuffer); - winpr_HexDump(context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); - fprintf(stderr, "\n"); - + WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", (int) context->NegotiateMessage.cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); ntlm_print_negotiate_flags(message->NegotiateFlags); if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ntlm_print_version_info(&(message->Version)); + #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); - return SEC_I_CONTINUE_NEEDED; } @@ -274,10 +262,8 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu wStream* s; int length; NTLM_NEGOTIATE_MESSAGE* message; - message = &context->NEGOTIATE_MESSAGE; ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) @@ -312,19 +298,13 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu ntlm_get_version_info(&(message->Version)); context->NegotiateFlags = message->NegotiateFlags; - /* Message Header (12 bytes) */ ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) message); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ - /* DomainNameFields (8 bytes) */ ntlm_write_message_fields(s, &(message->DomainName)); - /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ - /* WorkstationFields (8 bytes) */ ntlm_write_message_fields(s, &(message->Workstation)); @@ -339,20 +319,16 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "NEGOTIATE_MESSAGE (length = %d)\n", length); - winpr_HexDump(Stream_Buffer(s), length); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ntlm_print_version_info(&(message->Version)); + #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); - return SEC_I_CONTINUE_NEEDED; } @@ -364,12 +340,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf PBYTE PayloadOffset; NTLM_AV_PAIR* AvTimestamp; NTLM_CHALLENGE_MESSAGE* message; - ntlm_generate_client_challenge(context); - message = &context->CHALLENGE_MESSAGE; ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) @@ -428,7 +401,6 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer; context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len; - AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*) message->TargetInfo.Buffer, MsvAvTimestamp); if (AvTimestamp) @@ -446,12 +418,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf return SEC_E_INTERNAL_ERROR; CopyMemory(context->ChallengeMessage.pvBuffer, StartOffset, length); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "CHALLENGE_MESSAGE (length = %d)\n", length); - winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); - fprintf(stderr, "\n"); - + WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); ntlm_print_negotiate_flags(context->NegotiateFlags); if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -462,9 +431,10 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf if (context->ChallengeTargetInfo.cbBuffer > 0) { - fprintf(stderr, "ChallengeTargetInfo (%d):\n", (int) context->ChallengeTargetInfo.cbBuffer); + WLog_DBG(TAG, "ChallengeTargetInfo (%d):", (int) context->ChallengeTargetInfo.cbBuffer); ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer); } + #endif /* AV_PAIRs */ @@ -487,76 +457,44 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf return SEC_E_INTERNAL_ERROR; ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */ - ntlm_generate_random_session_key(context); /* RandomSessionKey */ - ntlm_generate_exported_session_key(context); /* ExportedSessionKey */ - ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */ - /* Generate signing keys */ ntlm_generate_client_signing_key(context); ntlm_generate_server_signing_key(context); - /* Generate sealing keys */ ntlm_generate_client_sealing_key(context); ntlm_generate_server_sealing_key(context); - /* Initialize RC4 seal state using client sealing key */ ntlm_init_rc4_seal_states(context); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "ClientChallenge\n"); - winpr_HexDump(context->ClientChallenge, 8); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerChallenge\n"); - winpr_HexDump(context->ServerChallenge, 8); - fprintf(stderr, "\n"); - - fprintf(stderr, "SessionBaseKey\n"); - winpr_HexDump(context->SessionBaseKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "KeyExchangeKey\n"); - winpr_HexDump(context->KeyExchangeKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ExportedSessionKey\n"); - winpr_HexDump(context->ExportedSessionKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "RandomSessionKey\n"); - winpr_HexDump(context->RandomSessionKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientSigningKey\n"); - winpr_HexDump(context->ClientSigningKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientSealingKey\n"); - winpr_HexDump(context->ClientSealingKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerSigningKey\n"); - winpr_HexDump(context->ServerSigningKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerSealingKey\n"); - winpr_HexDump(context->ServerSealingKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "Timestamp\n"); - winpr_HexDump(context->Timestamp, 8); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ClientChallenge"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); + WLog_DBG(TAG, "ServerChallenge"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); + WLog_DBG(TAG, "SessionBaseKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); + WLog_DBG(TAG, "KeyExchangeKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); + WLog_DBG(TAG, "ExportedSessionKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); + WLog_DBG(TAG, "RandomSessionKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); + WLog_DBG(TAG, "ClientSigningKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); + WLog_DBG(TAG, "ClientSealingKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); + WLog_DBG(TAG, "ServerSigningKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); + WLog_DBG(TAG, "ServerSealingKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); + WLog_DBG(TAG, "Timestamp"); + winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); #endif - context->state = NTLM_STATE_AUTHENTICATE; - ntlm_free_message_fields_buffer(&(message->TargetName)); - Stream_Free(s, FALSE); - return SEC_I_CONTINUE_NEEDED; } @@ -566,30 +504,23 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu int length; UINT32 PayloadOffset; NTLM_CHALLENGE_MESSAGE* message; - message = &context->CHALLENGE_MESSAGE; ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; ntlm_get_version_info(&(message->Version)); /* Version */ - ntlm_generate_server_challenge(context); /* Server Challenge */ - ntlm_generate_timestamp(context); /* Timestamp */ if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */ return SEC_E_INTERNAL_ERROR; CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */ - message->NegotiateFlags = context->NegotiateFlags; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_CHALLENGE); - /* Message Header (12 bytes) */ ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) message); @@ -614,15 +545,11 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu message->TargetName.BufferOffset = PayloadOffset; message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len; - /* TargetNameFields (8 bytes) */ ntlm_write_message_fields(s, &(message->TargetName)); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ - /* TargetInfoFields (8 bytes) */ ntlm_write_message_fields(s, &(message->TargetInfo)); @@ -644,12 +571,9 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu return SEC_E_INTERNAL_ERROR; CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "CHALLENGE_MESSAGE (length = %d)\n", length); - winpr_HexDump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); - fprintf(stderr, "\n"); - + WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); ntlm_print_negotiate_flags(message->NegotiateFlags); if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -658,11 +582,8 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu ntlm_print_message_fields(&(message->TargetName), "TargetName"); ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); #endif - context->state = NTLM_STATE_AUTHENTICATE; - Stream_Free(s, FALSE); - return SEC_I_CONTINUE_NEEDED; } @@ -675,13 +596,10 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer UINT32 PayloadBufferOffset; NTLM_AUTHENTICATE_MESSAGE* message; SSPI_CREDENTIALS* credentials = context->credentials; - flags = 0; AvFlags = NULL; - message = &context->AUTHENTICATE_MESSAGE; ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) @@ -712,11 +630,10 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer return SEC_E_INVALID_TOKEN; Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - context->NegotiateKeyExchange = (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE; if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) || - (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len)) + (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len)) return SEC_E_INVALID_TOKEN; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -753,16 +670,12 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer return SEC_E_INVALID_TOKEN; Stream_Free(snt, FALSE); - context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer; context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len; - sspi_SecBufferFree(&(context->ChallengeTargetInfo)); context->ChallengeTargetInfo.pvBuffer = (void*) context->NTLMv2Response.Challenge.AvPairs; context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16); - CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8); - AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, MsvAvFlags); if (AvFlags) @@ -784,10 +697,9 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) return SEC_E_INTERNAL_ERROR; - + CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); buffer->cbBuffer = length; - Stream_SetPosition(s, PayloadBufferOffset); if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) @@ -802,9 +714,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer } #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "AUTHENTICATE_MESSAGE (length = %d)\n", (int) context->AuthenticateMessage.cbBuffer); - winpr_HexDump(context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", (int) context->AuthenticateMessage.cbBuffer); + winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ntlm_print_version_info(&(message->Version)); @@ -815,14 +726,14 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); - ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs); if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { - fprintf(stderr, "MessageIntegrityCheck:\n"); - winpr_HexDump(message->MessageIntegrityCheck, 16); + WLog_DBG(TAG, "MessageIntegrityCheck:"); + winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); } + #endif if (message->UserName.Len > 0) @@ -848,11 +759,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer } Stream_Free(s, FALSE); - /* Computations beyond this point require the NTLM hash of the password */ - context->state = NTLM_STATE_COMPLETION; - return SEC_I_COMPLETE_NEEDED; } @@ -870,10 +778,8 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer UINT32 PayloadBufferOffset; NTLM_AUTHENTICATE_MESSAGE* message; SSPI_CREDENTIALS* credentials = context->credentials; - message = &context->AUTHENTICATE_MESSAGE; ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*) buffer->pvBuffer, buffer->cbBuffer); if (!s) @@ -925,10 +831,8 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer message->UserName.Len = (UINT16) credentials->identity.UserLength * 2; message->UserName.Buffer = (BYTE*) credentials->identity.User; - message->LmChallengeResponse.Len = (UINT16) context->LmChallengeResponse.cbBuffer; message->LmChallengeResponse.Buffer = (BYTE*) context->LmChallengeResponse.pvBuffer; - message->NtChallengeResponse.Len = (UINT16) context->NtChallengeResponse.cbBuffer; message->NtChallengeResponse.Buffer = (BYTE*) context->NtChallengeResponse.pvBuffer; @@ -952,23 +856,14 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer message->LmChallengeResponse.BufferOffset = message->Workstation.BufferOffset + message->Workstation.Len; message->NtChallengeResponse.BufferOffset = message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len; message->EncryptedRandomSessionKey.BufferOffset = message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*) message, MESSAGE_TYPE_AUTHENTICATE); - - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) message); /* Message Header (12 bytes) */ - + ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*) message); /* Message Header (12 bytes) */ ntlm_write_message_fields(s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->NtChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->DomainName)); /* DomainNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->UserName)); /* UserNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKeyFields (8 bytes) */ - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -989,14 +884,13 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */ ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */ - ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ntlm_write_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */ length = Stream_GetPosition(s); - + if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) return SEC_E_INTERNAL_ERROR; @@ -1007,17 +901,14 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer { /* Message Integrity Check */ ntlm_compute_message_integrity_check(context); - Stream_SetPosition(s, context->MessageIntegrityCheckOffset); Stream_Write(s, context->MessageIntegrityCheck, 16); Stream_SetPosition(s, length); } #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "AUTHENTICATE_MESSAGE (length = %d)\n", length); - winpr_HexDump(Stream_Buffer(s), length); - fprintf(stderr, "\n"); - + WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length); + winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); ntlm_print_negotiate_flags(message->NegotiateFlags); if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) @@ -1025,7 +916,7 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (context->AuthenticateTargetInfo.cbBuffer > 0) { - fprintf(stderr, "AuthenticateTargetInfo (%d):\n", (int) context->AuthenticateTargetInfo.cbBuffer); + WLog_DBG(TAG, "AuthenticateTargetInfo (%d):", (int) context->AuthenticateTargetInfo.cbBuffer); ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer); } @@ -1038,16 +929,13 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (context->UseMIC) { - fprintf(stderr, "MessageIntegrityCheck (length = 16)\n"); - winpr_HexDump(context->MessageIntegrityCheck, 16); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)"); + winpr_HexDump(TAG, WLOG_DEBUG, context->MessageIntegrityCheck, 16); } + #endif - context->state = NTLM_STATE_FINAL; - Stream_Free(s, FALSE); - return SEC_I_COMPLETE_NEEDED; } @@ -1061,7 +949,6 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) return SEC_E_OUT_OF_SEQUENCE; message = &context->AUTHENTICATE_MESSAGE; - AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, MsvAvFlags); if (AvFlags) @@ -1075,31 +962,25 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) /* KeyExchangeKey */ ntlm_generate_key_exchange_key(context); - /* EncryptedRandomSessionKey */ ntlm_decrypt_random_session_key(context); - /* ExportedSessionKey */ ntlm_generate_exported_session_key(context); if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { ZeroMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], 16); - ntlm_compute_message_integrity_check(context); - CopyMemory(&((PBYTE) context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], - message->MessageIntegrityCheck, 16); + message->MessageIntegrityCheck, 16); if (memcmp(context->MessageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0) { - fprintf(stderr, "Message Integrity Check (MIC) verification failed!\n"); - - fprintf(stderr, "Expected MIC:\n"); - winpr_HexDump(context->MessageIntegrityCheck, 16); - fprintf(stderr, "Actual MIC:\n"); - winpr_HexDump(message->MessageIntegrityCheck, 16); - + WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!"); + WLog_ERR(TAG, "Expected MIC:"); + winpr_HexDump(TAG, WLOG_ERROR, context->MessageIntegrityCheck, 16); + WLog_ERR(TAG, "Actual MIC:"); + winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck, 16); return SEC_E_MESSAGE_ALTERED; } } @@ -1107,68 +988,41 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) /* Generate signing keys */ ntlm_generate_client_signing_key(context); ntlm_generate_server_signing_key(context); - /* Generate sealing keys */ ntlm_generate_client_sealing_key(context); ntlm_generate_server_sealing_key(context); - /* Initialize RC4 seal state */ ntlm_init_rc4_seal_states(context); - #ifdef WITH_DEBUG_NTLM - fprintf(stderr, "ClientChallenge\n"); - winpr_HexDump(context->ClientChallenge, 8); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerChallenge\n"); - winpr_HexDump(context->ServerChallenge, 8); - fprintf(stderr, "\n"); - - fprintf(stderr, "SessionBaseKey\n"); - winpr_HexDump(context->SessionBaseKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "KeyExchangeKey\n"); - winpr_HexDump(context->KeyExchangeKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ExportedSessionKey\n"); - winpr_HexDump(context->ExportedSessionKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "RandomSessionKey\n"); - winpr_HexDump(context->RandomSessionKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientSigningKey\n"); - winpr_HexDump(context->ClientSigningKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ClientSealingKey\n"); - winpr_HexDump(context->ClientSealingKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerSigningKey\n"); - winpr_HexDump(context->ServerSigningKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "ServerSealingKey\n"); - winpr_HexDump(context->ServerSealingKey, 16); - fprintf(stderr, "\n"); - - fprintf(stderr, "Timestamp\n"); - winpr_HexDump(context->Timestamp, 8); - fprintf(stderr, "\n"); + WLog_DBG(TAG, "ClientChallenge"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); + WLog_DBG(TAG, "ServerChallenge"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); + WLog_DBG(TAG, "SessionBaseKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); + WLog_DBG(TAG, "KeyExchangeKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); + WLog_DBG(TAG, "ExportedSessionKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); + WLog_DBG(TAG, "RandomSessionKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); + WLog_DBG(TAG, "ClientSigningKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); + WLog_DBG(TAG, "ClientSealingKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); + WLog_DBG(TAG, "ServerSigningKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); + WLog_DBG(TAG, "ServerSealingKey"); + winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); + WLog_DBG(TAG, "Timestamp"); + winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); #endif - context->state = NTLM_STATE_FINAL; - ntlm_free_message_fields_buffer(&(message->DomainName)); ntlm_free_message_fields_buffer(&(message->UserName)); ntlm_free_message_fields_buffer(&(message->Workstation)); ntlm_free_message_fields_buffer(&(message->LmChallengeResponse)); ntlm_free_message_fields_buffer(&(message->NtChallengeResponse)); ntlm_free_message_fields_buffer(&(message->EncryptedRandomSessionKey)); - return SEC_E_OK; } diff --git a/winpr/libwinpr/sspi/Schannel/schannel_openssl.c b/winpr/libwinpr/sspi/Schannel/schannel_openssl.c index 5ad6e600e..98fb35c79 100644 --- a/winpr/libwinpr/sspi/Schannel/schannel_openssl.c +++ b/winpr/libwinpr/sspi/Schannel/schannel_openssl.c @@ -3,7 +3,7 @@ * Schannel Security Package (OpenSSL) * * Copyright 2012-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 @@ -23,10 +23,14 @@ #include #include +#include #include #include "schannel_openssl.h" +#include "../../log.h" +#define TAG WINPR_TAG("sspi.schannel") + char* openssl_get_ssl_error_string(int ssl_error) { switch (ssl_error) @@ -44,7 +48,6 @@ char* openssl_get_ssl_error_string(int ssl_error) return "SSL_ERROR_SYSCALL"; case SSL_ERROR_SSL: - ERR_print_errors_fp(stdout); return "SSL_ERROR_SSL"; } @@ -55,12 +58,11 @@ int schannel_openssl_client_init(SCHANNEL_OPENSSL* context) { int status; long options = 0; - context->ctx = SSL_CTX_new(TLSv1_client_method()); if (!context->ctx) { - fprintf(stderr, "SSL_CTX_new failed\n"); + WLog_ERR(TAG, "SSL_CTX_new failed"); return -1; } @@ -76,7 +78,6 @@ int schannel_openssl_client_init(SCHANNEL_OPENSSL* context) #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif - /** * SSL_OP_TLS_BLOCK_PADDING_BUG: * @@ -84,7 +85,6 @@ int schannel_openssl_client_init(SCHANNEL_OPENSSL* context) * It absolutely needs to be disabled otherwise it won't work. */ options |= SSL_OP_TLS_BLOCK_PADDING_BUG; - /** * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: * @@ -92,14 +92,12 @@ int schannel_openssl_client_init(SCHANNEL_OPENSSL* context) * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - SSL_CTX_set_options(context->ctx, options); - context->ssl = SSL_new(context->ctx); if (!context->ssl) { - fprintf(stderr, "SSL_new failed\n"); + WLog_ERR(TAG, "SSL_new failed"); return -1; } @@ -107,29 +105,24 @@ int schannel_openssl_client_init(SCHANNEL_OPENSSL* context) if (!context->bioRead) { - fprintf(stderr, "BIO_new failed\n"); + WLog_ERR(TAG, "BIO_new failed"); return -1; } status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN); - context->bioWrite = BIO_new(BIO_s_mem()); if (!context->bioWrite) { - fprintf(stderr, "BIO_new failed\n"); + WLog_ERR(TAG, "BIO_new failed"); return -1; } status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN); - status = BIO_make_bio_pair(context->bioRead, context->bioWrite); - SSL_set_bio(context->ssl, context->bioRead, context->bioWrite); - context->ReadBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN); context->WriteBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN); - return 0; } @@ -137,13 +130,12 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) { int status; long options = 0; - //context->ctx = SSL_CTX_new(SSLv23_server_method()); context->ctx = SSL_CTX_new(TLSv1_server_method()); if (!context->ctx) { - fprintf(stderr, "SSL_CTX_new failed\n"); + WLog_ERR(TAG, "SSL_CTX_new failed"); return -1; } @@ -154,7 +146,6 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) * SSLv3 is used by, eg. Microsoft RDC for Mac OS X. */ options |= SSL_OP_NO_SSLv2; - /** * SSL_OP_NO_COMPRESSION: * @@ -167,7 +158,6 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif - /** * SSL_OP_TLS_BLOCK_PADDING_BUG: * @@ -175,7 +165,6 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) * It absolutely needs to be disabled otherwise it won't work. */ options |= SSL_OP_TLS_BLOCK_PADDING_BUG; - /** * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: * @@ -183,12 +172,11 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; - SSL_CTX_set_options(context->ctx, options); if (SSL_CTX_use_RSAPrivateKey_file(context->ctx, "/tmp/localhost.key", SSL_FILETYPE_PEM) <= 0) { - fprintf(stderr, "SSL_CTX_use_RSAPrivateKey_file failed\n"); + WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed"); return -1; } @@ -196,13 +184,13 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) if (!context->ssl) { - fprintf(stderr, "SSL_new failed\n"); + WLog_ERR(TAG, "SSL_new failed"); return -1; } if (SSL_use_certificate_file(context->ssl, "/tmp/localhost.crt", SSL_FILETYPE_PEM) <= 0) { - fprintf(stderr, "SSL_use_certificate_file failed\n"); + WLog_ERR(TAG, "SSL_use_certificate_file failed"); return -1; } @@ -210,29 +198,24 @@ int schannel_openssl_server_init(SCHANNEL_OPENSSL* context) if (!context->bioRead) { - fprintf(stderr, "BIO_new failed\n"); + WLog_ERR(TAG, "BIO_new failed"); return -1; } status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN); - context->bioWrite = BIO_new(BIO_s_mem()); if (!context->bioWrite) { - fprintf(stderr, "BIO_new failed\n"); + WLog_ERR(TAG, "BIO_new failed"); return -1; } status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN); - status = BIO_make_bio_pair(context->bioRead, context->bioWrite); - SSL_set_bio(context->ssl, context->bioRead, context->bioWrite); - context->ReadBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN); context->WriteBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN); - return 0; } @@ -262,7 +245,7 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); - fprintf(stderr, "SSL_connect error: %s\n", openssl_get_ssl_error_string(ssl_error)); + WLog_ERR(TAG, "SSL_connect error: %s", openssl_get_ssl_error_string(ssl_error)); } if (status == 1) @@ -285,7 +268,6 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status); pBuffer->cbBuffer = status; - return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED; } else @@ -315,13 +297,12 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context return SEC_E_INVALID_TOKEN; status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer); - status = SSL_accept(context->ssl); if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); - fprintf(stderr, "SSL_accept error: %s\n", openssl_get_ssl_error_string(ssl_error)); + WLog_ERR(TAG, "SSL_accept error: %s", openssl_get_ssl_error_string(ssl_error)); } if (status == 1) @@ -344,7 +325,6 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status); pBuffer->cbBuffer = status; - return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED; } else @@ -366,7 +346,6 @@ SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSec PSecBuffer pStreamBodyBuffer; PSecBuffer pStreamHeaderBuffer; PSecBuffer pStreamTrailerBuffer; - pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER); pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA); pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER); @@ -379,7 +358,7 @@ SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSec if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); - fprintf(stderr, "SSL_write: %s\n", openssl_get_ssl_error_string(ssl_error)); + WLog_ERR(TAG, "SSL_write: %s", openssl_get_ssl_error_string(ssl_error)); } status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN); @@ -390,12 +369,10 @@ SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSec length = (pStreamHeaderBuffer->cbBuffer > (unsigned long) status) ? status : pStreamHeaderBuffer->cbBuffer; CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length); status -= length; - offset += length; length = (pStreamBodyBuffer->cbBuffer > (unsigned long) status) ? status : pStreamBodyBuffer->cbBuffer; CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length); status -= length; - offset += length; length = (pStreamTrailerBuffer->cbBuffer > (unsigned long) status) ? status : pStreamTrailerBuffer->cbBuffer; CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length); @@ -412,54 +389,43 @@ SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSec BYTE* buffer; int ssl_error; PSecBuffer pBuffer; - pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA); if (!pBuffer) return SEC_E_INVALID_TOKEN; status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer); - status = SSL_read(context->ssl, pBuffer->pvBuffer, pBuffer->cbBuffer); if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); - fprintf(stderr, "SSL_read: %s\n", openssl_get_ssl_error_string(ssl_error)); + WLog_ERR(TAG, "SSL_read: %s", openssl_get_ssl_error_string(ssl_error)); } length = status; buffer = pBuffer->pvBuffer; - pMessage->pBuffers[0].BufferType = SECBUFFER_STREAM_HEADER; pMessage->pBuffers[0].cbBuffer = 5; - pMessage->pBuffers[1].BufferType = SECBUFFER_DATA; pMessage->pBuffers[1].pvBuffer = buffer; pMessage->pBuffers[1].cbBuffer = length; - pMessage->pBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER; pMessage->pBuffers[2].cbBuffer = 36; - pMessage->pBuffers[3].BufferType = SECBUFFER_EMPTY; pMessage->pBuffers[3].cbBuffer = 0; - return SEC_E_OK; } SCHANNEL_OPENSSL* schannel_openssl_new() { SCHANNEL_OPENSSL* context; - context = (SCHANNEL_OPENSSL*) malloc(sizeof(SCHANNEL_OPENSSL)); if (context != NULL) { ZeroMemory(context, sizeof(SCHANNEL_OPENSSL)); - - SSL_load_error_strings(); - SSL_library_init(); - + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); context->connected = FALSE; } @@ -472,7 +438,6 @@ void schannel_openssl_free(SCHANNEL_OPENSSL* context) { free(context->ReadBuffer); free(context->WriteBuffer); - free(context); } } diff --git a/winpr/libwinpr/sspi/sspi_winpr.c b/winpr/libwinpr/sspi/sspi_winpr.c index dee803b6b..dcfb4e2b2 100644 --- a/winpr/libwinpr/sspi/sspi_winpr.c +++ b/winpr/libwinpr/sspi/sspi_winpr.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -463,8 +464,7 @@ void sspi_GlobalInit() { if (!sspi_initialized) { - SSL_load_error_strings(); - SSL_library_init(); + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); sspi_ContextBufferAllocTableNew(); sspi_initialized = TRUE; diff --git a/winpr/libwinpr/sspi/test/CMakeLists.txt b/winpr/libwinpr/sspi/test/CMakeLists.txt index afe93c408..60e8e09fd 100644 --- a/winpr/libwinpr/sspi/test/CMakeLists.txt +++ b/winpr/libwinpr/sspi/test/CMakeLists.txt @@ -30,12 +30,7 @@ if(WIN32) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} secur32 crypt32) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-sspi winpr-thread winpr-pipe winpr-file winpr-crypto winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/sspi/test/TestNTLM.c b/winpr/libwinpr/sspi/test/TestNTLM.c index a56992acf..052fc7892 100644 --- a/winpr/libwinpr/sspi/test/TestNTLM.c +++ b/winpr/libwinpr/sspi/test/TestNTLM.c @@ -2,6 +2,7 @@ #include #include #include +#include static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 }; @@ -64,12 +65,12 @@ static const char* TEST_NTLM_PASSWORD = "P4ss123!"; //static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db"; static const BYTE TEST_NTLM_HASH[16] = - { 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82, 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb }; +{ 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82, 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb }; //static const char* TEST_NTLM_HASH_V2_STRING = "4c7f706f7dde05a9d1a0f4e7ffe3bfb8"; static const BYTE TEST_NTLM_V2_HASH[16] = - { 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9, 0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 }; +{ 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9, 0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 }; //#define NTLM_PACKAGE_NAME NEGOSSP_NAME #define NTLM_PACKAGE_NAME NTLMSP_NAME @@ -100,13 +101,9 @@ typedef struct _TEST_NTLM_CLIENT TEST_NTLM_CLIENT; int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* domain, const char* password) { SECURITY_STATUS status; - SecInvalidateHandle(&(ntlm->context)); - ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE); - sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password); - status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo); if (status != SEC_E_OK) @@ -117,9 +114,8 @@ int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* } ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken; - status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, - SECPKG_CRED_OUTBOUND, NULL, &ntlm->identity, NULL, NULL, &ntlm->credentials, &ntlm->expiration); + SECPKG_CRED_OUTBOUND, NULL, &ntlm->identity, NULL, NULL, &ntlm->credentials, &ntlm->expiration); if (status != SEC_E_OK) { @@ -132,19 +128,15 @@ int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* ntlm->haveInputBuffer = FALSE; ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer)); ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer)); - ntlm->fContextReq = 0; - #if 0 /* HTTP authentication flags */ ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY; #endif - /* NLA authentication flags */ ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH; ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY; ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY; - return 1; } @@ -245,12 +237,12 @@ int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm) } status = ntlm->table->InitializeSecurityContext(&ntlm->credentials, - (ntlm->haveContext) ? &ntlm->context : NULL, - (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL, - ntlm->fContextReq, 0, SECURITY_NATIVE_DREP, - (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : NULL, - 0, &ntlm->context, &ntlm->outputBufferDesc, - &ntlm->pfContextAttr, &ntlm->expiration); + (ntlm->haveContext) ? &ntlm->context : NULL, + (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL, + ntlm->fContextReq, 0, SECURITY_NATIVE_DREP, + (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : NULL, + 0, &ntlm->context, &ntlm->outputBufferDesc, + &ntlm->pfContextAttr, &ntlm->expiration); if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED)) { @@ -270,14 +262,12 @@ int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm) ntlm->haveInputBuffer = TRUE; ntlm->haveContext = TRUE; - return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0; } TEST_NTLM_CLIENT* test_ntlm_client_new() { TEST_NTLM_CLIENT* ntlm; - ntlm = (TEST_NTLM_CLIENT*) calloc(1, sizeof(TEST_NTLM_CLIENT)); if (!ntlm) @@ -292,7 +282,6 @@ void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm) return; test_ntlm_client_uninit(ntlm); - free(ntlm); } @@ -323,13 +312,9 @@ typedef struct _TEST_NTLM_SERVER TEST_NTLM_SERVER; int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm) { SECURITY_STATUS status; - ntlm->UseNtlmV2Hash = TRUE; - SecInvalidateHandle(&(ntlm->context)); - ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE); - status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo); if (status != SEC_E_OK) @@ -340,10 +325,9 @@ int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm) } ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken; - status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, - SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, - &ntlm->credentials, &ntlm->expiration); + SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, + &ntlm->credentials, &ntlm->expiration); if (status != SEC_E_OK) { @@ -356,9 +340,7 @@ int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm) ntlm->haveInputBuffer = FALSE; ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer)); ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer)); - ntlm->fContextReq = 0; - /* NLA authentication flags */ ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH; ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY; @@ -367,7 +349,6 @@ int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm) ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT; ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT; ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR; - return 1; } @@ -398,32 +379,27 @@ void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm) int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm) { SECURITY_STATUS status; - ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION; ntlm->inputBufferDesc.cBuffers = 1; ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer; ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN; - ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION; ntlm->outputBufferDesc.cBuffers = 1; ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0]; ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN; ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken; ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer); - status = ntlm->table->AcceptSecurityContext(&ntlm->credentials, - ntlm->haveContext? &ntlm->context: NULL, - &ntlm->inputBufferDesc, ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, - &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration); + ntlm->haveContext? &ntlm->context: NULL, + &ntlm->inputBufferDesc, ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, + &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration); if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED)) { SecPkgContext_AuthIdentity AuthIdentity; SecPkgContext_AuthNtlmHash AuthNtlmHash; - ZeroMemory(&AuthIdentity, sizeof(SecPkgContext_AuthIdentity)); ZeroMemory(&AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash)); - status = ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_IDENTITY, &AuthIdentity); if (status == SEC_E_OK) @@ -442,7 +418,7 @@ int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm) } status = ntlm->table->SetContextAttributes(&ntlm->context, - SECPKG_ATTR_AUTH_NTLM_HASH, &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash)); + SECPKG_ATTR_AUTH_NTLM_HASH, &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash)); } } @@ -463,14 +439,12 @@ int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm) } ntlm->haveContext = TRUE; - return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0; } TEST_NTLM_SERVER* test_ntlm_server_new() { TEST_NTLM_SERVER* ntlm; - ntlm = (TEST_NTLM_SERVER*) calloc(1, sizeof(TEST_NTLM_SERVER)); if (!ntlm) @@ -485,7 +459,6 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm) return; test_ntlm_server_uninit(ntlm); - free(ntlm); } @@ -496,13 +469,10 @@ int TestNTLM(int argc, char* argv[]) TEST_NTLM_CLIENT* client; TEST_NTLM_SERVER* server; BOOL DynamicTest = TRUE; - /** * Client Initialization */ - client = test_ntlm_client_new(); - status = test_ntlm_client_init(client, TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD); if (status < 0) @@ -514,9 +484,7 @@ int TestNTLM(int argc, char* argv[]) /** * Server Initialization */ - server = test_ntlm_server_new(); - status = test_ntlm_server_init(server); if (status < 0) @@ -528,7 +496,6 @@ int TestNTLM(int argc, char* argv[]) /** * Client -> Negotiate Message */ - status = test_ntlm_client_authenticate(client); if (status < 0) @@ -542,24 +509,19 @@ int TestNTLM(int argc, char* argv[]) SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp; SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge; SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge; - CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8); - AuthNtlmTimestamp.ChallengeOrResponse = TRUE; client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, - &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); - + &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); AuthNtlmTimestamp.ChallengeOrResponse = FALSE; client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, - &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); - + &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8); CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8); - client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, - &AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge)); + &AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge)); client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, - &AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge)); + &AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge)); } pSecBuffer = &(client->outputBuffer[0]); @@ -572,18 +534,15 @@ int TestNTLM(int argc, char* argv[]) } fprintf(stderr, "NTLM_NEGOTIATE (length = %d):\n", pSecBuffer->cbBuffer); - winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); - + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); /** * Server <- Negotiate Message * Server -> Challenge Message */ - server->haveInputBuffer = TRUE; server->inputBuffer[0].BufferType = SECBUFFER_TOKEN; server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer; server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer; - status = test_ntlm_server_authenticate(server); if (status < 0) @@ -597,24 +556,19 @@ int TestNTLM(int argc, char* argv[]) SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp; SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge; SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge; - CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8); - AuthNtlmTimestamp.ChallengeOrResponse = TRUE; client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, - &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); - + &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); AuthNtlmTimestamp.ChallengeOrResponse = FALSE; client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, - &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); - + &AuthNtlmTimestamp, sizeof(SecPkgContext_AuthNtlmTimestamp)); CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8); CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8); - server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, - &AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge)); + &AuthNtlmClientChallenge, sizeof(SecPkgContext_AuthNtlmClientChallenge)); server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, - &AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge)); + &AuthNtlmServerChallenge, sizeof(SecPkgContext_AuthNtlmServerChallenge)); } pSecBuffer = &(server->outputBuffer[0]); @@ -622,32 +576,26 @@ int TestNTLM(int argc, char* argv[]) if (!DynamicTest) { SecPkgContext_AuthNtlmMessage AuthNtlmMessage; - pSecBuffer->cbBuffer = sizeof(TEST_NTLM_CHALLENGE) -1; pSecBuffer->pvBuffer = (void*) malloc(pSecBuffer->cbBuffer); CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer); - AuthNtlmMessage.type = 2; AuthNtlmMessage.length = pSecBuffer->cbBuffer; AuthNtlmMessage.buffer = (BYTE*) pSecBuffer->pvBuffer; - server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, - &AuthNtlmMessage, sizeof(SecPkgContext_AuthNtlmMessage)); + &AuthNtlmMessage, sizeof(SecPkgContext_AuthNtlmMessage)); } fprintf(stderr, "NTLM_CHALLENGE (length = %d):\n", pSecBuffer->cbBuffer); - winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); - + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); /** * Client <- Challenge Message * Client -> Authenticate Message */ - client->haveInputBuffer = TRUE; client->inputBuffer[0].BufferType = SECBUFFER_TOKEN; client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer; client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer; - status = test_ntlm_client_authenticate(client); if (status < 0) @@ -657,6 +605,7 @@ int TestNTLM(int argc, char* argv[]) } pSecBuffer = &(client->outputBuffer[0]); + if (!DynamicTest) { pSecBuffer->cbBuffer = sizeof(TEST_NTLM_AUTHENTICATE) -1; @@ -665,17 +614,14 @@ int TestNTLM(int argc, char* argv[]) } fprintf(stderr, "NTLM_AUTHENTICATE (length = %d):\n", pSecBuffer->cbBuffer); - winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); - + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); /** * Server <- Authenticate Message */ - server->haveInputBuffer = TRUE; server->inputBuffer[0].BufferType = SECBUFFER_TOKEN; server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer; server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer; - status = test_ntlm_server_authenticate(server); if (status < 0) @@ -687,9 +633,7 @@ int TestNTLM(int argc, char* argv[]) /** * Cleanup & Termination */ - test_ntlm_client_free(client); test_ntlm_server_free(server); - return 0; } diff --git a/winpr/libwinpr/sspi/test/TestSchannel.c b/winpr/libwinpr/sspi/test/TestSchannel.c index f4385d143..c7fdaf2fc 100644 --- a/winpr/libwinpr/sspi/test/TestSchannel.c +++ b/winpr/libwinpr/sspi/test/TestSchannel.c @@ -9,6 +9,7 @@ #include #include #include +#include #include BOOL g_ClientWait = FALSE; @@ -21,193 +22,193 @@ HANDLE g_ServerWritePipe = NULL; BYTE test_localhost_crt[1029] = { - 0x2D,0x2D,0x2D,0x2D,0x2D,0x42,0x45,0x47,0x49,0x4E,0x20,0x43,0x45,0x52,0x54, - 0x49,0x46,0x49,0x43,0x41,0x54,0x45,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,0x4D,0x49, - 0x49,0x43,0x79,0x6A,0x43,0x43,0x41,0x62,0x4B,0x67,0x41,0x77,0x49,0x42,0x41, - 0x67,0x49,0x45,0x63,0x61,0x64,0x63,0x72,0x7A,0x41,0x4E,0x42,0x67,0x6B,0x71, - 0x68,0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x55,0x46,0x41,0x44,0x41, - 0x55,0x4D,0x52,0x49,0x77,0x45,0x41,0x59,0x44,0x56,0x51,0x51,0x44,0x45,0x77, - 0x6C,0x73,0x0A,0x62,0x32,0x4E,0x68,0x62,0x47,0x68,0x76,0x63,0x33,0x51,0x77, - 0x48,0x68,0x63,0x4E,0x4D,0x54,0x4D,0x78,0x4D,0x44,0x45,0x78,0x4D,0x44,0x59, - 0x78,0x4E,0x7A,0x55,0x31,0x57,0x68,0x63,0x4E,0x4D,0x54,0x51,0x78,0x4D,0x44, - 0x45,0x78,0x4D,0x44,0x59,0x78,0x4E,0x7A,0x55,0x31,0x57,0x6A,0x41,0x55,0x4D, - 0x52,0x49,0x77,0x45,0x41,0x59,0x44,0x0A,0x56,0x51,0x51,0x44,0x45,0x77,0x6C, - 0x73,0x62,0x32,0x4E,0x68,0x62,0x47,0x68,0x76,0x63,0x33,0x51,0x77,0x67,0x67, - 0x45,0x69,0x4D,0x41,0x30,0x47,0x43,0x53,0x71,0x47,0x53,0x49,0x62,0x33,0x44, - 0x51,0x45,0x42,0x41,0x51,0x55,0x41,0x41,0x34,0x49,0x42,0x44,0x77,0x41,0x77, - 0x67,0x67,0x45,0x4B,0x41,0x6F,0x49,0x42,0x41,0x51,0x43,0x33,0x0A,0x65,0x6E, - 0x33,0x68,0x5A,0x4F,0x53,0x33,0x6B,0x51,0x2F,0x55,0x54,0x30,0x53,0x45,0x6C, - 0x30,0x48,0x6E,0x50,0x79,0x64,0x48,0x75,0x35,0x39,0x61,0x69,0x71,0x64,0x73, - 0x64,0x53,0x55,0x74,0x6E,0x43,0x41,0x37,0x46,0x66,0x74,0x30,0x4F,0x36,0x51, - 0x79,0x68,0x49,0x71,0x58,0x7A,0x30,0x47,0x32,0x53,0x76,0x77,0x4C,0x54,0x62, - 0x79,0x68,0x0A,0x59,0x54,0x68,0x31,0x36,0x78,0x31,0x72,0x45,0x48,0x68,0x31, - 0x57,0x47,0x5A,0x6D,0x36,0x77,0x64,0x2B,0x4B,0x76,0x38,0x6B,0x31,0x6B,0x2F, - 0x36,0x6F,0x41,0x2F,0x4F,0x51,0x76,0x65,0x61,0x38,0x6B,0x63,0x45,0x64,0x53, - 0x72,0x54,0x64,0x75,0x71,0x4A,0x33,0x65,0x66,0x74,0x48,0x4A,0x4A,0x6E,0x43, - 0x4B,0x30,0x41,0x62,0x68,0x34,0x39,0x0A,0x41,0x47,0x41,0x50,0x39,0x79,0x58, - 0x77,0x77,0x59,0x41,0x6A,0x51,0x49,0x52,0x6E,0x38,0x2B,0x4F,0x63,0x63,0x48, - 0x74,0x6F,0x4E,0x75,0x75,0x79,0x52,0x63,0x6B,0x49,0x50,0x71,0x75,0x70,0x78, - 0x79,0x31,0x4A,0x5A,0x4B,0x39,0x64,0x76,0x76,0x62,0x34,0x79,0x53,0x6B,0x49, - 0x75,0x7A,0x62,0x79,0x50,0x6F,0x54,0x41,0x79,0x61,0x55,0x2B,0x0A,0x51,0x72, - 0x70,0x34,0x78,0x67,0x64,0x4B,0x46,0x54,0x70,0x6B,0x50,0x46,0x34,0x33,0x6A, - 0x32,0x4D,0x6D,0x5A,0x72,0x46,0x63,0x42,0x76,0x79,0x6A,0x69,0x35,0x6A,0x4F, - 0x37,0x74,0x66,0x6F,0x56,0x61,0x6B,0x59,0x47,0x53,0x2F,0x4C,0x63,0x78,0x77, - 0x47,0x2B,0x77,0x51,0x77,0x63,0x4F,0x43,0x54,0x42,0x45,0x78,0x2F,0x7A,0x31, - 0x53,0x30,0x0A,0x37,0x49,0x2F,0x6A,0x62,0x44,0x79,0x53,0x4E,0x68,0x44,0x35, - 0x63,0x61,0x63,0x54,0x75,0x4E,0x36,0x50,0x68,0x33,0x58,0x30,0x71,0x70,0x47, - 0x73,0x37,0x79,0x50,0x6B,0x4E,0x79,0x69,0x4A,0x33,0x57,0x52,0x69,0x6C,0x35, - 0x75,0x57,0x73,0x4B,0x65,0x79,0x63,0x64,0x71,0x42,0x4E,0x72,0x34,0x75,0x32, - 0x62,0x49,0x52,0x6E,0x63,0x54,0x51,0x0A,0x46,0x72,0x68,0x73,0x58,0x39,0x69, - 0x77,0x37,0x35,0x76,0x75,0x53,0x64,0x35,0x46,0x39,0x37,0x56,0x70,0x41,0x67, - 0x4D,0x42,0x41,0x41,0x47,0x6A,0x4A,0x44,0x41,0x69,0x4D,0x42,0x4D,0x47,0x41, - 0x31,0x55,0x64,0x4A,0x51,0x51,0x4D,0x4D,0x41,0x6F,0x47,0x43,0x43,0x73,0x47, - 0x41,0x51,0x55,0x46,0x42,0x77,0x4D,0x42,0x4D,0x41,0x73,0x47,0x0A,0x41,0x31, - 0x55,0x64,0x44,0x77,0x51,0x45,0x41,0x77,0x49,0x45,0x4D,0x44,0x41,0x4E,0x42, - 0x67,0x6B,0x71,0x68,0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x55,0x46, - 0x41,0x41,0x4F,0x43,0x41,0x51,0x45,0x41,0x49,0x51,0x66,0x75,0x2F,0x77,0x39, - 0x45,0x34,0x4C,0x6F,0x67,0x30,0x71,0x35,0x4B,0x53,0x38,0x71,0x46,0x78,0x62, - 0x36,0x6F,0x0A,0x36,0x31,0x62,0x35,0x37,0x6F,0x6D,0x6E,0x46,0x59,0x52,0x34, - 0x47,0x43,0x67,0x33,0x6F,0x6A,0x4F,0x4C,0x54,0x66,0x38,0x7A,0x6A,0x4D,0x43, - 0x52,0x6D,0x75,0x59,0x32,0x76,0x30,0x4E,0x34,0x78,0x66,0x68,0x69,0x35,0x4B, - 0x69,0x59,0x67,0x64,0x76,0x4E,0x4C,0x4F,0x33,0x52,0x42,0x6D,0x4E,0x50,0x76, - 0x59,0x58,0x50,0x52,0x46,0x41,0x76,0x0A,0x66,0x61,0x76,0x66,0x57,0x75,0x6C, - 0x44,0x31,0x64,0x50,0x36,0x31,0x69,0x35,0x62,0x36,0x59,0x66,0x56,0x6C,0x78, - 0x62,0x31,0x61,0x57,0x46,0x37,0x4C,0x5A,0x44,0x32,0x55,0x6E,0x63,0x41,0x6A, - 0x37,0x4E,0x38,0x78,0x38,0x2B,0x36,0x58,0x6B,0x30,0x6B,0x63,0x70,0x58,0x46, - 0x38,0x6C,0x77,0x58,0x48,0x55,0x57,0x57,0x55,0x6D,0x73,0x2B,0x0A,0x4B,0x56, - 0x44,0x34,0x34,0x39,0x68,0x6F,0x4D,0x2B,0x77,0x4E,0x4A,0x49,0x61,0x4F,0x52, - 0x39,0x4C,0x46,0x2B,0x6B,0x6F,0x32,0x32,0x37,0x7A,0x74,0x37,0x54,0x41,0x47, - 0x64,0x56,0x35,0x4A,0x75,0x7A,0x71,0x38,0x32,0x2F,0x6B,0x75,0x73,0x6F,0x65, - 0x32,0x69,0x75,0x57,0x77,0x54,0x65,0x42,0x6C,0x53,0x5A,0x6E,0x6B,0x42,0x38, - 0x63,0x64,0x0A,0x77,0x4D,0x30,0x5A,0x42,0x58,0x6D,0x34,0x35,0x48,0x38,0x6F, - 0x79,0x75,0x36,0x4A,0x71,0x59,0x71,0x45,0x6D,0x75,0x4A,0x51,0x64,0x67,0x79, - 0x52,0x2B,0x63,0x53,0x53,0x41,0x7A,0x2B,0x4F,0x32,0x6D,0x61,0x62,0x68,0x50, - 0x5A,0x65,0x49,0x76,0x78,0x65,0x67,0x6A,0x6A,0x61,0x5A,0x61,0x46,0x4F,0x71, - 0x74,0x73,0x2B,0x64,0x33,0x72,0x39,0x0A,0x79,0x71,0x4A,0x78,0x67,0x75,0x39, - 0x43,0x38,0x39,0x5A,0x69,0x33,0x39,0x57,0x34,0x38,0x46,0x66,0x46,0x63,0x49, - 0x58,0x4A,0x4F,0x6B,0x39,0x43,0x4E,0x46,0x41,0x2F,0x69,0x70,0x54,0x57,0x6A, - 0x74,0x74,0x4E,0x2F,0x6B,0x4F,0x6B,0x5A,0x42,0x70,0x6F,0x6A,0x2F,0x32,0x6A, - 0x4E,0x45,0x62,0x4F,0x59,0x7A,0x7A,0x6E,0x4B,0x77,0x3D,0x3D,0x0A,0x2D,0x2D, - 0x2D,0x2D,0x2D,0x45,0x4E,0x44,0x20,0x43,0x45,0x52,0x54,0x49,0x46,0x49,0x43, - 0x41,0x54,0x45,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A + 0x2D,0x2D,0x2D,0x2D,0x2D,0x42,0x45,0x47,0x49,0x4E,0x20,0x43,0x45,0x52,0x54, + 0x49,0x46,0x49,0x43,0x41,0x54,0x45,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,0x4D,0x49, + 0x49,0x43,0x79,0x6A,0x43,0x43,0x41,0x62,0x4B,0x67,0x41,0x77,0x49,0x42,0x41, + 0x67,0x49,0x45,0x63,0x61,0x64,0x63,0x72,0x7A,0x41,0x4E,0x42,0x67,0x6B,0x71, + 0x68,0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x55,0x46,0x41,0x44,0x41, + 0x55,0x4D,0x52,0x49,0x77,0x45,0x41,0x59,0x44,0x56,0x51,0x51,0x44,0x45,0x77, + 0x6C,0x73,0x0A,0x62,0x32,0x4E,0x68,0x62,0x47,0x68,0x76,0x63,0x33,0x51,0x77, + 0x48,0x68,0x63,0x4E,0x4D,0x54,0x4D,0x78,0x4D,0x44,0x45,0x78,0x4D,0x44,0x59, + 0x78,0x4E,0x7A,0x55,0x31,0x57,0x68,0x63,0x4E,0x4D,0x54,0x51,0x78,0x4D,0x44, + 0x45,0x78,0x4D,0x44,0x59,0x78,0x4E,0x7A,0x55,0x31,0x57,0x6A,0x41,0x55,0x4D, + 0x52,0x49,0x77,0x45,0x41,0x59,0x44,0x0A,0x56,0x51,0x51,0x44,0x45,0x77,0x6C, + 0x73,0x62,0x32,0x4E,0x68,0x62,0x47,0x68,0x76,0x63,0x33,0x51,0x77,0x67,0x67, + 0x45,0x69,0x4D,0x41,0x30,0x47,0x43,0x53,0x71,0x47,0x53,0x49,0x62,0x33,0x44, + 0x51,0x45,0x42,0x41,0x51,0x55,0x41,0x41,0x34,0x49,0x42,0x44,0x77,0x41,0x77, + 0x67,0x67,0x45,0x4B,0x41,0x6F,0x49,0x42,0x41,0x51,0x43,0x33,0x0A,0x65,0x6E, + 0x33,0x68,0x5A,0x4F,0x53,0x33,0x6B,0x51,0x2F,0x55,0x54,0x30,0x53,0x45,0x6C, + 0x30,0x48,0x6E,0x50,0x79,0x64,0x48,0x75,0x35,0x39,0x61,0x69,0x71,0x64,0x73, + 0x64,0x53,0x55,0x74,0x6E,0x43,0x41,0x37,0x46,0x66,0x74,0x30,0x4F,0x36,0x51, + 0x79,0x68,0x49,0x71,0x58,0x7A,0x30,0x47,0x32,0x53,0x76,0x77,0x4C,0x54,0x62, + 0x79,0x68,0x0A,0x59,0x54,0x68,0x31,0x36,0x78,0x31,0x72,0x45,0x48,0x68,0x31, + 0x57,0x47,0x5A,0x6D,0x36,0x77,0x64,0x2B,0x4B,0x76,0x38,0x6B,0x31,0x6B,0x2F, + 0x36,0x6F,0x41,0x2F,0x4F,0x51,0x76,0x65,0x61,0x38,0x6B,0x63,0x45,0x64,0x53, + 0x72,0x54,0x64,0x75,0x71,0x4A,0x33,0x65,0x66,0x74,0x48,0x4A,0x4A,0x6E,0x43, + 0x4B,0x30,0x41,0x62,0x68,0x34,0x39,0x0A,0x41,0x47,0x41,0x50,0x39,0x79,0x58, + 0x77,0x77,0x59,0x41,0x6A,0x51,0x49,0x52,0x6E,0x38,0x2B,0x4F,0x63,0x63,0x48, + 0x74,0x6F,0x4E,0x75,0x75,0x79,0x52,0x63,0x6B,0x49,0x50,0x71,0x75,0x70,0x78, + 0x79,0x31,0x4A,0x5A,0x4B,0x39,0x64,0x76,0x76,0x62,0x34,0x79,0x53,0x6B,0x49, + 0x75,0x7A,0x62,0x79,0x50,0x6F,0x54,0x41,0x79,0x61,0x55,0x2B,0x0A,0x51,0x72, + 0x70,0x34,0x78,0x67,0x64,0x4B,0x46,0x54,0x70,0x6B,0x50,0x46,0x34,0x33,0x6A, + 0x32,0x4D,0x6D,0x5A,0x72,0x46,0x63,0x42,0x76,0x79,0x6A,0x69,0x35,0x6A,0x4F, + 0x37,0x74,0x66,0x6F,0x56,0x61,0x6B,0x59,0x47,0x53,0x2F,0x4C,0x63,0x78,0x77, + 0x47,0x2B,0x77,0x51,0x77,0x63,0x4F,0x43,0x54,0x42,0x45,0x78,0x2F,0x7A,0x31, + 0x53,0x30,0x0A,0x37,0x49,0x2F,0x6A,0x62,0x44,0x79,0x53,0x4E,0x68,0x44,0x35, + 0x63,0x61,0x63,0x54,0x75,0x4E,0x36,0x50,0x68,0x33,0x58,0x30,0x71,0x70,0x47, + 0x73,0x37,0x79,0x50,0x6B,0x4E,0x79,0x69,0x4A,0x33,0x57,0x52,0x69,0x6C,0x35, + 0x75,0x57,0x73,0x4B,0x65,0x79,0x63,0x64,0x71,0x42,0x4E,0x72,0x34,0x75,0x32, + 0x62,0x49,0x52,0x6E,0x63,0x54,0x51,0x0A,0x46,0x72,0x68,0x73,0x58,0x39,0x69, + 0x77,0x37,0x35,0x76,0x75,0x53,0x64,0x35,0x46,0x39,0x37,0x56,0x70,0x41,0x67, + 0x4D,0x42,0x41,0x41,0x47,0x6A,0x4A,0x44,0x41,0x69,0x4D,0x42,0x4D,0x47,0x41, + 0x31,0x55,0x64,0x4A,0x51,0x51,0x4D,0x4D,0x41,0x6F,0x47,0x43,0x43,0x73,0x47, + 0x41,0x51,0x55,0x46,0x42,0x77,0x4D,0x42,0x4D,0x41,0x73,0x47,0x0A,0x41,0x31, + 0x55,0x64,0x44,0x77,0x51,0x45,0x41,0x77,0x49,0x45,0x4D,0x44,0x41,0x4E,0x42, + 0x67,0x6B,0x71,0x68,0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x55,0x46, + 0x41,0x41,0x4F,0x43,0x41,0x51,0x45,0x41,0x49,0x51,0x66,0x75,0x2F,0x77,0x39, + 0x45,0x34,0x4C,0x6F,0x67,0x30,0x71,0x35,0x4B,0x53,0x38,0x71,0x46,0x78,0x62, + 0x36,0x6F,0x0A,0x36,0x31,0x62,0x35,0x37,0x6F,0x6D,0x6E,0x46,0x59,0x52,0x34, + 0x47,0x43,0x67,0x33,0x6F,0x6A,0x4F,0x4C,0x54,0x66,0x38,0x7A,0x6A,0x4D,0x43, + 0x52,0x6D,0x75,0x59,0x32,0x76,0x30,0x4E,0x34,0x78,0x66,0x68,0x69,0x35,0x4B, + 0x69,0x59,0x67,0x64,0x76,0x4E,0x4C,0x4F,0x33,0x52,0x42,0x6D,0x4E,0x50,0x76, + 0x59,0x58,0x50,0x52,0x46,0x41,0x76,0x0A,0x66,0x61,0x76,0x66,0x57,0x75,0x6C, + 0x44,0x31,0x64,0x50,0x36,0x31,0x69,0x35,0x62,0x36,0x59,0x66,0x56,0x6C,0x78, + 0x62,0x31,0x61,0x57,0x46,0x37,0x4C,0x5A,0x44,0x32,0x55,0x6E,0x63,0x41,0x6A, + 0x37,0x4E,0x38,0x78,0x38,0x2B,0x36,0x58,0x6B,0x30,0x6B,0x63,0x70,0x58,0x46, + 0x38,0x6C,0x77,0x58,0x48,0x55,0x57,0x57,0x55,0x6D,0x73,0x2B,0x0A,0x4B,0x56, + 0x44,0x34,0x34,0x39,0x68,0x6F,0x4D,0x2B,0x77,0x4E,0x4A,0x49,0x61,0x4F,0x52, + 0x39,0x4C,0x46,0x2B,0x6B,0x6F,0x32,0x32,0x37,0x7A,0x74,0x37,0x54,0x41,0x47, + 0x64,0x56,0x35,0x4A,0x75,0x7A,0x71,0x38,0x32,0x2F,0x6B,0x75,0x73,0x6F,0x65, + 0x32,0x69,0x75,0x57,0x77,0x54,0x65,0x42,0x6C,0x53,0x5A,0x6E,0x6B,0x42,0x38, + 0x63,0x64,0x0A,0x77,0x4D,0x30,0x5A,0x42,0x58,0x6D,0x34,0x35,0x48,0x38,0x6F, + 0x79,0x75,0x36,0x4A,0x71,0x59,0x71,0x45,0x6D,0x75,0x4A,0x51,0x64,0x67,0x79, + 0x52,0x2B,0x63,0x53,0x53,0x41,0x7A,0x2B,0x4F,0x32,0x6D,0x61,0x62,0x68,0x50, + 0x5A,0x65,0x49,0x76,0x78,0x65,0x67,0x6A,0x6A,0x61,0x5A,0x61,0x46,0x4F,0x71, + 0x74,0x73,0x2B,0x64,0x33,0x72,0x39,0x0A,0x79,0x71,0x4A,0x78,0x67,0x75,0x39, + 0x43,0x38,0x39,0x5A,0x69,0x33,0x39,0x57,0x34,0x38,0x46,0x66,0x46,0x63,0x49, + 0x58,0x4A,0x4F,0x6B,0x39,0x43,0x4E,0x46,0x41,0x2F,0x69,0x70,0x54,0x57,0x6A, + 0x74,0x74,0x4E,0x2F,0x6B,0x4F,0x6B,0x5A,0x42,0x70,0x6F,0x6A,0x2F,0x32,0x6A, + 0x4E,0x45,0x62,0x4F,0x59,0x7A,0x7A,0x6E,0x4B,0x77,0x3D,0x3D,0x0A,0x2D,0x2D, + 0x2D,0x2D,0x2D,0x45,0x4E,0x44,0x20,0x43,0x45,0x52,0x54,0x49,0x46,0x49,0x43, + 0x41,0x54,0x45,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A }; BYTE test_localhost_key[1704] = { - 0x2D,0x2D,0x2D,0x2D,0x2D,0x42,0x45,0x47,0x49,0x4E,0x20,0x50,0x52,0x49,0x56, - 0x41,0x54,0x45,0x20,0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,0x4D,0x49, - 0x49,0x45,0x76,0x51,0x49,0x42,0x41,0x44,0x41,0x4E,0x42,0x67,0x6B,0x71,0x68, - 0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x45,0x46,0x41,0x41,0x53,0x43, - 0x42,0x4B,0x63,0x77,0x67,0x67,0x53,0x6A,0x41,0x67,0x45,0x41,0x41,0x6F,0x49, - 0x42,0x41,0x51,0x43,0x33,0x65,0x6E,0x33,0x68,0x5A,0x4F,0x53,0x33,0x6B,0x51, - 0x2F,0x55,0x0A,0x54,0x30,0x53,0x45,0x6C,0x30,0x48,0x6E,0x50,0x79,0x64,0x48, - 0x75,0x35,0x39,0x61,0x69,0x71,0x64,0x73,0x64,0x53,0x55,0x74,0x6E,0x43,0x41, - 0x37,0x46,0x66,0x74,0x30,0x4F,0x36,0x51,0x79,0x68,0x49,0x71,0x58,0x7A,0x30, - 0x47,0x32,0x53,0x76,0x77,0x4C,0x54,0x62,0x79,0x68,0x59,0x54,0x68,0x31,0x36, - 0x78,0x31,0x72,0x45,0x48,0x68,0x31,0x0A,0x57,0x47,0x5A,0x6D,0x36,0x77,0x64, - 0x2B,0x4B,0x76,0x38,0x6B,0x31,0x6B,0x2F,0x36,0x6F,0x41,0x2F,0x4F,0x51,0x76, - 0x65,0x61,0x38,0x6B,0x63,0x45,0x64,0x53,0x72,0x54,0x64,0x75,0x71,0x4A,0x33, - 0x65,0x66,0x74,0x48,0x4A,0x4A,0x6E,0x43,0x4B,0x30,0x41,0x62,0x68,0x34,0x39, - 0x41,0x47,0x41,0x50,0x39,0x79,0x58,0x77,0x77,0x59,0x41,0x6A,0x0A,0x51,0x49, - 0x52,0x6E,0x38,0x2B,0x4F,0x63,0x63,0x48,0x74,0x6F,0x4E,0x75,0x75,0x79,0x52, - 0x63,0x6B,0x49,0x50,0x71,0x75,0x70,0x78,0x79,0x31,0x4A,0x5A,0x4B,0x39,0x64, - 0x76,0x76,0x62,0x34,0x79,0x53,0x6B,0x49,0x75,0x7A,0x62,0x79,0x50,0x6F,0x54, - 0x41,0x79,0x61,0x55,0x2B,0x51,0x72,0x70,0x34,0x78,0x67,0x64,0x4B,0x46,0x54, - 0x70,0x6B,0x0A,0x50,0x46,0x34,0x33,0x6A,0x32,0x4D,0x6D,0x5A,0x72,0x46,0x63, - 0x42,0x76,0x79,0x6A,0x69,0x35,0x6A,0x4F,0x37,0x74,0x66,0x6F,0x56,0x61,0x6B, - 0x59,0x47,0x53,0x2F,0x4C,0x63,0x78,0x77,0x47,0x2B,0x77,0x51,0x77,0x63,0x4F, - 0x43,0x54,0x42,0x45,0x78,0x2F,0x7A,0x31,0x53,0x30,0x37,0x49,0x2F,0x6A,0x62, - 0x44,0x79,0x53,0x4E,0x68,0x44,0x35,0x0A,0x63,0x61,0x63,0x54,0x75,0x4E,0x36, - 0x50,0x68,0x33,0x58,0x30,0x71,0x70,0x47,0x73,0x37,0x79,0x50,0x6B,0x4E,0x79, - 0x69,0x4A,0x33,0x57,0x52,0x69,0x6C,0x35,0x75,0x57,0x73,0x4B,0x65,0x79,0x63, - 0x64,0x71,0x42,0x4E,0x72,0x34,0x75,0x32,0x62,0x49,0x52,0x6E,0x63,0x54,0x51, - 0x46,0x72,0x68,0x73,0x58,0x39,0x69,0x77,0x37,0x35,0x76,0x75,0x0A,0x53,0x64, - 0x35,0x46,0x39,0x37,0x56,0x70,0x41,0x67,0x4D,0x42,0x41,0x41,0x45,0x43,0x67, - 0x67,0x45,0x41,0x42,0x36,0x6A,0x6C,0x65,0x48,0x4E,0x74,0x32,0x50,0x77,0x46, - 0x58,0x53,0x65,0x79,0x42,0x4A,0x63,0x4C,0x2B,0x55,0x74,0x35,0x71,0x46,0x54, - 0x38,0x34,0x68,0x72,0x48,0x77,0x6F,0x39,0x68,0x62,0x66,0x59,0x47,0x6F,0x6E, - 0x44,0x59,0x0A,0x66,0x70,0x47,0x2B,0x32,0x52,0x30,0x50,0x62,0x43,0x63,0x4B, - 0x35,0x30,0x46,0x61,0x4A,0x46,0x36,0x71,0x63,0x56,0x4A,0x4E,0x75,0x52,0x36, - 0x48,0x71,0x2B,0x43,0x55,0x4A,0x74,0x48,0x35,0x39,0x48,0x48,0x37,0x62,0x68, - 0x6A,0x39,0x62,0x64,0x78,0x45,0x6D,0x6F,0x48,0x30,0x4A,0x76,0x68,0x45,0x76, - 0x67,0x4D,0x2F,0x55,0x38,0x42,0x51,0x0A,0x65,0x57,0x4F,0x4E,0x68,0x78,0x50, - 0x73,0x69,0x73,0x6D,0x57,0x6B,0x78,0x61,0x5A,0x6F,0x6C,0x72,0x32,0x69,0x44, - 0x56,0x72,0x7A,0x54,0x37,0x55,0x4A,0x71,0x6A,0x74,0x59,0x49,0x74,0x67,0x2B, - 0x37,0x59,0x43,0x32,0x70,0x55,0x58,0x6B,0x64,0x49,0x35,0x4A,0x4D,0x67,0x6C, - 0x44,0x47,0x4D,0x52,0x5A,0x35,0x55,0x5A,0x48,0x75,0x63,0x7A,0x0A,0x41,0x56, - 0x2B,0x71,0x77,0x77,0x33,0x65,0x45,0x52,0x74,0x78,0x44,0x50,0x61,0x61,0x61, - 0x34,0x54,0x39,0x50,0x64,0x33,0x44,0x31,0x6D,0x62,0x71,0x58,0x66,0x75,0x45, - 0x68,0x42,0x6D,0x33,0x51,0x6F,0x2B,0x75,0x7A,0x51,0x32,0x36,0x76,0x73,0x66, - 0x48,0x75,0x56,0x76,0x61,0x39,0x38,0x32,0x4F,0x6A,0x41,0x55,0x6A,0x6E,0x64, - 0x30,0x70,0x0A,0x77,0x43,0x53,0x6E,0x42,0x49,0x48,0x67,0x70,0x73,0x30,0x79, - 0x61,0x45,0x50,0x63,0x37,0x46,0x78,0x39,0x71,0x45,0x63,0x6D,0x33,0x70,0x7A, - 0x41,0x56,0x31,0x69,0x72,0x31,0x4E,0x4E,0x63,0x51,0x47,0x55,0x45,0x75,0x45, - 0x6C,0x4A,0x78,0x76,0x2B,0x69,0x57,0x34,0x6D,0x35,0x70,0x7A,0x4C,0x6A,0x64, - 0x53,0x63,0x49,0x30,0x59,0x45,0x73,0x0A,0x4D,0x61,0x33,0x78,0x32,0x79,0x48, - 0x74,0x6E,0x77,0x79,0x65,0x4C,0x4D,0x54,0x4B,0x6C,0x72,0x46,0x4B,0x70,0x55, - 0x4E,0x4A,0x62,0x78,0x73,0x35,0x32,0x62,0x5A,0x4B,0x71,0x49,0x56,0x33,0x33, - 0x4A,0x53,0x34,0x41,0x51,0x4B,0x42,0x67,0x51,0x44,0x73,0x4C,0x54,0x49,0x68, - 0x35,0x59,0x38,0x4C,0x2F,0x48,0x33,0x64,0x74,0x68,0x63,0x62,0x0A,0x53,0x43, - 0x45,0x77,0x32,0x64,0x42,0x49,0x76,0x49,0x79,0x54,0x7A,0x39,0x53,0x72,0x62, - 0x33,0x58,0x37,0x37,0x41,0x77,0x57,0x45,0x4C,0x53,0x4D,0x49,0x57,0x53,0x50, - 0x55,0x43,0x4B,0x54,0x49,0x70,0x6A,0x4D,0x73,0x6E,0x7A,0x6B,0x46,0x67,0x32, - 0x32,0x59,0x32,0x53,0x75,0x47,0x38,0x4C,0x72,0x50,0x6D,0x76,0x73,0x46,0x4A, - 0x34,0x30,0x0A,0x32,0x67,0x35,0x44,0x55,0x6C,0x59,0x33,0x59,0x6D,0x53,0x4F, - 0x46,0x61,0x45,0x4A,0x54,0x70,0x55,0x47,0x44,0x4D,0x79,0x65,0x33,0x74,0x36, - 0x4F,0x30,0x6C,0x63,0x51,0x41,0x66,0x79,0x6D,0x58,0x66,0x41,0x38,0x74,0x50, - 0x42,0x48,0x6A,0x5A,0x78,0x56,0x61,0x38,0x78,0x78,0x52,0x5A,0x6E,0x56,0x43, - 0x31,0x41,0x62,0x75,0x49,0x49,0x52,0x0A,0x6E,0x77,0x72,0x4E,0x46,0x2B,0x42, - 0x6F,0x53,0x4B,0x55,0x41,0x73,0x78,0x2B,0x46,0x75,0x35,0x5A,0x4A,0x4B,0x4F, - 0x66,0x79,0x4D,0x51,0x4B,0x42,0x67,0x51,0x44,0x47,0x34,0x50,0x52,0x39,0x2F, - 0x58,0x58,0x6B,0x51,0x54,0x36,0x6B,0x7A,0x4B,0x64,0x34,0x50,0x6C,0x50,0x4D, - 0x63,0x2B,0x4B,0x51,0x79,0x4C,0x45,0x6C,0x4B,0x39,0x71,0x47,0x0A,0x41,0x6D, - 0x6E,0x2F,0x31,0x68,0x64,0x69,0x57,0x57,0x4F,0x52,0x57,0x46,0x62,0x32,0x38, - 0x30,0x4D,0x77,0x76,0x77,0x41,0x64,0x78,0x72,0x66,0x65,0x4C,0x57,0x4D,0x57, - 0x32,0x66,0x76,0x4C,0x59,0x4B,0x66,0x6C,0x4F,0x35,0x50,0x51,0x44,0x59,0x67, - 0x4B,0x4A,0x78,0x35,0x79,0x50,0x37,0x52,0x64,0x38,0x2F,0x64,0x50,0x79,0x5A, - 0x59,0x36,0x0A,0x7A,0x56,0x37,0x47,0x47,0x6B,0x51,0x5A,0x42,0x4B,0x36,0x79, - 0x74,0x61,0x66,0x32,0x35,0x44,0x50,0x67,0x50,0x72,0x32,0x77,0x73,0x59,0x4D, - 0x43,0x6C,0x53,0x74,0x6C,0x56,0x74,0x72,0x6D,0x4F,0x78,0x59,0x55,0x56,0x77, - 0x42,0x59,0x4F,0x69,0x36,0x45,0x62,0x50,0x69,0x6B,0x78,0x47,0x48,0x5A,0x70, - 0x59,0x6F,0x5A,0x5A,0x70,0x68,0x4A,0x0A,0x4E,0x61,0x38,0x4F,0x4C,0x31,0x69, - 0x77,0x75,0x51,0x4B,0x42,0x67,0x51,0x44,0x42,0x55,0x55,0x31,0x54,0x79,0x5A, - 0x2B,0x4A,0x5A,0x43,0x64,0x79,0x72,0x33,0x58,0x43,0x63,0x77,0x77,0x58,0x2F, - 0x48,0x49,0x73,0x31,0x34,0x6B,0x4B,0x42,0x48,0x68,0x44,0x79,0x33,0x78,0x37, - 0x74,0x50,0x38,0x2F,0x6F,0x48,0x54,0x6F,0x72,0x76,0x79,0x74,0x0A,0x41,0x68, - 0x38,0x4B,0x36,0x4B,0x72,0x43,0x41,0x75,0x65,0x50,0x6D,0x79,0x32,0x6D,0x4F, - 0x54,0x31,0x54,0x39,0x6F,0x31,0x61,0x47,0x55,0x49,0x6C,0x66,0x38,0x72,0x76, - 0x33,0x2F,0x30,0x45,0x78,0x67,0x53,0x6B,0x57,0x50,0x6D,0x4F,0x41,0x38,0x35, - 0x49,0x32,0x2F,0x58,0x48,0x65,0x66,0x71,0x54,0x6F,0x45,0x48,0x30,0x44,0x65, - 0x41,0x4E,0x0A,0x7A,0x6C,0x4B,0x4C,0x71,0x79,0x44,0x56,0x30,0x42,0x56,0x4E, - 0x76,0x48,0x42,0x57,0x79,0x32,0x49,0x51,0x35,0x62,0x50,0x42,0x57,0x76,0x30, - 0x37,0x63,0x34,0x2B,0x6A,0x39,0x4E,0x62,0x57,0x67,0x64,0x44,0x43,0x43,0x35, - 0x52,0x6B,0x4F,0x6A,0x70,0x33,0x4D,0x4E,0x45,0x58,0x47,0x56,0x43,0x69,0x51, - 0x51,0x4B,0x42,0x67,0x43,0x7A,0x4D,0x0A,0x77,0x65,0x61,0x62,0x73,0x50,0x48, - 0x68,0x44,0x4B,0x5A,0x38,0x2F,0x34,0x43,0x6A,0x73,0x61,0x62,0x4E,0x75,0x41, - 0x7A,0x62,0x57,0x4B,0x52,0x42,0x38,0x37,0x44,0x61,0x58,0x46,0x78,0x6F,0x4D, - 0x73,0x35,0x52,0x79,0x6F,0x38,0x55,0x4D,0x6B,0x72,0x67,0x30,0x35,0x4C,0x6F, - 0x67,0x37,0x4D,0x78,0x62,0x33,0x76,0x61,0x42,0x34,0x63,0x2F,0x0A,0x52,0x57, - 0x77,0x7A,0x38,0x72,0x34,0x39,0x70,0x48,0x64,0x71,0x68,0x4F,0x6D,0x63,0x6C, - 0x45,0x77,0x79,0x4D,0x34,0x51,0x79,0x6A,0x39,0x52,0x6D,0x57,0x62,0x51,0x58, - 0x54,0x54,0x45,0x63,0x2B,0x35,0x67,0x54,0x4B,0x50,0x4E,0x53,0x33,0x6D,0x70, - 0x4D,0x54,0x36,0x39,0x46,0x45,0x74,0x2F,0x35,0x72,0x4D,0x52,0x70,0x4B,0x2B, - 0x52,0x68,0x0A,0x49,0x32,0x42,0x58,0x6B,0x51,0x71,0x31,0x36,0x6E,0x72,0x31, - 0x61,0x45,0x4D,0x6D,0x64,0x51,0x42,0x51,0x79,0x4B,0x59,0x4A,0x6C,0x30,0x6C, - 0x50,0x68,0x69,0x42,0x2F,0x75,0x6C,0x5A,0x63,0x72,0x67,0x4C,0x70,0x41,0x6F, - 0x47,0x41,0x65,0x30,0x65,0x74,0x50,0x4A,0x77,0x6D,0x51,0x46,0x6B,0x6A,0x4D, - 0x70,0x66,0x4D,0x44,0x61,0x4E,0x34,0x0A,0x70,0x7A,0x71,0x45,0x51,0x72,0x52, - 0x35,0x4B,0x35,0x4D,0x6E,0x54,0x48,0x76,0x47,0x67,0x2F,0x70,0x6A,0x57,0x6A, - 0x43,0x57,0x58,0x56,0x48,0x67,0x35,0x76,0x36,0x46,0x6F,0x5A,0x48,0x35,0x6E, - 0x59,0x2B,0x56,0x2F,0x57,0x75,0x57,0x38,0x38,0x6A,0x6C,0x4B,0x53,0x50,0x6C, - 0x77,0x6A,0x50,0x7A,0x41,0x67,0x7A,0x47,0x33,0x45,0x41,0x55,0x0A,0x71,0x57, - 0x6B,0x42,0x67,0x30,0x71,0x75,0x50,0x4D,0x72,0x54,0x6B,0x73,0x69,0x6E,0x58, - 0x50,0x2B,0x58,0x6B,0x51,0x65,0x46,0x66,0x58,0x61,0x33,0x38,0x6A,0x72,0x70, - 0x62,0x4B,0x46,0x4F,0x72,0x7A,0x49,0x6F,0x6A,0x69,0x65,0x6C,0x4B,0x55,0x4D, - 0x50,0x4D,0x78,0x2F,0x78,0x70,0x53,0x6A,0x63,0x55,0x42,0x68,0x62,0x4E,0x34, - 0x45,0x54,0x0A,0x4F,0x30,0x66,0x63,0x57,0x47,0x6F,0x61,0x56,0x50,0x72,0x63, - 0x6E,0x38,0x62,0x58,0x4D,0x54,0x45,0x4E,0x53,0x31,0x41,0x3D,0x0A,0x2D,0x2D, - 0x2D,0x2D,0x2D,0x45,0x4E,0x44,0x20,0x50,0x52,0x49,0x56,0x41,0x54,0x45,0x20, - 0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A + 0x2D,0x2D,0x2D,0x2D,0x2D,0x42,0x45,0x47,0x49,0x4E,0x20,0x50,0x52,0x49,0x56, + 0x41,0x54,0x45,0x20,0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,0x4D,0x49, + 0x49,0x45,0x76,0x51,0x49,0x42,0x41,0x44,0x41,0x4E,0x42,0x67,0x6B,0x71,0x68, + 0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,0x51,0x45,0x46,0x41,0x41,0x53,0x43, + 0x42,0x4B,0x63,0x77,0x67,0x67,0x53,0x6A,0x41,0x67,0x45,0x41,0x41,0x6F,0x49, + 0x42,0x41,0x51,0x43,0x33,0x65,0x6E,0x33,0x68,0x5A,0x4F,0x53,0x33,0x6B,0x51, + 0x2F,0x55,0x0A,0x54,0x30,0x53,0x45,0x6C,0x30,0x48,0x6E,0x50,0x79,0x64,0x48, + 0x75,0x35,0x39,0x61,0x69,0x71,0x64,0x73,0x64,0x53,0x55,0x74,0x6E,0x43,0x41, + 0x37,0x46,0x66,0x74,0x30,0x4F,0x36,0x51,0x79,0x68,0x49,0x71,0x58,0x7A,0x30, + 0x47,0x32,0x53,0x76,0x77,0x4C,0x54,0x62,0x79,0x68,0x59,0x54,0x68,0x31,0x36, + 0x78,0x31,0x72,0x45,0x48,0x68,0x31,0x0A,0x57,0x47,0x5A,0x6D,0x36,0x77,0x64, + 0x2B,0x4B,0x76,0x38,0x6B,0x31,0x6B,0x2F,0x36,0x6F,0x41,0x2F,0x4F,0x51,0x76, + 0x65,0x61,0x38,0x6B,0x63,0x45,0x64,0x53,0x72,0x54,0x64,0x75,0x71,0x4A,0x33, + 0x65,0x66,0x74,0x48,0x4A,0x4A,0x6E,0x43,0x4B,0x30,0x41,0x62,0x68,0x34,0x39, + 0x41,0x47,0x41,0x50,0x39,0x79,0x58,0x77,0x77,0x59,0x41,0x6A,0x0A,0x51,0x49, + 0x52,0x6E,0x38,0x2B,0x4F,0x63,0x63,0x48,0x74,0x6F,0x4E,0x75,0x75,0x79,0x52, + 0x63,0x6B,0x49,0x50,0x71,0x75,0x70,0x78,0x79,0x31,0x4A,0x5A,0x4B,0x39,0x64, + 0x76,0x76,0x62,0x34,0x79,0x53,0x6B,0x49,0x75,0x7A,0x62,0x79,0x50,0x6F,0x54, + 0x41,0x79,0x61,0x55,0x2B,0x51,0x72,0x70,0x34,0x78,0x67,0x64,0x4B,0x46,0x54, + 0x70,0x6B,0x0A,0x50,0x46,0x34,0x33,0x6A,0x32,0x4D,0x6D,0x5A,0x72,0x46,0x63, + 0x42,0x76,0x79,0x6A,0x69,0x35,0x6A,0x4F,0x37,0x74,0x66,0x6F,0x56,0x61,0x6B, + 0x59,0x47,0x53,0x2F,0x4C,0x63,0x78,0x77,0x47,0x2B,0x77,0x51,0x77,0x63,0x4F, + 0x43,0x54,0x42,0x45,0x78,0x2F,0x7A,0x31,0x53,0x30,0x37,0x49,0x2F,0x6A,0x62, + 0x44,0x79,0x53,0x4E,0x68,0x44,0x35,0x0A,0x63,0x61,0x63,0x54,0x75,0x4E,0x36, + 0x50,0x68,0x33,0x58,0x30,0x71,0x70,0x47,0x73,0x37,0x79,0x50,0x6B,0x4E,0x79, + 0x69,0x4A,0x33,0x57,0x52,0x69,0x6C,0x35,0x75,0x57,0x73,0x4B,0x65,0x79,0x63, + 0x64,0x71,0x42,0x4E,0x72,0x34,0x75,0x32,0x62,0x49,0x52,0x6E,0x63,0x54,0x51, + 0x46,0x72,0x68,0x73,0x58,0x39,0x69,0x77,0x37,0x35,0x76,0x75,0x0A,0x53,0x64, + 0x35,0x46,0x39,0x37,0x56,0x70,0x41,0x67,0x4D,0x42,0x41,0x41,0x45,0x43,0x67, + 0x67,0x45,0x41,0x42,0x36,0x6A,0x6C,0x65,0x48,0x4E,0x74,0x32,0x50,0x77,0x46, + 0x58,0x53,0x65,0x79,0x42,0x4A,0x63,0x4C,0x2B,0x55,0x74,0x35,0x71,0x46,0x54, + 0x38,0x34,0x68,0x72,0x48,0x77,0x6F,0x39,0x68,0x62,0x66,0x59,0x47,0x6F,0x6E, + 0x44,0x59,0x0A,0x66,0x70,0x47,0x2B,0x32,0x52,0x30,0x50,0x62,0x43,0x63,0x4B, + 0x35,0x30,0x46,0x61,0x4A,0x46,0x36,0x71,0x63,0x56,0x4A,0x4E,0x75,0x52,0x36, + 0x48,0x71,0x2B,0x43,0x55,0x4A,0x74,0x48,0x35,0x39,0x48,0x48,0x37,0x62,0x68, + 0x6A,0x39,0x62,0x64,0x78,0x45,0x6D,0x6F,0x48,0x30,0x4A,0x76,0x68,0x45,0x76, + 0x67,0x4D,0x2F,0x55,0x38,0x42,0x51,0x0A,0x65,0x57,0x4F,0x4E,0x68,0x78,0x50, + 0x73,0x69,0x73,0x6D,0x57,0x6B,0x78,0x61,0x5A,0x6F,0x6C,0x72,0x32,0x69,0x44, + 0x56,0x72,0x7A,0x54,0x37,0x55,0x4A,0x71,0x6A,0x74,0x59,0x49,0x74,0x67,0x2B, + 0x37,0x59,0x43,0x32,0x70,0x55,0x58,0x6B,0x64,0x49,0x35,0x4A,0x4D,0x67,0x6C, + 0x44,0x47,0x4D,0x52,0x5A,0x35,0x55,0x5A,0x48,0x75,0x63,0x7A,0x0A,0x41,0x56, + 0x2B,0x71,0x77,0x77,0x33,0x65,0x45,0x52,0x74,0x78,0x44,0x50,0x61,0x61,0x61, + 0x34,0x54,0x39,0x50,0x64,0x33,0x44,0x31,0x6D,0x62,0x71,0x58,0x66,0x75,0x45, + 0x68,0x42,0x6D,0x33,0x51,0x6F,0x2B,0x75,0x7A,0x51,0x32,0x36,0x76,0x73,0x66, + 0x48,0x75,0x56,0x76,0x61,0x39,0x38,0x32,0x4F,0x6A,0x41,0x55,0x6A,0x6E,0x64, + 0x30,0x70,0x0A,0x77,0x43,0x53,0x6E,0x42,0x49,0x48,0x67,0x70,0x73,0x30,0x79, + 0x61,0x45,0x50,0x63,0x37,0x46,0x78,0x39,0x71,0x45,0x63,0x6D,0x33,0x70,0x7A, + 0x41,0x56,0x31,0x69,0x72,0x31,0x4E,0x4E,0x63,0x51,0x47,0x55,0x45,0x75,0x45, + 0x6C,0x4A,0x78,0x76,0x2B,0x69,0x57,0x34,0x6D,0x35,0x70,0x7A,0x4C,0x6A,0x64, + 0x53,0x63,0x49,0x30,0x59,0x45,0x73,0x0A,0x4D,0x61,0x33,0x78,0x32,0x79,0x48, + 0x74,0x6E,0x77,0x79,0x65,0x4C,0x4D,0x54,0x4B,0x6C,0x72,0x46,0x4B,0x70,0x55, + 0x4E,0x4A,0x62,0x78,0x73,0x35,0x32,0x62,0x5A,0x4B,0x71,0x49,0x56,0x33,0x33, + 0x4A,0x53,0x34,0x41,0x51,0x4B,0x42,0x67,0x51,0x44,0x73,0x4C,0x54,0x49,0x68, + 0x35,0x59,0x38,0x4C,0x2F,0x48,0x33,0x64,0x74,0x68,0x63,0x62,0x0A,0x53,0x43, + 0x45,0x77,0x32,0x64,0x42,0x49,0x76,0x49,0x79,0x54,0x7A,0x39,0x53,0x72,0x62, + 0x33,0x58,0x37,0x37,0x41,0x77,0x57,0x45,0x4C,0x53,0x4D,0x49,0x57,0x53,0x50, + 0x55,0x43,0x4B,0x54,0x49,0x70,0x6A,0x4D,0x73,0x6E,0x7A,0x6B,0x46,0x67,0x32, + 0x32,0x59,0x32,0x53,0x75,0x47,0x38,0x4C,0x72,0x50,0x6D,0x76,0x73,0x46,0x4A, + 0x34,0x30,0x0A,0x32,0x67,0x35,0x44,0x55,0x6C,0x59,0x33,0x59,0x6D,0x53,0x4F, + 0x46,0x61,0x45,0x4A,0x54,0x70,0x55,0x47,0x44,0x4D,0x79,0x65,0x33,0x74,0x36, + 0x4F,0x30,0x6C,0x63,0x51,0x41,0x66,0x79,0x6D,0x58,0x66,0x41,0x38,0x74,0x50, + 0x42,0x48,0x6A,0x5A,0x78,0x56,0x61,0x38,0x78,0x78,0x52,0x5A,0x6E,0x56,0x43, + 0x31,0x41,0x62,0x75,0x49,0x49,0x52,0x0A,0x6E,0x77,0x72,0x4E,0x46,0x2B,0x42, + 0x6F,0x53,0x4B,0x55,0x41,0x73,0x78,0x2B,0x46,0x75,0x35,0x5A,0x4A,0x4B,0x4F, + 0x66,0x79,0x4D,0x51,0x4B,0x42,0x67,0x51,0x44,0x47,0x34,0x50,0x52,0x39,0x2F, + 0x58,0x58,0x6B,0x51,0x54,0x36,0x6B,0x7A,0x4B,0x64,0x34,0x50,0x6C,0x50,0x4D, + 0x63,0x2B,0x4B,0x51,0x79,0x4C,0x45,0x6C,0x4B,0x39,0x71,0x47,0x0A,0x41,0x6D, + 0x6E,0x2F,0x31,0x68,0x64,0x69,0x57,0x57,0x4F,0x52,0x57,0x46,0x62,0x32,0x38, + 0x30,0x4D,0x77,0x76,0x77,0x41,0x64,0x78,0x72,0x66,0x65,0x4C,0x57,0x4D,0x57, + 0x32,0x66,0x76,0x4C,0x59,0x4B,0x66,0x6C,0x4F,0x35,0x50,0x51,0x44,0x59,0x67, + 0x4B,0x4A,0x78,0x35,0x79,0x50,0x37,0x52,0x64,0x38,0x2F,0x64,0x50,0x79,0x5A, + 0x59,0x36,0x0A,0x7A,0x56,0x37,0x47,0x47,0x6B,0x51,0x5A,0x42,0x4B,0x36,0x79, + 0x74,0x61,0x66,0x32,0x35,0x44,0x50,0x67,0x50,0x72,0x32,0x77,0x73,0x59,0x4D, + 0x43,0x6C,0x53,0x74,0x6C,0x56,0x74,0x72,0x6D,0x4F,0x78,0x59,0x55,0x56,0x77, + 0x42,0x59,0x4F,0x69,0x36,0x45,0x62,0x50,0x69,0x6B,0x78,0x47,0x48,0x5A,0x70, + 0x59,0x6F,0x5A,0x5A,0x70,0x68,0x4A,0x0A,0x4E,0x61,0x38,0x4F,0x4C,0x31,0x69, + 0x77,0x75,0x51,0x4B,0x42,0x67,0x51,0x44,0x42,0x55,0x55,0x31,0x54,0x79,0x5A, + 0x2B,0x4A,0x5A,0x43,0x64,0x79,0x72,0x33,0x58,0x43,0x63,0x77,0x77,0x58,0x2F, + 0x48,0x49,0x73,0x31,0x34,0x6B,0x4B,0x42,0x48,0x68,0x44,0x79,0x33,0x78,0x37, + 0x74,0x50,0x38,0x2F,0x6F,0x48,0x54,0x6F,0x72,0x76,0x79,0x74,0x0A,0x41,0x68, + 0x38,0x4B,0x36,0x4B,0x72,0x43,0x41,0x75,0x65,0x50,0x6D,0x79,0x32,0x6D,0x4F, + 0x54,0x31,0x54,0x39,0x6F,0x31,0x61,0x47,0x55,0x49,0x6C,0x66,0x38,0x72,0x76, + 0x33,0x2F,0x30,0x45,0x78,0x67,0x53,0x6B,0x57,0x50,0x6D,0x4F,0x41,0x38,0x35, + 0x49,0x32,0x2F,0x58,0x48,0x65,0x66,0x71,0x54,0x6F,0x45,0x48,0x30,0x44,0x65, + 0x41,0x4E,0x0A,0x7A,0x6C,0x4B,0x4C,0x71,0x79,0x44,0x56,0x30,0x42,0x56,0x4E, + 0x76,0x48,0x42,0x57,0x79,0x32,0x49,0x51,0x35,0x62,0x50,0x42,0x57,0x76,0x30, + 0x37,0x63,0x34,0x2B,0x6A,0x39,0x4E,0x62,0x57,0x67,0x64,0x44,0x43,0x43,0x35, + 0x52,0x6B,0x4F,0x6A,0x70,0x33,0x4D,0x4E,0x45,0x58,0x47,0x56,0x43,0x69,0x51, + 0x51,0x4B,0x42,0x67,0x43,0x7A,0x4D,0x0A,0x77,0x65,0x61,0x62,0x73,0x50,0x48, + 0x68,0x44,0x4B,0x5A,0x38,0x2F,0x34,0x43,0x6A,0x73,0x61,0x62,0x4E,0x75,0x41, + 0x7A,0x62,0x57,0x4B,0x52,0x42,0x38,0x37,0x44,0x61,0x58,0x46,0x78,0x6F,0x4D, + 0x73,0x35,0x52,0x79,0x6F,0x38,0x55,0x4D,0x6B,0x72,0x67,0x30,0x35,0x4C,0x6F, + 0x67,0x37,0x4D,0x78,0x62,0x33,0x76,0x61,0x42,0x34,0x63,0x2F,0x0A,0x52,0x57, + 0x77,0x7A,0x38,0x72,0x34,0x39,0x70,0x48,0x64,0x71,0x68,0x4F,0x6D,0x63,0x6C, + 0x45,0x77,0x79,0x4D,0x34,0x51,0x79,0x6A,0x39,0x52,0x6D,0x57,0x62,0x51,0x58, + 0x54,0x54,0x45,0x63,0x2B,0x35,0x67,0x54,0x4B,0x50,0x4E,0x53,0x33,0x6D,0x70, + 0x4D,0x54,0x36,0x39,0x46,0x45,0x74,0x2F,0x35,0x72,0x4D,0x52,0x70,0x4B,0x2B, + 0x52,0x68,0x0A,0x49,0x32,0x42,0x58,0x6B,0x51,0x71,0x31,0x36,0x6E,0x72,0x31, + 0x61,0x45,0x4D,0x6D,0x64,0x51,0x42,0x51,0x79,0x4B,0x59,0x4A,0x6C,0x30,0x6C, + 0x50,0x68,0x69,0x42,0x2F,0x75,0x6C,0x5A,0x63,0x72,0x67,0x4C,0x70,0x41,0x6F, + 0x47,0x41,0x65,0x30,0x65,0x74,0x50,0x4A,0x77,0x6D,0x51,0x46,0x6B,0x6A,0x4D, + 0x70,0x66,0x4D,0x44,0x61,0x4E,0x34,0x0A,0x70,0x7A,0x71,0x45,0x51,0x72,0x52, + 0x35,0x4B,0x35,0x4D,0x6E,0x54,0x48,0x76,0x47,0x67,0x2F,0x70,0x6A,0x57,0x6A, + 0x43,0x57,0x58,0x56,0x48,0x67,0x35,0x76,0x36,0x46,0x6F,0x5A,0x48,0x35,0x6E, + 0x59,0x2B,0x56,0x2F,0x57,0x75,0x57,0x38,0x38,0x6A,0x6C,0x4B,0x53,0x50,0x6C, + 0x77,0x6A,0x50,0x7A,0x41,0x67,0x7A,0x47,0x33,0x45,0x41,0x55,0x0A,0x71,0x57, + 0x6B,0x42,0x67,0x30,0x71,0x75,0x50,0x4D,0x72,0x54,0x6B,0x73,0x69,0x6E,0x58, + 0x50,0x2B,0x58,0x6B,0x51,0x65,0x46,0x66,0x58,0x61,0x33,0x38,0x6A,0x72,0x70, + 0x62,0x4B,0x46,0x4F,0x72,0x7A,0x49,0x6F,0x6A,0x69,0x65,0x6C,0x4B,0x55,0x4D, + 0x50,0x4D,0x78,0x2F,0x78,0x70,0x53,0x6A,0x63,0x55,0x42,0x68,0x62,0x4E,0x34, + 0x45,0x54,0x0A,0x4F,0x30,0x66,0x63,0x57,0x47,0x6F,0x61,0x56,0x50,0x72,0x63, + 0x6E,0x38,0x62,0x58,0x4D,0x54,0x45,0x4E,0x53,0x31,0x41,0x3D,0x0A,0x2D,0x2D, + 0x2D,0x2D,0x2D,0x45,0x4E,0x44,0x20,0x50,0x52,0x49,0x56,0x41,0x54,0x45,0x20, + 0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A }; BYTE test_DummyMessage[64] = @@ -236,54 +237,42 @@ int schannel_send(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont SECURITY_STATUS status; DWORD NumberOfBytesWritten; SecPkgContext_StreamSizes StreamSizes; - ZeroMemory(&StreamSizes, sizeof(SecPkgContext_StreamSizes)); status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes); - ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer; ioBuffer = (BYTE*) malloc(ioBufferLength); ZeroMemory(ioBuffer, ioBufferLength); - pMessageBuffer = ioBuffer + StreamSizes.cbHeader; CopyMemory(pMessageBuffer, buffer, length); - Buffers[0].pvBuffer = ioBuffer; Buffers[0].cbBuffer = StreamSizes.cbHeader; Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; - Buffers[1].pvBuffer = pMessageBuffer; Buffers[1].cbBuffer = length; Buffers[1].BufferType = SECBUFFER_DATA; - Buffers[2].pvBuffer = pMessageBuffer + length; Buffers[2].cbBuffer = StreamSizes.cbTrailer; Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; - Buffers[3].pvBuffer = NULL; Buffers[3].cbBuffer = 0; Buffers[3].BufferType = SECBUFFER_EMPTY; - Message.ulVersion = SECBUFFER_VERSION; Message.cBuffers = 4; Message.pBuffers = Buffers; - ioBufferLength = Message.pBuffers[0].cbBuffer + Message.pBuffers[1].cbBuffer + Message.pBuffers[2].cbBuffer; - status = table->EncryptMessage(phContext, 0, &Message, 0); - printf("EncryptMessage status: 0x%08X\n", status); - printf("EncryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers, - Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType, - Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType, - Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType, - Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType); + Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType, + Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType, + Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType, + Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType); if (status != SEC_E_OK) return -1; printf("Client > Server (%d)\n", ioBufferLength); - winpr_HexDump(ioBuffer, ioBufferLength); + winpr_HexDump("sspi.test", WLOG_DEBUG, ioBuffer, ioBufferLength); if (!WriteFile(hPipe, ioBuffer, ioBufferLength, &NumberOfBytesWritten, NULL)) { @@ -304,10 +293,8 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont SECURITY_STATUS status; DWORD NumberOfBytesRead; SecPkgContext_StreamSizes StreamSizes; - ZeroMemory(&StreamSizes, sizeof(SecPkgContext_StreamSizes)); status = table->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &StreamSizes); - ioBufferLength = StreamSizes.cbHeader + StreamSizes.cbMaximumMessage + StreamSizes.cbTrailer; ioBuffer = (BYTE*) malloc(ioBufferLength); ZeroMemory(ioBuffer, ioBufferLength); @@ -321,38 +308,31 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont Buffers[0].pvBuffer = ioBuffer; Buffers[0].cbBuffer = NumberOfBytesRead; Buffers[0].BufferType = SECBUFFER_DATA; - Buffers[1].pvBuffer = NULL; Buffers[1].cbBuffer = 0; Buffers[1].BufferType = SECBUFFER_EMPTY; - Buffers[2].pvBuffer = NULL; Buffers[2].cbBuffer = 0; Buffers[2].BufferType = SECBUFFER_EMPTY; - Buffers[3].pvBuffer = NULL; Buffers[3].cbBuffer = 0; Buffers[3].BufferType = SECBUFFER_EMPTY; - Message.ulVersion = SECBUFFER_VERSION; Message.cBuffers = 4; Message.pBuffers = Buffers; - status = table->DecryptMessage(phContext, &Message, 0, NULL); - printf("DecryptMessage status: 0x%08X\n", status); - printf("DecryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers, - Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType, - Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType, - Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType, - Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType); + Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType, + Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType, + Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType, + Message.pBuffers[3].cbBuffer, Message.pBuffers[3].BufferType); if (status != SEC_E_OK) return -1; printf("Decrypted Message (%d)\n", Message.pBuffers[1].cbBuffer); - winpr_HexDump((BYTE*) Message.pBuffers[1].pvBuffer, Message.pBuffers[1].cbBuffer); + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) Message.pBuffers[1].pvBuffer, Message.pBuffers[1].cbBuffer); if (memcmp(Message.pBuffers[1].pvBuffer, test_LastDummyMessage, sizeof(test_LastDummyMessage)) == 0) return -1; @@ -386,14 +366,10 @@ static void* schannel_test_server_thread(void* arg) PSecPkgInfo pPackageInfo; PSecurityFunctionTable table; DWORD NumberOfBytesWritten; - printf("Starting Server\n"); - SecInvalidateHandle(&context); SecInvalidateHandle(&credentials); - table = InitSecurityInterface(); - status = QuerySecurityPackageInfo(SCHANNEL_NAME, &pPackageInfo); if (status != SEC_E_OK) @@ -403,7 +379,6 @@ static void* schannel_test_server_thread(void* arg) } cbMaxToken = pPackageInfo->cbMaxToken; - hCertStore = CertOpenSystemStore(0, _T("MY")); if (!hCertStore) @@ -425,27 +400,19 @@ static void* schannel_test_server_thread(void* arg) } cchNameString = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0); - pszNameString = (LPTSTR) malloc(cchNameString * sizeof(TCHAR)); cchNameString = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, cchNameString); - _tprintf(_T("Certificate Name: %s\n"), pszNameString); - ZeroMemory(&cred, sizeof(SCHANNEL_CRED)); cred.dwVersion = SCHANNEL_CRED_VERSION; - cred.cCreds = 1; cred.paCred = &pCertContext; - cred.cSupportedAlgs = 0; cred.palgSupportedAlgs = NULL; - cred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; - cred.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER; - status = table->AcquireCredentialsHandle(NULL, SCHANNEL_NAME, - SECPKG_CRED_INBOUND, NULL, &cred, NULL, NULL, &credentials, NULL); + SECPKG_CRED_INBOUND, NULL, &cred, NULL, NULL, &credentials, NULL); if (status != SEC_E_OK) { @@ -455,13 +422,11 @@ static void* schannel_test_server_thread(void* arg) extraData = FALSE; g_ServerWait = TRUE; - lpTokenIn = (BYTE*) malloc(cbMaxToken); lpTokenOut = (BYTE*) malloc(cbMaxToken); - fContextReq = ASC_REQ_STREAM | - ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | - ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR; + ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | + ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR; do { @@ -483,29 +448,23 @@ static void* schannel_test_server_thread(void* arg) extraData = FALSE; g_ServerWait = TRUE; - SecBuffer_in[0].BufferType = SECBUFFER_TOKEN; SecBuffer_in[0].pvBuffer = lpTokenIn; SecBuffer_in[0].cbBuffer = NumberOfBytesRead; - SecBuffer_in[1].BufferType = SECBUFFER_EMPTY; SecBuffer_in[1].pvBuffer = NULL; SecBuffer_in[1].cbBuffer = 0; - SecBufferDesc_in.ulVersion = SECBUFFER_VERSION; SecBufferDesc_in.cBuffers = 2; SecBufferDesc_in.pBuffers = SecBuffer_in; - SecBuffer_out[0].BufferType = SECBUFFER_TOKEN; SecBuffer_out[0].pvBuffer = lpTokenOut; SecBuffer_out[0].cbBuffer = cbMaxToken; - SecBufferDesc_out.ulVersion = SECBUFFER_VERSION; SecBufferDesc_out.cBuffers = 1; SecBufferDesc_out.pBuffers = SecBuffer_out; - status = table->AcceptSecurityContext(&credentials, SecIsValidHandle(&context) ? &context : NULL, - &SecBufferDesc_in, fContextReq, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry); + &SecBufferDesc_in, fContextReq, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry); if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE)) { @@ -523,10 +482,10 @@ static void* schannel_test_server_thread(void* arg) printf("AcceptSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n"); printf("Server cBuffers: %u pBuffers[0]: %u type: %u\n", - SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType); + SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType); printf("Server Input cBuffers: %d pBuffers[0]: %u type: %u pBuffers[1]: %u type: %u\n", SecBufferDesc_in.cBuffers, - SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType, - SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType); + SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType, + SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType); if (SecBufferDesc_in.pBuffers[1].BufferType == SECBUFFER_EXTRA) { @@ -544,7 +503,7 @@ static void* schannel_test_server_thread(void* arg) if (pSecBuffer->cbBuffer > 0) { printf("Server > Client (%d)\n", pSecBuffer->cbBuffer); - winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL)) { @@ -567,7 +526,7 @@ static void* schannel_test_server_thread(void* arg) if (schannel_recv(table, g_ServerReadPipe, &context) < 0) break; } - while(1); + while (1); return NULL; } @@ -576,13 +535,10 @@ int dump_test_certificate_files() { FILE* fp; char* fullpath; - /* * Output Certificate File */ - fullpath = GetCombinedPath("/tmp", "localhost.crt"); - fp = fopen(fullpath, "w+"); if (fp) @@ -592,13 +548,10 @@ int dump_test_certificate_files() } free(fullpath); - /* * Output Private Key File */ - fullpath = GetCombinedPath("/tmp", "localhost.key"); - fp = fopen(fullpath, "w+"); if (fp) @@ -608,7 +561,6 @@ int dump_test_certificate_files() } free(fullpath); - return 1; } @@ -640,13 +592,9 @@ int TestSchannel(int argc, char* argv[]) SecPkgCred_SupportedAlgs SupportedAlgs; SecPkgCred_CipherStrengths CipherStrengths; SecPkgCred_SupportedProtocols SupportedProtocols; - return 0; /* disable by default - causes crash */ - sspi_GlobalInit(); - dump_test_certificate_files(); - SecInvalidateHandle(&context); SecInvalidateHandle(&credentials); @@ -663,9 +611,7 @@ int TestSchannel(int argc, char* argv[]) } thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) schannel_test_server_thread, NULL, 0, NULL); - table = InitSecurityInterface(); - status = QuerySecurityPackageInfo(SCHANNEL_NAME, &pPackageInfo); if (status != SEC_E_OK) @@ -675,24 +621,18 @@ int TestSchannel(int argc, char* argv[]) } cbMaxToken = pPackageInfo->cbMaxToken; - ZeroMemory(&cred, sizeof(SCHANNEL_CRED)); cred.dwVersion = SCHANNEL_CRED_VERSION; - cred.cCreds = 0; cred.paCred = NULL; - cred.cSupportedAlgs = 0; cred.palgSupportedAlgs = NULL; - cred.grbitEnabledProtocols = SP_PROT_SSL3TLS1_CLIENTS; - cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS; cred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION; cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; - status = table->AcquireCredentialsHandle(NULL, SCHANNEL_NAME, - SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &credentials, NULL); + SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &credentials, NULL); if (status != SEC_E_OK) { @@ -714,17 +654,16 @@ int TestSchannel(int argc, char* argv[]) * 0x660E 0x6610 0x6801 0x6603 0x6601 0x8003 0x8004 * 0x800C 0x800D 0x800E 0x2400 0xAA02 0xAE06 0x2200 0x2203 */ - printf("SupportedAlgs: %d\n", SupportedAlgs.cSupportedAlgs); for (index = 0; index < SupportedAlgs.cSupportedAlgs; index++) { algId = SupportedAlgs.palgSupportedAlgs[index]; printf("\t0x%04X CLASS: %d TYPE: %d SID: %d\n", algId, - ((GET_ALG_CLASS(algId)) >> 13), ((GET_ALG_TYPE(algId)) >> 9), GET_ALG_SID(algId)); + ((GET_ALG_CLASS(algId)) >> 13), ((GET_ALG_TYPE(algId)) >> 9), GET_ALG_SID(algId)); } - printf("\n"); + printf("\n"); ZeroMemory(&CipherStrengths, sizeof(SecPkgCred_CipherStrengths)); status = table->QueryCredentialsAttributes(&credentials, SECPKG_ATTR_CIPHER_STRENGTHS, &CipherStrengths); @@ -735,10 +674,8 @@ int TestSchannel(int argc, char* argv[]) } /* CipherStrengths: Minimum: 40 Maximum: 256 */ - printf("CipherStrengths: Minimum: %d Maximum: %d\n", - CipherStrengths.dwMinimumCipherStrength, CipherStrengths.dwMaximumCipherStrength); - + CipherStrengths.dwMinimumCipherStrength, CipherStrengths.dwMaximumCipherStrength); ZeroMemory(&SupportedProtocols, sizeof(SecPkgCred_SupportedProtocols)); status = table->QueryCredentialsAttributes(&credentials, SECPKG_ATTR_SUPPORTED_PROTOCOLS, &SupportedProtocols); @@ -749,22 +686,17 @@ int TestSchannel(int argc, char* argv[]) } /* SupportedProtocols: 0x208A0 */ - printf("SupportedProtocols: 0x%04X\n", SupportedProtocols.grbitProtocol); - fContextReq = ISC_REQ_STREAM | - ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | - ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY; - + ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | + ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY; lpTokenIn = (BYTE*) malloc(cbMaxToken); lpTokenOut = (BYTE*) malloc(cbMaxToken); - ZeroMemory(&SecBuffer_in, sizeof(SecBuffer_in)); ZeroMemory(&SecBuffer_out, sizeof(SecBuffer_out)); ZeroMemory(&SecBufferDesc_in, sizeof(SecBufferDesc)); ZeroMemory(&SecBufferDesc_out, sizeof(SecBufferDesc)); - g_ClientWait = FALSE; do @@ -784,29 +716,23 @@ int TestSchannel(int argc, char* argv[]) g_ClientWait = TRUE; printf("NumberOfBytesRead: %d\n", NumberOfBytesRead); - SecBuffer_in[0].BufferType = SECBUFFER_TOKEN; SecBuffer_in[0].pvBuffer = lpTokenIn; SecBuffer_in[0].cbBuffer = NumberOfBytesRead; - SecBuffer_in[1].pvBuffer = NULL; SecBuffer_in[1].cbBuffer = 0; SecBuffer_in[1].BufferType = SECBUFFER_EMPTY; - SecBufferDesc_in.ulVersion = SECBUFFER_VERSION; SecBufferDesc_in.cBuffers = 2; SecBufferDesc_in.pBuffers = SecBuffer_in; - SecBuffer_out[0].BufferType = SECBUFFER_TOKEN; SecBuffer_out[0].pvBuffer = lpTokenOut; SecBuffer_out[0].cbBuffer = cbMaxToken; - SecBufferDesc_out.ulVersion = SECBUFFER_VERSION; SecBufferDesc_out.cBuffers = 1; SecBufferDesc_out.pBuffers = SecBuffer_out; - status = table->InitializeSecurityContext(&credentials, SecIsValidHandle(&context) ? &context : NULL, _T("localhost"), - fContextReq, 0, 0, &SecBufferDesc_in, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry); + fContextReq, 0, 0, &SecBufferDesc_in, 0, &context, &SecBufferDesc_out, &fContextAttr, &expiry); if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED) && (status != SEC_E_INCOMPLETE_MESSAGE)) { @@ -824,10 +750,10 @@ int TestSchannel(int argc, char* argv[]) printf("InitializeSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n"); printf("Client Output cBuffers: %d pBuffers[0]: %d type: %d\n", - SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType); + SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType); printf("Client Input cBuffers: %d pBuffers[0]: %d type: %d pBuffers[1]: %d type: %d\n", SecBufferDesc_in.cBuffers, - SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType, - SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType); + SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType, + SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType); if (status != SEC_E_INCOMPLETE_MESSAGE) { @@ -836,7 +762,7 @@ int TestSchannel(int argc, char* argv[]) if (pSecBuffer->cbBuffer > 0) { printf("Client > Server (%d)\n", pSecBuffer->cbBuffer); - winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); + winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer); if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL)) { @@ -852,7 +778,7 @@ int TestSchannel(int argc, char* argv[]) break; } } - while(1); + while (1); count = 0; @@ -864,30 +790,22 @@ int TestSchannel(int argc, char* argv[]) for (index = 0; index < sizeof(test_DummyMessage); index++) { BYTE b, ln, hn; - b = test_DummyMessage[index]; - ln = (b & 0x0F); hn = ((b & 0xF0) >> 4); - ln = (ln + 1) % 0xF; hn = (ln + 1) % 0xF; - b = (ln | (hn << 4)); - test_DummyMessage[index] = b; } Sleep(100); count++; } - while(count < 3); + while (count < 3); schannel_send(table, g_ServerWritePipe, &context, test_LastDummyMessage, sizeof(test_LastDummyMessage)); - WaitForSingleObject(thread, INFINITE); - sspi_GlobalFinish(); - return 0; } diff --git a/winpr/libwinpr/sspicli/CMakeLists.txt b/winpr/libwinpr/sspicli/CMakeLists.txt index 651978b11..f50585e3d 100644 --- a/winpr/libwinpr/sspicli/CMakeLists.txt +++ b/winpr/libwinpr/sspicli/CMakeLists.txt @@ -15,23 +15,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-sspicli") -set(MODULE_PREFIX "WINPR_SSPICLI") - -set(${MODULE_PREFIX}_SRCS - sspicli.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(sspicli.c) diff --git a/winpr/libwinpr/synch/CMakeLists.txt b/winpr/libwinpr/synch/CMakeLists.txt index 66ce56a53..4de39733c 100644 --- a/winpr/libwinpr/synch/CMakeLists.txt +++ b/winpr/libwinpr/synch/CMakeLists.txt @@ -15,16 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-synch") -set(MODULE_PREFIX "WINPR_SYNCH") - -if(HAVE_PTHREAD_GNU_EXT) - add_definitions(-D_GNU_SOURCE) -endif(HAVE_PTHREAD_GNU_EXT) - -include_directories(../thread) - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( address.c barrier.c condition.c @@ -39,35 +30,10 @@ set(${MODULE_PREFIX}_SRCS timer.c wait.c) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS}) - if((NOT WIN32) AND (NOT APPLE) AND (NOT ANDROID)) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-handle winpr-error winpr-interlocked winpr-thread winpr-sysinfo) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/synch/barrier.c b/winpr/libwinpr/synch/barrier.c index 95fef076c..f8d75cb5d 100644 --- a/winpr/libwinpr/synch/barrier.c +++ b/winpr/libwinpr/synch/barrier.c @@ -23,26 +23,154 @@ #include -/** - * InitializeSynchronizationBarrier - * EnterSynchronizationBarrier - * DeleteSynchronizationBarrier - */ +#include "synch.h" -#ifndef _WIN32 +#include -BOOL InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount) +#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) + +#include +#include + +#ifdef _WIN32 + +static HMODULE g_Kernel32 = NULL; +static BOOL g_NativeBarrier = FALSE; +static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT; + +typedef BOOL (WINAPI * fnInitializeSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); +typedef BOOL (WINAPI * fnEnterSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); +typedef BOOL (WINAPI * fnDeleteSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier); + +static fnInitializeSynchronizationBarrier pfnInitializeSynchronizationBarrier = NULL; +static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier = NULL; +static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier = NULL; + +static BOOL CALLBACK InitOnce_Barrier(PINIT_ONCE once, PVOID param, PVOID *context) { - return TRUE; -} + g_Kernel32 = LoadLibraryA("kernel32.dll"); -BOOL EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags) -{ - return TRUE; -} + if (!g_Kernel32) + return TRUE; + + pfnInitializeSynchronizationBarrier = (fnInitializeSynchronizationBarrier) + GetProcAddress(g_Kernel32, "InitializeSynchronizationBarrier"); + + pfnEnterSynchronizationBarrier = (fnEnterSynchronizationBarrier) + GetProcAddress(g_Kernel32, "EnterSynchronizationBarrier"); + + pfnDeleteSynchronizationBarrier = (fnDeleteSynchronizationBarrier) + GetProcAddress(g_Kernel32, "DeleteSynchronizationBarrier"); + + if (pfnInitializeSynchronizationBarrier && pfnEnterSynchronizationBarrier + && pfnDeleteSynchronizationBarrier) + { + g_NativeBarrier = TRUE; + } + + return TRUE; +} + +#endif + +BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount) +{ + WINPR_BARRIER* pBarrier; + +#ifdef _WIN32 + InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier, NULL, NULL); + + if (g_NativeBarrier) + return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount); +#endif + + if (!lpBarrier) + return FALSE; + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); + + pBarrier = (WINPR_BARRIER*) calloc(1, sizeof(WINPR_BARRIER)); + + if (!pBarrier) + return FALSE; + + if (lSpinCount < 0) + lSpinCount = 2000; + + pBarrier->lTotalThreads = lTotalThreads; + pBarrier->lSpinCount = lSpinCount; + pBarrier->count = 0; + + pBarrier->event = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (!pBarrier->event) + { + free(pBarrier); + return FALSE; + } + + lpBarrier->Reserved3[0] = (ULONG_PTR) pBarrier; + + return TRUE; +} + +BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags) +{ + LONG count; + BOOL status = FALSE; + WINPR_BARRIER* pBarrier; + +#ifdef _WIN32 + if (g_NativeBarrier) + return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags); +#endif + + if (!lpBarrier) + return FALSE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return FALSE; + + count = InterlockedIncrement(&(pBarrier->count)); + + if (count < pBarrier->lTotalThreads) + { + WaitForSingleObject(pBarrier->event, INFINITE); + } + else + { + SetEvent(pBarrier->event); + status = TRUE; + } + + return status; +} + +BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier) +{ + WINPR_BARRIER* pBarrier; + +#ifdef _WIN32 + if (g_NativeBarrier) + return pfnDeleteSynchronizationBarrier(lpBarrier); +#endif + + if (!lpBarrier) + return TRUE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return TRUE; + + CloseHandle(pBarrier->event); + + free(pBarrier); + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); -BOOL DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier) -{ return TRUE; } diff --git a/winpr/libwinpr/synch/critical.c b/winpr/libwinpr/synch/critical.c index bfe43292d..eb09d03ef 100644 --- a/winpr/libwinpr/synch/critical.c +++ b/winpr/libwinpr/synch/critical.c @@ -36,6 +36,9 @@ #ifndef _WIN32 +#include "../log.h" +#define TAG WINPR_TAG("synch.critical") + VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { InitializeCriticalSectionEx(lpCriticalSection, 0, 0); @@ -53,9 +56,9 @@ BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwS * - The RecursionCount field indicates the number of times that the owning * thread has called EnterCriticalSection for this critical section. */ - - if (Flags != 0) { - fprintf(stderr, "warning: InitializeCriticalSectionEx Flags unimplemented\n"); + if (Flags != 0) + { + WLog_WARN(TAG, "Flags unimplemented"); } lpCriticalSection->DebugInfo = NULL; @@ -63,16 +66,13 @@ BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwS lpCriticalSection->SpinCount = 0; lpCriticalSection->RecursionCount = 0; lpCriticalSection->OwningThread = NULL; - lpCriticalSection->LockSemaphore = (winpr_sem_t*) malloc(sizeof(winpr_sem_t)); #if defined(__APPLE__) semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 0); #else sem_init(lpCriticalSection->LockSemaphore, 0, 0); #endif - SetCriticalSectionSpinCount(lpCriticalSection, dwSpinCount); - return TRUE; } @@ -91,9 +91,11 @@ DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dw { /* Don't spin on uniprocessor systems! */ GetNativeSystemInfo(&sysinfo); + if (sysinfo.dwNumberOfProcessors < 2) dwSpinCount = 0; } + lpCriticalSection->SpinCount = dwSpinCount; return dwPreviousSpinCount; #else @@ -101,7 +103,7 @@ DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dw #endif } -VOID _WaitForCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +static VOID _WaitForCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { #if defined(__APPLE__) semaphore_wait(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); @@ -110,7 +112,7 @@ VOID _WaitForCriticalSection(LPCRITICAL_SECTION lpCriticalSection) #endif } -VOID _UnWaitCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +static VOID _UnWaitCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { #if defined __APPLE__ semaphore_signal(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); @@ -135,9 +137,10 @@ VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1) { lpCriticalSection->RecursionCount = 1; - lpCriticalSection->OwningThread = (HANDLE) (ULONG_PTR) GetCurrentThreadId(); + lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR) GetCurrentThreadId(); return; } + /* Failed to get the lock. Let the scheduler know that we're spinning. */ if (sched_yield()!=0) { @@ -156,7 +159,7 @@ VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) if (InterlockedIncrement(&lpCriticalSection->LockCount)) { /* Section is already locked. Check if it is owned by the current thread. */ - if (lpCriticalSection->OwningThread == (HANDLE) (ULONG_PTR) GetCurrentThreadId()) + if (lpCriticalSection->OwningThread == (HANDLE)(ULONG_PTR) GetCurrentThreadId()) { /* Recursion. No need to wait. */ lpCriticalSection->RecursionCount++; @@ -166,17 +169,18 @@ VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) /* Section is locked by another thread. We have to wait. */ _WaitForCriticalSection(lpCriticalSection); } + /* We got the lock. Own it ... */ lpCriticalSection->RecursionCount = 1; - lpCriticalSection->OwningThread = (HANDLE) (ULONG_PTR) GetCurrentThreadId(); + lpCriticalSection->OwningThread = (HANDLE)(ULONG_PTR) GetCurrentThreadId(); } BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { - HANDLE current_thread = (HANDLE) (ULONG_PTR) GetCurrentThreadId(); + HANDLE current_thread = (HANDLE)(ULONG_PTR) GetCurrentThreadId(); /* Atomically acquire the the lock if the section is free. */ - if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1 ) == -1) + if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1) { lpCriticalSection->RecursionCount = 1; lpCriticalSection->OwningThread = current_thread; @@ -202,6 +206,7 @@ VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { /* Last recursion, clear owner, unlock and if there are other waiting threads ... */ lpCriticalSection->OwningThread = NULL; + if (InterlockedDecrement(&lpCriticalSection->LockCount) >= 0) { /* ...signal the semaphore to unblock the next waiting thread */ @@ -235,9 +240,9 @@ VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) #endif -#if ((_WIN32) && (_WIN32_WINNT < 0x0403)) +#if (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) -typedef BOOL (WINAPI * PINITIALIZE_CRITICAL_SECTION_EX_FN)(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags); +typedef BOOL (WINAPI* PINITIALIZE_CRITICAL_SECTION_EX_FN)(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags); static HMODULE g_KERNEL32_Library = NULL; static BOOL g_InitializeCriticalSectionEx_Detected = FALSE; @@ -253,8 +258,7 @@ BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwS if (g_KERNEL32_Library) { g_pInitializeCriticalSectionEx = (PINITIALIZE_CRITICAL_SECTION_EX_FN) - GetProcAddress(g_KERNEL32_Library, "InitializeCriticalSectionEx"); - + GetProcAddress(g_KERNEL32_Library, "InitializeCriticalSectionEx"); g_InitializeCriticalSectionEx_Available = (g_pInitializeCriticalSectionEx) ? TRUE : FALSE; } else diff --git a/winpr/libwinpr/synch/event.c b/winpr/libwinpr/synch/event.c index 0bae21fa3..c839ccf1c 100644 --- a/winpr/libwinpr/synch/event.c +++ b/winpr/libwinpr/synch/event.c @@ -43,13 +43,15 @@ #include "../handle/handle.h" #include "../pipe/pipe.h" +#include "../log.h" +#define TAG WINPR_TAG("synch.event") + CRITICAL_SECTION cs = { NULL, 0, 0, NULL, NULL, 0 }; HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { WINPR_EVENT* event; HANDLE handle = NULL; - event = (WINPR_EVENT*) malloc(sizeof(WINPR_EVENT)); if (event) @@ -59,30 +61,31 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, if (!event->bManualReset) { - fprintf(stderr, "CreateEventW: auto-reset events not yet implemented\n"); + WLog_ERR(TAG, "auto-reset events not yet implemented"); } event->pipe_fd[0] = -1; event->pipe_fd[1] = -1; - #ifdef HAVE_EVENTFD_H event->pipe_fd[0] = eventfd(0, EFD_NONBLOCK); if (event->pipe_fd[0] < 0) { - fprintf(stderr, "CreateEventW: failed to create event\n"); + WLog_ERR(TAG, "failed to create event"); free(event); return NULL; } + #else + if (pipe(event->pipe_fd) < 0) { - fprintf(stderr, "CreateEventW: failed to create event\n"); + WLog_ERR(TAG, "failed to create event"); free(event); return NULL; } -#endif +#endif WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); handle = (HANDLE) event; @@ -121,6 +124,20 @@ HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) return NULL; } +#ifdef HAVE_EVENTFD_H +#if defined(__UCLIBC__) +static int eventfd_read(int fd, eventfd_t* value) +{ + return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1; +} + +static int eventfd_write(int fd, eventfd_t value) +{ + return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1; +} +#endif +#endif + BOOL SetEvent(HANDLE hEvent) { ULONG Type; @@ -128,13 +145,11 @@ BOOL SetEvent(HANDLE hEvent) int length; BOOL status; WINPR_EVENT* event; - status = FALSE; if (winpr_Handle_GetInfo(hEvent, &Type, &Object)) { event = (WINPR_EVENT*) Object; - #ifdef HAVE_EVENTFD_H eventfd_t val = 1; @@ -146,6 +161,7 @@ BOOL SetEvent(HANDLE hEvent) status = (length == 0) ? TRUE : FALSE; #else + if (WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0) { length = write(event->pipe_fd[1], "-", 1); @@ -157,6 +173,7 @@ BOOL SetEvent(HANDLE hEvent) { status = TRUE; } + #endif } @@ -170,7 +187,6 @@ BOOL ResetEvent(HANDLE hEvent) int length; BOOL status; WINPR_EVENT* event; - status = FALSE; if (winpr_Handle_GetInfo(hEvent, &Type, &Object)) @@ -190,11 +206,13 @@ BOOL ResetEvent(HANDLE hEvent) if ((length > 0) && (!status)) status = TRUE; + #else length = read(event->pipe_fd[0], &length, 1); if ((length == 1) && (!status)) status = TRUE; + #endif } } @@ -209,17 +227,14 @@ HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL #ifndef _WIN32 WINPR_EVENT* event; HANDLE handle = NULL; - event = (WINPR_EVENT*) malloc(sizeof(WINPR_EVENT)); if (event) { event->bAttached = TRUE; event->bManualReset = bManualReset; - event->pipe_fd[0] = FileDescriptor; event->pipe_fd[1] = -1; - WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); handle = (HANDLE) event; } @@ -239,15 +254,13 @@ HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL * Returns an event based on the handle returned by GetEventWaitObject() */ HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, BOOL bInitialState, void* pObject) + BOOL bManualReset, BOOL bInitialState, void* pObject) { #ifndef _WIN32 - return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState, (int) (ULONG_PTR) pObject); + return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState, (int)(ULONG_PTR) pObject); #else HANDLE hEvent = NULL; - DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE, DUPLICATE_SAME_ACCESS); - return hEvent; #endif } @@ -268,12 +281,17 @@ int GetEventFileDescriptor(HANDLE hEvent) return -1; event = (WINPR_EVENT*) Object; + if (Type == HANDLE_TYPE_NAMED_PIPE) { - WINPR_NAMED_PIPE *named = (WINPR_NAMED_PIPE *)hEvent; - if (named->ServerMode) { + WINPR_NAMED_PIPE* named = (WINPR_NAMED_PIPE*)hEvent; + + if (named->ServerMode) + { return named->serverfd; - } else { + } + else + { return named->clientfd; } } @@ -300,9 +318,7 @@ int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor) return -1; event = (WINPR_EVENT*) Object; - event->pipe_fd[0] = FileDescriptor; - return 0; #else return -1; @@ -324,11 +340,8 @@ void* GetEventWaitObject(HANDLE hEvent) #ifndef _WIN32 int fd; void* obj; - fd = GetEventFileDescriptor(hEvent); - - obj = ((void*) (long) fd); - + obj = ((void*)(long) fd); return obj; #else return hEvent; diff --git a/winpr/libwinpr/synch/init.c b/winpr/libwinpr/synch/init.c index 88d32c27c..44c43fcb4 100644 --- a/winpr/libwinpr/synch/init.c +++ b/winpr/libwinpr/synch/init.c @@ -3,6 +3,8 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Thincast Technologies GmbH + * Copyright 2014 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,27 +24,72 @@ #endif #include +#include -#ifndef _WIN32 +#include "../log.h" +#define TAG WINPR_TAG("sync") + +#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) BOOL InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID* lpContext) { - return TRUE; + WLog_ERR(TAG, "not implemented"); + return FALSE; } BOOL InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext) { - return TRUE; -} - -BOOL InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID* Context) -{ - return TRUE; + WLog_ERR(TAG, "not implemented"); + return FALSE; } VOID InitOnceInitialize(PINIT_ONCE InitOnce) { + WLog_ERR(TAG, "not implemented"); +} +BOOL InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID* Context) +{ + for (;;) + { + switch ((ULONG_PTR)InitOnce->Ptr & 3) + { + case 2: + /* already completed successfully */ + return TRUE; + + case 0: + + /* first time */ + if (InterlockedCompareExchangePointer(&InitOnce->Ptr, (PVOID)1, (PVOID)0) != (PVOID)0) + { + /* some other thread was faster */ + break; + } + + /* it's our job to call the init function */ + if (InitFn(InitOnce, Parameter, Context)) + { + /* success */ + InitOnce->Ptr = (PVOID)2; + return TRUE; + } + + /* the init function returned an error, reset the status */ + InitOnce->Ptr = (PVOID)0; + return FALSE; + + case 1: + /* in progress */ + break; + + default: + WLog_ERR(TAG, "internal error"); + return FALSE; + } + + Sleep(5); + } } #endif diff --git a/winpr/libwinpr/synch/semaphore.c b/winpr/libwinpr/synch/semaphore.c index aad257e8c..32b71f509 100644 --- a/winpr/libwinpr/synch/semaphore.c +++ b/winpr/libwinpr/synch/semaphore.c @@ -32,13 +32,15 @@ #ifndef _WIN32 #include "../handle/handle.h" +#include "../log.h" +#define TAG WINPR_TAG("synch.semaphore") HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName) { HANDLE handle; WINPR_SEMAPHORE* semaphore; - semaphore = (WINPR_SEMAPHORE*) malloc(sizeof(WINPR_SEMAPHORE)); + if (!semaphore) return NULL; @@ -52,7 +54,7 @@ HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lIniti if (pipe(semaphore->pipe_fd) < 0) { - fprintf(stderr, "CreateSemaphoreW: failed to create semaphore\n"); + WLog_ERR(TAG, "failed to create semaphore"); free(semaphore); return NULL; } @@ -77,13 +79,11 @@ HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lIniti #else sem_init(semaphore->sem, 0, lMaximumCount); #endif - #endif } WINPR_HANDLE_SET_TYPE(semaphore, HANDLE_TYPE_SEMAPHORE); handle = (HANDLE) semaphore; - return handle; } @@ -94,11 +94,13 @@ HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lIniti HANDLE OpenSemaphoreW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName) { + WLog_ERR(TAG, "not implemented"); return NULL; } HANDLE OpenSemaphoreA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { + WLog_ERR(TAG, "not implemented"); return NULL; } @@ -114,7 +116,6 @@ BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCo if (Type == HANDLE_TYPE_SEMAPHORE) { semaphore = (WINPR_SEMAPHORE*) Object; - #ifdef WINPR_PIPE_SEMAPHORE if (semaphore->pipe_fd[0] != -1) @@ -129,13 +130,11 @@ BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCo } #else - #if defined __APPLE__ semaphore_signal(*((winpr_sem_t*) semaphore->sem)); #else sem_post((winpr_sem_t*) semaphore->sem); #endif - #endif return TRUE; } diff --git a/winpr/libwinpr/synch/synch.h b/winpr/libwinpr/synch/synch.h index fbde1d4a8..51810237a 100644 --- a/winpr/libwinpr/synch/synch.h +++ b/winpr/libwinpr/synch/synch.h @@ -32,10 +32,10 @@ #define WITH_POSIX_TIMER 1 #endif -#ifndef _WIN32 - #include "../handle/handle.h" +#ifndef _WIN32 + #define WINPR_PIPE_SEMAPHORE 1 #if defined __APPLE__ @@ -144,4 +144,13 @@ struct winpr_timer_queue_timer #endif +struct winpr_barrier +{ + DECLSPEC_ALIGN(4) LONG count; + LONG lTotalThreads; + LONG lSpinCount; + HANDLE event; +}; +typedef struct winpr_barrier WINPR_BARRIER; + #endif /* WINPR_SYNCH_PRIVATE_H */ diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt index 7805d1798..68b76faa0 100644 --- a/winpr/libwinpr/synch/test/CMakeLists.txt +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -5,8 +5,10 @@ set(MODULE_PREFIX "TEST_SYNCH") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS + TestSynchInit.c TestSynchEvent.c TestSynchMutex.c + TestSynchBarrier.c TestSynchCritical.c TestSynchSemaphore.c TestSynchThread.c @@ -20,12 +22,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-synch winpr-sysinfo winpr-error) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/synch/test/TestSynchBarrier.c b/winpr/libwinpr/synch/test/TestSynchBarrier.c new file mode 100644 index 000000000..6b2258016 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchBarrier.c @@ -0,0 +1,72 @@ + +#include +#include +#include + +static int g_Count; +static HANDLE g_Event; +static CRITICAL_SECTION g_Lock; +static SYNCHRONIZATION_BARRIER g_Barrier; + +static void* test_synch_barrier_thread_func(void* arg) +{ + BOOL status; + int count; + + EnterCriticalSection(&g_Lock); + count = g_Count++; + LeaveCriticalSection(&g_Lock); + status = EnterSynchronizationBarrier(&g_Barrier, 0); + + printf("Thread #%d status: %s\n", count, + status ? "TRUE" : "FALSE"); + + if (status) + { + SetEvent(g_Event); + } + + return NULL; +} + +int TestSynchBarrier(int argc, char* argv[]) +{ + int index; + HANDLE threads[5]; + + g_Count = 0; + + g_Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + InitializeCriticalSectionAndSpinCount(&g_Lock, 4000); + + if (!InitializeSynchronizationBarrier(&g_Barrier, 5, -1)) + return -1; + + for (index = 0; index < 5; index++) + { + threads[index] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) + test_synch_barrier_thread_func, NULL, 0, NULL); + } + + WaitForSingleObject(g_Event, INFINITE); + + if (g_Count != 5) + return -1; + + printf("All threads have reached the barrier\n"); + + for (index = 0; index < 5; index++) + { + CloseHandle(threads[index]); + } + + DeleteSynchronizationBarrier(&g_Barrier); + + DeleteCriticalSection(&g_Lock); + + CloseHandle(g_Event); + + return 0; +} + diff --git a/winpr/libwinpr/synch/test/TestSynchInit.c b/winpr/libwinpr/synch/test/TestSynchInit.c new file mode 100644 index 000000000..efcd9c3af --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchInit.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +#define TEST_NUM_THREADS 100 +#define TEST_NUM_FAILURES 10 + +INIT_ONCE initOnceTest = INIT_ONCE_STATIC_INIT; + +HANDLE hStartEvent = NULL; +LONG *pErrors = NULL; +LONG *pTestThreadFunctionCalls = NULL; +LONG *pTestOnceFunctionCalls = NULL; +LONG *pInitOnceExecuteOnceCalls = NULL; + + +BOOL CALLBACK TestOnceFunction(PINIT_ONCE once, PVOID param, PVOID *context) +{ + LONG calls = InterlockedIncrement(pTestOnceFunctionCalls) - 1; + + /* simulate execution time */ + Sleep(100 + rand() % 400); + + if (calls < TEST_NUM_FAILURES) + { + /* simulated error */ + return FALSE; + } + if (calls == TEST_NUM_FAILURES) + { + return TRUE; + } + fprintf(stderr, "%s: error: called again after success\n", __FUNCTION__); + InterlockedIncrement(pErrors); + return FALSE; +} + +DWORD WINAPI TestThreadFunction(LPVOID lpParam) +{ + LONG calls; + BOOL ok; + InterlockedIncrement(pTestThreadFunctionCalls); + if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "%s: error: failed to wait for start event\n", __FUNCTION__); + InterlockedIncrement(pErrors); + return 0; + } + + ok = InitOnceExecuteOnce(&initOnceTest, TestOnceFunction, NULL, NULL); + calls = InterlockedIncrement(pInitOnceExecuteOnceCalls); + if (!ok && calls > TEST_NUM_FAILURES) + { + fprintf(stderr, "%s: InitOnceExecuteOnce failed unexpectedly\n", __FUNCTION__); + InterlockedIncrement(pErrors); + } + return 0; +} + +int TestSynchInit(int argc, char* argv[]) +{ + HANDLE hThreads[TEST_NUM_THREADS]; + DWORD dwCreatedThreads = 0; + DWORD i; + BOOL result = FALSE; + + pErrors = _aligned_malloc(sizeof(LONG), sizeof(LONG)); + pTestThreadFunctionCalls = _aligned_malloc(sizeof(LONG), sizeof(LONG)); + pTestOnceFunctionCalls = _aligned_malloc(sizeof(LONG), sizeof(LONG)); + pInitOnceExecuteOnceCalls = _aligned_malloc(sizeof(LONG), sizeof(LONG)); + + if (!pErrors || !pTestThreadFunctionCalls || !pTestOnceFunctionCalls || !pInitOnceExecuteOnceCalls) + { + fprintf(stderr, "error: _aligned_malloc failed\n"); + goto out; + } + + *pErrors = 0; + *pTestThreadFunctionCalls = 0; + *pTestOnceFunctionCalls = 0; + *pInitOnceExecuteOnceCalls = 0; + + if (!(hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + fprintf(stderr, "error creating start event\n"); + InterlockedIncrement(pErrors); + goto out; + } + + for (i = 0; i < TEST_NUM_THREADS; i++) + { + if (!(hThreads[i] = CreateThread(NULL, 0, TestThreadFunction, NULL, 0, NULL))) + { + fprintf(stderr, "error creating thread #%d\n", i); + InterlockedIncrement(pErrors); + goto out; + } + dwCreatedThreads++; + } + + Sleep(100); + SetEvent(hStartEvent); + + for (i = 0; i < dwCreatedThreads; i++) + { + if (WaitForSingleObject(hThreads[i], INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "error: error waiting for thread #%d\n", i); + InterlockedIncrement(pErrors); + goto out; + } + } + + if (*pErrors == 0 && + *pTestThreadFunctionCalls == TEST_NUM_THREADS && + *pInitOnceExecuteOnceCalls == TEST_NUM_THREADS && + *pTestOnceFunctionCalls == TEST_NUM_FAILURES + 1) + { + result = TRUE; + } + +out: + fprintf(stderr, "Test result: %s\n", result ? "OK" : "ERROR"); + fprintf(stderr, "Error count: %d\n", pErrors ? *pErrors : -1); + fprintf(stderr, "Threads created: %u\n", dwCreatedThreads); + fprintf(stderr, "TestThreadFunctionCalls: %d\n", pTestThreadFunctionCalls ? *pTestThreadFunctionCalls : -1); + fprintf(stderr, "InitOnceExecuteOnceCalls: %d\n", pInitOnceExecuteOnceCalls ? *pInitOnceExecuteOnceCalls : -1); + fprintf(stderr, "TestOnceFunctionCalls: %d\n", pTestOnceFunctionCalls ? *pTestOnceFunctionCalls : -1); + + _aligned_free(pErrors); + _aligned_free(pTestThreadFunctionCalls); + _aligned_free(pTestOnceFunctionCalls); + _aligned_free(pInitOnceExecuteOnceCalls); + + CloseHandle(hStartEvent); + + + for (i = 0; i < dwCreatedThreads; i++) + { + CloseHandle(hThreads[i]); + } + + return (result ? 0 : 1); +} diff --git a/winpr/libwinpr/synch/timer.c b/winpr/libwinpr/synch/timer.c index 0f0c41572..218060530 100644 --- a/winpr/libwinpr/synch/timer.c +++ b/winpr/libwinpr/synch/timer.c @@ -39,6 +39,9 @@ #include "../handle/handle.h" +#include "../log.h" +#define TAG WINPR_TAG("synch.timer") + #ifdef WITH_POSIX_TIMER static BOOL g_WaitableTimerSignalHandlerInstalled = FALSE; @@ -61,7 +64,7 @@ void WaitableTimerSignalHandler(int signum, siginfo_t* siginfo, void* arg) if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0) { - perror("timer_settime"); + WLog_ERR(TAG,"timer_settime"); } } } @@ -72,15 +75,11 @@ int InstallWaitableTimerSignalHandler() if (!g_WaitableTimerSignalHandlerInstalled) { struct sigaction action; - sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGALRM); - action.sa_flags = SA_RESTART | SA_SIGINFO; action.sa_sigaction = (void*) &WaitableTimerSignalHandler; - sigaction(SIGALRM, &action, NULL); - g_WaitableTimerSignalHandlerInstalled = TRUE; } @@ -95,7 +94,6 @@ int InitializeWaitableTimer(WINPR_TIMER* timer) { #ifdef HAVE_TIMERFD_H int status; - timer->fd = timerfd_create(CLOCK_MONOTONIC, 0); if (timer->fd <= 0) @@ -111,31 +109,29 @@ int InitializeWaitableTimer(WINPR_TIMER* timer) close(timer->fd); return -1; } + #endif } else { #ifdef WITH_POSIX_TIMER struct sigevent sigev; - InstallWaitableTimerSignalHandler(); - ZeroMemory(&sigev, sizeof(struct sigevent)); - sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGALRM; sigev.sigev_value.sival_ptr = (void*) timer; if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0) { - perror("timer_create"); + WLog_ERR(TAG,"timer_create"); return -1; } + #endif } timer->bInit = TRUE; - return 0; } @@ -147,14 +143,12 @@ HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManua { HANDLE handle = NULL; WINPR_TIMER* timer; - timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER)); if (timer) { WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER); handle = (HANDLE) timer; - timer->fd = -1; timer->lPeriod = 0; timer->bManualReset = bManualReset; @@ -174,9 +168,7 @@ HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManua HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) { BOOL bManualReset; - bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE; - return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName); } @@ -186,14 +178,18 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l } BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, - PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume) + PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume) { ULONG Type; PVOID Object; - int status = 0; WINPR_TIMER* timer; +#ifdef WITH_POSIX_TIMER LONGLONG seconds = 0; LONGLONG nanoseconds = 0; +#ifdef HAVE_TIMERFD_H + int status = 0; +#endif /* HAVE_TIMERFD_H */ +#endif /* WITH_POSIX_TIMER */ if (!winpr_Handle_GetInfo(hTimer, &Type, &Object)) return FALSE; @@ -208,7 +204,6 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio return FALSE; timer = (WINPR_TIMER*) Object; - timer->lPeriod = lPeriod; /* milliseconds */ timer->pfnCompletionRoutine = pfnCompletionRoutine; timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine; @@ -220,15 +215,12 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio } #ifdef WITH_POSIX_TIMER - ZeroMemory(&(timer->timeout), sizeof(struct itimerspec)); if (lpDueTime->QuadPart < 0) { LONGLONG due = lpDueTime->QuadPart * (-1); - /* due time is in 100 nanosecond intervals */ - seconds = (due / 10000000); nanoseconds = ((due % 10000000) * 100); } @@ -238,7 +230,7 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio } else { - printf("SetWaitableTimer: implement absolute time\n"); + WLog_ERR(TAG, "absolute time not implemented"); return FALSE; } @@ -266,27 +258,27 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio if (status) { - printf("SetWaitableTimer timerfd_settime failure: %d\n", status); + WLog_ERR(TAG, "timerfd_settime failure: %d", status); return FALSE; } + #endif } else { if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0) { - perror("timer_settime"); + WLog_ERR(TAG,"timer_settime"); return FALSE; } } #endif - return TRUE; } BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, - PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) + PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) { ULONG Type; PVOID Object; @@ -368,7 +360,7 @@ static void timespec_copy(struct timespec* dst, struct timespec* src) void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer) { WINPR_TIMER_QUEUE_TIMER* node; - + if (!(*pHead)) { *pHead = timer; @@ -377,7 +369,7 @@ void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TI } node = *pHead; - + while (node->next) { if (timespec_compare(&(timer->ExpirationTime), &(node->ExpirationTime)) > 0) @@ -428,14 +420,14 @@ void RemoveTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TI prevNode = node; node = node->next; } - + if (found) { if (prevNode) { prevNode->next = timer->next; } - + timer->next = NULL; } } @@ -449,7 +441,6 @@ int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue) return 0; timespec_gettimeofday(&CurrentTime); - node = timerQueue->activeHead; while (node) @@ -458,7 +449,6 @@ int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue) { node->Callback(node->Parameter, TRUE); node->FireCount++; - timerQueue->activeHead = node->next; node->next = NULL; @@ -471,7 +461,7 @@ int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue) { InsertTimerQueueTimer(&(timerQueue->inactiveHead), node); } - + node = timerQueue->activeHead; } else @@ -492,7 +482,6 @@ static void* TimerQueueThread(void* arg) while (1) { pthread_mutex_lock(&(timerQueue->cond_mutex)); - timespec_gettimeofday(&timeout); if (!timerQueue->activeHead) @@ -508,9 +497,7 @@ static void* TimerQueueThread(void* arg) } status = pthread_cond_timedwait(&(timerQueue->cond), &(timerQueue->cond_mutex), &timeout); - FireExpiredTimerQueueTimers(timerQueue); - pthread_mutex_unlock(&(timerQueue->cond_mutex)); if (timerQueue->bCancelled) @@ -524,15 +511,12 @@ int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue) { pthread_cond_init(&(timerQueue->cond), NULL); pthread_mutex_init(&(timerQueue->cond_mutex), NULL); - pthread_mutex_init(&(timerQueue->mutex), NULL); - pthread_attr_init(&(timerQueue->attr)); timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO); pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param)); pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO); pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue); - return 0; } @@ -540,20 +524,16 @@ HANDLE CreateTimerQueue(void) { HANDLE handle = NULL; WINPR_TIMER_QUEUE* timerQueue; - timerQueue = (WINPR_TIMER_QUEUE*) malloc(sizeof(WINPR_TIMER_QUEUE)); if (timerQueue) { ZeroMemory(timerQueue, sizeof(WINPR_TIMER_QUEUE)); - WINPR_HANDLE_SET_TYPE(timerQueue, HANDLE_TYPE_TIMER_QUEUE); handle = (HANDLE) timerQueue; - timerQueue->activeHead = NULL; timerQueue->inactiveHead = NULL; timerQueue->bCancelled = FALSE; - StartTimerQueueThread(timerQueue); } @@ -571,16 +551,11 @@ BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) return FALSE; timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue; - /* Cancel and delete timer queue timers */ - pthread_mutex_lock(&(timerQueue->cond_mutex)); - timerQueue->bCancelled = TRUE; - pthread_cond_signal(&(timerQueue->cond)); pthread_mutex_unlock(&(timerQueue->cond_mutex)); - pthread_join(timerQueue->thread, &rvalue); if (CompletionEvent == INVALID_HANDLE_VALUE) @@ -590,9 +565,7 @@ BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) else { /* Cancel all timers and return immediately */ - /* Move all active timers to the inactive timer list */ - node = timerQueue->activeHead; while (node) @@ -602,17 +575,13 @@ BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) } timerQueue->activeHead = NULL; - /* Once all timers are inactive, free them */ - node = timerQueue->inactiveHead; while (node) { nextNode = node->next; - free(node); - node = nextNode; } @@ -620,14 +589,10 @@ BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) } /* Delete timer queue */ - pthread_cond_destroy(&(timerQueue->cond)); pthread_mutex_destroy(&(timerQueue->cond_mutex)); - pthread_mutex_destroy(&(timerQueue->mutex)); - pthread_attr_destroy(&(timerQueue->attr)); - free(timerQueue); if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE)) @@ -642,7 +607,7 @@ BOOL DeleteTimerQueue(HANDLE TimerQueue) } BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue, - WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags) + WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags) { struct timespec CurrentTime; WINPR_TIMER_QUEUE* timerQueue; @@ -652,7 +617,6 @@ BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue, return FALSE; timespec_gettimeofday(&CurrentTime); - timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue; timer = (WINPR_TIMER_QUEUE_TIMER*) malloc(sizeof(WINPR_TIMER_QUEUE_TIMER)); @@ -660,30 +624,22 @@ BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue, return FALSE; WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER); - *((UINT_PTR*) phNewTimer) = (UINT_PTR) (HANDLE) timer; - + *((UINT_PTR*) phNewTimer) = (UINT_PTR)(HANDLE) timer; timespec_copy(&(timer->StartTime), &CurrentTime); timespec_add_ms(&(timer->StartTime), DueTime); timespec_copy(&(timer->ExpirationTime), &(timer->StartTime)); - timer->Flags = Flags; timer->DueTime = DueTime; timer->Period = Period; timer->Callback = Callback; timer->Parameter = Parameter; - timer->timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue; - timer->FireCount = 0; timer->next = NULL; - pthread_mutex_lock(&(timerQueue->cond_mutex)); - InsertTimerQueueTimer(&(timerQueue->activeHead), timer); - pthread_cond_signal(&(timerQueue->cond)); pthread_mutex_unlock(&(timerQueue->cond_mutex)); - return TRUE; } @@ -697,28 +653,20 @@ BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG return FALSE; timespec_gettimeofday(&CurrentTime); - timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue; timer = (WINPR_TIMER_QUEUE_TIMER*) Timer; - pthread_mutex_lock(&(timerQueue->cond_mutex)); - RemoveTimerQueueTimer(&(timerQueue->activeHead), timer); RemoveTimerQueueTimer(&(timerQueue->inactiveHead), timer); - timer->DueTime = DueTime; timer->Period = Period; timer->next = NULL; - timespec_copy(&(timer->StartTime), &CurrentTime); timespec_add_ms(&(timer->StartTime), DueTime); timespec_copy(&(timer->ExpirationTime), &(timer->StartTime)); - InsertTimerQueueTimer(&(timerQueue->activeHead), timer); - pthread_cond_signal(&(timerQueue->cond)); pthread_mutex_unlock(&(timerQueue->cond_mutex)); - return TRUE; } @@ -732,7 +680,6 @@ BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEve timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue; timer = (WINPR_TIMER_QUEUE_TIMER*) Timer; - pthread_mutex_lock(&(timerQueue->cond_mutex)); if (CompletionEvent == INVALID_HANDLE_VALUE) @@ -742,13 +689,11 @@ BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEve else { /* Cancel timer and return immediately */ - RemoveTimerQueueTimer(&(timerQueue->activeHead), timer); } pthread_cond_signal(&(timerQueue->cond)); pthread_mutex_unlock(&(timerQueue->cond_mutex)); - free(timer); if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE)) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 0272415ad..ea6e0921b 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -3,6 +3,7 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Hardening * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,10 +22,22 @@ #include "config.h" #endif +#ifdef HAVE_PTHREAD_GNU_EXT +#define _GNU_SOURCE +#endif + #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_POLL_H +#include +#else +#ifndef _WIN32 +#include +#endif +#endif + #include #include @@ -36,6 +49,9 @@ #include "../thread/thread.h" #include +#include "../log.h" +#define TAG WINPR_TAG("sync.wait") + /** * WaitForSingleObject * WaitForSingleObjectEx @@ -60,22 +76,18 @@ #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0 -int clock_gettime(int clk_id, struct timespec *t) +int clock_gettime(int clk_id, struct timespec* t) { UINT64 time; double seconds; double nseconds; mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); time = mach_absolute_time(); - nseconds = ((double) time * (double) timebase.numer) / ((double) timebase.denom); seconds = ((double) time * (double) timebase.numer) / ((double) timebase.denom * 1e9); - t->tv_sec = seconds; t->tv_nsec = nseconds; - return 0; } @@ -87,17 +99,16 @@ int clock_gettime(int clk_id, struct timespec *t) #if !defined(HAVE_PTHREAD_GNU_EXT) #include -static long long ts_difftime(const struct timespec *o, - const struct timespec *n) +static long long ts_difftime(const struct timespec* o, + const struct timespec* n) { long long oldValue = o->tv_sec * 1000000000LL + o->tv_nsec; long long newValue = n->tv_sec * 1000000000LL + n->tv_nsec; - return newValue - oldValue; } -static int pthread_timedjoin_np(pthread_t td, void **res, - struct timespec *timeout) +static int pthread_timedjoin_np(pthread_t td, void** res, + struct timespec* timeout) { struct timespec timenow; struct timespec sleepytime; @@ -111,7 +122,6 @@ static int pthread_timedjoin_np(pthread_t td, void **res, return pthread_join(td, res); nanosleep(&sleepytime, NULL); - clock_gettime(CLOCK_MONOTONIC, &timenow); if (ts_difftime(timeout, &timenow) >= 0) @@ -125,21 +135,20 @@ static int pthread_timedjoin_np(pthread_t td, void **res, } #if defined(__FreeBSD__) - /*the only way to get it work is to remove the static*/ - int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) +/*the only way to get it work is to remove the static*/ +int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* timeout) #else - static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) +static int pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* timeout) #endif { struct timespec timenow; struct timespec sleepytime; int retcode; - /* This is just to avoid a completely busy wait */ sleepytime.tv_sec = 0; sleepytime.tv_nsec = 10000000; /* 10ms */ - while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) + while ((retcode = pthread_mutex_trylock(mutex)) == EBUSY) { clock_gettime(CLOCK_MONOTONIC, &timenow); @@ -148,22 +157,59 @@ static int pthread_timedjoin_np(pthread_t td, void **res, return ETIMEDOUT; } - nanosleep (&sleepytime, NULL); + nanosleep(&sleepytime, NULL); } return retcode; } #endif -static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) +static void ts_add_ms(struct timespec* ts, DWORD dwMilliseconds) { ts->tv_sec += dwMilliseconds / 1000L; ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L; - ts->tv_sec += ts->tv_nsec / 1000000000L; ts->tv_nsec = ts->tv_nsec % 1000000000L; } +static int waitOnFd(int fd, DWORD dwMilliseconds) +{ + int status; +#ifdef HAVE_POLL_H + struct pollfd pollfds; + pollfds.fd = fd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, dwMilliseconds); + } + while ((status < 0) && (errno == EINTR)); + +#else + struct timeval timeout; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + ZeroMemory(&timeout, sizeof(timeout)); + + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) + { + timeout.tv_sec = dwMilliseconds / 1000; + timeout.tv_usec = (dwMilliseconds % 1000) * 1000; + } + + do + { + status = select(fd + 1, &rfds, NULL, NULL, (dwMilliseconds == INFINITE) ? NULL : &timeout); + } + while (status < 0 && (errno == EINTR)); + +#endif + return status; +} + DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; @@ -171,7 +217,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (!winpr_Handle_GetInfo(hHandle, &Type, &Object)) { - fprintf(stderr, "WaitForSingleObject failed: invalid hHandle.\n"); + WLog_ERR(TAG, "invalid hHandle."); return WAIT_FAILED; } @@ -180,7 +226,6 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) int status = 0; WINPR_THREAD* thread; void* thread_status = NULL; - thread = (WINPR_THREAD*) Object; if (thread->started) @@ -196,7 +241,6 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) clock_gettime(CLOCK_MONOTONIC, &timeout); ts_add_ms(&timeout, dwMilliseconds); - status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout); if (ETIMEDOUT == status) @@ -205,25 +249,26 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else status = pthread_join(thread->thread, &thread_status); + thread->started = FALSE; + if (status != 0) { - fprintf(stderr, "WaitForSingleObject: pthread_join failure: [%d] %s\n", - status, strerror(status)); + WLog_ERR(TAG, "pthread_join failure: [%d] %s", + status, strerror(status)); } if (thread_status) - thread->dwExitCode = ((DWORD) (size_t) thread_status); + thread->dwExitCode = ((DWORD)(size_t) thread_status); } } else if (Type == HANDLE_TYPE_PROCESS) { WINPR_PROCESS* process; - process = (WINPR_PROCESS*) Object; if (waitpid(process->pid, &(process->status), 0) != -1) { - fprintf(stderr, "WaitForSingleObject: waitpid failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "waitpid failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -232,17 +277,14 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else if (Type == HANDLE_TYPE_MUTEX) { WINPR_MUTEX* mutex; - mutex = (WINPR_MUTEX*) Object; if (dwMilliseconds != INFINITE) { int status; struct timespec timeout; - clock_gettime(CLOCK_MONOTONIC, &timeout); - ts_add_ms(&timeout, dwMilliseconds); - + ts_add_ms(&timeout, dwMilliseconds); status = pthread_mutex_timedlock(&mutex->mutex, &timeout); if (ETIMEDOUT == status) @@ -256,32 +298,14 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else if (Type == HANDLE_TYPE_EVENT) { int status; - fd_set rfds; WINPR_EVENT* event; - struct timeval timeout; - event = (WINPR_EVENT*) Object; - FD_ZERO(&rfds); - FD_SET(event->pipe_fd[0], &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(event->pipe_fd[0], dwMilliseconds); if (status < 0) { - fprintf(stderr, "WaitForSingleObject: event select() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "event select() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -291,37 +315,18 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else if (Type == HANDLE_TYPE_SEMAPHORE) { WINPR_SEMAPHORE* semaphore; - semaphore = (WINPR_SEMAPHORE*) Object; - #ifdef WINPR_PIPE_SEMAPHORE + if (semaphore->pipe_fd[0] != -1) { int status; int length; - fd_set rfds; - struct timeval timeout; - - FD_ZERO(&rfds); - FD_SET(semaphore->pipe_fd[0], &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(semaphore->pipe_fd[0], dwMilliseconds); if (status < 0) { - fprintf(stderr, "WaitForSingleObject: semaphore select() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "semaphore select() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -332,54 +337,34 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (length != 1) { - fprintf(stderr, "WaitForSingleObject: semaphore read failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "semaphore read failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } } -#else +#else #if defined __APPLE__ semaphore_wait(*((winpr_sem_t*) semaphore->sem)); #else sem_wait((winpr_sem_t*) semaphore->sem); #endif - #endif } else if (Type == HANDLE_TYPE_TIMER) { WINPR_TIMER* timer; - timer = (WINPR_TIMER*) Object; - #ifdef HAVE_EVENTFD_H + if (timer->fd != -1) { int status; - fd_set rfds; UINT64 expirations; - struct timeval timeout; - - FD_ZERO(&rfds); - FD_SET(timer->fd, &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(timer->fd + 1, &rfds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(timer->fd, dwMilliseconds); if (status < 0) { - fprintf(stderr, "WaitForSingleObject: timer select() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "timer select() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -395,11 +380,11 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (errno == ETIMEDOUT) return WAIT_TIMEOUT; - fprintf(stderr, "WaitForSingleObject: timer read() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "timer read() failure [%d] %s", errno, strerror(errno)); } else { - fprintf(stderr, "WaitForSingleObject: timer read() failure - incorrect number of bytes read"); + WLog_ERR(TAG, "timer read() failure - incorrect number of bytes read"); } return WAIT_FAILED; @@ -407,12 +392,12 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) } else { - fprintf(stderr, "WaitForSingleObject: invalid timer file descriptor\n"); + WLog_ERR(TAG, "invalid timer file descriptor"); return WAIT_FAILED; } #else - fprintf(stderr, "WaitForSingleObject: file descriptors not supported\n"); + WLog_ERR(TAG, "file descriptors not supported"); return WAIT_FAILED; #endif } @@ -420,38 +405,20 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { int fd; int status; - fd_set rfds; - struct timeval timeout; WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; - fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; if (fd == -1) { - fprintf(stderr, "WaitForSingleObject: invalid pipe file descriptor\n"); + WLog_ERR(TAG, "invalid pipe file descriptor"); return WAIT_FAILED; } - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(fd + 1, &rfds, NULL, NULL, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(fd, dwMilliseconds); if (status < 0) { - fprintf(stderr, "WaitForSingleObject: named pipe select() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "named pipe select() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -462,7 +429,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) } else { - fprintf(stderr, "WaitForSingleObject: unknown handle type %d\n", (int) Type); + WLog_ERR(TAG, "unknown handle type %d", (int) Type); } return WAIT_OBJECT_0; @@ -470,35 +437,45 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) { - fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + WLog_ERR(TAG, "Function not implemented."); assert(0); return WAIT_OBJECT_0; } +#define MAXIMUM_WAIT_OBJECTS 64 + DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) { int fd = -1; - int maxfd; int index; int status; - fd_set fds; ULONG Type; PVOID Object; +#ifdef HAVE_POLL_H + struct pollfd* pollfds; +#else + int maxfd; + fd_set fds; struct timeval timeout; +#endif - if (!nCount) + if (!nCount || (nCount > MAXIMUM_WAIT_OBJECTS)) { - fprintf(stderr, "WaitForMultipleObjects: invalid handles count\n"); + WLog_ERR(TAG, "invalid handles count(%d)", nCount); return WAIT_FAILED; } +#ifdef HAVE_POLL_H + pollfds = alloca(nCount * sizeof(struct pollfd)); +#else maxfd = 0; FD_ZERO(&fds); ZeroMemory(&timeout, sizeof(timeout)); +#endif if (bWaitAll) { - fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n"); + WLog_ERR(TAG, "bWaitAll not yet implemented"); assert(0); } @@ -506,8 +483,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl { if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object)) { - fprintf(stderr, "WaitForMultipleObjects: invalid handle\n"); - + WLog_ERR(TAG, "invalid handle"); return WAIT_FAILED; } @@ -517,7 +493,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "WaitForMultipleObjects: invalid event file descriptor\n"); + WLog_ERR(TAG, "invalid event file descriptor"); return WAIT_FAILED; } } @@ -526,7 +502,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl #ifdef WINPR_PIPE_SEMAPHORE fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; #else - fprintf(stderr, "WaitForMultipleObjects: semaphore not supported\n"); + WLog_ERR(TAG, "semaphore not supported"); return WAIT_FAILED; #endif } @@ -537,7 +513,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "WaitForMultipleObjects: invalid timer file descriptor\n"); + WLog_ERR(TAG, "invalid timer file descriptor"); return WAIT_FAILED; } } @@ -548,28 +524,45 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (fd == -1) { - fprintf(stderr, "WaitForMultipleObjects: invalid timer file descriptor\n"); + WLog_ERR(TAG, "invalid timer file descriptor"); return WAIT_FAILED; } } else { - fprintf(stderr, "WaitForMultipleObjects: unknown handle type %d\n", (int) Type); + WLog_ERR(TAG, "unknown handle type %d", (int) Type); return WAIT_FAILED; } if (fd == -1) { - fprintf(stderr, "WaitForMultipleObjects: invalid file descriptor\n"); + WLog_ERR(TAG, "invalid file descriptor"); return WAIT_FAILED; } +#ifdef HAVE_POLL_H + pollfds[index].fd = fd; + pollfds[index].events = POLLIN; + pollfds[index].revents = 0; +#else FD_SET(fd, &fds); if (fd > maxfd) maxfd = fd; + +#endif } +#ifdef HAVE_POLL_H + + do + { + status = poll(pollfds, nCount, dwMilliseconds); + } + while (status < 0 && errno == EINTR); + +#else + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) { timeout.tv_sec = dwMilliseconds / 1000; @@ -579,13 +572,15 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl do { status = select(maxfd + 1, &fds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); + (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && errno == EINTR); +#endif + if (status < 0) { - fprintf(stderr, "WaitForMultipleObjects: select() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "select() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } @@ -615,17 +610,21 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; } +#ifdef HAVE_POLL_H + + if (pollfds[index].revents & POLLIN) +#else if (FD_ISSET(fd, &fds)) +#endif { if (Type == HANDLE_TYPE_SEMAPHORE) { int length; - length = read(fd, &length, 1); if (length != 1) { - fprintf(stderr, "WaitForMultipleObjects: semaphore read() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "semaphore read() failure [%d] %s", errno, strerror(errno)); return WAIT_FAILED; } } @@ -633,7 +632,6 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl { int length; UINT64 expirations; - length = read(fd, (void*) &expirations, sizeof(UINT64)); if (length != 8) @@ -643,11 +641,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (errno == ETIMEDOUT) return WAIT_TIMEOUT; - fprintf(stderr, "WaitForMultipleObjects: timer read() failure [%d] %s\n", errno, strerror(errno)); + WLog_ERR(TAG, "timer read() failure [%d] %s", errno, strerror(errno)); } else { - fprintf(stderr, "WaitForMultipleObjects: timer read() failure - incorrect number of bytes read"); + WLog_ERR(TAG, "timer read() failure - incorrect number of bytes read"); } return WAIT_FAILED; @@ -658,22 +656,23 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl } } - fprintf(stderr, "WaitForMultipleObjects: failed (unknown error)\n"); + WLog_ERR(TAG, "failed (unknown error)"); return WAIT_FAILED; } DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) { - fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + WLog_ERR(TAG, "[ERROR] %s: Function not implemented."); assert(0); return 0; } DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) { - fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + WLog_ERR(TAG, "Function not implemented."); assert(0); return 0; } #endif + diff --git a/winpr/libwinpr/sysinfo/CMakeLists.txt b/winpr/libwinpr/sysinfo/CMakeLists.txt index 31006f0da..bc64f8751 100644 --- a/winpr/libwinpr/sysinfo/CMakeLists.txt +++ b/winpr/libwinpr/sysinfo/CMakeLists.txt @@ -15,36 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-sysinfo") -set(MODULE_PREFIX "WINPR_SYSINFO") - -set(${MODULE_PREFIX}_SRCS - sysinfo.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") +winpr_module_add(sysinfo.c) if((NOT WIN32) AND (NOT APPLE) AND (NOT ANDROID)) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/sysinfo/sysinfo.c b/winpr/libwinpr/sysinfo/sysinfo.c index 572916ca3..1529d54b3 100644 --- a/winpr/libwinpr/sysinfo/sysinfo.c +++ b/winpr/libwinpr/sysinfo/sysinfo.c @@ -68,10 +68,12 @@ defined(__OpenBSD__) || defined(__DragonFly__) #include #endif +#include "../log.h" +#define TAG WINPR_TAG("sysinfo") + static DWORD GetProcessorArchitecture() { DWORD cpuArch = PROCESSOR_ARCHITECTURE_UNKNOWN; - #if defined(_M_AMD64) cpuArch = PROCESSOR_ARCHITECTURE_AMD64; #elif defined(_M_IX86) @@ -87,16 +89,13 @@ static DWORD GetProcessorArchitecture() #elif defined(_M_ALPHA) cpuArch = PROCESSOR_ARCHITECTURE_ALPHA; #endif - return cpuArch; } static DWORD GetNumberOfProcessors() { DWORD numCPUs = 1; - /* TODO: iOS */ - #if defined(__linux__) || defined(__sun) || defined(_AIX) numCPUs = (DWORD) sysconf(_SC_NPROCESSORS_ONLN); #elif defined(__MACOSX__) || \ @@ -105,14 +104,12 @@ static DWORD GetNumberOfProcessors() { int mib[4]; size_t length = sizeof(numCPUs); - mib[0] = CTL_HW; - #if defined(__FreeBSD__) - mib[1] = HW_NCPU; - #else - mib[1] = HW_AVAILCPU; - #endif - +#if defined(__FreeBSD__) + mib[1] = HW_NCPU; +#else + mib[1] = HW_AVAILCPU; +#endif sysctl(mib, 2, &numCPUs, &length, NULL, 0); if (numCPUs < 1) @@ -129,7 +126,6 @@ static DWORD GetNumberOfProcessors() #elif defined(__sgi) numCPUs = (DWORD) sysconf(_SC_NPROC_ONLN); #endif - return numCPUs; } @@ -137,17 +133,13 @@ void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { lpSystemInfo->wProcessorArchitecture = GetProcessorArchitecture(); lpSystemInfo->wReserved = 0; - lpSystemInfo->dwPageSize = 0; lpSystemInfo->lpMinimumApplicationAddress = NULL; lpSystemInfo->lpMaximumApplicationAddress = NULL; lpSystemInfo->dwActiveProcessorMask = 0; - lpSystemInfo->dwNumberOfProcessors = GetNumberOfProcessors(); lpSystemInfo->dwProcessorType = 0; - lpSystemInfo->dwAllocationGranularity = 0; - lpSystemInfo->wProcessorLevel = 0; lpSystemInfo->wProcessorRevision = 0; } @@ -162,10 +154,8 @@ BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize) char* dot; int length; char hostname[256]; - gethostname(hostname, sizeof(hostname)); length = strlen(hostname); - dot = strchr(hostname, '.'); if (dot) @@ -182,7 +172,6 @@ BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize) CopyMemory(lpBuffer, hostname, length); lpBuffer[length] = '\0'; - return TRUE; } @@ -205,7 +194,6 @@ BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD l case ComputerNamePhysicalDnsHostname: case ComputerNamePhysicalDnsDomain: case ComputerNamePhysicalDnsFullyQualified: - if (*lpnSize <= length) { *lpnSize = length + 1; @@ -217,12 +205,10 @@ BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD l CopyMemory(lpBuffer, hostname, length); lpBuffer[length] = '\0'; - break; default: return FALSE; - break; } return TRUE; @@ -230,7 +216,7 @@ BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD l BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize) { - fprintf(stderr, "GetComputerNameExW unimplemented\n"); + WLog_ERR(TAG, "GetComputerNameExW unimplemented"); return 0; } @@ -241,9 +227,8 @@ BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) { /* Windows 7 SP1 Version Info */ - if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) || - (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))) + (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))) { lpVersionInformation->dwMajorVersion = 6; lpVersionInformation->dwMinorVersion = 1; @@ -254,7 +239,6 @@ BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)) { LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA) lpVersionInformation; - lpVersionInformationEx->wServicePackMajor = 1; lpVersionInformationEx->wServicePackMinor = 0; lpVersionInformationEx->wSuiteMask = 0; @@ -270,7 +254,7 @@ BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) { - fprintf(stderr, "GetVersionExW unimplemented\n"); + WLog_ERR(TAG, "GetVersionExW unimplemented"); return 1; } @@ -279,18 +263,15 @@ void GetSystemTime(LPSYSTEMTIME lpSystemTime) time_t ct = 0; struct tm* stm = NULL; WORD wMilliseconds = 0; - ct = time(NULL); - wMilliseconds = (WORD) (GetTickCount() % 1000); - + wMilliseconds = (WORD)(GetTickCount() % 1000); stm = gmtime(&ct); - ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME)); if (stm) { - lpSystemTime->wYear = (WORD) (stm->tm_year + 1900); - lpSystemTime->wMonth = (WORD) (stm->tm_mon + 1); + lpSystemTime->wYear = (WORD)(stm->tm_year + 1900); + lpSystemTime->wMonth = (WORD)(stm->tm_mon + 1); lpSystemTime->wDayOfWeek = (WORD) stm->tm_wday; lpSystemTime->wDay = (WORD) stm->tm_mday; lpSystemTime->wHour = (WORD) stm->tm_hour; @@ -310,18 +291,15 @@ VOID GetLocalTime(LPSYSTEMTIME lpSystemTime) time_t ct = 0; struct tm* ltm = NULL; WORD wMilliseconds = 0; - ct = time(NULL); - wMilliseconds = (WORD) (GetTickCount() % 1000); - + wMilliseconds = (WORD)(GetTickCount() % 1000); ltm = localtime(&ct); - ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME)); if (ltm) { - lpSystemTime->wYear = (WORD) (ltm->tm_year + 1900); - lpSystemTime->wMonth = (WORD) (ltm->tm_mon + 1); + lpSystemTime->wYear = (WORD)(ltm->tm_year + 1900); + lpSystemTime->wMonth = (WORD)(ltm->tm_mon + 1); lpSystemTime->wDayOfWeek = (WORD) ltm->tm_wday; lpSystemTime->wDay = (WORD) ltm->tm_mday; lpSystemTime->wHour = (WORD) ltm->tm_hour; @@ -339,14 +317,10 @@ BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime) VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) { ULARGE_INTEGER time64; - time64.u.HighPart = 0; - /* time represented in tenths of microseconds since midnight of January 1, 1601 */ - time64.QuadPart = time(NULL) + 11644473600LL; /* Seconds since January 1, 1601 */ time64.QuadPart *= 10000000; /* Convert timestamp to tenths of a microsecond */ - lpSystemTimeAsFileTime->dwLowDateTime = time64.LowPart; lpSystemTimeAsFileTime->dwHighDateTime = time64.HighPart; } @@ -363,28 +337,23 @@ BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PB DWORD GetTickCount(void) { DWORD ticks = 0; - #ifdef __linux__ - struct timespec ts; if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); #else - /** * FIXME: this is relative to the Epoch time, and we * need to return a value relative to the system uptime. */ - struct timeval tv; if (!gettimeofday(&tv, NULL)) ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); #endif - return ticks; } #endif // _WIN32 @@ -394,32 +363,25 @@ DWORD GetTickCount(void) ULONGLONG GetTickCount64(void) { ULONGLONG ticks = 0; - #if defined(__linux__) - struct timespec ts; if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); #elif defined(_WIN32) - ticks = (ULONGLONG) GetTickCount(); - #else - /** * FIXME: this is relative to the Epoch time, and we * need to return a value relative to the system uptime. */ - struct timeval tv; if (!gettimeofday(&tv, NULL)) ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); #endif - return ticks; } @@ -430,7 +392,7 @@ ULONGLONG GetTickCount64(void) #if defined(__GNUC__) && defined(__AVX__) #define xgetbv(_func_, _lo_, _hi_) \ - __asm__ __volatile__ ("xgetbv" : "=a" (_lo_), "=d" (_hi_) : "c" (_func_)) + __asm__ __volatile__ ("xgetbv" : "=a" (_lo_), "=d" (_hi_) : "c" (_func_)) #endif #define D_BIT_MMX (1<<23) @@ -439,6 +401,7 @@ ULONGLONG GetTickCount64(void) #define D_BIT_3DN (1<<30) #define C_BIT_SSE3 (1<<0) #define C_BIT_PCLMULQDQ (1<<1) +#define C81_BIT_LZCNT (1<<5) #define C_BIT_3DNP (1<<8) #define C_BIT_3DNP (1<<8) #define C_BIT_SSSE3 (1<<9) @@ -454,33 +417,31 @@ ULONGLONG GetTickCount64(void) #define E_BITS_AVX (E_BIT_XMM|E_BIT_YMM) static void cpuid( - unsigned info, - unsigned *eax, - unsigned *ebx, - unsigned *ecx, - unsigned *edx) + unsigned info, + unsigned* eax, + unsigned* ebx, + unsigned* ecx, + unsigned* edx) { #ifdef __GNUC__ - *eax = *ebx = *ecx = *edx = 0; - - __asm volatile - ( - /* The EBX (or RBX register on x86_64) is used for the PIC base address - * and must not be corrupted by our inline assembly. - */ + *eax = *ebx = *ecx = *edx = 0; + __asm volatile + ( + /* The EBX (or RBX register on x86_64) is used for the PIC base address + * and must not be corrupted by our inline assembly. + */ #ifdef _M_IX86 - "mov %%ebx, %%esi;" - "cpuid;" - "xchg %%ebx, %%esi;" + "mov %%ebx, %%esi;" + "cpuid;" + "xchg %%ebx, %%esi;" #else - "mov %%rbx, %%rsi;" - "cpuid;" - "xchg %%rbx, %%rsi;" + "mov %%rbx, %%rsi;" + "cpuid;" + "xchg %%rbx, %%rsi;" #endif - : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) - : "0" (info) - ); - + : "=a"(*eax), "=S"(*ebx), "=c"(*ecx), "=d"(*edx) + : "0"(info) + ); #elif defined(_MSC_VER) int a[4]; __cpuid(a, info); @@ -518,10 +479,10 @@ static void cpuid( // From linux kernel uapi/linux/auxvec.h #define AT_HWCAP 16 -static unsigned GetARMCPUCaps(void){ +static unsigned GetARMCPUCaps(void) +{ unsigned caps = 0; - - int fd = open ("/proc/self/auxv", O_RDONLY); + int fd = open("/proc/self/auxv", O_RDONLY); if (fd == -1) return 0; @@ -532,16 +493,20 @@ static unsigned GetARMCPUCaps(void){ unsigned a_val; /* Integer value */ } auxvec; - while (1){ + while (1) + { int num; - num = read(fd, (char *)&auxvec, sizeof(auxvec)); + num = read(fd, (char*)&auxvec, sizeof(auxvec)); + if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0)) - break; - if (auxvec.a_type == AT_HWCAP) + break; + + if (auxvec.a_type == AT_HWCAP) { - caps = auxvec.a_val; + caps = auxvec.a_val; } } + close(fd); return caps; } @@ -565,48 +530,69 @@ BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature) case PF_ARM_NEON: if (caps & HWCAP_NEON) ret = TRUE; + break; + case PF_ARM_THUMB: if (caps & HWCAP_THUMB) ret = TRUE; + case PF_ARM_VFP_32_REGISTERS_AVAILABLE: if (caps & HWCAP_VFPD32) ret = TRUE; + case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE: if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT)) ret = TRUE; + case PF_ARM_VFP3: if (caps & HWCAP_VFPv3) ret = TRUE; + break; + case PF_ARM_JAZELLE: if (caps & HWCAP_JAVA) ret = TRUE; + break; + case PF_ARM_DSP: if (caps & HWCAP_EDSP) ret = TRUE; + break; + case PF_ARM_MPU: if (caps & HWCAP_EDSP) ret = TRUE; + break; + case PF_ARM_THUMB2: if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4)) ret = TRUE; + break; + case PF_ARM_T2EE: if (caps & HWCAP_THUMBEE) ret = TRUE; + break; + case PF_ARM_INTEL_WMMX: if (caps & HWCAP_IWMMXT) ret = TRUE; + break; + default: break; } + #elif defined(__APPLE__) // __linux__ + switch (ProcessorFeature) { case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE: @@ -614,35 +600,45 @@ BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature) ret = TRUE; break; } + #endif // __linux__ #elif defined(_M_IX86_AMD64) #ifdef __GNUC__ unsigned a, b, c, d; - cpuid(1, &a, &b, &c, &d); switch (ProcessorFeature) { - case PF_MMX_INSTRUCTIONS_AVAILABLE: + case PF_MMX_INSTRUCTIONS_AVAILABLE: if (d & D_BIT_MMX) ret = TRUE; + break; - case PF_XMMI_INSTRUCTIONS_AVAILABLE: + + case PF_XMMI_INSTRUCTIONS_AVAILABLE: if (d & D_BIT_SSE) ret = TRUE; + break; - case PF_XMMI64_INSTRUCTIONS_AVAILABLE: + + case PF_XMMI64_INSTRUCTIONS_AVAILABLE: if (d & D_BIT_SSE2) ret = TRUE; + break; + case PF_3DNOW_INSTRUCTIONS_AVAILABLE: if (d & D_BIT_3DN) ret = TRUE; + break; - case PF_SSE3_INSTRUCTIONS_AVAILABLE: + + case PF_SSE3_INSTRUCTIONS_AVAILABLE: if (c & C_BIT_SSE3) ret = TRUE; + break; + default: break; } @@ -667,24 +663,34 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature) case PF_EX_ARM_VFP1: if (caps & HWCAP_VFP) ret = TRUE; + break; + case PF_EX_ARM_VFP3D16: if (caps & HWCAP_VFPv3D16) ret = TRUE; + break; + case PF_EX_ARM_VFP4: if (caps & HWCAP_VFPv4) ret = TRUE; + break; + case PF_EX_ARM_IDIVA: if (caps & HWCAP_IDIVA) ret = TRUE; + break; + case PF_EX_ARM_IDIVT: if (caps & HWCAP_IDIVT) ret = TRUE; + break; } + #endif // __linux__ #elif defined(_M_IX86_AMD64) unsigned a, b, c, d; @@ -692,23 +698,40 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature) switch (ProcessorFeature) { + case PF_EX_LZCNT: + { + unsigned a81, b81, c81, d81; + cpuid(0x80000001, &a81, &b81, &c81, &d81); + if (c81 & C81_BIT_LZCNT) + ret = TRUE; + } + break; + case PF_EX_3DNOW_PREFETCH: if (c & C_BIT_3DNP) ret = TRUE; + break; + case PF_EX_SSSE3: if (c & C_BIT_SSSE3) ret = TRUE; + break; + case PF_EX_SSE41: if (c & C_BIT_SSE41) ret = TRUE; + break; + case PF_EX_SSE42: if (c & C_BIT_SSE42) ret = TRUE; + break; #if defined(__GNUC__) && defined(__AVX__) + case PF_EX_AVX: case PF_EX_FMA: case PF_EX_AVX_AES: @@ -729,26 +752,34 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature) case PF_EX_AVX: ret = TRUE; break; + case PF_EX_FMA: if (c & C_BIT_FMA) ret = TRUE; + break; + case PF_EX_AVX_AES: if (c & C_BIT_AES) ret = TRUE; + break; + case PF_EX_AVX_PCLMULQDQ: if (c & C_BIT_PCLMULQDQ) ret = TRUE; + break; } } - } + } break; #endif //__AVX__ + default: break; } + #endif return ret; } diff --git a/winpr/libwinpr/sysinfo/test/CMakeLists.txt b/winpr/libwinpr/sysinfo/test/CMakeLists.txt index b757b273c..b76bbf6af 100644 --- a/winpr/libwinpr/sysinfo/test/CMakeLists.txt +++ b/winpr/libwinpr/sysinfo/test/CMakeLists.txt @@ -16,12 +16,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-sysinfo) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/thread/CMakeLists.txt b/winpr/libwinpr/thread/CMakeLists.txt index e8d4c01d1..9897d767a 100644 --- a/winpr/libwinpr/thread/CMakeLists.txt +++ b/winpr/libwinpr/thread/CMakeLists.txt @@ -15,10 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-thread") -set(MODULE_PREFIX "WINPR_THREAD") - -set(${MODULE_PREFIX}_SRCS +winpr_module_add( argv.c process.c processor.c @@ -26,39 +23,10 @@ set(${MODULE_PREFIX}_SRCS thread.h tls.c) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS}) - if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt) + winpr_library_add(rt) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-path winpr-handle) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/thread/argv.c b/winpr/libwinpr/thread/argv.c index e33ecf9ee..cc2a6078f 100644 --- a/winpr/libwinpr/thread/argv.c +++ b/winpr/libwinpr/thread/argv.c @@ -31,6 +31,9 @@ #include #endif +#include "../log.h" +#define TAG WINPR_TAG("thread") + /** * CommandLineToArgvW function: * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391/ @@ -111,10 +114,8 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) pArgs = NULL; numArgs = 0; - lpEscapedCmdLine = NULL; cmdLineLength = strlen(lpCmdLine); - lpEscapedChars = (BOOL*) malloc((cmdLineLength + 1) * sizeof(BOOL)); ZeroMemory(lpEscapedChars, (cmdLineLength + 1) * sizeof(BOOL)); @@ -122,9 +123,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) { int i, n; char* pLastEnd = NULL; - lpEscapedCmdLine = (char*) malloc((cmdLineLength + 1) * sizeof(char)); - p = (char*) lpCmdLine; pLastEnd = (char*) lpCmdLine; pOutput = (char*) lpEscapedCmdLine; @@ -139,7 +138,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) CopyMemory(pOutput, p, length); pOutput += length; p += length; - break; } @@ -157,7 +155,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) } n = (pEnd - pBeg) - 1; - length = (pBeg - pLastEnd); CopyMemory(pOutput, p, length); pOutput += length; @@ -176,13 +173,11 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) *pOutput = '"'; pOutput++; - pLastEnd = p; } *pOutput = '\0'; pOutput++; - lpCmdLine = (LPCSTR) lpEscapedCmdLine; cmdLineLength = strlen(lpCmdLine); } @@ -194,15 +189,12 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) while (currentIndex < cmdLineLength - 1) { index = strcspn(p, " \t"); - currentIndex += (index + 1); p = (char*) &lpCmdLine[currentIndex]; - maxNumArgs++; } maxBufferSize = (maxNumArgs * (sizeof(char*))) + (cmdLineLength + 1); - buffer = (char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, maxBufferSize); if (!buffer) @@ -210,7 +202,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) pArgs = (LPSTR*) buffer; pOutput = (char*) &buffer[maxNumArgs * (sizeof(char*))]; - numArgs = 0; currentIndex = 0; p = (char*) lpCmdLine; @@ -235,12 +226,9 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) if (p[index] != '"') { /* no whitespace escaped with double quotes */ - p = &p[index + 1]; pEnd = p - 1; - length = (pEnd - pBeg); - CopyMemory(pOutput, pBeg, length); pOutput[length] = '\0'; pArgs[numArgs++] = pOutput; @@ -265,7 +253,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) if (p[index] != '"') { - printf("CommandLineToArgvA parsing error: uneven number of unescaped double quotes!\n"); + WLog_ERR(TAG, "parsing error: uneven number of unescaped double quotes!"); } if (p[index] == '\0') @@ -313,7 +301,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) free(lpEscapedChars); *pNumArgs = numArgs; - return pArgs; } diff --git a/winpr/libwinpr/thread/test/CMakeLists.txt b/winpr/libwinpr/thread/test/CMakeLists.txt index 258704857..b078c0664 100644 --- a/winpr/libwinpr/thread/test/CMakeLists.txt +++ b/winpr/libwinpr/thread/test/CMakeLists.txt @@ -14,12 +14,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-thread winpr-heap winpr-environment winpr-synch) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 3d69f1700..51b775b7d 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -71,7 +71,6 @@ #include #if defined(__linux__) && !defined(__ANDROID__) -#define _GNU_SOURCE #include #include #include diff --git a/winpr/libwinpr/timezone/CMakeLists.txt b/winpr/libwinpr/timezone/CMakeLists.txt index b9fece024..49ae25418 100644 --- a/winpr/libwinpr/timezone/CMakeLists.txt +++ b/winpr/libwinpr/timezone/CMakeLists.txt @@ -15,23 +15,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-timezone") -set(MODULE_PREFIX "WINPR_TIMEZONE") - -set(${MODULE_PREFIX}_SRCS - timezone.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(timezone.c) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index dbf7f4cd1..3e75355a5 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -15,9 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-utils") -set(MODULE_PREFIX "WINPR_UTILS") - set(CMAKE_INCLUDE_CURRENT_DIR ON) set(${MODULE_PREFIX}_COLLECTIONS_SRCS @@ -38,6 +35,10 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/StreamPool.c collections/MessageQueue.c collections/MessagePipe.c) + +set(${MODULE_PREFIX}_LODEPNG_SRCS + lodepng/lodepng.c + lodepng/lodepng.h) set(${MODULE_PREFIX}_TRIO_SRCS trio/strio.h @@ -78,48 +79,38 @@ set(${MODULE_PREFIX}_SRCS ini.c sam.c ntlm.c + image.c print.c stream.c - cmdline.c) + debug.c + cmdline.c + ssl.c) -set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} +if (ANDROID) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +winpr_module_add(${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_COLLECTIONS_SRCS} + ${${MODULE_PREFIX}_LODEPNG_SRCS} ${${MODULE_PREFIX}_TRIO_SRCS} ${${MODULE_PREFIX}_WLOG_SRCS}) -include_directories("trio") -include_directories(${ZLIB_INCLUDE_DIRS}) -include_directories(${OPENSSL_INCLUDE_DIR}) +winpr_include_directory_add( + "lodepng" + "trio" + "." + ${ZLIB_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR}) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set(${MODULE_PREFIX}_LIBS +winpr_library_add( ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}) if(UNIX) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} m) + winpr_library_add(m) endif() -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-file winpr-path winpr-synch winpr-sysinfo) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index 478f26b74..c30cc96f0 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -38,7 +38,7 @@ * Gets or sets the number of elements that the ArrayList can contain. */ -int ArrayList_Capacity(wArrayList* arrayList) +int ArrayList_Capacity(wArrayList *arrayList) { return arrayList->capacity; } @@ -47,16 +47,26 @@ int ArrayList_Capacity(wArrayList* arrayList) * Gets the number of elements actually contained in the ArrayList. */ -int ArrayList_Count(wArrayList* arrayList) +int ArrayList_Count(wArrayList *arrayList) { return arrayList->size; } +/** + * Gets the internal list of items contained in the ArrayList. + */ + +int ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems) +{ + *ppItems = (ULONG_PTR*) arrayList->array; + return arrayList->size; +} + /** * Gets a value indicating whether the ArrayList has a fixed size. */ -BOOL ArrayList_IsFixedSized(wArrayList* arrayList) +BOOL ArrayList_IsFixedSized(wArrayList *arrayList) { return FALSE; } @@ -65,7 +75,7 @@ BOOL ArrayList_IsFixedSized(wArrayList* arrayList) * Gets a value indicating whether the ArrayList is read-only. */ -BOOL ArrayList_IsReadOnly(wArrayList* arrayList) +BOOL ArrayList_IsReadOnly(wArrayList *arrayList) { return FALSE; } @@ -74,7 +84,7 @@ BOOL ArrayList_IsReadOnly(wArrayList* arrayList) * Gets a value indicating whether access to the ArrayList is synchronized (thread safe). */ -BOOL ArrayList_IsSynchronized(wArrayList* arrayList) +BOOL ArrayList_IsSynchronized(wArrayList *arrayList) { return arrayList->synchronized; } @@ -83,7 +93,7 @@ BOOL ArrayList_IsSynchronized(wArrayList* arrayList) * Lock access to the ArrayList */ -void ArrayList_Lock(wArrayList* arrayList) +void ArrayList_Lock(wArrayList *arrayList) { EnterCriticalSection(&arrayList->lock); } @@ -92,7 +102,7 @@ void ArrayList_Lock(wArrayList* arrayList) * Unlock access to the ArrayList */ -void ArrayList_Unlock(wArrayList* arrayList) +void ArrayList_Unlock(wArrayList *arrayList) { LeaveCriticalSection(&arrayList->lock); } @@ -101,9 +111,9 @@ void ArrayList_Unlock(wArrayList* arrayList) * Gets the element at the specified index. */ -void* ArrayList_GetItem(wArrayList* arrayList, int index) +void *ArrayList_GetItem(wArrayList *arrayList, int index) { - void* obj = NULL; + void *obj = NULL; if ((index >= 0) && (index < arrayList->size)) { @@ -117,7 +127,7 @@ void* ArrayList_GetItem(wArrayList* arrayList, int index) * Sets the element at the specified index. */ -void ArrayList_SetItem(wArrayList* arrayList, int index, void* obj) +void ArrayList_SetItem(wArrayList *arrayList, int index, void *obj) { if ((index >= 0) && (index < arrayList->size)) { @@ -133,7 +143,7 @@ void ArrayList_SetItem(wArrayList* arrayList, int index, void* obj) * Shift a section of the list. */ -BOOL ArrayList_Shift(wArrayList* arrayList, int index, int count) +BOOL ArrayList_Shift(wArrayList *arrayList, int index, int count) { if (count > 0) { @@ -141,24 +151,28 @@ BOOL ArrayList_Shift(wArrayList* arrayList, int index, int count) { void **newArray; int newCapacity = arrayList->capacity * arrayList->growthFactor; + newArray = (void **)realloc(arrayList->array, sizeof(void *) * newCapacity); - newArray = (void **)realloc(arrayList->array, sizeof(void*) * newCapacity); if (!newArray) return FALSE; + arrayList->array = newArray; arrayList->capacity = newCapacity; } - MoveMemory(&arrayList->array[index + count], &arrayList->array[index], (arrayList->size - index) * sizeof(void*)); + MoveMemory(&arrayList->array[index + count], &arrayList->array[index], (arrayList->size - index) * sizeof(void *)); arrayList->size += count; } else if (count < 0) { int chunk = arrayList->size - index + count; + if (chunk > 0) - MoveMemory(&arrayList->array[index], &arrayList->array[index - count], chunk * sizeof(void*)); + MoveMemory(&arrayList->array[index], &arrayList->array[index - count], chunk * sizeof(void *)); + arrayList->size += count; } + return TRUE; } @@ -166,7 +180,7 @@ BOOL ArrayList_Shift(wArrayList* arrayList, int index, int count) * Removes all elements from the ArrayList. */ -void ArrayList_Clear(wArrayList* arrayList) +void ArrayList_Clear(wArrayList *arrayList) { int index; @@ -191,22 +205,33 @@ void ArrayList_Clear(wArrayList* arrayList) * Determines whether an element is in the ArrayList. */ -BOOL ArrayList_Contains(wArrayList* arrayList, void* obj) +BOOL ArrayList_Contains(wArrayList *arrayList, void *obj) { + DWORD index; + BOOL rc = FALSE; + if (arrayList->synchronized) EnterCriticalSection(&arrayList->lock); + for (index = 0; index < arrayList->size; index++) + { + rc = arrayList->object.fnObjectEquals(arrayList->array[index], obj); + + if (rc) + break; + } + if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); - return FALSE; + return rc; } /** * Adds an object to the end of the ArrayList. */ -int ArrayList_Add(wArrayList* arrayList, void* obj) +int ArrayList_Add(wArrayList *arrayList, void *obj) { int index = -1; @@ -217,7 +242,8 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) { void **newArray; int newCapacity = arrayList->capacity * arrayList->growthFactor; - newArray = (void **)realloc(arrayList->array, sizeof(void*) * newCapacity); + newArray = (void **)realloc(arrayList->array, sizeof(void *) * newCapacity); + if (!newArray) goto out; @@ -227,8 +253,8 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) arrayList->array[arrayList->size++] = obj; index = arrayList->size; - out: + if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); @@ -239,9 +265,10 @@ out: * Inserts an element into the ArrayList at the specified index. */ -BOOL ArrayList_Insert(wArrayList* arrayList, int index, void* obj) +BOOL ArrayList_Insert(wArrayList *arrayList, int index, void *obj) { BOOL ret = TRUE; + if (arrayList->synchronized) EnterCriticalSection(&arrayList->lock); @@ -259,6 +286,7 @@ BOOL ArrayList_Insert(wArrayList* arrayList, int index, void* obj) if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); + return ret; } @@ -266,7 +294,7 @@ BOOL ArrayList_Insert(wArrayList* arrayList, int index, void* obj) * Removes the first occurrence of a specific object from the ArrayList. */ -BOOL ArrayList_Remove(wArrayList* arrayList, void* obj) +BOOL ArrayList_Remove(wArrayList *arrayList, void *obj) { int index; BOOL found = FALSE; @@ -285,14 +313,16 @@ BOOL ArrayList_Remove(wArrayList* arrayList, void* obj) } if (found) - { + { if (arrayList->object.fnObjectFree) arrayList->object.fnObjectFree(arrayList->array[index]); + ret = ArrayList_Shift(arrayList, index, -1); - } + } if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); + return ret; } @@ -300,7 +330,7 @@ BOOL ArrayList_Remove(wArrayList* arrayList, void* obj) * Removes the element at the specified index of the ArrayList. */ -BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index) +BOOL ArrayList_RemoveAt(wArrayList *arrayList, int index) { BOOL ret = TRUE; @@ -311,11 +341,13 @@ BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index) { if (arrayList->object.fnObjectFree) arrayList->object.fnObjectFree(arrayList->array[index]); + ret = ArrayList_Shift(arrayList, index, -1); } if (arrayList->synchronized) LeaveCriticalSection(&arrayList->lock); + return ret; } @@ -329,7 +361,7 @@ BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index) * in the ArrayList that contains the specified number of elements and ends at the specified index. */ -int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int count) +int ArrayList_IndexOf(wArrayList *arrayList, void *obj, int startIndex, int count) { int index; BOOL found = FALSE; @@ -345,7 +377,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun for (index = startIndex; index < startIndex + count; index++) { - if (arrayList->array[index] == obj) + if (arrayList->object.fnObjectEquals(arrayList->array[index], obj)) { found = TRUE; break; @@ -371,7 +403,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun * in the ArrayList that contains the specified number of elements and ends at the specified index. */ -int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int count) +int ArrayList_LastIndexOf(wArrayList *arrayList, void *obj, int startIndex, int count) { int index; BOOL found = FALSE; @@ -387,7 +419,7 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int for (index = startIndex + count - 1; index >= startIndex; index--) { - if (arrayList->array[index] == obj) + if (arrayList->object.fnObjectEquals(arrayList->array[index], obj)) { found = TRUE; break; @@ -403,38 +435,42 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int return index; } +static BOOL ArrayList_DefaultCompare(void *objA, void *objB) +{ + return objA == objB ? TRUE : FALSE; +} + /** * Construction, Destruction */ -wArrayList* ArrayList_New(BOOL synchronized) +wArrayList *ArrayList_New(BOOL synchronized) { - wArrayList* arrayList = NULL; - + wArrayList *arrayList = NULL; arrayList = (wArrayList *)calloc(1, sizeof(wArrayList)); + if (!arrayList) return NULL; arrayList->synchronized = synchronized; arrayList->capacity = 32; arrayList->growthFactor = 2; - + arrayList->object.fnObjectEquals = ArrayList_DefaultCompare; arrayList->array = (void **)malloc(arrayList->capacity * sizeof(void *)); + if (!arrayList->array) goto out_free; InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000); return arrayList; - out_free: free(arrayList); return NULL; } -void ArrayList_Free(wArrayList* arrayList) +void ArrayList_Free(wArrayList *arrayList) { ArrayList_Clear(arrayList); - DeleteCriticalSection(&arrayList->lock); free(arrayList->array); free(arrayList); diff --git a/winpr/libwinpr/utils/collections/BitStream.c b/winpr/libwinpr/utils/collections/BitStream.c index 5604a5e20..02e336a79 100644 --- a/winpr/libwinpr/utils/collections/BitStream.c +++ b/winpr/libwinpr/utils/collections/BitStream.c @@ -21,7 +21,9 @@ #include "config.h" #endif +#include #include +#include "../trio/trio.h" const char* BYTE_BIT_STRINGS_LSB[256] = { @@ -159,28 +161,31 @@ const char* BYTE_BIT_STRINGS_MSB[256] = "00111111", "10111111", "01111111", "11111111" }; -void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags) +void BitDump(const char* tag, int level, const BYTE* buffer, UINT32 length, UINT32 flags) { DWORD i; int nbits; const char* str; const char** strs; - + char pbuffer[64 * 8 + 1]; + size_t pos = 0; strs = (flags & BITDUMP_MSB_FIRST) ? BYTE_BIT_STRINGS_MSB : BYTE_BIT_STRINGS_LSB; for (i = 0; i < length; i += 8) { str = strs[buffer[i / 8]]; - nbits = (length - i) > 8 ? 8 : (length - i); + pos += trio_snprintf(&pbuffer[pos], length - pos, "%.*s ", nbits, str); if ((i % 64) == 0) - printf("\n"); - - printf("%.*s ", nbits, str); + { + pos = 0; + WLog_LVL(tag, level, "%s", pbuffer); + } } - printf("\n"); + if (i) + WLog_LVL(tag, level, "%s ", pbuffer); } UINT32 ReverseBits32(UINT32 bits, UINT32 nbits) @@ -196,7 +201,6 @@ UINT32 ReverseBits32(UINT32 bits, UINT32 nbits) while (nbits > 0); rbits >>= 1; - return rbits; } @@ -217,12 +221,16 @@ WINPR_API void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits); void BitStream_Prefetch(wBitStream* bs) { (bs->prefetch) = 0; + if ((bs->pointer - bs->buffer) < (bs->capacity + 4)) (bs->prefetch) |= (*(bs->pointer + 4) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 5)) (bs->prefetch) |= (*(bs->pointer + 5) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 6)) (bs->prefetch) |= (*(bs->pointer + 6) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 7)) (bs->prefetch) |= (*(bs->pointer + 7) << 0); } @@ -233,10 +241,13 @@ void BitStream_Fetch(wBitStream* bs) if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) (bs->accumulator) |= (*(bs->pointer + 0) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) (bs->accumulator) |= (*(bs->pointer + 1) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) (bs->accumulator) |= (*(bs->pointer + 2) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) (bs->accumulator) |= (*(bs->pointer + 3) << 0); @@ -247,10 +258,13 @@ void BitStream_Flush(wBitStream* bs) { if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) *(bs->pointer + 0) = (bs->accumulator >> 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) *(bs->pointer + 1) = (bs->accumulator >> 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) *(bs->pointer + 2) = (bs->accumulator >> 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) *(bs->pointer + 3) = (bs->accumulator >> 0); } @@ -272,10 +286,8 @@ void BitStream_Shift(wBitStream* bs, UINT32 nbits) bs->mask = ((1 << nbits) - 1); bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); bs->prefetch <<= nbits; - bs->offset -= 32; bs->pointer += 4; - BitStream_Prefetch(bs); if (bs->offset) @@ -301,7 +313,6 @@ void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits) bs->offset -= 32; bs->mask = ((1 << (nbits - bs->offset)) - 1); bs->accumulator |= ((bits >> bs->offset) & bs->mask); - BitStream_Flush(bs); bs->accumulator = 0; bs->pointer += 4; @@ -316,13 +327,13 @@ void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits) #endif -void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity) +void BitStream_Attach(wBitStream* bs, const BYTE* buffer, UINT32 capacity) { bs->position = 0; bs->buffer = buffer; bs->offset = 0; bs->accumulator = 0; - bs->pointer = bs->buffer; + bs->pointer = (BYTE*) bs->buffer; bs->capacity = capacity; bs->length = bs->capacity * 8; } @@ -330,12 +341,10 @@ void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity) wBitStream* BitStream_New() { wBitStream* bs = NULL; - bs = (wBitStream*) calloc(1, sizeof(wBitStream)); if (bs) { - } return bs; diff --git a/winpr/libwinpr/utils/collections/BufferPool.c b/winpr/libwinpr/utils/collections/BufferPool.c index 3a0fda5b4..2b05263c6 100644 --- a/winpr/libwinpr/utils/collections/BufferPool.c +++ b/winpr/libwinpr/utils/collections/BufferPool.c @@ -34,7 +34,7 @@ * Methods */ -BOOL BufferPool_ShiftAvailable(wBufferPool* pool, int index, int count) +static BOOL BufferPool_ShiftAvailable(wBufferPool* pool, int index, int count) { if (count > 0) { @@ -61,7 +61,7 @@ BOOL BufferPool_ShiftAvailable(wBufferPool* pool, int index, int count) return TRUE; } -BOOL BufferPool_ShiftUsed(wBufferPool* pool, int index, int count) +static BOOL BufferPool_ShiftUsed(wBufferPool* pool, int index, int count) { if (count > 0) { diff --git a/winpr/libwinpr/utils/collections/HashTable.c b/winpr/libwinpr/utils/collections/HashTable.c index fcbe4aa3d..089b6ea67 100644 --- a/winpr/libwinpr/utils/collections/HashTable.c +++ b/winpr/libwinpr/utils/collections/HashTable.c @@ -33,9 +33,50 @@ * http://www.pomakis.com/hashtable/hashtable.h */ -static int isProbablePrime(long oddNumber) +BOOL HashTable_PointerCompare(void* pointer1, void* pointer2) { - long i; + return (pointer1 == pointer2); +} + +UINT32 HashTable_PointerHash(void* pointer) +{ + return ((UINT32) (UINT_PTR) pointer) >> 4; +} + +BOOL HashTable_StringCompare(void* string1, void* string2) +{ + if (!string1 || !string2) + return (string1 == string2); + + return (strcmp((char*) string1, (char*) string2) == 0); +} + +UINT32 HashTable_StringHash(void* key) +{ + UINT32 c; + UINT32 hash = 5381; + BYTE* str = (BYTE*) key; + + /* djb2 algorithm */ + while ((c = *str++) != '\0') + hash = (hash * 33) + c; + + return hash; +} + +void* HashTable_StringClone(void* str) +{ + return _strdup((char*) str); +} + +void HashTable_StringFree(void* str) +{ + free(str); +} + +static int HashTable_IsProbablePrime(int oddNumber) +{ + int i; for (i = 3; i < 51; i += 2) { @@ -48,55 +89,54 @@ static int isProbablePrime(long oddNumber) return 1; /* maybe */ } -static long calculateIdealNumOfBuckets(wHashTable* table) +static long HashTable_CalculateIdealNumOfBuckets(wHashTable* table) { - long idealNumOfBuckets = table->numOfElements / ((long) table->idealRatio); + int idealNumOfBuckets = table->numOfElements / ((int) table->idealRatio); if (idealNumOfBuckets < 5) idealNumOfBuckets = 5; else idealNumOfBuckets |= 0x01; - while (!isProbablePrime(idealNumOfBuckets)) + while (!HashTable_IsProbablePrime(idealNumOfBuckets)) idealNumOfBuckets += 2; return idealNumOfBuckets; } -void HashTable_Rehash(wHashTable* table, long numOfBuckets) +void HashTable_Rehash(wHashTable* table, int numOfBuckets) { int index; - long hashValue; + UINT32 hashValue; wKeyValuePair* pair; wKeyValuePair* nextPair; wKeyValuePair** newBucketArray; if (numOfBuckets == 0) - numOfBuckets = calculateIdealNumOfBuckets(table); + numOfBuckets = HashTable_CalculateIdealNumOfBuckets(table); if (numOfBuckets == table->numOfBuckets) return; /* already the right size! */ - newBucketArray = (wKeyValuePair**) malloc(numOfBuckets * sizeof(wKeyValuePair*)); + newBucketArray = (wKeyValuePair**) calloc(numOfBuckets, sizeof(wKeyValuePair*)); - if (newBucketArray == NULL) + if (!newBucketArray) { - /* Couldn't allocate memory for the new array. This isn't a fatal - * error; we just can't perform the rehash. */ + /* + * Couldn't allocate memory for the new array. + * This isn't a fatal error; we just can't perform the rehash. + */ return; } - for (index = 0; index < numOfBuckets; index++) - newBucketArray[index] = NULL; - for (index = 0; index < table->numOfBuckets; index++) { pair = table->bucketArray[index]; - while (pair != NULL) + while (pair) { nextPair = pair->next; - hashValue = table->hashFunction(pair->key) % numOfBuckets; + hashValue = table->hash(pair->key) % numOfBuckets; pair->next = newBucketArray[hashValue]; newBucketArray[hashValue] = pair; pair = nextPair; @@ -116,40 +156,21 @@ void HashTable_SetIdealRatio(wHashTable* table, float idealRatio, table->upperRehashThreshold = upperRehashThreshold; } -unsigned long HashTable_StringHashFunction(void* key) -{ - int c; - unsigned long hash = 5381; - unsigned char* str = (unsigned char*) key; - - /* djb2 algorithm */ - while ((c = *str++) != '\0') - hash = (hash * 33) + c; - - return hash; -} - wKeyValuePair* HashTable_Get(wHashTable* table, void* key) { - long hashValue = table->hashFunction(key) % table->numOfBuckets; - wKeyValuePair* pair = table->bucketArray[hashValue]; + UINT32 hashValue; + wKeyValuePair* pair; - while (pair != NULL && table->keycmp(key, pair->key) != 0) + hashValue = table->hash(key) % table->numOfBuckets; + + pair = table->bucketArray[hashValue]; + + while (pair && !table->keyCompare(key, pair->key)) pair = pair->next; return pair; } -static int pointercmp(void* pointer1, void* pointer2) -{ - return (pointer1 != pointer2); -} - -static unsigned long pointerHashFunction(void* pointer) -{ - return ((unsigned long) pointer) >> 4; -} - /** * C equivalent of the C# Hashtable Class: * http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx @@ -179,35 +200,51 @@ int HashTable_Count(wHashTable* table) int HashTable_Add(wHashTable* table, void* key, void* value) { int status = 0; - long hashValue; + UINT32 hashValue; wKeyValuePair* pair; wKeyValuePair* newPair; if (!key || !value) return -1; + if (table->keyClone) + { + key = table->keyClone(key); + + if (!key) + return -1; + } + + if (table->valueClone) + { + value = table->valueClone(value); + + if (!value) + return -1; + } + if (table->synchronized) EnterCriticalSection(&table->lock); - hashValue = table->hashFunction(key) % table->numOfBuckets; + hashValue = table->hash(key) % table->numOfBuckets; pair = table->bucketArray[hashValue]; - while (pair != NULL && table->keycmp(key, pair->key) != 0) + while (pair && !table->keyCompare(key, pair->key)) pair = pair->next; if (pair) { if (pair->key != key) { - if (table->keyDeallocator) - table->keyDeallocator((void*) pair->key); + if (table->keyFree) + table->keyFree(pair->key); pair->key = key; } if (pair->value != value) { - if (table->valueDeallocator) - table->valueDeallocator(pair->value); + if (table->valueFree) + table->valueFree(pair->value); pair->value = value; } } @@ -249,15 +286,19 @@ int HashTable_Add(wHashTable* table, void* key, void* value) BOOL HashTable_Remove(wHashTable* table, void* key) { + UINT32 hashValue; BOOL status = TRUE; - long hashValue = table->hashFunction(key) % table->numOfBuckets; - wKeyValuePair* pair = table->bucketArray[hashValue]; + wKeyValuePair* pair = NULL; wKeyValuePair* previousPair = NULL; if (table->synchronized) EnterCriticalSection(&table->lock); - while (pair && table->keycmp(key, pair->key) != 0) + hashValue = table->hash(key) % table->numOfBuckets; + + pair = table->bucketArray[hashValue]; + + while (pair && !table->keyCompare(key, pair->key)) { previousPair = pair; pair = pair->next; @@ -269,11 +310,11 @@ BOOL HashTable_Remove(wHashTable* table, void* key) } else { - if (table->keyDeallocator) - table->keyDeallocator((void*) pair->key); + if (table->keyFree) + table->keyFree(pair->key); - if (table->valueDeallocator) - table->valueDeallocator(pair->value); + if (table->valueFree) + table->valueFree(pair->value); if (previousPair) previousPair->next = pair->next; @@ -331,6 +372,14 @@ BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value) BOOL status = TRUE; wKeyValuePair* pair; + if (table->valueClone && value) + { + value = table->valueClone(value); + + if (!value) + return FALSE; + } + if (table->synchronized) EnterCriticalSection(&table->lock); @@ -368,14 +417,11 @@ void HashTable_Clear(wHashTable* table) { nextPair = pair->next; - if (table->pfnKeyValueFree) - table->pfnKeyValueFree(table->context, pair->key, pair->value); + if (table->keyFree) + table->keyFree(pair->key); - if (table->keyDeallocator) - table->keyDeallocator((void*) pair->key); - - if (table->valueDeallocator) - table->valueDeallocator(pair->value); + if (table->valueFree) + table->valueFree(pair->value); free(pair); @@ -410,8 +456,17 @@ int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys) iKey = 0; count = table->numOfElements; + pKeys = (ULONG_PTR*) calloc(count, sizeof(ULONG_PTR)); + if (!pKeys) + { + if (table->synchronized) + LeaveCriticalSection(&table->lock); + + return -1; + } + for (index = 0; index < table->numOfBuckets; index++) { pair = table->bucketArray[index]; @@ -491,7 +546,7 @@ BOOL HashTable_ContainsValue(wHashTable* table, void* value) while (pair) { - if (table->valuecmp(value, pair->value) == 0) + if (table->valueCompare(value, pair->value)) { status = TRUE; break; @@ -510,19 +565,12 @@ BOOL HashTable_ContainsValue(wHashTable* table, void* value) return status; } -void HashTable_SetFreeFunction(wHashTable* table, void* context, KEY_VALUE_FREE_FN pfnKeyValueFree) -{ - table->context = context; - table->pfnKeyValueFree = pfnKeyValueFree; -} - /** * Construction, Destruction */ wHashTable* HashTable_New(BOOL synchronized) { - int index; wHashTable* table; table = (wHashTable*) calloc(1, sizeof(wHashTable)); @@ -530,12 +578,13 @@ wHashTable* HashTable_New(BOOL synchronized) if (table) { table->synchronized = synchronized; + InitializeCriticalSectionAndSpinCount(&(table->lock), 4000); table->numOfBuckets = 64; table->numOfElements = 0; - table->bucketArray = (wKeyValuePair**) malloc(table->numOfBuckets * sizeof(wKeyValuePair*)); + table->bucketArray = (wKeyValuePair**) calloc(table->numOfBuckets, sizeof(wKeyValuePair*)); if (!table->bucketArray) { @@ -543,18 +592,17 @@ wHashTable* HashTable_New(BOOL synchronized) return NULL; } - for (index = 0; index < table->numOfBuckets; index++) - table->bucketArray[index] = NULL; - table->idealRatio = 3.0; table->lowerRehashThreshold = 0.0; table->upperRehashThreshold = 15.0; - table->keycmp = pointercmp; - table->valuecmp = pointercmp; - table->hashFunction = pointerHashFunction; - table->keyDeallocator = NULL; - table->valueDeallocator = NULL; + table->hash = HashTable_PointerHash; + table->keyCompare = HashTable_PointerCompare; + table->valueCompare = HashTable_PointerCompare; + table->keyClone = NULL; + table->valueClone = NULL; + table->keyFree = NULL; + table->valueFree = NULL; } return table; @@ -576,11 +624,11 @@ void HashTable_Free(wHashTable* table) { nextPair = pair->next; - if (table->keyDeallocator) - table->keyDeallocator((void*) pair->key); + if (table->keyFree) + table->keyFree(pair->key); - if (table->valueDeallocator) - table->valueDeallocator(pair->value); + if (table->valueFree) + table->valueFree(pair->value); free(pair); diff --git a/winpr/libwinpr/utils/collections/LinkedList.c b/winpr/libwinpr/utils/collections/LinkedList.c index 5cac91bed..939e85189 100644 --- a/winpr/libwinpr/utils/collections/LinkedList.c +++ b/winpr/libwinpr/utils/collections/LinkedList.c @@ -124,11 +124,13 @@ void LinkedList_Clear(wLinkedList* list) * Adds a new node containing the specified value at the start of the LinkedList. */ -void LinkedList_AddFirst(wLinkedList* list, void* value) +BOOL LinkedList_AddFirst(wLinkedList* list, void* value) { wLinkedListNode* node; node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + if (!node) + return FALSE; node->prev = node->next = NULL; node->value = value; @@ -144,17 +146,20 @@ void LinkedList_AddFirst(wLinkedList* list, void* value) } list->count++; + return TRUE; } /** * Adds a new node containing the specified value at the end of the LinkedList. */ -void LinkedList_AddLast(wLinkedList* list, void* value) +BOOL LinkedList_AddLast(wLinkedList* list, void* value) { wLinkedListNode* node; node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + if (!node) + return FALSE; node->prev = node->next = NULL; node->value = value; @@ -170,13 +175,14 @@ void LinkedList_AddLast(wLinkedList* list, void* value) } list->count++; + return TRUE; } /** * Removes the first occurrence of the specified value from the LinkedList. */ -void LinkedList_Remove(wLinkedList* list, void* value) +BOOL LinkedList_Remove(wLinkedList* list, void* value) { wLinkedListNode* node; @@ -201,12 +207,12 @@ void LinkedList_Remove(wLinkedList* list, void* value) free(node); list->count--; - - break; + return TRUE; } node = node->next; } + return FALSE; } /** @@ -300,7 +306,7 @@ BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list) { if (list->initial) list->initial = 0; - else + else if (list->current) list->current = list->current->next; if (!list->current) diff --git a/winpr/libwinpr/utils/collections/MessageQueue.c b/winpr/libwinpr/utils/collections/MessageQueue.c index b4dc6c295..8b8ec1e15 100644 --- a/winpr/libwinpr/utils/collections/MessageQueue.c +++ b/winpr/libwinpr/utils/collections/MessageQueue.c @@ -111,6 +111,7 @@ void MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* w message.id = type; message.wParam = wParam; message.lParam = lParam; + message.Free = NULL; MessageQueue_Dispatch(queue, &message); } diff --git a/winpr/libwinpr/utils/collections/ObjectPool.c b/winpr/libwinpr/utils/collections/ObjectPool.c index bca31edfd..b479c3b1b 100644 --- a/winpr/libwinpr/utils/collections/ObjectPool.c +++ b/winpr/libwinpr/utils/collections/ObjectPool.c @@ -116,12 +116,10 @@ wObjectPool* ObjectPool_New(BOOL synchronized) { wObjectPool* pool = NULL; - pool = (wObjectPool*) malloc(sizeof(wObjectPool)); + pool = (wObjectPool*) calloc(1, sizeof(wObjectPool)); if (pool) { - ZeroMemory(pool, sizeof(wObjectPool)); - pool->synchronized = synchronized; if (pool->synchronized) diff --git a/winpr/libwinpr/utils/corkscrew/backtrace.h b/winpr/libwinpr/utils/corkscrew/backtrace.h new file mode 100644 index 000000000..a24ac21aa --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/backtrace.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +/* A stack unwinder. */ + +#ifndef _CORKSCREW_BACKTRACE_H +#define _CORKSCREW_BACKTRACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + + /* + * Describes a single frame of a backtrace. + */ + typedef struct + { + uintptr_t absolute_pc; /* absolute PC offset */ + uintptr_t stack_top; /* top of stack for this frame */ + size_t stack_size; /* size of this stack frame */ + } backtrace_frame_t; + + /* + * Describes the symbols associated with a backtrace frame. + */ + typedef struct + { + uintptr_t relative_pc; /* relative frame PC offset from the start of the library, + or the absolute PC if the library is unknown */ + uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the + library or 0 if the library is unknown */ + char *map_name; /* executable or library name, or NULL if unknown */ + char *symbol_name; /* symbol name, or NULL if unknown */ + char *demangled_name; /* demangled symbol name, or NULL if unknown */ + } backtrace_symbol_t; + + /* + * Unwinds the call stack for the current thread of execution. + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + */ + ssize_t unwind_backtrace(backtrace_frame_t *backtrace, size_t ignore_depth, size_t max_depth); + + /* + * Unwinds the call stack for a thread within this process. + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + * + * The task is briefly suspended while the backtrace is being collected. + */ + ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t *backtrace, + size_t ignore_depth, size_t max_depth); + + /* + * Unwinds the call stack of a task within a remote process using ptrace(). + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + */ + ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t *context, + backtrace_frame_t *backtrace, size_t ignore_depth, size_t max_depth); + + /* + * Gets the symbols for each frame of a backtrace. + * The symbols array must be big enough to hold one symbol record per frame. + * The symbols must later be freed using free_backtrace_symbols. + */ + void get_backtrace_symbols(const backtrace_frame_t *backtrace, size_t frames, + backtrace_symbol_t *backtrace_symbols); + + /* + * Gets the symbols for each frame of a backtrace from a remote process. + * The symbols array must be big enough to hold one symbol record per frame. + * The symbols must later be freed using free_backtrace_symbols. + */ + void get_backtrace_symbols_ptrace(const ptrace_context_t *context, + const backtrace_frame_t *backtrace, size_t frames, + backtrace_symbol_t *backtrace_symbols); + + /* + * Frees the storage associated with backtrace symbols. + */ + void free_backtrace_symbols(backtrace_symbol_t *backtrace_symbols, size_t frames); + + enum + { + // A hint for how big to make the line buffer for format_backtrace_line + MAX_BACKTRACE_LINE_LENGTH = 800, + }; + + /** + * Formats a line from a backtrace as a zero-terminated string into the specified buffer. + */ + void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t *frame, + const backtrace_symbol_t *symbol, char *buffer, size_t bufferSize); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_BACKTRACE_H diff --git a/winpr/libwinpr/utils/corkscrew/demangle.h b/winpr/libwinpr/utils/corkscrew/demangle.h new file mode 100644 index 000000000..04b022554 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/demangle.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +/* C++ symbol name demangling. */ + +#ifndef _CORKSCREW_DEMANGLE_H +#define _CORKSCREW_DEMANGLE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Demangles a C++ symbol name. + * If name is NULL or if the name cannot be demangled, returns NULL. + * Otherwise, returns a newly allocated string that contains the demangled name. + * + * The caller must free the returned string using free(). + */ +char* demangle_symbol_name(const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_DEMANGLE_H diff --git a/winpr/libwinpr/utils/corkscrew/map_info.h b/winpr/libwinpr/utils/corkscrew/map_info.h new file mode 100644 index 000000000..14bfad67d --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/map_info.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +/* Process memory map. */ + +#ifndef _CORKSCREW_MAP_INFO_H +#define _CORKSCREW_MAP_INFO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct map_info { + struct map_info* next; + uintptr_t start; + uintptr_t end; + bool is_readable; + bool is_writable; + bool is_executable; + void* data; // arbitrary data associated with the map by the user, initially NULL + char name[]; +} map_info_t; + +/* Loads memory map from /proc//maps. */ +map_info_t* load_map_info_list(pid_t tid); + +/* Frees memory map. */ +void free_map_info_list(map_info_t* milist); + +/* Finds the memory map that contains the specified address. */ +const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr); + +/* Returns true if the addr is in a readable map. */ +bool is_readable_map(const map_info_t* milist, uintptr_t addr); +/* Returns true if the addr is in a writable map. */ +bool is_writable_map(const map_info_t* milist, uintptr_t addr); +/* Returns true if the addr is in an executable map. */ +bool is_executable_map(const map_info_t* milist, uintptr_t addr); + +/* Acquires a reference to the memory map for this process. + * The result is cached and refreshed automatically. + * Make sure to release the map info when done. */ +map_info_t* acquire_my_map_info_list(); + +/* Releases a reference to the map info for this process that was + * previous acquired using acquire_my_map_info_list(). */ +void release_my_map_info_list(map_info_t* milist); + +/* Flushes the cached memory map so the next call to + * acquire_my_map_info_list() gets fresh data. */ +void flush_my_map_info_list(); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_MAP_INFO_H diff --git a/winpr/libwinpr/utils/corkscrew/ptrace.h b/winpr/libwinpr/utils/corkscrew/ptrace.h new file mode 100644 index 000000000..76276d89a --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/ptrace.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +/* Useful ptrace() utility functions. */ + +#ifndef _CORKSCREW_PTRACE_H +#define _CORKSCREW_PTRACE_H + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Stores information about a process that is used for several different + * ptrace() based operations. */ +typedef struct { + map_info_t* map_info_list; +} ptrace_context_t; + +/* Describes how to access memory from a process. */ +typedef struct { + pid_t tid; + const map_info_t* map_info_list; +} memory_t; + +#if __i386__ +/* ptrace() register context. */ +typedef struct pt_regs_x86 { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t xds; + uint32_t xes; + uint32_t xfs; + uint32_t xgs; + uint32_t orig_eax; + uint32_t eip; + uint32_t xcs; + uint32_t eflags; + uint32_t esp; + uint32_t xss; +} pt_regs_x86_t; +#endif + +#if __mips__ +/* ptrace() GET_REGS context. */ +typedef struct pt_regs_mips { + uint64_t regs[32]; + uint64_t lo; + uint64_t hi; + uint64_t cp0_epc; + uint64_t cp0_badvaddr; + uint64_t cp0_status; + uint64_t cp0_cause; +} pt_regs_mips_t; +#endif + +/* + * Initializes a memory structure for accessing memory from this process. + */ +void init_memory(memory_t* memory, const map_info_t* map_info_list); + +/* + * Initializes a memory structure for accessing memory from another process + * using ptrace(). + */ +void init_memory_ptrace(memory_t* memory, pid_t tid); + +/* + * Reads a word of memory safely. + * If the memory is local, ensures that the address is readable before dereferencing it. + * Returns false and a value of 0xffffffff if the word could not be read. + */ +bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value); + +/* + * Reads a word of memory safely using ptrace(). + * Returns false and a value of 0xffffffff if the word could not be read. + */ +bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value); + +/* + * Loads information needed for examining a remote process using ptrace(). + * The caller must already have successfully attached to the process + * using ptrace(). + * + * The context can be used for any threads belonging to that process + * assuming ptrace() is attached to them before performing the actual + * unwinding. The context can continue to be used to decode backtraces + * even after ptrace() has been detached from the process. + */ +ptrace_context_t* load_ptrace_context(pid_t pid); + +/* + * Frees a ptrace context. + */ +void free_ptrace_context(ptrace_context_t* context); + +/* + * Finds a symbol using ptrace. + * Returns the containing map and information about the symbol, or + * NULL if one or the other is not available. + */ +void find_symbol_ptrace(const ptrace_context_t* context, + uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_PTRACE_H diff --git a/winpr/libwinpr/utils/corkscrew/symbol_table.h b/winpr/libwinpr/utils/corkscrew/symbol_table.h new file mode 100644 index 000000000..4998750bf --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/symbol_table.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 _CORKSCREW_SYMBOL_TABLE_H +#define _CORKSCREW_SYMBOL_TABLE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uintptr_t start; + uintptr_t end; + char* name; +} symbol_t; + +typedef struct { + symbol_t* symbols; + size_t num_symbols; +} symbol_table_t; + +/* + * Loads a symbol table from a given file. + * Returns NULL on error. + */ +symbol_table_t* load_symbol_table(const char* filename); + +/* + * Frees a symbol table. + */ +void free_symbol_table(symbol_table_t* table); + +/* + * Finds a symbol associated with an address in the symbol table. + * Returns NULL if not found. + */ +const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_SYMBOL_TABLE_H diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c new file mode 100644 index 000000000..d76f1ac8a --- /dev/null +++ b/winpr/libwinpr/utils/debug.c @@ -0,0 +1,340 @@ +/** + * WinPR: Windows Portable Runtime + * Debugging Utils + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * 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 + +#if defined(HAVE_EXECINFO_H) +#include +#endif + +#if defined(ANDROID) +#include +#endif + +#include +#include +#include + +#define TAG "com.winpr.utils.debug" +#define LOGT(...) do { WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); } while(0) +#define LOGD(...) do { WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); } while(0) +#define LOGI(...) do { WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); } while(0) +#define LOGW(...) do { WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); } while(0) +#define LOGE(...) do { WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); } while(0) +#define LOGF(...) do { WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); } while(0) + +static const char *support_msg = "Invalid stacktrace buffer! check if platform is supported!"; + +#if defined(HAVE_EXECINFO_H) +typedef struct +{ + void **buffer; + size_t max; + size_t used; +} t_execinfo; +#endif + +#if defined(ANDROID) +#include +#include +#include + +typedef struct +{ + backtrace_frame_t *buffer; + size_t max; + size_t used; +} t_corkscrew_data; + +typedef struct +{ + void *hdl; + ssize_t (*unwind_backtrace)(backtrace_frame_t *backtrace, size_t ignore_depth, size_t max_depth); + ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t *backtrace, + size_t ignore_depth, size_t max_depth); + ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t *context, + backtrace_frame_t *backtrace, size_t ignore_depth, size_t max_depth); + void (*get_backtrace_symbols)(const backtrace_frame_t *backtrace, size_t frames, + backtrace_symbol_t *backtrace_symbols); + void (*get_backtrace_symbols_ptrace)(const ptrace_context_t *context, + const backtrace_frame_t *backtrace, size_t frames, + backtrace_symbol_t *backtrace_symbols); + void (*free_backtrace_symbols)(backtrace_symbol_t *backtrace_symbols, size_t frames); + void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t *frame, + const backtrace_symbol_t *symbol, char *buffer, size_t bufferSize); +} t_corkscrew; + +static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static t_corkscrew *fkt = NULL; + +void load_library(void) +{ + static t_corkscrew lib; + { + lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY); + + if (!lib.hdl) + { + LOGF("dlopen error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace"); + + if (!lib.unwind_backtrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread"); + + if (!lib.unwind_backtrace_thread) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace"); + + if (!lib.unwind_backtrace_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols"); + + if (!lib.get_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace"); + + if (!lib.get_backtrace_symbols_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols"); + + if (!lib.free_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line"); + + if (!lib.format_backtrace_line) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + fkt = &lib; + return; + } +fail: + { + if (lib.hdl) + dlclose(lib.hdl); + + fkt = NULL; + } +} +#endif + +void winpr_backtrace_free(void *buffer) +{ + if (!buffer) + { + LOGF(support_msg); + return; + } + +#if defined(HAVE_EXECINFO_H) + t_execinfo *data = (t_execinfo *)buffer; + + if (data->buffer) + free(data->buffer); + + free(data); +#elif defined(ANDROID) + t_corkscrew_data *data = (t_corkscrew_data *)buffer; + + if (data->buffer) + free(data->buffer); + + free(data); +#else + LOGF(support_msg); +#endif +} + +void *winpr_backtrace(DWORD size) +{ +#if defined(HAVE_EXECINFO_H) + t_execinfo *data = calloc(1, sizeof(t_execinfo)); + + if (!data) + return NULL; + + data->buffer = calloc(size, sizeof(void *)); + + if (!data->buffer) + return NULL; + + data->max = size; + data->used = backtrace(data->buffer, size); + return data; +#elif defined(ANDROID) + t_corkscrew_data *data = calloc(1, sizeof(t_corkscrew_data)); + + if (!data) + return NULL; + + data->buffer = calloc(size, sizeof(backtrace_frame_t)); + + if (!data->buffer) + { + free(data); + return NULL; + } + + pthread_once(&initialized, load_library); + data->max = size; + data->used = fkt->unwind_backtrace(data->buffer, 0, size); + return data; +#else + LOGF(support_msg); + return NULL; +#endif +} + +char **winpr_backtrace_symbols(void *buffer, size_t *used) +{ + if (used) + *used = 0; + + if (!buffer) + { + LOGF(support_msg); + return NULL; + } + +#if defined(HAVE_EXECINFO_H) + t_execinfo *data = (t_execinfo *)buffer; + assert(data); + + if (used) + *used = data->used; + + return backtrace_symbols(data->buffer, data->used); +#elif defined(ANDROID) + t_corkscrew_data *data = (t_corkscrew_data *)buffer; + assert(data); + pthread_once(&initialized, load_library); + + if (!fkt) + { + LOGF(support_msg); + return NULL; + } + else + { + size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t i; + char *lines = calloc(data->used + 1, sizeof(char *) * line_len); + char **vlines = (char **)lines; + backtrace_symbol_t *symbols = calloc(data->used, sizeof(backtrace_symbol_t));; + + if (!lines || !symbols) + { + if (lines) + free(lines); + + if (symbols) + free(symbols); + + return NULL; + } + + /* To allow a char** malloced array to be returned, allocate n+1 lines + * and fill in the first lines[i] char with the address of lines[(i+1) * 1024] */ + for (i=0; iused; i++) + vlines[i] = &lines[(i + 1) * line_len]; + + fkt->get_backtrace_symbols(data->buffer, data->used, symbols); + + for (i=0; iused; i++) + fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len); + + fkt->free_backtrace_symbols(symbols, data->used); + + if (used) + *used = data->used; + + return (char **)lines; + } + +#else + LOGF(support_msg); + return NULL; +#endif +} + +void winpr_backtrace_symbols_fd(void *buffer, int fd) +{ + if (!buffer) + { + LOGF(support_msg); + return; + } + +#if defined(HAVE_EXECINFO_H) + t_execinfo *data = (t_execinfo *)buffer; + assert(data); + backtrace_symbols_fd(data->buffer, data->used, fd); +#elif defined(ANDROID) + size_t used; + t_corkscrew_data *data = (t_corkscrew_data *)buffer; + assert(data); + char **lines = winpr_backtrace_symbols(buffer, &used); + + if (lines) + { + DWORD i; + + for (i=0; i + * + * 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 "lodepng/lodepng.h" + +#include "../log.h" +#define TAG WINPR_TAG("utils.image") + +/** + * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book + */ + +int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, int bpp) +{ + FILE* fp; + WINPR_BITMAP_FILE_HEADER bf; + WINPR_BITMAP_INFO_HEADER bi; + + fp = fopen(filename, "w+b"); + + if (!fp) + { + WLog_ERR(TAG, "failed to open file %s", filename); + return -1; + } + + bf.bfType[0] = 'B'; + bf.bfType[1] = 'M'; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + bf.bfOffBits = sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER); + bi.biSizeImage = width * height * (bpp / 8); + bf.bfSize = bf.bfOffBits + bi.biSizeImage; + + bi.biWidth = width; + bi.biHeight = -1 * height; + bi.biPlanes = 1; + bi.biBitCount = bpp; + bi.biCompression = 0; + bi.biXPelsPerMeter = width; + bi.biYPelsPerMeter = height; + bi.biClrUsed = 0; + bi.biClrImportant = 0; + bi.biSize = sizeof(WINPR_BITMAP_INFO_HEADER); + + fwrite((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp); + fwrite((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp); + fwrite((void*) data, bi.biSizeImage, 1, fp); + + fclose(fp); + + return 1; +} + +int winpr_image_write(wImage* image, const char* filename) +{ + int status = -1; + + if (image->type == WINPR_IMAGE_BITMAP) + { + status = winpr_bitmap_write(filename, image->data, image->width, image->height, image->bitsPerPixel); + } + else + { + int lodepng_status; + + lodepng_status = lodepng_encode32_file(filename, image->data, image->width, image->height); + + status = (lodepng_status) ? -1 : 1; + } + + return status; +} + +int winpr_image_png_read_fp(wImage* image, FILE* fp) +{ + int size; + BYTE* data; + UINT32 width; + UINT32 height; + int lodepng_status; + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + data = (BYTE*) malloc(size); + + if (!data) + return -1; + + fread((void*) data, size, 1, fp); + + fclose(fp); + + lodepng_status = lodepng_decode32(&(image->data), &width, &height, data, size); + + free(data); + + if (lodepng_status) + return -1; + + image->width = width; + image->height = height; + + image->bitsPerPixel = 32; + image->bytesPerPixel = 4; + image->scanline = image->bytesPerPixel * image->width; + + return 1; +} + +int winpr_image_png_read_buffer(wImage* image, BYTE* buffer, int size) +{ + UINT32 width; + UINT32 height; + int lodepng_status; + + lodepng_status = lodepng_decode32(&(image->data), &width, &height, buffer, size); + + if (lodepng_status) + return -1; + + image->width = width; + image->height = height; + + image->bitsPerPixel = 32; + image->bytesPerPixel = 4; + image->scanline = image->bytesPerPixel * image->width; + + return 1; +} + +int winpr_image_bitmap_read_fp(wImage* image, FILE* fp) +{ + int index; + BOOL vFlip; + BYTE* pDstData; + WINPR_BITMAP_FILE_HEADER bf; + WINPR_BITMAP_INFO_HEADER bi; + + fread((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp); + + if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M')) + return -1; + + image->type = WINPR_IMAGE_BITMAP; + + fread((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp); + + if (ftell(fp) != bf.bfOffBits) + { + fseek(fp, bf.bfOffBits, SEEK_SET); + } + + image->width = bi.biWidth; + + if (bi.biHeight < 0) + { + vFlip = FALSE; + image->height = -1 * bi.biHeight; + } + else + { + vFlip = TRUE; + image->height = bi.biHeight; + } + + image->bitsPerPixel = bi.biBitCount; + image->bytesPerPixel = (image->bitsPerPixel / 8); + image->scanline = (bi.biSizeImage / bi.biHeight); + + image->data = (BYTE*) malloc(bi.biSizeImage); + + if (!image->data) + return -1; + + if (!vFlip) + { + fread((void*) image->data, bi.biSizeImage, 1, fp); + } + else + { + pDstData = &(image->data[(image->height - 1) * image->scanline]); + + for (index = 0; index < image->height; index++) + { + fread((void*) pDstData, image->scanline, 1, fp); + pDstData -= image->scanline; + } + } + + fclose(fp); + + return 1; +} + +int winpr_image_bitmap_read_buffer(wImage* image, BYTE* buffer, int size) +{ + int index; + BOOL vFlip; + BYTE* pSrcData; + BYTE* pDstData; + WINPR_BITMAP_FILE_HEADER bf; + WINPR_BITMAP_INFO_HEADER bi; + + pSrcData = buffer; + + CopyMemory(&bf, pSrcData, sizeof(WINPR_BITMAP_FILE_HEADER)); + pSrcData += sizeof(WINPR_BITMAP_FILE_HEADER); + + if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M')) + return -1; + + image->type = WINPR_IMAGE_BITMAP; + + CopyMemory(&bi, pSrcData, sizeof(WINPR_BITMAP_INFO_HEADER)); + pSrcData += sizeof(WINPR_BITMAP_INFO_HEADER); + + if ((pSrcData - buffer) != bf.bfOffBits) + { + pSrcData = &buffer[bf.bfOffBits]; + } + + image->width = bi.biWidth; + + if (bi.biHeight < 0) + { + vFlip = FALSE; + image->height = -1 * bi.biHeight; + } + else + { + vFlip = TRUE; + image->height = bi.biHeight; + } + + image->bitsPerPixel = bi.biBitCount; + image->bytesPerPixel = (image->bitsPerPixel / 8); + image->scanline = (bi.biSizeImage / bi.biHeight); + + image->data = (BYTE*) malloc(bi.biSizeImage); + + if (!image->data) + return -1; + + if (!vFlip) + { + CopyMemory(image->data, pSrcData, bi.biSizeImage); + pSrcData += bi.biSizeImage; + } + else + { + pDstData = &(image->data[(image->height - 1) * image->scanline]); + + for (index = 0; index < image->height; index++) + { + CopyMemory(pDstData, pSrcData, image->scanline); + pSrcData += image->scanline; + pDstData -= image->scanline; + } + } + + return 1; +} + +int winpr_image_read(wImage* image, const char* filename) +{ + FILE* fp; + BYTE sig[8]; + int status = -1; + + fp = fopen(filename, "r+b"); + + if (!fp) + { + WLog_ERR(TAG, "failed to open file %s", filename); + return -1; + } + + fread((void*) &sig, sizeof(sig), 1, fp); + fseek(fp, 0, SEEK_SET); + + if ((sig[0] == 'B') && (sig[1] == 'M')) + { + image->type = WINPR_IMAGE_BITMAP; + status = winpr_image_bitmap_read_fp(image, fp); + } + else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') && + (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) + { + image->type = WINPR_IMAGE_PNG; + status = winpr_image_png_read_fp(image, fp); + } + else + { + fclose(fp); + } + + return status; +} + +int winpr_image_read_buffer(wImage* image, BYTE* buffer, int size) +{ + BYTE sig[8]; + int status = -1; + + if (size < 8) + return -1; + + CopyMemory(sig, buffer, 8); + + if ((sig[0] == 'B') && (sig[1] == 'M')) + { + image->type = WINPR_IMAGE_BITMAP; + status = winpr_image_bitmap_read_buffer(image, buffer, size); + } + else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') && + (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) + { + image->type = WINPR_IMAGE_PNG; + status = winpr_image_png_read_buffer(image, buffer, size); + } + + return status; +} + +wImage* winpr_image_new() +{ + wImage* image; + + image = (wImage*) calloc(1, sizeof(wImage)); + + if (!image) + return NULL; + + return image; +} + +void winpr_image_free(wImage* image, BOOL bFreeBuffer) +{ + if (!image) + return; + + if (bFreeBuffer) + free(image->data); + + free(image); +} diff --git a/winpr/libwinpr/utils/ini.c b/winpr/libwinpr/utils/ini.c index 64163ad0c..3b34fe0f2 100644 --- a/winpr/libwinpr/utils/ini.c +++ b/winpr/libwinpr/utils/ini.c @@ -43,6 +43,10 @@ int IniFile_Load_String(wIniFile* ini, const char* iniString) return -1; ini->buffer = (char*) malloc(fileSize + 2); + + if (!ini->buffer) + return -1; + CopyMemory(ini->buffer, iniString, fileSize); ini->buffer[fileSize] = '\n'; @@ -53,25 +57,26 @@ int IniFile_Load_String(wIniFile* ini, const char* iniString) return 1; } -int IniFile_Load_File(wIniFile* ini, const char* filename) +int IniFile_Open_File(wIniFile* ini, const char* filename) { - long int fileSize; - if (ini->readOnly) - { ini->fp = fopen(filename, "r"); - } else - { - ini->fp = fopen(filename, "r+"); - - if (!ini->fp) - ini->fp = fopen(filename, "w+"); - } + ini->fp = fopen(filename, "w+"); if (!ini->fp) return -1; + return 1; +} + +int IniFile_Load_File(wIniFile* ini, const char* filename) +{ + int fileSize; + + if (IniFile_Open_File(ini, filename) < 0) + return -1; + fseek(ini->fp, 0, SEEK_END); fileSize = ftell(ini->fp); fseek(ini->fp, 0, SEEK_SET); @@ -85,6 +90,9 @@ int IniFile_Load_File(wIniFile* ini, const char* filename) ini->buffer = (char*) malloc(fileSize + 2); + if (!ini->buffer) + return -1; + if (fread(ini->buffer, fileSize, 1, ini->fp) != 1) { free(ini->buffer); @@ -92,6 +100,9 @@ int IniFile_Load_File(wIniFile* ini, const char* filename) return -1; } + fclose(ini->fp); + ini->fp = NULL; + ini->buffer[fileSize] = '\n'; ini->buffer[fileSize + 1] = '\0'; @@ -147,11 +158,12 @@ wIniFileKey* IniFile_Key_New(const char* name, const char* value) void IniFile_Key_Free(wIniFileKey* key) { - if (key) - { - free(key->name); - free(key->value); - } + if (!key) + return; + + free(key->name); + free(key->value); + free(key); } wIniFileSection* IniFile_Section_New(const char* name) @@ -169,41 +181,109 @@ wIniFileSection* IniFile_Section_New(const char* name) void IniFile_Section_Free(wIniFileSection* section) { - if (section) - { - free(section); - } -} + int index; -int IniFile_AddSection(wIniFile* ini, const char* name) -{ - if ((ini->nSections + 1) >= (ini->cSections)) - { - ini->cSections *= 2; - ini->sections = (wIniFileSection**) realloc(ini->sections, sizeof(wIniFileSection*) * ini->cSections); - } - - ini->sections[ini->nSections] = IniFile_Section_New(name); - ini->nSections++; - - return 1; -} - -int IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name, const char* value) -{ if (!section) - return -1; - - if ((section->nKeys + 1) >= (section->cKeys)) + return; + + for (index = 0; index < section->nKeys; index++) { - section->cKeys *= 2; - section->keys = (wIniFileKey**) realloc(section->keys, sizeof(wIniFileKey*) * section->cKeys); + IniFile_Key_Free(section->keys[index]); } - section->keys[section->nKeys] = IniFile_Key_New(name, value); - section->nKeys++; + free(section); +} - return 1; +wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name) +{ + int index; + wIniFileSection* section = NULL; + + for (index = 0; index < ini->nSections; index++) + { + if (_stricmp(name, ini->sections[index]->name) == 0) + { + section = ini->sections[index]; + break; + } + } + + return section; +} + +wIniFileSection* IniFile_AddSection(wIniFile* ini, const char* name) +{ + wIniFileSection* section; + + if (!name) + return NULL; + + section = IniFile_GetSection(ini, name); + + if (!section) + { + if ((ini->nSections + 1) >= (ini->cSections)) + { + ini->cSections *= 2; + ini->sections = (wIniFileSection**) realloc(ini->sections, sizeof(wIniFileSection*) * ini->cSections); + } + + section = IniFile_Section_New(name); + ini->sections[ini->nSections] = section; + ini->nSections++; + } + + return section; +} + +wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name) +{ + int index; + wIniFileKey* key = NULL; + + for (index = 0; index < section->nKeys; index++) + { + if (_stricmp(name, section->keys[index]->name) == 0) + { + key = section->keys[index]; + break; + } + } + + return key; +} + +wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name, const char* value) +{ + wIniFileKey* key; + + if (!section) + return NULL; + + if (!name) + return NULL; + + key = IniFile_GetKey(ini, section, name); + + if (!key) + { + if ((section->nKeys + 1) >= (section->cKeys)) + { + section->cKeys *= 2; + section->keys = (wIniFileKey**) realloc(section->keys, sizeof(wIniFileKey*) * section->cKeys); + } + + key = IniFile_Key_New(name, value); + section->keys[section->nKeys] = key; + section->nKeys++; + } + else + { + free(key->value); + key->value = _strdup(value); + } + + return key; } int IniFile_Load(wIniFile* ini) @@ -277,14 +357,14 @@ int IniFile_Load(wIniFile* ini) return 1; } -int IniFile_ParseString(wIniFile* ini, const char* iniString) +int IniFile_ReadBuffer(wIniFile* ini, const char* buffer) { int status; ini->readOnly = TRUE; ini->filename = NULL; - status = IniFile_Load_String(ini, iniString); + status = IniFile_Load_String(ini, buffer); if (status < 0) return status; @@ -294,14 +374,16 @@ int IniFile_ParseString(wIniFile* ini, const char* iniString) return status; } -int IniFile_Parse(wIniFile* ini, const char* filename) +int IniFile_ReadFile(wIniFile* ini, const char* filename) { int status; ini->readOnly = TRUE; + + free(ini->filename); ini->filename = _strdup(filename); - status = IniFile_Load_File(ini, ini->filename); + status = IniFile_Load_File(ini, filename); if (status < 0) return status; @@ -311,40 +393,6 @@ int IniFile_Parse(wIniFile* ini, const char* filename) return status; } -wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name) -{ - int index; - wIniFileSection* section = NULL; - - for (index = 0; index < ini->nSections; index++) - { - if (_stricmp(name, ini->sections[index]->name) == 0) - { - section = ini->sections[index]; - break; - } - } - - return section; -} - -wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name) -{ - int index; - wIniFileKey* key = NULL; - - for (index = 0; index < section->nKeys; index++) - { - if (_stricmp(name, section->keys[index]->name) == 0) - { - key = section->keys[index]; - break; - } - } - - return key; -} - char** IniFile_GetSectionNames(wIniFile* ini, int* count) { char* p; @@ -425,12 +473,12 @@ char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count return keyNames; } -char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key) +const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key) { - char* value = NULL; + const char* value = NULL; wIniFileKey* pKey = NULL; wIniFileSection* pSection = NULL; - + pSection = IniFile_GetSection(ini, section); if (!pSection) @@ -441,14 +489,14 @@ char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* if (!pKey) return NULL; - value = pKey->value; + value = (const char*) pKey->value; return value; } -UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key) +int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key) { - UINT32 value = 0; + int value = 0; wIniFileKey* pKey = NULL; wIniFileSection* pSection = NULL; @@ -467,6 +515,137 @@ UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* ke return value; } +int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key, const char* value) +{ + wIniFileKey* pKey = NULL; + wIniFileSection* pSection = NULL; + + pSection = IniFile_GetSection(ini, section); + + if (!pSection) + pSection = IniFile_AddSection(ini, section); + + if (!pSection) + return -1; + + pKey = IniFile_AddKey(ini, pSection, key, value); + + if (!pKey) + return -1; + + return 1; +} + +int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value) +{ + char strVal[128]; + wIniFileKey* pKey = NULL; + wIniFileSection* pSection = NULL; + + sprintf_s(strVal, sizeof(strVal), "%d", value); + + pSection = IniFile_GetSection(ini, section); + + if (!pSection) + pSection = IniFile_AddSection(ini, section); + + if (!pSection) + return -1; + + pKey = IniFile_AddKey(ini, pSection, key, strVal); + + if (!pKey) + return -1; + + return 1; +} + +char* IniFile_WriteBuffer(wIniFile* ini) +{ + int i, j; + int offset; + int size; + char* buffer; + wIniFileKey* key; + wIniFileSection* section; + + size = 0; + + for (i = 0; i < ini->nSections; i++) + { + section = ini->sections[i]; + size += strlen(section->name) + 3; + + for (j = 0; j < section->nKeys; j++) + { + key = section->keys[j]; + size += strlen(key->name) + strlen(key->value) + 2; + } + + size += 1; + } + + size += 1; + + buffer = malloc(size + 1); + + if (!buffer) + return NULL; + + offset = 0; + + for (i = 0; i < ini->nSections; i++) + { + section = ini->sections[i]; + sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name); + offset += strlen(section->name) + 3; + + for (j = 0; j < section->nKeys; j++) + { + key = section->keys[j]; + sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value); + offset += strlen(key->name) + strlen(key->value) + 2; + } + + sprintf_s(&buffer[offset], size - offset, "\n"); + offset += 1; + } + + buffer[offset] = '\0'; + size += 1; + + return buffer; +} + +int IniFile_WriteFile(wIniFile* ini, const char* filename) +{ + int length; + char* buffer; + + buffer = IniFile_WriteBuffer(ini); + + if (!buffer) + return -1; + + length = strlen(buffer); + + ini->readOnly = FALSE; + + if (!filename) + filename = ini->filename; + + if (IniFile_Open_File(ini, filename) < 0) + return -1; + + fwrite((void*) buffer, length, 1, ini->fp); + + fclose(ini->fp); + + free(buffer); + + return 1; +} + wIniFile* IniFile_New() { wIniFile* ini = (wIniFile*) calloc(1, sizeof(wIniFile)); @@ -483,10 +662,19 @@ wIniFile* IniFile_New() void IniFile_Free(wIniFile* ini) { - if (ini) - { - free(ini->filename); + int index; - free(ini); + if (!ini) + return; + + free(ini->filename); + + for (index = 0; index < ini->nSections; index++) + { + IniFile_Section_Free(ini->sections[index]); } + + free(ini->sections); + + free(ini); } diff --git a/winpr/libwinpr/utils/lodepng/lodepng.c b/winpr/libwinpr/utils/lodepng/lodepng.c new file mode 100644 index 000000000..a65926c41 --- /dev/null +++ b/winpr/libwinpr/utils/lodepng/lodepng.c @@ -0,0 +1,5834 @@ +/* +LodePNG version 20140823 + +Copyright (c) 2005-2014 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#include "lodepng.h" + +#include +#include + +#define VERSION_STRING "20140823" + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_reserve(uivector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} + +/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_copy(uivector* p, const uivector* q) +{ + size_t i; + if(!uivector_resize(p, q->size)) return 0; + for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*resize and give all new elements the value*/ +static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) +{ + size_t oldsize = p->size, i; + if(!ucvector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i = 0; + if(string_resize(out, insize)) + { + for(i = 0; i < insize; i++) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + FILE* file; + long size; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + file = fopen(filename, "rb"); + if(!file) return 78; + + /*get filesize:*/ + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); + + /*read contents of the file into the vector*/ + *outsize = 0; + *out = (unsigned char*)malloc((size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + + fclose(file); + if(!(*out) && size) return 83; /*the above malloc failed*/ + return 0; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + (*bitpointer)++;\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i < nbits; i++) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + (*bitpointer)++; + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i < tree->tree1d.size; i++) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + free(tree->tree2d); + free(tree->tree1d); + free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; n++) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; n++) /*the codes*/ + { + for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/ + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + nodefilled++; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; n++) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned bits, n, error = 0; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; bits++) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n < tree->numcodes; n++) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/* +A coin, this is the terminology used for the package-merge algorithm and the +coin collector's problem. This is used to generate the huffman tree. +A coin can be multiple coins (when they're merged) +*/ +typedef struct Coin +{ + uivector symbols; + float weight; /*the sum of all weights in this coin*/ +} Coin; + +static void coin_init(Coin* c) +{ + uivector_init(&c->symbols); +} + +/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ +static void coin_cleanup(void* c) +{ + uivector_cleanup(&((Coin*)c)->symbols); +} + +static void coin_copy(Coin* c1, const Coin* c2) +{ + c1->weight = c2->weight; + uivector_copy(&c1->symbols, &c2->symbols); +} + +static void add_coins(Coin* c1, const Coin* c2) +{ + size_t i; + for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); + c1->weight += c2->weight; +} + +static void init_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_init(&coins[i]); +} + +static void cleanup_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_cleanup(&coins[i]); +} + +static int coin_compare(const void* a, const void* b) { + float wa = ((const Coin*)a)->weight; + float wb = ((const Coin*)b)->weight; + return wa > wb ? 1 : wa < wb ? -1 : 0; +} + +static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) +{ + unsigned i; + unsigned j = 0; /*index of present symbols*/ + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] != 0) /*only include symbols that are present*/ + { + coins[j].weight = frequencies[i] / (float)sum; + uivector_push_back(&coins[j].symbols, i); + j++; + } + } + return 0; +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i, j; + size_t sum = 0, numpresent = 0; + unsigned error = 0; + Coin* coins; /*the coins of the currently calculated row*/ + Coin* prev_row; /*the previous row of coins*/ + size_t numcoins; + size_t coinmem; + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] > 0) + { + numpresent++; + sum += frequencies[i]; + } + } + + for(i = 0; i < numcodes; i++) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + for(i = 0; i < numcodes; i++) + { + if(frequencies[i]) + { + lengths[i] = 1; + lengths[i == 0 ? 1 : 0] = 1; + break; + } + } + } + else + { + /*Package-Merge algorithm represented by coin collector's problem + For every symbol, maxbitlen coins will be created*/ + + coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ + coins = (Coin*)malloc(sizeof(Coin) * coinmem); + prev_row = (Coin*)malloc(sizeof(Coin) * coinmem); + if(!coins || !prev_row) + { + free(coins); + free(prev_row); + return 83; /*alloc fail*/ + } + init_coins(coins, coinmem); + init_coins(prev_row, coinmem); + + /*first row, lowest denominator*/ + error = append_symbol_coins(coins, frequencies, numcodes, sum); + numcoins = numpresent; + qsort(coins, numcoins, sizeof(Coin), coin_compare); + if(!error) + { + unsigned numprev = 0; + for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ + { + unsigned tempnum; + Coin* tempcoins; + /*swap prev_row and coins, and their amounts*/ + tempcoins = prev_row; prev_row = coins; coins = tempcoins; + tempnum = numprev; numprev = numcoins; numcoins = tempnum; + + cleanup_coins(coins, numcoins); + init_coins(coins, numcoins); + + numcoins = 0; + + /*fill in the merged coins of the previous row*/ + for(i = 0; i + 1 < numprev; i += 2) + { + /*merge prev_row[i] and prev_row[i + 1] into new coin*/ + Coin* coin = &coins[numcoins++]; + coin_copy(coin, &prev_row[i]); + add_coins(coin, &prev_row[i + 1]); + } + /*fill in all the original symbols again*/ + if(j < maxbitlen) + { + error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); + numcoins += numpresent; + } + qsort(coins, numcoins, sizeof(Coin), coin_compare); + } + } + + if(!error) + { + /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ + for(i = 0; i < numpresent - 1; i++) + { + Coin* coin = &coins[i]; + for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++; + } + } + + cleanup_coins(coins, coinmem); + free(coins); + cleanup_coins(prev_row, coinmem); + free(prev_row); + } + + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; i++) bitlen[i] = 8; + for(i = 144; i <= 255; i++) bitlen[i] = 9; + for(i = 256; i <= 279; i++) bitlen[i] = 7; + for(i = 280; i <= 287; i++) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + (*bp)++; + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0; + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + i++; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + i++; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + free(bitlen_cl); + free(bitlen_ll); + free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + (*pos)++; + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + for(forward = 0; forward < length; forward++) + { + out->data[(*pos)] = out->data[backward]; + (*pos)++; + backward++; + if(backward >= start) backward = start - distance; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + /*go to first boundary of byte*/ + size_t p; + unsigned LEN, NLEN, n, error = 0; + while(((*bp) & 0x7) != 0) (*bp)++; + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*linear search implementation*/ + /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; + return array_size - 1;*/ + + /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ + size_t left = 1; + size_t right = array_size - 1; + while(left <= right) + { + size_t mid = (left + right) / 2; + if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ + else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ + else return mid - 1; + } + return array_size - 1; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1; + for(i = 0; i < windowsize; i++) hash->val[i] = -1; + for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; i++) hash->headz[i] = -1; + for(i = 0; i < windowsize; i++) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + free(hash->head); + free(hash->val); + free(hash->chain); + + free(hash->zeros); + free(hash->headz); + free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if (pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i < amount; i++) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while (data != end && *data == 0) data++; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; pos++) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } else { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + pos--; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; i++) + { + pos++; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i < numdeflateblocks; i++) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN % 256)); + ucvector_push_back(out, (unsigned char)(LEN / 256)); + ucvector_push_back(out, (unsigned char)(NLEN % 256)); + ucvector_push_back(out, (unsigned char)(NLEN / 256)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; j++) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i < lz77_encoded->size; i++) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i < lz77_encoded.size; i++) + { + unsigned symbol = lz77_encoded.data[i]; + frequencies_ll.data[symbol]++; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + frequencies_d.data[dist]++; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i < (unsigned)bitlen_lld.size; i++) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + j++; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; k++) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < bitlen_lld_e.size; i++) + { + frequencies_cl.data[bitlen_lld_e.data[i]]++; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) i++; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < tree_cl.numcodes; i++) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i < bitlen_lld_e.size; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + blocksize = insize / 8 + 8; + if(blocksize < 65535) blocksize = 65535; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i < numdeflateblocks && !error; i++) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + amount--; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + unsigned ADLER32; + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]); + free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len) +{ + unsigned c = 0xffffffffL; + size_t n; + + for(n = 0; n < len; n++) + { + c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; i--) + { + result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + (*bitpointer)++; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + (*bitpointer)++; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i < 4; i++) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i < length; i++) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i < a->palettesize * 4; i++) + { + if(a->palette[i] != b->palette[i]) return 0; + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + info->palettesize++; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i < info->palettesize; i++) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return (w * h * lodepng_get_bpp(color) + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; +} + + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return h * ((w * lodepng_get_bpp(color) + 7) / 8); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0; + for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i < 3; i++) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; j++) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->text_num; i++) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + free(info->text_keys); + free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i < source->text_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + free(new_keys); + free(new_strings); + return 83; /*alloc fail*/ + } + + info->text_num++; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->itext_num; i++) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + free(info->itext_keys); + free(info->itext_langtags); + free(info->itext_transkeys); + free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i < source->itext_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + free(new_keys); + free(new_langtags); + free(new_transkeys); + free(new_strings); + return 83; /*alloc fail*/ + } + + info->itext_num++; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) +{ + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i < numbytes; i++) out[i] = in[i]; + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palsize = 1u << mode_out->bitdepth; + if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; + color_tree_init(&tree); + for(i = 0; i < palsize; i++) + { + unsigned char* p = &mode_out->palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i < numpixels; i++) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return 0; /*no error (this function currently never has one, but maybe OOM detection added later.)*/ +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_profile_init(LodePNGColorProfile* profile) +{ + profile->colored = 0; + profile->key = 0; + profile->alpha = 0; + profile->key_r = profile->key_g = profile->key_b = 0; + profile->numcolors = 0; + profile->bits = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +unsigned getValueRequiredBits(unsigned char value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +unsigned get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode->bitdepth == 16) + { + unsigned short r, g, b, a; + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(r % 257u != 0 || g % 257u != 0 || b % 257u != 0 || a % 257u != 0) /*first and second byte differ*/ + { + sixteen = 1; + break; + } + } + } + + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 65535 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + } + else /* < 16-bit */ + { + for(i = 0; i < numpixels; i++) + { + unsigned char r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) + { + if(!color_tree_has(&tree, r, g, b, a)) + { + color_tree_add(&tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + profile->numcolors++; + numcolors_done = profile->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r *= 257; + profile->key_g *= 257; + profile->key_b *= 257; + } + + color_tree_cleanup(&tree); + return error; +} + +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) +{ + LodePNGColorProfile prof; + unsigned error = 0; + unsigned i, n, palettebits, grey_ok, palette_ok; + + lodepng_color_profile_init(&prof); + error = get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; + + if(prof.key && w * h <= 16) prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) + { + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i < prof.numcolors; i++) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } + else /*8-bit or 16-bit per channel*/ + { + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) + { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i < 7; i++) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i < 7; i++) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 29) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i < length; i++) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; i++) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; i++) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; y++) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < olinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediatly filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i < 7; i++) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i < color->palettesize; i++) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) length++; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i < length; i++) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + free(key); + free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + langtag = (char*)malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i < length; i++) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + transkey = (char*)malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i < length; i++) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + free(key); + free(langtag); + free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + size_t predict; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + The prediction is currently not correct for interlaced PNG images.*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + } + ucvector_cleanup(&idat); + + if(!state->error) + { + ucvector outv; + ucvector_init(&outv); + if(!ucvector_resizev(&outv, + lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/ + if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); + *out = outv.data; + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i < info->palettesize * 4; i++) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i > 0; i--) + { + if(info->palette[4 * (i - 1) + 3] == 255) amount--; + else break; + } + /*add only alpha channel*/ + for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year / 256); + data[1] = (unsigned char)(time->year % 256); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i < length; i++) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i < length; i++) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; i++) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { result++; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]); + } + else + { + for(x = 0; x < linebytes; x++) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type].data[x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x < 256; x++) count[x] = 0; + for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++; + count[type]++; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x < 256; x++) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ + } + for(y = 0; y < h; y++) /*try the 5 filter types*/ + { + for(type = 0; type < 5; type++) + { + unsigned testsize = attempt[type].size; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); + free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < ilinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + free(padded); + } + else + { + /*we can immediatly filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i < 7; i++) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i < palettesize; i++) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i < info.text_num; i++) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i < info.text_num; i++) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i < info.itext_num; i++) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ + case 48: return "empty input or file doesn't exist"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + diff --git a/winpr/libwinpr/utils/lodepng/lodepng.h b/winpr/libwinpr/utils/lodepng/lodepng.h new file mode 100644 index 000000000..141eddf34 --- /dev/null +++ b/winpr/libwinpr/utils/lodepng/lodepng.h @@ -0,0 +1,1563 @@ +/* +LodePNG version 20140823 + +Copyright (c) 2005-2014 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +#ifdef __cplusplus +#include +#include +#endif /*__cplusplus*/ + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile +{ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with vareous compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. changes + 12. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + + +11. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrinked the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also vareous fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +12. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2014 Lode Vandevenne +*/ diff --git a/winpr/libwinpr/utils/print.c b/winpr/libwinpr/utils/print.c index 9b0d6942b..20bdae42b 100644 --- a/winpr/libwinpr/utils/print.c +++ b/winpr/libwinpr/utils/print.c @@ -24,46 +24,70 @@ #include #include #include +#include #include #include #include "trio.h" -void winpr_HexDump(const BYTE* data, int length) +#include "../log.h" + +void winpr_HexDump(const char* tag, int level, const BYTE* data, int length) { const BYTE* p = data; int i, line, offset = 0; + size_t blen = 7 + WINPR_HEXDUMP_LINE_LENGTH * 5; + size_t pos = 0; + char* buffer = malloc(blen); + + if (!buffer) + { + WLog_ERR(tag, "malloc(%zd) failed with [%d] %s", blen, errno, strerror(errno)); + return; + } while (offset < length) { - fprintf(stderr, "%04x ", offset); - + pos += trio_snprintf(&buffer[pos], blen - pos, "%04x ", offset); line = length - offset; if (line > WINPR_HEXDUMP_LINE_LENGTH) line = WINPR_HEXDUMP_LINE_LENGTH; for (i = 0; i < line; i++) - fprintf(stderr, "%02x ", p[i]); + pos += trio_snprintf(&buffer[pos], blen - pos, "%02x ", p[i]); for (; i < WINPR_HEXDUMP_LINE_LENGTH; i++) - fprintf(stderr, " "); + pos += trio_snprintf(&buffer[pos], blen - pos, " "); for (i = 0; i < line; i++) - fprintf(stderr, "%c", (p[i] >= 0x20 && p[i] < 0x7F) ? p[i] : '.'); - - fprintf(stderr, "\n"); + pos += trio_snprintf(&buffer[pos], blen - pos, "%c", + (p[i] >= 0x20 && p[i] < 0x7F) ? p[i] : '.'); + pos += trio_snprintf(&buffer[pos], blen - pos, "\n"); + WLog_LVL(tag, level, "%s", buffer); offset += line; p += line; + pos = 0; } + + free(buffer); } -void winpr_CArrayDump(const BYTE* data, int length, int width) +void winpr_CArrayDump(const char* tag, int level, const BYTE* data, int length, int width) { const BYTE* p = data; int i, line, offset = 0; + const size_t llen = ((length > width) ? width : length) * 4 + 1; + size_t pos; + char* buffer = malloc(llen); + + if (!buffer) + { + WLog_ERR(tag, "malloc(%zd) failed with [%d] %s", llen, errno, strerror(errno)); + return; + } while (offset < length) { @@ -72,18 +96,17 @@ void winpr_CArrayDump(const BYTE* data, int length, int width) if (line > width) line = width; - printf("\t\""); + pos = 0; for (i = 0; i < line; i++) - printf("\\x%02X", p[i]); - - printf("\"\n"); + pos += trio_snprintf(&buffer[pos], llen - pos, "\\x%02X", p[i]); + WLog_LVL(tag, level, "%s", buffer); offset += line; p += line; } - printf("\n"); + free(buffer); } char* winpr_BinToHexString(const BYTE* data, int length, BOOL space) @@ -93,16 +116,13 @@ char* winpr_BinToHexString(const BYTE* data, int length, BOOL space) char* p; int ln, hn; char bin2hex[] = "0123456789ABCDEF"; - n = space ? 3 : 2; - p = (char*) malloc((length + 1) * n); for (i = 0; i < length; i++) { ln = data[i] & 0xF; hn = (data[i] >> 4) & 0xF; - p[i * n] = bin2hex[hn]; p[(i * n) + 1] = bin2hex[ln]; @@ -111,28 +131,25 @@ char* winpr_BinToHexString(const BYTE* data, int length, BOOL space) } p[length * n] = '\0'; - return p; } -int wvprintfx(const char *fmt, va_list args) +int wvprintfx(const char* fmt, va_list args) { return trio_vprintf(fmt, args); } -int wprintfx(const char *fmt, ...) +int wprintfx(const char* fmt, ...) { va_list args; int status; - va_start(args, fmt); status = trio_vprintf(fmt, args); va_end(args); - return status; } -int wvsnprintfx(char *buffer, size_t bufferSize, const char* fmt, va_list args) +int wvsnprintfx(char* buffer, size_t bufferSize, const char* fmt, va_list args) { return trio_vsnprintf(buffer, bufferSize, fmt, args); } diff --git a/winpr/libwinpr/utils/sam.c b/winpr/libwinpr/utils/sam.c index 8c3b91764..8018e5194 100644 --- a/winpr/libwinpr/utils/sam.c +++ b/winpr/libwinpr/utils/sam.c @@ -29,6 +29,7 @@ #include #include +#include "../log.h" #ifdef HAVE_UNISTD_H #include #endif @@ -38,6 +39,7 @@ #else #define WINPR_SAM_FILE "/etc/winpr/SAM" #endif +#define TAG WINPR_TAG("utils") WINPR_SAM* SamOpen(BOOL read_only) { @@ -63,16 +65,15 @@ WINPR_SAM* SamOpen(BOOL read_only) sam->fp = fp; } else - printf("Could not open SAM file!\n"); + WLog_ERR(TAG, "Could not open SAM file!"); return sam; } -BOOL SamLookupStart(WINPR_SAM* sam) +static BOOL SamLookupStart(WINPR_SAM* sam) { size_t read_size; long int file_size; - fseek(sam->fp, 0, SEEK_END); file_size = ftell(sam->fp); fseek(sam->fp, 0, SEEK_SET); @@ -81,7 +82,6 @@ BOOL SamLookupStart(WINPR_SAM* sam) return FALSE; sam->buffer = (char*) malloc(file_size + 2); - read_size = fread(sam->buffer, file_size, 1, sam->fp); if (!read_size) @@ -99,24 +99,20 @@ BOOL SamLookupStart(WINPR_SAM* sam) sam->buffer[file_size] = '\n'; sam->buffer[file_size + 1] = '\0'; - sam->line = strtok(sam->buffer, "\n"); - return TRUE; } -void SamLookupFinish(WINPR_SAM* sam) +static void SamLookupFinish(WINPR_SAM* sam) { free(sam->buffer); - sam->buffer = NULL; sam->line = NULL; } -void HexStrToBin(char* str, BYTE* bin, int length) +static void HexStrToBin(char* str, BYTE* bin, int length) { int i; - CharUpperBuffA(str, length * 2); for (i = 0; i < length; i++) @@ -142,7 +138,6 @@ WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry) char* p[7]; int LmHashLength; int NtHashLength; - p[0] = sam->line; p[1] = strchr(p[0], ':') + 1; p[2] = strchr(p[1], ':') + 1; @@ -150,13 +145,10 @@ WINPR_SAM_ENTRY* SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry) p[4] = strchr(p[3], ':') + 1; p[5] = strchr(p[4], ':') + 1; p[6] = p[0] + strlen(p[0]); - - entry->UserLength = (UINT32) (p[1] - p[0] - 1); - entry->DomainLength = (UINT32) (p[2] - p[1] - 1); - - LmHashLength = (int) (p[3] - p[2] - 1); - NtHashLength = (int) (p[4] - p[3] - 1); - + entry->UserLength = (UINT32)(p[1] - p[0] - 1); + entry->DomainLength = (UINT32)(p[2] - p[1] - 1); + LmHashLength = (int)(p[3] - p[2] - 1); + NtHashLength = (int)(p[4] - p[3] - 1); entry->User = (LPSTR) malloc(entry->UserLength + 1); memcpy(entry->User, p[0], entry->UserLength); entry->User[entry->UserLength] = '\0'; @@ -204,9 +196,7 @@ WINPR_SAM_ENTRY* SamLookupUserA(WINPR_SAM* sam, LPSTR User, UINT32 UserLength, L int length; BOOL found = 0; WINPR_SAM_ENTRY* entry; - entry = (WINPR_SAM_ENTRY*) malloc(sizeof(WINPR_SAM_ENTRY)); - SamLookupStart(sam); while (sam->line != NULL) @@ -252,9 +242,7 @@ WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, LPWSTR EntryDomain; UINT32 EntryDomainLength; WINPR_SAM_ENTRY* entry; - entry = (WINPR_SAM_ENTRY*) malloc(sizeof(WINPR_SAM_ENTRY)); - SamLookupStart(sam); while (sam->line != NULL) @@ -267,7 +255,6 @@ WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, { DomainMatch = 0; UserMatch = 0; - entry = SamReadEntry(sam, entry); if (DomainLength > 0) @@ -277,7 +264,7 @@ WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, EntryDomainLength = (UINT32) strlen(entry->Domain) * 2; EntryDomain = (LPWSTR) malloc(EntryDomainLength + 2); MultiByteToWideChar(CP_ACP, 0, entry->Domain, EntryDomainLength / 2, - (LPWSTR) EntryDomain, EntryDomainLength / 2); + (LPWSTR) EntryDomain, EntryDomainLength / 2); if (DomainLength == EntryDomainLength) { @@ -286,6 +273,7 @@ WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, DomainMatch = 1; } } + free(EntryDomain); } else @@ -303,7 +291,7 @@ WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, EntryUserLength = (UINT32) strlen(entry->User) * 2; EntryUser = (LPWSTR) malloc(EntryUserLength + 2); MultiByteToWideChar(CP_ACP, 0, entry->User, EntryUserLength / 2, - (LPWSTR) EntryUser, EntryUserLength / 2); + (LPWSTR) EntryUser, EntryUserLength / 2); if (UserLength == EntryUserLength) { diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c new file mode 100644 index 000000000..a0745aac3 --- /dev/null +++ b/winpr/libwinpr/utils/ssl.c @@ -0,0 +1,275 @@ +/** + * WinPR: Windows Portable Runtime + * OpenSSL Library Initialization + * + * Copyright 2014 Thincast Technologies GmbH + * Copyright 2014 Norbert Federa + * + * 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 +#include +#include +#include + +#include +#include + +#include "../log.h" +#define TAG WINPR_TAG("utils.ssl") + +static int g_winpr_openssl_num_locks = 0; +static HANDLE* g_winpr_openssl_locks = NULL; +static BOOL g_winpr_openssl_initialized_by_winpr = FALSE; + +struct CRYPTO_dynlock_value +{ + HANDLE mutex; +}; + + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) +static unsigned long _winpr_openssl_id(void) +{ + return (unsigned long)GetCurrentThreadId(); +} +#endif + +static void _winpr_openssl_locking(int mode, int type, const char* file, int line) +{ + if (mode & CRYPTO_LOCK) + { + WaitForSingleObject(g_winpr_openssl_locks[type], INFINITE); + } + else + { + ReleaseMutex(g_winpr_openssl_locks[type]); + } +} + +static struct CRYPTO_dynlock_value* _winpr_openssl_dynlock_create(const char* file, int line) +{ + struct CRYPTO_dynlock_value* dynlock = (struct CRYPTO_dynlock_value*) + malloc(sizeof(struct CRYPTO_dynlock_value)); + + if (dynlock) + { + dynlock->mutex = CreateMutex(NULL, FALSE, NULL); + } + + return dynlock; +} + +static void _winpr_openssl_dynlock_lock(int mode, struct CRYPTO_dynlock_value* dynlock, const char* file, int line) +{ + if (mode & CRYPTO_LOCK) + { + WaitForSingleObject(dynlock->mutex, INFINITE); + } + else + { + ReleaseMutex(dynlock->mutex); + } +} + +static void _winpr_openssl_dynlock_destroy(struct CRYPTO_dynlock_value* dynlock, const char* file, int line) +{ + CloseHandle(dynlock->mutex); + free(dynlock); +} + +static BOOL _winpr_openssl_initialize_locking(void) +{ + int i, count; + + /* OpenSSL static locking */ + + if (CRYPTO_get_locking_callback()) + { + WLog_WARN(TAG, "OpenSSL static locking callback is already set"); + } + else + { + if ((count = CRYPTO_num_locks()) > 0) + { + HANDLE* locks; + + if (!(locks = calloc(count, sizeof(HANDLE)))) + { + WLog_ERR(TAG, "error allocating lock table"); + return FALSE; + } + + for (i = 0; i < count; i++) + { + if (!(locks[i] = CreateMutex(NULL, FALSE, NULL))) + { + WLog_ERR(TAG, "error creating lock #%d", i); + + while (i--) + { + CloseHandle(g_winpr_openssl_locks[i]); + } + + free(locks); + return FALSE; + } + } + + g_winpr_openssl_locks = locks; + g_winpr_openssl_num_locks = count; + CRYPTO_set_locking_callback(_winpr_openssl_locking); + } + } + + /* OpenSSL dynamic locking */ + + if (CRYPTO_get_dynlock_create_callback() || + CRYPTO_get_dynlock_lock_callback() || + CRYPTO_get_dynlock_destroy_callback()) + { + WLog_WARN(TAG, "dynamic locking callbacks are already set"); + } + else + { + CRYPTO_set_dynlock_create_callback(_winpr_openssl_dynlock_create); + CRYPTO_set_dynlock_lock_callback(_winpr_openssl_dynlock_lock); + CRYPTO_set_dynlock_destroy_callback(_winpr_openssl_dynlock_destroy); + } + + /* Use the deprecated CRYPTO_get_id_callback() if building against OpenSSL < 1.0.0 */ +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + + if (CRYPTO_get_id_callback()) + { + WLog_WARN(TAG, "OpenSSL id_callback is already set"); + } + else + { + CRYPTO_set_id_callback(_winpr_openssl_id); + } + +#endif + return TRUE; +} + +static BOOL _winpr_openssl_cleanup_locking(void) +{ + /* undo our static locking modifications */ + if (CRYPTO_get_locking_callback() == _winpr_openssl_locking) + { + int i; + CRYPTO_set_locking_callback(NULL); + + for (i = 0; i < g_winpr_openssl_num_locks; i++) + { + CloseHandle(g_winpr_openssl_locks[i]); + } + + g_winpr_openssl_num_locks = 0; + free(g_winpr_openssl_locks); + g_winpr_openssl_locks = NULL; + } + + /* unset our dynamic locking callbacks */ + + if (CRYPTO_get_dynlock_create_callback() == _winpr_openssl_dynlock_create) + { + CRYPTO_set_dynlock_create_callback(NULL); + } + + if (CRYPTO_get_dynlock_lock_callback() == _winpr_openssl_dynlock_lock) + { + CRYPTO_set_dynlock_lock_callback(NULL); + } + + if (CRYPTO_get_dynlock_destroy_callback() == _winpr_openssl_dynlock_destroy) + { + CRYPTO_set_dynlock_destroy_callback(NULL); + } + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + + if (CRYPTO_get_id_callback() == _winpr_openssl_id) + { + CRYPTO_set_id_callback(NULL); + } + +#endif + return TRUE; +} + +static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVOID* context) +{ + DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT; + + if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED) + { + return TRUE; + } + + if (flags & WINPR_SSL_INIT_ENABLE_LOCKING) + { + if (!_winpr_openssl_initialize_locking()) + { + return FALSE; + } + } + + /* SSL_load_error_strings() is void */ + SSL_load_error_strings(); + /* SSL_library_init() always returns "1" */ + SSL_library_init(); + g_winpr_openssl_initialized_by_winpr = TRUE; + return TRUE; +} + + +/* exported functions */ + +BOOL winpr_InitializeSSL(DWORD flags) +{ + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; + return InitOnceExecuteOnce(&once, _winpr_openssl_initialize, &flags, NULL); +} + +BOOL winpr_CleanupSSL(DWORD flags) +{ + if (flags & WINPR_SSL_CLEANUP_GLOBAL) + { + if (!g_winpr_openssl_initialized_by_winpr) + { + WLog_WARN(TAG, "ssl was not initialized by winpr"); + return FALSE; + } + + g_winpr_openssl_initialized_by_winpr = FALSE; + _winpr_openssl_cleanup_locking(); + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + EVP_cleanup(); + flags |= WINPR_SSL_CLEANUP_THREAD; + } + + if (flags & WINPR_SSL_CLEANUP_THREAD) + { +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + ERR_remove_state(0); +#else + ERR_remove_thread_state(NULL); +#endif + } + + return TRUE; +} diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index c217cd587..199780d9b 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -6,6 +6,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestIni.c + TestImage.c TestQueue.c TestPrint.c TestPubSub.c @@ -27,12 +28,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-path winpr-thread winpr-utils) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/utils/test/TestBitStream.c b/winpr/libwinpr/utils/test/TestBitStream.c index ec1d0d25b..456da8e93 100644 --- a/winpr/libwinpr/utils/test/TestBitStream.c +++ b/winpr/libwinpr/utils/test/TestBitStream.c @@ -9,7 +9,7 @@ void BitStrGen() DWORD i, j; char str[64]; - for (i = 0; i < 256; ) + for (i = 0; i < 256;) { printf("\t"); @@ -18,7 +18,6 @@ void BitStrGen() if (0) { /* Least Significant Bit First */ - str[0] = (i & (1 << 7)) ? '1' : '0'; str[1] = (i & (1 << 6)) ? '1' : '0'; str[2] = (i & (1 << 5)) ? '1' : '0'; @@ -32,7 +31,6 @@ void BitStrGen() else { /* Most Significant Bit First */ - str[7] = (i & (1 << 7)) ? '1' : '0'; str[6] = (i & (1 << 6)) ? '1' : '0'; str[5] = (i & (1 << 5)) ? '1' : '0'; @@ -45,7 +43,6 @@ void BitStrGen() } printf("\"%s\",%s", str, j == 3 ? "" : " "); - i++; } @@ -57,44 +54,30 @@ int TestBitStream(int argc, char* argv[]) { wBitStream* bs; BYTE buffer[1024]; - ZeroMemory(buffer, sizeof(buffer)); - bs = BitStream_New(); - BitStream_Attach(bs, buffer, sizeof(buffer)); - BitStream_Write_Bits(bs, 0xAF, 8); /* 11110101 */ BitStream_Write_Bits(bs, 0xF, 4); /* 1111 */ BitStream_Write_Bits(bs, 0xA, 4); /* 0101 */ - BitStream_Flush(bs); - BitDump(buffer, bs->position, BITDUMP_MSB_FIRST); - + BitDump(__FUNCTION__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST); BitStream_Write_Bits(bs, 3, 2); /* 11 */ BitStream_Write_Bits(bs, 0, 3); /* 000 */ BitStream_Write_Bits(bs, 0x2D, 6); /* 101101 */ BitStream_Write_Bits(bs, 0x19, 5); /* 11001 */ - //BitStream_Flush(bs); /* flush should be done automatically here (32 bits written) */ - BitDump(buffer, bs->position, BITDUMP_MSB_FIRST); - + BitDump(__FUNCTION__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST); BitStream_Write_Bits(bs, 3, 2); /* 11 */ - BitStream_Flush(bs); - BitDump(buffer, bs->position, BITDUMP_MSB_FIRST); - + BitDump(__FUNCTION__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST); BitStream_Write_Bits(bs, 00, 2); /* 00 */ BitStream_Write_Bits(bs, 0xF, 4); /* 1111 */ - BitStream_Write_Bits(bs, 0, 20); BitStream_Write_Bits(bs, 0xAFF, 12); /* 111111110101 */ - BitStream_Flush(bs); - BitDump(buffer, bs->position, BITDUMP_MSB_FIRST); - + BitDump(__FUNCTION__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST); BitStream_Free(bs); - return 0; } diff --git a/winpr/libwinpr/utils/test/TestHashTable.c b/winpr/libwinpr/utils/test/TestHashTable.c index 0fc73a54f..61e096f1f 100644 --- a/winpr/libwinpr/utils/test/TestHashTable.c +++ b/winpr/libwinpr/utils/test/TestHashTable.c @@ -11,7 +11,7 @@ static char* val1 = "val1"; static char* val2 = "val2"; static char* val3 = "val3"; -int TestHashTable(int argc, char* argv[]) +int test_hash_table_pointer() { int count; char* value; @@ -137,5 +137,153 @@ int TestHashTable(int argc, char* argv[]) HashTable_Free(table); + return 1; +} + +int test_hash_table_string() +{ + int count; + char* value; + wHashTable* table; + + table = HashTable_New(TRUE); + + table->hash = HashTable_StringHash; + table->keyCompare = HashTable_StringCompare; + table->valueCompare = HashTable_StringCompare; + table->keyClone = HashTable_StringClone; + table->valueClone = HashTable_StringClone; + table->keyFree = HashTable_StringFree; + table->valueFree = HashTable_StringFree; + + HashTable_Add(table, key1, val1); + HashTable_Add(table, key2, val2); + HashTable_Add(table, key3, val3); + + count = HashTable_Count(table); + + if (count != 3) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 3, count); + return -1; + } + + HashTable_Remove(table, key2); + + count = HashTable_Count(table); + + if (count != 2) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 2, count); + return -1; + } + + HashTable_Remove(table, key3); + + count = HashTable_Count(table); + + if (count != 1) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 1, count); + return -1; + } + + HashTable_Remove(table, key1); + + count = HashTable_Count(table); + + if (count != 0) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 0, count); + return -1; + } + + HashTable_Add(table, key1, val1); + HashTable_Add(table, key2, val2); + HashTable_Add(table, key3, val3); + + count = HashTable_Count(table); + + if (count != 3) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 3, count); + return -1; + } + + value = (char*) HashTable_GetItemValue(table, key1); + + if (strcmp(value, val1) != 0) + { + printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val1, value); + return -1; + } + + value = (char*) HashTable_GetItemValue(table, key2); + + if (strcmp(value, val2) != 0) + { + printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val2, value); + return -1; + } + + value = (char*) HashTable_GetItemValue(table, key3); + + if (strcmp(value, val3) != 0) + { + printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val3, value); + return -1; + } + + HashTable_SetItemValue(table, key2, "apple"); + + value = (char*) HashTable_GetItemValue(table, key2); + + if (strcmp(value, "apple") != 0) + { + printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", "apple", value); + return -1; + } + + if (!HashTable_Contains(table, key2)) + { + printf("HashTable_Contains: Expected : %d, Actual: %d\n", TRUE, FALSE); + return -1; + } + + if (!HashTable_Remove(table, key2)) + { + printf("HashTable_Remove: Expected : %d, Actual: %d\n", TRUE, FALSE); + return -1; + } + + if (HashTable_Remove(table, key2)) + { + printf("HashTable_Remove: Expected : %d, Actual: %d\n", FALSE, TRUE); + return -1; + } + + HashTable_Clear(table); + + count = HashTable_Count(table); + + if (count != 0) + { + printf("HashTable_Count: Expected : %d, Actual: %d\n", 0, count); + return -1; + } + + HashTable_Free(table); + + return 1; +} + +int TestHashTable(int argc, char* argv[]) +{ + if (test_hash_table_pointer() < 0) + return 1; + + if (test_hash_table_string() < 0) + return 1; + return 0; } diff --git a/winpr/libwinpr/utils/test/TestImage.c b/winpr/libwinpr/utils/test/TestImage.c new file mode 100644 index 000000000..72e8fc268 --- /dev/null +++ b/winpr/libwinpr/utils/test/TestImage.c @@ -0,0 +1,48 @@ + +#include +#include +#include +#include + +int test_image_png_to_bmp() +{ + int status; + wImage* image; + + if (!PathFileExistsA("/tmp/test.png")) + return 1; /* skip */ + + image = winpr_image_new(); + + if (!image) + return -1; + + status = winpr_image_read(image, "/tmp/test.png"); + + if (status < 0) + return -1; + + image->type = WINPR_IMAGE_BITMAP; + status = winpr_image_write(image, "/tmp/test_out.bmp"); + + if (status < 0) + return -1; + + image->type = WINPR_IMAGE_PNG; + status = winpr_image_write(image, "/tmp/test_out.png"); + + if (status < 0) + return -1; + + winpr_image_free(image, TRUE); + + return 1; +} + +int TestImage(int argc, char* argv[]) +{ + test_image_png_to_bmp(); + + return 0; +} + diff --git a/winpr/libwinpr/utils/test/TestIni.c b/winpr/libwinpr/utils/test/TestIni.c index 3308a49a8..a584c5007 100644 --- a/winpr/libwinpr/utils/test/TestIni.c +++ b/winpr/libwinpr/utils/test/TestIni.c @@ -32,9 +32,9 @@ int TestIni(int argc, char* argv[]) int i, j; int nKeys; int nSections; - char* sValue; UINT32 iValue; wIniFile* ini; + const char* sValue; char** keyNames; char** sectionNames; @@ -42,7 +42,7 @@ int TestIni(int argc, char* argv[]) ini = IniFile_New(); - IniFile_ParseString(ini, TEST_INI_01); + IniFile_ReadBuffer(ini, TEST_INI_01); sectionNames = IniFile_GetSectionNames(ini, &nSections); @@ -109,7 +109,7 @@ int TestIni(int argc, char* argv[]) ini = IniFile_New(); - IniFile_ParseString(ini, TEST_INI_02); + IniFile_ReadBuffer(ini, TEST_INI_02); sectionNames = IniFile_GetSectionNames(ini, &nSections); diff --git a/winpr/libwinpr/utils/test/TestLinkedList.c b/winpr/libwinpr/utils/test/TestLinkedList.c index 555d617e7..6697ae668 100644 --- a/winpr/libwinpr/utils/test/TestLinkedList.c +++ b/winpr/libwinpr/utils/test/TestLinkedList.c @@ -109,6 +109,33 @@ int TestLinkedList(int argc, char* argv[]) LinkedList_Free(list); + /* Test enumerator robustness */ + + /* enumerator on an empty list */ + list = LinkedList_New(); + LinkedList_Enumerator_Reset(list); + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + LinkedList_Free(list); + + /* Use an enumerator without reset */ + list = LinkedList_New(); + LinkedList_AddFirst(list, (void*) (size_t) 4); + LinkedList_AddLast(list, (void*) (size_t) 5); + LinkedList_AddLast(list, (void*) (size_t) 6); + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + LinkedList_Free(list); + + return 0; } diff --git a/winpr/libwinpr/utils/trio/trio.c b/winpr/libwinpr/utils/trio/trio.c index 08b02240a..19cfdadd0 100644 --- a/winpr/libwinpr/utils/trio/trio.c +++ b/winpr/libwinpr/utils/trio/trio.c @@ -901,8 +901,8 @@ typedef struct _trio_userdef_t { * Internal Variables * *************************************************************************/ - -static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.131 2010/09/12 11:08:08 breese Exp $"; +/* Unused but kept for reference */ +/* static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.131 2010/09/12 11:08:08 breese Exp $"; */ #if TRIO_FEATURE_FLOAT /* diff --git a/winpr/libwinpr/utils/trio/triodef.h b/winpr/libwinpr/utils/trio/triodef.h index 11c14b9c4..ce2667b0a 100644 --- a/winpr/libwinpr/utils/trio/triodef.h +++ b/winpr/libwinpr/utils/trio/triodef.h @@ -168,9 +168,9 @@ #if defined(__cplusplus) # define PREDEF_STANDARD_CXX -#endif -#if __cplusplus - 0 >= 199711L -# define PREDEF_STANDARD_CXX89 +# if __cplusplus - 0 >= 199711L +# define PREDEF_STANDARD_CXX89 +# endif #endif #if defined(TRIO_PLATFORM_UNIX) diff --git a/winpr/libwinpr/utils/trio/trionan.c b/winpr/libwinpr/utils/trio/trionan.c index 301632257..d58246881 100644 --- a/winpr/libwinpr/utils/trio/trionan.c +++ b/winpr/libwinpr/utils/trio/trionan.c @@ -227,7 +227,8 @@ */ #if !defined(TRIO_EMBED_NAN) -static TRIO_CONST char rcsid[] = "@(#)$Id: trionan.c,v 1.33 2005/05/29 11:57:25 breese Exp $"; +/* Unused but kept for reference */ +/* static TRIO_CONST char rcsid[] = "@(#)$Id: trionan.c,v 1.33 2005/05/29 11:57:25 breese Exp $"; */ #endif #if defined(TRIO_FUNC_INTERNAL_MAKE_DOUBLE) \ diff --git a/winpr/libwinpr/utils/trio/triostr.c b/winpr/libwinpr/utils/trio/triostr.c index c471b4a1d..4425bcd21 100644 --- a/winpr/libwinpr/utils/trio/triostr.c +++ b/winpr/libwinpr/utils/trio/triostr.c @@ -160,7 +160,8 @@ struct _trio_string_t */ #if !defined(TRIO_EMBED_STRING) -static TRIO_CONST char rcsid[] = "@(#)$Id: triostr.c,v 1.36 2010/01/26 13:02:02 breese Exp $"; +/* Unused but kept for reference */ +/* static TRIO_CONST char rcsid[] = "@(#)$Id: triostr.c,v 1.36 2010/01/26 13:02:02 breese Exp $"; */ #endif /************************************************************************* diff --git a/winpr/libwinpr/utils/wlog/BinaryAppender.c b/winpr/libwinpr/utils/wlog/BinaryAppender.c index f0bd1ba5f..79395d506 100644 --- a/winpr/libwinpr/utils/wlog/BinaryAppender.c +++ b/winpr/libwinpr/utils/wlog/BinaryAppender.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -71,6 +73,9 @@ int WLog_BinaryAppender_Open(wLog* log, wLogBinaryAppender* appender) ProcessId = GetCurrentProcessId(); + if (!log || !appender) + return -1; + if (!appender->FilePath) { appender->FilePath = GetKnownSubPath(KNOWN_PATH_TEMP, "wlog"); @@ -122,6 +127,9 @@ int WLog_BinaryAppender_WriteMessage(wLog* log, wLogBinaryAppender* appender, wL int FunctionNameLength; int TextStringLength; + if (!log || !appender || !message) + return -1; + fp = appender->FileDescriptor; if (!fp) diff --git a/winpr/libwinpr/utils/wlog/ConsoleAppender.c b/winpr/libwinpr/utils/wlog/ConsoleAppender.c index b7f4a985e..0383a823f 100644 --- a/winpr/libwinpr/utils/wlog/ConsoleAppender.c +++ b/winpr/libwinpr/utils/wlog/ConsoleAppender.c @@ -30,6 +30,10 @@ #include "wlog/ConsoleAppender.h" +#ifdef ANDROID +#include +#endif + /** * Console Appender */ @@ -84,11 +88,45 @@ int WLog_ConsoleAppender_WriteMessage(wLog* log, wLogConsoleAppender* appender, return 1; } #endif +#ifdef ANDROID + (void)fp; + android_LogPriority level; + switch(message->Level) + { + case WLOG_TRACE: + level = ANDROID_LOG_VERBOSE; + break; + case WLOG_DEBUG: + level = ANDROID_LOG_DEBUG; + break; + case WLOG_INFO: + level = ANDROID_LOG_INFO; + break; + case WLOG_WARN: + level = ANDROID_LOG_WARN; + break; + case WLOG_ERROR: + level = ANDROID_LOG_ERROR; + break; + case WLOG_FATAL: + level = ANDROID_LOG_FATAL; + break; + case WLOG_OFF: + level = ANDROID_LOG_SILENT; + break; + default: + level = ANDROID_LOG_FATAL; + break; + } + if (level != ANDROID_LOG_SILENT) + __android_log_print(level, log->Name, "%s%s", message->PrefixString, message->TextString); + +#else fp = (appender->outputStream == WLOG_CONSOLE_STDERR) ? stderr : stdout; fprintf(fp, "%s%s\n", message->PrefixString, message->TextString); - +#endif return 1; } @@ -143,8 +181,9 @@ int WLog_ConsoleAppender_WritePacketMessage(wLog* log, wLogConsoleAppender* appe free(FullFileName); } - WLog_PacketMessage_Write((wPcap*) appender->PacketMessageContext, - message->PacketData, message->PacketLength, message->PacketFlags); + if (appender->PacketMessageContext) + WLog_PacketMessage_Write((wPcap*) appender->PacketMessageContext, + message->PacketData, message->PacketLength, message->PacketFlags); return PacketId; } diff --git a/winpr/libwinpr/utils/wlog/DataMessage.c b/winpr/libwinpr/utils/wlog/DataMessage.c index ded9f9af6..892050425 100644 --- a/winpr/libwinpr/utils/wlog/DataMessage.c +++ b/winpr/libwinpr/utils/wlog/DataMessage.c @@ -25,21 +25,21 @@ #include "wlog/DataMessage.h" +#include "../../log.h" +#define TAG WINPR_TAG("utils.wlog") + int WLog_DataMessage_Write(char* filename, void* data, int length) { FILE* fp; - fp = fopen(filename, "w+b"); if (!fp) { - fprintf(stderr, "failed to open file %s\n", filename); + WLog_ERR(TAG, "failed to open file %s", filename); return -1; } fwrite(data, length, 1, fp); - fclose(fp); - return 0; } diff --git a/winpr/libwinpr/utils/wlog/FileAppender.c b/winpr/libwinpr/utils/wlog/FileAppender.c index 4e1feb006..90ce6cb56 100644 --- a/winpr/libwinpr/utils/wlog/FileAppender.c +++ b/winpr/libwinpr/utils/wlog/FileAppender.c @@ -70,6 +70,9 @@ int WLog_FileAppender_Open(wLog* log, wLogFileAppender* appender) ProcessId = GetCurrentProcessId(); + if (!log || !appender) + return -1; + if (!appender->FilePath) { appender->FilePath = GetKnownSubPath(KNOWN_PATH_TEMP, "wlog"); @@ -102,6 +105,9 @@ int WLog_FileAppender_Open(wLog* log, wLogFileAppender* appender) int WLog_FileAppender_Close(wLog* log, wLogFileAppender* appender) { + if (!log || !appender) + return -1; + if (!appender->FileDescriptor) return 0; @@ -117,6 +123,9 @@ int WLog_FileAppender_WriteMessage(wLog* log, wLogFileAppender* appender, wLogMe FILE* fp; char prefix[WLOG_MAX_PREFIX_SIZE]; + if (!log || !appender || !message) + return -1; + fp = appender->FileDescriptor; if (!fp) @@ -139,6 +148,9 @@ int WLog_FileAppender_WriteDataMessage(wLog* log, wLogFileAppender* appender, wL int DataId; char* FullFileName; + if (!log || !appender || !message) + return -1; + DataId = g_DataId++; FullFileName = WLog_Message_GetOutputFileName(DataId, "dat"); @@ -156,6 +168,9 @@ int WLog_FileAppender_WriteImageMessage(wLog* log, wLogFileAppender* appender, w int ImageId; char* FullFileName; + if (!log || !appender || !message) + return -1; + ImageId = g_ImageId++; FullFileName = WLog_Message_GetOutputFileName(ImageId, "bmp"); diff --git a/winpr/libwinpr/utils/wlog/ImageMessage.c b/winpr/libwinpr/utils/wlog/ImageMessage.c index 89af777c5..a8d2ab979 100644 --- a/winpr/libwinpr/utils/wlog/ImageMessage.c +++ b/winpr/libwinpr/utils/wlog/ImageMessage.c @@ -22,89 +22,18 @@ #endif #include +#include #include "wlog/ImageMessage.h" -#include -#include - -typedef struct -{ - BYTE magic[2]; -} BITMAP_MAGIC; - -typedef struct -{ - UINT32 filesz; - UINT16 creator1; - UINT16 creator2; - UINT32 bmp_offset; -} BITMAP_CORE_HEADER; - -typedef struct -{ - UINT32 header_sz; - INT32 width; - INT32 height; - UINT16 nplanes; - UINT16 bitspp; - UINT32 compress_type; - UINT32 bmp_bytesz; - INT32 hres; - INT32 vres; - UINT32 ncolors; - UINT32 nimpcolors; -} BITMAP_INFO_HEADER; - int WLog_ImageMessage_Write(char* filename, void* data, int width, int height, int bpp) { - FILE* fp; - BITMAP_MAGIC magic; - BITMAP_CORE_HEADER header; - BITMAP_INFO_HEADER info_header; + int status; - fp = fopen(filename, "w+b"); + status = winpr_bitmap_write(filename, data, width, height, bpp); - if (!fp) - { - fprintf(stderr, "failed to open file %s\n", filename); + if (status < 0) return -1; - } - magic.magic[0] = 'B'; - magic.magic[1] = 'M'; - - header.creator1 = 0; - header.creator2 = 0; - - header.bmp_offset = - sizeof(BITMAP_MAGIC) + - sizeof(BITMAP_CORE_HEADER) + - sizeof(BITMAP_INFO_HEADER); - - info_header.bmp_bytesz = width * height * (bpp / 8); - - header.filesz = - header.bmp_offset + - info_header.bmp_bytesz; - - info_header.width = width; - info_header.height = (-1) * height; - info_header.nplanes = 1; - info_header.bitspp = bpp; - info_header.compress_type = 0; - info_header.hres = width; - info_header.vres = height; - info_header.ncolors = 0; - info_header.nimpcolors = 0; - info_header.header_sz = sizeof(BITMAP_INFO_HEADER); - - fwrite((void*) &magic, sizeof(BITMAP_MAGIC), 1, fp); - fwrite((void*) &header, sizeof(BITMAP_CORE_HEADER), 1, fp); - fwrite((void*) &info_header, sizeof(BITMAP_INFO_HEADER), 1, fp); - fwrite((void*) data, info_header.bmp_bytesz, 1, fp); - - fclose(fp); - - return 0; + return 1; } diff --git a/winpr/libwinpr/utils/wlog/Layout.c b/winpr/libwinpr/utils/wlog/Layout.c index fc1f6a1d1..43670d0d0 100644 --- a/winpr/libwinpr/utils/wlog/Layout.c +++ b/winpr/libwinpr/utils/wlog/Layout.c @@ -356,7 +356,13 @@ wLogLayout* WLog_Layout_New(wLog* log) if (env) layout->FormatString = env; else + { +#ifdef ANDROID + layout->FormatString = _strdup("[pid=%pid:tid=%tid] - "); +#else layout->FormatString = _strdup("[%hr:%mi:%se:%ml] [%pid:%tid] [%lv][%mn] - "); +#endif + } } return layout; diff --git a/winpr/libwinpr/utils/wlog/PacketMessage.c b/winpr/libwinpr/utils/wlog/PacketMessage.c index ad6472841..a63769c8b 100644 --- a/winpr/libwinpr/utils/wlog/PacketMessage.c +++ b/winpr/libwinpr/utils/wlog/PacketMessage.c @@ -28,6 +28,9 @@ #include #include +#include "../../log.h" +#define TAG WINPR_TAG("utils.wlog") + #ifndef _WIN32 #include #else @@ -47,35 +50,43 @@ static int gettimeofday(struct timeval* tp, void* tz) void Pcap_Read_Header(wPcap* pcap, wPcapHeader* header) { - fread((void*) header, sizeof(wPcapHeader), 1, pcap->fp); + if (pcap && pcap->fp) + fread((void*) header, sizeof(wPcapHeader), 1, pcap->fp); } void Pcap_Write_Header(wPcap* pcap, wPcapHeader* header) { - fwrite((void*) header, sizeof(wPcapHeader), 1, pcap->fp); + if (pcap && pcap->fp) + fwrite((void*) header, sizeof(wPcapHeader), 1, pcap->fp); } void Pcap_Read_RecordHeader(wPcap* pcap, wPcapRecordHeader* record) { - fread((void*) record, sizeof(wPcapRecordHeader), 1, pcap->fp); + if (pcap && pcap->fp) + fread((void*) record, sizeof(wPcapRecordHeader), 1, pcap->fp); } void Pcap_Write_RecordHeader(wPcap* pcap, wPcapRecordHeader* record) { - fwrite((void*) record, sizeof(wPcapRecordHeader), 1, pcap->fp); + if (pcap && pcap->fp) + fwrite((void*) record, sizeof(wPcapRecordHeader), 1, pcap->fp); } void Pcap_Write_RecordContent(wPcap* pcap, wPcapRecord* record) { - fwrite(record->data, record->length, 1, pcap->fp); + if (pcap && pcap->fp) + fwrite(record->data, record->length, 1, pcap->fp); } void Pcap_Read_Record(wPcap* pcap, wPcapRecord* record) { - Pcap_Read_RecordHeader(pcap, &record->header); - record->length = record->header.incl_len; - record->data = malloc(record->length); - fread(record->data, record->length, 1, pcap->fp); + if (pcap && pcap->fp) + { + Pcap_Read_RecordHeader(pcap, &record->header); + record->length = record->header.incl_len; + record->data = malloc(record->length); + fread(record->data, record->length, 1, pcap->fp); + } } void Pcap_Write_Record(wPcap* pcap, wPcapRecord* record) @@ -93,7 +104,6 @@ void Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length) { pcap->tail = (wPcapRecord*) malloc(sizeof(wPcapRecord)); ZeroMemory(pcap->tail, sizeof(wPcapRecord)); - pcap->head = pcap->tail; pcap->record = pcap->head; record = pcap->tail; @@ -102,7 +112,6 @@ void Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length) { record = (wPcapRecord*) malloc(sizeof(wPcapRecord)); ZeroMemory(record, sizeof(wPcapRecord)); - pcap->tail->next = record; pcap->tail = record; } @@ -114,7 +123,6 @@ void Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length) record->length = length; record->header.incl_len = length; record->header.orig_len = length; - gettimeofday(&tp, 0); record->header.ts_sec = tp.tv_sec; record->header.ts_usec = tp.tv_usec; @@ -135,14 +143,18 @@ BOOL Pcap_GetNext_RecordHeader(wPcap* pcap, wPcapRecord* record) Pcap_Read_RecordHeader(pcap, &record->header); record->length = record->header.incl_len; - return TRUE; } BOOL Pcap_GetNext_RecordContent(wPcap* pcap, wPcapRecord* record) { - fread(record->data, record->length, 1, pcap->fp); - return TRUE; + if (pcap && pcap->fp) + { + fread(record->data, record->length, 1, pcap->fp); + return TRUE; + } + + return FALSE; } BOOL Pcap_GetNext_Record(wPcap* pcap, wPcapRecord* record) @@ -151,19 +163,17 @@ BOOL Pcap_GetNext_Record(wPcap* pcap, wPcapRecord* record) return FALSE; Pcap_Read_Record(pcap, record); - return TRUE; } wPcap* Pcap_Open(char* name, BOOL write) { wPcap* pcap; - FILE* pcap_fp = fopen(name, write ? "w+b" : "rb"); if (!pcap_fp) { - perror("opening pcap file"); + WLog_ERR(TAG,"opening pcap file"); return NULL; } @@ -172,7 +182,6 @@ wPcap* Pcap_Open(char* name, BOOL write) if (pcap) { ZeroMemory(pcap, sizeof(wPcap)); - pcap->name = name; pcap->write = write; pcap->record_count = 0; @@ -189,7 +198,7 @@ wPcap* Pcap_Open(char* name, BOOL write) pcap->header.network = 1; /* ethernet */ Pcap_Write_Header(pcap, &pcap->header); } - else + else if (pcap->fp) { fseek(pcap->fp, 0, SEEK_END); pcap->file_size = (int) ftell(pcap->fp); @@ -203,23 +212,25 @@ wPcap* Pcap_Open(char* name, BOOL write) void Pcap_Flush(wPcap* pcap) { + if (!pcap || !pcap->fp) + return; + while (pcap->record) { Pcap_Write_Record(pcap, pcap->record); pcap->record = pcap->record->next; } - if (pcap->fp) - fflush(pcap->fp); + fflush(pcap->fp); } void Pcap_Close(wPcap* pcap) { + if (!pcap || !pcap->fp) + return; + Pcap_Flush(pcap); - - if (pcap->fp) - fclose(pcap->fp); - + fclose(pcap->fp); free(pcap); } @@ -228,16 +239,15 @@ int WLog_PacketMessage_Write_EthernetHeader(wPcap* pcap, wEthernetHeader* ethern wStream* s; BYTE buffer[14]; - s = Stream_New(buffer, 14); + if (!pcap || !pcap->fp || !ethernet) + return -1; + s = Stream_New(buffer, 14); Stream_Write(s, ethernet->Destination, 6); Stream_Write(s, ethernet->Source, 6); Stream_Write_UINT16_BE(s, ethernet->Type); - fwrite(buffer, 14, 1, pcap->fp); - Stream_Free(s, FALSE); - return 0; } @@ -260,7 +270,7 @@ UINT16 IPv4Checksum(BYTE* ipv4, int length) while (checksum >> 16) checksum = (checksum & 0xFFFF) + (checksum >> 16); - return (UINT16) (~checksum); + return (UINT16)(~checksum); } int WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4) @@ -268,8 +278,10 @@ int WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4) wStream* s; BYTE buffer[20]; - s = Stream_New(buffer, 20); + if (!pcap || !pcap->fp || !ipv4) + return -1; + s = Stream_New(buffer, 20); Stream_Write_UINT8(s, (ipv4->Version << 4) | ipv4->InternetHeaderLength); Stream_Write_UINT8(s, ipv4->TypeOfService); Stream_Write_UINT16_BE(s, ipv4->TotalLength); @@ -280,16 +292,12 @@ int WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4) Stream_Write_UINT16(s, ipv4->HeaderChecksum); Stream_Write_UINT32_BE(s, ipv4->SourceAddress); Stream_Write_UINT32_BE(s, ipv4->DestinationAddress); - ipv4->HeaderChecksum = IPv4Checksum((BYTE*) buffer, 20); Stream_Rewind(s, 10); Stream_Write_UINT16(s, ipv4->HeaderChecksum); Stream_Seek(s, 8); - fwrite(buffer, 20, 1, pcap->fp); - Stream_Free(s, FALSE); - return 0; } @@ -298,8 +306,10 @@ int WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp) wStream* s; BYTE buffer[20]; - s = Stream_New(buffer, 20); + if (!pcap || !pcap->fp || !tcp) + return -1; + s = Stream_New(buffer, 20); Stream_Write_UINT16_BE(s, tcp->SourcePort); Stream_Write_UINT16_BE(s, tcp->DestinationPort); Stream_Write_UINT32_BE(s, tcp->SequenceNumber); @@ -310,10 +320,10 @@ int WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp) Stream_Write_UINT16_BE(s, tcp->Checksum); Stream_Write_UINT16_BE(s, tcp->UrgentPointer); - fwrite(buffer, 20, 1, pcap->fp); + if (pcap->fp) + fwrite(buffer, 20, 1, pcap->fp); Stream_Free(s, FALSE); - return 0; } @@ -327,9 +337,11 @@ int WLog_PacketMessage_Write(wPcap* pcap, void* data, DWORD length, DWORD flags) struct timeval tp; wPcapRecord record; wEthernetHeader ethernet; - ethernet.Type = 0x0800; + if (!pcap || !pcap->fp) + return -1; + if (flags & WLOG_PACKET_OUTBOUND) { /* 00:15:5D:01:64:04 */ @@ -339,7 +351,6 @@ int WLog_PacketMessage_Write(wPcap* pcap, void* data, DWORD length, DWORD flags) ethernet.Source[3] = 0x01; ethernet.Source[4] = 0x64; ethernet.Source[5] = 0x04; - /* 00:15:5D:01:64:01 */ ethernet.Destination[0] = 0x00; ethernet.Destination[1] = 0x15; @@ -357,7 +368,6 @@ int WLog_PacketMessage_Write(wPcap* pcap, void* data, DWORD length, DWORD flags) ethernet.Source[3] = 0x01; ethernet.Source[4] = 0x64; ethernet.Source[5] = 0x01; - /* 00:15:5D:01:64:04 */ ethernet.Destination[0] = 0x00; ethernet.Destination[1] = 0x15; @@ -370,7 +380,7 @@ int WLog_PacketMessage_Write(wPcap* pcap, void* data, DWORD length, DWORD flags) ipv4.Version = 4; ipv4.InternetHeaderLength = 5; ipv4.TypeOfService = 0; - ipv4.TotalLength = (UINT16) (length + 20 + 20); + ipv4.TotalLength = (UINT16)(length + 20 + 20); ipv4.Identification = 0; ipv4.InternetProtocolFlags = 0x02; ipv4.FragmentOffset = 0; @@ -411,23 +421,19 @@ int WLog_PacketMessage_Write(wPcap* pcap, void* data, DWORD length, DWORD flags) tcp.Window = 0x7FFF; tcp.Checksum = 0; tcp.UrgentPointer = 0; - record.data = data; record.length = length; record.header.incl_len = record.length + 14 + 20 + 20; record.header.orig_len = record.length + 14 + 20 + 20; record.next = NULL; - gettimeofday(&tp, 0); record.header.ts_sec = tp.tv_sec; record.header.ts_usec = tp.tv_usec; - Pcap_Write_RecordHeader(pcap, &record.header); WLog_PacketMessage_Write_EthernetHeader(pcap, ðernet); WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4); WLog_PacketMessage_Write_TcpHeader(pcap, &tcp); Pcap_Write_RecordContent(pcap, &record); fflush(pcap->fp); - return 0; } diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c index 366292dc7..34dc579a0 100644 --- a/winpr/libwinpr/utils/wlog/wlog.c +++ b/winpr/libwinpr/utils/wlog/wlog.c @@ -23,16 +23,22 @@ #include #include -#include #include #include +#include #include +#if defined(ANDROID) +#include +#endif + #include #include "wlog/wlog.h" +#include "../../log.h" + /** * References for general logging concepts: * @@ -57,11 +63,38 @@ const char* WLOG_LEVELS[7] = static DWORD g_FilterCount = 0; static wLogFilter* g_Filters = NULL; +static void log_recursion(const char* file, const char* fkt, int line) +{ + size_t used, i; + void* bt = winpr_backtrace(20); + char** msg = winpr_backtrace_symbols(bt, &used); +#if defined(ANDROID) + const char* tag = WINPR_TAG("utils.wlog"); + __android_log_print(ANDROID_LOG_FATAL, tag, "Recursion detected!!!"); + __android_log_print(ANDROID_LOG_FATAL, tag, "Check %s [%s:%d]", fkt, file, line); + + for (i=0; ilock); - status = appender->WriteMessage(log, appender, message); + if (appender->recursive) + log_recursion(message->FileName, message->FunctionName, message->LineNumber); + else + { + appender->recursive = TRUE; + status = appender->WriteMessage(log, appender, message); + appender->recursive = FALSE; + } LeaveCriticalSection(&appender->lock); - return status; } int WLog_WriteData(wLog* log, wLogMessage* message) { - int status; + int status = -1; wLogAppender* appender; - appender = WLog_GetLogAppender(log); if (!appender) @@ -100,18 +138,23 @@ int WLog_WriteData(wLog* log, wLogMessage* message) EnterCriticalSection(&appender->lock); - status = appender->WriteDataMessage(log, appender, message); + if (appender->recursive) + log_recursion(message->FileName, message->FunctionName, message->LineNumber); + else + { + appender->recursive = TRUE; + status = appender->WriteDataMessage(log, appender, message); + appender->recursive = FALSE; + } LeaveCriticalSection(&appender->lock); - return status; } int WLog_WriteImage(wLog* log, wLogMessage* message) { - int status; + int status = -1; wLogAppender* appender; - appender = WLog_GetLogAppender(log); if (!appender) @@ -125,18 +168,23 @@ int WLog_WriteImage(wLog* log, wLogMessage* message) EnterCriticalSection(&appender->lock); - status = appender->WriteImageMessage(log, appender, message); + if (appender->recursive) + log_recursion(message->FileName, message->FunctionName, message->LineNumber); + else + { + appender->recursive = TRUE; + status = appender->WriteImageMessage(log, appender, message); + appender->recursive = FALSE; + } LeaveCriticalSection(&appender->lock); - return status; } int WLog_WritePacket(wLog* log, wLogMessage* message) { - int status; + int status = -1; wLogAppender* appender; - appender = WLog_GetLogAppender(log); if (!appender) @@ -150,10 +198,16 @@ int WLog_WritePacket(wLog* log, wLogMessage* message) EnterCriticalSection(&appender->lock); - status = appender->WritePacketMessage(log, appender, message); + if (appender->recursive) + log_recursion(message->FileName, message->FunctionName, message->LineNumber); + else + { + appender->recursive = TRUE; + status = appender->WritePacketMessage(log, appender, message); + appender->recursive = FALSE; + } LeaveCriticalSection(&appender->lock); - return status; } @@ -172,7 +226,6 @@ int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args) { char formattedLogMessage[WLOG_MAX_STRING_SIZE]; wvsnprintfx(formattedLogMessage, WLOG_MAX_STRING_SIZE - 1, message->FormatString, args); - message->TextString = formattedLogMessage; status = WLog_Write(log, message); } @@ -181,7 +234,6 @@ int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args) { message->Data = va_arg(args, void*); message->Length = va_arg(args, int); - status = WLog_WriteData(log, message); } else if (message->Type == WLOG_MESSAGE_IMAGE) @@ -190,7 +242,6 @@ int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args) message->ImageWidth = va_arg(args, int); message->ImageHeight = va_arg(args, int); message->ImageBpp = va_arg(args, int); - status = WLog_WriteImage(log, message); } else if (message->Type == WLOG_MESSAGE_PACKET) @@ -198,7 +249,6 @@ int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args) message->PacketData = va_arg(args, void*); message->PacketLength = va_arg(args, int); message->PacketFlags = va_arg(args, int); - status = WLog_WritePacket(log, message); } @@ -209,11 +259,8 @@ void WLog_PrintMessage(wLog* log, wLogMessage* message, ...) { int status; va_list args; - va_start(args, message); - status = WLog_PrintMessageVA(log, message, args); - va_end(args); } @@ -271,7 +318,6 @@ int WLog_ParseFilter(wLogFilter* filter, LPCSTR name) int count; LPSTR names; int iLevel; - count = 1; p = (char*) name; @@ -285,11 +331,9 @@ int WLog_ParseFilter(wLogFilter* filter, LPCSTR name) filter->NameCount = count; filter->Names = (LPSTR*) malloc(sizeof(LPSTR) * (count + 1)); filter->Names[count] = NULL; - count = 0; p = (char*) names; filter->Names[count++] = p; - q = strrchr(p, ':'); if (!q) @@ -297,7 +341,6 @@ int WLog_ParseFilter(wLogFilter* filter, LPCSTR name) *q = '\0'; q++; - iLevel = WLog_ParseLogLevel(q); if (iLevel < 0) @@ -323,7 +366,6 @@ int WLog_ParseFilters() DWORD nSize; int status; char** strs; - nSize = GetEnvironmentVariableA("WLOG_FILTER", NULL, 0); if (nSize < 1) @@ -335,7 +377,6 @@ int WLog_ParseFilters() return -1; nSize = GetEnvironmentVariableA("WLOG_FILTER", env, nSize); - count = 1; p = env; @@ -346,11 +387,9 @@ int WLog_ParseFilters() } g_FilterCount = count; - p = env; count = 0; strs = (char**) calloc(g_FilterCount, sizeof(char*)); - strs[count++] = p; while ((p = strchr(p, ',')) != NULL) @@ -374,7 +413,6 @@ int WLog_ParseFilters() } free(strs); - return 0; } @@ -424,7 +462,6 @@ int WLog_ParseName(wLog* log, LPCSTR name) char* p; int count; LPSTR names; - count = 1; p = (char*) name; @@ -438,7 +475,6 @@ int WLog_ParseName(wLog* log, LPCSTR name) log->NameCount = count; log->Names = (LPSTR*) malloc(sizeof(LPSTR) * (count + 1)); log->Names[count] = NULL; - count = 0; p = (char*) names; log->Names[count++] = p; @@ -459,7 +495,6 @@ wLog* WLog_New(LPCSTR name, wLog* rootLogger) char* env; DWORD nSize; int iLevel; - log = (wLog*) calloc(1, sizeof(wLog)); if (log) @@ -470,10 +505,8 @@ wLog* WLog_New(LPCSTR name, wLog* rootLogger) return NULL; WLog_ParseName(log, name); - log->Parent = rootLogger; log->ChildrenCount = 0; - log->ChildrenSize = 16; log->Children = (wLog**) calloc(log->ChildrenSize, sizeof(wLog*)); @@ -488,15 +521,13 @@ wLog* WLog_New(LPCSTR name, wLog* rootLogger) } else { - log->Level = WLOG_WARN; - + log->Level = WLOG_INFO; nSize = GetEnvironmentVariableA("WLOG_LEVEL", NULL, 0); if (nSize) { env = (LPSTR) malloc(nSize); nSize = GetEnvironmentVariableA("WLOG_LEVEL", env, nSize); - iLevel = WLog_ParseLogLevel(env); if (iLevel >= 0) @@ -529,7 +560,6 @@ void WLog_Free(wLog* log) free(log->Names[0]); free(log->Names); free(log->Children); - free(log); } } @@ -546,11 +576,8 @@ wLog* WLog_GetRoot() { g_RootLog = WLog_New("", NULL); g_RootLog->IsRoot = TRUE; - WLog_ParseFilters(); - logAppenderType = WLOG_APPENDER_CONSOLE; - nSize = GetEnvironmentVariableA("WLOG_APPENDER", NULL, 0); if (nSize) @@ -587,7 +614,6 @@ int WLog_AddChild(wLog* parent, wLog* child) parent->Children[parent->ChildrenCount++] = child; child->Parent = parent; - return 0; } @@ -597,7 +623,6 @@ wLog* WLog_FindChild(LPCSTR name) wLog* root; wLog* child = NULL; BOOL found = FALSE; - root = WLog_GetRoot(); for (index = 0; index < root->ChildrenCount; index++) @@ -618,9 +643,7 @@ wLog* WLog_Get(LPCSTR name) { wLog* log; wLog* root; - root = WLog_GetRoot(); - log = WLog_FindChild(name); if (!log) @@ -640,7 +663,6 @@ void WLog_Init() void WLog_Uninit() { wLog* root = WLog_GetRoot(); - DWORD index; wLog* child = NULL; diff --git a/winpr/libwinpr/winhttp/CMakeLists.txt b/winpr/libwinpr/winhttp/CMakeLists.txt index 62088e7c3..57576c6f9 100644 --- a/winpr/libwinpr/winhttp/CMakeLists.txt +++ b/winpr/libwinpr/winhttp/CMakeLists.txt @@ -15,23 +15,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-winhttp") -set(MODULE_PREFIX "WINPR_WINHTTP") - -set(${MODULE_PREFIX}_SRCS - winhttp.c) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -if(MONOLITHIC_BUILD) - -else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +winpr_module_add(winhttp.c) diff --git a/winpr/libwinpr/winsock/CMakeLists.txt b/winpr/libwinpr/winsock/CMakeLists.txt index c4369c535..1d2e1159a 100644 --- a/winpr/libwinpr/winsock/CMakeLists.txt +++ b/winpr/libwinpr/winsock/CMakeLists.txt @@ -15,32 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-winsock") -set(MODULE_PREFIX "WINPR_WINSOCK") - -set(${MODULE_PREFIX}_SRCS - winsock.c) - -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") +winpr_module_add(winsock.c) if(WIN32) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32) + winpr_library_add(ws2_32) endif() - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") diff --git a/winpr/libwinpr/winsock/winsock.c b/winpr/libwinpr/winsock/winsock.c index ac07ea694..71a64d2d4 100644 --- a/winpr/libwinpr/winsock/winsock.c +++ b/winpr/libwinpr/winsock/winsock.c @@ -482,6 +482,9 @@ int _bind(SOCKET s, const struct sockaddr* addr, int namelen) status = bind(fd, addr, (socklen_t) namelen); + if (status < 0) + return SOCKET_ERROR; + return status; } @@ -502,6 +505,9 @@ int _connect(SOCKET s, const struct sockaddr* name, int namelen) status = connect(fd, name, (socklen_t) namelen); + if (status < 0) + return SOCKET_ERROR; + return status; } @@ -612,7 +618,11 @@ int _select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, cons { int status; - status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout); + do + { + status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout); + } + while ((status < 0) && (errno == EINTR)); return status; } @@ -680,9 +690,15 @@ int _shutdown(SOCKET s, int how) SOCKET _socket(int af, int type, int protocol) { + int fd; SOCKET s; - s = (SOCKET) socket(af, type, protocol); + fd = socket(af, type, protocol); + + if (fd < 1) + return INVALID_SOCKET; + + s = (SOCKET) fd; return s; } diff --git a/winpr/libwinpr/wnd/CMakeLists.txt b/winpr/libwinpr/wnd/CMakeLists.txt index 37a779407..f3897cde5 100644 --- a/winpr/libwinpr/wnd/CMakeLists.txt +++ b/winpr/libwinpr/wnd/CMakeLists.txt @@ -15,37 +15,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-wnd") -set(MODULE_PREFIX "WINPR_WND") - -set(${MODULE_PREFIX}_SRCS - wnd.c +winpr_module_add(wnd.c wnd.h) -if(MSVC AND (NOT MONOLITHIC_BUILD)) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) -endif() - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-crt winpr-utils) - -if(MONOLITHIC_BUILD) - -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/wnd/test/CMakeLists.txt b/winpr/libwinpr/wnd/test/CMakeLists.txt index c233ad235..8882d4c44 100644 --- a/winpr/libwinpr/wnd/test/CMakeLists.txt +++ b/winpr/libwinpr/wnd/test/CMakeLists.txt @@ -14,12 +14,7 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-wnd winpr-library) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/wtsapi/CMakeLists.txt b/winpr/libwinpr/wtsapi/CMakeLists.txt index 20da3086c..71c164660 100644 --- a/winpr/libwinpr/wtsapi/CMakeLists.txt +++ b/winpr/libwinpr/wtsapi/CMakeLists.txt @@ -15,34 +15,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(MODULE_NAME "winpr-wtsapi") -set(MODULE_PREFIX "WINPR_WTSAPI") - -set(${MODULE_PREFIX}_SRCS - wtsapi.c +winpr_module_add(wtsapi.c wtsapi.h) -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS} - EXPORT) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE winpr - MODULES winpr-nt winpr-io winpr-synch winpr-file winpr-error winpr-library winpr-environment winpr-utils) - -if(MONOLITHIC_BUILD) - set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) +if(WIN32) + winpr_module_add(wtsapi_win32.c wtsapi_win32.h) endif() -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") - if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/wtsapi/test/CMakeLists.txt b/winpr/libwinpr/wtsapi/test/CMakeLists.txt index 67fd5a1c4..b26197ee0 100644 --- a/winpr/libwinpr/wtsapi/test/CMakeLists.txt +++ b/winpr/libwinpr/wtsapi/test/CMakeLists.txt @@ -20,12 +20,8 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-library winpr-wtsapi winpr-utils) -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +target_link_libraries(${MODULE_NAME} winpr) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") diff --git a/winpr/libwinpr/wtsapi/wtsapi.c b/winpr/libwinpr/wtsapi/wtsapi.c index 02cf985cb..f11355b0b 100644 --- a/winpr/libwinpr/wtsapi/wtsapi.c +++ b/winpr/libwinpr/wtsapi/wtsapi.c @@ -32,6 +32,13 @@ #include "wtsapi.h" +#ifdef _WIN32 +#include "wtsapi_win32.h" +#endif + +#include "../log.h" +#define TAG WINPR_TAG("wtsapi") + /** * Remote Desktop Services API Functions: * http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464/ @@ -44,6 +51,163 @@ static HMODULE g_WtsApiModule = NULL; static PWtsApiFunctionTable g_WtsApi = NULL; +static HMODULE g_WtsApi32Module = NULL; + +static WtsApiFunctionTable WtsApi32_WtsApiFunctionTable = +{ + 0, /* dwVersion */ + 0, /* dwFlags */ + + NULL, /* StopRemoteControlSession */ + NULL, /* StartRemoteControlSessionW */ + NULL, /* StartRemoteControlSessionA */ + NULL, /* ConnectSessionW */ + NULL, /* ConnectSessionA */ + NULL, /* EnumerateServersW */ + NULL, /* EnumerateServersA */ + NULL, /* OpenServerW */ + NULL, /* OpenServerA */ + NULL, /* OpenServerExW */ + NULL, /* OpenServerExA */ + NULL, /* CloseServer */ + NULL, /* EnumerateSessionsW */ + NULL, /* EnumerateSessionsA */ + NULL, /* EnumerateSessionsExW */ + NULL, /* EnumerateSessionsExA */ + NULL, /* EnumerateProcessesW */ + NULL, /* EnumerateProcessesA */ + NULL, /* TerminateProcess */ + NULL, /* QuerySessionInformationW */ + NULL, /* QuerySessionInformationA */ + NULL, /* QueryUserConfigW */ + NULL, /* QueryUserConfigA */ + NULL, /* SetUserConfigW */ + NULL, /* SetUserConfigA */ + NULL, /* SendMessageW */ + NULL, /* SendMessageA */ + NULL, /* DisconnectSession */ + NULL, /* LogoffSession */ + NULL, /* ShutdownSystem */ + NULL, /* WaitSystemEvent */ + NULL, /* VirtualChannelOpen */ + NULL, /* VirtualChannelOpenEx */ + NULL, /* VirtualChannelClose */ + NULL, /* VirtualChannelRead */ + NULL, /* VirtualChannelWrite */ + NULL, /* VirtualChannelPurgeInput */ + NULL, /* VirtualChannelPurgeOutput */ + NULL, /* VirtualChannelQuery */ + NULL, /* FreeMemory */ + NULL, /* RegisterSessionNotification */ + NULL, /* UnRegisterSessionNotification */ + NULL, /* RegisterSessionNotificationEx */ + NULL, /* UnRegisterSessionNotificationEx */ + NULL, /* QueryUserToken */ + NULL, /* FreeMemoryExW */ + NULL, /* FreeMemoryExA */ + NULL, /* EnumerateProcessesExW */ + NULL, /* EnumerateProcessesExA */ + NULL, /* EnumerateListenersW */ + NULL, /* EnumerateListenersA */ + NULL, /* QueryListenerConfigW */ + NULL, /* QueryListenerConfigA */ + NULL, /* CreateListenerW */ + NULL, /* CreateListenerA */ + NULL, /* SetListenerSecurityW */ + NULL, /* SetListenerSecurityA */ + NULL, /* GetListenerSecurityW */ + NULL, /* GetListenerSecurityA */ + NULL, /* EnableChildSessions */ + NULL, /* IsChildSessionsEnabled */ + NULL, /* GetChildSessionId */ + NULL /* GetActiveConsoleSessionId */ +}; + +#define WTSAPI32_LOAD_PROC(_name, _type) \ + WtsApi32_WtsApiFunctionTable.p ## _name = (## _type) GetProcAddress(g_WtsApi32Module, "WTS" #_name); + +int WtsApi32_InitializeWtsApi(void) +{ + g_WtsApi32Module = LoadLibraryA("wtsapi32.dll"); + + if (!g_WtsApi32Module) + return -1; + +#ifdef _WIN32 + WTSAPI32_LOAD_PROC(StopRemoteControlSession, WTS_STOP_REMOTE_CONTROL_SESSION_FN); + WTSAPI32_LOAD_PROC(StartRemoteControlSessionW, WTS_START_REMOTE_CONTROL_SESSION_FN_W); + WTSAPI32_LOAD_PROC(StartRemoteControlSessionA, WTS_START_REMOTE_CONTROL_SESSION_FN_A); + WTSAPI32_LOAD_PROC(ConnectSessionW, WTS_CONNECT_SESSION_FN_W); + WTSAPI32_LOAD_PROC(ConnectSessionA, WTS_CONNECT_SESSION_FN_A); + WTSAPI32_LOAD_PROC(EnumerateServersW, WTS_ENUMERATE_SERVERS_FN_W); + WTSAPI32_LOAD_PROC(EnumerateServersA, WTS_ENUMERATE_SERVERS_FN_A); + WTSAPI32_LOAD_PROC(OpenServerW, WTS_OPEN_SERVER_FN_W); + WTSAPI32_LOAD_PROC(OpenServerA, WTS_OPEN_SERVER_FN_A); + WTSAPI32_LOAD_PROC(OpenServerExW, WTS_OPEN_SERVER_EX_FN_W); + WTSAPI32_LOAD_PROC(OpenServerExA, WTS_OPEN_SERVER_EX_FN_A); + WTSAPI32_LOAD_PROC(CloseServer, WTS_CLOSE_SERVER_FN); + WTSAPI32_LOAD_PROC(EnumerateSessionsW, WTS_ENUMERATE_SESSIONS_FN_W); + WTSAPI32_LOAD_PROC(EnumerateSessionsA, WTS_ENUMERATE_SESSIONS_FN_A); + WTSAPI32_LOAD_PROC(EnumerateSessionsExW, WTS_ENUMERATE_SESSIONS_EX_FN_W); + WTSAPI32_LOAD_PROC(EnumerateSessionsExA, WTS_ENUMERATE_SESSIONS_EX_FN_A); + WTSAPI32_LOAD_PROC(EnumerateProcessesW, WTS_ENUMERATE_PROCESSES_FN_W); + WTSAPI32_LOAD_PROC(EnumerateProcessesA, WTS_ENUMERATE_PROCESSES_FN_A); + WTSAPI32_LOAD_PROC(TerminateProcess, WTS_TERMINATE_PROCESS_FN); + WTSAPI32_LOAD_PROC(QuerySessionInformationW, WTS_QUERY_SESSION_INFORMATION_FN_W); + WTSAPI32_LOAD_PROC(QuerySessionInformationA, WTS_QUERY_SESSION_INFORMATION_FN_A); + WTSAPI32_LOAD_PROC(QueryUserConfigW, WTS_QUERY_USER_CONFIG_FN_W); + WTSAPI32_LOAD_PROC(QueryUserConfigA, WTS_QUERY_USER_CONFIG_FN_A); + WTSAPI32_LOAD_PROC(SetUserConfigW, WTS_SET_USER_CONFIG_FN_W); + WTSAPI32_LOAD_PROC(SetUserConfigA, WTS_SET_USER_CONFIG_FN_A); + WTSAPI32_LOAD_PROC(SendMessageW, WTS_SEND_MESSAGE_FN_W); + WTSAPI32_LOAD_PROC(SendMessageA, WTS_SEND_MESSAGE_FN_A); + WTSAPI32_LOAD_PROC(DisconnectSession, WTS_DISCONNECT_SESSION_FN); + WTSAPI32_LOAD_PROC(LogoffSession, WTS_LOGOFF_SESSION_FN); + WTSAPI32_LOAD_PROC(ShutdownSystem, WTS_SHUTDOWN_SYSTEM_FN); + WTSAPI32_LOAD_PROC(WaitSystemEvent, WTS_WAIT_SYSTEM_EVENT_FN); + WTSAPI32_LOAD_PROC(VirtualChannelOpen, WTS_VIRTUAL_CHANNEL_OPEN_FN); + WTSAPI32_LOAD_PROC(VirtualChannelOpenEx, WTS_VIRTUAL_CHANNEL_OPEN_EX_FN); + WTSAPI32_LOAD_PROC(VirtualChannelClose, WTS_VIRTUAL_CHANNEL_CLOSE_FN); + WTSAPI32_LOAD_PROC(VirtualChannelRead, WTS_VIRTUAL_CHANNEL_READ_FN); + WTSAPI32_LOAD_PROC(VirtualChannelWrite, WTS_VIRTUAL_CHANNEL_WRITE_FN); + WTSAPI32_LOAD_PROC(VirtualChannelPurgeInput, WTS_VIRTUAL_CHANNEL_PURGE_INPUT_FN); + WTSAPI32_LOAD_PROC(VirtualChannelPurgeOutput, WTS_VIRTUAL_CHANNEL_PURGE_OUTPUT_FN); + WTSAPI32_LOAD_PROC(VirtualChannelQuery, WTS_VIRTUAL_CHANNEL_QUERY_FN); + WTSAPI32_LOAD_PROC(FreeMemory, WTS_FREE_MEMORY_FN); + WTSAPI32_LOAD_PROC(RegisterSessionNotification, WTS_REGISTER_SESSION_NOTIFICATION_FN); + WTSAPI32_LOAD_PROC(UnRegisterSessionNotification, WTS_UNREGISTER_SESSION_NOTIFICATION_FN); + WTSAPI32_LOAD_PROC(RegisterSessionNotificationEx, WTS_REGISTER_SESSION_NOTIFICATION_EX_FN); + WTSAPI32_LOAD_PROC(UnRegisterSessionNotificationEx, WTS_UNREGISTER_SESSION_NOTIFICATION_EX_FN); + WTSAPI32_LOAD_PROC(QueryUserToken, WTS_QUERY_USER_TOKEN_FN); + WTSAPI32_LOAD_PROC(FreeMemoryExW, WTS_FREE_MEMORY_EX_FN_W); + WTSAPI32_LOAD_PROC(FreeMemoryExA, WTS_FREE_MEMORY_EX_FN_A); + WTSAPI32_LOAD_PROC(EnumerateProcessesExW, WTS_ENUMERATE_PROCESSES_EX_FN_W); + WTSAPI32_LOAD_PROC(EnumerateProcessesExA, WTS_ENUMERATE_PROCESSES_EX_FN_A); + WTSAPI32_LOAD_PROC(EnumerateListenersW, WTS_ENUMERATE_LISTENERS_FN_W); + WTSAPI32_LOAD_PROC(EnumerateListenersA, WTS_ENUMERATE_LISTENERS_FN_A); + WTSAPI32_LOAD_PROC(QueryListenerConfigW, WTS_QUERY_LISTENER_CONFIG_FN_W); + WTSAPI32_LOAD_PROC(QueryListenerConfigA, WTS_QUERY_LISTENER_CONFIG_FN_A); + WTSAPI32_LOAD_PROC(CreateListenerW, WTS_CREATE_LISTENER_FN_W); + WTSAPI32_LOAD_PROC(CreateListenerA, WTS_CREATE_LISTENER_FN_A); + WTSAPI32_LOAD_PROC(SetListenerSecurityW, WTS_SET_LISTENER_SECURITY_FN_W); + WTSAPI32_LOAD_PROC(SetListenerSecurityA, WTS_SET_LISTENER_SECURITY_FN_A); + WTSAPI32_LOAD_PROC(GetListenerSecurityW, WTS_GET_LISTENER_SECURITY_FN_W); + WTSAPI32_LOAD_PROC(GetListenerSecurityA, WTS_GET_LISTENER_SECURITY_FN_A); + WTSAPI32_LOAD_PROC(EnableChildSessions, WTS_ENABLE_CHILD_SESSIONS_FN); + WTSAPI32_LOAD_PROC(IsChildSessionsEnabled, WTS_IS_CHILD_SESSIONS_ENABLED_FN); + WTSAPI32_LOAD_PROC(GetChildSessionId, WTS_GET_CHILD_SESSION_ID_FN); + WTSAPI32_LOAD_PROC(GetActiveConsoleSessionId, WTS_GET_ACTIVE_CONSOLE_SESSION_ID_FN); + + Win32_InitializeWinSta(&WtsApi32_WtsApiFunctionTable); +#endif + + g_WtsApi = &WtsApi32_WtsApiFunctionTable; + + return 1; +} + +/* WtsApi Functions */ + BOOL WINAPI WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers) { WTSAPI_STUB_CALL_BOOL(StartRemoteControlSessionW, pTargetServerName, TargetLogonId, HotkeyVk, HotkeyModifiers); @@ -170,17 +334,17 @@ BOOL WINAPI WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLA } BOOL WINAPI WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle, DWORD TitleLength, - LPWSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait) + LPWSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait) { WTSAPI_STUB_CALL_BOOL(SendMessageW, hServer, SessionId, pTitle, TitleLength, - pMessage, MessageLength, Style, Timeout, pResponse, bWait); + pMessage, MessageLength, Style, Timeout, pResponse, bWait); } BOOL WINAPI WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle, DWORD TitleLength, - LPSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait) + LPSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait) { WTSAPI_STUB_CALL_BOOL(SendMessageA, hServer, SessionId, pTitle, TitleLength, - pMessage, MessageLength, Style, Timeout, pResponse, bWait); + pMessage, MessageLength, Style, Timeout, pResponse, bWait); } BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait) @@ -314,47 +478,47 @@ BOOL WINAPI WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved, DWORD Reser } BOOL WINAPI WTSCreateListenerW(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer, DWORD flag) + LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer, DWORD flag) { WTSAPI_STUB_CALL_BOOL(CreateListenerW, hServer, pReserved, Reserved, pListenerName, pBuffer, flag); } BOOL WINAPI WTSCreateListenerA(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer, DWORD flag) + LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer, DWORD flag) { WTSAPI_STUB_CALL_BOOL(CreateListenerA, hServer, pReserved, Reserved, pListenerName, pBuffer, flag); } BOOL WINAPI WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR pSecurityDescriptor) + LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor) { WTSAPI_STUB_CALL_BOOL(SetListenerSecurityW, hServer, pReserved, Reserved, - pListenerName, SecurityInformation, pSecurityDescriptor); + pListenerName, SecurityInformation, pSecurityDescriptor); } BOOL WINAPI WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR pSecurityDescriptor) + LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor) { WTSAPI_STUB_CALL_BOOL(SetListenerSecurityA, hServer, pReserved, Reserved, - pListenerName, SecurityInformation, pSecurityDescriptor); + pListenerName, SecurityInformation, pSecurityDescriptor); } BOOL WINAPI WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded) + LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded) { WTSAPI_STUB_CALL_BOOL(GetListenerSecurityW, hServer, pReserved, Reserved, pListenerName, - SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded); + SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded); } BOOL WINAPI WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved, - LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded) + LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded) { WTSAPI_STUB_CALL_BOOL(GetListenerSecurityA, hServer, pReserved, Reserved, pListenerName, - SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded); + SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded); } BOOL CDECL WTSEnableChildSessions(BOOL bEnable) @@ -394,10 +558,11 @@ DWORD WINAPI WTSGetActiveConsoleSessionId(void) BOOL WTSRegisterWtsApiFunctionTable(PWtsApiFunctionTable table) { g_WtsApi = table; + g_Initialized = TRUE; return TRUE; } -static BOOL LoadAndInitialize(char *library) +static BOOL LoadAndInitialize(char* library) { INIT_WTSAPI_FN pInitWtsApi; g_WtsApiModule = LoadLibraryA(library); @@ -411,6 +576,7 @@ static BOOL LoadAndInitialize(char *library) { return FALSE; } + g_WtsApi = pInitWtsApi(); return TRUE; } @@ -432,52 +598,52 @@ void InitializeWtsApiStubs_Env() env = (LPSTR) malloc(nSize); nSize = GetEnvironmentVariableA("WTSAPI_LIBRARY", env, nSize); + if (env) LoadAndInitialize(env); } #define FREERDS_LIBRARY_NAME "libfreerds-fdsapi.so" + void InitializeWtsApiStubs_FreeRDS() { - char* prefix; - char* libdir; wIniFile* ini; - + const char* prefix; + const char* libdir; + if (g_WtsApi) return; - + ini = IniFile_New(); - if (IniFile_Parse(ini, "/var/run/freerds.instance") < 0) + if (IniFile_ReadFile(ini, "/var/run/freerds.instance") < 0) { IniFile_Free(ini); - fprintf(stderr, "failed to parse freerds.instance\n"); + WLog_ERR(TAG, "failed to parse freerds.instance"); LoadAndInitialize(FREERDS_LIBRARY_NAME); return; } - + prefix = IniFile_GetKeyValueString(ini, "FreeRDS", "prefix"); libdir = IniFile_GetKeyValueString(ini, "FreeRDS", "libdir"); - - fprintf(stderr, "FreeRDS (prefix / libdir): %s / %s\n", prefix, libdir); - + WLog_INFO(TAG, "FreeRDS (prefix / libdir): %s / %s", prefix, libdir); + if (prefix && libdir) { char* prefix_libdir; char* wtsapi_library; - prefix_libdir = GetCombinedPath(prefix, libdir); wtsapi_library = GetCombinedPath(prefix_libdir, FREERDS_LIBRARY_NAME); - + if (wtsapi_library) { LoadAndInitialize(wtsapi_library); } - + free(prefix_libdir); free(wtsapi_library); } - + IniFile_Free(ini); } @@ -487,9 +653,12 @@ void InitializeWtsApiStubs(void) return; g_Initialized = TRUE; - InitializeWtsApiStubs_Env(); - + +#ifdef _WIN32 + WtsApi32_InitializeWtsApi(); +#endif + if (!g_WtsApi) InitializeWtsApiStubs_FreeRDS(); diff --git a/winpr/libwinpr/wtsapi/wtsapi_win32.c b/winpr/libwinpr/wtsapi/wtsapi_win32.c new file mode 100644 index 000000000..252c3e26e --- /dev/null +++ b/winpr/libwinpr/wtsapi/wtsapi_win32.c @@ -0,0 +1,731 @@ +/** + * WinPR: Windows Portable Runtime + * Windows Terminal Services API + * + * Copyright 2013-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 + +#include + +#include "wtsapi_win32.h" + +#include "wtsapi.h" + +#define WTSAPI_CHANNEL_MAGIC 0x44484356 + +struct _WTSAPI_CHANNEL +{ + UINT32 magic; + HANDLE hServer; + DWORD SessionId; + HANDLE hFile; + HANDLE hEvent; + char* VirtualName; + + DWORD flags; + BYTE* chunk; + BOOL dynamic; + BOOL readSync; + BOOL readAsync; + BOOL readDone; + UINT32 readSize; + UINT32 readOffset; + BYTE* readBuffer; + BOOL showProtocol; + BOOL waitObjectMode; + OVERLAPPED overlapped; + CHANNEL_PDU_HEADER* header; +}; +typedef struct _WTSAPI_CHANNEL WTSAPI_CHANNEL; + +static BOOL g_Initialized = FALSE; +static HMODULE g_WinStaModule = NULL; + +typedef HANDLE (WINAPI * fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName); +typedef HANDLE (WINAPI * fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName, DWORD flags); + +static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL; +static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL; + +BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel); + +BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel) +{ + BOOL status = TRUE; + DWORD numBytes = 0; + + if (pChannel->readAsync) + return TRUE; + + ZeroMemory(&(pChannel->overlapped), sizeof(OVERLAPPED)); + pChannel->overlapped.hEvent = pChannel->hEvent; + ResetEvent(pChannel->hEvent); + + if (pChannel->showProtocol) + { + ZeroMemory(pChannel->header, sizeof(CHANNEL_PDU_HEADER)); + + status = ReadFile(pChannel->hFile, pChannel->header, + sizeof(CHANNEL_PDU_HEADER), &numBytes, &(pChannel->overlapped)); + } + else + { + status = ReadFile(pChannel->hFile, pChannel->chunk, + CHANNEL_CHUNK_LENGTH, &numBytes, &(pChannel->overlapped)); + + if (status) + { + pChannel->readOffset = 0; + pChannel->header->length = numBytes; + + pChannel->readDone = TRUE; + SetEvent(pChannel->hEvent); + + return TRUE; + } + } + + if (status) + { + fprintf(stderr, "Unexpected ReadFile status: %d numBytes: %d\n", status, numBytes); + return FALSE; /* ReadFile should return FALSE and set ERROR_IO_PENDING */ + } + + if (GetLastError() != ERROR_IO_PENDING) + { + fprintf(stderr, "ReadFile: GetLastError() = %d\n", GetLastError()); + return FALSE; + } + + pChannel->readAsync = TRUE; + + return TRUE; +} + +HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName, DWORD flags) +{ + HANDLE hFile; + HANDLE hChannel; + WTSAPI_CHANNEL* pChannel; + + if (!pVirtualName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags); + + if (!hFile) + return NULL; + + pChannel = (WTSAPI_CHANNEL*) calloc(1, sizeof(WTSAPI_CHANNEL)); + + if (!pChannel) + { + CloseHandle(hFile); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + hChannel = (HANDLE) pChannel; + pChannel->magic = WTSAPI_CHANNEL_MAGIC; + pChannel->hServer = hServer; + pChannel->SessionId = SessionId; + pChannel->hFile = hFile; + pChannel->VirtualName = _strdup(pVirtualName); + + pChannel->flags = flags; + pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE; + + pChannel->showProtocol = pChannel->dynamic; + + pChannel->readSize = CHANNEL_PDU_LENGTH; + pChannel->readBuffer = (BYTE*) malloc(pChannel->readSize); + + pChannel->header = (CHANNEL_PDU_HEADER*) pChannel->readBuffer; + pChannel->chunk = &(pChannel->readBuffer[sizeof(CHANNEL_PDU_HEADER)]); + + pChannel->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pChannel->overlapped.hEvent = pChannel->hEvent; + + if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer) + { + Win32_WTSVirtualChannelClose(hChannel); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + return hChannel; +} + +HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName) +{ + return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0); +} + +HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags) +{ + return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags); +} + +BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel) +{ + BOOL status = TRUE; + WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel; + + if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (pChannel->hFile) + { + if (pChannel->readAsync) + { + CancelIo(pChannel->hFile); + pChannel->readAsync = FALSE; + } + + status = CloseHandle(pChannel->hFile); + pChannel->hFile = NULL; + } + + if (pChannel->hEvent) + { + CloseHandle(pChannel->hEvent); + pChannel->hEvent = NULL; + } + + if (pChannel->VirtualName) + { + free(pChannel->VirtualName); + pChannel->VirtualName = NULL; + } + + if (pChannel->readBuffer) + { + free(pChannel->readBuffer); + pChannel->readBuffer = NULL; + } + + pChannel->magic = 0; + free(pChannel); + + return status; +} + +BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred) +{ + if (pChannel->readDone) + { + DWORD numBytesRead = 0; + DWORD numBytesToRead = 0; + + *lpNumberOfBytesTransferred = 0; + + numBytesToRead = nNumberOfBytesToRead; + + if (numBytesToRead > (pChannel->header->length - pChannel->readOffset)) + numBytesToRead = (pChannel->header->length - pChannel->readOffset); + + CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead); + *lpNumberOfBytesTransferred += numBytesToRead; + pChannel->readOffset += numBytesToRead; + + if (pChannel->readOffset != pChannel->header->length) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + else + { + pChannel->readDone = FALSE; + Win32_WTSVirtualChannelReadAsync(pChannel); + } + + return TRUE; + } + else if (pChannel->readSync) + { + BOOL bSuccess; + OVERLAPPED overlapped; + DWORD numBytesRead = 0; + DWORD numBytesToRead = 0; + + *lpNumberOfBytesTransferred = 0; + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + + numBytesToRead = nNumberOfBytesToRead; + + if (numBytesToRead > (pChannel->header->length - pChannel->readOffset)) + numBytesToRead = (pChannel->header->length - pChannel->readOffset); + + if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped)) + { + *lpNumberOfBytesTransferred += numBytesRead; + pChannel->readOffset += numBytesRead; + + if (pChannel->readOffset != pChannel->header->length) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + pChannel->readSync = FALSE; + Win32_WTSVirtualChannelReadAsync(pChannel); + + return TRUE; + } + + if (GetLastError() != ERROR_IO_PENDING) + return FALSE; + + bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE); + + if (!bSuccess) + return FALSE; + + *lpNumberOfBytesTransferred += numBytesRead; + pChannel->readOffset += numBytesRead; + + if (pChannel->readOffset != pChannel->header->length) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + pChannel->readSync = FALSE; + Win32_WTSVirtualChannelReadAsync(pChannel); + + return TRUE; + } + else if (pChannel->readAsync) + { + BOOL bSuccess; + DWORD numBytesRead = 0; + DWORD numBytesToRead = 0; + + *lpNumberOfBytesTransferred = 0; + + if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT) + { + bSuccess = GetOverlappedResult(pChannel->hFile, + &(pChannel->overlapped), &numBytesRead, TRUE); + + pChannel->readOffset = 0; + pChannel->header->length = numBytesRead; + + if (!bSuccess && (GetLastError() != ERROR_MORE_DATA)) + return FALSE; + + numBytesToRead = nNumberOfBytesToRead; + + if (numBytesRead < numBytesToRead) + { + numBytesToRead = numBytesRead; + nNumberOfBytesToRead = numBytesRead; + } + + CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead); + *lpNumberOfBytesTransferred += numBytesToRead; + ((BYTE*) lpBuffer) += numBytesToRead; + nNumberOfBytesToRead -= numBytesToRead; + pChannel->readOffset += numBytesToRead; + + pChannel->readAsync = FALSE; + + if (!nNumberOfBytesToRead) + { + Win32_WTSVirtualChannelReadAsync(pChannel); + return TRUE; + } + + pChannel->readSync = TRUE; + + numBytesRead = 0; + + bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, + lpBuffer, nNumberOfBytesToRead, &numBytesRead); + + *lpNumberOfBytesTransferred += numBytesRead; + return bSuccess; + } + else + { + SetLastError(ERROR_IO_INCOMPLETE); + return FALSE; + } + } + + return FALSE; +} + +BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred) +{ + if (pChannel->readSync) + { + BOOL bSuccess; + OVERLAPPED overlapped; + DWORD numBytesRead = 0; + DWORD numBytesToRead = 0; + + *lpNumberOfBytesTransferred = 0; + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + + numBytesToRead = nNumberOfBytesToRead; + + if (numBytesToRead > (pChannel->header->length - pChannel->readOffset)) + numBytesToRead = (pChannel->header->length - pChannel->readOffset); + + if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped)) + { + *lpNumberOfBytesTransferred += numBytesRead; + pChannel->readOffset += numBytesRead; + + if (pChannel->readOffset != pChannel->header->length) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + pChannel->readSync = FALSE; + Win32_WTSVirtualChannelReadAsync(pChannel); + + return TRUE; + } + + if (GetLastError() != ERROR_IO_PENDING) + return FALSE; + + bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE); + + if (!bSuccess) + return FALSE; + + *lpNumberOfBytesTransferred += numBytesRead; + pChannel->readOffset += numBytesRead; + + if (pChannel->readOffset != pChannel->header->length) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + pChannel->readSync = FALSE; + Win32_WTSVirtualChannelReadAsync(pChannel); + + return TRUE; + } + else if (pChannel->readAsync) + { + BOOL bSuccess; + DWORD numBytesRead = 0; + + *lpNumberOfBytesTransferred = 0; + + if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT) + { + bSuccess = GetOverlappedResult(pChannel->hFile, + &(pChannel->overlapped), &numBytesRead, TRUE); + + if (pChannel->showProtocol) + { + if (numBytesRead != sizeof(CHANNEL_PDU_HEADER)) + return FALSE; + + if (!bSuccess && (GetLastError() != ERROR_MORE_DATA)) + return FALSE; + + CopyMemory(lpBuffer, pChannel->header, numBytesRead); + *lpNumberOfBytesTransferred += numBytesRead; + ((BYTE*) lpBuffer) += numBytesRead; + nNumberOfBytesToRead -= numBytesRead; + } + + pChannel->readAsync = FALSE; + + if (!pChannel->header->length) + { + Win32_WTSVirtualChannelReadAsync(pChannel); + return TRUE; + } + + pChannel->readSync = TRUE; + pChannel->readOffset = 0; + + if (!nNumberOfBytesToRead) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + numBytesRead = 0; + + bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, + lpBuffer, nNumberOfBytesToRead, &numBytesRead); + + *lpNumberOfBytesTransferred += numBytesRead; + return bSuccess; + } + else + { + SetLastError(ERROR_IO_INCOMPLETE); + return FALSE; + } + } + + return FALSE; +} + +BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred) +{ + WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel; + + if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!pChannel->waitObjectMode) + { + OVERLAPPED overlapped; + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + + if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred, &overlapped)) + return TRUE; + + if (GetLastError() != ERROR_IO_PENDING) + return FALSE; + + if (!dwMilliseconds) + { + CancelIo(pChannel->hFile); + *lpNumberOfBytesTransferred = 0; + return TRUE; + } + + if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT) + return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, FALSE); + + CancelIo(pChannel->hFile); + SetLastError(ERROR_IO_INCOMPLETE); + + return FALSE; + } + else + { + if (pChannel->dynamic) + { + return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, + lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred); + } + else + { + return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, + lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred); + } + } + + return FALSE; +} + +BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesTransferred) +{ + OVERLAPPED overlapped; + WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel; + + if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + + if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred, &overlapped)) + return TRUE; + + if (GetLastError() == ERROR_IO_PENDING) + return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE); + + return FALSE; +} + +#ifndef FILE_DEVICE_TERMSRV +#define FILE_DEVICE_TERMSRV 0x00000038 +#endif + +BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode) +{ + DWORD error; + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannelHandle; + + if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + ntstatus = _NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0); + + if (ntstatus == STATUS_PENDING) + { + ntstatus = _NtWaitForSingleObject(pChannel->hFile, 0, 0); + + if (ntstatus >= 0) + ntstatus = ioStatusBlock.Status; + } + + if (ntstatus == STATUS_BUFFER_OVERFLOW) + { + ntstatus = STATUS_BUFFER_TOO_SMALL; + error = _RtlNtStatusToDosError(ntstatus); + SetLastError(error); + return FALSE; + } + + if (ntstatus < 0) + { + error = _RtlNtStatusToDosError(ntstatus); + SetLastError(error); + return FALSE; + } + + return TRUE; +} + +BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle) +{ + return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle, (FILE_DEVICE_TERMSRV << 16) | 0x0107); +} + +BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle) +{ + return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle, (FILE_DEVICE_TERMSRV << 16) | 0x010B); +} + +BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer, DWORD* pBytesReturned) +{ + WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannelHandle; + + if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (WtsVirtualClass == WTSVirtualClientData) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + else if (WtsVirtualClass == WTSVirtualFileHandle) + { + *pBytesReturned = sizeof(HANDLE); + *ppBuffer = LocalAlloc(LMEM_ZEROINIT, *pBytesReturned); + + if (*ppBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned); + } + else if (WtsVirtualClass == WTSVirtualEventHandle) + { + *pBytesReturned = sizeof(HANDLE); + *ppBuffer = LocalAlloc(LMEM_ZEROINIT, *pBytesReturned); + + if (*ppBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned); + + Win32_WTSVirtualChannelReadAsync(pChannel); + pChannel->waitObjectMode = TRUE; + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return TRUE; +} + +VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory) +{ + LocalFree(pMemory); + return TRUE; +} + +BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries) +{ + return TRUE; +} + +BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries) +{ + return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries); +} + +int Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi) +{ + g_WinStaModule = LoadLibraryA("winsta.dll"); + + if (!g_WinStaModule) + return -1; + + pfnWinStationVirtualOpen = (fnWinStationVirtualOpen) GetProcAddress(g_WinStaModule, "WinStationVirtualOpen"); + pfnWinStationVirtualOpenEx = (fnWinStationVirtualOpenEx) GetProcAddress(g_WinStaModule, "WinStationVirtualOpenEx"); + + if (!pfnWinStationVirtualOpenEx) + return -1; + + pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen; + pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx; + pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose; + pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead; + pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite; + pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput; + pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput; + pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery; + pWtsApi->pFreeMemory = Win32_WTSFreeMemory; + //pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW; + //pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA; + + return 1; +} diff --git a/winpr/libwinpr/wtsapi/wtsapi_win32.h b/winpr/libwinpr/wtsapi/wtsapi_win32.h new file mode 100644 index 000000000..c6add2f62 --- /dev/null +++ b/winpr/libwinpr/wtsapi/wtsapi_win32.h @@ -0,0 +1,27 @@ +/** + * WinPR: Windows Portable Runtime + * Windows Terminal Services API + * + * Copyright 2013-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_WTSAPI_WIN32_PRIVATE_H +#define WINPR_WTSAPI_WIN32_PRIVATE_H + +#include + +int Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi); + +#endif /* WINPR_WTSAPI_WIN32_PRIVATE_H */ diff --git a/winpr/tools/hash/CMakeLists.txt b/winpr/tools/hash/CMakeLists.txt index e9b307173..702ec184a 100644 --- a/winpr/tools/hash/CMakeLists.txt +++ b/winpr/tools/hash/CMakeLists.txt @@ -28,12 +28,8 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${ZLIB_LIBRARIES} - ${OPENSSL_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-utils) + ${OPENSSL_LIBRARIES} + winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/winpr/tools/makecert/CMakeLists.txt b/winpr/tools/makecert/CMakeLists.txt index afd925610..6afa33613 100644 --- a/winpr/tools/makecert/CMakeLists.txt +++ b/winpr/tools/makecert/CMakeLists.txt @@ -27,12 +27,8 @@ add_library(${MODULE_NAME} STATIC ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${ZLIB_LIBRARIES} - ${OPENSSL_LIBRARIES}) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-utils winpr-sysinfo winpr-file winpr-path) + ${OPENSSL_LIBRARIES} + winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/winpr/tools/makecert/makecert.c b/winpr/tools/makecert/makecert.c index ce775891c..5fea4c9bb 100644 --- a/winpr/tools/makecert/makecert.c +++ b/winpr/tools/makecert/makecert.c @@ -27,8 +27,10 @@ #include #include -#include #include +#include +#include +#include #include #include @@ -38,16 +40,27 @@ struct _MAKECERT_CONTEXT int argc; char** argv; - BIO* bio; RSA* rsa; X509* x509; EVP_PKEY* pkey; + PKCS12* pkcs12; BOOL live; BOOL silent; + BOOL crtFormat; + BOOL pemFormat; + BOOL pfxFormat; + + char* password; + char* output_file; + char* output_path; char* default_name; + char* common_name; + + int duration_years; + int duration_months; }; COMMAND_LINE_ARGUMENT_A args[] = @@ -63,6 +76,15 @@ COMMAND_LINE_ARGUMENT_A args[] = { "live", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Generate certificate live in memory when used as a library." }, + { "format", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "Specify certificate file format" + }, + { "path", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "Specify certificate file output path" + }, + { "p", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "Specify certificate export password" + }, /* Basic Options */ @@ -154,6 +176,9 @@ COMMAND_LINE_ARGUMENT_A args[] = { "m", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Specifies the duration, in months, of the certificate validity period." }, + { "y", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "Specifies the duration, in years, of the certificate validity period." + }, { "nscp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Includes the Netscape client-authorization extension." }, @@ -346,6 +371,65 @@ int makecert_context_parse_arguments(MAKECERT_CONTEXT* context, int argc, char** { context->live = TRUE; } + CommandLineSwitchCase(arg, "format") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + if (strcmp(arg->Value, "crt") == 0) + { + context->crtFormat = TRUE; + context->pemFormat = FALSE; + context->pfxFormat = FALSE; + } + else if (strcmp(arg->Value, "pem") == 0) + { + context->crtFormat = FALSE; + context->pemFormat = TRUE; + context->pfxFormat = FALSE; + } + else if (strcmp(arg->Value, "pfx") == 0) + { + context->crtFormat = FALSE; + context->pemFormat = FALSE; + context->pfxFormat = TRUE; + } + } + CommandLineSwitchCase(arg, "path") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + context->output_path = _strdup(arg->Value); + } + CommandLineSwitchCase(arg, "p") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + context->password = _strdup(arg->Value); + } + CommandLineSwitchCase(arg, "n") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + context->common_name = _strdup(arg->Value); + } + CommandLineSwitchCase(arg, "y") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + context->duration_years = atoi(arg->Value); + } + CommandLineSwitchCase(arg, "m") + { + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + continue; + + context->duration_months = atoi(arg->Value); + } CommandLineSwitchDefault(arg) { @@ -362,6 +446,7 @@ int makecert_context_parse_arguments(MAKECERT_CONTEXT* context, int argc, char** int makecert_context_set_output_file_name(MAKECERT_CONTEXT* context, char* name) { + free(context->output_file); context->output_file = _strdup(name); return 1; } @@ -369,12 +454,14 @@ int makecert_context_set_output_file_name(MAKECERT_CONTEXT* context, char* name) int makecert_context_output_certificate_file(MAKECERT_CONTEXT* context, char* path) { FILE* fp; + int status; int length; + int offset; char* filename; char* fullpath; if (!context->output_file) - context->output_file = context->default_name; + context->output_file = _strdup(context->default_name); /* * Output Certificate File @@ -383,7 +470,13 @@ int makecert_context_output_certificate_file(MAKECERT_CONTEXT* context, char* pa length = strlen(context->output_file); filename = malloc(length + 8); strcpy(filename, context->output_file); - strcpy(&filename[length], ".crt"); + + if (context->crtFormat) + strcpy(&filename[length], ".crt"); + else if (context->pemFormat) + strcpy(&filename[length], ".pem"); + else if (context->pfxFormat) + strcpy(&filename[length], ".pfx"); if (path) fullpath = GetCombinedPath(path, filename); @@ -394,7 +487,153 @@ int makecert_context_output_certificate_file(MAKECERT_CONTEXT* context, char* pa if (fp) { - PEM_write_X509(fp, context->x509); + BIO* bio; + BYTE* x509_str; + + if (context->pfxFormat) + { + if (!context->password) + { + context->password = _strdup("password"); + printf("Using default export password \"password\"\n"); + } + + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + + context->pkcs12 = PKCS12_create(context->password, context->default_name, + context->pkey, context->x509, NULL, 0, 0, 0, 0, 0); + + bio = BIO_new(BIO_s_mem()); + + if (!bio) + return -1; + + status = i2d_PKCS12_bio(bio, context->pkcs12); + + offset = 0; + length = 2048; + x509_str = (BYTE*) malloc(length); + + status = BIO_read(bio, x509_str, length); + + if (status < 0) + return -1; + + offset += status; + + while (offset >= length) + { + length *= 2; + x509_str = (BYTE*) realloc(x509_str, length); + + status = BIO_read(bio, &x509_str[offset], length); + + if (status < 0) + break; + + offset += status; + } + + if (status < 0) + return -1; + + length = offset; + + fwrite((void*) x509_str, length, 1, fp); + + free(x509_str); + BIO_free(bio); + } + else + { + bio = BIO_new(BIO_s_mem()); + + if (!bio) + return -1; + + status = PEM_write_bio_X509(bio, context->x509); + + offset = 0; + length = 2048; + x509_str = (BYTE*) malloc(length); + + status = BIO_read(bio, x509_str, length); + + if (status < 0) + return -1; + + offset += status; + + while (offset >= length) + { + length *= 2; + x509_str = (BYTE*) realloc(x509_str, length); + + status = BIO_read(bio, &x509_str[offset], length); + + if (status < 0) + break; + + offset += status; + } + + if (status < 0) + return -1; + + length = offset; + + fwrite((void*) x509_str, length, 1, fp); + + free(x509_str); + BIO_free(bio); + + if (context->pemFormat) + { + bio = BIO_new(BIO_s_mem()); + + if (!bio) + return -1; + + status = PEM_write_bio_PrivateKey(bio, context->pkey, NULL, NULL, 0, NULL, NULL); + + offset = 0; + length = 2048; + x509_str = (BYTE*) malloc(length); + + status = BIO_read(bio, x509_str, length); + + if (status < 0) + return -1; + + offset += status; + + while (offset >= length) + { + length *= 2; + x509_str = (BYTE*) realloc(x509_str, length); + + status = BIO_read(bio, &x509_str[offset], length); + + if (status < 0) + break; + + offset += status; + } + + if (status < 0) + return -1; + + length = offset; + + fwrite((void*) x509_str, length, 1, fp); + + free(x509_str); + BIO_free(bio); + } + } + fclose(fp); } @@ -407,10 +646,15 @@ int makecert_context_output_certificate_file(MAKECERT_CONTEXT* context, char* pa int makecert_context_output_private_key_file(MAKECERT_CONTEXT* context, char* path) { FILE* fp; + int status; int length; + int offset; char* filename; char* fullpath; + if (!context->crtFormat) + return 1; + if (!context->output_file) context->output_file = context->default_name; @@ -433,7 +677,50 @@ int makecert_context_output_private_key_file(MAKECERT_CONTEXT* context, char* pa if (fp) { - PEM_write_PrivateKey(fp, context->pkey, NULL, NULL, 0, NULL, NULL); + BIO* bio; + BYTE* x509_str; + + bio = BIO_new(BIO_s_mem()); + + if (!bio) + return -1; + + status = PEM_write_bio_PrivateKey(bio, context->pkey, NULL, NULL, 0, NULL, NULL); + + offset = 0; + length = 2048; + x509_str = (BYTE*) malloc(length); + + status = BIO_read(bio, x509_str, length); + + if (status < 0) + return -1; + + offset += status; + + while (offset >= length) + { + length *= 2; + x509_str = (BYTE*) realloc(x509_str, length); + + status = BIO_read(bio, &x509_str[offset], length); + + if (status < 0) + break; + + offset += status; + } + + if (status < 0) + return -1; + + length = offset; + + fwrite((void*) x509_str, length, 1, fp); + + free(x509_str); + BIO_free(bio); + fclose(fp); } @@ -456,10 +743,13 @@ int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv) if (makecert_context_parse_arguments(context, argc, argv) < 1) return 0; - context->default_name = x509_get_default_name(); + if (!context->default_name && !context->common_name) + context->default_name = x509_get_default_name(); + else + context->default_name = _strdup(context->common_name); - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); - context->bio = BIO_new_fp(stderr, BIO_NOCLOSE); + if (!context->common_name) + context->common_name = _strdup(context->default_name); if (!context->pkey) context->pkey = EVP_PKEY_new(); @@ -501,7 +791,16 @@ int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv) ASN1_INTEGER_set(X509_get_serialNumber(context->x509), serial); X509_gmtime_adj(X509_get_notBefore(context->x509), 0); - X509_gmtime_adj(X509_get_notAfter(context->x509), (long) 60 * 60 * 24 * 365); + + if (context->duration_months) + { + X509_gmtime_adj(X509_get_notAfter(context->x509), (long) (60 * 60 * 24 * 31 * context->duration_months)); + } + else if (context->duration_years) + { + X509_gmtime_adj(X509_get_notAfter(context->x509), (long) (60 * 60 * 24 * 365 * context->duration_years)); + } + X509_set_pubkey(context->x509, context->pkey); name = X509_get_subject_name(context->x509); @@ -535,19 +834,14 @@ int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv) if (entry) X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0); - entry = x509_name_parse(arg->Value, "CN", &length); - - if (!entry) - { - entry = context->default_name; - length = strlen(entry); - } + entry = context->common_name; + length = strlen(entry); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0); } else { - entry = context->default_name; + entry = context->common_name; length = strlen(entry); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8, (const unsigned char*) entry, length, -1, 0); @@ -584,7 +878,55 @@ int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv) */ if (!context->silent) - X509_print_fp(stdout, context->x509); + { + BIO* bio; + int status; + int length; + int offset; + BYTE* x509_str; + + bio = BIO_new(BIO_s_mem()); + + if (!bio) + return -1; + + status = X509_print(bio, context->x509); + + offset = 0; + length = 2048; + x509_str = (BYTE*) malloc(length + 1); + + status = BIO_read(bio, x509_str, length); + + if (status < 0) + return -1; + + offset += status; + + while (offset >= length) + { + length *= 2; + x509_str = (BYTE*) realloc(x509_str, length + 1); + + status = BIO_read(bio, &x509_str[offset], length); + + if (status < 0) + break; + + offset += status; + } + + if (status < 0) + return -1; + + length = offset; + x509_str[length] = '\0'; + + printf("%s", x509_str); + + free(x509_str); + BIO_free(bio); + } /** * Output certificate and private key to files @@ -592,8 +934,10 @@ int makecert_context_process(MAKECERT_CONTEXT* context, int argc, char** argv) if (!context->live) { - makecert_context_output_certificate_file(context, NULL); - makecert_context_output_private_key_file(context, NULL); + makecert_context_output_certificate_file(context, context->output_path); + + if (context->crtFormat) + makecert_context_output_private_key_file(context, context->output_path); } return 0; @@ -603,11 +947,12 @@ MAKECERT_CONTEXT* makecert_context_new() { MAKECERT_CONTEXT* context = NULL; - context = (MAKECERT_CONTEXT*) malloc(sizeof(MAKECERT_CONTEXT)); + context = (MAKECERT_CONTEXT*) calloc(1, sizeof(MAKECERT_CONTEXT)); if (context) { - ZeroMemory(context, sizeof(MAKECERT_CONTEXT)); + context->crtFormat = TRUE; + context->duration_years = 1; } return context; @@ -617,16 +962,16 @@ void makecert_context_free(MAKECERT_CONTEXT* context) { if (context) { + free(context->password); + X509_free(context->x509); EVP_PKEY_free(context->pkey); free(context->default_name); + free(context->common_name); CRYPTO_cleanup_all_ex_data(); - CRYPTO_mem_leaks(context->bio); - BIO_free(context->bio); - free(context); } }