Merge pull request #1679 from awakecoding/master

Robustness, WinPR, Codecs, CMake
This commit is contained in:
Marc-André Moreau 2014-02-05 13:49:38 -05:00
commit 19ab10d819
180 changed files with 14756 additions and 2369 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@ CMakeCache.txt
config.h config.h
install_manifest*.txt install_manifest*.txt
CTestTestfile.cmake CTestTestfile.cmake
freerdp.pc *.pc
Makefile Makefile
Testing Testing
cmake_install.cmake cmake_install.cmake

View File

@ -144,6 +144,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
CHECK_C_COMPILER_FLAG(-Wno-deprecated-declarations Wno-deprecated-declarations) CHECK_C_COMPILER_FLAG(-Wno-deprecated-declarations Wno-deprecated-declarations)
if(Wno-deprecated-declarations) if(Wno-deprecated-declarations)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
endif() endif()
if(NOT EXPORT_ALL_SYMBOLS) if(NOT EXPORT_ALL_SYMBOLS)
message(STATUS "GCC default symbol visibility: hidden") message(STATUS "GCC default symbol visibility: hidden")
@ -176,6 +177,7 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
CHECK_C_COMPILER_FLAG(-Wno-deprecated-declarations Wno-deprecated-declarations) CHECK_C_COMPILER_FLAG(-Wno-deprecated-declarations Wno-deprecated-declarations)
if(Wno-deprecated-declarations) if(Wno-deprecated-declarations)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
endif() endif()
endif() endif()
@ -212,8 +214,8 @@ if(IOS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -isysroot ${CMAKE_IOS_SDK_ROOT} -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -isysroot ${CMAKE_IOS_SDK_ROOT} -g")
endif() endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_EXPORTS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFREERDP_EXPORTS") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFREERDP_EXPORTS")
# Include files # Include files
if(NOT IOS) if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(fcntl.h HAVE_FCNTL_H)
@ -313,10 +315,11 @@ if(NOT IOS AND NOT ANDROID)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
endif() endif()
if(NOT WIN32)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
check_library_exists(pthread pthread_tryjoin_np "" HAVE_PTHREAD_GNU_EXT) check_library_exists(pthread pthread_tryjoin_np "" HAVE_PTHREAD_GNU_EXT)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
endif()
if(UNIX OR CYGWIN) if(UNIX OR CYGWIN)
check_include_files(sys/eventfd.h HAVE_AIO_H) check_include_files(sys/eventfd.h HAVE_AIO_H)
@ -382,6 +385,10 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_PURPOSE "codec")
set(JPEG_FEATURE_DESCRIPTION "use JPEG library") set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
set(GSM_FEATURE_TYPE "OPTIONAL")
set(GSM_FEATURE_PURPOSE "codec")
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
if(WIN32) if(WIN32)
set(X11_FEATURE_TYPE "DISABLED") set(X11_FEATURE_TYPE "DISABLED")
set(ZLIB_FEATURE_TYPE "DISABLED") set(ZLIB_FEATURE_TYPE "DISABLED")
@ -427,9 +434,7 @@ endif()
find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION}) find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION})
find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION}) find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION})
if (${WITH_DIRECTFB}) if (${WITH_DIRECTFB})
message(WARNING " message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details")
DIRECTFB is orphaned and not maintained see docs/README.directfb for details
")
endif() endif()
find_feature(ZLIB ${ZLIB_FEATURE_TYPE} ${ZLIB_FEATURE_PURPOSE} ${ZLIB_FEATURE_DESCRIPTION}) find_feature(ZLIB ${ZLIB_FEATURE_TYPE} ${ZLIB_FEATURE_PURPOSE} ${ZLIB_FEATURE_DESCRIPTION})
@ -446,6 +451,7 @@ find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FE
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION}) find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
if(TARGET_ARCH MATCHES "x86|x64") if(TARGET_ARCH MATCHES "x86|x64")
if (NOT APPLE) if (NOT APPLE)
@ -456,7 +462,7 @@ if(TARGET_ARCH MATCHES "x86|x64")
endif() endif()
# Installation Paths # Installation Paths
if(WIN32) if(WIN32 AND NOT FREERDP_SDK)
set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_BINDIR ".")
set(CMAKE_INSTALL_LIBDIR ".") set(CMAKE_INSTALL_LIBDIR ".")
endif() endif()
@ -521,12 +527,6 @@ include_directories("${CMAKE_BINARY_DIR}/winpr/include")
add_subdirectory(winpr) add_subdirectory(winpr)
# Generate pkg-config
if(NOT MSVC)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
if(WITH_CUNIT) if(WITH_CUNIT)
message(FATAL_ERROR "cunit (WITH_CUNIT) is deprecated please use BUILD_TESTING to build ctest tests. message(FATAL_ERROR "cunit (WITH_CUNIT) is deprecated please use BUILD_TESTING to build ctest tests.
The cunit directory contains the old tests and is kept until all tests are converted.") The cunit directory contains the old tests and is kept until all tests are converted.")

View File

@ -212,6 +212,74 @@ void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT3
} }
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
int index;
int formatNameLength;
CLIPRDR_FORMAT* formats;
CLIPRDR_FORMAT_LIST formatList;
formatList.msgType = CB_FORMAT_LIST;
formatList.msgFlags = msgFlags;
formatList.dataLen = dataLen;
formatList.cFormats = 0;
while (dataLen)
{
Stream_Seek(s, 4); /* formatId */
dataLen -= 4;
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
formatList.cFormats++;
}
index = 0;
dataLen = formatList.dataLen;
Stream_Rewind(s, dataLen);
formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats);
formatList.formats = formats;
while (dataLen)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId */
dataLen -= 4;
formats[index].formatName = NULL;
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
if (formatNameLength)
{
formatNameLength = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
-1, &(formats[index].formatName), 0, NULL, NULL);
Stream_Seek(s, formatNameLength * 2);
dataLen -= (formatNameLength * 2);
}
else
{
Stream_Seek(s, 2);
dataLen -= 2;
}
index++;
}
if (context->ServerFormatList)
context->ServerFormatList(context, &formatList);
for (index = 0; index < formatList.cFormats; index++)
free(formats[index].formatName);
free(formats);
}
else
{ {
int i; int i;
UINT32 format; UINT32 format;
@ -303,22 +371,56 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
cliprdr_send_format_list_response(cliprdr); cliprdr_send_format_list_response(cliprdr);
} }
}
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{ {
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */ CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
wMessage* event;
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
if (context->custom)
{
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse.msgFlags = msgFlags;
formatListResponse.dataLen = dataLen;
if (context->ServerFormatListResponse)
context->ServerFormatListResponse(context, &formatListResponse);
}
else
{
if ((msgFlags & CB_RESPONSE_FAIL) != 0) if ((msgFlags & CB_RESPONSE_FAIL) != 0)
{ {
/* In case of an error the clipboard will not be synchronized with the server. /* In case of an error the clipboard will not be synchronized with the server.
* Post this event to restart format negociation and data transfer. */ * Post this event to restart format negotiation and data transfer. */
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
wMessage* event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
} }
} }
}
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
formatDataRequest.msgFlags = msgFlags;
formatDataRequest.dataLen = dataLen;
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
if (context->ServerFormatDataRequest)
context->ServerFormatDataRequest(context, &formatDataRequest);
}
else
{ {
RDP_CB_DATA_REQUEST_EVENT* cb_event; RDP_CB_DATA_REQUEST_EVENT* cb_event;
@ -328,6 +430,7 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
Stream_Read_UINT32(s, cb_event->format); Stream_Read_UINT32(s, cb_event->format);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
} }
}
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event) void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event)
{ {
@ -360,6 +463,30 @@ void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DA
} }
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
formatDataResponse.msgFlags = msgFlags;
formatDataResponse.dataLen = dataLen;
formatDataResponse.requestedFormatData = NULL;
if (dataLen)
{
formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen);
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
}
if (context->ClientFormatDataResponse)
context->ClientFormatDataResponse(context, &formatDataResponse);
free(formatDataResponse.requestedFormatData);
}
else
{ {
RDP_CB_DATA_RESPONSE_EVENT* cb_event; RDP_CB_DATA_RESPONSE_EVENT* cb_event;
@ -375,3 +502,4 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
} }
}

View File

@ -53,6 +53,14 @@ static const char* const CB_MSG_TYPE_STRINGS[] =
"CB_UNLOCK_CLIPDATA" "CB_UNLOCK_CLIPDATA"
}; };
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
{
CliprdrClientContext* pInterface;
rdpSvcPlugin* plugin = (rdpSvcPlugin*) cliprdr;
pInterface = (CliprdrClientContext*) plugin->channel_entry_points.pInterface;
return pInterface;
}
wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen) wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen)
{ {
wStream* s; wStream* s;
@ -110,7 +118,9 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
{ {
UINT32 version; UINT32 version;
UINT32 generalFlags; UINT32 generalFlags;
RDP_CB_CLIP_CAPS *caps_event; CliprdrClientContext* context;
context = cliprdr_get_client_interface(cliprdr);
Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, version); /* version (4 bytes) */
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
@ -121,9 +131,6 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
cliprdr_print_general_capability_flags(generalFlags); cliprdr_print_general_capability_flags(generalFlags);
#endif #endif
caps_event = (RDP_CB_CLIP_CAPS *)freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL);
caps_event->capabilities = generalFlags;
if (generalFlags & CB_USE_LONG_FORMAT_NAMES) if (generalFlags & CB_USE_LONG_FORMAT_NAMES)
cliprdr->use_long_format_names = TRUE; cliprdr->use_long_format_names = TRUE;
@ -138,8 +145,32 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
cliprdr->received_caps = TRUE; cliprdr->received_caps = TRUE;
svc_plugin_send_event((rdpSvcPlugin *)cliprdr, (wMessage *)caps_event); if (context->custom)
{
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;
if (context->ServerCapabilities)
context->ServerCapabilities(context, &capabilities);
}
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);
}
} }
static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags)
@ -194,6 +225,21 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr)
} }
static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags)
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
CLIPRDR_MONITOR_READY monitorReady;
monitorReady.msgType = CB_MONITOR_READY;
monitorReady.msgFlags = flags;
monitorReady.dataLen = length;
if (context->MonitorReady)
context->MonitorReady(context, &monitorReady);
}
else
{ {
RDP_CB_MONITOR_READY_EVENT* event; RDP_CB_MONITOR_READY_EVENT* event;
@ -204,6 +250,7 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event);
} }
}
static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
{ {
@ -290,23 +337,127 @@ static void cliprdr_process_terminate(rdpSvcPlugin* plugin)
* Callback Interface * Callback Interface
*/ */
int cliprdr_monitor_ready(CliprdrClientContext* context) int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities)
{ {
wStream* s;
CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
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 */
cliprdr_packet_send(cliprdr, s);
return 0; return 0;
} }
int cliprdr_format_list(CliprdrClientContext* context) int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList)
{ {
int index;
wStream* s;
int length = 0;
int formatNameSize;
CLIPRDR_FORMAT* format;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
for (index = 0; index < formatList->cFormats; index++)
{
format = (CLIPRDR_FORMAT*) &(formatList->formats[index]);
length += 4;
formatNameSize = 2;
if (format->formatName)
formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2;
length += formatNameSize;
}
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length);
for (index = 0; index < formatList->cFormats; 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;
Stream_Seek(s, formatNameSize);
}
else
{
Stream_Write_UINT16(s, 0);
}
}
cliprdr_packet_send(cliprdr, s);
return 0; return 0;
} }
int cliprdr_data_request(CliprdrClientContext* context) int cliprdr_client_format_list_response(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
{ {
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatListResponse->msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse->dataLen = 0;
s = cliprdr_packet_new(formatListResponse->msgType, formatListResponse->msgFlags, formatListResponse->dataLen);
cliprdr_packet_send(cliprdr, s);
return 0; return 0;
} }
int cliprdr_data_response(CliprdrClientContext* context) int cliprdr_client_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
{ {
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatDataRequest->msgType = CB_FORMAT_DATA_REQUEST;
formatDataRequest->msgFlags = 0;
formatDataRequest->dataLen = 4;
s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, formatDataRequest->dataLen);
Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
cliprdr_packet_send(cliprdr, s);
return 0;
}
int cliprdr_client_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
{
wStream* s;
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE;
s = cliprdr_packet_new(formatDataResponse->msgType, formatDataResponse->msgFlags, formatDataResponse->dataLen);
Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
cliprdr_packet_send(cliprdr, s);
return 0; return 0;
} }
@ -315,25 +466,25 @@ int cliprdr_data_response(CliprdrClientContext* context)
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{ {
cliprdrPlugin* _p; cliprdrPlugin* cliprdr;
CliprdrClientContext* context; CliprdrClientContext* context;
CHANNEL_ENTRY_POINTS_EX* pEntryPointsEx; CHANNEL_ENTRY_POINTS_EX* pEntryPointsEx;
_p = (cliprdrPlugin*) malloc(sizeof(cliprdrPlugin)); cliprdr = (cliprdrPlugin*) malloc(sizeof(cliprdrPlugin));
ZeroMemory(_p, sizeof(cliprdrPlugin)); ZeroMemory(cliprdr, sizeof(cliprdrPlugin));
_p->plugin.channel_def.options = cliprdr->plugin.channel_def.options =
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL; CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(_p->plugin.channel_def.name, "cliprdr"); strcpy(cliprdr->plugin.channel_def.name, "cliprdr");
_p->plugin.connect_callback = cliprdr_process_connect; cliprdr->plugin.connect_callback = cliprdr_process_connect;
_p->plugin.receive_callback = cliprdr_process_receive; cliprdr->plugin.receive_callback = cliprdr_process_receive;
_p->plugin.event_callback = cliprdr_process_event; cliprdr->plugin.event_callback = cliprdr_process_event;
_p->plugin.terminate_callback = cliprdr_process_terminate; cliprdr->plugin.terminate_callback = cliprdr_process_terminate;
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_EX*) pEntryPoints; pEntryPointsEx = (CHANNEL_ENTRY_POINTS_EX*) pEntryPoints;
@ -341,16 +492,20 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
{ {
context = (CliprdrClientContext*) malloc(sizeof(CliprdrClientContext)); context = (CliprdrClientContext*) malloc(sizeof(CliprdrClientContext));
ZeroMemory(context, sizeof(CliprdrClientContext));
context->MonitorReady = cliprdr_monitor_ready; context->handle = (void*) cliprdr;
context->FormatList = cliprdr_format_list;
context->DataRequest = cliprdr_data_request; context->ClientCapabilities = cliprdr_client_capabilities;
context->DataResponse = cliprdr_data_response; 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; *(pEntryPointsEx->ppInterface) = (void*) context;
} }
svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints); svc_plugin_init((rdpSvcPlugin*) cliprdr, pEntryPoints);
return 1; return 1;
} }

View File

@ -41,6 +41,8 @@ typedef struct cliprdr_plugin cliprdrPlugin;
wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen); wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen);
void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out); void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out);
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
#ifdef WITH_DEBUG_CLIPRDR #ifdef WITH_DEBUG_CLIPRDR
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(CLIPRDR, fmt, ## __VA_ARGS__) #define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(CLIPRDR, fmt, ## __VA_ARGS__)
#else #else

View File

@ -28,14 +28,6 @@
#define CLIPRDR_HEADER_LENGTH 8 #define CLIPRDR_HEADER_LENGTH 8
struct _CLIPRDR_HEADER
{
UINT16 msgType;
UINT16 msgFlags;
UINT32 dataLen;
};
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
struct _cliprdr_server_private struct _cliprdr_server_private
{ {
HANDLE Thread; HANDLE Thread;

View File

@ -42,7 +42,7 @@ RailClientContext* rail_get_client_interface(void* railObject)
{ {
RailClientContext* pInterface; RailClientContext* pInterface;
rdpSvcPlugin* plugin = (rdpSvcPlugin*) railObject; rdpSvcPlugin* plugin = (rdpSvcPlugin*) railObject;
pInterface = (RailClientContext*) *(plugin->channel_entry_points.ppInterface); pInterface = (RailClientContext*) plugin->channel_entry_points.pInterface;
return pInterface; return pInterface;
} }
@ -503,25 +503,25 @@ int rail_server_get_appid_response(RailClientContext* context, RAIL_GET_APPID_RE
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{ {
railPlugin* _p; railPlugin* rail;
RailClientContext* context; RailClientContext* context;
CHANNEL_ENTRY_POINTS_EX* pEntryPointsEx; CHANNEL_ENTRY_POINTS_EX* pEntryPointsEx;
_p = (railPlugin*) malloc(sizeof(railPlugin)); rail = (railPlugin*) malloc(sizeof(railPlugin));
ZeroMemory(_p, sizeof(railPlugin)); ZeroMemory(rail, sizeof(railPlugin));
_p->plugin.channel_def.options = rail->plugin.channel_def.options =
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL; CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(_p->plugin.channel_def.name, "rail"); strcpy(rail->plugin.channel_def.name, "rail");
_p->plugin.connect_callback = rail_process_connect; rail->plugin.connect_callback = rail_process_connect;
_p->plugin.receive_callback = rail_process_receive; rail->plugin.receive_callback = rail_process_receive;
_p->plugin.event_callback = rail_process_event; rail->plugin.event_callback = rail_process_event;
_p->plugin.terminate_callback = rail_process_terminate; rail->plugin.terminate_callback = rail_process_terminate;
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_EX*) pEntryPoints; pEntryPointsEx = (CHANNEL_ENTRY_POINTS_EX*) pEntryPoints;
@ -530,7 +530,7 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{ {
context = (RailClientContext*) malloc(sizeof(RailClientContext)); context = (RailClientContext*) malloc(sizeof(RailClientContext));
context->handle = (void*) _p; context->handle = (void*) rail;
context->ClientExecute = rail_client_execute; context->ClientExecute = rail_client_execute;
context->ClientActivate = rail_client_activate; context->ClientActivate = rail_client_activate;
@ -557,11 +557,11 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
} }
WLog_Init(); WLog_Init();
_p->log = WLog_Get("com.freerdp.channels.rail.client"); rail->log = WLog_Get("com.freerdp.channels.rail.client");
WLog_Print(_p->log, WLOG_DEBUG, "VirtualChannelEntry"); WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntry");
svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints); svc_plugin_init((rdpSvcPlugin*) rail, pEntryPoints);
return 1; return 1;
} }

View File

@ -17,10 +17,6 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* Use AudioQueue to implement audio redirection
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
@ -40,163 +36,242 @@
#include "rdpsnd_main.h" #include "rdpsnd_main.h"
#define AQ_NUM_BUFFERS 10 #define MAC_AUDIO_QUEUE_NUM_BUFFERS 10
#define AQ_BUF_SIZE (32 * 1024) #define MAC_AUDIO_QUEUE_BUFFER_SIZE 32768
static void aq_playback_cb(void *user_data, struct rdpsnd_mac_plugin
AudioQueueRef aq_ref,
AudioQueueBufferRef aq_buf_ref
);
struct rdpsnd_audio_q_plugin
{ {
rdpsndDevicePlugin device; rdpsndDevicePlugin device;
/* audio queue player state */ BOOL isOpen;
int is_open; // true when audio_q has been inited BOOL isPlaying;
char * device_name;
int is_playing;
int buf_index;
AudioStreamBasicDescription data_format; UINT32 latency;
AudioQueueRef aq_ref; AUDIO_FORMAT format;
AudioQueueBufferRef buffers[AQ_NUM_BUFFERS]; int audioBufferIndex;
AudioQueueRef audioQueue;
AudioStreamBasicDescription audioFormat;
AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS];
}; };
typedef struct rdpsnd_audio_q_plugin rdpsndAudioQPlugin; typedef struct rdpsnd_mac_plugin rdpsndMacPlugin;
static void rdpsnd_audio_close(rdpsndDevicePlugin* device) static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{ {
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin*) device;
AudioQueueStop(aq_plugin_p->aq_ref, 0);
aq_plugin_p->is_open = 0;
} }
static void rdpsnd_audio_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static void rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
int rv; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
int i;
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; mac->latency = (UINT32) latency;
if (aq_plugin_p->is_open) { CopyMemory(&(mac->format), format, sizeof(AUDIO_FORMAT));
return;
}
aq_plugin_p->buf_index = 0;
// setup AudioStreamBasicDescription
aq_plugin_p->data_format.mSampleRate = 44100;
aq_plugin_p->data_format.mFormatID = kAudioFormatLinearPCM;
aq_plugin_p->data_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
// until we know better, assume that one packet = one frame
// one frame = bytes_per_sample x number_of_channels
aq_plugin_p->data_format.mBytesPerPacket = 4;
aq_plugin_p->data_format.mFramesPerPacket = 1;
aq_plugin_p->data_format.mBytesPerFrame = 4;
aq_plugin_p->data_format.mChannelsPerFrame = 2;
aq_plugin_p->data_format.mBitsPerChannel = 16;
rv = AudioQueueNewOutput(
&aq_plugin_p->data_format, // audio stream basic desc
aq_playback_cb, // callback when more data is required
aq_plugin_p, // data to pass to callback
CFRunLoopGetCurrent(), // The current run loop, and the one on
// which the audio queue playback callback
// will be invoked
kCFRunLoopCommonModes, // run loop modes in which callbacks can
// be invoked
0, // flags - reserved
&aq_plugin_p->aq_ref
);
if (rv != 0) {
fprintf(stderr, "rdpsnd_audio_open: AudioQueueNewOutput() failed with error %d\n", rv);
aq_plugin_p->is_open = 1;
return;
}
for (i = 0; i < AQ_NUM_BUFFERS; i++)
{
rv = AudioQueueAllocateBuffer(aq_plugin_p->aq_ref, AQ_BUF_SIZE, &aq_plugin_p->buffers[i]);
}
aq_plugin_p->is_open = 1;
}
static void rdpsnd_audio_free(rdpsndDevicePlugin* device)
{
}
static BOOL rdpsnd_audio_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format)
{
switch (format->wFormatTag) switch (format->wFormatTag)
{ {
case 1: /* PCM */ case WAVE_FORMAT_ALAW:
if (format->cbSize == 0 && mac->audioFormat.mFormatID = kAudioFormatALaw;
(format->nSamplesPerSec <= 48000) && break;
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels == 1 || format->nChannels == 2)) case WAVE_FORMAT_MULAW:
{ mac->audioFormat.mFormatID = kAudioFormatULaw;
return 1; break;
}
case WAVE_FORMAT_PCM:
mac->audioFormat.mFormatID = kAudioFormatLinearPCM;
break;
case WAVE_FORMAT_GSM610:
mac->audioFormat.mFormatID = kAudioFormatMicrosoftGSM;
break;
default:
break; break;
} }
return 0;
mac->audioFormat.mSampleRate = format->nSamplesPerSec;
mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
mac->audioFormat.mFramesPerPacket = 1;
mac->audioFormat.mChannelsPerFrame = format->nChannels;
mac->audioFormat.mBitsPerChannel = format->wBitsPerSample;
mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
mac->audioFormat.mBytesPerPacket = format->nBlockAlign;
mac->audioFormat.mReserved = 0;
rdpsnd_print_audio_format(format);
} }
static void rdpsnd_audio_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
} int index;
OSStatus status;
static void rdpsnd_audio_set_volume(rdpsndDevicePlugin* device, UINT32 value) rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (mac->isOpen)
return;
mac->audioBufferIndex = 0;
device->SetFormat(device, format, 0);
status = AudioQueueNewOutput(&(mac->audioFormat),
mac_audio_queue_output_cb, mac,
NULL, NULL, 0, &(mac->audioQueue));
if (status != 0)
{ {
} fprintf(stderr, "AudioQueueNewOutput failure\n");
static void rdpsnd_audio_play(rdpsndDevicePlugin* device, BYTE* data, int size)
{
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device;
AudioQueueBufferRef aq_buf_ref;
int len;
if (!aq_plugin_p->is_open) {
return; return;
} }
/* get next empty buffer */ UInt32 DecodeBufferSizeFrames;
aq_buf_ref = aq_plugin_p->buffers[aq_plugin_p->buf_index]; UInt32 propertySize = sizeof(DecodeBufferSizeFrames);
// fill aq_buf_ref with audio data AudioQueueGetProperty(mac->audioQueue,
len = size > AQ_BUF_SIZE ? AQ_BUF_SIZE : size; kAudioQueueProperty_DecodeBufferSizeFrames,
&DecodeBufferSizeFrames,
&propertySize);
memcpy(aq_buf_ref->mAudioData, (char *) data, len); if (status != 0)
aq_buf_ref->mAudioDataByteSize = len;
// add buffer to audioqueue
AudioQueueEnqueueBuffer(aq_plugin_p->aq_ref, aq_buf_ref, 0, 0);
// update buf_index
aq_plugin_p->buf_index++;
if (aq_plugin_p->buf_index >= AQ_NUM_BUFFERS) {
aq_plugin_p->buf_index = 0;
}
}
static void rdpsnd_audio_start(rdpsndDevicePlugin* device)
{ {
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; printf("AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n");
AudioQueueStart(aq_plugin_p->aq_ref, NULL);
} }
/** for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
* AudioQueue Playback callback
*
* our job here is to fill aq_buf_ref with audio data and enqueue it
*/
static void aq_playback_cb(void* user_data, AudioQueueRef aq_ref, AudioQueueBufferRef aq_buf_ref)
{ {
status = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, &mac->audioBuffers[index]);
if (status != 0)
{
fprintf(stderr, "AudioQueueAllocateBuffer failed\n");
}
}
mac->isOpen = TRUE;
}
static void rdpsnd_mac_close(rdpsndDevicePlugin* device)
{
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (mac->isOpen)
{
mac->isOpen = FALSE;
AudioQueueStop(mac->audioQueue, true);
AudioQueueDispose(mac->audioQueue, true);
mac->audioQueue = NULL;
mac->isPlaying = FALSE;
}
}
static void rdpsnd_mac_free(rdpsndDevicePlugin* device)
{
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
device->Close(device);
free(mac);
}
static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format)
{
if (format->wFormatTag == WAVE_FORMAT_PCM)
{
return TRUE;
}
else if (format->wFormatTag == WAVE_FORMAT_ALAW)
{
return TRUE;
}
else if (format->wFormatTag == WAVE_FORMAT_MULAW)
{
return TRUE;
}
else if (format->wFormatTag == WAVE_FORMAT_GSM610)
{
return FALSE;
}
return FALSE;
}
static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{
OSStatus status;
Float32 fVolume;
UINT16 volumeLeft;
UINT16 volumeRight;
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (!mac->audioQueue)
return;
volumeLeft = (value & 0xFFFF);
volumeRight = ((value >> 16) & 0xFFFF);
fVolume = ((float) volumeLeft) / 65535.0;
status = AudioQueueSetParameter(mac->audioQueue, kAudioQueueParam_Volume, fVolume);
if (status != 0)
{
fprintf(stderr, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
}
}
static void rdpsnd_mac_start(rdpsndDevicePlugin* device)
{
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (!mac->isPlaying)
{
OSStatus status;
if (!mac->audioQueue)
return;
status = AudioQueueStart(mac->audioQueue, NULL);
if (status != 0)
{
fprintf(stderr, "AudioQueueStart failed\n");
}
mac->isPlaying = TRUE;
}
}
static void rdpsnd_mac_play(rdpsndDevicePlugin* device, BYTE* data, int size)
{
int length;
AudioQueueBufferRef audioBuffer;
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (!mac->isOpen)
return;
audioBuffer = mac->audioBuffers[mac->audioBufferIndex];
length = size > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : size;
CopyMemory(audioBuffer->mAudioData, data, length);
audioBuffer->mAudioDataByteSize = length;
AudioQueueEnqueueBuffer(mac->audioQueue, audioBuffer, 0, 0);
mac->audioBufferIndex++;
if (mac->audioBufferIndex >= MAC_AUDIO_QUEUE_NUM_BUFFERS)
{
mac->audioBufferIndex = 0;
}
device->Start(device);
} }
#ifdef STATIC_CHANNELS #ifdef STATIC_CHANNELS
@ -205,31 +280,25 @@ static void aq_playback_cb(void* user_data, AudioQueueRef aq_ref, AudioQueueBuff
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
{ {
fprintf(stderr, "freerdp_rdpsnd_client_subsystem_entry()\n\n"); rdpsndMacPlugin* mac;
ADDIN_ARGV* args; mac = (rdpsndMacPlugin*) malloc(sizeof(rdpsndMacPlugin));
rdpsndAudioQPlugin* aqPlugin;
aqPlugin = (rdpsndAudioQPlugin*) malloc(sizeof(rdpsndAudioQPlugin)); if (mac)
ZeroMemory(aqPlugin, sizeof(rdpsndAudioQPlugin));
aqPlugin->device.Open = rdpsnd_audio_open;
aqPlugin->device.FormatSupported = rdpsnd_audio_format_supported;
aqPlugin->device.SetFormat = rdpsnd_audio_set_format;
aqPlugin->device.SetVolume = rdpsnd_audio_set_volume;
aqPlugin->device.Play = rdpsnd_audio_play;
aqPlugin->device.Start = rdpsnd_audio_start;
aqPlugin->device.Close = rdpsnd_audio_close;
aqPlugin->device.Free = rdpsnd_audio_free;
args = pEntryPoints->args;
if (args->argc > 2)
{ {
/* TODO: parse device name */ ZeroMemory(mac, sizeof(rdpsndMacPlugin));
}
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) aqPlugin); mac->device.Open = rdpsnd_mac_open;
mac->device.FormatSupported = rdpsnd_mac_format_supported;
mac->device.SetFormat = rdpsnd_mac_set_format;
mac->device.SetVolume = rdpsnd_mac_set_volume;
mac->device.Play = rdpsnd_mac_play;
mac->device.Start = rdpsnd_mac_start;
mac->device.Close = rdpsnd_mac_close;
mac->device.Free = rdpsnd_mac_free;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
}
return 0; return 0;
} }

View File

@ -32,7 +32,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MODULE freerdp MODULE freerdp
MODULES freerdp-codec freerdp-utils) MODULES freerdp-codec freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY}) list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY})
if(GSM_FOUND)
list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES})
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -26,10 +26,15 @@
#include <string.h> #include <string.h>
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h> #include <winpr/cmdline.h>
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
#ifdef WITH_GSM
#include <gsm/gsm.h>
#endif
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/codec/dsp.h> #include <freerdp/codec/dsp.h>
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
@ -52,6 +57,11 @@ struct rdpsnd_pulse_plugin
int latency; int latency;
FREERDP_DSP_CONTEXT* dsp_context; FREERDP_DSP_CONTEXT* dsp_context;
#ifdef WITH_GSM
gsm gsm_context;
wStream* gsmBuffer;
#endif
}; };
static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata) static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata)
@ -241,6 +251,7 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT*
break; break;
case WAVE_FORMAT_GSM610: case WAVE_FORMAT_GSM610:
sample_spec.format = PA_SAMPLE_S16LE;
break; break;
} }
@ -331,6 +342,14 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
if (state == PA_STREAM_READY) if (state == PA_STREAM_READY)
{ {
freerdp_dsp_context_reset_adpcm(pulse->dsp_context); freerdp_dsp_context_reset_adpcm(pulse->dsp_context);
#ifdef WITH_GSM
if (pulse->gsm_context)
gsm_destroy(pulse->gsm_context);
pulse->gsm_context = gsm_create();
#endif
DEBUG_SVC("connected"); DEBUG_SVC("connected");
} }
else else
@ -410,7 +429,18 @@ static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORM
return TRUE; return TRUE;
} }
break; break;
#ifdef WITH_GSM
case WAVE_FORMAT_GSM610:
if ((format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->nBlockAlign == 65) && (format->nChannels == 1))
{
return TRUE;
} }
break;
#endif
}
return FALSE; return FALSE;
} }
@ -459,63 +489,108 @@ static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
} }
static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* size)
{
BYTE* pcmData = NULL;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
if (pulse->format == WAVE_FORMAT_ADPCM)
{
pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context,
data, *size, pulse->sample_spec.channels, pulse->block_size);
*size = pulse->dsp_context->adpcm_size;
pcmData = pulse->dsp_context->adpcm_buffer;
}
else if (pulse->format == WAVE_FORMAT_DVI_ADPCM)
{
pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context,
data, *size, pulse->sample_spec.channels, pulse->block_size);
*size = pulse->dsp_context->adpcm_size;
pcmData = pulse->dsp_context->adpcm_buffer;
}
#ifdef WITH_GSM
else if (pulse->format == WAVE_FORMAT_GSM610)
{
int inPos = 0;
int inSize = *size;
UINT16 gsmBlockBuffer[160];
Stream_SetPosition(pulse->gsmBuffer, 0);
while (inSize)
{
ZeroMemory(gsmBlockBuffer, sizeof(gsmBlockBuffer));
gsm_decode(pulse->gsm_context, (gsm_byte*) &data[inPos], (gsm_signal*) gsmBlockBuffer);
if ((inPos % 65) == 0)
{
inPos += 33;
inSize -= 33;
}
else
{
inPos += 32;
inSize -= 32;
}
Stream_EnsureRemainingCapacity(pulse->gsmBuffer, 160 * 2);
Stream_Write(pulse->gsmBuffer, (void*) gsmBlockBuffer, 160 * 2);
}
Stream_SealLength(pulse->gsmBuffer);
pcmData = Stream_Buffer(pulse->gsmBuffer);
*size = Stream_Length(pulse->gsmBuffer);
}
#endif
else
{
pcmData = data;
}
return pcmData;
}
static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size) static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size)
{ {
int len; int length;
int ret; int status;
BYTE* src; BYTE* pcmData;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
if (!pulse->stream) if (!pulse->stream)
return; return;
if (pulse->format == WAVE_FORMAT_ADPCM) pcmData = rdpsnd_pulse_convert_audio(device, data, &size);
{
pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context,
data, size, pulse->sample_spec.channels, pulse->block_size);
size = pulse->dsp_context->adpcm_size;
src = pulse->dsp_context->adpcm_buffer;
}
else if (pulse->format == WAVE_FORMAT_DVI_ADPCM)
{
pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context,
data, size, pulse->sample_spec.channels, pulse->block_size);
size = pulse->dsp_context->adpcm_size;
src = pulse->dsp_context->adpcm_buffer;
}
else
{
src = data;
}
pa_threaded_mainloop_lock(pulse->mainloop); pa_threaded_mainloop_lock(pulse->mainloop);
while (size > 0) while (size > 0)
{ {
while ((len = pa_stream_writable_size(pulse->stream)) == 0) while ((length = pa_stream_writable_size(pulse->stream)) == 0)
{ {
pa_threaded_mainloop_wait(pulse->mainloop); pa_threaded_mainloop_wait(pulse->mainloop);
} }
if (len < 0) if (length < 0)
break; break;
if (len > size) if (length > size)
len = size; length = size;
ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE); status = pa_stream_write(pulse->stream, pcmData, length, NULL, 0LL, PA_SEEK_RELATIVE);
if (ret < 0) if (status < 0)
{ {
DEBUG_WARN("pa_stream_write failed (%d)", DEBUG_WARN("pa_stream_write failed (%d)",
pa_context_errno(pulse->context)); pa_context_errno(pulse->context));
break; break;
} }
src += len; pcmData += length;
size -= len; size -= length;
} }
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
@ -595,6 +670,10 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
pulse->dsp_context = freerdp_dsp_context_new(); pulse->dsp_context = freerdp_dsp_context_new();
#ifdef WITH_GSM
pulse->gsmBuffer = Stream_New(NULL, 4096);
#endif
pulse->mainloop = pa_threaded_mainloop_new(); pulse->mainloop = pa_threaded_mainloop_new();
if (!pulse->mainloop) if (!pulse->mainloop)

View File

@ -33,6 +33,7 @@
#include <string.h> #include <string.h>
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/thread.h> #include <winpr/thread.h>
@ -62,9 +63,11 @@ struct rdpsnd_plugin
UINT32 OpenHandle; UINT32 OpenHandle;
wMessagePipe* MsgPipe; wMessagePipe* MsgPipe;
wLog* log;
HANDLE ScheduleThread; HANDLE ScheduleThread;
BYTE cBlockNo; BYTE cBlockNo;
UINT16 wQualityMode;
int wCurrentFormatNo; int wCurrentFormatNo;
AUDIO_FORMAT* ServerFormats; AUDIO_FORMAT* ServerFormats;
@ -91,7 +94,7 @@ struct rdpsnd_plugin
rdpsndDevicePlugin* device; rdpsndDevicePlugin* device;
}; };
static void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo); static void rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave);
static void* rdpsnd_schedule_thread(void* arg) static void* rdpsnd_schedule_thread(void* arg)
{ {
@ -123,9 +126,10 @@ static void* rdpsnd_schedule_thread(void* arg)
Sleep(wTimeDiff); Sleep(wTimeDiff);
} }
rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo); rdpsnd_confirm_wave(rdpsnd, wave);
free(wave);
message.wParam = NULL; message.wParam = NULL;
free(wave);
} }
return NULL; return NULL;
@ -139,9 +143,11 @@ void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */ Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */
Stream_Write_UINT8(pdu, 0); /* bPad */ Stream_Write_UINT8(pdu, 0); /* bPad */
Stream_Write_UINT16(pdu, 4); /* BodySize */ Stream_Write_UINT16(pdu, 4); /* BodySize */
Stream_Write_UINT16(pdu, HIGH_QUALITY); /* wQualityMode */ Stream_Write_UINT16(pdu, rdpsnd->wQualityMode); /* wQualityMode */
Stream_Write_UINT16(pdu, 0); /* Reserved */ Stream_Write_UINT16(pdu, 0); /* Reserved */
WLog_Print(rdpsnd->log, WLOG_DEBUG, "QualityMode: %d", rdpsnd->wQualityMode);
rdpsnd_virtual_channel_write(rdpsnd, pdu); rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
@ -258,6 +264,8 @@ void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
Stream_Write(pdu, clientFormat->data, clientFormat->cbSize); Stream_Write(pdu, clientFormat->data, clientFormat->cbSize);
} }
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats");
rdpsnd_virtual_channel_write(rdpsnd, pdu); rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
@ -310,6 +318,8 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
rdpsnd_select_supported_audio_formats(rdpsnd); rdpsnd_select_supported_audio_formats(rdpsnd);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Server Audio Formats");
rdpsnd_send_client_audio_formats(rdpsnd); rdpsnd_send_client_audio_formats(rdpsnd);
if (wVersion >= 6) if (wVersion >= 6)
@ -330,6 +340,9 @@ void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, U
Stream_Write_UINT16(pdu, wTimeStamp); Stream_Write_UINT16(pdu, wTimeStamp);
Stream_Write_UINT16(pdu, wPackSize); Stream_Write_UINT16(pdu, wPackSize);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Response: wTimeStamp: %d wPackSize: %d",
wTimeStamp, wPackSize);
rdpsnd_virtual_channel_write(rdpsnd, pdu); rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
@ -341,6 +354,9 @@ static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Read_UINT16(s, wTimeStamp); Stream_Read_UINT16(s, wTimeStamp);
Stream_Read_UINT16(s, wPackSize); Stream_Read_UINT16(s, wPackSize);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Request: wTimeStamp: %d wPackSize: %d",
wTimeStamp, wPackSize);
rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize); rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
} }
@ -361,6 +377,9 @@ static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 B
format = &rdpsnd->ClientFormats[wFormatNo]; format = &rdpsnd->ClientFormats[wFormatNo];
WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %d wFormatNo: %d",
rdpsnd->cBlockNo, wFormatNo);
if (!rdpsnd->isOpen) if (!rdpsnd->isOpen)
{ {
rdpsnd->isOpen = TRUE; rdpsnd->isOpen = TRUE;
@ -399,8 +418,19 @@ void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE
rdpsnd_virtual_channel_write(rdpsnd, pdu); rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
void rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave)
{
WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveConfirm: cBlockNo: %d wTimeStamp: %d wTimeDiff: %d",
wave->cBlockNo, wave->wTimeStampB, wave->wTimeStampB - wave->wTimeStampA);
rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo);
}
static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
{ {
if (device->DisableConfirmThread)
rdpsnd_confirm_wave(device->rdpsnd, wave);
else
MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, NULL); MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, NULL);
} }
@ -434,12 +464,19 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
wave->data = data; wave->data = data;
wave->length = size; wave->length = size;
wave->AutoConfirm = TRUE;
format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo]; format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
wave->wAudioLength = rdpsnd_compute_audio_time_length(format, size); wave->wAudioLength = rdpsnd_compute_audio_time_length(format, size);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %d wTimeStamp: %d",
wave->cBlockNo, wave->wTimeStampA);
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
wave->wLocalTimeB = wave->wLocalTimeA;
wave->wTimeStampB = wave->wTimeStampA;
rdpsnd_confirm_wave(rdpsnd, wave);
free(wave); free(wave);
return; return;
} }
@ -463,11 +500,15 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
wave->wTimeStampB = rdpsnd->wTimeStamp + wave->wAudioLength + TIME_DELAY_MS; wave->wTimeStampB = rdpsnd->wTimeStamp + wave->wAudioLength + TIME_DELAY_MS;
wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS; wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS;
} }
if (wave->AutoConfirm)
rdpsnd->device->WaveConfirm(rdpsnd->device, wave); rdpsnd->device->WaveConfirm(rdpsnd->device, wave);
} }
static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
{ {
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Close");
if (rdpsnd->device) if (rdpsnd->device)
{ {
IFCALL(rdpsnd->device->Close, rdpsnd->device); IFCALL(rdpsnd->device->Close, rdpsnd->device);
@ -482,6 +523,8 @@ static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Read_UINT32(s, dwVolume); Stream_Read_UINT32(s, dwVolume);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%04X", dwVolume);
if (rdpsnd->device) if (rdpsnd->device)
{ {
IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
@ -597,6 +640,7 @@ COMMAND_LINE_ARGUMENT_A rdpsnd_args[] =
{ "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" }, { "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
{ "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" }, { "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
{ "latency", COMMAND_LINE_VALUE_REQUIRED, "<latency>", NULL, NULL, -1, NULL, "latency" }, { "latency", COMMAND_LINE_VALUE_REQUIRED, "<latency>", NULL, NULL, -1, NULL, "latency" },
{ "quality", COMMAND_LINE_VALUE_REQUIRED, "<quality mode>", NULL, NULL, -1, NULL, "quality mode" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
}; };
@ -606,10 +650,13 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
DWORD flags; DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg; COMMAND_LINE_ARGUMENT_A* arg;
rdpsnd->wQualityMode = HIGH_QUALITY; /* default quality mode */
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
rdpsnd_args, flags, rdpsnd, NULL, NULL); rdpsnd_args, flags, rdpsnd, NULL, NULL);
if (status < 0) if (status < 0)
return; return;
@ -646,6 +693,24 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
{ {
rdpsnd->latency = atoi(arg->Value); rdpsnd->latency = atoi(arg->Value);
} }
CommandLineSwitchCase(arg, "quality")
{
int wQualityMode = DYNAMIC_QUALITY;
if (_stricmp(arg->Value, "dynamic") == 0)
wQualityMode = DYNAMIC_QUALITY;
else if (_stricmp(arg->Value, "medium") == 0)
wQualityMode = MEDIUM_QUALITY;
else if (_stricmp(arg->Value, "high") == 0)
wQualityMode = HIGH_QUALITY;
else
wQualityMode = atoi(arg->Value);
if ((wQualityMode < 0) || (wQualityMode > 2))
wQualityMode = DYNAMIC_QUALITY;
rdpsnd->wQualityMode = (UINT16) wQualityMode;
}
CommandLineSwitchDefault(arg) CommandLineSwitchDefault(arg)
{ {
@ -662,10 +727,6 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
rdpsnd->latency = -1; rdpsnd->latency = -1;
rdpsnd->ScheduleThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
(void*) rdpsnd, 0, NULL);
args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData;
if (args) if (args)
@ -674,7 +735,9 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
if (rdpsnd->subsystem) if (rdpsnd->subsystem)
{ {
if (strcmp(rdpsnd->subsystem, "fake") == 0) if (strcmp(rdpsnd->subsystem, "fake") == 0)
{
return; return;
}
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
} }
@ -718,7 +781,7 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
#if defined(WITH_MACAUDIO) #if defined(WITH_MACAUDIO)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "macaudio"); rdpsnd_set_subsystem(rdpsnd, "mac");
rdpsnd_set_device_name(rdpsnd, "default"); rdpsnd_set_device_name(rdpsnd, "default");
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
} }
@ -738,6 +801,13 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
DEBUG_WARN("no sound device."); DEBUG_WARN("no sound device.");
return; return;
} }
if (!rdpsnd->device->DisableConfirmThread)
{
rdpsnd->ScheduleThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
(void*) rdpsnd, 0, NULL);
}
} }
@ -1018,6 +1088,10 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, pEntryPoints->cbSize); CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, pEntryPoints->cbSize);
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
WLog_SetLogLevel(rdpsnd->log, WLOG_TRACE);
rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle, rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle,
&rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event); &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event);

View File

@ -38,28 +38,16 @@
#include "rdpsnd_main.h" #include "rdpsnd_main.h"
typedef struct rdpsnd_winmm_datablock rdpsndWinmmDatablock;
struct rdpsnd_winmm_datablock
{
WAVEHDR header;
rdpsndWinmmDatablock* next;
};
typedef struct rdpsnd_winmm_plugin rdpsndWinmmPlugin; typedef struct rdpsnd_winmm_plugin rdpsndWinmmPlugin;
struct rdpsnd_winmm_plugin struct rdpsnd_winmm_plugin
{ {
rdpsndDevicePlugin device; rdpsndDevicePlugin device;
HWAVEOUT out_handle; HWAVEOUT hWaveOut;
WAVEFORMATEX format; WAVEFORMATEX format;
int wformat; int wformat;
int block_size; int block_size;
int latency;
HANDLE event;
rdpsndWinmmDatablock* datablock_head;
FREERDP_DSP_CONTEXT* dsp_context; FREERDP_DSP_CONTEXT* dsp_context;
}; };
@ -92,25 +80,6 @@ static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* ou
return result; return result;
} }
static void rdpsnd_winmm_clear_datablocks(rdpsndWinmmPlugin* winmm, BOOL drain)
{
rdpsndWinmmDatablock* datablock;
while ((datablock = winmm->datablock_head) != NULL)
{
if (!drain && (datablock->header.dwFlags & WHDR_DONE) == 0)
break;
while ((datablock->header.dwFlags & WHDR_DONE) == 0)
WaitForSingleObject(winmm->event, INFINITE);
winmm->datablock_head = datablock->next;
free(datablock->header.lpData);
free(datablock);
}
}
static void rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static void rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
@ -122,46 +91,93 @@ static void rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* fo
winmm->wformat = format->wFormatTag; winmm->wformat = format->wFormatTag;
winmm->block_size = format->nBlockAlign; winmm->block_size = format->nBlockAlign;
} }
}
winmm->latency = latency; static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
MMRESULT mmResult;
RDPSND_WAVE* wave;
LPWAVEHDR lpWaveHdr;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance;
switch (uMsg)
{
case MM_WOM_OPEN:
fprintf(stderr, "MM_WOM_OPEN\n");
break;
case MM_WOM_CLOSE:
fprintf(stderr, "MM_WOM_CLOSE\n");
break;
case MM_WOM_DONE:
{
UINT32 wTimeDelta;
lpWaveHdr = (LPWAVEHDR) dwParam1;
if (!lpWaveHdr)
return;
wave = (RDPSND_WAVE*) lpWaveHdr->dwUser;
if (!wave)
return;
fprintf(stderr, "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;
winmm->device.WaveConfirm(&(winmm->device), wave);
if (lpWaveHdr->lpData)
free(lpWaveHdr->lpData);
free(wave);
}
break;
}
} }
static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
MMRESULT result; MMRESULT mmResult;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (winmm->out_handle != NULL) if (winmm->hWaveOut)
return; return;
DEBUG_SVC("opening");
rdpsnd_winmm_set_format(device, format, latency); rdpsnd_winmm_set_format(device, format, latency);
freerdp_dsp_context_reset_adpcm(winmm->dsp_context); freerdp_dsp_context_reset_adpcm(winmm->dsp_context);
result = waveOutOpen(&winmm->out_handle, WAVE_MAPPER, &winmm->format, (DWORD_PTR) winmm->event, 0, CALLBACK_EVENT); mmResult = waveOutOpen(&winmm->hWaveOut, WAVE_MAPPER, &winmm->format,
(DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) if (mmResult != MMSYSERR_NOERROR)
{ {
DEBUG_WARN("waveOutOpen failed: %d", result); fprintf(stderr, "waveOutOpen failed: %d\n", mmResult);
} }
} }
static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)
{ {
MMRESULT mmResult;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (winmm->out_handle) if (winmm->hWaveOut)
{ {
DEBUG_SVC("close"); mmResult = waveOutReset(winmm->hWaveOut);
rdpsnd_winmm_clear_datablocks(winmm, TRUE);
if (waveOutClose(winmm->out_handle) != MMSYSERR_NOERROR) mmResult = waveOutClose(winmm->hWaveOut);
if (mmResult != MMSYSERR_NOERROR)
{ {
DEBUG_WARN("waveOutClose error"); fprintf(stderr, "waveOutClose failure: %d\n", mmResult);
} }
winmm->out_handle = NULL; winmm->hWaveOut = NULL;
} }
} }
@ -169,11 +185,15 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (winmm)
{
rdpsnd_winmm_close(device); rdpsnd_winmm_close(device);
freerdp_dsp_context_free(winmm->dsp_context); freerdp_dsp_context_free(winmm->dsp_context);
CloseHandle(winmm->event);
free(winmm); free(winmm);
} }
}
static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format)
{ {
@ -203,10 +223,10 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device)
dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */
dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; dwVolume = (dwVolumeLeft << 16) | dwVolumeRight;
if (!winmm->out_handle) if (!winmm->hWaveOut)
return dwVolume; return dwVolume;
waveOutGetVolume(winmm->out_handle, &dwVolume); waveOutGetVolume(winmm->hWaveOut, &dwVolume);
return dwVolume; return dwVolume;
} }
@ -215,82 +235,94 @@ static void rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (!winmm->out_handle) if (!winmm->hWaveOut)
return; return;
waveOutSetVolume(winmm->out_handle, value); waveOutSetVolume(winmm->hWaveOut, value);
} }
static void rdpsnd_winmm_play(rdpsndDevicePlugin* device, BYTE* data, int size) static void rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
{ {
BYTE* src; int length;
MMRESULT result; BYTE* data;
rdpsndWinmmDatablock* last;
rdpsndWinmmDatablock* datablock;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (!winmm->out_handle)
return;
if (winmm->wformat == WAVE_FORMAT_ADPCM) if (winmm->wformat == WAVE_FORMAT_ADPCM)
{ {
winmm->dsp_context->decode_ms_adpcm(winmm->dsp_context, winmm->dsp_context->decode_ms_adpcm(winmm->dsp_context,
data, size, winmm->format.nChannels, winmm->block_size); wave->data, wave->length, winmm->format.nChannels, winmm->block_size);
size = winmm->dsp_context->adpcm_size; length = winmm->dsp_context->adpcm_size;
src = winmm->dsp_context->adpcm_buffer; data = winmm->dsp_context->adpcm_buffer;
} }
else if (winmm->wformat == WAVE_FORMAT_DVI_ADPCM) else if (winmm->wformat == WAVE_FORMAT_DVI_ADPCM)
{ {
winmm->dsp_context->decode_ima_adpcm(winmm->dsp_context, winmm->dsp_context->decode_ima_adpcm(winmm->dsp_context,
data, size, winmm->format.nChannels, winmm->block_size); wave->data, wave->length, winmm->format.nChannels, winmm->block_size);
size = winmm->dsp_context->adpcm_size; length = winmm->dsp_context->adpcm_size;
src = winmm->dsp_context->adpcm_buffer; data = winmm->dsp_context->adpcm_buffer;
} }
else else
{ {
src = data; length = wave->length;
data = wave->data;
} }
rdpsnd_winmm_clear_datablocks(winmm, FALSE); wave->data = (BYTE*) malloc(length);
CopyMemory(wave->data, data, length);
for (last = winmm->datablock_head; last && last->next; last = last->next) wave->length = length;
{
} }
datablock = (rdpsndWinmmDatablock*) malloc(sizeof(rdpsndWinmmDatablock)); void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
ZeroMemory(datablock, sizeof(rdpsndWinmmDatablock));
if (last)
last->next = datablock;
else
winmm->datablock_head = datablock;
datablock->header.dwBufferLength = size;
datablock->header.lpData = (LPSTR) malloc(size);
CopyMemory(datablock->header.lpData, src, size);
result = waveOutPrepareHeader(winmm->out_handle, &datablock->header, sizeof(datablock->header));
if (result != MMSYSERR_NOERROR)
{ {
DEBUG_WARN("waveOutPrepareHeader: %d", result); MMRESULT mmResult;
LPWAVEHDR lpWaveHdr;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (!winmm->hWaveOut)
return;
wave->AutoConfirm = FALSE;
lpWaveHdr = (LPWAVEHDR) malloc(sizeof(WAVEHDR));
if (!lpWaveHdr)
return;
ZeroMemory(lpWaveHdr, sizeof(WAVEHDR));
lpWaveHdr->dwFlags = 0;
lpWaveHdr->dwLoops = 0;
lpWaveHdr->lpData = (LPSTR) wave->data;
lpWaveHdr->dwBufferLength = wave->length;
lpWaveHdr->dwUser = (DWORD_PTR) wave;
lpWaveHdr->lpNext = NULL;
mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if (mmResult != MMSYSERR_NOERROR)
{
fprintf(stderr, "waveOutPrepareHeader failure: %d\n", mmResult);
return; return;
} }
ResetEvent(winmm->event); mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
waveOutWrite(winmm->out_handle, &datablock->header, sizeof(datablock->header));
if (mmResult != MMSYSERR_NOERROR)
{
fprintf(stderr, "waveOutWrite failure: %d\n", mmResult);
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
return;
}
} }
static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) static void rdpsnd_winmm_start(rdpsndDevicePlugin* device)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
rdpsnd_winmm_clear_datablocks(winmm, FALSE);
} }
static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args)
{ {
} }
#ifdef STATIC_CHANNELS #ifdef STATIC_CHANNELS
@ -305,12 +337,15 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
winmm = (rdpsndWinmmPlugin*) malloc(sizeof(rdpsndWinmmPlugin)); winmm = (rdpsndWinmmPlugin*) malloc(sizeof(rdpsndWinmmPlugin));
ZeroMemory(winmm, sizeof(rdpsndWinmmPlugin)); ZeroMemory(winmm, sizeof(rdpsndWinmmPlugin));
winmm->device.DisableConfirmThread = TRUE;
winmm->device.Open = rdpsnd_winmm_open; winmm->device.Open = rdpsnd_winmm_open;
winmm->device.FormatSupported = rdpsnd_winmm_format_supported; winmm->device.FormatSupported = rdpsnd_winmm_format_supported;
winmm->device.SetFormat = rdpsnd_winmm_set_format; winmm->device.SetFormat = rdpsnd_winmm_set_format;
winmm->device.GetVolume = rdpsnd_winmm_get_volume; winmm->device.GetVolume = rdpsnd_winmm_get_volume;
winmm->device.SetVolume = rdpsnd_winmm_set_volume; winmm->device.SetVolume = rdpsnd_winmm_set_volume;
winmm->device.Play = rdpsnd_winmm_play; winmm->device.WaveDecode = rdpsnd_winmm_wave_decode;
winmm->device.WavePlay = rdpsnd_winmm_wave_play;
winmm->device.Start = rdpsnd_winmm_start; winmm->device.Start = rdpsnd_winmm_start;
winmm->device.Close = rdpsnd_winmm_close; winmm->device.Close = rdpsnd_winmm_close;
winmm->device.Free = rdpsnd_winmm_free; winmm->device.Free = rdpsnd_winmm_free;
@ -319,7 +354,6 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args);
winmm->dsp_context = freerdp_dsp_context_new(); winmm->dsp_context = freerdp_dsp_context_new();
winmm->event = CreateEvent(NULL, TRUE, FALSE, NULL);
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm); pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm);

View File

@ -8,3 +8,7 @@ libs/armeabi*
AndroidManifest.xml AndroidManifest.xml
local.properties local.properties
!.project !.project
FreeRDPCore/project.properties
FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java
aFreeRDP/project.properties

4
client/Android/FreeRDPCore/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
ant.properties
build.xml
jni/Android.mk
jni/Application.mk

4
client/Android/aFreeRDP/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
ant.properties
build.xml
jni/Android.mk
jni/Application.mk

View File

@ -1,3 +1,6 @@
#ifndef MRDPVIEW_H
#define MRDPVIEW_H
/** /**
* FreeRDP: A Remote Desktop Protocol Implementation * FreeRDP: A Remote Desktop Protocol Implementation
* MacFreeRDP * MacFreeRDP
@ -97,3 +100,5 @@ BOOL mac_post_connect(freerdp* instance);
BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain);
int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
DWORD mac_client_thread(void* param); DWORD mac_client_thread(void* param);
#endif // MRDPVIEW_H

View File

@ -59,6 +59,8 @@
#import "freerdp/types.h" #import "freerdp/types.h"
#import "freerdp/channels/channels.h" #import "freerdp/channels/channels.h"
#import "freerdp/gdi/gdi.h" #import "freerdp/gdi/gdi.h"
#import "freerdp/gdi/dc.h"
#import "freerdp/gdi/region.h"
#import "freerdp/graphics.h" #import "freerdp/graphics.h"
#import "freerdp/utils/event.h" #import "freerdp/utils/event.h"
#import "freerdp/client/cliprdr.h" #import "freerdp/client/cliprdr.h"
@ -496,32 +498,84 @@ DWORD mac_client_thread(void* param)
mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y); mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y);
} }
DWORD fixKeyCode(DWORD keyCode, unichar keyChar)
{
/**
* In 99% of cases, the given key code is truly keyboard independent.
* This function handles the remaining 1% of edge cases.
*
* Hungarian Keyboard: This is 'QWERTZ' and not 'QWERTY'.
* The '0' key is on the left of the '1' key, where '~' is on a US keyboard.
* A special 'i' letter key with acute is found on the right of the left shift key.
* On the hungarian keyboard, the 'i' key is at the left of the 'Y' key
* Some international keyboards have a corresponding key which would be at
* the left of the 'Z' key when using a QWERTY layout.
*
* The Apple Hungarian keyboard sends inverted key codes for the '0' and 'i' keys.
* When using the US keyboard layout, key codes are left as-is (inverted).
* When using the Hungarian keyboard layout, key codes are swapped (non-inverted).
* This means that when using the Hungarian keyboard layout with a US keyboard,
* the keys corresponding to '0' and 'i' will effectively be inverted.
*
* To fix the '0' and 'i' key inversion, we use the corresponding output character
* provided by OS X and check for a character to key code mismatch: for instance,
* when the output character is '0' for the key code corresponding to the 'i' key.
*/
switch (keyChar)
{
case '0':
case 0x00A7: /* section sign */
if (keyCode == APPLE_VK_ISO_Section)
keyCode = APPLE_VK_ANSI_Grave;
break;
case 0x00ED: /* latin small letter i with acute */
case 0x00CD: /* latin capital letter i with acute */
if (keyCode == APPLE_VK_ANSI_Grave)
keyCode = APPLE_VK_ISO_Section;
break;
}
return keyCode;
}
/** ********************************************************************* /** *********************************************************************
* called when a key is pressed * called when a key is pressed
***********************************************************************/ ***********************************************************************/
- (void) keyDown:(NSEvent *) event - (void) keyDown:(NSEvent *) event
{ {
int key; DWORD keyCode;
DWORD keyFlags; DWORD keyFlags;
DWORD vkcode; DWORD vkcode;
DWORD scancode; DWORD scancode;
unichar keyChar;
NSString* characters;
if (!is_connected) if (!is_connected)
return; return;
keyFlags = KBD_FLAGS_DOWN; keyFlags = KBD_FLAGS_DOWN;
key = [event keyCode] + 8; keyCode = [event keyCode];
vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE); characters = [event charactersIgnoringModifiers];
if ([characters length] > 0)
{
keyChar = [characters characterAtIndex:0];
keyCode = fixKeyCode(keyCode, keyChar);
}
vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE);
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0;
scancode &= 0xFF; scancode &= 0xFF;
vkcode &= 0xFF; vkcode &= 0xFF;
#if 0 #if 0
fprintf(stderr, "keyDown: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n", fprintf(stderr, "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n",
key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode));
#endif #endif
freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode);
@ -533,18 +587,28 @@ DWORD mac_client_thread(void* param)
- (void) keyUp:(NSEvent *) event - (void) keyUp:(NSEvent *) event
{ {
int key; DWORD keyCode;
DWORD keyFlags; DWORD keyFlags;
DWORD vkcode; DWORD vkcode;
DWORD scancode; DWORD scancode;
unichar keyChar;
NSString* characters;
if (!is_connected) if (!is_connected)
return; return;
key = [event keyCode] + 8;
keyFlags = KBD_FLAGS_RELEASE; keyFlags = KBD_FLAGS_RELEASE;
keyCode = [event keyCode];
vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE); characters = [event charactersIgnoringModifiers];
if ([characters length] > 0)
{
keyChar = [characters characterAtIndex:0];
keyCode = fixKeyCode(keyCode, keyChar);
}
vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE);
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0;
scancode &= 0xFF; scancode &= 0xFF;
@ -552,7 +616,7 @@ DWORD mac_client_thread(void* param)
#if 0 #if 0
fprintf(stderr, "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n", fprintf(stderr, "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s\n",
key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode));
#endif #endif
freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode);
@ -660,6 +724,8 @@ DWORD mac_client_thread(void* param)
if (!is_connected) if (!is_connected)
return; return;
gdi_free(context->instance);
freerdp_channels_global_uninit(); freerdp_channels_global_uninit();
if (pixel_data) if (pixel_data)
@ -743,7 +809,6 @@ DWORD mac_client_thread(void* param)
BOOL mac_pre_connect(freerdp* instance) BOOL mac_pre_connect(freerdp* instance)
{ {
rdpSettings* settings; rdpSettings* settings;
BOOL bitmap_cache;
// setup callbacks // setup callbacks
instance->update->BeginPaint = mac_begin_paint; instance->update->BeginPaint = mac_begin_paint;
@ -760,17 +825,13 @@ BOOL mac_pre_connect(freerdp* instance)
return -1; return -1;
} }
freerdp_client_load_addins(instance->context->channels, instance->settings); settings->ColorDepth = 32;
settings->SoftwareGdi = TRUE;
settings = instance->settings; settings->OsMajorType = OSMAJORTYPE_MACINTOSH;
bitmap_cache = settings->BitmapCacheEnabled; settings->OsMinorType = OSMINORTYPE_MACINTOSH;
instance->settings->ColorDepth = 32;
instance->settings->SoftwareGdi = TRUE;
settings->OsMajorType = OSMAJORTYPE_UNIX;
settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER;
ZeroMemory(settings->OrderSupport, 32);
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
@ -783,23 +844,21 @@ BOOL mac_pre_connect(freerdp* instance)
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache; settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE; settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE;
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE; settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE; settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
freerdp_client_load_addins(instance->context->channels, instance->settings);
freerdp_channels_pre_connect(instance->context->channels, instance); freerdp_channels_pre_connect(instance->context->channels, instance);
return TRUE; return TRUE;
@ -855,7 +914,6 @@ BOOL mac_post_connect(freerdp* instance)
return TRUE; return TRUE;
} }
BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain) BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain)
{ {
PasswordDialog* dialog = [PasswordDialog new]; PasswordDialog* dialog = [PasswordDialog new];
@ -921,9 +979,6 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer)
freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData, freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData,
pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv); pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv);
// TODO if xorBpp is > 24 need to call freerdp_image_swap_color_order
// see file df_graphics.c
/* store cursor bitmap image in representation - required by NSImage */ /* store cursor bitmap image in representation - required by NSImage */
bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data
pixelsWide:rect.size.width pixelsWide:rect.size.width
@ -1049,6 +1104,10 @@ void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap)
void mac_begin_paint(rdpContext* context) void mac_begin_paint(rdpContext* context)
{ {
rdpGdi* gdi = context->gdi; rdpGdi* gdi = context->gdi;
if (!gdi)
return;
gdi->primary->hdc->hwnd->invalid->null = 1; gdi->primary->hdc->hwnd->invalid->null = 1;
} }
@ -1058,20 +1117,24 @@ void mac_begin_paint(rdpContext* context)
void mac_end_paint(rdpContext* context) void mac_end_paint(rdpContext* context)
{ {
int i;
rdpGdi* gdi; rdpGdi* gdi;
NSRect drawRect; HGDI_RGN invalid;
NSRect newDrawRect;
int ww, wh, dw, dh;
mfContext* mfc = (mfContext*) context; mfContext* mfc = (mfContext*) context;
MRDPView* view = (MRDPView*) mfc->view; MRDPView* view = (MRDPView*) mfc->view;
int ww, wh, dw, dh; gdi = context->gdi;
if (!gdi)
return;
ww = mfc->client_width; ww = mfc->client_width;
wh = mfc->client_height; wh = mfc->client_height;
dw = mfc->context.settings->DesktopWidth; dw = mfc->context.settings->DesktopWidth;
dh = mfc->context.settings->DesktopHeight; dh = mfc->context.settings->DesktopHeight;
if ((context == 0) || (context->gdi == 0)) if ((!context) || (!context->gdi))
return; return;
if (context->gdi->primary->hdc->hwnd->invalid->null) if (context->gdi->primary->hdc->hwnd->invalid->null)
@ -1080,37 +1143,31 @@ void mac_end_paint(rdpContext* context)
if (context->gdi->drawing != context->gdi->primary) if (context->gdi->drawing != context->gdi->primary)
return; return;
gdi = context->gdi; invalid = gdi->primary->hdc->hwnd->invalid;
for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) newDrawRect.origin.x = invalid->x;
{ newDrawRect.origin.y = invalid->y;
drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; newDrawRect.size.width = invalid->w;
drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; newDrawRect.size.height = invalid->h;
drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w;
drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h;
if (mfc->context.settings->SmartSizing && (ww != dw || wh != dh)) if (mfc->context.settings->SmartSizing && (ww != dw || wh != dh))
{ {
drawRect.origin.y = drawRect.origin.y * wh / dh - 1; newDrawRect.origin.y = newDrawRect.origin.y * wh / dh - 1;
drawRect.size.height = drawRect.size.height * wh / dh + 1; newDrawRect.size.height = newDrawRect.size.height * wh / dh + 1;
drawRect.origin.x = drawRect.origin.x * ww / dw - 1; newDrawRect.origin.x = newDrawRect.origin.x * ww / dw - 1;
drawRect.size.width = drawRect.size.width * ww / dw + 1; newDrawRect.size.width = newDrawRect.size.width * ww / dw + 1;
} }
else else
{ {
drawRect.origin.y = drawRect.origin.y - 1; newDrawRect.origin.y = newDrawRect.origin.y - 1;
drawRect.size.height = drawRect.size.height + 1; newDrawRect.size.height = newDrawRect.size.height + 1;
drawRect.origin.x = drawRect.origin.x - 1; newDrawRect.origin.x = newDrawRect.origin.x - 1;
drawRect.size.width = drawRect.size.width + 1; newDrawRect.size.width = newDrawRect.size.width + 1;
} }
windows_to_apple_cords(mfc->view, &drawRect); windows_to_apple_cords(mfc->view, &newDrawRect);
// Note: The xCurrentScroll and yCurrentScroll values do not need to be taken into account [view setNeedsDisplayInRect:newDrawRect];
// because the current frame is always at full size, since the scrolling is handled by the external container.
[view setNeedsDisplayInRect:drawRect];
}
gdi->primary->hdc->hwnd->ninvalid = 0; gdi->primary->hdc->hwnd->ninvalid = 0;
} }

View File

@ -16,7 +16,6 @@ static AppDelegate* _singleDelegate = nil;
void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e); void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e);
void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e); void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e);
void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e); void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e);
int mac_client_start(rdpContext* context);
void mac_set_view_size(rdpContext* context, MRDPView* view); void mac_set_view_size(rdpContext* context, MRDPView* view);
@implementation AppDelegate @implementation AppDelegate
@ -94,7 +93,13 @@ void mac_set_view_size(rdpContext* context, MRDPView* view);
} }
status = freerdp_client_settings_parse_command_line(context->settings, argc, argv); status = freerdp_client_settings_parse_command_line(context->settings, argc, argv);
if (context->argc && context->argv)
status = freerdp_client_settings_command_line_status_print(context->settings, status, context->argc, context->argv); status = freerdp_client_settings_command_line_status_print(context->settings, status, context->argc, context->argv);
else
{
freerdp_client_print_command_line_help(argc, argv);
}
return status; return status;
} }
@ -109,8 +114,6 @@ void mac_set_view_size(rdpContext* context, MRDPView* view);
RdpClientEntry(&clientEntryPoints); RdpClientEntry(&clientEntryPoints);
clientEntryPoints.ClientStart = mac_client_start;
context = freerdp_client_context_new(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints);
} }
@ -174,7 +177,6 @@ void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e)
[[_singleDelegate->window contentView] addSubview:mfc->view]; [[_singleDelegate->window contentView] addSubview:mfc->view];
} }
mac_set_view_size(context, mfc->view); mac_set_view_size(context, mfc->view);
} }
} }
@ -193,13 +195,12 @@ void AppDelegate_ConnectionResultEventHandler(void* ctx, ConnectionResultEventAr
NSString* message = nil; NSString* message = nil;
if (connectErrorCode == AUTHENTICATIONERROR) if (connectErrorCode == AUTHENTICATIONERROR)
{ {
message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."]; message = [NSString stringWithFormat:@"%@", @"Authentication failure, check credentials."];
} }
// Making sure this should be invoked on the main UI thread. // Making sure this should be invoked on the main UI thread.
[_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE]; [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE];
[message release];
} }
} }
} }
@ -223,7 +224,6 @@ void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e)
} }
} }
void mac_set_view_size(rdpContext* context, MRDPView* view) void mac_set_view_size(rdpContext* context, MRDPView* view)
{ {
// set client area to specified dimensions // set client area to specified dimensions
@ -244,22 +244,6 @@ void mac_set_view_size(rdpContext* context, MRDPView* view)
// set window to given area // set window to given area
[[view window] setFrame:outerRect display:YES]; [[view window] setFrame:outerRect display:YES];
if (context->settings->Fullscreen) if (context->settings->Fullscreen)
[[view window] toggleFullScreen:nil]; [[view window] toggleFullScreen:nil];
} }
int mac_client_start(rdpContext* context)
{
mfContext* mfc;
MRDPView* view;
mfc = (mfContext*) context;
view = [[MRDPView alloc] initWithFrame : NSMakeRect(0, 0, context->settings->DesktopWidth, context->settings->DesktopHeight)];
mfc->view = view;
[view rdpStart:context];
mac_set_view_size(context, view);
return 0;
}

View File

@ -105,38 +105,6 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
settings->AsyncChannels = TRUE; settings->AsyncChannels = TRUE;
settings->AsyncTransport = TRUE; settings->AsyncTransport = TRUE;
settings->OsMajorType = OSMAJORTYPE_MACINTOSH;
settings->OsMinorType = OSMINORTYPE_MACINTOSH;
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE;
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
return 0; return 0;
} }

View File

@ -63,7 +63,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if(WITH_CLIENT_INTERFACE) if(WITH_CLIENT_INTERFACE)
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT WinPRTargets) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets)
add_subdirectory(cli) add_subdirectory(cli)
else() else()
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)

View File

@ -54,7 +54,7 @@ static UINT32 get_local_format_id_by_name(cliprdrContext *cliprdr, void *format_
for (i = 0; i < cliprdr->map_size; i++) for (i = 0; i < cliprdr->map_size; i++)
{ {
map = &cliprdr->format_mappings[i]; map = &cliprdr->format_mappings[i];
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) if ((cliprdr->capabilities & CB_USE_LONG_FORMAT_NAMES) != 0)
{ {
if (map->name) if (map->name)
{ {
@ -144,7 +144,7 @@ static void cliprdr_send_format_list(cliprdrContext *cliprdr)
{ {
Write_UINT32(format_data + len, format); Write_UINT32(format_data + len, format);
len += 4; len += 4;
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) if ((cliprdr->capabilities & CB_USE_LONG_FORMAT_NAMES) != 0)
{ {
if (format >= CF_MAX) if (format >= CF_MAX)
{ {
@ -518,7 +518,7 @@ static void wf_cliprdr_process_cb_format_list_event(wfContext *wfc, RDP_CB_FORMA
clear_format_map(cliprdr); clear_format_map(cliprdr);
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) if ((cliprdr->capabilities & CB_USE_LONG_FORMAT_NAMES) != 0)
{ {
while (left_size >= 6) while (left_size >= 6)
{ {

View File

@ -798,39 +798,6 @@ int freerdp_client_set_window_size(wfContext* wfc, int width, int height)
return 0; return 0;
} }
void wf_ParamChangeEventHandler(rdpContext* context, ParamChangeEventArgs* e)
{
RECT rect;
HMENU hMenu;
wfContext* wfc = (wfContext*) context;
// specific processing here
switch (e->id)
{
case FreeRDP_SmartSizing:
fprintf(stderr, "SmartSizing changed.\n");
if (!context->settings->SmartSizing && (wfc->client_width > context->settings->DesktopWidth || wfc->client_height > context->settings->DesktopHeight))
{
GetWindowRect(wfc->hwnd, &rect);
SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, MIN(wfc->client_width + wfc->offset_x, rect.right - rect.left), MIN(wfc->client_height + wfc->offset_y, rect.bottom - rect.top), SWP_NOMOVE | SWP_FRAMECHANGED);
wf_update_canvas_diff(wfc);
}
hMenu = GetSystemMenu(wfc->hwnd, FALSE);
CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, context->settings->SmartSizing);
wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
GetClientRect(wfc->hwnd, &rect);
InvalidateRect(wfc->hwnd, &rect, TRUE);
break;
case FreeRDP_ConnectionType:
fprintf(stderr, "ConnectionType changed.\n");
freerdp_set_connection_type(wfc->instance->settings, wfc->instance->settings->ConnectionType);
break;
}
}
// TODO: Some of that code is a duplicate of wf_pre_connect. Refactor? // TODO: Some of that code is a duplicate of wf_pre_connect. Refactor?
int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename) int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename)
{ {
@ -862,37 +829,6 @@ int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename)
return 0; return 0;
} }
int freerdp_client_save_settings_to_rdp_file(wfContext* wfc, char* filename)
{
if (!filename)
return 1;
if (wfc->instance->settings->ConnectionFile)
{
free(wfc->instance->settings->ConnectionFile);
}
wfc->instance->settings->ConnectionFile = _strdup(filename);
// Reuse existing rdpFile structure if available, to preserve unsupported settings when saving to disk.
if (wfc->connectionRdpFile == NULL)
{
wfc->connectionRdpFile = freerdp_client_rdp_file_new();
}
if (!freerdp_client_populate_rdp_file_from_settings(wfc->connectionRdpFile, wfc->instance->settings))
{
return 1;
}
if (!freerdp_client_write_rdp_file(wfc->connectionRdpFile, filename, UNICODE));
{
return 2;
}
return 0;
}
void wf_size_scrollbars(wfContext* wfc, int client_width, int client_height) void wf_size_scrollbars(wfContext* wfc, int client_width, int client_height)
{ {
BOOL rc; BOOL rc;
@ -1048,8 +984,6 @@ int wfreerdp_client_new(freerdp* instance, rdpContext* context)
wfc->instance = instance; wfc->instance = instance;
context->channels = freerdp_channels_new(); context->channels = freerdp_channels_new();
PubSub_SubscribeParamChange(context->pubSub, wf_ParamChangeEventHandler);
return 0; return 0;
} }

View File

@ -11,7 +11,7 @@
LPSTR tmp = NULL; LPSTR tmp = NULL;
LPSTR tr_esc_str(LPSTR arg) LPSTR tr_esc_str(LPCSTR arg)
{ {
size_t cs = 0, x, ds; size_t cs = 0, x, ds;
size_t s; size_t s;

View File

@ -762,6 +762,35 @@ BOOL xf_pre_connect(freerdp* instance)
settings = instance->settings; settings = instance->settings;
channels = instance->context->channels; 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;
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE;
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
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; xfc->UseXThreads = TRUE;
if (xfc->UseXThreads) if (xfc->UseXThreads)
@ -1728,37 +1757,6 @@ void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e)
} }
} }
void xf_ParamChangeEventHandler(rdpContext* context, ParamChangeEventArgs* e)
{
xfContext* xfc = (xfContext*) context;
switch (e->id)
{
case FreeRDP_ScalingFactor:
xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor;
xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor;
xf_transform_window(xfc);
{
ResizeWindowEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
}
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
break;
default:
break;
}
}
static void xf_ScalingFactorChangeEventHandler(rdpContext* context, ScalingFactorChangeEventArgs* e) static void xf_ScalingFactorChangeEventHandler(rdpContext* context, ScalingFactorChangeEventArgs* e)
{ {
xfContext* xfc = (xfContext*) context; xfContext* xfc = (xfContext*) context;
@ -1870,36 +1868,7 @@ static int xfreerdp_client_new(freerdp* instance, rdpContext* context)
settings = instance->settings; settings = instance->settings;
xfc->settings = instance->context->settings; xfc->settings = instance->context->settings;
settings->OsMajorType = OSMAJORTYPE_UNIX;
settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER;
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE;
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler); PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler);
PubSub_SubscribeParamChange(context->pubSub, (pParamChangeEventHandler) xf_ParamChangeEventHandler);
PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler); PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler);
return 0; return 0;

View File

@ -830,11 +830,11 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
switch (polygon_cb->fillMode) switch (polygon_cb->fillMode)
{ {
case 1: /* alternate */ case GDI_FILL_ALTERNATE: /* alternate */
XSetFillRule(xfc->display, xfc->gc, EvenOddRule); XSetFillRule(xfc->display, xfc->gc, EvenOddRule);
break; break;
case 2: /* winding */ case GDI_FILL_WINDING: /* winding */
XSetFillRule(xfc->display, xfc->gc, WindingRule); XSetFillRule(xfc->display, xfc->gc, WindingRule);
break; break;

View File

@ -182,7 +182,7 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
{ {
status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp);
if (status == FALSE) if (!status)
{ {
fprintf(stderr, "xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); fprintf(stderr, "xf_Bitmap_Decompress: Bitmap Decompression Failed\n");
} }

View File

@ -18,9 +18,6 @@
set(MODULE_NAME "freerdp-client") set(MODULE_NAME "freerdp-client")
set(MODULE_PREFIX "FREERDP_CLIENT") set(MODULE_PREFIX "FREERDP_CLIENT")
include_directories(${OPENSSL_INCLUDE_DIR})
include_directories(${ZLIB_INCLUDE_DIRS})
set(${MODULE_PREFIX}_SRCS set(${MODULE_PREFIX}_SRCS
client.c client.c
cmdline.c cmdline.c
@ -40,6 +37,9 @@ endif()
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) 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") set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
@ -53,7 +53,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHI
MODULE winpr MODULE winpr
MODULES winpr-crt winpr-utils) MODULES winpr-crt winpr-utils)
if(NOT WIN32)
set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "")
set_target_properties(${MODULE_NAME} PROPERTIES INTERFACE_LINK_LIBRARIES "")
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -133,7 +133,7 @@ int freerdp_client_settings_parse_connection_file(rdpSettings* settings, const c
return 0; return 0;
} }
int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, BYTE* buffer, size_t size) int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, const BYTE* buffer, size_t size)
{ {
rdpFile* file; rdpFile* file;
int status = -1; int status = -1;
@ -151,22 +151,19 @@ int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
return status; return status;
} }
int freerdp_client_settings_write_connection_file(rdpSettings* settings, const char* filename, BOOL unicode) int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename, BOOL unicode)
{ {
rdpFile* file; rdpFile* file;
int status = -1;
file = freerdp_client_rdp_file_new(); file = freerdp_client_rdp_file_new();
if (freerdp_client_populate_rdp_file_from_settings(file, settings)) if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
{ return -1;
if (freerdp_client_write_rdp_file(file, filename, unicode))
{ if (!freerdp_client_write_rdp_file(file, filename, unicode))
status = 0; return -1;
}
}
freerdp_client_rdp_file_free(file); freerdp_client_rdp_file_free(file);
return status; return 0;
} }

View File

@ -148,6 +148,8 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "auth-only", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Authenticate only." }, { "auth-only", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Authenticate only." },
{ "reconnect-cookie", COMMAND_LINE_VALUE_REQUIRED, "<base64 cookie>", NULL, NULL, -1, NULL, "Pass base64 reconnect cookie to the connection" }, { "reconnect-cookie", COMMAND_LINE_VALUE_REQUIRED, "<base64 cookie>", NULL, NULL, -1, NULL, "Pass base64 reconnect cookie to the connection" },
{ "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" }, { "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" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
}; };
@ -719,6 +721,15 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT
freerdp_client_add_dynamic_channel(settings, count, p); freerdp_client_add_dynamic_channel(settings, count, p);
} }
} }
CommandLineSwitchCase(arg, "heartbeat")
{
settings->SupportHeartbeatPdu = TRUE;
}
CommandLineSwitchCase(arg, "multitransport")
{
settings->SupportMultitransport = TRUE;
settings->MultitransportFlags = (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED);
}
CommandLineSwitchEnd(arg) CommandLineSwitchEnd(arg)
@ -990,7 +1001,7 @@ 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_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH;
*flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE; *flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE;
if (windows_cli_count > posix_cli_count) if (windows_cli_count >= posix_cli_count)
{ {
*flags = COMMAND_LINE_SEPARATOR_COLON; *flags = COMMAND_LINE_SEPARATOR_COLON;
*flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS; *flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;
@ -1099,7 +1110,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
return status; return status;
} }
arg = CommandLineFindArgumentA(args, "v"); arg = CommandLineFindArgumentA(args, "v");
arg = args; arg = args;
@ -1139,10 +1149,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->PreconnectionBlob = _strdup(arg->Value); settings->PreconnectionBlob = _strdup(arg->Value);
} }
} }
CommandLineSwitchCase(arg, "port")
{
settings->ServerPort = atoi(arg->Value);
}
CommandLineSwitchCase(arg, "w") CommandLineSwitchCase(arg, "w")
{ {
settings->DesktopWidth = atoi(arg->Value); settings->DesktopWidth = atoi(arg->Value);
@ -1484,9 +1490,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} }
CommandLineSwitchCase(arg, "gdi") CommandLineSwitchCase(arg, "gdi")
{ {
if (strcmp(arg->Value, "sw") == 0) if (_stricmp(arg->Value, "sw") == 0)
settings->SoftwareGdi = TRUE; settings->SoftwareGdi = TRUE;
else if (strcmp(arg->Value, "hw") == 0) else if (_stricmp(arg->Value, "hw") == 0)
settings->SoftwareGdi = FALSE; settings->SoftwareGdi = FALSE;
} }
CommandLineSwitchCase(arg, "gfx") CommandLineSwitchCase(arg, "gfx")
@ -1745,6 +1751,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} }
} }
arg = CommandLineFindArgumentA(args, "port");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
{
settings->ServerPort = atoi(arg->Value);
}
arg = CommandLineFindArgumentA(args, "p"); arg = CommandLineFindArgumentA(args, "p");
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
@ -1797,6 +1810,13 @@ int freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
settings->AudioCapture = TRUE; settings->AudioCapture = TRUE;
} }
if (settings->NetworkAutoDetect ||
settings->SupportHeartbeatPdu ||
settings->SupportMultitransport)
{
settings->DeviceRedirection = TRUE; /* these RDP 8 features require rdpdr to be registered */
}
if (settings->RedirectDrives) if (settings->RedirectDrives)
{ {
settings->DeviceRedirection = TRUE; settings->DeviceRedirection = TRUE;

View File

@ -199,7 +199,12 @@ int freerdp_client_old_command_line_pre_filter(void* context, int index, int arg
{ {
return -1; return -1;
} }
freerdp_client_old_parse_hostname((char*) argv[index], &settings->ServerHostname, &settings->ServerPort);
if (settings)
{
freerdp_client_old_parse_hostname((char*) argv[index],
&settings->ServerHostname, &settings->ServerPort);
}
} }
else else
{ {
@ -280,12 +285,17 @@ int freerdp_client_old_command_line_pre_filter(void* context, int index, int arg
index++; index++;
i++; i++;
} }
} else { }
else
{
if (settings)
{
if (settings->instance) if (settings->instance)
{ {
freerdp_client_old_process_plugin(settings, args); freerdp_client_old_process_plugin(settings, args);
} }
} }
}
for (i = 0; i < args->argc; i++) for (i = 0; i < args->argc; i++)
free(args->argv[i]); free(args->argv[i]);

View File

@ -49,8 +49,10 @@ static WCHAR CR_LF_STR_W[] = { '\r', '\n', '\0' };
#define INVALID_INTEGER_VALUE 0xFFFFFFFF #define INVALID_INTEGER_VALUE 0xFFFFFFFF
BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, char* name, int value) BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, const char* name, int value, int index)
{ {
BOOL bStandard = TRUE;
#ifdef DEBUG_CLIENT_FILE #ifdef DEBUG_CLIENT_FILE
fprintf(stderr, "%s:i:%d\n", name, value); fprintf(stderr, "%s:i:%d\n", name, value);
#endif #endif
@ -184,12 +186,26 @@ BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, char* name, int value)
else if (_stricmp(name, "rdgiskdcproxy") == 0) else if (_stricmp(name, "rdgiskdcproxy") == 0)
file->RdgIsKdcProxy = value; file->RdgIsKdcProxy = value;
else else
return FALSE; bStandard = FALSE;
return TRUE; if (index >= 0)
{
file->lines[index].name = _strdup(name);
file->lines[index].iValue = (DWORD) value;
file->lines[index].flags = RDP_FILE_LINE_FLAG_FORMATTED;
file->lines[index].flags |= RDP_FILE_LINE_FLAG_TYPE_INTEGER;
if (bStandard)
file->lines[index].flags |= RDP_FILE_LINE_FLAG_STANDARD;
file->lines[index].valueLength = 0;
} }
void freerdp_client_parse_rdp_file_integer_unicode(rdpFile* file, WCHAR* name, WCHAR* value) return bStandard;
}
void freerdp_client_parse_rdp_file_integer_unicode(rdpFile* file, WCHAR* name, WCHAR* value, int index)
{ {
int length; int length;
int ivalue; int ivalue;
@ -207,20 +223,22 @@ void freerdp_client_parse_rdp_file_integer_unicode(rdpFile* file, WCHAR* name, W
valueA[length] = '\0'; valueA[length] = '\0';
ivalue = atoi(valueA); ivalue = atoi(valueA);
freerdp_client_rdp_file_set_integer(file, nameA, ivalue); freerdp_client_rdp_file_set_integer(file, nameA, ivalue, index);
free(nameA); free(nameA);
free(valueA); free(valueA);
} }
void freerdp_client_parse_rdp_file_integer_ascii(rdpFile* file, char* name, char* value) void freerdp_client_parse_rdp_file_integer_ascii(rdpFile* file, const char* name, const char* value, int index)
{ {
int ivalue = atoi(value); int ivalue = atoi(value);
freerdp_client_rdp_file_set_integer(file, name, ivalue); freerdp_client_rdp_file_set_integer(file, name, ivalue, index);
} }
BOOL freerdp_client_rdp_file_set_string(rdpFile* file, char* name, char* value) BOOL freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, const char* value, int index)
{ {
BOOL bStandard = TRUE;
#ifdef DEBUG_CLIENT_FILE #ifdef DEBUG_CLIENT_FILE
fprintf(stderr, "%s:s:%s\n", name, value); fprintf(stderr, "%s:s:%s\n", name, value);
#endif #endif
@ -264,9 +282,23 @@ BOOL freerdp_client_rdp_file_set_string(rdpFile* file, char* name, char* value)
else if (_stricmp(name, "winposstr") == 0) else if (_stricmp(name, "winposstr") == 0)
file->WinPosStr = _strdup(value); file->WinPosStr = _strdup(value);
else else
return FALSE; bStandard = FALSE;
return TRUE; if (index >= 0)
{
file->lines[index].name = _strdup(name);
file->lines[index].sValue = _strdup(value);
file->lines[index].flags = RDP_FILE_LINE_FLAG_FORMATTED;
file->lines[index].flags |= RDP_FILE_LINE_FLAG_TYPE_STRING;
if (bStandard)
file->lines[index].flags |= RDP_FILE_LINE_FLAG_STANDARD;
file->lines[index].valueLength = 0;
}
return bStandard;
} }
void freerdp_client_add_option(rdpFile* file, char* option) void freerdp_client_add_option(rdpFile* file, char* option)
@ -281,7 +313,41 @@ void freerdp_client_add_option(rdpFile* file, char* option)
(file->argc)++; (file->argc)++;
} }
void freerdp_client_parse_rdp_file_string_unicode(rdpFile* file, WCHAR* name, WCHAR* value) int freerdp_client_parse_rdp_file_add_line(rdpFile* file, char* line, int index)
{
if (index < 0)
index = file->lineCount;
while ((file->lineCount + 1) > file->lineSize)
{
file->lineSize *= 2;
file->lines = (rdpFileLine*) realloc(file->lines, file->lineSize * sizeof(rdpFileLine));
}
ZeroMemory(&(file->lines[file->lineCount]), sizeof(rdpFileLine));
file->lines[file->lineCount].text = _strdup(line);
file->lines[file->lineCount].index = index;
(file->lineCount)++;
return index;
}
void freerdp_client_parse_rdp_file_add_line_unicode(rdpFile* file, WCHAR* line, int index)
{
char* lineA = NULL;
ConvertFromUnicode(CP_UTF8, 0, line, -1, &lineA, 0, NULL, NULL);
freerdp_client_parse_rdp_file_add_line(file, lineA, index);
free(lineA);
}
void freerdp_client_parse_rdp_file_add_line_ascii(rdpFile* file, char* line, int index)
{
freerdp_client_parse_rdp_file_add_line(file, line, index);
}
void freerdp_client_parse_rdp_file_string_unicode(rdpFile* file, WCHAR* name, WCHAR* value, int index)
{ {
int length; int length;
char* nameA; char* nameA;
@ -297,18 +363,20 @@ void freerdp_client_parse_rdp_file_string_unicode(rdpFile* file, WCHAR* name, WC
WideCharToMultiByte(CP_UTF8, 0, value, length, valueA, length, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, value, length, valueA, length, NULL, NULL);
valueA[length] = '\0'; valueA[length] = '\0';
freerdp_client_rdp_file_set_string(file, nameA, valueA); freerdp_client_rdp_file_set_string(file, nameA, valueA, index);
free(nameA); free(nameA);
free(valueA); free(valueA);
} }
void freerdp_client_parse_rdp_file_string_ascii(rdpFile* file, char* name, char* value) void freerdp_client_parse_rdp_file_string_ascii(rdpFile* file, char* name, char* value, int index)
{ {
freerdp_client_rdp_file_set_string(file, name, value); char* valueA = _strdup(value);
freerdp_client_rdp_file_set_string(file, name, valueA, index);
free(valueA);
} }
void freerdp_client_parse_rdp_file_option_unicode(rdpFile* file, WCHAR* option) void freerdp_client_parse_rdp_file_option_unicode(rdpFile* file, WCHAR* option, int index)
{ {
char* optionA = NULL; char* optionA = NULL;
@ -318,13 +386,14 @@ void freerdp_client_parse_rdp_file_option_unicode(rdpFile* file, WCHAR* option)
free(optionA); free(optionA);
} }
void freerdp_client_parse_rdp_file_option_ascii(rdpFile* file, char* option) void freerdp_client_parse_rdp_file_option_ascii(rdpFile* file, char* option, int index)
{ {
freerdp_client_add_option(file, option); freerdp_client_add_option(file, option);
} }
BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, size_t size) BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, const BYTE* buffer, size_t size)
{ {
int index;
int length; int length;
char* line; char* line;
char* type; char* type;
@ -333,6 +402,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
char *beg, *end; char *beg, *end;
char *name, *value; char *name, *value;
index = 0;
line = strtok_s((char*) buffer, "\r\n", &context); line = strtok_s((char*) buffer, "\r\n", &context);
while (line) while (line)
@ -344,9 +414,11 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
beg = line; beg = line;
end = &line[length - 1]; end = &line[length - 1];
freerdp_client_parse_rdp_file_add_line_ascii(file, line, index);
if (beg[0] == '/') if (beg[0] == '/')
{ {
freerdp_client_parse_rdp_file_option_ascii(file, line); freerdp_client_parse_rdp_file_option_ascii(file, line, index);
goto next_line; /* FreeRDP option */ goto next_line; /* FreeRDP option */
} }
@ -364,8 +436,6 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
if ((d2 - d1) != 2) if ((d2 - d1) != 2)
goto next_line; /* improper type length */ goto next_line; /* improper type length */
if (d2 == end)
goto next_line; /* no value */
*d1 = 0; *d1 = 0;
*d2 = 0; *d2 = 0;
@ -375,12 +445,12 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
if (*type == 'i') if (*type == 'i')
{ {
/* integer type */ /* integer type */
freerdp_client_parse_rdp_file_integer_ascii(file, name, value); freerdp_client_parse_rdp_file_integer_ascii(file, name, value, index);
} }
else if (*type == 's') else if (*type == 's')
{ {
/* string type */ /* string type */
freerdp_client_parse_rdp_file_string_ascii(file, name, value); freerdp_client_parse_rdp_file_string_ascii(file, name, value, index);
} }
else if (*type == 'b') else if (*type == 'b')
{ {
@ -390,13 +460,15 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
next_line: next_line:
line = strtok_s(NULL, "\r\n", &context); line = strtok_s(NULL, "\r\n", &context);
index++;
} }
return TRUE; return TRUE;
} }
BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, size_t size) BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, const BYTE* buffer, size_t size)
{ {
int index;
int length; int length;
WCHAR* line; WCHAR* line;
WCHAR* type; WCHAR* type;
@ -405,6 +477,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, s
WCHAR *beg, *end; WCHAR *beg, *end;
WCHAR *name, *value; WCHAR *name, *value;
index = 0;
line = wcstok_s((WCHAR*) buffer, CR_LF_STR_W, &context); line = wcstok_s((WCHAR*) buffer, CR_LF_STR_W, &context);
while (line != NULL) while (line != NULL)
@ -416,10 +489,12 @@ BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, s
beg = line; beg = line;
end = &line[length - 1]; end = &line[length - 1];
freerdp_client_parse_rdp_file_add_line_unicode(file, line, index);
if (beg[0] == '/') if (beg[0] == '/')
{ {
/* FreeRDP option */ /* FreeRDP option */
freerdp_client_parse_rdp_file_option_unicode(file, line); freerdp_client_parse_rdp_file_option_unicode(file, line, index);
goto next_line; goto next_line;
} }
@ -437,8 +512,6 @@ BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, s
if ((d2 - d1) != 2) if ((d2 - d1) != 2)
goto next_line; /* improper type length */ goto next_line; /* improper type length */
if (d2 == end)
goto next_line; /* no value */
*d1 = 0; *d1 = 0;
*d2 = 0; *d2 = 0;
@ -448,12 +521,12 @@ BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, s
if (*type == 'i') if (*type == 'i')
{ {
/* integer type */ /* integer type */
freerdp_client_parse_rdp_file_integer_unicode(file, name, value); freerdp_client_parse_rdp_file_integer_unicode(file, name, value, index);
} }
else if (*type == 's') else if (*type == 's')
{ {
/* string type */ /* string type */
freerdp_client_parse_rdp_file_string_unicode(file, name, value); freerdp_client_parse_rdp_file_string_unicode(file, name, value, index);
} }
else if (*type == 'b') else if (*type == 'b')
{ {
@ -463,12 +536,13 @@ BOOL freerdp_client_parse_rdp_file_buffer_unicode(rdpFile* file, BYTE* buffer, s
next_line: next_line:
line = wcstok_s(NULL, CR_LF_STR_W, &context); line = wcstok_s(NULL, CR_LF_STR_W, &context);
index++;
} }
return TRUE; return TRUE;
} }
BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, BYTE* buffer, size_t size) BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, const BYTE* buffer, size_t size)
{ {
if (size < 2) if (size < 2)
return FALSE; return FALSE;
@ -532,13 +606,14 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name)
#define WRITE_ALL_SETTINGS TRUE #define WRITE_ALL_SETTINGS TRUE
#define SETTING_MODIFIED(_settings, _field) (WRITE_ALL_SETTINGS || _settings->SettingsModified[FreeRDP_##_field]) #define SETTING_MODIFIED(_settings, _field) (WRITE_ALL_SETTINGS || _settings->SettingsModified[FreeRDP_##_field])
#define SETTING_MODIFIED_SET(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _settings->_field #define SETTING_MODIFIED_SET(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _settings->_field
#define SETTING_MODIFIED_SET_STRING(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _strdup(_settings->_field)
BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings* settings) BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSettings* settings)
{ {
SETTING_MODIFIED_SET(file->Domain, settings, Domain); SETTING_MODIFIED_SET_STRING(file->Domain, settings, Domain);
SETTING_MODIFIED_SET(file->Username, settings, Username); SETTING_MODIFIED_SET_STRING(file->Username, settings, Username);
SETTING_MODIFIED_SET(file->ServerPort, settings, ServerPort); SETTING_MODIFIED_SET(file->ServerPort, settings, ServerPort);
SETTING_MODIFIED_SET(file->FullAddress, settings, ServerHostname); SETTING_MODIFIED_SET_STRING(file->FullAddress, settings, ServerHostname);
SETTING_MODIFIED_SET(file->DesktopWidth, settings, DesktopWidth); SETTING_MODIFIED_SET(file->DesktopWidth, settings, DesktopWidth);
SETTING_MODIFIED_SET(file->DesktopHeight, settings, DesktopHeight); SETTING_MODIFIED_SET(file->DesktopHeight, settings, DesktopHeight);
SETTING_MODIFIED_SET(file->SessionBpp, settings, ColorDepth); SETTING_MODIFIED_SET(file->SessionBpp, settings, ColorDepth);
@ -546,8 +621,8 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings*
SETTING_MODIFIED_SET(file->AdministrativeSession, settings, ConsoleSession); SETTING_MODIFIED_SET(file->AdministrativeSession, settings, ConsoleSession);
SETTING_MODIFIED_SET(file->NegotiateSecurityLayer, settings, NegotiateSecurityLayer); SETTING_MODIFIED_SET(file->NegotiateSecurityLayer, settings, NegotiateSecurityLayer);
SETTING_MODIFIED_SET(file->EnableCredSSPSupport, settings, NlaSecurity); SETTING_MODIFIED_SET(file->EnableCredSSPSupport, settings, NlaSecurity);
SETTING_MODIFIED_SET(file->AlternateShell, settings, AlternateShell); SETTING_MODIFIED_SET_STRING(file->AlternateShell, settings, AlternateShell);
SETTING_MODIFIED_SET(file->ShellWorkingDirectory, settings, ShellWorkingDirectory); SETTING_MODIFIED_SET_STRING(file->ShellWorkingDirectory, settings, ShellWorkingDirectory);
SETTING_MODIFIED_SET(file->ConnectionType, settings, ConnectionType); SETTING_MODIFIED_SET(file->ConnectionType, settings, ConnectionType);
if (SETTING_MODIFIED(settings, AudioPlayback) || SETTING_MODIFIED(settings, RemoteConsoleAudio)) if (SETTING_MODIFIED(settings, AudioPlayback) || SETTING_MODIFIED(settings, RemoteConsoleAudio))
@ -560,17 +635,17 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings*
file->AudioMode = AUDIO_MODE_NONE; file->AudioMode = AUDIO_MODE_NONE;
} }
SETTING_MODIFIED_SET(file->GatewayHostname, settings, GatewayHostname); SETTING_MODIFIED_SET_STRING(file->GatewayHostname, settings, GatewayHostname);
SETTING_MODIFIED_SET(file->GatewayUsageMethod, settings, GatewayUsageMethod); SETTING_MODIFIED_SET(file->GatewayUsageMethod, settings, GatewayUsageMethod);
SETTING_MODIFIED_SET(file->PromptCredentialOnce, settings, GatewayUseSameCredentials); SETTING_MODIFIED_SET(file->PromptCredentialOnce, settings, GatewayUseSameCredentials);
SETTING_MODIFIED_SET(file->RemoteApplicationMode, settings, RemoteApplicationMode); SETTING_MODIFIED_SET(file->RemoteApplicationMode, settings, RemoteApplicationMode);
SETTING_MODIFIED_SET(file->RemoteApplicationProgram, settings, RemoteApplicationProgram); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationProgram, settings, RemoteApplicationProgram);
SETTING_MODIFIED_SET(file->RemoteApplicationName, settings, RemoteApplicationName); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationName, settings, RemoteApplicationName);
SETTING_MODIFIED_SET(file->RemoteApplicationIcon, settings, RemoteApplicationIcon); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationIcon, settings, RemoteApplicationIcon);
SETTING_MODIFIED_SET(file->RemoteApplicationFile, settings, RemoteApplicationFile); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationFile, settings, RemoteApplicationFile);
SETTING_MODIFIED_SET(file->RemoteApplicationGuid, settings, RemoteApplicationGuid); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationGuid, settings, RemoteApplicationGuid);
SETTING_MODIFIED_SET(file->RemoteApplicationCmdLine, settings, RemoteApplicationCmdLine); SETTING_MODIFIED_SET_STRING(file->RemoteApplicationCmdLine, settings, RemoteApplicationCmdLine);
SETTING_MODIFIED_SET(file->SpanMonitors, settings, SpanMonitors); SETTING_MODIFIED_SET(file->SpanMonitors, settings, SpanMonitors);
SETTING_MODIFIED_SET(file->UseMultiMon, settings, UseMultimon); SETTING_MODIFIED_SET(file->UseMultiMon, settings, UseMultimon);
@ -578,138 +653,94 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings*
return TRUE; return TRUE;
} }
BOOL freerdp_client_write_rdp_file(rdpFile* file, const char* name, BOOL unicode) BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL unicode)
{ {
int rc = 0; FILE* fp;
int length;
char* buffer; char* buffer;
int len, len2; int status = 0;
FILE* fp = NULL;
WCHAR* unicodestr = NULL; WCHAR* unicodestr = NULL;
len = freerdp_client_write_rdp_file_buffer(file, NULL, 0); length = freerdp_client_write_rdp_file_buffer(file, NULL, 0);
if (len <= 0) if (length < 0)
{ {
fprintf(stderr, "freerdp_client_write_rdp_file: Error determining buffer size.\n"); fprintf(stderr, "freerdp_client_write_rdp_file: error determining buffer size.\n");
return FALSE; return FALSE;
} }
buffer = (char*) malloc((len + 1) * sizeof(char)); buffer = (char*) malloc((length + 1) * sizeof(char));
len2 = freerdp_client_write_rdp_file_buffer(file, buffer, len + 1);
if (len2 == len) 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");
return FALSE;
}
fp = fopen(name, "w+b"); fp = fopen(name, "w+b");
if (fp != NULL) if (fp)
{ {
if (unicode) if (unicode)
{ {
ConvertToUnicode(CP_UTF8, 0, buffer, len, &unicodestr, 0); ConvertToUnicode(CP_UTF8, 0, buffer, length, &unicodestr, 0);
// Write multi-byte header /* Write multi-byte header */
fwrite(BOM_UTF16_LE, sizeof(BYTE), 2, fp); fwrite(BOM_UTF16_LE, sizeof(BYTE), 2, fp);
fwrite(unicodestr, 2, len, fp); fwrite(unicodestr, 2, length, fp);
free(unicodestr); free(unicodestr);
} }
else else
{ {
fwrite(buffer, 1, len, fp); fwrite(buffer, 1, length, fp);
} }
rc = fflush(fp); status = fflush(fp);
rc = fclose(fp); status = fclose(fp);
}
} }
if (buffer != NULL) if (buffer)
free(buffer); free(buffer);
return (rc == 0); return (status == 0) ? TRUE : FALSE;
} }
#define WRITE_RDP_FILE_DECLARE(_file, _buffer, _size) \ size_t freerdp_client_write_rdp_file_buffer(const rdpFile* file, char* buffer, size_t size)
rdpFile* __rdpFile = file; \
char* __buffer = _buffer; \
size_t __size = _size; \
size_t __required_size = 0; \
int __current = 0; \
int __count = 0;
#define WRITE_RDP_FILE_VALUE_INTEGER(_format, _field) \
if (~__rdpFile->_field) \
{ \
__count = sprintf_s(__buffer == NULL ? NULL : __buffer + __current, __buffer == NULL ? 0 : __size - __required_size, _format, (int) __rdpFile->_field); \
__required_size += __count; \
__current += __count; \
}
#define WRITE_RDP_FILE_VALUE_STRING(_format, _field) \
if (~((size_t) __rdpFile->_field) && __rdpFile->_field != NULL) \
{ \
__count = sprintf_s(__buffer == NULL ? NULL : __buffer + __current, __buffer == NULL ? 0 : __size - __required_size, _format, __rdpFile->_field); \
__required_size += __count; \
__current += __count; \
}
#define WRITE_RDP_FILE_VALUE_RETURN \
return __required_size;
size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size)
{ {
WRITE_RDP_FILE_DECLARE(file, buffer, size) int index;
int length;
char* output;
rdpFileLine* line;
WRITE_RDP_FILE_VALUE_INTEGER("screen mode id:i:%d\n", ScreenModeId); if (!buffer)
WRITE_RDP_FILE_VALUE_INTEGER("use multimon:i:%d\n", UseMultiMon); size = 0;
WRITE_RDP_FILE_VALUE_INTEGER("desktopwidth:i:%d\n", DesktopWidth);
WRITE_RDP_FILE_VALUE_INTEGER("desktopheight:i:%d\n", DesktopHeight);
WRITE_RDP_FILE_VALUE_INTEGER("session bpp:i:%d\n", SessionBpp);
WRITE_RDP_FILE_VALUE_STRING("winposstr:s:%s\n", WinPosStr);
WRITE_RDP_FILE_VALUE_INTEGER("compression:i:%d\n", Compression);
WRITE_RDP_FILE_VALUE_INTEGER("keyboardhook:i:%d\n", KeyboardHook);
WRITE_RDP_FILE_VALUE_INTEGER("audiocapturemode:i:%d\n", AudioCaptureMode);
WRITE_RDP_FILE_VALUE_INTEGER("videoplaybackmode:i:%d\n", VideoPlaybackMode);
WRITE_RDP_FILE_VALUE_INTEGER("connection type:i:%d\n", ConnectionType);
WRITE_RDP_FILE_VALUE_INTEGER("networkautodetect:i:%d\n", NetworkAutoDetect);
WRITE_RDP_FILE_VALUE_INTEGER("bandwidthautodetect:i:%d\n", BandwidthAutoDetect);
WRITE_RDP_FILE_VALUE_INTEGER("displayconnectionbar:i:%d\n", DisplayConnectionBar);
WRITE_RDP_FILE_VALUE_INTEGER("enableworkspacereconnect:i:%d\n", EnableWorkspaceReconnect);
WRITE_RDP_FILE_VALUE_INTEGER("disable wallpaper:i:%d\n", DisableWallpaper);
WRITE_RDP_FILE_VALUE_INTEGER("allow font smoothing:i:%d\n", AllowFontSmoothing);
WRITE_RDP_FILE_VALUE_INTEGER("allow desktop composition:i:%d\n", AllowDesktopComposition);
WRITE_RDP_FILE_VALUE_INTEGER("disable full window drag:i:%d\n", DisableFullWindowDrag);
WRITE_RDP_FILE_VALUE_INTEGER("disable menu anims:i:%d\n", DisableMenuAnims);
WRITE_RDP_FILE_VALUE_INTEGER("disable themes:i:%d\n", DisableThemes);
WRITE_RDP_FILE_VALUE_INTEGER("disable cursor setting:i:%d\n", DisableCursorSetting);
WRITE_RDP_FILE_VALUE_INTEGER("bitmapcachepersistenable:i:%d\n", BitmapCachePersistEnable);
WRITE_RDP_FILE_VALUE_STRING("full address:s:%s\n", FullAddress);
WRITE_RDP_FILE_VALUE_INTEGER("audiomode:i:%d\n", AudioMode);
WRITE_RDP_FILE_VALUE_INTEGER("redirectprinters:i:%d\n", RedirectPrinters);
WRITE_RDP_FILE_VALUE_INTEGER("redirectcomports:i:%d\n", RedirectComPorts);
WRITE_RDP_FILE_VALUE_INTEGER("redirectsmartcards:i:%d\n", RedirectSmartCards);
WRITE_RDP_FILE_VALUE_INTEGER("redirectclipboard:i:%d\n", RedirectClipboard);
WRITE_RDP_FILE_VALUE_INTEGER("redirectposdevices:i:%d\n", RedirectPosDevices);
WRITE_RDP_FILE_VALUE_INTEGER("autoreconnection enabled:i:%d\n", AutoReconnectionEnabled);
WRITE_RDP_FILE_VALUE_INTEGER("authentication level:i:%d\n", AuthenticationLevel);
WRITE_RDP_FILE_VALUE_INTEGER("prompt for credentials:i:%d\n", PromptForCredentials);
WRITE_RDP_FILE_VALUE_INTEGER("negotiate security layer:i:%d\n", NegotiateSecurityLayer);
WRITE_RDP_FILE_VALUE_INTEGER("remoteapplicationmode:i:%d\n", RemoteApplicationMode);
WRITE_RDP_FILE_VALUE_STRING("alternate shell:s:%s\n", AlternateShell);
WRITE_RDP_FILE_VALUE_STRING("shell working directory:s:%s\n", ShellWorkingDirectory);
WRITE_RDP_FILE_VALUE_STRING("gatewayhostname:s:%s\n", GatewayHostname);
WRITE_RDP_FILE_VALUE_INTEGER("gatewayusagemethod:i:%d\n", GatewayUsageMethod);
WRITE_RDP_FILE_VALUE_INTEGER("gatewaycredentialssource:i:%d\n", GatewayCredentialsSource);
WRITE_RDP_FILE_VALUE_INTEGER("gatewayprofileusagemethod:i:%d\n", GatewayProfileUsageMethod);
WRITE_RDP_FILE_VALUE_INTEGER("promptcredentialonce:i:%d\n", PromptCredentialOnce);
WRITE_RDP_FILE_VALUE_INTEGER("use redirection server name:i:%d\n", UseRedirectionServerName);
WRITE_RDP_FILE_VALUE_INTEGER("rdgiskdcproxy:i:%d\n", RdgIsKdcProxy);
WRITE_RDP_FILE_VALUE_STRING("kdcproxyname:s:%s\n", KdcProxyName);
WRITE_RDP_FILE_VALUE_STRING("drivestoredirect:s:%s\n", DrivesToRedirect);
WRITE_RDP_FILE_VALUE_STRING("username:s:%s\n", Username);
WRITE_RDP_FILE_VALUE_STRING("domain:s:%s\n", Domain);
WRITE_RDP_FILE_VALUE_RETURN output = buffer;
for (index = 0; index < file->lineCount; index++)
{
line = &(file->lines[index]);
length = strlen(line->text);
if (!buffer)
{
size += length + 1;
}
else
{
CopyMemory(output, line->text, length);
output += length;
*output = '\n';
output++;
}
}
if (buffer)
size = (output - buffer);
return size;
} }
BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* settings) BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* settings)
@ -846,7 +877,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
} }
if (~file->PromptCredentialOnce) if (~file->PromptCredentialOnce)
freerdp_set_param_bool(settings, FreeRDP_GatewayUseSameCredentials, TRUE); freerdp_set_param_bool(settings, FreeRDP_GatewayUseSameCredentials, file->PromptCredentialOnce);
if (~file->RemoteApplicationMode) if (~file->RemoteApplicationMode)
freerdp_set_param_bool(settings, FreeRDP_RemoteApplicationMode, file->RemoteApplicationMode); freerdp_set_param_bool(settings, FreeRDP_RemoteApplicationMode, file->RemoteApplicationMode);
@ -858,8 +889,6 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
freerdp_set_param_string(settings, FreeRDP_RemoteApplicationIcon, file->RemoteApplicationIcon); freerdp_set_param_string(settings, FreeRDP_RemoteApplicationIcon, file->RemoteApplicationIcon);
if (~((size_t) file->RemoteApplicationFile)) if (~((size_t) file->RemoteApplicationFile))
freerdp_set_param_string(settings, FreeRDP_RemoteApplicationGuid, file->RemoteApplicationGuid); freerdp_set_param_string(settings, FreeRDP_RemoteApplicationGuid, file->RemoteApplicationGuid);
if (~((size_t) file->RemoteApplicationGuid))
freerdp_set_param_string(settings, FreeRDP_RemoteApplicationGuid, file->RemoteApplicationGuid);
if (~((size_t) file->RemoteApplicationCmdLine)) if (~((size_t) file->RemoteApplicationCmdLine))
freerdp_set_param_string(settings, FreeRDP_RemoteApplicationCmdLine, file->RemoteApplicationCmdLine); freerdp_set_param_string(settings, FreeRDP_RemoteApplicationCmdLine, file->RemoteApplicationCmdLine);
@ -879,7 +908,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (~file->DisableThemes) if (~file->DisableThemes)
freerdp_set_param_bool(settings, FreeRDP_DisableThemes, file->DisableThemes); freerdp_set_param_bool(settings, FreeRDP_DisableThemes, file->DisableThemes);
if (~file->AllowDesktopComposition) if (~file->AllowDesktopComposition)
freerdp_set_param_bool(settings, FreeRDP_DisableCursorShadow, file->AllowDesktopComposition); freerdp_set_param_bool(settings, FreeRDP_AllowDesktopComposition, file->AllowDesktopComposition);
if (~file->BitmapCachePersistEnable) if (~file->BitmapCachePersistEnable)
freerdp_set_param_bool(settings, FreeRDP_BitmapCachePersistEnabled, file->BitmapCachePersistEnable); freerdp_set_param_bool(settings, FreeRDP_BitmapCachePersistEnabled, file->BitmapCachePersistEnable);
@ -965,12 +994,147 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (file->argc > 1) if (file->argc > 1)
{ {
char* ConnectionFile = settings->ConnectionFile;
settings->ConnectionFile = NULL;
freerdp_client_settings_parse_command_line(settings, file->argc, file->argv); freerdp_client_settings_parse_command_line(settings, file->argc, file->argv);
settings->ConnectionFile = ConnectionFile;
} }
return TRUE; return TRUE;
} }
rdpFileLine* freerdp_client_rdp_file_find_line_index(rdpFile* file, int index)
{
rdpFileLine* line;
line = &(file->lines[index]);
return line;
}
rdpFileLine* freerdp_client_rdp_file_find_line_by_name(rdpFile* file, const char* name)
{
int index;
BOOL bFound = FALSE;
rdpFileLine* line = NULL;
for (index = 0; index < file->lineCount; index++)
{
line = &(file->lines[index]);
if (line->flags & RDP_FILE_LINE_FLAG_FORMATTED)
{
if (strcmp(name, line->name) == 0)
{
bFound = TRUE;
break;
}
}
}
return (bFound) ? line : NULL;
}
int freerdp_client_rdp_file_set_string_option(rdpFile* file, const char* name, const char* value)
{
int index;
int length;
char* text;
rdpFileLine* line;
line = freerdp_client_rdp_file_find_line_by_name(file, name);
length = _scprintf("%s:s:%s", name, value);
text = (char*) malloc(length + 1);
sprintf_s(text, length + 1, "%s:s:%s", name, value ? value : "");
text[length] = '\0';
if (line)
{
free(line->sValue);
line->sValue = _strdup(value);
free(line->text);
line->text = text;
}
else
{
index = freerdp_client_parse_rdp_file_add_line(file, text, -1);
line = freerdp_client_rdp_file_find_line_index(file, index);
freerdp_client_rdp_file_set_string(file, name, value, index);
free(text);
}
return 0;
}
const char* freerdp_client_rdp_file_get_string_option(rdpFile* file, const char* name)
{
rdpFileLine* line;
line = freerdp_client_rdp_file_find_line_by_name(file, name);
if (!line)
return NULL;
if (!(line->flags & RDP_FILE_LINE_FLAG_TYPE_STRING))
return NULL;
return line->sValue;
}
int freerdp_client_rdp_file_set_integer_option(rdpFile* file, const char* name, int value)
{
int index;
int length;
char* text;
rdpFileLine* line;
line = freerdp_client_rdp_file_find_line_by_name(file, name);
length = _scprintf("%s:i:%d", name, value);
text = (char*) malloc(length + 1);
sprintf_s(text, length + 1, "%s:i:%d", name, value);
text[length] = '\0';
if (line)
{
line->iValue = value;
free(line->text);
line->text = text;
}
else
{
index = freerdp_client_parse_rdp_file_add_line(file, text, -1);
line = freerdp_client_rdp_file_find_line_index(file, index);
freerdp_client_rdp_file_set_integer(file, (char*) name, value, index);
free(text);
}
return 0;
}
int freerdp_client_rdp_file_get_integer_option(rdpFile* file, const char* name)
{
rdpFileLine* line;
line = freerdp_client_rdp_file_find_line_by_name(file, name);
if (!line)
return -1;
if (!(line->flags & RDP_FILE_LINE_FLAG_TYPE_INTEGER))
return -1;
return line->iValue;
}
void freerdp_client_file_string_check_free(LPSTR str) void freerdp_client_file_string_check_free(LPSTR str)
{ {
if (~((size_t) str)) if (~((size_t) str))
@ -987,6 +1151,10 @@ rdpFile* freerdp_client_rdp_file_new()
{ {
FillMemory(file, sizeof(rdpFile), 0xFF); FillMemory(file, sizeof(rdpFile), 0xFF);
file->lineCount = 0;
file->lineSize = 32;
file->lines = (rdpFileLine*) malloc(file->lineSize * sizeof(rdpFileLine));
file->argc = 0; file->argc = 0;
file->argSize = 32; file->argSize = 32;
file->argv = (char**) malloc(file->argSize * sizeof(char*)); file->argv = (char**) malloc(file->argSize * sizeof(char*));
@ -1003,6 +1171,18 @@ void freerdp_client_rdp_file_free(rdpFile* file)
if (file) if (file)
{ {
if (file->lineCount)
{
for (i = 0; i < file->lineCount; i++)
{
free(file->lines[i].text);
free(file->lines[i].name);
free(file->lines[i].sValue);
}
free(file->lines);
}
if (file->argv) if (file->argv)
{ {
for (i = 0; i < file->argc; i++) for (i = 0; i < file->argc; i++)

View File

@ -256,11 +256,17 @@ static char testRdpFileUTF8[] =
"rdgiskdcproxy:i:0\n" "rdgiskdcproxy:i:0\n"
"kdcproxyname:s:\n" "kdcproxyname:s:\n"
"drivestoredirect:s:*\n" "drivestoredirect:s:*\n"
"username:s:LAB1\\JohnDoe\n"; "username:s:LAB1\\JohnDoe\n"
"vendor integer:i:123\n"
"vendor string:s:microsoft\n";
int TestClientRdpFile(int argc, char* argv[]) int TestClientRdpFile(int argc, char* argv[])
{ {
int index;
int iValue;
char* sValue;
rdpFile* file; rdpFile* file;
rdpFileLine* line;
/* Unicode */ /* Unicode */
@ -324,6 +330,38 @@ int TestClientRdpFile(int argc, char* argv[])
return -1; return -1;
} }
iValue = freerdp_client_rdp_file_get_integer_option(file, "vendor integer");
freerdp_client_rdp_file_set_integer_option(file, "vendor integer", 456);
iValue = freerdp_client_rdp_file_get_integer_option(file, "vendor integer");
sValue = (char*) freerdp_client_rdp_file_get_string_option(file, "vendor string");
freerdp_client_rdp_file_set_string_option(file, "vendor string", "apple");
sValue = (char*) freerdp_client_rdp_file_get_string_option(file, "vendor string");
freerdp_client_rdp_file_set_string_option(file, "fruits", "banana,oranges");
freerdp_client_rdp_file_set_integer_option(file, "numbers", 123456789);
for (index = 0; index < file->lineCount; index++)
{
line = &(file->lines[index]);
if (line->flags & RDP_FILE_LINE_FLAG_FORMATTED)
{
if (line->flags & RDP_FILE_LINE_FLAG_TYPE_STRING)
{
printf("line %02d: name: %s value: %s, %s\n",
line->index, line->name, line->sValue,
(line->flags & RDP_FILE_LINE_FLAG_STANDARD) ? "standard" : "non-standard");
}
else if (line->flags & RDP_FILE_LINE_FLAG_TYPE_INTEGER)
{
printf("line %02d: name: %s value: %d, %s\n",
line->index, line->name, line->iValue,
(line->flags & RDP_FILE_LINE_FLAG_STANDARD) ? "standard" : "non-standard");
}
}
}
freerdp_client_rdp_file_free(file); freerdp_client_rdp_file_free(file);
return 0; return 0;

View File

@ -6,3 +6,5 @@ bin/
build/ build/
project.pbxproj project.pbxproj
!iFreeRDP.xcodeproj/ !iFreeRDP.xcodeproj/
iFreeRDP.app/

View File

@ -470,6 +470,7 @@ if( ANDROID_FORBID_SYGWIN )
endif() endif()
endif() endif()
# FIXME: properly detect 64-bit host, currently reported as 32-bit
# detect current host platform # 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")
@ -493,7 +494,7 @@ else()
endif() endif()
if( NOT ANDROID_NDK_HOST_X64 ) 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() endif()
# see if we have path to Android NDK # see if we have path to Android NDK

13
cmake/FindGSM.cmake Normal file
View File

@ -0,0 +1,13 @@
find_path(GSM_INCLUDE_DIR gsm/gsm.h)
find_library(GSM_LIBRARY gsm)
find_package_handle_standard_args(GSM DEFAULT_MSG GSM_INCLUDE_DIR GSM_LIBRARY)
if(GSM_FOUND)
set(GSM_LIBRARIES ${GSM_LIBRARY})
set(GSM_INCLUDE_DIRS ${GSM_INCLUDE_DIR})
endif()
mark_as_advanced(GSM_INCLUDE_DIR GSM_LIBRARY)

View File

@ -143,14 +143,10 @@ IF(WIN32 AND NOT CYGWIN)
"lib/VC" "lib/VC"
) )
if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) set( OPENSSL_DEBUG_LIBRARIES ${SSL_EAY_DEBUG} ${LIB_EAY_DEBUG} )
set( OPENSSL_LIBRARIES set( OPENSSL_RELEASE_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} )
optimized ${SSL_EAY_RELEASE} debug ${SSL_EAY_DEBUG} set( OPENSSL_LIBRARIES ${OPENSSL_RELEASE_LIBRARIES} )
optimized ${LIB_EAY_RELEASE} debug ${LIB_EAY_DEBUG}
)
else()
set( OPENSSL_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} )
endif()
MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE) MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE)
MARK_AS_ADVANCED(LIB_EAY_DEBUG LIB_EAY_RELEASE) MARK_AS_ADVANCED(LIB_EAY_DEBUG LIB_EAY_RELEASE)
ELSEIF(MINGW) ELSEIF(MINGW)
@ -322,4 +318,4 @@ else (OPENSSL_VERSION)
) )
endif (OPENSSL_VERSION) endif (OPENSSL_VERSION)
MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_DEBUG_LIBRARIES OPENSSL_RELEASE_LIBRARIES)

View File

@ -44,6 +44,7 @@
#cmakedefine WITH_PULSE #cmakedefine WITH_PULSE
#cmakedefine WITH_IOSAUDIO #cmakedefine WITH_IOSAUDIO
#cmakedefine WITH_OPENSLES #cmakedefine WITH_OPENSLES
#cmakedefine WITH_GSM
/* Plugins */ /* Plugins */
#cmakedefine STATIC_CHANNELS #cmakedefine STATIC_CHANNELS

83
docs/valgrind.supp Normal file
View File

@ -0,0 +1,83 @@
{
ignore glibc getaddrinfo
Memcheck:Param
sendmsg(mmsg[0].msg_hdr)
fun:sendmmsg
fun:__libc_res_nsend
fun:__libc_res_nquery
fun:__libc_res_nsearch
fun:_nss_dns_gethostbyname4_r
fun:gaih_inet
fun:getaddrinfo
fun:freerdp_tcp_connect
fun:tcp_connect
fun:transport_connect
fun:nego_tcp_connect
fun:nego_transport_connect
}
{
ignore openssl malloc
Memcheck:Leak
fun:malloc
fun:CRYPTO_malloc
...
obj:*libcrypto*
}
{
ignore openssl realloc
Memcheck:Leak
fun:realloc
fun:CRYPTO_realloc
...
obj:*libcrypto*
}
{
ignore libssl cond
Memcheck:Cond
obj:*libssl*
}
{
ignore libssl value
Memcheck:Value4
obj:*libssl*
}
{
ignore ssl3_read_bytes tls1_enc
Memcheck:Cond
fun:tls1_enc
fun:ssl3_read_bytes
obj:*libssl*
}
{
ignore ssl3_read_bytes memcpy
Memcheck:Cond
fun:memcpy@@GLIBC_2.14
fun:ssl3_read_bytes
obj:*libssl*
}
{
ignore ssl3_read_bytes value8
Memcheck:Value8
fun:memcpy@@GLIBC_2.14
fun:ssl3_read_bytes
obj:*libssl*
}
{
ignore write buf BIO_write
Memcheck:Param
write(buf)
obj:*libpthread*
obj:*libcrypto*
fun:BIO_write
fun:ssl3_write_pending
fun:ssl3_write_bytes
}

View File

@ -0,0 +1,177 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_CLIPRDR_H
#define FREERDP_CHANNEL_CLIPRDR_H
#include <freerdp/api.h>
#include <freerdp/types.h>
#define CLIPRDR_SVC_CHANNEL_NAME "cliprdr"
/**
* 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
#define CB_FORMAT_GIF 0xD013
/* CLIPRDR_HEADER.msgType */
#define CB_MONITOR_READY 0x0001
#define CB_FORMAT_LIST 0x0002
#define CB_FORMAT_LIST_RESPONSE 0x0003
#define CB_FORMAT_DATA_REQUEST 0x0004
#define CB_FORMAT_DATA_RESPONSE 0x0005
#define CB_TEMP_DIRECTORY 0x0006
#define CB_CLIP_CAPS 0x0007
#define CB_FILECONTENTS_REQUEST 0x0008
#define CB_FILECONTENTS_RESPONSE 0x0009
#define CB_LOCK_CLIPDATA 0x000A
#define CB_UNLOCK_CLIPDATA 0x000B
/* CLIPRDR_HEADER.msgFlags */
#define CB_RESPONSE_OK 0x0001
#define CB_RESPONSE_FAIL 0x0002
#define CB_ASCII_NAMES 0x0004
/* CLIPRDR_CAPS_SET.capabilitySetType */
#define CB_CAPSTYPE_GENERAL 0x0001
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
#define CB_CAPSTYPE_GENERAL_LEN 12
/* CLIPRDR_GENERAL_CAPABILITY.version */
#define CB_CAPS_VERSION_1 0x00000001
#define CB_CAPS_VERSION_2 0x00000002
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
#define CB_CAN_LOCK_CLIPDATA 0x00000010
#define DEFINE_CLIPRDR_HEADER_COMMON() \
UINT16 msgType; \
UINT16 msgFlags; \
UINT32 dataLen
struct _CLIPRDR_HEADER
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
struct _CLIPRDR_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
};
typedef struct _CLIPRDR_CAPABILITY_SET CLIPRDR_CAPABILITY_SET;
struct _CLIPRDR_GENERAL_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
UINT32 version;
UINT32 generalFlags;
};
typedef struct _CLIPRDR_GENERAL_CAPABILITY_SET CLIPRDR_GENERAL_CAPABILITY_SET;
struct _CLIPRDR_CAPABILITIES
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 cCapabilitiesSets;
CLIPRDR_CAPABILITY_SET* capabilitySets;
};
typedef struct _CLIPRDR_CAPABILITIES CLIPRDR_CAPABILITIES;
struct _CLIPRDR_MONITOR_READY
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY;
struct _CLIPRDR_FORMAT
{
UINT32 formatId;
char* formatName;
};
typedef struct _CLIPRDR_FORMAT CLIPRDR_FORMAT;
struct _CLIPRDR_FORMAT_LIST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 cFormats;
CLIPRDR_FORMAT* formats;
};
typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST;
struct _CLIPRDR_FORMAT_LIST_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE;
struct _CLIPRDR_FORMAT_DATA_REQUEST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 requestedFormatId;
};
typedef struct _CLIPRDR_FORMAT_DATA_REQUEST CLIPRDR_FORMAT_DATA_REQUEST;
struct _CLIPRDR_FORMAT_DATA_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
BYTE* requestedFormatData;
};
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
#endif /* FREERDP_CHANNEL_CLIPRDR_H */

View File

@ -87,8 +87,8 @@ 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_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(rdpSettings* settings, const char* filename);
FREERDP_API int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, BYTE* buffer, size_t size); 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(rdpSettings* settings, const char* filename, BOOL unicode); FREERDP_API int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename, BOOL unicode);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,6 +1,6 @@
/** /**
* FreeRDP: A Remote Desktop Protocol Implementation * FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel Types * Clipboard Virtual Channel Extension
* *
* Copyright 2011 Vic Lee * Copyright 2011 Vic Lee
* *
@ -22,72 +22,45 @@
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/message.h>
#include <freerdp/channels/cliprdr.h>
/** /**
* Client Interface * Client Interface
*/ */
typedef struct _cliprdr_client_context CliprdrClientContext; typedef struct _cliprdr_client_context CliprdrClientContext;
typedef int (*pcCliprdrMonitorReady)(CliprdrClientContext* context); typedef int (*pcCliprdrServerCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities);
typedef int (*pcCliprdrFormatList)(CliprdrClientContext* context); typedef int (*pcCliprdrClientCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities);
typedef int (*pcCliprdrDataRequest)(CliprdrClientContext* context); typedef int (*pcCliprdrMonitorReady)(CliprdrClientContext* context, CLIPRDR_MONITOR_READY* monitorReady);
typedef int (*pcCliprdrDataResponse)(CliprdrClientContext* context); typedef int (*pcCliprdrClientFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList);
typedef int (*pcCliprdrServerFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList);
typedef int (*pcCliprdrClientFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
typedef int (*pcCliprdrServerFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
typedef int (*pcCliprdrClientFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
typedef int (*pcCliprdrServerFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
typedef int (*pcCliprdrClientFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
typedef int (*pcCliprdrServerFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
struct _cliprdr_client_context struct _cliprdr_client_context
{ {
void* handle;
void* custom;
pcCliprdrServerCapabilities ServerCapabilities;
pcCliprdrClientCapabilities ClientCapabilities;
pcCliprdrMonitorReady MonitorReady; pcCliprdrMonitorReady MonitorReady;
pcCliprdrFormatList FormatList; pcCliprdrClientFormatList ClientFormatList;
pcCliprdrDataRequest DataRequest; pcCliprdrServerFormatList ServerFormatList;
pcCliprdrDataResponse DataResponse; pcCliprdrClientFormatListResponse ClientFormatListResponse;
pcCliprdrServerFormatListResponse ServerFormatListResponse;
pcCliprdrClientFormatDataRequest ClientFormatDataRequest;
pcCliprdrServerFormatDataRequest ServerFormatDataRequest;
pcCliprdrClientFormatDataResponse ClientFormatDataResponse;
pcCliprdrServerFormatDataResponse ServerFormatDataResponse;
}; };
/**
* Clipboard Formats
*/
#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
#define CB_FORMAT_GIF 0xD013
/* CLIPRDR_HEADER.msgType */
#define CB_MONITOR_READY 0x0001
#define CB_FORMAT_LIST 0x0002
#define CB_FORMAT_LIST_RESPONSE 0x0003
#define CB_FORMAT_DATA_REQUEST 0x0004
#define CB_FORMAT_DATA_RESPONSE 0x0005
#define CB_TEMP_DIRECTORY 0x0006
#define CB_CLIP_CAPS 0x0007
#define CB_FILECONTENTS_REQUEST 0x0008
#define CB_FILECONTENTS_RESPONSE 0x0009
#define CB_LOCK_CLIPDATA 0x000A
#define CB_UNLOCK_CLIPDATA 0x000B
/* CLIPRDR_HEADER.msgFlags */
#define CB_RESPONSE_OK 0x0001
#define CB_RESPONSE_FAIL 0x0002
#define CB_ASCII_NAMES 0x0004
/* CLIPRDR_CAPS_SET.capabilitySetType */
#define CB_CAPSTYPE_GENERAL 0x0001
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
#define CB_CAPSTYPE_GENERAL_LEN 12
/* CLIPRDR_GENERAL_CAPABILITY.version */
#define CB_CAPS_VERSION_1 0x00000001
#define CB_CAPS_VERSION_2 0x00000002
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
#define CB_CAN_LOCK_CLIPDATA 0x00000010
struct _CLIPRDR_FORMAT_NAME struct _CLIPRDR_FORMAT_NAME
{ {
UINT32 id; UINT32 id;
@ -99,10 +72,6 @@ typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
/** /**
* Clipboard Events * Clipboard Events
*/ */
#define CAPS_USE_LONG_FORMAT_NAMES 0x00000002
#define CAPS_STREAM_FILECLIP_ENABLED 0x00000004
#define CAPS_FILECLIP_NO_FILE_PATH 0x00000008
#define CAPS_CAN_LOCK_CLIPDATA 0x00000010
struct _RDP_CB_CLIP_CAPS struct _RDP_CB_CLIP_CAPS
{ {

View File

@ -23,6 +23,25 @@
#include <freerdp/api.h> #include <freerdp/api.h>
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#define RDP_FILE_LINE_FLAG_FORMATTED 0x00000001
#define RDP_FILE_LINE_FLAG_STANDARD 0x00000002
#define RDP_FILE_LINE_FLAG_TYPE_STRING 0x00000010
#define RDP_FILE_LINE_FLAG_TYPE_INTEGER 0x00000020
#define RDP_FILE_LINE_FLAG_TYPE_BINARY 0x00000040
struct rdp_file_line
{
int index;
char* text;
DWORD flags;
char* name;
LPSTR sValue;
DWORD iValue;
PBYTE bValue;
int valueLength;
};
typedef struct rdp_file_line rdpFileLine;
struct rdp_file struct rdp_file
{ {
DWORD UseMultiMon; /* use multimon */ DWORD UseMultiMon; /* use multimon */
@ -130,6 +149,10 @@ struct rdp_file
LPSTR DevicesToRedirect; /* devicestoredirect */ LPSTR DevicesToRedirect; /* devicestoredirect */
LPSTR WinPosStr; /* winposstr */ LPSTR WinPosStr; /* winposstr */
int lineCount;
int lineSize;
rdpFileLine* lines;
int argc; int argc;
char** argv; char** argv;
int argSize; int argSize;
@ -142,12 +165,18 @@ extern "C" {
#endif #endif
FREERDP_API BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name); FREERDP_API BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name);
FREERDP_API BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, BYTE* buffer, size_t size); FREERDP_API BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, const BYTE* buffer, size_t size);
FREERDP_API BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* settings); FREERDP_API BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* settings);
FREERDP_API BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings* settings); FREERDP_API BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSettings* settings);
FREERDP_API BOOL freerdp_client_write_rdp_file(rdpFile* file, const char* name, BOOL unicode); FREERDP_API BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL unicode);
FREERDP_API size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size); FREERDP_API size_t freerdp_client_write_rdp_file_buffer(const rdpFile* file, char* buffer, size_t size);
FREERDP_API int freerdp_client_rdp_file_set_string_option(rdpFile* file, const char* name, const char* value);
FREERDP_API const char* freerdp_client_rdp_file_get_string_option(rdpFile* file, const char* name);
FREERDP_API int freerdp_client_rdp_file_set_integer_option(rdpFile* file, const char* name, int value);
FREERDP_API int freerdp_client_rdp_file_get_integer_option(rdpFile* file, const char* name);
FREERDP_API rdpFile* freerdp_client_rdp_file_new(void); FREERDP_API rdpFile* freerdp_client_rdp_file_new(void);
FREERDP_API void freerdp_client_rdp_file_free(rdpFile* file); FREERDP_API void freerdp_client_rdp_file_free(rdpFile* file);

View File

@ -43,6 +43,8 @@ struct _RDPSND_WAVE
UINT32 wLocalTimeA; UINT32 wLocalTimeA;
UINT32 wLocalTimeB; UINT32 wLocalTimeB;
BOOL AutoConfirm;
}; };
typedef struct _RDPSND_WAVE RDPSND_WAVE; typedef struct _RDPSND_WAVE RDPSND_WAVE;
@ -81,6 +83,8 @@ struct rdpsnd_device_plugin
pcWaveDecode WaveDecode; pcWaveDecode WaveDecode;
pcWavePlay WavePlay; pcWavePlay WavePlay;
pcWaveConfirm WaveConfirm; pcWaveConfirm WaveConfirm;
BOOL DisableConfirmThread;
}; };
#define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry" #define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry"

View File

@ -23,6 +23,8 @@
#include <freerdp/api.h> #include <freerdp/api.h>
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/codec/color.h>
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/stream.h> #include <winpr/stream.h>
@ -31,4 +33,17 @@ FREERDP_API BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int
FREERDP_API int freerdp_bitmap_compress(char* in_data, int width, int height, 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); 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);
#endif /* FREERDP_CODEC_BITMAP_H */ #endif /* FREERDP_CODEC_BITMAP_H */

View File

@ -23,6 +23,20 @@
#include <freerdp/api.h> #include <freerdp/api.h>
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#define FREERDP_PIXEL_FORMAT_TYPE_ARGB 1
#define FREERDP_PIXEL_FORMAT_TYPE_ABGR 2
#define FREERDP_PIXEL_FLIP_NONE 0
#define FREERDP_PIXEL_FLIP_VERTICAL 1
#define FREERDP_PIXEL_FLIP_HORIZONTAL 2
#define FREERDP_PIXEL_FORMAT(_bpp, _type, _flip) \
((_bpp << 24) | (_type << 16) | (_flip << 8))
#define FREERDP_PIXEL_FORMAT_BPP(_format) (((_format) >> 24) & 0xFF)
#define FREERDP_PIXEL_FORMAT_TYPE(_format) (((_format) >> 16) & 0xFF)
#define FREERDP_PIXEL_FORMAT_FLIP(_format) (((_format) >> 8) & 0xFF)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -50,6 +50,7 @@ FREERDP_API int decompress_rdp_4(struct rdp_mppc_dec* dec, BYTE* cbuf, int len,
FREERDP_API int decompress_rdp_5(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen); FREERDP_API int decompress_rdp_5(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen);
FREERDP_API int decompress_rdp_6(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen); FREERDP_API int decompress_rdp_6(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen);
FREERDP_API int decompress_rdp_61(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen); FREERDP_API int decompress_rdp_61(struct rdp_mppc_dec* dec, BYTE* cbuf, int len, int ctype, UINT32* roff, UINT32* rlen);
FREERDP_API struct rdp_mppc_dec* mppc_dec_new(void); FREERDP_API struct rdp_mppc_dec* mppc_dec_new(void);
FREERDP_API void mppc_dec_free(struct rdp_mppc_dec* dec); FREERDP_API void mppc_dec_free(struct rdp_mppc_dec* dec);

View File

@ -34,6 +34,35 @@
#include <winpr/stream.h> #include <winpr/stream.h>
#define TLS_ALERT_LEVEL_WARNING 1
#define TLS_ALERT_LEVEL_FATAL 2
#define TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY 0
#define TLS_ALERT_DESCRIPTION_UNEXPECTED_MESSAGE 10
#define TLS_ALERT_DESCRIPTION_BAD_RECORD_MAC 20
#define TLS_ALERT_DESCRIPTION_DECRYPTION_FAILED 21
#define TLS_ALERT_DESCRIPTION_RECORD_OVERFLOW 22
#define TLS_ALERT_DESCRIPTION_DECOMPRESSION_FAILURE 30
#define TLS_ALERT_DESCRIPTION_HANSHAKE_FAILURE 40
#define TLS_ALERT_DESCRIPTION_NO_CERTIFICATE 41
#define TLS_ALERT_DESCRIPTION_BAD_CERTIFICATE 42
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE 43
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_REVOKED 44
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_EXPIRED 45
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN 46
#define TLS_ALERT_DESCRIPTION_ILLEGAL_PARAMETER 47
#define TLS_ALERT_DESCRIPTION_UNKNOWN_CA 48
#define TLS_ALERT_DESCRIPTION_ACCESS_DENIED 49
#define TLS_ALERT_DESCRIPTION_DECODE_ERROR 50
#define TLS_ALERT_DESCRIPTION_DECRYPT_ERROR 51
#define TLS_ALERT_DESCRIPTION_EXPORT_RESTRICTION 60
#define TLS_ALERT_DESCRIPTION_PROTOCOL_VERSION 70
#define TLS_ALERT_DESCRIPTION_INSUFFICIENT_SECURITY 71
#define TLS_ALERT_DESCRIPTION_INTERNAL_ERROR 80
#define TLS_ALERT_DESCRIPTION_USER_CANCELED 90
#define TLS_ALERT_DESCRIPTION_NO_RENEGOTIATION 100
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION 110
typedef struct rdp_tls rdpTls; typedef struct rdp_tls rdpTls;
struct rdp_tls struct rdp_tls
@ -49,6 +78,10 @@ struct rdp_tls
rdpSettings* settings; rdpSettings* settings;
SecPkgContext_Bindings* Bindings; SecPkgContext_Bindings* Bindings;
rdpCertificateStore* certificate_store; rdpCertificateStore* certificate_store;
char* hostname;
int port;
int alertLevel;
int alertDescription;
}; };
FREERDP_API BOOL tls_connect(rdpTls* tls); FREERDP_API BOOL tls_connect(rdpTls* tls);
@ -63,8 +96,10 @@ FREERDP_API int tls_write_all(rdpTls* tls, BYTE* data, int length);
FREERDP_API int tls_wait_read(rdpTls* tls); FREERDP_API int tls_wait_read(rdpTls* tls);
FREERDP_API int tls_wait_write(rdpTls* tls); FREERDP_API int tls_wait_write(rdpTls* tls);
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname); FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname);
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname); FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file); FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file);
FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count); FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count);

View File

@ -45,6 +45,19 @@ extern "C" {
#define ERRINFO_RPC_INITIATED_DISCONNECT_BY_USER 0x0000000B #define ERRINFO_RPC_INITIATED_DISCONNECT_BY_USER 0x0000000B
#define ERRINFO_LOGOFF_BY_USER 0x0000000C #define ERRINFO_LOGOFF_BY_USER 0x0000000C
/* Protocol-independent codes generated by the Connection Broker */
#define ERRINFO_CB_DESTINATION_NOT_FOUND 0x0000400
#define ERRINFO_CB_LOADING_DESTINATION 0x0000402
#define ERRINFO_CB_REDIRECTING_TO_DESTINATION 0x0000404
#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE 0x0000405
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT 0x0000406
#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS 0x0000407
#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE 0x0000408
#define ERRINFO_CB_CONNECTION_CANCELLED 0x0000409
#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS 0x0000410
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT 0x0000411
#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED 0x0000412
/* Protocol-independent licensing codes */ /* Protocol-independent licensing codes */
#define ERRINFO_LICENSE_INTERNAL 0x00000100 #define ERRINFO_LICENSE_INTERNAL 0x00000100
#define ERRINFO_LICENSE_NO_LICENSE_SERVER 0x00000101 #define ERRINFO_LICENSE_NO_LICENSE_SERVER 0x00000101
@ -123,6 +136,11 @@ extern "C" {
#define ERRINFO_VC_DATA_TOO_LONG 0x0000112B #define ERRINFO_VC_DATA_TOO_LONG 0x0000112B
#define ERRINFO_GRAPHICS_MODE_NOT_SUPPORTED 0x0000112D #define ERRINFO_GRAPHICS_MODE_NOT_SUPPORTED 0x0000112D
#define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED 0x0000112E #define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED 0x0000112E
#define ERRINFO_GRAPHICS_SUBSYSTEM_FAILED 0x0000112F
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_SHORT 0x00001130
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_LONG 0x00001131
#define ERRINFO_DYNAMIC_DST_DISABLED_FIELD_MISSING 0x00001132
#define ERRINFO_VC_DECODING_ERROR 0x00001133
#define ERRINFO_UPDATE_SESSION_KEY_FAILED 0x00001191 #define ERRINFO_UPDATE_SESSION_KEY_FAILED 0x00001191
#define ERRINFO_DECRYPT_FAILED 0x00001192 #define ERRINFO_DECRYPT_FAILED 0x00001192
#define ERRINFO_ENCRYPT_FAILED 0x00001193 #define ERRINFO_ENCRYPT_FAILED 0x00001193
@ -155,6 +173,7 @@ FREERDP_API extern int connectErrorCode;
#define TLSCONNECTERROR ERRORSTART + 8 #define TLSCONNECTERROR ERRORSTART + 8
#define AUTHENTICATIONERROR ERRORSTART + 9 #define AUTHENTICATIONERROR ERRORSTART + 9
#define INSUFFICIENTPRIVILEGESERROR ERRORSTART + 10 #define INSUFFICIENTPRIVILEGESERROR ERRORSTART + 10
#define CANCELEDBYUSER ERRORSTART + 11
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -65,10 +65,6 @@ DEFINE_EVENT_BEGIN(ErrorInfo)
UINT32 code; UINT32 code;
DEFINE_EVENT_END(ErrorInfo) DEFINE_EVENT_END(ErrorInfo)
DEFINE_EVENT_BEGIN(ParamChange)
int id;
DEFINE_EVENT_END(ParamChange)
DEFINE_EVENT_BEGIN(Terminate) DEFINE_EVENT_BEGIN(Terminate)
int code; int code;
DEFINE_EVENT_END(Terminate) DEFINE_EVENT_END(Terminate)

View File

@ -61,6 +61,7 @@ typedef void (*pPostDisconnect)(freerdp* instance);
typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain); typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain);
typedef BOOL (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint); typedef BOOL (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint);
typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject, char* issuer, char* new_fingerprint, char* old_fingerprint); typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject, char* issuer, char* new_fingerprint, char* old_fingerprint);
typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data, int length, const char* hostname, int port, DWORD flags);
typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type); typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type);
@ -195,13 +196,19 @@ struct rdp_freerdp
Used when a certificate differs from stored fingerprint. Used when a certificate differs from stored fingerprint.
If returns TRUE, the new fingerprint will be trusted and old thrown out. */ If returns TRUE, the new fingerprint will be trusted and old thrown out. */
ALIGN64 pLogonErrorInfo LogonErrorInfo; /**< (offset 53) Callback for logon error info, important for logon system messages with RemoteApp */ ALIGN64 pVerifyX509Certificate VerifyX509Certificate; /**< (offset 53) Callback for X509 certificate verification (PEM format) */
ALIGN64 pPostDisconnect PostDisconnect; /**< (offset 54) ALIGN64 pLogonErrorInfo LogonErrorInfo; /**< (offset 54) Callback for logon error info, important for logon system messages with RemoteApp */
ALIGN64 pPostDisconnect PostDisconnect; /**< (offset 55)
Callback for cleaning up resources allocated Callback for cleaning up resources allocated
by connect callbacks. */ by connect callbacks. */
UINT64 paddingD[64 - 55]; /* 55 */ ALIGN64 pAuthenticate GatewayAuthenticate; /**< (offset 56)
Callback for gateway authentication.
It is used to get the username/password when it was not provided at connection time. */
UINT64 paddingD[64 - 57]; /* 57 */
ALIGN64 pSendChannelData SendChannelData; /* (offset 64) ALIGN64 pSendChannelData SendChannelData; /* (offset 64)
Callback for sending data to a channel. Callback for sending data to a channel.

View File

@ -113,6 +113,10 @@
#define GDI_OPAQUE 0x00000001 #define GDI_OPAQUE 0x00000001
#define GDI_TRANSPARENT 0x00000002 #define GDI_TRANSPARENT 0x00000002
/* Fill Modes */
#define GDI_FILL_ALTERNATE 0x01
#define GDI_FILL_WINDING 0x02
/* GDI Object Types */ /* GDI Object Types */
#define GDIOBJECT_BITMAP 0x00 #define GDIOBJECT_BITMAP 0x00
#define GDIOBJECT_PEN 0x01 #define GDIOBJECT_PEN 0x01

View File

@ -23,6 +23,8 @@
#include <freerdp/api.h> #include <freerdp/api.h>
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/channels/wtsvc.h> #include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/cliprdr.h>
#include <freerdp/client/cliprdr.h> #include <freerdp/client/cliprdr.h>
/** /**

View File

@ -51,13 +51,15 @@
#define CS_CLUSTER 0xC004 #define CS_CLUSTER 0xC004
#define CS_MONITOR 0xC005 #define CS_MONITOR 0xC005
#define CS_MCS_MSGCHANNEL 0xC006 #define CS_MCS_MSGCHANNEL 0xC006
#define CS_MULTITRANSPORT 0xC008 #define CS_MONITOR_EX 0xC008
#define CS_MULTITRANSPORT 0xC00A
/* Server to Client (SC) data blocks */ /* Server to Client (SC) data blocks */
#define SC_CORE 0x0C01 #define SC_CORE 0x0C01
#define SC_SECURITY 0x0C02 #define SC_SECURITY 0x0C02
#define SC_NET 0x0C03 #define SC_NET 0x0C03
#define SC_MULTITRANSPORT 0x0C06 #define SC_MCS_MSGCHANNEL 0x0C04
#define SC_MULTITRANSPORT 0x0C08
/* RDP version */ /* RDP version */
#define RDP_VERSION_4 0x00080001 #define RDP_VERSION_4 0x00080001
@ -240,6 +242,15 @@ typedef struct _TARGET_NET_ADDRESS TARGET_NET_ADDRESS;
#define LOGON_FAILED_OTHER 0x00000002 #define LOGON_FAILED_OTHER 0x00000002
#define LOGON_WARNING 0x00000003 #define LOGON_WARNING 0x00000003
/* Server Status Info */
#define STATUS_FINDING_DESTINATION 0x00000401
#define STATUS_LOADING_DESTINATION 0x00000402
#define STATUS_BRINGING_SESSION_ONLINE 0x00000403
#define STATUS_REDIRECTING_TO_DESTINATION 0x00000404
#define STATUS_VM_LOADING 0x00000501
#define STATUS_VM_WAKING 0x00000502
#define STATUS_VM_BOOTING 0x00000503
/* SYSTEM_TIME */ /* SYSTEM_TIME */
typedef struct typedef struct
{ {
@ -389,6 +400,26 @@ struct rdp_monitor
}; };
typedef struct rdp_monitor rdpMonitor; typedef struct rdp_monitor rdpMonitor;
struct _MONITOR_DEF
{
INT32 left;
INT32 top;
INT32 right;
INT32 bottom;
UINT32 flags;
};
typedef struct _MONITOR_DEF MONITOR_DEF;
struct _MONITOR_ATTRIBUTES
{
UINT32 physicalWidth;
UINT32 physicalHeight;
UINT32 orientation;
UINT32 desktopScaleFactor;
UINT32 deviceScaleFactor;
};
typedef struct _MONITOR_ATTRIBUTES MONITOR_ATTRIBUTES;
/* Device Redirection */ /* Device Redirection */
#define RDPDR_DTYP_SERIAL 0x00000001 #define RDPDR_DTYP_SERIAL 0x00000001
@ -493,6 +524,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_SupportMonitorLayoutPdu 141 #define FreeRDP_SupportMonitorLayoutPdu 141
#define FreeRDP_SupportGraphicsPipeline 142 #define FreeRDP_SupportGraphicsPipeline 142
#define FreeRDP_SupportDynamicTimeZone 143 #define FreeRDP_SupportDynamicTimeZone 143
#define FreeRDP_SupportHeartbeatPdu 144
#define FreeRDP_DisableEncryption 192 #define FreeRDP_DisableEncryption 192
#define FreeRDP_EncryptionMethods 193 #define FreeRDP_EncryptionMethods 193
#define FreeRDP_ExtEncryptionMethods 194 #define FreeRDP_ExtEncryptionMethods 194
@ -516,6 +548,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_DesktopPosX 390 #define FreeRDP_DesktopPosX 390
#define FreeRDP_DesktopPosY 391 #define FreeRDP_DesktopPosY 391
#define FreeRDP_MultitransportFlags 512 #define FreeRDP_MultitransportFlags 512
#define FreeRDP_SupportMultitransport 513
#define FreeRDP_AlternateShell 640 #define FreeRDP_AlternateShell 640
#define FreeRDP_ShellWorkingDirectory 641 #define FreeRDP_ShellWorkingDirectory 641
#define FreeRDP_AutoLogonEnabled 704 #define FreeRDP_AutoLogonEnabled 704
@ -594,6 +627,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_RdpKeyFile 1412 #define FreeRDP_RdpKeyFile 1412
#define FreeRDP_RdpServerRsaKey 1413 #define FreeRDP_RdpServerRsaKey 1413
#define FreeRDP_RdpServerCertificate 1414 #define FreeRDP_RdpServerCertificate 1414
#define FreeRDP_ExternalCertificateManagement 1415
#define FreeRDP_Workarea 1536 #define FreeRDP_Workarea 1536
#define FreeRDP_Fullscreen 1537 #define FreeRDP_Fullscreen 1537
#define FreeRDP_PercentScreen 1538 #define FreeRDP_PercentScreen 1538
@ -698,6 +732,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_CompDeskSupportLevel 3456 #define FreeRDP_CompDeskSupportLevel 3456
#define FreeRDP_SurfaceCommandsEnabled 3520 #define FreeRDP_SurfaceCommandsEnabled 3520
#define FreeRDP_FrameMarkerCommandEnabled 3521 #define FreeRDP_FrameMarkerCommandEnabled 3521
#define FreeRDP_SurfaceFrameMarkerEnabled 3522
#define FreeRDP_RemoteFxOnly 3648 #define FreeRDP_RemoteFxOnly 3648
#define FreeRDP_RemoteFxCodec 3649 #define FreeRDP_RemoteFxCodec 3649
#define FreeRDP_RemoteFxCodecId 3650 #define FreeRDP_RemoteFxCodecId 3650
@ -786,7 +821,8 @@ struct rdp_settings
ALIGN64 BOOL SupportMonitorLayoutPdu; /* 141 */ ALIGN64 BOOL SupportMonitorLayoutPdu; /* 141 */
ALIGN64 BOOL SupportGraphicsPipeline; /* 142 */ ALIGN64 BOOL SupportGraphicsPipeline; /* 142 */
ALIGN64 BOOL SupportDynamicTimeZone; /* 143 */ ALIGN64 BOOL SupportDynamicTimeZone; /* 143 */
UINT64 padding0192[192 - 143]; /* 143 */ ALIGN64 BOOL SupportHeartbeatPdu; /* 144 */
UINT64 padding0192[192 - 145]; /* 145 */
/* Client/Server Security Data */ /* Client/Server Security Data */
ALIGN64 BOOL DisableEncryption; /* 192 */ ALIGN64 BOOL DisableEncryption; /* 192 */
@ -831,7 +867,8 @@ struct rdp_settings
/* Client Multitransport Channel Data */ /* Client Multitransport Channel Data */
ALIGN64 UINT32 MultitransportFlags; /* 512 */ ALIGN64 UINT32 MultitransportFlags; /* 512 */
UINT64 padding0576[576 - 513]; /* 513 */ ALIGN64 BOOL SupportMultitransport; /* 513 */
UINT64 padding0576[576 - 514]; /* 514 */
UINT64 padding0640[640 - 576]; /* 576 */ UINT64 padding0640[640 - 576]; /* 576 */
/* /*
@ -960,7 +997,8 @@ struct rdp_settings
ALIGN64 char* RdpKeyFile; /* 1412 */ ALIGN64 char* RdpKeyFile; /* 1412 */
ALIGN64 rdpRsaKey* RdpServerRsaKey; /* 1413 */ ALIGN64 rdpRsaKey* RdpServerRsaKey; /* 1413 */
ALIGN64 rdpCertificate* RdpServerCertificate; /* 1414 */ ALIGN64 rdpCertificate* RdpServerCertificate; /* 1414 */
UINT64 padding1472[1472 - 1350]; /* 1415 */ ALIGN64 BOOL ExternalCertificateManagement; /* 1415 */
UINT64 padding1472[1472 - 1416]; /* 1416 */
UINT64 padding1536[1536 - 1472]; /* 1472 */ UINT64 padding1536[1536 - 1472]; /* 1472 */
/** /**
@ -1173,7 +1211,8 @@ struct rdp_settings
/* Surface Commands Capabilities */ /* Surface Commands Capabilities */
ALIGN64 BOOL SurfaceCommandsEnabled; /* 3520 */ ALIGN64 BOOL SurfaceCommandsEnabled; /* 3520 */
ALIGN64 BOOL FrameMarkerCommandEnabled; /* 3521 */ ALIGN64 BOOL FrameMarkerCommandEnabled; /* 3521 */
UINT64 padding3584[3584 - 3522]; /* 3522 */ ALIGN64 BOOL SurfaceFrameMarkerEnabled; /* 3522 */
UINT64 padding3584[3584 - 3523]; /* 3523 */
UINT64 padding3648[3648 - 3584]; /* 3584 */ UINT64 padding3648[3648 - 3584]; /* 3584 */
/* /*

View File

@ -109,7 +109,8 @@ struct _CHANNEL_ENTRY_POINTS_EX
/* Extended Fields */ /* Extended Fields */
UINT32 MagicNumber; /* identifies FreeRDP */ UINT32 MagicNumber; /* identifies FreeRDP */
void* pExtendedData; /* extended initial data */ void* pExtendedData; /* extended initial data */
void** ppInterface; /* channel callback interface */ void* pInterface; /* channel callback interface, use after initialization */
void** ppInterface; /* channel callback interface, use for initialization */
PVIRTUALCHANNELEVENTPUSH pVirtualChannelEventPush; PVIRTUALCHANNELEVENTPUSH pVirtualChannelEventPush;
}; };
typedef struct _CHANNEL_ENTRY_POINTS_EX CHANNEL_ENTRY_POINTS_EX; typedef struct _CHANNEL_ENTRY_POINTS_EX CHANNEL_ENTRY_POINTS_EX;

View File

@ -50,8 +50,8 @@ struct rdp_svc_plugin
HANDLE thread; HANDLE thread;
wStream* data_in; wStream* data_in;
void* init_handle; void* InitHandle;
UINT32 open_handle; UINT32 OpenHandle;
wMessagePipe* MsgPipe; wMessagePipe* MsgPipe;
}; };

View File

@ -65,3 +65,7 @@ if(MONOLITHIC_BUILD)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
endif() endif()
set(FREERDP_PC_LIBS "-lfreerdp -lwinpr")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

View File

@ -22,6 +22,8 @@ set(${MODULE_PREFIX}_SRCS
dsp.c dsp.c
color.c color.c
audio.c audio.c
planar.c
planar.h
bitmap_decode.c bitmap_decode.c
bitmap_encode.c bitmap_encode.c
rfx_bitstream.h rfx_bitstream.h
@ -106,3 +108,8 @@ else()
endif() endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -35,8 +35,36 @@ UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size)
* http://msdn.microsoft.com/en-us/library/ms713497.aspx * http://msdn.microsoft.com/en-us/library/ms713497.aspx
*/ */
if (format->wBitsPerSample)
{
wSamples = (size * 8) / format->wBitsPerSample; wSamples = (size * 8) / format->wBitsPerSample;
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels); mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
}
else
{
mstime = 0;
if (format->wFormatTag == WAVE_FORMAT_GSM610)
{
UINT16 nSamplesPerBlock;
if ((format->cbSize == 2) && (format->data))
{
nSamplesPerBlock = *((UINT16*) format->data);
wSamples = (size / format->nBlockAlign) * nSamplesPerBlock;
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
}
else
{
fprintf(stderr, "rdpsnd_compute_audio_time_length: invalid WAVE_FORMAT_GSM610 format\n");
}
}
else
{
fprintf(stderr, "rdpsnd_compute_audio_time_length: unknown format %d\n", format->wFormatTag);
}
}
return mstime; return mstime;
} }

View File

@ -21,7 +21,11 @@
#include "config.h" #include "config.h"
#endif #endif
#include <winpr/crt.h>
#include <winpr/stream.h> #include <winpr/stream.h>
#include "planar.h"
#include <freerdp/codec/color.h> #include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h> #include <freerdp/codec/bitmap.h>
@ -251,190 +255,6 @@ static UINT32 ExtractRunLength(UINT32 code, BYTE* pbOrderHdr, UINT32* advance)
#define RLEEXTRA #define RLEEXTRA
#include "include/bitmap.c" #include "include/bitmap.c"
#define IN_UINT8_MV(_p) (*((_p)++))
/**
* decompress an RLE color plane
* RDP6_BITMAP_STREAM
*/
static int process_rle_plane(BYTE* in, int width, int height, BYTE* out, int size)
{
int indexw;
int indexh;
int code;
int collen;
int replen;
int color;
int x;
int revcode;
BYTE* last_line;
BYTE* this_line;
BYTE* org_in;
BYTE* org_out;
org_in = in;
org_out = out;
last_line = 0;
indexh = 0;
while (indexh < height)
{
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
color = 0;
this_line = out;
indexw = 0;
if (last_line == 0)
{
while (indexw < width)
{
code = IN_UINT8_MV(in);
replen = code & 0xf;
collen = (code >> 4) & 0xf;
revcode = (replen << 4) | collen;
if ((revcode <= 47) && (revcode >= 16))
{
replen = revcode;
collen = 0;
}
while (collen > 0)
{
color = IN_UINT8_MV(in);
*out = color;
out += 4;
indexw++;
collen--;
}
while (replen > 0)
{
*out = color;
out += 4;
indexw++;
replen--;
}
}
}
else
{
while (indexw < width)
{
code = IN_UINT8_MV(in);
replen = code & 0xf;
collen = (code >> 4) & 0xf;
revcode = (replen << 4) | collen;
if ((revcode <= 47) && (revcode >= 16))
{
replen = revcode;
collen = 0;
}
while (collen > 0)
{
x = IN_UINT8_MV(in);
if (x & 1)
{
x = x >> 1;
x = x + 1;
color = -x;
}
else
{
x = x >> 1;
color = x;
}
x = last_line[indexw * 4] + color;
*out = x;
out += 4;
indexw++;
collen--;
}
while (replen > 0)
{
x = last_line[indexw * 4] + color;
*out = x;
out += 4;
indexw++;
replen--;
}
}
}
indexh++;
last_line = this_line;
}
return (int) (in - org_in);
}
/**
* process a raw color plane
*/
static int process_raw_plane(BYTE* srcData, int width, int height, BYTE* dstData, int size)
{
int x, y;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
dstData[(((height - y - 1) * width) + x) * 4] = srcData[((y * width) + x)];
}
}
return (width * height);
}
/**
* 4 byte bitmap decompress
* RDP6_BITMAP_STREAM
*/
static BOOL bitmap_decompress4(BYTE* srcData, BYTE* dstData, int width, int height, int size)
{
int RLE;
int code;
int NoAlpha;
int bytes_processed;
int total_processed;
code = IN_UINT8_MV(srcData);
RLE = code & 0x10;
total_processed = 1;
NoAlpha = code & 0x20;
if (NoAlpha == 0)
{
bytes_processed = process_rle_plane(srcData, width, height, dstData + 3, size - total_processed);
total_processed += bytes_processed;
srcData += bytes_processed;
}
if (RLE != 0)
{
bytes_processed = process_rle_plane(srcData, width, height, dstData + 2, size - total_processed);
total_processed += bytes_processed;
srcData += bytes_processed;
bytes_processed = process_rle_plane(srcData, width, height, dstData + 1, size - total_processed);
total_processed += bytes_processed;
srcData += bytes_processed;
bytes_processed = process_rle_plane(srcData, width, height, dstData + 0, size - total_processed);
total_processed += bytes_processed;
}
else
{
bytes_processed = process_raw_plane(srcData, width, height, dstData + 2, size - total_processed);
total_processed += bytes_processed;
srcData += bytes_processed;
bytes_processed = process_raw_plane(srcData, width, height, dstData + 1, size - total_processed);
total_processed += bytes_processed;
srcData += bytes_processed;
bytes_processed = process_raw_plane(srcData, width, height, dstData + 0, size - total_processed);
total_processed += bytes_processed + 1;
}
return (size == total_processed) ? TRUE : FALSE;
}
/** /**
* bitmap decompression routine * bitmap decompression routine
*/ */
@ -451,7 +271,7 @@ BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int
} }
else if (srcBpp == 32 && dstBpp == 32) else if (srcBpp == 32 && dstBpp == 32)
{ {
if (!bitmap_decompress4(srcData, dstData, width, height, size)) if (freerdp_bitmap_planar_decompress(srcData, dstData, width, height, size) < 0)
return FALSE; return FALSE;
} }
else if (srcBpp == 15 && dstBpp == 15) else if (srcBpp == 15 && dstBpp == 15)

View File

@ -23,27 +23,9 @@
#include <freerdp/codec/bitmap.h> #include <freerdp/codec/bitmap.h>
#define GETPIXEL8(d, x, y, w) (*(((unsigned char*)d) + ((y) * (w) + (x))))
#define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) #define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x))))
#define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) #define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x))))
/*****************************************************************************/
#define IN_PIXEL8(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \
{ \
if (in_ptr == 0) \
{ \
in_pixel = 0; \
} \
else if (in_x < in_w) \
{ \
in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \
} \
else \
{ \
in_pixel = in_last_pixel; \
} \
}
/*****************************************************************************/ /*****************************************************************************/
#define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ #define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \
{ \ { \
@ -78,35 +60,6 @@
} \ } \
} }
/*****************************************************************************/
/* color */
#define OUT_COLOR_COUNT1(in_count, in_s, in_data) \
{ \
if (in_count > 0) \
{ \
if (in_count < 32) \
{ \
temp = (0x3 << 5) | in_count; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write_UINT8(in_s, in_data); \
} \
else if (in_count < 256 + 32) \
{ \
Stream_Write_UINT8(in_s, 0x60); \
temp = in_count - 32; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write_UINT8(in_s, in_data); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf3); \
Stream_Write_UINT16(in_s, in_count); \
Stream_Write_UINT8(in_s, in_data); \
} \
} \
in_count = 0; \
}
/*****************************************************************************/ /*****************************************************************************/
/* color */ /* color */
#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ #define OUT_COLOR_COUNT2(in_count, in_s, in_data) \
@ -171,36 +124,6 @@
in_count = 0; \ in_count = 0; \
} }
/*****************************************************************************/
/* copy */
#define OUT_COPY_COUNT1(in_count, in_s, in_data) \
{ \
if (in_count > 0) \
{ \
if (in_count < 32) \
{ \
temp = (0x4 << 5) | in_count; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write(in_s, Stream_Buffer(in_data), in_count); \
} \
else if (in_count < 256 + 32) \
{ \
Stream_Write_UINT8(in_s, 0x80); \
temp = in_count - 32; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write(in_s, Stream_Buffer(in_data), in_count); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf4); \
Stream_Write_UINT16(in_s, in_count); \
Stream_Write(in_s, Stream_Buffer(in_data), in_count); \
} \
} \
in_count = 0; \
Stream_SetPosition(in_data, 0); \
}
/*****************************************************************************/ /*****************************************************************************/
/* copy */ /* copy */
#define OUT_COPY_COUNT2(in_count, in_s, in_data) \ #define OUT_COPY_COUNT2(in_count, in_s, in_data) \
@ -267,39 +190,6 @@
Stream_SetPosition(in_data, 0); \ Stream_SetPosition(in_data, 0); \
} }
/*****************************************************************************/
/* bicolor */
#define OUT_BICOLOR_COUNT1(in_count, in_s, in_color1, in_color2) \
{ \
if (in_count > 0) \
{ \
if (in_count / 2 < 16) \
{ \
temp = (0xe << 4) | (in_count / 2); \
Stream_Write_UINT8(in_s, temp); \
Stream_Write_UINT8(in_s, in_color1); \
Stream_Write_UINT8(in_s, in_color2); \
} \
else if (in_count / 2 < 256 + 16) \
{ \
Stream_Write_UINT8(in_s, 0xe0); \
temp = in_count / 2 - 16; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write_UINT8(in_s, in_color1); \
Stream_Write_UINT8(in_s, in_color2); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf8); \
temp = in_count / 2; \
Stream_Write_UINT16(in_s, temp); \
Stream_Write_UINT8(in_s, in_color1); \
Stream_Write_UINT8(in_s, in_color2); \
} \
} \
in_count = 0; \
}
/*****************************************************************************/ /*****************************************************************************/
/* bicolor */ /* bicolor */
#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ #define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \
@ -378,31 +268,6 @@
in_count = 0; \ in_count = 0; \
} }
/*****************************************************************************/
/* fill */
#define OUT_FILL_COUNT1(in_count, in_s) \
{ \
if (in_count > 0) \
{ \
if (in_count < 32) \
{ \
Stream_Write_UINT8(in_s, in_count); \
} \
else if (in_count < 256 + 32) \
{ \
Stream_Write_UINT8(in_s, 0x0); \
temp = in_count - 32; \
Stream_Write_UINT8(in_s, temp); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf0); \
Stream_Write_UINT16(in_s, in_count); \
} \
} \
in_count = 0; \
}
/*****************************************************************************/ /*****************************************************************************/
/* fill */ /* fill */
#define OUT_FILL_COUNT2(in_count, in_s) \ #define OUT_FILL_COUNT2(in_count, in_s) \
@ -453,32 +318,6 @@
in_count = 0; \ in_count = 0; \
} }
/*****************************************************************************/
/* mix */
#define OUT_MIX_COUNT1(in_count, in_s) \
{ \
if (in_count > 0) \
{ \
if (in_count < 32) \
{ \
temp = (0x1 << 5) | in_count; \
Stream_Write_UINT8(in_s, temp); \
} \
else if (in_count < 256 + 32) \
{ \
Stream_Write_UINT8(in_s, 0x20); \
temp = in_count - 32; \
Stream_Write_UINT8(in_s, temp); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf1); \
Stream_Write_UINT16(in_s, in_count); \
} \
} \
in_count = 0; \
}
/*****************************************************************************/ /*****************************************************************************/
/* mix */ /* mix */
#define OUT_MIX_COUNT2(in_count, in_s) \ #define OUT_MIX_COUNT2(in_count, in_s) \
@ -531,35 +370,6 @@
in_count = 0; \ in_count = 0; \
} }
/*****************************************************************************/
/* fom */
#define OUT_FOM_COUNT1(in_count, in_s, in_mask, in_mask_len) \
{ \
if (in_count > 0) \
{ \
if ((in_count % 8) == 0 && in_count < 249) \
{ \
temp = (0x2 << 5) | (in_count / 8); \
Stream_Write_UINT8(in_s, temp); \
Stream_Write(in_s, in_mask, in_mask_len); \
} \
else if (in_count < 256) \
{ \
Stream_Write_UINT8(in_s, 0x40); \
temp = in_count - 1; \
Stream_Write_UINT8(in_s, temp); \
Stream_Write(in_s, in_mask, in_mask_len); \
} \
else \
{ \
Stream_Write_UINT8(in_s, 0xf2); \
Stream_Write_UINT16(in_s, in_count); \
Stream_Write(in_s, in_mask, in_mask_len); \
} \
} \
in_count = 0; \
}
/*****************************************************************************/ /*****************************************************************************/
/* fom */ /* fom */
#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ #define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \
@ -618,7 +428,6 @@
in_count = 0; \ in_count = 0; \
} }
/*****************************************************************************/
#define TEST_FILL \ #define TEST_FILL \
((last_line == 0 && pixel == 0) || \ ((last_line == 0 && pixel == 0) || \
(last_line != 0 && pixel == ypixel)) (last_line != 0 && pixel == ypixel))
@ -646,8 +455,7 @@
bicolor_spin = 0; \ bicolor_spin = 0; \
} }
/*****************************************************************************/ int freerdp_bitmap_compress(char* srcData, int width, int height,
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) wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e)
{ {
char *line; char *line;
@ -691,303 +499,11 @@ int freerdp_bitmap_compress(char* in_data, int width, int height,
mix_count = 0; mix_count = 0;
fom_count = 0; fom_count = 0;
if (bpp == 8) if ((bpp == 15) || (bpp == 16))
{
mix = 0xFF;
out_count = end;
line = in_data + width * start_line;
while (start_line >= 0 && out_count < 32768)
{
i = Stream_GetPosition(s) + count;
if (i - color_count >= byte_limit &&
i - bicolor_count >= byte_limit &&
i - fill_count >= byte_limit &&
i - mix_count >= byte_limit &&
i - fom_count >= byte_limit)
{
break;
}
out_count += end;
for (i = 0; i < end; i++)
{
/* read next pixel */
IN_PIXEL8(line, i, 0, width, last_pixel, pixel);
IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel);
if (!TEST_FILL)
{
if (fill_count > 3 &&
fill_count >= color_count &&
fill_count >= bicolor_count &&
fill_count >= mix_count &&
fill_count >= fom_count)
{
count -= fill_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FILL_COUNT1(fill_count, s);
RESET_COUNTS;
}
fill_count = 0;
}
if (!TEST_MIX)
{
if (mix_count > 3 &&
mix_count >= fill_count &&
mix_count >= bicolor_count &&
mix_count >= color_count &&
mix_count >= fom_count)
{
count -= mix_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_MIX_COUNT1(mix_count, s);
RESET_COUNTS;
}
mix_count = 0;
}
if (!TEST_COLOR)
{
if (color_count > 3 &&
color_count >= fill_count &&
color_count >= bicolor_count &&
color_count >= mix_count &&
color_count >= fom_count)
{
count -= color_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_COLOR_COUNT1(color_count, s, last_pixel);
RESET_COUNTS;
}
color_count = 0;
}
if (!TEST_BICOLOR)
{
if (bicolor_count > 3 &&
bicolor_count >= fill_count &&
bicolor_count >= color_count &&
bicolor_count >= mix_count &&
bicolor_count >= fom_count)
{
if ((bicolor_count % 2) == 0)
{
count -= bicolor_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2);
}
else
{
bicolor_count--;
count -= bicolor_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1);
}
RESET_COUNTS;
}
bicolor_count = 0;
bicolor1 = last_pixel;
bicolor2 = pixel;
bicolor_spin = 0;
}
if (!TEST_FOM)
{
if (fom_count > 3 &&
fom_count >= fill_count &&
fom_count >= color_count &&
fom_count >= mix_count &&
fom_count >= bicolor_count)
{
count -= fom_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len);
RESET_COUNTS;
}
fom_count = 0;
fom_mask_len = 0;
}
if (TEST_FILL)
{
fill_count++;
}
if (TEST_MIX)
{
mix_count++;
}
if (TEST_COLOR)
{
color_count++;
}
if (TEST_BICOLOR)
{
bicolor_spin = !bicolor_spin;
bicolor_count++;
}
if (TEST_FOM)
{
if ((fom_count % 8) == 0)
{
fom_mask[fom_mask_len] = 0;
fom_mask_len++;
}
if (pixel == (ypixel ^ mix))
{
fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8));
}
fom_count++;
}
Stream_Write_UINT8(temp_s, pixel);
count++;
last_pixel = pixel;
last_ypixel = ypixel;
}
/* can't take fix, mix, or fom past first line */
if (last_line == 0)
{
if (fill_count > 3 &&
fill_count >= color_count &&
fill_count >= bicolor_count &&
fill_count >= mix_count &&
fill_count >= fom_count)
{
count -= fill_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FILL_COUNT1(fill_count, s);
RESET_COUNTS;
}
fill_count = 0;
if (mix_count > 3 &&
mix_count >= fill_count &&
mix_count >= bicolor_count &&
mix_count >= color_count &&
mix_count >= fom_count)
{
count -= mix_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_MIX_COUNT1(mix_count, s);
RESET_COUNTS;
}
mix_count = 0;
if (fom_count > 3 &&
fom_count >= fill_count &&
fom_count >= color_count &&
fom_count >= mix_count &&
fom_count >= bicolor_count)
{
count -= fom_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len);
RESET_COUNTS;
}
fom_count = 0;
fom_mask_len = 0;
}
last_line = line;
line = line - width;
start_line--;
lines_sent++;
}
if (fill_count > 3 &&
fill_count >= color_count &&
fill_count >= bicolor_count &&
fill_count >= mix_count &&
fill_count >= fom_count)
{
count -= fill_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FILL_COUNT1(fill_count, s);
}
else if (mix_count > 3 &&
mix_count >= color_count &&
mix_count >= bicolor_count &&
mix_count >= fill_count &&
mix_count >= fom_count)
{
count -= mix_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_MIX_COUNT1(mix_count, s);
}
else if (color_count > 3 &&
color_count >= mix_count &&
color_count >= bicolor_count &&
color_count >= fill_count &&
color_count >= fom_count)
{
count -= color_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_COLOR_COUNT1(color_count, s, last_pixel);
}
else if (bicolor_count > 3 &&
bicolor_count >= mix_count &&
bicolor_count >= color_count &&
bicolor_count >= fill_count &&
bicolor_count >= fom_count)
{
if ((bicolor_count % 2) == 0)
{
count -= bicolor_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2);
}
else
{
bicolor_count--;
count -= bicolor_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1);
}
count -= bicolor_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2);
}
else if (fom_count > 3 &&
fom_count >= mix_count &&
fom_count >= color_count &&
fom_count >= fill_count &&
fom_count >= bicolor_count)
{
count -= fom_count;
OUT_COPY_COUNT1(count, s, temp_s);
OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len);
}
else
{
OUT_COPY_COUNT1(count, s, temp_s);
}
}
else if ((bpp == 15) || (bpp == 16))
{ {
mix = (bpp == 15) ? 0xBA1F : 0xFFFF; mix = (bpp == 15) ? 0xBA1F : 0xFFFF;
out_count = end * 2; out_count = end * 2;
line = in_data + width * start_line * 2; line = srcData + width * start_line * 2;
while (start_line >= 0 && out_count < 32768) while (start_line >= 0 && out_count < 32768)
{ {
@ -1279,7 +795,7 @@ int freerdp_bitmap_compress(char* in_data, int width, int height,
{ {
mix = 0xFFFFFF; mix = 0xFFFFFF;
out_count = end * 3; out_count = end * 3;
line = in_data + width * start_line * 4; line = srcData + width * start_line * 4;
while (start_line >= 0 && out_count < 32768) while (start_line >= 0 && out_count < 32768)
{ {
@ -1572,153 +1088,3 @@ int freerdp_bitmap_compress(char* in_data, int width, int height,
return lines_sent; return lines_sent;
} }
/**
* RDP6 Bitmap Test Case ([MS-RDPEGDI])
*/
const BYTE TEST_RDP6_COMPRESSED_BITMAP[220] =
"\x85\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x06\x8B\x99\xD6\x99"
"\xD6\x99\xD6\x10\x84\x08\x42\x08\x42\x10\x84\x99\xD6\x99\xD6\x99"
"\xD6\x99\xD6\x06\x84\x99\xD6\x99\xD6\x99\xD6\xFF\xFF\x16\x69\x99"
"\xD6\x06\x69\x99\xD6\x04\xCC\x89\x52\x03\x6E\xFF\xFF\x02\x6E\x08"
"\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18\xC6\x01\x81\x08\x42\xCE"
"\x66\x29\x02\xCD\x89\x52\x03\x88\x10\x84\x99\xD6\x99\xD6\x99\xD6"
"\x00\x00\x00\x00\x00\x00\x00\x00\xD8\x99\xD6\x03\xF8\x01\x00\x00"
"\x00\x00\xF0\x66\x99\xD6\x05\x6A\x99\xD6\x00\xC4\xCC\x89\x52\x03"
"\x6E\xFF\xFF\x02\x6E\x08\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18"
"\xC6\x01\x81\x08\x42\xCE\x66\x29\x02\xCD\x89\x52\x03\x00\x04\xD6"
"\x99\xD6\xC3\x80\x61\x00\xA5\x80\x40\xEC\x52\x00\x5A\x00\x2D\x00"
"\x24\x00\x12\x00\x24\x00\x12\x00\x5A\x00\x2D\x00\xA5\x80\x52\x00"
"\xC3\x80\x61\x00\x00\x00\x00\x00\xCC\x89\x52\x03\x6E\xFF\xFF\x02"
"\xCB\x18\xC6\x84\x08\x42\x08\x42\x08\x42\xFF\xFF";
const BYTE TEST_RDP6_UNCOMPRESSED_BITMAP[2048] =
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42"
"\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42"
"\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00"
"\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF"
"\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6"
"\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42"
"\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84"
"\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42"
"\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF";

860
libfreerdp/codec/planar.c Normal file
View File

@ -0,0 +1,860 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP6 Planar Codec
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/print.h>
#include <freerdp/codec/bitmap.h>
#include "planar.h"
static int freerdp_bitmap_planar_decompress_plane_rle(BYTE* inPlane, int width, int height, BYTE* outPlane, int srcSize)
{
int k;
int x, y;
BYTE* srcp;
BYTE* dstp;
UINT32 pixel;
int scanline;
int cRawBytes;
int nRunLength;
int deltaValue;
BYTE controlByte;
BYTE* currentScanline;
BYTE* previousScanline;
k = 0;
srcp = inPlane;
dstp = outPlane;
scanline = width * 4;
previousScanline = NULL;
y = 0;
while (y < height)
{
pixel = 0;
dstp = (outPlane + height * scanline) - ((y + 1) * scanline);
currentScanline = dstp;
x = 0;
while (x < width)
{
controlByte = *srcp;
srcp++;
if ((srcp - inPlane) > srcSize)
{
printf("freerdp_bitmap_planar_decompress_plane_rle: error reading input buffer\n");
return -1;
}
nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
//printf("CONTROL(%d, %d)\n", cRawBytes, nRunLength);
if (nRunLength == 1)
{
nRunLength = cRawBytes + 16;
cRawBytes = 0;
}
else if (nRunLength == 2)
{
nRunLength = cRawBytes + 32;
cRawBytes = 0;
}
#if 0
printf("y: %d cRawBytes: %d nRunLength: %d\n", y, cRawBytes, nRunLength);
printf("RAW[");
for (k = 0; k < cRawBytes; k++)
{
printf("0x%02X%s", srcp[k],
((k + 1) == cRawBytes) ? "" : ", ");
}
printf("] RUN[%d]\n", nRunLength);
#endif
if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > width * 4)
{
printf("freerdp_bitmap_planar_decompress_plane_rle: too many pixels in scanline\n");
return -1;
}
if (!previousScanline)
{
/* first scanline, absolute values */
while (cRawBytes > 0)
{
pixel = *srcp;
srcp++;
*dstp = pixel;
dstp += 4;
x++;
cRawBytes--;
}
while (nRunLength > 0)
{
*dstp = pixel;
dstp += 4;
x++;
nRunLength--;
}
}
else
{
/* delta values relative to previous scanline */
while (cRawBytes > 0)
{
deltaValue = *srcp;
srcp++;
if (deltaValue & 1)
{
deltaValue = deltaValue >> 1;
deltaValue = deltaValue + 1;
pixel = -deltaValue;
}
else
{
deltaValue = deltaValue >> 1;
pixel = deltaValue;
}
deltaValue = previousScanline[x * 4] + pixel;
*dstp = deltaValue;
dstp += 4;
x++;
cRawBytes--;
}
while (nRunLength > 0)
{
deltaValue = previousScanline[x * 4] + pixel;
*dstp = deltaValue;
dstp += 4;
x++;
nRunLength--;
}
}
}
previousScanline = currentScanline;
y++;
}
return (int) (srcp - inPlane);
}
static int freerdp_bitmap_planar_decompress_plane_raw(BYTE* srcData, int width, int height, BYTE* dstData, int size)
{
int x, y;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
dstData[(((height - y - 1) * width) + x) * 4] = srcData[((y * width) + x)];
}
}
return (width * height);
}
int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size)
{
BYTE* srcp;
int dstSize;
BYTE FormatHeader;
srcp = srcData;
FormatHeader = *srcp;
srcp++;
/* AlphaPlane */
if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
{
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
dstSize = freerdp_bitmap_planar_decompress_plane_rle(srcp, width, height, dstData + 3, size - (srcp - srcData));
if (dstSize < 0)
return -1;
srcp += dstSize;
}
else
{
dstSize = freerdp_bitmap_planar_decompress_plane_raw(srcp, width, height, dstData + 3, size - (srcp - srcData));
srcp += dstSize;
}
}
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
/* LumaOrRedPlane */
dstSize = freerdp_bitmap_planar_decompress_plane_rle(srcp, width, height, dstData + 2, size - (srcp - srcData));
if (dstSize < 0)
return -1;
srcp += dstSize;
/* OrangeChromaOrGreenPlane */
dstSize = freerdp_bitmap_planar_decompress_plane_rle(srcp, width, height, dstData + 1, size - (srcp - srcData));
if (dstSize < 0)
return -1;
srcp += dstSize;
/* GreenChromeOrBluePlane */
dstSize = freerdp_bitmap_planar_decompress_plane_rle(srcp, width, height, dstData + 0, size - (srcp - srcData));
if (dstSize < 0)
return -1;
srcp += dstSize;
}
else
{
/* LumaOrRedPlane */
dstSize = freerdp_bitmap_planar_decompress_plane_raw(srcp, width, height, dstData + 2, size - (srcp - srcData));
srcp += dstSize;
/* OrangeChromaOrGreenPlane */
dstSize = freerdp_bitmap_planar_decompress_plane_raw(srcp, width, height, dstData + 1, size - (srcp - srcData));
srcp += dstSize;
/* GreenChromeOrBluePlane */
dstSize = freerdp_bitmap_planar_decompress_plane_raw(srcp, width, height, dstData + 0, size - (srcp - srcData));
srcp += dstSize;
srcp++;
}
return (size == (srcp - srcData)) ? 0 : -1;
}
int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4])
{
int bpp;
int i, j, k;
k = 0;
bpp = FREERDP_PIXEL_FORMAT_BPP(format);
if (bpp == 32)
{
UINT32* pixel;
for (i = height - 1; i >= 0; i--)
{
pixel = (UINT32*) &data[scanline * i];
for (j = 0; j < width; j++)
{
GetARGB32(planes[0][k], planes[1][k], planes[2][k], planes[3][k], *pixel);
pixel++;
k++;
}
}
}
else if (bpp == 24)
{
UINT32* pixel;
for (i = height - 1; i >= 0; i--)
{
pixel = (UINT32*) &data[scanline * i];
for (j = 0; j < width; j++)
{
GetRGB32(planes[1][k], planes[2][k], planes[3][k], *pixel);
planes[0][k] = 0xFF; /* A */
pixel++;
k++;
}
}
}
return 0;
}
int freerdp_bitmap_planar_write_rle_bytes(BYTE* pInBuffer, int cRawBytes, int nRunLength, BYTE* pOutBuffer, int outBufferSize)
{
BYTE* pInput;
BYTE* pOutput;
BYTE controlByte;
int nBytesToWrite;
pInput = pInBuffer;
pOutput = pOutBuffer;
if (!cRawBytes && !nRunLength)
return 0;
if (nRunLength < 3)
{
cRawBytes += nRunLength;
nRunLength = 0;
}
while (cRawBytes)
{
if (cRawBytes < 16)
{
if (nRunLength > 15)
{
if (nRunLength < 18)
{
controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
nRunLength -= 13;
cRawBytes = 0;
}
else
{
controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
nRunLength -= 15;
cRawBytes = 0;
}
}
else
{
controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
nRunLength = 0;
cRawBytes = 0;
}
}
else
{
controlByte = PLANAR_CONTROL_BYTE(0, 15);
cRawBytes -= 15;
}
if (outBufferSize < 1)
return 0;
outBufferSize--;
*pOutput = controlByte;
pOutput++;
nBytesToWrite = (int) (controlByte >> 4);
if (nBytesToWrite)
{
if (outBufferSize < nBytesToWrite)
return 0;
outBufferSize -= nBytesToWrite;
CopyMemory(pOutput, pInput, nBytesToWrite);
pOutput += nBytesToWrite;
pInput += nBytesToWrite;
}
}
while (nRunLength)
{
if (nRunLength > 47)
{
if (nRunLength < 50)
{
controlByte = PLANAR_CONTROL_BYTE(2, 13);
nRunLength -= 45;
}
else
{
controlByte = PLANAR_CONTROL_BYTE(2, 15);
nRunLength -= 47;
}
}
else if (nRunLength > 31)
{
controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
nRunLength = 0;
}
else if (nRunLength > 15)
{
controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
nRunLength = 0;
}
else
{
controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
nRunLength = 0;
}
if (outBufferSize < 1)
return 0;
--outBufferSize;
*pOutput = controlByte;
pOutput++;
}
return (pOutput - pOutBuffer);
}
int freerdp_bitmap_planar_encode_rle_bytes(BYTE* pInBuffer, int inBufferSize, BYTE* pOutBuffer, int outBufferSize)
{
BYTE symbol;
BYTE* pInput;
BYTE* pOutput;
BYTE* pBytes;
int cRawBytes;
int nRunLength;
int bSymbolMatch;
int nBytesWritten;
int nTotalBytesWritten;
symbol = 0;
cRawBytes = 0;
nRunLength = 0;
pInput = pInBuffer;
pOutput = pOutBuffer;
nTotalBytesWritten = 0;
if (!outBufferSize)
return 0;
do
{
if (!inBufferSize)
break;
bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
symbol = *pInput;
pInput++;
inBufferSize--;
if (nRunLength && !bSymbolMatch)
{
if (nRunLength < 3)
{
cRawBytes += nRunLength;
nRunLength = 0;
}
else
{
pBytes = pInput - (cRawBytes + nRunLength + 1);
nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes,
cRawBytes, nRunLength, pOutput, outBufferSize);
nRunLength = 0;
if (!nBytesWritten || (nBytesWritten > outBufferSize))
return nRunLength;
nTotalBytesWritten += nBytesWritten;
outBufferSize -= nBytesWritten;
pOutput += nBytesWritten;
cRawBytes = 0;
}
}
nRunLength += bSymbolMatch;
cRawBytes += (!bSymbolMatch) ? TRUE : FALSE;
}
while (outBufferSize);
if (cRawBytes || nRunLength)
{
pBytes = pInput - (cRawBytes + nRunLength);
nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes,
cRawBytes, nRunLength, pOutput, outBufferSize);
if (!nBytesWritten)
return 0;
nTotalBytesWritten += nBytesWritten;
}
if (inBufferSize)
return 0;
return nTotalBytesWritten;
}
BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* inPlane, int width, int height, BYTE* outPlane, int* dstSize)
{
int index;
BYTE* pInput;
BYTE* pOutput;
int outBufferSize;
int nBytesWritten;
int nTotalBytesWritten;
if (!outPlane)
{
outBufferSize = width * height;
outPlane = malloc(outBufferSize);
}
else
{
outBufferSize = *dstSize;
}
index = 0;
pInput = inPlane;
pOutput = outPlane;
nTotalBytesWritten = 0;
while (outBufferSize)
{
nBytesWritten = freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
return NULL;
outBufferSize -= nBytesWritten;
nTotalBytesWritten += nBytesWritten;
pOutput += nBytesWritten;
pInput += width;
index++;
if (index >= height)
break;
}
*dstSize = nTotalBytesWritten;
return outPlane;
}
int freerdp_bitmap_planar_compress_planes_rle(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes, int* dstSizes, BOOL skipAlpha)
{
int outPlanesSize = width * height * 4;
/* AlphaPlane */
if (skipAlpha)
{
dstSizes[0] = 0;
}
else
{
dstSizes[0] = outPlanesSize;
if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes, &dstSizes[0]))
return 0;
outPlanes += dstSizes[0];
outPlanesSize -= dstSizes[0];
}
/* LumaOrRedPlane */
dstSizes[1] = outPlanesSize;
if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes, &dstSizes[1]))
return 0;
outPlanes += dstSizes[1];
outPlanesSize -= dstSizes[1];
/* OrangeChromaOrGreenPlane */
dstSizes[2] = outPlanesSize;
if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes, &dstSizes[2]))
return 0;
outPlanes += dstSizes[2];
outPlanesSize -= dstSizes[2];
/* GreenChromeOrBluePlane */
dstSizes[3] = outPlanesSize;
if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes, &dstSizes[3]))
return 0;
outPlanes += dstSizes[3];
outPlanesSize -= dstSizes[3];
return 1;
}
BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane)
{
char s2c;
int delta;
int y, x;
BYTE *outPtr, *srcPtr, *prevLinePtr;
if (!outPlane)
outPlane = (BYTE*) malloc(width * height);
// first line is copied as is
CopyMemory(outPlane, inPlane, width);
outPtr = outPlane + width;
srcPtr = inPlane + width;
prevLinePtr = inPlane;
for (y = 1; y < height; y++)
{
for (x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
{
delta = *srcPtr - *prevLinePtr;
s2c = (delta >= 0) ? (char) delta : (char) (~((BYTE) (-delta)) + 1);
s2c = (s2c >= 0) ? (s2c << 1) : (char) (((~((BYTE) s2c) + 1) << 1) - 1);
*outPtr = (BYTE)s2c;
}
}
return outPlane;
}
int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4])
{
freerdp_bitmap_planar_delta_encode_plane(inPlanes[0], width, height, outPlanes[0]);
freerdp_bitmap_planar_delta_encode_plane(inPlanes[1], width, height, outPlanes[1]);
freerdp_bitmap_planar_delta_encode_plane(inPlanes[2], width, height, outPlanes[2]);
freerdp_bitmap_planar_delta_encode_plane(inPlanes[3], width, height, outPlanes[3]);
return 0;
}
BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format,
int width, int height, int scanline, BYTE* dstData, int* dstSize)
{
int size;
BYTE* dstp;
int planeSize;
int dstSizes[4];
BYTE FormatHeader = 0;
if (context->AllowSkipAlpha)
FormatHeader |= PLANAR_FORMAT_HEADER_NA;
planeSize = width * height;
freerdp_split_color_planes(data, format, width, height, scanline, context->planes);
if (context->AllowRunLengthEncoding)
{
freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height, context->deltaPlanes);
if (freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
context->rlePlanesBuffer, (int*) &dstSizes, context->AllowSkipAlpha) > 0)
{
int offset = 0;
FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
offset += dstSizes[0];
context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
offset += dstSizes[1];
context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
offset += dstSizes[2];
context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
offset += dstSizes[3];
//printf("R: [%d/%d] G: [%d/%d] B: [%d/%d]\n",
// dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
}
}
if (!dstData)
{
size = 1;
if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
{
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
size += dstSizes[0];
else
size += planeSize;
}
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
else
size += (planeSize * 3);
if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
size++;
dstData = malloc(size);
*dstSize = size;
}
dstp = dstData;
*dstp = FormatHeader; /* FormatHeader */
dstp++;
/* AlphaPlane */
if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
{
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]); /* Alpha */
dstp += dstSizes[0];
}
else
{
CopyMemory(dstp, context->planes[0], planeSize); /* Alpha */
dstp += planeSize;
}
}
/* LumaOrRedPlane */
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]); /* Red */
dstp += dstSizes[1];
}
else
{
CopyMemory(dstp, context->planes[1], planeSize); /* Red */
dstp += planeSize;
}
/* OrangeChromaOrGreenPlane */
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]); /* Green */
dstp += dstSizes[2];
}
else
{
CopyMemory(dstp, context->planes[2], planeSize); /* Green */
dstp += planeSize;
}
/* GreenChromeOrBluePlane */
if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
{
CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]); /* Blue */
dstp += dstSizes[3];
}
else
{
CopyMemory(dstp, context->planes[3], planeSize); /* Blue */
dstp += planeSize;
}
/* Pad1 (1 byte) */
if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
{
*dstp = 0;
dstp++;
}
size = (dstp - dstData);
*dstSize = size;
return dstData;
}
BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight)
{
BITMAP_PLANAR_CONTEXT* context;
context = (BITMAP_PLANAR_CONTEXT*) malloc(sizeof(BITMAP_PLANAR_CONTEXT));
if (!context)
return NULL;
ZeroMemory(context, sizeof(BITMAP_PLANAR_CONTEXT));
if (flags & PLANAR_FORMAT_HEADER_NA)
context->AllowSkipAlpha = TRUE;
if (flags & PLANAR_FORMAT_HEADER_RLE)
context->AllowRunLengthEncoding = TRUE;
if (flags & PLANAR_FORMAT_HEADER_CS)
context->AllowColorSubsampling = TRUE;
context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
if (context->ColorLossLevel)
context->AllowDynamicColorFidelity = TRUE;
context->maxWidth = maxWidth;
context->maxHeight = maxHeight;
context->maxPlaneSize = context->maxWidth * context->maxHeight;
context->planesBuffer = malloc(context->maxPlaneSize * 4);
context->planes[0] = &context->planesBuffer[context->maxPlaneSize * 0];
context->planes[1] = &context->planesBuffer[context->maxPlaneSize * 1];
context->planes[2] = &context->planesBuffer[context->maxPlaneSize * 2];
context->planes[3] = &context->planesBuffer[context->maxPlaneSize * 3];
context->deltaPlanesBuffer = malloc(context->maxPlaneSize * 4);
context->deltaPlanes[0] = &context->deltaPlanesBuffer[context->maxPlaneSize * 0];
context->deltaPlanes[1] = &context->deltaPlanesBuffer[context->maxPlaneSize * 1];
context->deltaPlanes[2] = &context->deltaPlanesBuffer[context->maxPlaneSize * 2];
context->deltaPlanes[3] = &context->deltaPlanesBuffer[context->maxPlaneSize * 3];
context->rlePlanesBuffer = malloc(context->maxPlaneSize * 4);
return context;
}
void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
{
if (!context)
return;
free(context->planesBuffer);
free(context->deltaPlanesBuffer);
free(context->rlePlanesBuffer);
free(context);
}

97
libfreerdp/codec/planar.h Normal file
View File

@ -0,0 +1,97 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP6 Planar Codec
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CODEC_PLANAR_PRIVATE_H
#define FREERDP_CODEC_PLANAR_PRIVATE_H
#include <winpr/crt.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#define PLANAR_CONTROL_BYTE(_nRunLength, _cRawBytes) \
(_nRunLength & 0x0F) | ((_cRawBytes & 0x0F) << 4)
#define PLANAR_CONTROL_BYTE_RUN_LENGTH(_controlByte) (_controlByte & 0x0F)
#define PLANAR_CONTROL_BYTE_RAW_BYTES(_controlByte) ((_controlByte >> 4) & 0x0F)
struct _RDP6_RLE_SEGMENT
{
/**
* controlByte:
* [0-3]: nRunLength
* [4-7]: cRawBytes
*/
BYTE controlByte;
BYTE* rawValues;
};
typedef struct _RDP6_RLE_SEGMENT RDP6_RLE_SEGMENT;
struct _RDP6_RLE_SEGMENTS
{
UINT32 cSegments;
RDP6_RLE_SEGMENT* segments;
};
typedef struct _RDP6_RLE_SEGMENTS RDP6_RLE_SEGMENTS;
struct _RDP6_BITMAP_STREAM
{
/**
* formatHeader:
* [0-2]: Color Loss Level (CLL)
* [3] : Chroma Subsampling (CS)
* [4] : Run Length Encoding (RLE)
* [5] : No Alpha (NA)
* [6-7]: Reserved
*/
BYTE formatHeader;
};
typedef struct _RDP6_BITMAP_STREAM RDP6_BITMAP_STREAM;
struct _BITMAP_PLANAR_CONTEXT
{
int maxWidth;
int maxHeight;
int maxPlaneSize;
BOOL AllowSkipAlpha;
BOOL AllowRunLengthEncoding;
BOOL AllowColorSubsampling;
BOOL AllowDynamicColorFidelity;
int ColorLossLevel;
BYTE* planes[4];
BYTE* planesBuffer;
BYTE* deltaPlanes[4];
BYTE* deltaPlanesBuffer;
BYTE* rlePlanes[4];
BYTE* rlePlanesBuffer;
};
int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size);
int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]);
BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int width, int height, BYTE* outPlane, int* dstSize);
BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane);
int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */

3
libfreerdp/codec/test/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
TestFreeRDPCodec
TestFreeRDPCodec.c

View File

@ -0,0 +1,32 @@
set(MODULE_NAME "TestFreeRDPCodec")
set(MODULE_PREFIX "TEST_FREERDP_CODEC")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestFreeRDPCodecMppc.c
TestFreeRDPCodecPlanar.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})
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})
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/Test")

View File

@ -0,0 +1,684 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/mppc_dec.h>
#include <freerdp/codec/mppc_enc.h>
static BYTE TEST_RDP5_COMPRESSED_DATA[] =
{
0x24, 0x02, 0x03, 0x09, 0x00, 0x20, 0x0c, 0x05, 0x10, 0x01, 0x40, 0x0a, 0xbf, 0xdf, 0xc3, 0x20,
0x80, 0x00, 0x1f, 0x0a, 0x00, 0x00, 0x07, 0x43, 0x4e, 0x00, 0x68, 0x02, 0x00, 0x22, 0x00, 0x34,
0xcb, 0xfb, 0xf8, 0x18, 0x40, 0x01, 0x00, 0x27, 0xe2, 0x90, 0x0f, 0xc3, 0x91, 0xa8, 0x00, 0x08,
0x00, 0x00, 0x68, 0x50, 0x60, 0x65, 0xfc, 0x0e, 0xfe, 0x04, 0x00, 0x08, 0x00, 0x06, 0x0c, 0x00,
0x01, 0x00, 0xf8, 0x40, 0x20, 0x00, 0x00, 0x90, 0x00, 0xcf, 0x95, 0x1f, 0x44, 0x90, 0x00, 0x6e,
0x03, 0xf4, 0x40, 0x21, 0x9f, 0x26, 0x01, 0xbf, 0x88, 0x10, 0x90, 0x00, 0x08, 0x04, 0x00, 0x04,
0x30, 0x03, 0xe4, 0xc7, 0xea, 0x05, 0x1e, 0x87, 0xf8, 0x20, 0x1c, 0x00, 0x10, 0x84, 0x22, 0x1f,
0x71, 0x0d, 0x0e, 0xb9, 0x88, 0x9f, 0x5c, 0xee, 0x41, 0x97, 0xfb, 0xf8, 0x88, 0x68, 0x08, 0x6d,
0xd0, 0x44, 0xfc, 0x34, 0x06, 0xe6, 0x16, 0x21, 0x04, 0x11, 0x0f, 0xb9, 0x85, 0x86, 0x5d, 0x44,
0x4f, 0xae, 0xb7, 0x40, 0xa8, 0xcd, 0x5b, 0xed, 0x02, 0xee, 0xc2, 0x21, 0x40, 0x21, 0x21, 0x23,
0x17, 0xb7, 0x00, 0x60, 0x00, 0x3b, 0xfd, 0xfc, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x34, 0x00, 0x33,
0xc7, 0xe0, 0xc0, 0x0f, 0x07, 0x12, 0x42, 0x01, 0xe8, 0x6c, 0xc7, 0x83, 0x07, 0x8c, 0xd4, 0x30,
0x07, 0x20, 0x01, 0x90, 0xa3, 0xf1, 0xdb, 0xf5, 0xd4, 0x13, 0xc2, 0x4f, 0x0f, 0xe5, 0xe2, 0xc7,
0x87, 0xf2, 0xf0, 0x93, 0xc3, 0xf9, 0x78, 0xb0, 0x1a, 0x03, 0xe1, 0xf1, 0xd0, 0x08, 0x4c, 0x66,
0xac, 0x32, 0x31, 0x70, 0x60, 0x11, 0x01, 0x11, 0x01, 0x01, 0x01, 0xf0, 0x36, 0x1f, 0xe5, 0xe0,
0x6c, 0xbc, 0x26, 0xf0, 0x36, 0x5f, 0xe5, 0xe0, 0x6c, 0xbc, 0x26, 0xf0, 0x34, 0xf9, 0x94, 0x32,
0x31, 0x74, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xbf, 0x87, 0xdf, 0xef, 0xfe, 0x4b, 0xbf, 0x02, 0xfa,
0xde, 0xa7, 0x79, 0x32, 0x44, 0x7c, 0x20, 0x82, 0x00, 0x5f, 0xef, 0xff, 0x09, 0xe1, 0x05, 0x74,
0x32, 0xea, 0x09, 0xe1, 0x0f, 0x55, 0x83, 0x85, 0x2a, 0xa0, 0x1d, 0x50, 0x0e, 0x0e, 0x0b, 0x01,
0x01, 0x43, 0x06, 0x02, 0xbe, 0x5f, 0x00, 0x00, 0x0c, 0x3d, 0x4d, 0x87, 0xa6, 0x5e, 0xa6, 0xcb,
0xc3, 0xcf, 0x53, 0x65, 0xe9, 0x97, 0xa9, 0xb2, 0xf5, 0x9b, 0xd4, 0xd3, 0xee, 0xcd, 0xc0, 0x7c,
0xae, 0xe0, 0x65, 0x1f, 0xe5, 0xe0, 0x6c, 0xbc, 0x26, 0xf0, 0x36, 0x5f, 0xe5, 0xe0, 0x6c, 0xbc,
0x26, 0xf0, 0x34, 0xfb, 0xb3, 0xf2, 0x41, 0x30, 0x20, 0x04, 0xa0, 0x80, 0x93, 0xf3, 0xf2, 0x1b,
0xed, 0xf6, 0x0f, 0x04, 0x82, 0x7b, 0xcc, 0x00, 0x65, 0xef, 0x4f, 0x86, 0x02, 0xf7, 0xa7, 0xe0,
0x0a, 0x88, 0x1c, 0x34, 0x02, 0x02, 0x02, 0x60, 0x60, 0x49, 0x40, 0xc1, 0x2f, 0x14, 0xca, 0x60,
0xc1, 0x81, 0x80, 0x07, 0xc3, 0x00, 0x00, 0x39, 0xfa, 0x86, 0x38, 0x93, 0x47, 0x08, 0x27, 0x08,
0xfc, 0xb8, 0x4e, 0x38, 0x47, 0xe5, 0xc2, 0x09, 0xc2, 0x3f, 0x2e, 0x13, 0x8e, 0x11, 0xf3, 0xc3,
0x57, 0x1a, 0x88, 0x7d, 0x44, 0x3c, 0x3c, 0x04, 0x0f, 0xd4, 0x3f, 0x83, 0x8d, 0x82, 0x00, 0x25,
0x04, 0x84, 0xdf, 0xe0, 0x17, 0xf8, 0x04, 0x03, 0xe1, 0x47, 0xc4, 0xaf, 0x9c, 0x00, 0x00, 0x31,
0xf5, 0x4c, 0x71, 0x78, 0x8f, 0x54, 0xfb, 0x1c, 0x97, 0xa4, 0x04, 0x13, 0xd5, 0x2f, 0x77, 0xc7,
0xb8, 0x9e, 0xef, 0xcb, 0xc2, 0x6f, 0x77, 0xe5, 0xee, 0x27, 0xbb, 0xf2, 0xf7, 0xe3, 0xdd, 0xf3,
0xc6, 0xfb, 0x2a, 0x78, 0x6d, 0x3c, 0x34, 0x37, 0xc0, 0xaf, 0x25, 0xc7, 0x81, 0x7d, 0x6e, 0x5d,
0x5c, 0xd6, 0xe3, 0x43, 0xc0, 0x82, 0xd0, 0x95, 0x90, 0xd8, 0xbd, 0xfc, 0x00, 0x09, 0xc0, 0x34,
0x39, 0x46, 0x84, 0x20, 0x40, 0x38, 0xa3, 0x42, 0x12, 0xb0, 0x55, 0xbe, 0x28, 0xc0, 0x70, 0x64,
0x28, 0xc8, 0x48, 0x42, 0x08, 0xb2, 0x1b, 0x46, 0xa6, 0x09, 0x54, 0x2e, 0x5f, 0x73, 0x84, 0xfc,
0x28, 0x4a, 0x73, 0x79, 0xf2, 0x6c, 0x5d, 0x82, 0x82, 0x6e, 0xc2, 0x27, 0xd7, 0x6b, 0xb8, 0x4f,
0xa4, 0xa4, 0x22, 0xee, 0x22, 0x7e, 0x10, 0x03, 0x78, 0x08, 0xf4, 0x94, 0x5e, 0x02, 0x01, 0xef,
0x02, 0x27, 0xd7, 0x8b, 0xc8, 0x3f, 0xa4, 0xa4, 0x1a, 0xf3, 0xd1, 0x84, 0x0c, 0x32, 0x31, 0x75,
0x60, 0x05, 0xe2, 0x30, 0xb7, 0xad, 0x5b, 0x15, 0xd5, 0xc3, 0xc0, 0x00, 0x11, 0x81, 0x81, 0x69,
0x8f, 0x06, 0x0f, 0x14, 0xcf, 0xa6, 0xe8, 0xb1, 0x22, 0x77, 0xeb, 0xd7, 0x45, 0x89, 0xf0, 0xb6,
0x3e, 0x23, 0x06, 0x80, 0xf8, 0x5b, 0x0f, 0x04, 0x83, 0xfc, 0x2d, 0x8f, 0x88, 0xc1, 0xa0, 0x3e,
0x16, 0x1d, 0x00, 0x83, 0x74, 0x58, 0xa0, 0xc0, 0x10, 0xce, 0x8b, 0x17, 0xe0, 0x68, 0xff, 0x20,
0xff, 0x03, 0x63, 0xe5, 0xcf, 0x1f, 0xa0, 0x40, 0x00, 0x00, 0x2a, 0xff, 0xd6, 0xd1, 0xc0, 0xb9,
0xe0, 0x5f, 0x6b, 0x81, 0x73, 0xc9, 0x93, 0xd1, 0x63, 0x50, 0xf0, 0x9b, 0xf0, 0x48, 0x4f, 0xaf,
0xe0, 0x1b, 0xef, 0x82, 0x6f, 0xc2, 0x40, 0xe0, 0xe4, 0x60, 0xa0, 0x69, 0xa1, 0xa1, 0xbe, 0xba,
0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x42, 0x00, 0x44, 0x00, 0x88, 0x01, 0x10, 0x02,
0x21, 0x02, 0x22, 0x04, 0x44, 0x08, 0x9c, 0x8f, 0xcd, 0xe0, 0x02, 0x20, 0x88, 0x02, 0x10, 0x40,
0x01, 0xf0, 0x60, 0x44, 0xc0, 0xce, 0xb1, 0x8f, 0xd0, 0x30, 0x00, 0x60, 0x00, 0xa0, 0x00, 0xc4,
0x00, 0xcc, 0x01, 0x98, 0x03, 0x28, 0x03, 0x31, 0x03, 0x33, 0x06, 0x66, 0x07, 0x0e, 0x2c, 0xe3,
0x7b, 0x18, 0x85, 0xc7, 0xd6, 0x51, 0x71, 0x0f, 0x0e, 0xb8, 0x88, 0x9f, 0x5c, 0x6e, 0x41, 0xde,
0xeb, 0x71, 0x20, 0x5c, 0xba, 0xf7, 0xc8, 0x6f, 0xba, 0xc1, 0xf7, 0x30, 0xd0, 0xce, 0xc1, 0x31,
0x74, 0xec, 0x13, 0x41, 0x77, 0x41, 0x13, 0xa0, 0x10, 0xbf, 0x7c, 0x45, 0xd3, 0xa5, 0xbc, 0x55,
0x84, 0xaa, 0x41, 0xc1, 0xc1, 0xe0, 0xe0, 0x29, 0x01, 0x20, 0x81, 0x00, 0x03, 0x80, 0x07, 0xc0,
0x0f, 0xe0, 0x06, 0xbe, 0x16, 0x75, 0xe7, 0x9f, 0xfb, 0x1e, 0x17, 0x90, 0xef, 0x0b, 0xbb, 0x15,
0x03, 0x7c, 0x2b, 0x7e, 0x22, 0x78, 0x56, 0x83, 0xae, 0x77, 0x40, 0xcf, 0xb0, 0xf0, 0x98, 0x28,
0x04, 0x2f, 0xaf, 0x0e, 0x40, 0xfc, 0x01, 0x1c, 0x5c, 0xb1, 0xf2, 0xbf, 0xa5, 0xd7, 0x8f, 0x97,
0xc0, 0xfe, 0x9f, 0x02, 0xe7, 0x24, 0x79, 0xe0, 0x9b, 0xa9, 0xfd, 0x74, 0x3b, 0xaf, 0x2d, 0xf8,
0x4b, 0xd2, 0xf7, 0x84, 0x54, 0x04, 0x2a, 0x02, 0x02, 0x01, 0xe1, 0x1e, 0xf0, 0x87, 0xff, 0x77,
0x07, 0x00, 0x02, 0x00, 0x0d, 0xbd, 0xe1, 0xf0, 0x01, 0x1e, 0xf0, 0xfd, 0x80, 0x4c, 0x24, 0x11,
0x2c, 0x10, 0x24, 0x02, 0x01, 0x40, 0xb0, 0x5c, 0x2c, 0x14, 0x08, 0x07, 0x1b, 0x80, 0x01, 0xa7,
0xbd, 0x3e, 0x00, 0x27, 0xde, 0x9f, 0xb0, 0x85, 0x01, 0xfb, 0xd2, 0x04, 0x0c, 0x1c, 0x2e, 0x0e,
0x06, 0x18, 0x03, 0xd4, 0x00, 0x00, 0x67, 0xef, 0x4f, 0x80, 0x0a, 0xf7, 0xa7, 0xe3, 0x94, 0xe0,
0xe0, 0x10, 0x1b, 0xfd, 0xfc, 0x74, 0x62, 0xe8, 0xc0, 0x1d, 0x62, 0x00, 0x0b, 0x00, 0xb7, 0x70,
0xe6, 0x8a, 0x68, 0x75, 0x38, 0x3c, 0x3c, 0x4c, 0x2f, 0x87, 0xef, 0x01, 0xc7, 0xb2, 0x40, 0x21,
0xa3, 0x23, 0x0a, 0x08, 0x01, 0xa1, 0xa1, 0xe1, 0x80, 0x69, 0x40, 0xe1, 0x00, 0x00, 0x40, 0xd0,
0xea, 0xe5, 0xe1, 0xc0, 0x81, 0x87, 0xed, 0x68, 0x1a, 0x08, 0x94, 0x0c, 0x0c, 0xf1, 0x7c, 0xbe,
0x5f, 0x2f, 0x8f, 0x00, 0x00, 0x0d, 0x1f, 0x68, 0x7a, 0x1a, 0x04, 0x05, 0xce, 0xe6, 0x2a, 0x0c,
0x01, 0xc2, 0x00, 0x40, 0x42, 0x61, 0xc0, 0x49, 0x41, 0x60, 0xa0, 0x80, 0x01, 0xc0, 0x03, 0xe0,
0x07, 0xf0, 0x07, 0xfa, 0x00, 0x07, 0x3b, 0x99, 0x01, 0x0f, 0x19, 0x18, 0x54, 0x40, 0xe0, 0x60,
0xee, 0xd0, 0x0e, 0x19, 0x0a, 0x03, 0xa5, 0x7d, 0x05, 0xd0, 0x83, 0x98, 0x5a, 0x96, 0x21, 0x4b,
0x10, 0x10, 0xe6, 0x17, 0xaf, 0xeb, 0xaf, 0x34, 0x3c, 0xc8, 0x0f, 0xf0, 0x64, 0x3f, 0xd0, 0x0f,
0xe0, 0x03, 0xfe, 0x10, 0x02, 0x7d, 0x47, 0x2d, 0x58, 0xfc, 0x35, 0xe0, 0xca, 0x0f, 0x19, 0x0a,
0xf9, 0xf1, 0xe0, 0xb9, 0xc0, 0x81, 0x10, 0x03, 0xe0, 0xbd, 0x4f, 0xea, 0x61, 0xf7, 0xeb, 0xf6,
0x02, 0xd4, 0x7a, 0xf9, 0xff, 0x15, 0x30, 0xfa, 0x88, 0x68, 0x68, 0xd8, 0x80, 0x12, 0x60, 0x50,
0x50, 0xf0, 0x03, 0xfc, 0x01, 0xfe, 0x01, 0x7f, 0xa0, 0x7c, 0x28, 0xbf, 0xd0, 0x3e, 0x64, 0x0f,
0x00, 0x37, 0x00, 0x08, 0x80, 0x20, 0x0b, 0x88, 0x81, 0xa5, 0x04, 0x84, 0x60, 0x40, 0x36, 0x04,
0x1b, 0x8f, 0x88, 0x01, 0x00, 0xa1, 0x80, 0x1e, 0x00, 0x36, 0xfd, 0xb9, 0x12, 0x02, 0x4c, 0x09,
0x08, 0x1e, 0x00, 0x61, 0x80, 0x20, 0x60, 0x44, 0x17, 0xdc, 0x7c, 0x62, 0x00, 0x03, 0x67, 0xdb,
0x81, 0xb1, 0x30, 0x34, 0xb0, 0xa0, 0xaf, 0xa0, 0x80, 0x75, 0x35, 0x20, 0x7c, 0x49, 0xfc, 0x0f,
0xf5, 0x0d, 0x7f, 0x7e, 0x45, 0x00, 0x53, 0x42, 0x82, 0x83, 0xc0, 0x0c, 0x28, 0x1f, 0x72, 0x3e,
0xd3, 0xf5, 0x62, 0xd4, 0x00, 0x22, 0xa8, 0x81, 0xec, 0x67, 0x96, 0x02, 0xa0, 0x49, 0x7d, 0xfd,
0x6b, 0xbf, 0xcc, 0x7c, 0x4a, 0xf8, 0xd0, 0x00, 0x00, 0xcf, 0xd5, 0xd2, 0x23, 0x35, 0x60, 0x01,
0xf1, 0x60, 0x14, 0xc0, 0xb0, 0xbe, 0xb3, 0x02, 0x0f, 0x89, 0x5f, 0x1b, 0x00, 0x02, 0x0b, 0xfd,
0x80, 0x00, 0x01, 0x9b, 0xf3, 0x40, 0x42, 0x10, 0x00, 0xd8, 0xb8, 0x0f, 0xa8, 0x17, 0xfe, 0x59,
0xef, 0x14, 0x61, 0xf2, 0x30, 0x65, 0xfc, 0x51, 0xe2, 0xc1, 0x18, 0xc0, 0x07, 0x5e, 0x68, 0x08,
0xe8, 0x46, 0xf8, 0x95, 0xf1, 0xb0, 0xf9, 0x13, 0x7f, 0xbc, 0x00, 0x00, 0x32, 0x7e, 0xa8, 0xeb,
0xcd, 0x03, 0x20, 0x09, 0xa1, 0x81, 0x97, 0xfb, 0x87, 0x80, 0xb0, 0xf9, 0x19, 0x7c, 0xa8, 0x63,
0xf3, 0xe6, 0x20, 0x22, 0xbd, 0x85, 0x9e, 0x62, 0x00, 0x8b, 0x7c, 0x87, 0x91, 0x00, 0x22, 0xff,
0x21, 0xe2, 0xa0, 0x08, 0xc7, 0xc8, 0x78, 0x20, 0x02, 0x33, 0xf2, 0x1c, 0x10, 0x41, 0xe3, 0x40,
0x69, 0x7c, 0x45, 0x72, 0x62, 0xf0, 0x04, 0x7f, 0x60, 0x68, 0x6f, 0x80, 0x00, 0x08, 0x1f, 0xf7,
0xad, 0x51, 0x03, 0xf3, 0xf8, 0xa0, 0x9d, 0xa8, 0x40, 0x00, 0x23, 0x42, 0x37, 0x46, 0x0f, 0xde,
0xa6, 0x06, 0xd3, 0x3c, 0x33, 0xe1, 0x78, 0xd8, 0x34, 0x32, 0x14, 0x67, 0xdb, 0xd2, 0x38, 0xaf,
0xc7, 0x9c, 0xdf, 0xd0, 0x21, 0xe6, 0xd7, 0x80, 0x40, 0x22, 0x3f, 0x21, 0xe8, 0xd8, 0x12, 0xf9,
0x0f, 0xb4, 0x01, 0x13, 0xf9, 0x0f, 0x46, 0xc0, 0xa7, 0x13, 0x37, 0x1e, 0x67, 0x07, 0x8b, 0x01,
0xfd, 0xfe, 0x0f, 0xf7, 0x7a, 0xf0, 0x16, 0x36, 0x0a, 0x92, 0x08, 0x08, 0xc1, 0x70, 0xb8, 0x30,
0x34, 0xf1, 0xf3, 0x72, 0x27, 0x8f, 0x4b, 0x60, 0x21, 0xc4, 0xdd, 0xe2, 0xdf, 0x0b, 0xca, 0x4f,
0x2e, 0x4f, 0x9c, 0xde, 0x59, 0xe9, 0xf1, 0x55, 0x00, 0x8d, 0xf2, 0x20, 0x53, 0x3c, 0xc4, 0xf6,
0x46, 0x7e, 0x24, 0xee, 0xf2, 0x0c, 0x0d, 0x81, 0x83, 0xf9, 0x98, 0x0e, 0x00, 0x02, 0x10, 0x11,
0x01, 0x08, 0x95, 0x2a, 0xfc, 0x28, 0x95, 0x2a, 0x84, 0x80, 0xbf, 0x81, 0x06, 0x80, 0x0d, 0x00,
0x86, 0xe0, 0x6b, 0xa5, 0xc3, 0xd8, 0x8f, 0x22, 0xa0, 0x3e, 0xe9, 0x8f, 0x90, 0xf2, 0x6b, 0x85,
0x77, 0x57, 0x99, 0x43, 0x5c, 0x66, 0x5f, 0x9e, 0x85, 0x7c, 0x3f, 0x1f, 0xb3, 0xce, 0xc0, 0x0e,
0x64, 0x20, 0x0e, 0x20, 0xdc, 0x7e, 0x18, 0x81, 0x90, 0xa3, 0x13, 0x4e, 0x52, 0x71, 0x81, 0x03,
0xa4, 0x30, 0x30, 0x6c, 0x73, 0x8f, 0xc4, 0x50, 0x60, 0x16, 0x38, 0x03, 0xbf, 0x6f, 0x89, 0x3e,
0x00, 0x77, 0x00, 0xb1, 0xc0, 0x28, 0x3d, 0x73, 0x98, 0x06, 0xfe, 0x00, 0xe9, 0x81, 0xa3, 0xb8,
0x1c, 0x85, 0x20, 0x45, 0x45, 0xe1, 0xa1, 0x23, 0x63, 0xa0, 0x29, 0x61, 0x41, 0x27, 0xf4, 0x03,
0xfa, 0x01, 0x02, 0x05, 0xff, 0xe1, 0x20, 0x34, 0x08, 0x08, 0x04, 0x04, 0x02, 0xff, 0xeb, 0x96,
0x05, 0x24, 0x8e, 0x0a, 0xb1, 0xce, 0xf2, 0x06, 0xc7, 0xb9, 0x01, 0xd7, 0x20, 0x52, 0x04, 0x03,
0xe1, 0x47, 0xc4, 0xa4, 0x0b, 0xfd, 0x03, 0x01, 0xc0, 0x47, 0xe6, 0xc0, 0x2c, 0x7c, 0x09, 0x10,
0x1c, 0x0a, 0xfd, 0x7e, 0xc0, 0xd2, 0x94, 0x7a, 0x1a, 0x06, 0x07, 0xcf, 0x12, 0x2a, 0x8c, 0x1e,
0xe7, 0x07, 0x08, 0x81, 0x81, 0x91, 0x90, 0x72, 0x26, 0x9e, 0x55, 0x44, 0x0e, 0x4d, 0x21, 0x00,
0x08, 0x40, 0x02, 0x20, 0x01, 0x17, 0x2c, 0xd4, 0x22, 0x00, 0x88, 0x80, 0x44, 0x40, 0x23, 0xcd,
0xf8, 0xf1, 0xc8, 0x9b, 0x02, 0x10, 0x0c, 0x02, 0x99, 0x30, 0x00, 0x0a, 0x06, 0x01, 0x4b, 0x18,
0x00, 0x46, 0x00, 0x29, 0x9c, 0xa3, 0x86, 0x60, 0x11, 0x98, 0x05, 0x32, 0x80, 0xcc, 0xc0, 0xf3,
0xc3, 0xb8, 0x7a, 0x21, 0x7d, 0xbe, 0xfa, 0xce, 0x2a, 0x9d, 0xfa, 0xa0, 0x3c, 0x32, 0xfb, 0x7d,
0x13, 0x22, 0x05, 0xeb, 0x0b, 0xbb, 0xb8, 0x00, 0x15, 0xfe, 0xfe, 0x1a, 0x14, 0x7e, 0x1c, 0x00,
0x01, 0x82, 0x3a, 0xa7, 0xd2, 0x6c, 0x11, 0xdd, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x18, 0x23, 0x5a,
0x00, 0x80, 0xb0, 0x47, 0x84, 0x7c, 0xa8, 0x03, 0xa7, 0x82, 0x48, 0x83, 0x01, 0x50, 0x11, 0x2a,
0x37, 0xfb, 0xfc, 0x03, 0x03, 0xd1, 0xa3, 0x35, 0x68, 0xcd, 0x58, 0x40, 0x03, 0xe3, 0x47, 0xc4,
0xaf, 0x8d, 0x1f, 0x42, 0x84, 0x20, 0x81, 0x08, 0x57, 0xfb, 0xff, 0xd0, 0x98, 0x27, 0xc8, 0xaf,
0x99, 0x1f, 0x12, 0x04, 0x3e, 0x84, 0xfe, 0x08, 0x1c, 0xc1, 0x31, 0x58, 0x80, 0x3a, 0xd1, 0x99,
0x8a, 0x40, 0x02, 0x5a, 0x04, 0x00, 0x02, 0x1a, 0x38, 0xf3, 0x08, 0x00, 0x01, 0xda, 0xe3, 0x35,
0x60, 0x5f, 0x88, 0x00, 0x03, 0x6e, 0xbf, 0xdf, 0xc0, 0xbe, 0x20, 0x00, 0x42, 0x80, 0x01, 0x77,
0x9e, 0x80, 0xd0, 0x30, 0x4a, 0x32, 0x81, 0xe3, 0x94, 0x04, 0x21, 0x0a, 0x9c, 0xcc, 0x52, 0x03,
0x7d, 0xa7, 0x0c, 0x51, 0x80, 0x6f, 0xa5, 0xc0, 0x3f, 0x3e, 0x80, 0xa0, 0x22, 0x10, 0x40, 0x68,
0x17, 0x9f, 0x60, 0x1e, 0x9b, 0x09, 0x52, 0x03, 0x2d, 0x03, 0x81, 0x88, 0x41, 0x3c, 0x65, 0x14,
0x98, 0xcd, 0x58, 0x6a, 0x04, 0x21, 0x80, 0x9b, 0x81, 0x45, 0x21, 0x24, 0xe1, 0x8c, 0xf1, 0x9a,
0xb0, 0xa9, 0x38, 0xef, 0xe7, 0x90, 0xdf, 0x98, 0x00, 0x19, 0xa8, 0x18, 0x42, 0x6a, 0xc0, 0x7f,
0xda, 0x00, 0x00, 0x2b, 0x1e, 0x36, 0x7c, 0xaa, 0xa0, 0x00, 0xc0, 0xf8, 0xa0, 0xbe, 0x60, 0x2e,
0xb1, 0x09, 0xab, 0x60, 0x3e, 0x38, 0xf9, 0x6f, 0xa9, 0x3e, 0x08, 0x81, 0xa6, 0x8c, 0x13, 0xae,
0x83, 0x7e, 0x0a, 0xfb, 0x0f, 0x60, 0x86, 0x3e, 0x90, 0x6d, 0xa2, 0x33, 0x56, 0x06, 0xfa, 0xcf,
0xc5, 0x1f, 0x12, 0x38, 0x49, 0x3d, 0x04, 0x03, 0xa6, 0x42, 0x54, 0x82, 0x3e, 0xd3, 0xd1, 0xd0,
0x08, 0x58, 0x06, 0xdc, 0x10, 0x85, 0xe8, 0xf8, 0xf8, 0x94, 0x10, 0x84, 0x21, 0xe7, 0xa3, 0x85,
0xfe, 0xfe, 0xc1, 0xe9, 0x77, 0xa3, 0x27, 0xe7, 0xbd, 0x31, 0x98, 0x17, 0xa1, 0xe2, 0x13, 0xe8,
0x5a, 0xf1, 0x44, 0x7c, 0x4a, 0x00, 0x00, 0x07, 0x2d, 0x03, 0x2d, 0x05, 0xa3, 0x46, 0x6a, 0xc1,
0x9e, 0x9f, 0x9f, 0x51, 0xc0, 0x55, 0x1a, 0x13, 0x56, 0x0e, 0xf4, 0xa4, 0x85, 0xfd, 0x4c, 0x47,
0x10, 0x0d, 0x70, 0x24, 0x9b, 0xfa, 0x45, 0x41, 0x3a, 0x33, 0xea, 0x28, 0x60, 0x00, 0x80, 0x00,
0xbc, 0x00, 0x80, 0x7b, 0x2e, 0x43, 0x10, 0x0b, 0x00, 0xec, 0x1e, 0x98, 0x8a, 0xb4, 0x26, 0xac,
0x5f, 0xf9, 0x20, 0x03, 0xf2, 0xc1, 0xdf, 0xca, 0x14, 0x40, 0x07, 0x40, 0x1e, 0x00, 0x3d, 0x10,
0xe1, 0x37, 0x90, 0x64, 0x17, 0xec, 0x3d, 0x4c, 0xf5, 0x94, 0x20, 0x15, 0x80, 0xdc, 0x3e, 0x74,
0x7f, 0x87, 0x87, 0xa9, 0xa6, 0x33, 0x56, 0x16, 0xfd, 0xcf, 0xa9, 0x1f, 0x12, 0x23, 0x35, 0x60,
0xaf, 0xa4, 0x04, 0xf5, 0xb0, 0x1f, 0xe4, 0x3d, 0x75, 0x1c, 0x20, 0xeb, 0xd7, 0x19, 0x00, 0xb8,
0x04, 0x21, 0x7a, 0xd3, 0xbe, 0x15, 0xeb, 0x4a, 0xf1, 0x84, 0x78, 0x52, 0x3e, 0x25, 0x03, 0x16,
0x81, 0xc3, 0x7d, 0x59, 0x1f, 0x12, 0x30, 0x50, 0xe3, 0xe1, 0xcf, 0xc5, 0x8f, 0xa1, 0x1c, 0x0e,
0x9e, 0xd0, 0x0d, 0x7b, 0x18, 0x14, 0xcc, 0x21, 0x04, 0x1b, 0x6a, 0x8c, 0xd5, 0x86, 0xe0, 0x31,
0x9a, 0xb0, 0x4f, 0xc8, 0x0b, 0x7c, 0x40, 0x37, 0xc4, 0x5c, 0x22, 0x80, 0x3e, 0x54, 0x71, 0x10,
0xbf, 0x26, 0xf9, 0xa2, 0x1c, 0x0b, 0x82, 0xf0, 0x8f, 0x22, 0x47, 0x8a, 0xab, 0xca, 0xd4, 0x31,
0x08, 0xf1, 0xe6, 0x51, 0x9a, 0xb7, 0xcc, 0x80, 0x7f, 0xc9, 0xc2, 0x13, 0x08, 0xfd, 0x95, 0xfe,
0x23, 0xc0, 0x14, 0x0f, 0x08, 0xe1, 0xb5, 0x5f, 0x4a, 0x38, 0x10, 0x47, 0x1b, 0x17, 0x0a, 0x07,
0x1d, 0x38, 0xe3, 0xcb, 0x42, 0x10, 0x4f, 0x5d, 0x40, 0x3f, 0xf8, 0xe1, 0x0a, 0xe0, 0x45, 0xa8,
0x47, 0xe0, 0x78, 0x23, 0x0f, 0x91, 0x5f, 0x4a, 0x7f, 0xe3, 0xc9, 0x11, 0xe0, 0x4a, 0x09, 0xfe,
0x5a, 0xf0, 0xea, 0x8f, 0x21, 0x57, 0x82, 0xa3, 0xfa, 0x47, 0xc4, 0x8e, 0x0d, 0x8f, 0xcc, 0xfe,
0x11, 0xf1, 0x22, 0x33, 0x56, 0xe1, 0xf9, 0x1f, 0x9a, 0x83, 0x79, 0x2d, 0xe3, 0xf5, 0x23, 0xf6,
0x50, 0x64, 0x17, 0xce, 0x4f, 0x12, 0x58, 0x5f, 0xe0, 0xc4, 0x32, 0x0d, 0xfc, 0xab, 0xd5, 0x54,
0x15, 0x04, 0xfd, 0x91, 0xf1, 0x20, 0x32, 0x0d, 0xe1, 0x48, 0xf8, 0x91, 0xe5, 0x48, 0x09, 0xfc,
0xdb, 0x7b, 0xab, 0x84, 0x22, 0x0d, 0xfd, 0x23, 0xda, 0xd1, 0xf2, 0x20, 0x2a, 0x11, 0xfe, 0x23,
0xe7, 0x4f, 0x8c, 0x2f, 0x80, 0xe7, 0x1f, 0x09, 0x40, 0x2f, 0x00, 0xee, 0x7f, 0xf5, 0x1f, 0x12,
0x3c, 0x0d, 0x40, 0xff, 0xa9, 0xc3, 0x1b, 0x01, 0x42, 0xce, 0x18, 0x5b, 0x52, 0xd9, 0x8a, 0x79,
0xa7, 0xbc, 0xc5, 0x01, 0x08, 0x41, 0x21, 0xb5, 0xfc, 0x1b, 0x93, 0x1e, 0x8f, 0x60, 0x02, 0x98,
0xf8, 0xe0, 0x0c, 0x1c, 0x2e, 0x15, 0x00, 0xe7, 0x61, 0x08, 0x02, 0xfd, 0x16, 0x5c, 0xdb, 0xf2,
0xb8, 0x4f, 0x03, 0xfd, 0x81, 0x8a, 0x88, 0x52, 0x05, 0x20, 0x0e, 0xe9, 0xf9, 0xaa, 0xed, 0x7f,
0xbf, 0xd0, 0x0b, 0x0b, 0x42, 0x60, 0x85, 0xa1, 0x3f, 0x0a, 0x0b, 0x42, 0x40, 0x08, 0xa8, 0x02,
0x04, 0xa9, 0x60, 0x46, 0x00, 0x45, 0x40, 0x5c, 0xa7, 0xa6, 0xfa, 0x5c, 0x07, 0xf0, 0xe0, 0xa4,
0x0f, 0x94, 0xc4, 0x16, 0x82, 0x96, 0x82, 0x94, 0x83, 0x71, 0x76, 0x04, 0x94, 0x8f, 0xa1, 0xf3,
0x40, 0x00, 0x93, 0x85, 0xa2, 0x50, 0xc0, 0x00, 0x28, 0x1c, 0xbb, 0x03, 0x09, 0x12, 0x5e, 0x91,
0xaf, 0x21, 0x42, 0x05, 0x09, 0x6b, 0xe5, 0x59, 0x27, 0xcf, 0x8f, 0x88, 0x24, 0x00, 0x90, 0x7c,
0x60, 0x00, 0x00, 0x17, 0x1a, 0x02, 0x40, 0x2c, 0x03, 0x94, 0x1a, 0xf8, 0x02, 0xa0, 0x80, 0xd2,
0x15, 0xf5, 0x64, 0x00, 0xc0, 0x32, 0x01, 0x83, 0xa4, 0xc0, 0x5e, 0xb2, 0x0e, 0x70, 0x9a, 0x7b,
0x12, 0x23, 0x35, 0x6f, 0x26, 0x43, 0x7f, 0x40, 0x6a, 0x04, 0xe8, 0x14, 0x04, 0xa4, 0xb3, 0x14,
0x81, 0x30, 0x2f, 0x16, 0x84, 0xd0, 0x0c, 0x0b, 0x42, 0x6e, 0x14, 0x00, 0x9a, 0x00, 0x87, 0x76,
0x80, 0x07, 0x98, 0x2c, 0x03, 0x99, 0x9c, 0xf3, 0xbb, 0x7f, 0xb8, 0xa4, 0xdb, 0xde, 0xfc, 0x4a,
0x00, 0x05, 0xa4, 0xc2, 0x6a, 0xc0, 0xed, 0x3d, 0x15, 0xc1, 0x04, 0xe1, 0x30, 0x2e, 0x2c, 0xf1,
0x50, 0x69, 0x84, 0xa9, 0x0f, 0xf8, 0xc2, 0xbe, 0x35, 0xa8, 0x87, 0x50, 0x10, 0x0e, 0x00, 0xe5,
0x1e, 0xc6, 0xa9, 0x55, 0xfe, 0xff, 0x48, 0xf5, 0xe0, 0x53, 0xdc, 0x78, 0x80, 0x10, 0x51, 0x89,
0x52, 0xc0, 0x06, 0xab, 0x03, 0x14, 0x6f, 0xed, 0x85, 0xde, 0x80, 0x03, 0x09, 0x52, 0xe5, 0xff,
0x5e, 0x02, 0xbf, 0x8f, 0x8f, 0xc9, 0xcf, 0xe5, 0xeb, 0xf3, 0x72, 0xbb, 0x80, 0x00, 0xc6, 0x6a,
0xd8, 0x08, 0x95, 0xf4, 0xb2, 0xf9, 0x4f, 0xa1, 0xc1, 0xc2, 0x5a, 0xef, 0xf7, 0xfa, 0x81, 0xdd,
0xbd, 0xef, 0xee, 0xe0, 0xd1, 0xe5, 0x72, 0xc5, 0xcd, 0xf0, 0x2c, 0x00, 0x03, 0xcb, 0x98, 0xf0,
0x7f, 0x52, 0x00
};
static BYTE TEST_RDP5_UNCOMPRESSED_DATA[] =
{
0x24, 0x02, 0x03, 0x09, 0x00, 0x20, 0x0c, 0x05, 0x10, 0x01, 0x40, 0x0a, 0xff, 0xff, 0x0c, 0x84,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x0d, 0x38, 0x01, 0xc0, 0x10, 0x01, 0x10,
0x01, 0xcc, 0xff, 0x7f, 0x03, 0x08, 0x00, 0x20, 0x04, 0x05, 0x10, 0x01, 0x40, 0x0a, 0x00, 0x0c,
0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x0a,
0x0c, 0x0c, 0xff, 0x03, 0xff, 0x02, 0x00, 0x04, 0x00, 0x03, 0x06, 0x00, 0x00, 0x80, 0x00, 0x80,
0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x0c, 0x80, 0x00, 0x80, 0x00, 0x06, 0x00, 0x00, 0x48, 0x00,
0x37, 0x01, 0x02, 0x00, 0x00, 0x01, 0x0c, 0x48, 0x00, 0x37, 0x01, 0x06, 0x01, 0x00, 0x00, 0x04,
0x24, 0x00, 0x02, 0x01, 0x00, 0x01, 0x0c, 0x00, 0x04, 0x24, 0x00, 0x02, 0x00, 0x00, 0x09, 0x0a,
0x3d, 0x0f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11,
0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3,
0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6,
0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x09, 0x18, 0xfb, 0x70, 0x06, 0x00, 0x03,
0xff, 0xff, 0x00, 0x03, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x00, 0x80, 0x0c, 0x00, 0x0f,
0x00, 0x01, 0x49, 0x08, 0x07, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x72, 0x00, 0x19,
0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0xff, 0xff, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e,
0xf3, 0xf2, 0x0c, 0x08, 0x42, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b,
0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x10, 0x84, 0x11,
0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x3a, 0x01, 0x09, 0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0x11, 0x01,
0x11, 0x01, 0x01, 0x01, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f,
0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4,
0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e,
0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19, 0x18,
0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5,
0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff,
0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3,
0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11,
0x0a, 0x01, 0x09, 0x19, 0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0x11, 0x01, 0x11, 0x01, 0x01, 0x11,
0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xdd, 0x0c, 0xf5,
0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff,
0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3,
0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11,
0x0a, 0x01, 0x09, 0x19, 0x18, 0xf4, 0x60, 0x00, 0x00, 0x00, 0xd0, 0x0e, 0xd0, 0x0e, 0x0e, 0x0b,
0x01, 0x01, 0x43, 0x06, 0x02, 0xfc, 0xfc, 0x00, 0x00, 0x30, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe,
0xf5, 0x04, 0xff, 0xff, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0x08,
0x42, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x99, 0xd6, 0x11, 0x0f,
0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x10, 0x84, 0x11, 0x0d, 0x01, 0x0b, 0xf6,
0x11, 0x3a, 0x01, 0x09, 0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0x11, 0x01, 0x11, 0x01, 0x01, 0x01,
0x01, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3,
0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01,
0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99,
0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00,
0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11,
0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d,
0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11,
0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19,
0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0x11, 0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xdd, 0x0c, 0xf5, 0x04, 0x08, 0x42, 0x11,
0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d,
0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11,
0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19,
0x18, 0xf4, 0x60, 0x00, 0x00, 0x00, 0xd0, 0x0e, 0xd0, 0x0e, 0x0e, 0x13, 0x02, 0x00, 0x4a, 0x08,
0x09, 0x3f, 0x3f, 0x21, 0xfd, 0xfd, 0x87, 0x84, 0x84, 0xfc, 0x00, 0x00, 0x00, 0x32, 0x00, 0x19,
0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0xff, 0xff, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e,
0xf3, 0xf2, 0x0c, 0x08, 0x42, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b,
0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x10, 0x84, 0x11,
0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x3a, 0x01, 0x09, 0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0x11, 0x01,
0x11, 0x01, 0x01, 0x01, 0x02, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f,
0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4,
0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e,
0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19, 0x18,
0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5,
0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff,
0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3,
0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11,
0x0a, 0x01, 0x09, 0x19, 0x18, 0x54, 0x40, 0x00, 0x00, 0x00, 0x10, 0x10, 0x13, 0x03, 0x02, 0x4a,
0x06, 0x09, 0x78, 0xcc, 0xcc, 0x18, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x73, 0x00,
0x19, 0x0a, 0x3f, 0xdd, 0x0c, 0xf5, 0x04, 0xff, 0xff, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11,
0x3e, 0xf3, 0xf2, 0x0c, 0x08, 0x42, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3,
0x0b, 0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x10, 0x84,
0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x3a, 0x01, 0x09, 0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0xd1,
0x0f, 0xd1, 0x0f, 0x0f, 0x01, 0x03, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11,
0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d,
0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11,
0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19,
0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe,
0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff,
0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f,
0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6,
0x11, 0x0a, 0x01, 0x09, 0x19, 0x18, 0x54, 0x40, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1b, 0x04, 0x00,
0x4a, 0x09, 0x09, 0xff, 0x80, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0xff, 0x80, 0x00, 0x00, 0x31, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04,
0xff, 0xff, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0x08, 0x42, 0x11,
0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0b,
0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x10, 0x84, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x3a,
0x01, 0x09, 0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0x11, 0x01, 0x11, 0x01, 0x01, 0x01, 0x04, 0x19,
0x0a, 0x3f, 0xdd, 0x0c, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0d, 0x0e, 0xf3, 0x11, 0x3e,
0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0b,
0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5, 0xf4, 0x0a, 0x99, 0xd6, 0x11,
0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0xcf,
0x0d, 0xcf, 0x0d, 0x0d, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1,
0x0d, 0x0e, 0xf3, 0x11, 0x3e, 0xf3, 0xf2, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0d, 0xf4, 0x11,
0x3f, 0x0d, 0x01, 0xf3, 0x0b, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0b, 0x0c, 0xf5, 0x11, 0x3e, 0xf5,
0xf4, 0x0a, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0b, 0xf6, 0x11, 0x0a, 0x01, 0x09, 0x19, 0x18, 0xf4,
0x20, 0xff, 0xff, 0x00, 0x11, 0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xee, 0x34, 0x3c, 0x08, 0x2d, 0x09, 0x59, 0x0d, 0x97,
0xff, 0x00, 0x02, 0x70, 0x0d, 0x0e, 0x51, 0xc2, 0x10, 0x20, 0x1c, 0x51, 0xc2, 0x12, 0xe0, 0xd6,
0x51, 0xc2, 0x12, 0x30, 0x1c, 0x19, 0x0a, 0x32, 0x12, 0x10, 0x84, 0x59, 0x0d, 0xc6, 0xcc, 0x12,
0xd0, 0xf2, 0x51, 0xc2, 0x10, 0x20, 0x1c, 0x51, 0xc2, 0x12, 0xe0, 0xd6, 0x51, 0xc2, 0x12, 0x30,
0x1c, 0x19, 0x0a, 0x3f, 0x0a, 0x12, 0xb9, 0xf9, 0x08, 0x42, 0x11, 0x0f, 0xf6, 0x0a, 0x09, 0xf6,
0x11, 0x3e, 0xf6, 0xf7, 0x09, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x08, 0xf7, 0x11, 0x3f, 0x08, 0x01,
0xf8, 0x08, 0x10, 0x84, 0x11, 0x0f, 0xf8, 0x08, 0x07, 0xf8, 0x11, 0x3e, 0xf8, 0xf9, 0x07, 0x99,
0xd6, 0x11, 0x0d, 0x01, 0x06, 0xf9, 0x11, 0x0a, 0x01, 0x06, 0x19, 0x18, 0xf5, 0x60, 0x05, 0x00,
0x00, 0x00, 0xef, 0x5a, 0xec, 0x57, 0x57, 0x0f, 0x00, 0x00, 0x46, 0x06, 0x05, 0xcc, 0x78, 0x30,
0x78, 0xcc, 0x00, 0x00, 0x00, 0x72, 0x00, 0x19, 0x0a, 0x3f, 0x13, 0xfe, 0xfa, 0x04, 0xff, 0xff,
0x11, 0x0f, 0xf6, 0x0a, 0x09, 0xf6, 0x11, 0x3e, 0xf6, 0xf7, 0x09, 0x08, 0x42, 0x11, 0x0d, 0x01,
0x08, 0xf7, 0x11, 0x3f, 0x08, 0x01, 0xf8, 0x08, 0x99, 0xd6, 0x11, 0x0f, 0xf8, 0x08, 0x07, 0xf8,
0x11, 0x3e, 0xf8, 0xf9, 0x07, 0x10, 0x84, 0x11, 0x0d, 0x01, 0x06, 0xf9, 0x11, 0x3a, 0x01, 0x06,
0x99, 0xd6, 0x19, 0x18, 0xf0, 0x60, 0x0c, 0x01, 0x0c, 0x01, 0x01, 0x01, 0x00, 0x19, 0x0a, 0x3f,
0x13, 0xfe, 0xfa, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf6, 0x0a, 0x09, 0xf6, 0x11, 0x3e, 0xf6, 0xf7,
0x09, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x08, 0xf7, 0x11, 0x3f, 0x08, 0x01, 0xf8, 0x08, 0x10, 0x84,
0x11, 0x0f, 0xf8, 0x08, 0x07, 0xf8, 0x11, 0x3e, 0xf8, 0xf9, 0x07, 0x99, 0xd6, 0x11, 0x0d, 0x01,
0x06, 0xf9, 0x11, 0x0a, 0x01, 0x06, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0x0a, 0xff, 0x0a,
0xff, 0xff, 0x19, 0x0a, 0x3f, 0x13, 0xfe, 0xfa, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf6, 0x0a, 0x09,
0xf6, 0x11, 0x3e, 0xf6, 0xf7, 0x09, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x08, 0xf7, 0x11, 0x3f, 0x08,
0x01, 0xf8, 0x08, 0x10, 0x84, 0x11, 0x0f, 0xf8, 0x08, 0x07, 0xf8, 0x11, 0x3e, 0xf8, 0xf9, 0x07,
0x99, 0xd6, 0x11, 0x0d, 0x01, 0x06, 0xf9, 0x11, 0x0a, 0x01, 0x06, 0x19, 0x18, 0xf4, 0x20, 0xff,
0xff, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x19, 0x0a, 0x0f, 0x09, 0xfe, 0x09, 0x09, 0x19, 0x18, 0xf5, 0x60, 0x06, 0xff, 0xff,
0x00, 0x09, 0xfe, 0x12, 0x07, 0x07, 0x23, 0x05, 0x03, 0x4d, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x08,
0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x88, 0x01, 0x10, 0x02, 0x20, 0x04, 0x40, 0x08, 0x88,
0x11, 0x10, 0x22, 0x20, 0x44, 0x40, 0x00, 0x00, 0x6f, 0x00, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00,
0x1f, 0x06, 0x04, 0x4c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x60, 0x00, 0xc0,
0x01, 0x90, 0x03, 0x30, 0x06, 0x60, 0x0c, 0xc0, 0x19, 0x90, 0x33, 0x30, 0x66, 0x60, 0x70, 0x00,
0x19, 0x0a, 0x37, 0xe3, 0x10, 0xf1, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e,
0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d,
0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11,
0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x60, 0x00, 0x00,
0x00, 0xd6, 0x12, 0xd2, 0x0e, 0x0e, 0x0f, 0x07, 0x01, 0x48, 0x09, 0x04, 0x08, 0x00, 0x1c, 0x00,
0x3e, 0x00, 0x7f, 0x00, 0x35, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x10, 0x84, 0x11,
0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x0e, 0xf1, 0xf2, 0x0e, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11,
0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x0e, 0xf3,
0xf4, 0x0c, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x0a, 0x01, 0x0b, 0x19, 0x18, 0xf0, 0x60, 0x11,
0x01, 0x11, 0x01, 0x01, 0x01, 0x07, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11,
0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d,
0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11,
0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99,
0xd6, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f,
0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2,
0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84,
0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01,
0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0x11,
0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19,
0x0a, 0x3f, 0xdd, 0x0e, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e,
0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d,
0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11,
0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x60, 0x00, 0x00,
0x00, 0xd0, 0x10, 0xd0, 0x10, 0x10, 0x0f, 0x08, 0x01, 0x48, 0x09, 0x04, 0x7f, 0x00, 0x3e, 0x00,
0x1c, 0x00, 0x08, 0x00, 0x36, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x10, 0x84, 0x11,
0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x0e, 0xf1, 0xf2, 0x0e, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11,
0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x0e, 0xf3,
0xf4, 0x0c, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x0a, 0x01, 0x0b, 0x19, 0x18, 0xf0, 0x60, 0x11,
0x01, 0x11, 0x01, 0x01, 0x01, 0x08, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11,
0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d,
0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11,
0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99,
0xd6, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f,
0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2,
0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84,
0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01,
0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0x11,
0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19,
0x0a, 0x3f, 0xdd, 0x0e, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e,
0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d,
0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11,
0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x60, 0x00, 0x00,
0x00, 0xd0, 0x10, 0xd0, 0x10, 0x10, 0x13, 0x09, 0x04, 0x4b, 0x04, 0x09, 0x00, 0x80, 0xc0, 0xe0,
0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5,
0x04, 0x10, 0x84, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x0e, 0xf1, 0xf2, 0x0e, 0x11, 0x0d,
0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x99, 0xd6, 0x11, 0x0f, 0xf3, 0x0d, 0x0c,
0xf3, 0x11, 0x0e, 0xf3, 0xf4, 0x0c, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x0a, 0x01, 0x0b, 0x19,
0x18, 0xf0, 0x60, 0x11, 0x01, 0x11, 0x01, 0x01, 0x01, 0x09, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5,
0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6,
0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3,
0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11,
0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1,
0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01,
0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff,
0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x20,
0xff, 0xff, 0x00, 0x11, 0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xdd, 0x0e, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f,
0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f,
0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4,
0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18,
0xf4, 0x60, 0x00, 0x00, 0x00, 0xd0, 0x10, 0xd0, 0x10, 0x10, 0x13, 0x0a, 0x03, 0x4b, 0x04, 0x09,
0x00, 0x10, 0x30, 0x70, 0xf0, 0x70, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x19, 0x0a,
0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x10, 0x84, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x0e, 0xf1,
0xf2, 0x0e, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x99, 0xd6, 0x11,
0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x0e, 0xf3, 0xf4, 0x0c, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11,
0x0a, 0x01, 0x0b, 0x19, 0x18, 0xf0, 0x60, 0x11, 0x01, 0x11, 0x01, 0x01, 0x01, 0x0a, 0x19, 0x0a,
0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f, 0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1,
0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2, 0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10,
0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e, 0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d,
0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6, 0x19, 0x18, 0xf4, 0x20, 0x10, 0x00, 0x00,
0x0f, 0xff, 0x0f, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0x1d, 0xfe, 0xf5, 0x04, 0x08, 0x42, 0x11, 0x0f,
0xf1, 0x0f, 0x0e, 0xf1, 0x11, 0x3e, 0xf1, 0xf2, 0x0e, 0x99, 0xd6, 0x11, 0x0d, 0x01, 0x0d, 0xf2,
0x11, 0x3f, 0x0d, 0x01, 0xf3, 0x0d, 0x10, 0x84, 0x11, 0x0f, 0xf3, 0x0d, 0x0c, 0xf3, 0x11, 0x3e,
0xf3, 0xf4, 0x0c, 0xff, 0xff, 0x11, 0x0d, 0x01, 0x0b, 0xf4, 0x11, 0x3a, 0x01, 0x0b, 0x99, 0xd6,
0x19, 0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0x11, 0x01, 0x11, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10,
0x84, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xce, 0x0e, 0x01, 0x01, 0xff, 0xff,
0x1d, 0x18, 0xf4, 0x60, 0x0e, 0xe2, 0x00, 0x0b, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x0e,
0xce, 0x0f, 0x0f, 0x13, 0x0b, 0x04, 0x4b, 0x04, 0x09, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xe0, 0xc0,
0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x19, 0x0a, 0x01, 0x0d, 0x19, 0x18, 0x50, 0x40, 0x0d,
0x0d, 0x0f, 0x0c, 0x03, 0x4a, 0x07, 0x08, 0x00, 0x02, 0x06, 0x8e, 0xdc, 0xf8, 0x70, 0x20, 0x61,
0x00, 0x19, 0x0a, 0x01, 0x0d, 0x19, 0x18, 0x50, 0x40, 0x0d, 0x0d, 0x0f, 0x0d, 0x04, 0x4a, 0x06,
0x06, 0x78, 0xfc, 0xfc, 0xfc, 0xfc, 0x78, 0x00, 0x00, 0x68, 0x00, 0x19, 0x0a, 0x3d, 0x0d, 0x02,
0x02, 0x99, 0xd6, 0x19, 0x18, 0xd0, 0x60, 0x0e, 0x10, 0x02, 0x02, 0x13, 0x0e, 0x02, 0x4a, 0x0b,
0x05, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x00, 0x3f, 0x80, 0x7f, 0xc0, 0x00, 0x00, 0x35, 0x00, 0x19,
0x0a, 0x01, 0x0f, 0x19, 0x18, 0x54, 0x40, 0x10, 0x00, 0x00, 0x0f, 0x0f, 0x01, 0x0e, 0x19, 0x0a,
0x03, 0xca, 0x0f, 0x19, 0x18, 0xf4, 0x20, 0xff, 0xff, 0x00, 0xcb, 0x10, 0xcb, 0x10, 0x10, 0x11,
0xf4, 0x20, 0x10, 0x84, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x01, 0x0f, 0x19, 0x18,
0x54, 0x40, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x13, 0x0f, 0x02, 0x4a, 0x0b, 0x05, 0x7f, 0xc0, 0x3f,
0x80, 0x1f, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0x00, 0x19, 0x0a, 0x01, 0x0f, 0x19,
0x18, 0x54, 0x40, 0x10, 0x00, 0x00, 0x0f, 0x0f, 0x01, 0x0f, 0x19, 0x0a, 0x01, 0x0f, 0x19, 0x18,
0xf4, 0x20, 0xff, 0xff, 0x00, 0x10, 0x01, 0x10, 0x01, 0x01, 0x11, 0xf4, 0x20, 0x10, 0x84, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x0a, 0x3f, 0xd3, 0x0f, 0xfe, 0xfe, 0xff, 0xff, 0x19, 0x18,
0xf4, 0x60, 0x00, 0x00, 0x00, 0xd3, 0x0f, 0xd1, 0x0d, 0x0d, 0x1b, 0x10, 0x02, 0x4c, 0x0a, 0x0a,
0x1e, 0x00, 0x7f, 0x80, 0x7f, 0x80, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x7f, 0x80,
0x7f, 0x80, 0x1e, 0x00, 0x6e, 0x00, 0x11, 0x00, 0x40, 0x17, 0x11, 0x03, 0x4a, 0x09, 0x08, 0x01,
0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x01, 0x00, 0xc3, 0x00, 0x3c, 0x00, 0x6d,
0x00, 0x11, 0x00, 0x40, 0x17, 0x12, 0x02, 0x4c, 0x09, 0x08, 0x1e, 0x00, 0x61, 0x80, 0x40, 0x00,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x6c, 0x00, 0x11, 0x00, 0x40, 0x1b,
0x13, 0x03, 0x4b, 0x0a, 0x0a, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00,
0x40, 0x00, 0x80, 0x00, 0x80, 0xc3, 0x00, 0x3c, 0x00, 0x6b, 0x00, 0x11, 0x00, 0x40, 0x1b, 0x14,
0x01, 0x4d, 0x0a, 0x0a, 0x0f, 0x00, 0x30, 0xc0, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x80, 0x00,
0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x6a, 0x00, 0x11, 0x54, 0x40, 0xff, 0xff, 0x00,
0x0d, 0x0d, 0x1b, 0x15, 0x02, 0x4b, 0x09, 0x09, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x00, 0x00, 0x67, 0x00, 0x11, 0x04,
0x40, 0x99, 0xd6, 0x00, 0x1f, 0x16, 0x01, 0x4c, 0x0b, 0x0b, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0xff, 0xe0,
0x00, 0x00, 0x66, 0x00, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x1b, 0x17, 0x01, 0x4c, 0x0a, 0x0a,
0xff, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
0x80, 0x00, 0x80, 0x00, 0x65, 0x00, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x23, 0x18, 0x00, 0x4d,
0x0d, 0x0d, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0xff, 0xf8, 0x00, 0x00, 0x64, 0x00,
0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x1f, 0x19, 0x00, 0x4d, 0x0c, 0x0c, 0xff, 0xf0, 0x80, 0x00,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
0x80, 0x00, 0x80, 0x00, 0x63, 0x00, 0x11, 0x54, 0x40, 0xff, 0xff, 0x00, 0x0d, 0x0d, 0x01, 0x15,
0x11, 0x04, 0x40, 0x99, 0xd6, 0x00, 0x01, 0x16, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x17,
0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x19,
0x11, 0x04, 0x40, 0x00, 0x00, 0x00, 0x0f, 0x1a, 0x03, 0x4b, 0x07, 0x08, 0x00, 0x02, 0x06, 0x8e,
0xdc, 0xf8, 0x70, 0x20, 0x62, 0x00, 0x11, 0x54, 0x40, 0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x15,
0x11, 0x00, 0x40, 0x01, 0x16, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x17, 0x11, 0x04, 0x40,
0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x19, 0x11, 0x54, 0x40,
0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x15, 0x11, 0x00, 0x40, 0x01, 0x16, 0x11, 0x04, 0x40, 0x08,
0x42, 0x00, 0x01, 0x17, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04, 0x40, 0x10,
0x84, 0x00, 0x01, 0x19, 0x11, 0x04, 0x40, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x11, 0xf4, 0x60, 0x99,
0xd6, 0x00, 0xcc, 0x0d, 0xcc, 0x0d, 0x0d, 0x01, 0x15, 0x11, 0x00, 0x40, 0x01, 0x16, 0x11, 0x04,
0x40, 0x08, 0x42, 0x00, 0x01, 0x17, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04,
0x40, 0x10, 0x84, 0x00, 0x01, 0x19, 0x11, 0x00, 0x40, 0x01, 0x1a, 0x19, 0x0a, 0x33, 0x0d, 0x0d,
0x00, 0x00, 0x19, 0x18, 0x54, 0x40, 0xff, 0xff, 0x00, 0x0d, 0x0d, 0x01, 0x10, 0x11, 0x04, 0x40,
0x99, 0xd6, 0x00, 0x01, 0x11, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x12, 0x11, 0x04, 0x40,
0xff, 0xff, 0x00, 0x01, 0x13, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x14, 0x19, 0x0a, 0x01,
0x0d, 0x19, 0x18, 0x54, 0x40, 0xff, 0xff, 0x00, 0x0d, 0x0d, 0x01, 0x10, 0x11, 0x04, 0x40, 0x99,
0xd6, 0x00, 0x01, 0x11, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x12, 0x11, 0x04, 0x40, 0xff,
0xff, 0x00, 0x01, 0x13, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x14, 0x11, 0x04, 0x40, 0x00,
0x00, 0x00, 0x0b, 0x1b, 0x05, 0x49, 0x04, 0x04, 0x60, 0xf0, 0xf0, 0x60, 0x69, 0x00, 0x19, 0x0a,
0x01, 0x0d, 0x19, 0x18, 0x54, 0x40, 0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x10, 0x11, 0x00, 0x40,
0x01, 0x11, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x12, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00,
0x01, 0x13, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x14, 0x19, 0x0a, 0x01, 0x0d, 0x19, 0x18,
0x54, 0x40, 0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x10, 0x11, 0x00, 0x40, 0x01, 0x11, 0x11, 0x04,
0x40, 0x08, 0x42, 0x00, 0x01, 0x12, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x01, 0x13, 0x11, 0x04,
0x40, 0x10, 0x84, 0x00, 0x01, 0x14, 0x11, 0x04, 0x40, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x19, 0x0a,
0x03, 0xcc, 0x0d, 0x19, 0x18, 0xf4, 0x60, 0x99, 0xd6, 0x00, 0xcc, 0x0d, 0xcc, 0x0d, 0x0d, 0x01,
0x10, 0x11, 0x00, 0x40, 0x01, 0x11, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x12, 0x11, 0x04,
0x40, 0xff, 0xff, 0x00, 0x01, 0x13, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x14, 0x11, 0x00,
0x40, 0x01, 0x1b, 0x03, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x08, 0x08, 0x81, 0x08, 0xaa,
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0x09, 0x01, 0x7f, 0x02, 0x0d, 0x00, 0x1a, 0x01, 0x0d,
0x00, 0x0d, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x99, 0xd6, 0x00, 0x81, 0x19, 0x18, 0x54, 0x40, 0x99,
0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x16, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x17, 0x11, 0x04,
0x40, 0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x19, 0x11, 0x00,
0x40, 0x01, 0x1a, 0x11, 0x54, 0x40, 0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x15, 0x11, 0x00, 0x40,
0x01, 0x16, 0x11, 0x04, 0x40, 0x08, 0x42, 0x00, 0x01, 0x17, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00,
0x01, 0x18, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x01, 0x19, 0x11, 0x00, 0x40, 0x01, 0x1a, 0x11,
0x54, 0x40, 0x99, 0xd6, 0x00, 0x0d, 0x0d, 0x01, 0x15, 0x11, 0x00, 0x40, 0x01, 0x16, 0x11, 0x04,
0x40, 0x08, 0x42, 0x00, 0x01, 0x17, 0x11, 0x04, 0x40, 0xff, 0xff, 0x00, 0x01, 0x18, 0x11, 0x04,
0x40, 0x10, 0x84, 0x00, 0x01, 0x19, 0x11, 0x00, 0x40, 0x01, 0x1a, 0x19, 0x0a, 0x31, 0x34, 0xff,
0xff, 0x19, 0x18, 0x54, 0x40, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x1b, 0x1c, 0x02, 0x4b, 0x09, 0x09,
0xc1, 0x80, 0xe3, 0x80, 0x77, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x3e, 0x00, 0x77, 0x00, 0xe3, 0x80,
0xc1, 0x80, 0x00, 0x00, 0x72, 0x00, 0x19, 0x0a, 0x03, 0xcc, 0x0d, 0x1d, 0x18, 0xf0, 0x60, 0xa0,
0x45, 0x45, 0xcc, 0x0d, 0xcc, 0x0d, 0x0d, 0x1b, 0x1d, 0x01, 0x4b, 0x0a, 0x09, 0x3f, 0xc0, 0x3f,
0xc0, 0x20, 0x40, 0xff, 0x40, 0xff, 0x40, 0x81, 0xc0, 0x81, 0x00, 0x81, 0x00, 0xff, 0x00, 0x00,
0x00, 0x32, 0x00, 0x19, 0x0a, 0x01, 0x0d, 0x19, 0x18, 0x50, 0x40, 0x0d, 0x0d, 0x1b, 0x1e, 0x01,
0x4c, 0x0a, 0x0a, 0xff, 0xc0, 0xff, 0xc0, 0x80, 0x40, 0x80, 0x40, 0x80, 0x40, 0x80, 0x40, 0x80,
0x40, 0x80, 0x40, 0x80, 0x40, 0xff, 0xc0, 0x31, 0x00, 0x19, 0x0a, 0x01, 0x0d, 0x19, 0x18, 0x50,
0x40, 0x0d, 0x0d, 0x0b, 0x1f, 0x02, 0x44, 0x07, 0x02, 0xfe, 0xfe, 0x00, 0x00, 0x30, 0x00, 0x19,
0x0a, 0x3d, 0x0d, 0x03, 0x03, 0x99, 0xd6, 0x19, 0x18, 0xd4, 0x60, 0xff, 0xff, 0x00, 0x0e, 0x11,
0x03, 0x03, 0x23, 0x20, 0x00, 0x4d, 0x0d, 0x0d, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00,
0x10, 0x00, 0x88, 0x00, 0x44, 0x00, 0x22, 0x00, 0x11, 0x00, 0x88, 0x80, 0x44, 0x40, 0x22, 0x20,
0x11, 0x10, 0x00, 0x00, 0x78, 0x00, 0x11, 0x04, 0x40, 0x10, 0x84, 0x00, 0x1f, 0x21, 0x00, 0x4c,
0x0c, 0x0c, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x98, 0x00, 0xcc, 0x00,
0x66, 0x00, 0x33, 0x00, 0x99, 0x80, 0xcc, 0xc0, 0x66, 0x60, 0x79, 0x00, 0x19, 0x0a, 0x3d, 0x10,
0xfd, 0xfd, 0xff, 0xff, 0x19, 0x18, 0xd4, 0x60, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0xfd, 0xfd, 0x13,
0x22, 0x05, 0x4b, 0x04, 0x09, 0x00, 0x10, 0x30, 0x70, 0xf0, 0x70, 0x30, 0x10, 0x00, 0x00, 0x00,
0x00, 0x77, 0x00, 0x02, 0xff, 0xff, 0x0d, 0x0a, 0x3f, 0x0e, 0x00, 0x00, 0xff, 0x03, 0xff, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x06, 0x02, 0x00, 0x48, 0x00, 0x37,
0x01, 0x02, 0x02, 0x00, 0x09, 0x00, 0x0c, 0x48, 0x00, 0x37, 0x01, 0x03, 0xcf, 0x04, 0xa2, 0x0c,
0x05, 0x40, 0x44, 0xd1, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00,
0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00,
0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84, 0x08, 0x42, 0xff, 0xff, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84,
0xff, 0xff, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84,
0xff, 0xff, 0x99, 0xd6, 0x10, 0x84, 0x08, 0x42, 0x1c, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x75, 0xc6, 0x66, 0x29, 0x00, 0x09, 0x68, 0x10, 0x00, 0x08, 0x68, 0x10, 0x84,
0x00, 0x20, 0x00, 0x07, 0x6b, 0x99, 0xd6, 0x05, 0x6b, 0x99, 0xd6, 0x00, 0x03, 0x6e, 0xff, 0xff,
0x02, 0x6e, 0xff, 0xff, 0x00, 0x10, 0xc0, 0x00, 0xf7, 0xbd, 0x01, 0xc0, 0x00, 0x08, 0x42, 0xc0,
0x00, 0xff, 0xff, 0x81, 0x08, 0x42, 0xce, 0x66, 0x29, 0x01, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd,
0x2e, 0x01, 0x81, 0x08, 0x42, 0xce, 0x66, 0x29, 0x02, 0x81, 0x10, 0x84, 0x06, 0x82, 0x00, 0x00,
0x00, 0x00, 0x07, 0xcd, 0x89, 0x52, 0x03, 0x2d, 0x03, 0x83, 0x10, 0x84, 0x99, 0xd6, 0x99, 0xd6,
0xc9, 0x99, 0xd6, 0x1a, 0x82, 0x10, 0x00, 0x10, 0x00, 0x0a, 0x29, 0x09, 0x27, 0x0c, 0x67, 0x99,
0xd6, 0x15, 0x27, 0x1d, 0x82, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x67, 0x99, 0xd6, 0x00, 0x19, 0xd0,
0x30, 0x89, 0xd6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x99, 0xd6, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x83, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xd8, 0x89,
0xd6, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x83, 0x99, 0xd6, 0x10, 0x00, 0x10,
0x00, 0x1a, 0x68, 0x00, 0x00, 0x09, 0x86, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x99, 0xd6, 0x18, 0x68, 0x00, 0x00, 0x1b, 0x68, 0x99, 0xd6, 0x06, 0x86, 0x99, 0xd6, 0x10,
0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x99, 0xd6, 0x19, 0x6b, 0x99, 0xd6, 0x03, 0xcc, 0x89,
0x52, 0x08, 0x68, 0x99, 0xd6, 0x05, 0x6b, 0x99, 0xd6, 0x04, 0x2c, 0x03, 0x6e, 0x08, 0x42, 0x02,
0x6e, 0xff, 0xff, 0x02, 0x6e, 0xff, 0xff, 0x02, 0x6e, 0x08, 0x42, 0x10, 0x81, 0x08, 0x42, 0x70,
0xff, 0xff, 0x60, 0x00, 0x08, 0x42, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0x81, 0x08, 0x42, 0xce, 0x66,
0x29, 0x01, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd, 0x2e, 0x02, 0xcd, 0x89, 0x52, 0x03, 0x89, 0x10,
0x84, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x2d, 0x03, 0x2d, 0x05, 0xc6, 0x99, 0xd6, 0x0c, 0x84, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x99, 0xd6, 0x0a, 0xc6, 0x89, 0xd6, 0x0e, 0x82, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x84, 0x99,
0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x1c, 0x40, 0x35, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xd0, 0x4e, 0x99, 0xd6, 0x03, 0x00, 0x00, 0x60, 0x00, 0x80, 0x01, 0x78, 0x01, 0x00, 0x82,
0x10, 0x00, 0x10, 0x00, 0x0c, 0x40, 0x2c, 0x03, 0xe0, 0x05, 0x00, 0x00, 0x00, 0xd6, 0x89, 0xd6,
0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x4e, 0x99, 0xd6, 0x3b, 0x00, 0x00, 0x00, 0x28, 0x80,
0x1d, 0x00, 0x78, 0x00, 0x86, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x0c, 0x85, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x40, 0x2b, 0x01,
0xf0, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x89, 0xd6, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x99,
0xd6, 0x16, 0x86, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x0a,
0x69, 0x99, 0xd6, 0x04, 0xcc, 0x89, 0x52, 0x07, 0x69, 0x99, 0xd6, 0x08, 0x68, 0x99, 0xd6, 0x03,
0x6e, 0xff, 0xff, 0x02, 0x6e, 0x08, 0x42, 0x02, 0x6e, 0xff, 0xff, 0x02, 0x6e, 0xff, 0xff, 0x01,
0x70, 0x08, 0x42, 0x70, 0xff, 0xff, 0x60, 0x00, 0x08, 0x42, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0x81,
0x08, 0x42, 0xce, 0x66, 0x29, 0x01, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd, 0x2e, 0x02, 0xcd, 0x89,
0x52, 0x03, 0x8a, 0x10, 0x84, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x2d, 0x03, 0x8d, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x99, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99,
0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x06, 0xc6, 0x99, 0xd6, 0x1a, 0xc6, 0x89, 0xd6, 0x0a, 0x66, 0x10,
0x84, 0x1b, 0x6a, 0x99, 0xd6, 0x1b, 0x81, 0x99, 0xd6, 0x09, 0x6a, 0x99, 0xd6, 0x16, 0x6a, 0x99,
0xd6, 0x06, 0x6a, 0x99, 0xd6, 0xf0, 0x94, 0x01, 0xcc, 0x89, 0x52, 0x00, 0x03, 0x6e, 0xff, 0xff,
0x02, 0x6e, 0x08, 0x42, 0x02, 0x6e, 0xff, 0xff, 0x02, 0x6e, 0xff, 0xff, 0x01, 0x70, 0x08, 0x42,
0x70, 0xff, 0xff, 0x60, 0x00, 0x08, 0x42, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0x81, 0x08, 0x42, 0xce,
0x66, 0x29, 0x01, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd, 0x2e, 0x02, 0xcd, 0x89, 0x52, 0x03, 0x10,
0x2d, 0x03, 0x2d, 0x17, 0x88, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x00, 0x00, 0x00, 0x00, 0x18, 0x88, 0xff, 0xff, 0xff, 0xff, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x99, 0xd6, 0xff, 0xff, 0xff, 0xff, 0x07, 0x88, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99,
0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x09, 0x88, 0x99, 0xd6, 0x00, 0x00, 0x00,
0x00, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x07, 0x88, 0x10, 0x00, 0x10,
0x00, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00, 0x10, 0x00, 0x08, 0x89, 0x10,
0x84, 0x10, 0x84, 0xff, 0xff, 0xff, 0xff, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84, 0x10, 0x84, 0x99,
0xd6, 0x07, 0x88, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00,
0x00, 0x99, 0xd6, 0x0a, 0x86, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0xd6, 0x08, 0x88, 0x99, 0xd6, 0x10, 0x00, 0x10, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00, 0x10,
0x00, 0x99, 0xd6, 0x08, 0x88, 0x99, 0xd6, 0x10, 0x84, 0x10, 0x84, 0xff, 0xff, 0xff, 0xff, 0x10,
0x84, 0x10, 0x84, 0x99, 0xd6, 0x09, 0x86, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x99, 0xd6, 0x0c, 0x84, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x0a, 0x86, 0x99,
0xd6, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x99, 0xd6, 0x0a, 0x86, 0x99, 0xd6, 0x10,
0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x99, 0xd6, 0x0b, 0x84, 0x99, 0xd6, 0x00, 0x00, 0x00,
0x00, 0x99, 0xd6, 0x0d, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x84, 0x99,
0xd6, 0x10, 0x00, 0x10, 0x00, 0x99, 0xd6, 0x0c, 0x85, 0x99, 0xd6, 0x10, 0x84, 0x10, 0x84, 0xff,
0xff, 0xff, 0xff, 0x0b, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x86, 0x00,
0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x84, 0x10, 0x00, 0x10,
0x00, 0x10, 0x00, 0x10, 0x00, 0x0c, 0x86, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0xff,
0xff, 0xff, 0xff, 0x09, 0x86, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x88, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x00,
0x00, 0x00, 0x00, 0x08, 0x86, 0x10, 0x00, 0x10, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00, 0x10,
0x00, 0x0a, 0x88, 0x10, 0x84, 0x10, 0x84, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84, 0x10, 0x84, 0xff,
0xff, 0xff, 0xff, 0x07, 0x88, 0x00, 0x00, 0x00, 0x00, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99,
0xd6, 0x00, 0x00, 0x00, 0x00, 0x09, 0x6a, 0x99, 0xd6, 0x05, 0x88, 0x10, 0x00, 0x10, 0x00, 0x99,
0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x00, 0x10, 0x00, 0x08, 0x89, 0x10, 0x84, 0x10,
0x84, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x10, 0x84, 0x10, 0x84, 0x99, 0xd6, 0x07,
0x6a, 0x99, 0xd6, 0x16, 0x6a, 0x99, 0xd6, 0x06, 0x6a, 0x99, 0xd6, 0x14, 0x2c, 0x00, 0x03, 0x6e,
0xff, 0xff, 0x02, 0x6e, 0x08, 0x42, 0x02, 0x6e, 0xff, 0xff, 0x02, 0xcb, 0x66, 0x29, 0x84, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x42, 0x09, 0x0d, 0xdf, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x03, 0x15, 0x00, 0xa2, 0x0c,
0x05, 0x40, 0x40, 0x17, 0xff, 0xff, 0x00, 0x1c, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0xbc, 0x0f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x0a, 0x40,
0xc8, 0x03, 0xf4, 0x00, 0xa2, 0x0c, 0x05, 0x40, 0x40, 0xf6, 0xff, 0xff, 0xc0, 0x2c, 0x2d, 0x09,
0x84, 0x2d, 0x09, 0x2d, 0x09, 0x2d, 0x09, 0x2d, 0x09, 0x00, 0x22, 0xc0, 0x10, 0x25, 0x4b, 0x02,
0x30, 0x02, 0x2a, 0x02, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd, 0x2e, 0x03, 0xfd, 0x2e, 0x03, 0xfd,
0x29, 0x03, 0xcd, 0x89, 0x52, 0x03, 0x2d, 0x05, 0x2d, 0x05, 0x29, 0x06, 0xc6, 0x99, 0xd6, 0x09,
0x29, 0x1f, 0x43, 0x03, 0x00, 0x00, 0x01, 0x27, 0x0b, 0x44, 0xc3, 0x00, 0x00, 0xc0, 0x68, 0x99,
0xd6, 0x18, 0x48, 0xa5, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x5a, 0x00, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xa0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x81, 0x99, 0xd6, 0x48, 0x05, 0x80, 0x05, 0x00, 0x00, 0xfc,
0x01, 0x50, 0x40, 0x69, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x80, 0x06, 0x00,
0x00, 0x02, 0x6a, 0x99, 0xd6, 0x1c, 0x86, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0x2d,
0x09, 0x2d, 0x09, 0x6f, 0xff, 0xff, 0x02, 0x6e, 0xff, 0xff, 0x04, 0x6e, 0xff, 0xff, 0x04, 0xc9,
0x66, 0x29, 0x02, 0x60, 0x5e, 0x2d, 0x09, 0xc0, 0x30, 0x2d, 0x09, 0xf0, 0xc0, 0x09, 0xc0, 0x10,
0x08, 0x42, 0x00, 0x00, 0xfd, 0xce, 0x18, 0xc6, 0x01, 0xfd, 0x2e, 0x00, 0x02, 0xcd, 0x89, 0x52,
0x03, 0x83, 0x99, 0xd6, 0x99, 0xd6, 0x99, 0xd6, 0xc9, 0xef, 0x7b, 0x81, 0x99, 0xd6, 0x00, 0x05,
0xc9, 0x89, 0xd6, 0x07, 0x69, 0x10, 0x84, 0x00, 0x08, 0x27, 0x09, 0x82, 0xff, 0xff, 0x99, 0xd6,
0xd0, 0x69, 0x89, 0x52, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x51, 0x0e, 0xc0, 0x40, 0x38, 0x03, 0xa8, 0x00, 0xa2, 0x0c, 0x05, 0x40, 0x40, 0xaa,
0xff, 0xff, 0xc8, 0x2d, 0x09, 0x00, 0x14, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0xc6, 0x25, 0x4b, 0x00, 0x1a, 0xd8, 0x18, 0xc6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf7, 0xc0, 0x01, 0x89, 0x52, 0x0f, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7,
0x00, 0x01, 0x99, 0xd6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x3b, 0xef,
0x7b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x2d, 0x09, 0x00, 0x58, 0xf3, 0x7c,
0x0b, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x0a, 0x40, 0xc8,
};
int TestFreeRDPCodecMppc(int argc, char* argv[])
{
BOOL status;
UINT32 roff;
UINT32 rlen;
struct rdp_mppc_enc* enc;
struct rdp_mppc_dec* rmppc;
/* Decompression */
rmppc = mppc_dec_new();
status = decompress_rdp_5(rmppc, TEST_RDP5_COMPRESSED_DATA,
sizeof(TEST_RDP5_COMPRESSED_DATA), PACKET_COMPRESSED, &roff, &rlen);
if (!status)
{
printf("RDP5 decompression failure: %d\n", status);
return -1;
}
if (memcmp(TEST_RDP5_UNCOMPRESSED_DATA, rmppc->history_buf, sizeof(TEST_RDP5_UNCOMPRESSED_DATA)) != 0)
{
printf("RDP5 decompression failure\n");
return -1;
}
mppc_dec_free(rmppc);
rmppc = mppc_dec_new();
/* Compression */
enc = mppc_enc_new(PROTO_RDP_50);
status = compress_rdp(enc, TEST_RDP5_UNCOMPRESSED_DATA, sizeof(TEST_RDP5_UNCOMPRESSED_DATA));
if (!status)
{
printf("RDP5 decompression failure: %d\n", status);
return -1;
}
if (enc->flags & PACKET_COMPRESSED)
{
status = decompress_rdp_5(rmppc, (BYTE*) enc->outputBuffer,
enc->bytes_in_opb, enc->flags, &roff, &rlen);
if (!status)
{
printf("RDP5 compression/decompression failure: %d\n", status);
return -1;
}
if (rlen != sizeof(TEST_RDP5_UNCOMPRESSED_DATA))
{
printf("RDP5 compression/decompression failure: size mismatch: Actual: %d, Expected: %d\n",
rlen, sizeof(TEST_RDP5_UNCOMPRESSED_DATA));
return -1;
}
if (memcmp(TEST_RDP5_UNCOMPRESSED_DATA, &rmppc->history_buf[roff], rlen) != 0)
{
printf("RDP5 compression/decompression failure\n");
return -1;
}
}
if (enc->bytes_in_opb != sizeof(TEST_RDP5_UNCOMPRESSED_DATA))
{
printf("RDP5 decompression failure: size mismatch: Actual: %d, Expected: %d\n",
enc->bytes_in_opb, sizeof(TEST_RDP5_UNCOMPRESSED_DATA));
return -1;
}
if (memcmp(TEST_RDP5_COMPRESSED_DATA, enc->outputBuffer, sizeof(TEST_RDP5_COMPRESSED_DATA)) != 0)
{
printf("RDP5 decompression failure\n");
return -1;
}
mppc_enc_free(enc);
mppc_dec_free(rmppc);
return 0;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -665,6 +665,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
return settings->IgnoreCertificate; return settings->IgnoreCertificate;
break; break;
case FreeRDP_ExternalCertificateManagement:
return settings->ExternalCertificateManagement;
break;
case FreeRDP_Workarea: case FreeRDP_Workarea:
return settings->Workarea; return settings->Workarea;
break; break;
@ -1129,6 +1133,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->IgnoreCertificate = param; settings->IgnoreCertificate = param;
break; break;
case FreeRDP_ExternalCertificateManagement:
settings->ExternalCertificateManagement = param;
break;
case FreeRDP_Workarea: case FreeRDP_Workarea:
settings->Workarea = param; settings->Workarea = param;
break; break;

View File

@ -83,6 +83,12 @@ set(${MODULE_PREFIX}_SRCS
connection.h connection.h
redirection.c redirection.c
redirection.h redirection.h
autodetect.c
autodetect.h
heartbeat.c
heartbeat.h
multitransport.c
multitransport.h
timezone.c timezone.c
timezone.h timezone.h
rdp.c rdp.c

View File

@ -368,7 +368,8 @@ BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s)
if (!rdp_send_server_font_map_pdu(rdp)) if (!rdp_send_server_font_map_pdu(rdp))
return FALSE; return FALSE;
rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); if (rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE) < 0)
return FALSE;
return TRUE; return TRUE;
} }

View File

@ -0,0 +1,288 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Auto-Detect PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//#define WITH_DEBUG_AUTODETECT
#include "autodetect.h"
typedef struct
{
UINT8 headerLength;
UINT8 headerTypeId;
UINT16 sequenceNumber;
UINT16 requestType;
} AUTODETECT_REQ_PDU;
static BOOL autodetect_send_rtt_measure_response(rdpRdp* rdp, UINT16 sequenceNumber)
{
wStream* s;
/* Send the response PDU to the server */
s = rdp_message_channel_pdu_init(rdp);
if (s == NULL) return FALSE;
DEBUG_AUTODETECT("sending RTT Measure Response PDU");
Stream_Write_UINT8(s, 0x06); /* headerLength (1 byte) */
Stream_Write_UINT8(s, TYPE_ID_AUTODETECT_RESPONSE); /* headerTypeId (1 byte) */
Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
Stream_Write_UINT16(s, 0x0000); /* responseType (1 byte) */
return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
}
static BOOL autodetect_send_bandwidth_measure_results(rdpRdp* rdp, UINT16 responseType, UINT16 sequenceNumber)
{
UINT32 timeDelta;
wStream* s;
/* Compute the total time */
timeDelta = GetTickCount() - rdp->autodetect->bandwidthMeasureStartTime;
/* Send the result PDU to the server */
s = rdp_message_channel_pdu_init(rdp);
if (s == NULL) return FALSE;
DEBUG_AUTODETECT("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) */
Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
Stream_Write_UINT16(s, responseType); /* responseType (1 byte) */
Stream_Write_UINT32(s, timeDelta); /* timeDelta (4 bytes) */
Stream_Write_UINT32(s, rdp->autodetect->bandwidthMeasureByteCount); /* byteCount (4 bytes) */
return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
}
static BOOL autodetect_send_netchar_sync(rdpRdp* rdp, UINT16 sequenceNumber)
{
wStream* s;
/* Send the response PDU to the server */
s = rdp_message_channel_pdu_init(rdp);
if (s == NULL) return FALSE;
DEBUG_AUTODETECT("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) */
Stream_Write_UINT16(s, sequenceNumber); /* sequenceNumber (2 bytes) */
Stream_Write_UINT16(s, 0x0018); /* responseType (1 byte) */
Stream_Write_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
Stream_Write_UINT32(s, rdp->autodetect->netCharAverageRTT); /* rtt (4 bytes) */
return rdp_send_message_channel_pdu(rdp, s, SEC_AUTODETECT_RSP);
}
static BOOL autodetect_recv_rtt_measure_request(rdpRdp* rdp, wStream* s, AUTODETECT_REQ_PDU* autodetectReqPdu)
{
if (autodetectReqPdu->headerLength != 0x06)
return FALSE;
DEBUG_AUTODETECT("received RTT Measure Request PDU");
/* Send a response to the server */
return autodetect_send_rtt_measure_response(rdp, autodetectReqPdu->sequenceNumber);
}
static BOOL autodetect_recv_bandwidth_measure_start(rdpRdp* rdp, wStream* s, AUTODETECT_REQ_PDU* autodetectReqPdu)
{
if (autodetectReqPdu->headerLength != 0x06)
return FALSE;
DEBUG_AUTODETECT("received Bandwidth Measure Start PDU - time=%lu", GetTickCount());
/* Initialize bandwidth measurement parameters */
rdp->autodetect->bandwidthMeasureStartTime = GetTickCount();
rdp->autodetect->bandwidthMeasureByteCount = 0;
return TRUE;
}
static BOOL autodetect_recv_bandwidth_measure_payload(rdpRdp* rdp, wStream* s, AUTODETECT_REQ_PDU* autodetectReqPdu)
{
UINT16 payloadLength;
if (autodetectReqPdu->headerLength != 0x08)
return FALSE;
if (Stream_GetRemainingLength(s) < 2)
return FALSE;
Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
DEBUG_AUTODETECT("received Bandwidth Measure Payload PDU -> payloadLength=%u", payloadLength);
/* Add the payload length to the bandwidth measurement parameters */
rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
return TRUE;
}
static BOOL autodetect_recv_bandwidth_measure_stop(rdpRdp* rdp, wStream* s, AUTODETECT_REQ_PDU* autodetectReqPdu)
{
UINT16 payloadLength;
UINT16 responseType;
if (autodetectReqPdu->requestType == 0x002B)
{
if (autodetectReqPdu->headerLength != 0x08)
return FALSE;
if (Stream_GetRemainingLength(s) < 2)
return FALSE;
Stream_Read_UINT16(s, payloadLength); /* payloadLength (2 bytes) */
}
else
{
if (autodetectReqPdu->headerLength != 0x06)
return FALSE;
payloadLength = 0;
}
DEBUG_AUTODETECT("received Bandwidth Measure Stop PDU -> payloadLength=%u", payloadLength);
/* Add the payload length to the bandwidth measurement parameters */
rdp->autodetect->bandwidthMeasureByteCount += payloadLength;
/* Send a response the server */
responseType = autodetectReqPdu->requestType == 0x002B ? 0x0003 : 0x000B;
return autodetect_send_bandwidth_measure_results(rdp, responseType, autodetectReqPdu->sequenceNumber);
}
static BOOL autodetect_recv_netchar_result(rdpRdp* rdp, wStream* s, AUTODETECT_REQ_PDU* autodetectReqPdu)
{
switch (autodetectReqPdu->requestType)
{
case 0x0840:
/* baseRTT and averageRTT fields are present (bandwidth field is not) */
if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
return FALSE;
Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
break;
case 0x0880:
/* bandwidth and averageRTT fields are present (baseRTT field is not) */
if ((autodetectReqPdu->headerLength != 0x0E) || (Stream_GetRemainingLength(s) < 8))
return FALSE;
Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
break;
case 0x08C0:
/* baseRTT, bandwidth, and averageRTT fields are present */
if ((autodetectReqPdu->headerLength != 0x12) || (Stream_GetRemainingLength(s) < 12))
return FALSE;
Stream_Read_UINT32(s, rdp->autodetect->netCharBaseRTT); /* baseRTT (4 bytes) */
Stream_Read_UINT32(s, rdp->autodetect->netCharBandwidth); /* bandwidth (4 bytes) */
Stream_Read_UINT32(s, rdp->autodetect->netCharAverageRTT); /* averageRTT (4 bytes) */
break;
}
DEBUG_AUTODETECT("received Network Characteristics Result PDU -> baseRTT=%u, bandwidth=%u, averageRTT=%u", rdp->autodetect->netCharBaseRTT, rdp->autodetect->netCharBandwidth, rdp->autodetect->netCharAverageRTT);
return TRUE;
}
int rdp_recv_autodetect_packet(rdpRdp* rdp, wStream* s)
{
AUTODETECT_REQ_PDU autodetectReqPdu;
BOOL success = FALSE;
if (Stream_GetRemainingLength(s) < 6)
return -1;
Stream_Read_UINT8(s, autodetectReqPdu.headerLength); /* headerLength (1 byte) */
Stream_Read_UINT8(s, autodetectReqPdu.headerTypeId); /* headerTypeId (1 byte) */
Stream_Read_UINT16(s, autodetectReqPdu.sequenceNumber); /* sequenceNumber (2 bytes) */
Stream_Read_UINT16(s, autodetectReqPdu.requestType); /* requestType (2 bytes) */
DEBUG_AUTODETECT(
"rdp_recv_autodetect_packet: headerLength=%u, headerTypeId=%u, sequenceNumber=%u, requestType=%04x",
autodetectReqPdu.headerLength, autodetectReqPdu.headerTypeId,
autodetectReqPdu.sequenceNumber, autodetectReqPdu.requestType);
if (autodetectReqPdu.headerTypeId != TYPE_ID_AUTODETECT_REQUEST)
return -1;
switch (autodetectReqPdu.requestType)
{
case 0x0001:
case 0x1001:
/* RTT Measure Request (RDP_RTT_REQUEST) - MS-RDPBCGR 2.2.14.1.1 */
success = autodetect_recv_rtt_measure_request(rdp, s, &autodetectReqPdu);
break;
case 0x0014:
case 0x0114:
case 0x1014:
/* Bandwidth Measure Start (RDP_BW_START) - MS-RDPBCGR 2.2.14.1.2 */
success = autodetect_recv_bandwidth_measure_start(rdp, s, &autodetectReqPdu);
break;
case 0x0002:
/* Bandwidth Measure Payload (RDP_BW_PAYLOAD) - MS-RDPBCGR 2.2.14.1.3 */
success = autodetect_recv_bandwidth_measure_payload(rdp, s, &autodetectReqPdu);
break;
case 0x002B:
case 0x0429:
case 0x0629:
/* Bandwidth Measure Stop (RDP_BW_STOP) - MS-RDPBCGR 2.2.14.1.4 */
success = autodetect_recv_bandwidth_measure_stop(rdp, s, &autodetectReqPdu);
break;
case 0x0840:
case 0x0880:
case 0x08C0:
/* Network Characteristics Result (RDP_NETCHAR_RESULT) - MS-RDPBCGR 2.2.14.1.5 */
success = autodetect_recv_netchar_result(rdp, s, &autodetectReqPdu);
break;
default:
break;
}
return success ? 0 : -1;
}
rdpAutoDetect* autodetect_new(void)
{
rdpAutoDetect* autodetect = (rdpAutoDetect*)malloc(sizeof(rdpAutoDetect));
if (autodetect)
{
memset(autodetect, 0, sizeof(rdpAutoDetect));
}
return autodetect;
}
void autodetect_free(rdpAutoDetect* autodetect)
{
free(autodetect);
}

View File

@ -0,0 +1,58 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Auto-Detect PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __AUTODETECT_H
#define __AUTODETECT_H
typedef struct rdp_autodetect rdpAutoDetect;
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#define TYPE_ID_AUTODETECT_REQUEST 0x00
#define TYPE_ID_AUTODETECT_RESPONSE 0x01
struct rdp_autodetect
{
/* Bandwidth measurement */
UINT32 bandwidthMeasureStartTime;
UINT32 bandwidthMeasureByteCount;
/* Network characteristics (as reported by server) */
UINT32 netCharBandwidth;
UINT32 netCharBaseRTT;
UINT32 netCharAverageRTT;
};
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
#endif /* __AUTODETECT_H */

View File

@ -2387,13 +2387,15 @@ BOOL rdp_print_large_pointer_capability_set(wStream* s, UINT16 length)
BOOL rdp_read_surface_commands_capability_set(wStream* s, UINT16 length, rdpSettings* settings) BOOL rdp_read_surface_commands_capability_set(wStream* s, UINT16 length, rdpSettings* settings)
{ {
UINT32 cmdFlags;
if (length < 12) if (length < 12)
return FALSE; return FALSE;
Stream_Seek_UINT32(s); /* cmdFlags (4 bytes) */ Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
Stream_Seek_UINT32(s); /* reserved (4 bytes) */ Stream_Seek_UINT32(s); /* reserved (4 bytes) */
settings->SurfaceCommandsEnabled = TRUE; settings->SurfaceCommandsEnabled = TRUE;
settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER);
return TRUE; return TRUE;
} }
@ -2414,9 +2416,10 @@ void rdp_write_surface_commands_capability_set(wStream* s, rdpSettings* settings
header = rdp_capability_set_start(s); header = rdp_capability_set_start(s);
cmdFlags = SURFCMDS_FRAME_MARKER | cmdFlags = SURFCMDS_SET_SURFACE_BITS |
SURFCMDS_SET_SURFACE_BITS |
SURFCMDS_STREAM_SURFACE_BITS; SURFCMDS_STREAM_SURFACE_BITS;
if (settings->SurfaceFrameMarkerEnabled)
cmdFlags |= SURFCMDS_FRAME_MARKER;
Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */ Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */ Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */
@ -3386,9 +3389,14 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId)
if (*pChannelId != MCS_GLOBAL_CHANNEL_ID) if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
{ {
fprintf(stderr, "expected MCS_GLOBAL_CHANNEL_ID %04x, got %04x\n", MCS_GLOBAL_CHANNEL_ID, *pChannelId); UINT16 mcsMessageChannelId = rdp->mcs->message_channel_id;
if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
{
fprintf(stderr, "unexpected MCS channel id %04x received\n", *pChannelId);
return FALSE; return FALSE;
} }
}
return TRUE; return TRUE;
} }

View File

@ -581,6 +581,31 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
rdp->mcs->global_channel_joined = TRUE; rdp->mcs->global_channel_joined = TRUE;
if (rdp->mcs->message_channel_id != 0)
{
if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->message_channel_id))
return FALSE;
all_joined = FALSE;
}
else
{
if (rdp->settings->ChannelCount > 0)
{
if (!mcs_send_channel_join_request(rdp->mcs, rdp->settings->ChannelDefArray[0].ChannelId))
return FALSE;
all_joined = FALSE;
}
}
}
else if ((rdp->mcs->message_channel_id != 0) && !rdp->mcs->message_channel_joined)
{
if (channel_id != rdp->mcs->message_channel_id)
return FALSE;
rdp->mcs->message_channel_joined = TRUE;
if (rdp->settings->ChannelCount > 0) if (rdp->settings->ChannelCount > 0)
{ {
if (!mcs_send_channel_join_request(rdp->mcs, rdp->settings->ChannelDefArray[0].ChannelId)) if (!mcs_send_channel_join_request(rdp->mcs, rdp->settings->ChannelDefArray[0].ChannelId))
@ -626,6 +651,33 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
return TRUE; return TRUE;
} }
BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream *s)
{
BYTE* mark;
UINT16 length;
UINT16 channelId;
/* If the MCS message channel has been joined... */
if (rdp->mcs->message_channel_id != 0)
{
/* Process any MCS message channel PDUs. */
Stream_GetPointer(s, mark);
if (rdp_read_header(rdp, s, &length, &channelId))
{
if (channelId == rdp->mcs->message_channel_id)
{
if (rdp_recv_message_channel_pdu(rdp, s) == 0)
return TRUE;
}
}
Stream_SetPointer(s, mark);
}
return FALSE;
}
int rdp_client_connect_license(rdpRdp* rdp, wStream* s) int rdp_client_connect_license(rdpRdp* rdp, wStream* s)
{ {
int status; int status;

View File

@ -53,6 +53,7 @@ BOOL rdp_client_reconnect(rdpRdp* rdp);
BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s);
int rdp_client_connect_license(rdpRdp* rdp, wStream* s); int rdp_client_connect_license(rdpRdp* rdp, wStream* s);
int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s);
int rdp_client_connect_finalize(rdpRdp* rdp); int rdp_client_connect_finalize(rdpRdp* rdp);

View File

@ -62,6 +62,41 @@ int connectErrorCode;
#define ERRINFO_LOGOFF_BY_USER_STRING \ #define ERRINFO_LOGOFF_BY_USER_STRING \
"The disconnection was initiated by the user logging off his or her session on the server." "The disconnection was initiated by the user logging off his or her session on the server."
/* Protocol-independent codes generated by the Connection Broker */
#define ERRINFO_CB_DESTINATION_NOT_FOUND_STRING \
"The target endpoint could not be found."
#define ERRINFO_CB_LOADING_DESTINATION_STRING \
"The target endpoint to which the client is being redirected is disconnecting from the Connection Broker."
#define ERRINFO_CB_REDIRECTING_TO_DESTINATION_STRING \
"An error occurred while the connection was being redirected to the target endpoint."
#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE_STRING \
"An error occurred while the target endpoint (a virtual machine) was being awakened."
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_STRING \
"An error occurred while the target endpoint (a virtual machine) was being started."
#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS_STRING \
"The IP address of the target endpoint (a virtual machine) cannot be determined."
#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE_STRING \
"There are no available endpoints in the pool managed by the Connection Broker."
#define ERRINFO_CB_CONNECTION_CANCELLED_STRING \
"Processing of the connection has been cancelled."
#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS_STRING \
"The settings contained in the routingToken field of the X.224 Connection Request PDU (section 2.2.1.1) cannot be validated."
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT_STRING \
"A time-out occurred while the target endpoint (a virtual machine) was being started."
#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED_STRING \
"A session monitoring error occurred while the target endpoint (a virtual machine) was being started."
/* Protocol-independent licensing codes */ /* Protocol-independent licensing codes */
#define ERRINFO_LICENSE_INTERNAL_STRING \ #define ERRINFO_LICENSE_INTERNAL_STRING \
@ -319,6 +354,21 @@ int connectErrorCode;
#define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED_STRING \ #define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED_STRING \
"The server-side graphics subsystem failed to reset." "The server-side graphics subsystem failed to reset."
#define ERRINFO_GRAPHICS_SUBSYSTEM_FAILED_STRING \
"The server-side graphics subsystem is in an error state and unable to continue graphics encoding."
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_SHORT_STRING \
"There is not enough data to read the cbDynamicDSTTimeZoneKeyName field in the Extended Info Packet (section 2.2.1.11.1.1.1)."
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_LONG_STRING \
"The length reported in the cbDynamicDSTTimeZoneKeyName field of the Extended Info Packet (section 2.2.1.11.1.1.1) is too long."
#define ERRINFO_DYNAMIC_DST_DISABLED_FIELD_MISSING_STRING \
"The dynamicDaylightTimeDisabled field is not present in the Extended Info Packet (section 2.2.1.11.1.1.1)."
#define ERRINFO_VC_DECODING_ERROR_STRING \
"An error occurred when processing dynamic virtual channel data ([MS-RDPEDYC] section 3.3.5)."
#define ERRINFO_UPDATE_SESSION_KEY_FAILED_STRING \ #define ERRINFO_UPDATE_SESSION_KEY_FAILED_STRING \
"An attempt to update the session keys while using Standard RDP Security mechanisms (section 5.3.7) failed." "An attempt to update the session keys while using Standard RDP Security mechanisms (section 5.3.7) failed."
@ -356,6 +406,19 @@ static const ERRINFO ERRINFO_CODES[] =
ERRINFO_DEFINE(RPC_INITIATED_DISCONNECT_BY_USER), ERRINFO_DEFINE(RPC_INITIATED_DISCONNECT_BY_USER),
ERRINFO_DEFINE(LOGOFF_BY_USER), ERRINFO_DEFINE(LOGOFF_BY_USER),
/* Protocol-independent codes generated by the Connection Broker */
ERRINFO_DEFINE(CB_DESTINATION_NOT_FOUND),
ERRINFO_DEFINE(CB_LOADING_DESTINATION),
ERRINFO_DEFINE(CB_REDIRECTING_TO_DESTINATION),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_WAKE),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_BOOT),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_NO_DNS),
ERRINFO_DEFINE(CB_DESTINATION_POOL_NOT_FREE),
ERRINFO_DEFINE(CB_CONNECTION_CANCELLED),
ERRINFO_DEFINE(CB_CONNECTION_ERROR_INVALID_SETTINGS),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_BOOT_TIMEOUT),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_SESSMON_FAILED),
/* Protocol-independent licensing codes */ /* Protocol-independent licensing codes */
ERRINFO_DEFINE(LICENSE_INTERNAL), ERRINFO_DEFINE(LICENSE_INTERNAL),
ERRINFO_DEFINE(LICENSE_NO_LICENSE_SERVER), ERRINFO_DEFINE(LICENSE_NO_LICENSE_SERVER),
@ -434,6 +497,11 @@ static const ERRINFO ERRINFO_CODES[] =
ERRINFO_DEFINE(VC_DATA_TOO_LONG), ERRINFO_DEFINE(VC_DATA_TOO_LONG),
ERRINFO_DEFINE(GRAPHICS_MODE_NOT_SUPPORTED), ERRINFO_DEFINE(GRAPHICS_MODE_NOT_SUPPORTED),
ERRINFO_DEFINE(GRAPHICS_SUBSYSTEM_RESET_FAILED), ERRINFO_DEFINE(GRAPHICS_SUBSYSTEM_RESET_FAILED),
ERRINFO_DEFINE(GRAPHICS_SUBSYSTEM_FAILED),
ERRINFO_DEFINE(TIMEZONE_KEY_NAME_LENGTH_TOO_SHORT),
ERRINFO_DEFINE(TIMEZONE_KEY_NAME_LENGTH_TOO_LONG),
ERRINFO_DEFINE(DYNAMIC_DST_DISABLED_FIELD_MISSING),
ERRINFO_DEFINE(VC_DECODING_ERROR),
ERRINFO_DEFINE(UPDATE_SESSION_KEY_FAILED), ERRINFO_DEFINE(UPDATE_SESSION_KEY_FAILED),
ERRINFO_DEFINE(DECRYPT_FAILED), ERRINFO_DEFINE(DECRYPT_FAILED),
ERRINFO_DEFINE(ENCRYPT_FAILED), ERRINFO_DEFINE(ENCRYPT_FAILED),
@ -500,4 +568,3 @@ void rdp_print_errinfo(UINT32 code)
fprintf(stderr, "ERRINFO_UNKNOWN 0x%08X: Unknown error.\n", code); fprintf(stderr, "ERRINFO_UNKNOWN 0x%08X: Unknown error.\n", code);
} }

View File

@ -369,7 +369,6 @@ static wEventType FreeRDP_Events[] =
DEFINE_EVENT_ENTRY(PanningChange) DEFINE_EVENT_ENTRY(PanningChange)
DEFINE_EVENT_ENTRY(ScalingFactorChange) DEFINE_EVENT_ENTRY(ScalingFactorChange)
DEFINE_EVENT_ENTRY(ErrorInfo) DEFINE_EVENT_ENTRY(ErrorInfo)
DEFINE_EVENT_ENTRY(ParamChange)
DEFINE_EVENT_ENTRY(Terminate) DEFINE_EVENT_ENTRY(Terminate)
DEFINE_EVENT_ENTRY(ConnectionResult) DEFINE_EVENT_ENTRY(ConnectionResult)
DEFINE_EVENT_ENTRY(ChannelConnected) DEFINE_EVENT_ENTRY(ChannelConnected)

View File

@ -27,6 +27,7 @@
#include <winpr/tchar.h> #include <winpr/tchar.h>
#include <winpr/stream.h> #include <winpr/stream.h>
#include <winpr/dsparse.h> #include <winpr/dsparse.h>
#include <winpr/winhttp.h>
#include <openssl/rand.h> #include <openssl/rand.h>
@ -98,12 +99,15 @@ int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc)
http_response = http_response_recv(rpc->TlsIn); http_response = http_response_recv(rpc->TlsIn);
if (http_response->AuthParam)
{
ntlm_token_data = NULL; ntlm_token_data = NULL;
crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam), crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam),
&ntlm_token_data, &ntlm_token_length); &ntlm_token_data, &ntlm_token_length);
ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].pvBuffer = ntlm_token_data;
ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length;
}
http_response_free(http_response); http_response_free(http_response);
@ -113,30 +117,67 @@ int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc)
int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel) int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel)
{ {
rdpNtlm* ntlm = NULL; rdpNtlm* ntlm = NULL;
rdpSettings* settings; rdpSettings* settings = rpc->settings;
freerdp* instance = (freerdp*) rpc->settings->instance;
settings = rpc->settings; BOOL promptPassword = FALSE;
if (channel == TSG_CHANNEL_IN) if (channel == TSG_CHANNEL_IN)
ntlm = rpc->NtlmHttpIn->ntlm; ntlm = rpc->NtlmHttpIn->ntlm;
else if (channel == TSG_CHANNEL_OUT) else if (channel == TSG_CHANNEL_OUT)
ntlm = rpc->NtlmHttpOut->ntlm; ntlm = rpc->NtlmHttpOut->ntlm;
ntlm_client_init(ntlm, TRUE, settings->GatewayUsername, if ((!settings->GatewayPassword) || (!settings->GatewayUsername)
|| (!strlen(settings->GatewayPassword)) || (!strlen(settings->GatewayUsername)))
{
promptPassword = TRUE;
}
if (promptPassword)
{
if (instance->GatewayAuthenticate)
{
BOOL proceed = instance->GatewayAuthenticate(instance,
&settings->GatewayUsername, &settings->GatewayPassword, &settings->GatewayDomain);
if (!proceed)
{
connectErrorCode = CANCELEDBYUSER;
return 0;
}
if (settings->GatewayUseSameCredentials)
{
settings->Username = _strdup(settings->GatewayUsername);
settings->Domain = _strdup(settings->GatewayDomain);
settings->Password = _strdup(settings->GatewayPassword);
}
}
}
if (!ntlm_client_init(ntlm, TRUE, settings->GatewayUsername,
settings->GatewayDomain, settings->GatewayPassword, settings->GatewayDomain, settings->GatewayPassword,
rpc->TlsIn->Bindings); rpc->TlsIn->Bindings))
{
return 0;
}
//ntlm_client_make_spn(ntlm, NULL, settings->GatewayHostname); //ntlm_client_make_spn(ntlm, NULL, settings->GatewayHostname);
ntlm_client_make_spn(ntlm, _T("HTTP"), settings->GatewayHostname); if (!ntlm_client_make_spn(ntlm, _T("HTTP"), settings->GatewayHostname))
{
return 0; return 0;
} }
return 1;
}
BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc) BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc)
{ {
rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm; rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm;
BOOL success = FALSE;
rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_IN); if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_IN) == 1)
{
success = TRUE;
/* Send IN Channel Request */ /* Send IN Channel Request */
@ -151,11 +192,13 @@ BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc)
rpc_ncacn_http_send_in_channel_request(rpc); rpc_ncacn_http_send_in_channel_request(rpc);
ntlm_client_uninit(ntlm); ntlm_client_uninit(ntlm);
}
ntlm_free(ntlm); ntlm_free(ntlm);
rpc->NtlmHttpIn->ntlm = NULL; rpc->NtlmHttpIn->ntlm = NULL;
return TRUE; return success;
} }
int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc) int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc)
@ -180,7 +223,7 @@ int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc)
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc) int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc)
{ {
int ntlm_token_length; int ntlm_token_length = 0;
BYTE* ntlm_token_data; BYTE* ntlm_token_data;
HttpResponse* http_response; HttpResponse* http_response;
rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm; rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm;
@ -188,8 +231,11 @@ int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc)
http_response = http_response_recv(rpc->TlsOut); http_response = http_response_recv(rpc->TlsOut);
ntlm_token_data = NULL; ntlm_token_data = NULL;
if (http_response && http_response->AuthParam)
{
crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam), crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam),
&ntlm_token_data, &ntlm_token_length); &ntlm_token_data, &ntlm_token_length);
}
ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].pvBuffer = ntlm_token_data;
ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length;
@ -202,8 +248,11 @@ int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc)
BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc) BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc)
{ {
rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm; rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm;
BOOL success = FALSE;
rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_OUT); if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_OUT) == 1)
{
success = TRUE;
/* Send OUT Channel Request */ /* Send OUT Channel Request */
@ -218,9 +267,13 @@ BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc)
rpc_ncacn_http_send_out_channel_request(rpc); rpc_ncacn_http_send_out_channel_request(rpc);
ntlm_client_uninit(ntlm); ntlm_client_uninit(ntlm);
}
ntlm_free(ntlm); ntlm_free(ntlm);
return TRUE; rpc->NtlmHttpOut->ntlm = NULL;
return success;
} }
void rpc_ntlm_http_init_channel(rdpRpc* rpc, rdpNtlmHttp* ntlm_http, TSG_CHANNEL channel) void rpc_ntlm_http_init_channel(rdpRpc* rpc, rdpNtlmHttp* ntlm_http, TSG_CHANNEL channel)

View File

@ -151,7 +151,7 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, char* hostname)
status = DsMakeSpn(ServiceClass, hostnameX, NULL, 0, NULL, &SpnLength, ntlm->ServicePrincipalName); status = DsMakeSpn(ServiceClass, hostnameX, NULL, 0, NULL, &SpnLength, ntlm->ServicePrincipalName);
if (status != ERROR_SUCCESS) if (status != ERROR_SUCCESS)
return -1; return FALSE;
return TRUE; return TRUE;
} }
@ -227,6 +227,12 @@ BOOL ntlm_authenticate(rdpNtlm* ntlm)
} }
} }
if ((!ntlm) || (!ntlm->table))
{
fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n");
return FALSE;
}
status = ntlm->table->InitializeSecurityContext(&ntlm->credentials, status = ntlm->table->InitializeSecurityContext(&ntlm->credentials,
(ntlm->haveContext) ? &ntlm->context : NULL, (ntlm->haveContext) ? &ntlm->context : NULL,
(ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL, (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL,
@ -270,10 +276,13 @@ void ntlm_client_uninit(rdpNtlm* ntlm)
free(ntlm->identity.Password); free(ntlm->identity.Password);
free(ntlm->ServicePrincipalName); free(ntlm->ServicePrincipalName);
if (ntlm->table)
{
ntlm->table->FreeCredentialsHandle(&ntlm->credentials); ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
ntlm->table->FreeContextBuffer(ntlm->pPackageInfo); ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
ntlm->table->DeleteSecurityContext(&ntlm->context); ntlm->table->DeleteSecurityContext(&ntlm->context);
} }
}
rdpNtlm* ntlm_new() rdpNtlm* ntlm_new()
{ {

View File

@ -360,6 +360,12 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum)
ntlm = rpc->ntlm; ntlm = rpc->ntlm;
if ((!ntlm) || (!ntlm->table))
{
fprintf(stderr, "rpc_write: invalid ntlm context\n");
return -1;
}
if (ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_SIZES, &ntlm->ContextSizes) != SEC_E_OK) if (ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_SIZES, &ntlm->ContextSizes) != SEC_E_OK)
{ {
fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n"); fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n");

View File

@ -97,11 +97,41 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
p_cont_elem_t* p_cont_elem; p_cont_elem_t* p_cont_elem;
rpcconn_bind_hdr_t* bind_pdu; rpcconn_bind_hdr_t* bind_pdu;
rdpSettings* settings = rpc->settings; rdpSettings* settings = rpc->settings;
BOOL promptPassword = FALSE;
freerdp* instance = (freerdp*) settings->instance;
DEBUG_RPC("Sending bind PDU"); DEBUG_RPC("Sending bind PDU");
rpc->ntlm = ntlm_new(); rpc->ntlm = ntlm_new();
if ((!settings->GatewayPassword) || (!settings->GatewayUsername)
|| (!strlen(settings->GatewayPassword)) || (!strlen(settings->GatewayUsername)))
{
promptPassword = TRUE;
}
if (promptPassword)
{
if (instance->GatewayAuthenticate)
{
BOOL proceed = instance->GatewayAuthenticate(instance,
&settings->GatewayUsername, &settings->GatewayPassword, &settings->GatewayDomain);
if (!proceed)
{
connectErrorCode = CANCELEDBYUSER;
return 0;
}
if (settings->GatewayUseSameCredentials)
{
settings->Username = _strdup(settings->GatewayUsername);
settings->Domain = _strdup(settings->GatewayDomain);
settings->Password = _strdup(settings->GatewayPassword);
}
}
}
ntlm_client_init(rpc->ntlm, FALSE, settings->GatewayUsername, settings->GatewayDomain, settings->GatewayPassword, NULL); ntlm_client_init(rpc->ntlm, FALSE, settings->GatewayUsername, settings->GatewayDomain, settings->GatewayPassword, NULL);
ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname); ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname);

View File

@ -22,6 +22,7 @@
#endif #endif
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/winhttp.h>
#include "ncacn_http.h" #include "ncacn_http.h"
#include "rpc_client.h" #include "rpc_client.h"
@ -147,11 +148,17 @@ BOOL rts_connect(rdpRpc* rpc)
http_response = http_response_recv(rpc->TlsOut); http_response = http_response_recv(rpc->TlsOut);
if (http_response->StatusCode != 200) if (http_response->StatusCode != HTTP_STATUS_OK)
{ {
fprintf(stderr, "rts_connect error! Status Code: %d\n", http_response->StatusCode); fprintf(stderr, "rts_connect error! Status Code: %d\n", http_response->StatusCode);
http_response_print(http_response); http_response_print(http_response);
http_response_free(http_response); http_response_free(http_response);
if (!connectErrorCode && http_response->StatusCode == HTTP_STATUS_DENIED)
{
connectErrorCode = AUTHENTICATIONERROR;
}
return FALSE; return FALSE;
} }

View File

@ -1367,6 +1367,9 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port)
pdu = rpc_recv_dequeue_pdu(rpc); pdu = rpc_recv_dequeue_pdu(rpc);
if (!pdu)
return FALSE;
call = rpc_client_call_find_by_id(rpc, pdu->CallId); call = rpc_client_call_find_by_id(rpc, pdu->CallId);
if (call->OpNum == TsProxyMakeTunnelCallOpnum) if (call->OpNum == TsProxyMakeTunnelCallOpnum)
@ -1409,6 +1412,9 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port)
#if 0 #if 0
pdu = rpc_recv_dequeue_pdu(rpc); pdu = rpc_recv_dequeue_pdu(rpc);
if (!pdu)
return FALSE;
if (!TsProxySetupReceivePipeReadResponse(tsg, pdu)) if (!TsProxySetupReceivePipeReadResponse(tsg, pdu))
{ {
fprintf(stderr, "TsProxySetupReceivePipe: error reading response\n"); fprintf(stderr, "TsProxySetupReceivePipe: error reading response\n");

View File

@ -232,36 +232,46 @@ BOOL gcc_read_conference_create_response(wStream* s, rdpSettings* settings)
BYTE number; BYTE number;
/* ConnectData */ /* ConnectData */
per_read_choice(s, &choice); if (!per_read_choice(s, &choice) ||
per_read_object_identifier(s, t124_02_98_oid); !per_read_object_identifier(s, t124_02_98_oid))
return FALSE;
/* ConnectData::connectPDU (OCTET_STRING) */ /* ConnectData::connectPDU (OCTET_STRING) */
per_read_length(s, &length); if (!per_read_length(s, &length))
return FALSE;
/* ConnectGCCPDU */ /* ConnectGCCPDU */
per_read_choice(s, &choice); if (!per_read_choice(s, &choice))
return FALSE;
/* ConferenceCreateResponse::nodeID (UserID) */ /* ConferenceCreateResponse::nodeID (UserID) */
per_read_integer16(s, &nodeID, 1001); if (!per_read_integer16(s, &nodeID, 1001))
return FALSE;
/* ConferenceCreateResponse::tag (INTEGER) */ /* ConferenceCreateResponse::tag (INTEGER) */
per_read_integer(s, &tag); if (!per_read_integer(s, &tag))
return FALSE;
/* ConferenceCreateResponse::result (ENUMERATED) */ /* ConferenceCreateResponse::result (ENUMERATED) */
per_read_enumerated(s, &result, MCS_Result_enum_length); if (!per_read_enumerated(s, &result, MCS_Result_enum_length))
return FALSE;
/* number of UserData sets */ /* number of UserData sets */
per_read_number_of_sets(s, &number); if (!per_read_number_of_sets(s, &number))
return FALSE;
/* UserData::value present + select h221NonStandard (1) */ /* UserData::value present + select h221NonStandard (1) */
per_read_choice(s, &choice); if (!per_read_choice(s, &choice))
return FALSE;
/* h221NonStandard */ /* h221NonStandard */
if (!per_read_octet_string(s, h221_sc_key, 4, 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */ if (!per_read_octet_string(s, h221_sc_key, 4, 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
return FALSE; return FALSE;
/* userData (OCTET_STRING) */ /* userData (OCTET_STRING) */
per_read_length(s, &length); if (!per_read_length(s, &length))
return FALSE;
if (!gcc_read_server_data_blocks(s, settings, length)) if (!gcc_read_server_data_blocks(s, settings, length))
{ {
fprintf(stderr, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed\n"); fprintf(stderr, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed\n");
@ -309,14 +319,18 @@ BOOL gcc_read_client_data_blocks(wStream* s, rdpSettings* settings, int length)
{ {
UINT16 type; UINT16 type;
UINT16 blockLength; UINT16 blockLength;
int pos; int begPos, endPos;
while (length > 0) while (length > 0)
{ {
pos = Stream_GetPosition(s); begPos = Stream_GetPosition(s);
if (!gcc_read_user_data_header(s, &type, &blockLength)) if (!gcc_read_user_data_header(s, &type, &blockLength))
return FALSE; return FALSE;
if (Stream_GetRemainingLength(s) < (blockLength - 4))
return FALSE;
switch (type) switch (type)
{ {
case CS_CORE: case CS_CORE:
@ -344,12 +358,37 @@ BOOL gcc_read_client_data_blocks(wStream* s, rdpSettings* settings, int length)
return FALSE; return FALSE;
break; break;
case CS_MCS_MSGCHANNEL:
if (!gcc_read_client_message_channel_data(s, settings, blockLength - 4))
return FALSE;
break;
case CS_MONITOR_EX:
if (!gcc_read_client_monitor_extended_data(s, settings, blockLength - 4))
return FALSE;
break;
case CS_MULTITRANSPORT:
if (!gcc_read_client_multitransport_channel_data(s, settings, blockLength - 4))
return FALSE;
break;
default: default:
fprintf(stderr, "Unknown GCC client data block: 0x%04X\n", type);
Stream_Seek(s, blockLength - 4);
break; break;
} }
endPos = Stream_GetPosition(s);
if (endPos != (begPos + blockLength))
{
fprintf(stderr, "Error parsing GCC client data block 0x%04X: Actual Offset: %d Expected Offset: %d\n",
type, endPos, begPos + blockLength);
}
length -= blockLength; length -= blockLength;
Stream_SetPosition(s, pos + blockLength); Stream_SetPosition(s, begPos + blockLength);
} }
return TRUE; return TRUE;
@ -366,10 +405,12 @@ void gcc_write_client_data_blocks(wStream* s, rdpSettings* settings)
if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED) if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
{ {
if (!settings->SpanMonitors) if (settings->SpanMonitors)
{ {
gcc_write_client_monitor_data(s, settings); gcc_write_client_monitor_data(s, settings);
} }
gcc_write_client_message_channel_data(s, settings);
gcc_write_client_multitransport_channel_data(s, settings);
} }
else else
{ {
@ -433,6 +474,22 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpSettings* settings, int length)
} }
break; break;
case SC_MCS_MSGCHANNEL:
if (!gcc_read_server_message_channel_data(s, settings))
{
fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed\n");
return FALSE;
}
break;
case SC_MULTITRANSPORT:
if (!gcc_read_server_multitransport_channel_data(s, settings))
{
fprintf(stderr, "gcc_read_server_data_blocks: gcc_read_server_multitransport_channel_data failed\n");
return FALSE;
}
break;
default: default:
fprintf(stderr, "gcc_read_server_data_blocks: ignoring type=%hu\n", type); fprintf(stderr, "gcc_read_server_data_blocks: ignoring type=%hu\n", type);
break; break;
@ -446,9 +503,13 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpSettings* settings, int length)
void gcc_write_server_data_blocks(wStream* s, rdpSettings* settings) void gcc_write_server_data_blocks(wStream* s, rdpSettings* settings)
{ {
gcc_write_server_core_data(s, settings); gcc_write_server_core_data(s, settings); /* serverCoreData */
gcc_write_server_network_data(s, settings); gcc_write_server_network_data(s, settings); /* serverNetworkData */
gcc_write_server_security_data(s, settings); gcc_write_server_security_data(s, settings); /* serverSecurityData */
/* TODO: Send these GCC data blocks only when the client sent them */
//gcc_write_server_message_channel_data(s, settings); /* serverMessageChannelData */
//gcc_write_server_multitransport_channel_data(s, settings); /* serverMultitransportChannelData */
} }
BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length) BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length)
@ -496,20 +557,25 @@ BOOL gcc_read_client_core_data(wStream* s, rdpSettings* settings, UINT16 blockLe
UINT16 highColorDepth = 0; UINT16 highColorDepth = 0;
UINT16 supportedColorDepths = 0; UINT16 supportedColorDepths = 0;
UINT32 serverSelectedProtocol = 0; UINT32 serverSelectedProtocol = 0;
UINT32 desktopPhysicalWidth = 0;
UINT32 desktopPhysicalHeight = 0;
UINT16 desktopOrientation = 0;
UINT32 desktopScaleFactor = 0;
UINT32 deviceScaleFactor = 0;
/* Length of all required fields, until imeFileName */ /* Length of all required fields, until imeFileName */
if (blockLength < 128) if (blockLength < 128)
return FALSE; return FALSE;
Stream_Read_UINT32(s, version); /* version */ Stream_Read_UINT32(s, version); /* version (4 bytes) */
settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7); settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7);
Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth */ Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */
Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight */ Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
Stream_Read_UINT16(s, colorDepth); /* ColorDepth */ Stream_Read_UINT16(s, colorDepth); /* ColorDepth (2 bytes) */
Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) */ Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */ Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild */ Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */
/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL); ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL);
@ -519,11 +585,11 @@ BOOL gcc_read_client_core_data(wStream* s, rdpSettings* settings, UINT16 blockLe
free(str); free(str);
str = NULL; str = NULL;
Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType */ Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */
Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */ Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */
Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */ Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */
Stream_Seek(s, 64); /* imeFileName */ Stream_Seek(s, 64); /* imeFileName (64 bytes) */
blockLength -= 128; blockLength -= 128;
@ -538,56 +604,81 @@ BOOL gcc_read_client_core_data(wStream* s, rdpSettings* settings, UINT16 blockLe
{ {
if (blockLength < 2) if (blockLength < 2)
break; break;
Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */ Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */
blockLength -= 2; blockLength -= 2;
if (blockLength < 2) if (blockLength < 2)
break; break;
Stream_Seek_UINT16(s); /* clientProductID */ Stream_Seek_UINT16(s); /* clientProductID (2 bytes) */
blockLength -= 2; blockLength -= 2;
if (blockLength < 4) if (blockLength < 4)
break; break;
Stream_Seek_UINT32(s); /* serialNumber */ Stream_Seek_UINT32(s); /* serialNumber (4 bytes) */
blockLength -= 4; blockLength -= 4;
if (blockLength < 2) if (blockLength < 2)
break; break;
Stream_Read_UINT16(s, highColorDepth); /* highColorDepth */ Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */
blockLength -= 2; blockLength -= 2;
if (blockLength < 2) if (blockLength < 2)
break; break;
Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths */ Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths (2 bytes) */
blockLength -= 2; blockLength -= 2;
if (blockLength < 2) if (blockLength < 2)
break; break;
Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */ Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
blockLength -= 2; blockLength -= 2;
if (blockLength < 64) if (blockLength < 64)
break; break;
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL);
Stream_Seek(s, 64); Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */
sprintf_s(settings->ClientProductId, 32, "%s", str); sprintf_s(settings->ClientProductId, 32, "%s", str);
free(str); free(str);
blockLength -= 64; blockLength -= 64;
if (blockLength < 1) if (blockLength < 1)
break; break;
Stream_Read_UINT8(s, settings->PerformanceFlags); /* connectionType */ Stream_Read_UINT8(s, settings->PerformanceFlags); /* connectionType (1 byte) */
blockLength -= 1; blockLength -= 1;
if (blockLength < 1) if (blockLength < 1)
break; break;
Stream_Seek_UINT8(s); /* pad1octet */ Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
blockLength -= 1; blockLength -= 1;
if (blockLength < 4) if (blockLength < 4)
break; break;
Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol */ Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
Stream_Read_UINT32(s, desktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
Stream_Read_UINT32(s, desktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
blockLength -= 4;
if (blockLength < 2)
break;
Stream_Read_UINT16(s, desktopOrientation); /* desktopOrientation (2 bytes) */
blockLength -= 2;
if (blockLength < 4)
break;
Stream_Read_UINT32(s, desktopScaleFactor); /* desktopScaleFactor (4 bytes) */
blockLength -= 4;
if (blockLength < 4)
break;
Stream_Read_UINT32(s, deviceScaleFactor); /* deviceScaleFactor (4 bytes) */
blockLength -= 4; blockLength -= 4;
if (settings->SelectedProtocol != serverSelectedProtocol) if (settings->SelectedProtocol != serverSelectedProtocol)
@ -730,6 +821,9 @@ void gcc_write_client_core_data(wStream* s, rdpSettings* settings)
if (settings->NetworkAutoDetect) if (settings->NetworkAutoDetect)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT; earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT;
if (settings->SupportHeartbeatPdu)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_HEARTBEAT_PDU;
if (settings->SupportGraphicsPipeline) if (settings->SupportGraphicsPipeline)
earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL; earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL;
@ -761,26 +855,38 @@ BOOL gcc_read_server_core_data(wStream* s, rdpSettings* settings)
{ {
UINT32 version; UINT32 version;
UINT32 clientRequestedProtocols; UINT32 clientRequestedProtocols;
UINT32 earlyCapabilityFlags;
if(Stream_GetRemainingLength(s) < 8) if (Stream_GetRemainingLength(s) < 4)
return FALSE; return FALSE;
Stream_Read_UINT32(s, version); /* version */ Stream_Read_UINT32(s, version); /* version */
Stream_Read_UINT32(s, clientRequestedProtocols); /* clientRequestedProtocols */
if (version == RDP_VERSION_4 && settings->RdpVersion > 4) if (version == RDP_VERSION_4 && settings->RdpVersion > 4)
settings->RdpVersion = 4; settings->RdpVersion = 4;
else if (version == RDP_VERSION_5_PLUS && settings->RdpVersion < 5) else if (version == RDP_VERSION_5_PLUS && settings->RdpVersion < 5)
settings->RdpVersion = 7; settings->RdpVersion = 7;
if (Stream_GetRemainingLength(s) >= 4)
{
Stream_Read_UINT32(s, clientRequestedProtocols); /* clientRequestedProtocols */
}
if (Stream_GetRemainingLength(s) >= 4)
{
Stream_Read_UINT32(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
}
return TRUE; return TRUE;
} }
void gcc_write_server_core_data(wStream* s, rdpSettings* settings) void gcc_write_server_core_data(wStream* s, rdpSettings* settings)
{ {
gcc_write_user_data_header(s, SC_CORE, 12); 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->RdpVersion == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS);
Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */ Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols */
Stream_Write_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */
} }
/** /**
@ -1125,24 +1231,31 @@ BOOL gcc_read_server_network_data(wStream* s, rdpSettings* settings)
{ {
int i; int i;
UINT16 MCSChannelId; UINT16 MCSChannelId;
UINT16 channelCount; UINT16 channelCount, channelsToTreat;
UINT16 channelId; UINT16 channelId;
if (Stream_GetRemainingLength(s) < 4) if (Stream_GetRemainingLength(s) < 4)
return FALSE; return FALSE;
Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */ Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
Stream_Read_UINT16(s, channelCount); /* channelCount */ Stream_Read_UINT16(s, channelCount); /* channelCount */
channelsToTreat = channelCount;
if (channelCount != settings->ChannelCount) if (channelCount != settings->ChannelCount)
{ {
fprintf(stderr, "requested %d channels, got %d instead\n", fprintf(stderr, "requested %d channels, got %d instead\n",
settings->ChannelCount, channelCount); settings->ChannelCount, channelCount);
/* we ensure that the response is not bigger than the request */
if (channelCount > settings->ChannelCount)
channelsToTreat = settings->ChannelCount;
} }
if (Stream_GetRemainingLength(s) < channelCount * 2) if (Stream_GetRemainingLength(s) < channelCount * 2)
return FALSE; return FALSE;
for (i = 0; i < channelCount; i++) for (i = 0; i < channelsToTreat; i++)
{ {
Stream_Read_UINT16(s, channelId); /* channelId */ Stream_Read_UINT16(s, channelId); /* channelId */
settings->ChannelDefArray[i].ChannelId = channelId; settings->ChannelDefArray[i].ChannelId = channelId;
@ -1182,18 +1295,16 @@ void gcc_write_server_network_data(wStream* s, rdpSettings* settings)
BOOL gcc_read_client_cluster_data(wStream* s, rdpSettings* settings, UINT16 blockLength) BOOL gcc_read_client_cluster_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{ {
UINT32 flags; UINT32 flags;
UINT32 redirectedSessionId;
if (blockLength < 4) if (blockLength < 8)
return FALSE; return FALSE;
Stream_Read_UINT32(s, flags); /* flags */ Stream_Read_UINT32(s, flags); /* flags */
Stream_Read_UINT32(s, redirectedSessionId); /* redirectedSessionId */
if ((flags & REDIRECTED_SESSIONID_FIELD_VALID)) if (flags & REDIRECTED_SESSIONID_FIELD_VALID)
{ settings->RedirectedSessionId = redirectedSessionId;
if(blockLength < 8)
return FALSE;
Stream_Read_UINT32(s, settings->RedirectedSessionId); /* redirectedSessionID */
}
return TRUE; return TRUE;
} }
@ -1229,7 +1340,34 @@ void gcc_write_client_cluster_data(wStream* s, rdpSettings* settings)
BOOL gcc_read_client_monitor_data(wStream* s, rdpSettings* settings, UINT16 blockLength) BOOL gcc_read_client_monitor_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{ {
fprintf(stderr, "CS_MONITOR\n"); UINT32 index;
UINT32 flags;
UINT32 monitorCount;
MONITOR_DEF* monitorDefArray;
if (blockLength < 8)
return FALSE;
Stream_Read_UINT32(s, flags); /* flags */
Stream_Read_UINT32(s, monitorCount); /* monitorCount */
if (blockLength < (8 + (monitorCount * 20)))
return FALSE;
monitorDefArray = (MONITOR_DEF*) malloc(sizeof(MONITOR_DEF) * monitorCount);
ZeroMemory(monitorDefArray, sizeof(MONITOR_DEF) * monitorCount);
for (index = 0; index < monitorCount; index++)
{
Stream_Read_UINT32(s, monitorDefArray[index].left); /* left */
Stream_Read_UINT32(s, monitorDefArray[index].top); /* top */
Stream_Read_UINT32(s, monitorDefArray[index].right); /* right */
Stream_Read_UINT32(s, monitorDefArray[index].bottom); /* bottom */
Stream_Read_UINT32(s, monitorDefArray[index].flags); /* flags */
}
free(monitorDefArray);
return TRUE; return TRUE;
} }
@ -1270,3 +1408,167 @@ void gcc_write_client_monitor_data(wStream* s, rdpSettings* settings)
} }
} }
} }
BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{
UINT32 index;
UINT32 flags;
UINT32 monitorCount;
UINT32 monitorAttributeSize;
MONITOR_ATTRIBUTES* monitorAttributesArray;
if (blockLength < 8)
return FALSE;
Stream_Read_UINT32(s, flags); /* flags */
Stream_Read_UINT32(s, monitorAttributeSize); /* monitorAttributeSize */
Stream_Read_UINT32(s, monitorCount); /* monitorCount */
if (monitorAttributeSize != 20)
return FALSE;
if (blockLength < (12 + (monitorCount * monitorAttributeSize)))
return FALSE;
monitorAttributesArray = (MONITOR_ATTRIBUTES*) malloc(sizeof(MONITOR_ATTRIBUTES) * monitorCount);
ZeroMemory(monitorAttributesArray, sizeof(MONITOR_ATTRIBUTES) * monitorCount);
for (index = 0; index < monitorCount; index++)
{
Stream_Read_UINT32(s, monitorAttributesArray[index].physicalWidth); /* physicalWidth */
Stream_Read_UINT32(s, monitorAttributesArray[index].physicalHeight); /* physicalHeight */
Stream_Read_UINT32(s, monitorAttributesArray[index].orientation); /* orientation */
Stream_Read_UINT32(s, monitorAttributesArray[index].desktopScaleFactor); /* desktopScaleFactor */
Stream_Read_UINT32(s, monitorAttributesArray[index].deviceScaleFactor); /* deviceScaleFactor */
}
free(monitorAttributesArray);
return TRUE;
}
void gcc_write_client_monitor_extended_data(wStream* s, rdpSettings* settings)
{
}
/**
* Read a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).\n
* @msdn{jj217627}
* @param s stream
* @param settings rdp settings
*/
BOOL gcc_read_client_message_channel_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{
UINT32 flags;
if (blockLength < 4)
return FALSE;
Stream_Read_UINT32(s, flags);
return TRUE;
}
/**
* Write a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).\n
* @msdn{jj217627}
* @param s stream
* @param settings rdp settings
*/
void gcc_write_client_message_channel_data(wStream* s, rdpSettings* settings)
{
if (settings->NetworkAutoDetect ||
settings->SupportHeartbeatPdu ||
settings->SupportMultitransport)
{
gcc_write_user_data_header(s, CS_MCS_MSGCHANNEL, 8);
Stream_Write_UINT32(s, 0); /* flags */
}
}
BOOL gcc_read_server_message_channel_data(wStream* s, rdpSettings* settings)
{
freerdp* instance;
UINT16 MCSChannelId;
if (Stream_GetRemainingLength(s) < 2)
return FALSE;
Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
/* Save the MCS message channel id */
instance = (freerdp*) settings->instance;
instance->context->rdp->mcs->message_channel_id = MCSChannelId;
return TRUE;
}
void gcc_write_server_message_channel_data(wStream* s, rdpSettings* settings)
{
UINT16 mcsChannelId = 0;
gcc_write_user_data_header(s, SC_MCS_MSGCHANNEL, 6);
Stream_Write_UINT16(s, mcsChannelId); /* mcsChannelId (2 bytes) */
}
/**
* Read a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).\n
* @msdn{jj217498}
* @param s stream
* @param settings rdp settings
*/
BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{
UINT32 flags;
if (blockLength < 4)
return FALSE;
Stream_Read_UINT32(s, flags);
return TRUE;
}
/**
* Write a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).\n
* @msdn{jj217498}
* @param s stream
* @param settings rdp settings
*/
void gcc_write_client_multitransport_channel_data(wStream* s, rdpSettings* settings)
{
if (settings->MultitransportFlags != 0)
{
gcc_write_user_data_header(s, CS_MULTITRANSPORT, 8);
Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags */
}
}
BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpSettings* settings)
{
UINT32 flags;
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, flags); /* flags */
return TRUE;
}
void gcc_write_server_multitransport_channel_data(wStream* s, rdpSettings* settings)
{
UINT32 flags = 0;
gcc_write_user_data_header(s, SC_MULTITRANSPORT, 8);
Stream_Write_UINT32(s, flags); /* flags (4 bytes) */
}

View File

@ -55,5 +55,15 @@ BOOL gcc_read_client_cluster_data(wStream* s, rdpSettings *settings, UINT16 bloc
void gcc_write_client_cluster_data(wStream* s, rdpSettings* settings); void gcc_write_client_cluster_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_client_monitor_data(wStream* s, rdpSettings* settings, UINT16 blockLength); BOOL gcc_read_client_monitor_data(wStream* s, rdpSettings* settings, UINT16 blockLength);
void gcc_write_client_monitor_data(wStream* s, rdpSettings* settings); void gcc_write_client_monitor_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpSettings* settings, UINT16 blockLength);
void gcc_write_client_monitor_extended_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_client_message_channel_data(wStream* s, rdpSettings* settings, UINT16 blockLength);
void gcc_write_client_message_channel_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_server_message_channel_data(wStream* s, rdpSettings* settings);
void gcc_write_server_message_channel_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpSettings* settings, UINT16 blockLength);
void gcc_write_client_multitransport_channel_data(wStream* s, rdpSettings* settings);
BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpSettings* settings);
void gcc_write_server_multitransport_channel_data(wStream* s, rdpSettings* settings);
#endif /* FREERDP_CORE_GCC_H */ #endif /* FREERDP_CORE_GCC_H */

View File

@ -0,0 +1,62 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Heartbeat PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define WITH_DEBUG_HEARTBEAT
#include "heartbeat.h"
int rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s)
{
BYTE reserved;
BYTE period;
BYTE count1;
BYTE count2;
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT8(s, reserved); /* reserved (1 byte) */
Stream_Read_UINT8(s, period); /* period (1 byte) */
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);
return 0;
}
rdpHeartbeat* heartbeat_new(void)
{
rdpHeartbeat* heartbeat = (rdpHeartbeat*)malloc(sizeof(rdpHeartbeat));
if (heartbeat)
{
ZeroMemory(heartbeat, sizeof(rdpHeartbeat));
}
return heartbeat;
}
void heartbeat_free(rdpHeartbeat* heartbeat)
{
free(heartbeat);
}

View File

@ -0,0 +1,47 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Heartbeat PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __HEARTBEAT_H
#define __HEARTBEAT_H
typedef struct rdp_heartbeat rdpHeartbeat;
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <winpr/stream.h>
struct rdp_heartbeat
{
UINT32 placeholder;
};
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
#endif /* __HEARTBEAT_H */

View File

@ -464,7 +464,7 @@ BOOL mcs_send_connect_initial(rdpMcs* mcs)
client_data = Stream_New(NULL, 512); client_data = Stream_New(NULL, 512);
gcc_write_client_data_blocks(client_data, mcs->transport->settings); gcc_write_client_data_blocks(client_data, mcs->transport->settings);
gcc_CCrq = Stream_New(NULL, 512); gcc_CCrq = Stream_New(NULL, 1024);
gcc_write_conference_create_request(gcc_CCrq, client_data); gcc_write_conference_create_request(gcc_CCrq, client_data);
length = Stream_GetPosition(gcc_CCrq) + 7; length = Stream_GetPosition(gcc_CCrq) + 7;
@ -584,11 +584,22 @@ BOOL mcs_send_connect_response(rdpMcs* mcs)
BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s) BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)
{ {
UINT16 length; UINT16 length;
UINT32 subHeight;
UINT32 subInterval;
enum DomainMCSPDU MCSPDU; enum DomainMCSPDU MCSPDU;
MCSPDU = DomainMCSPDU_ErectDomainRequest; MCSPDU = DomainMCSPDU_ErectDomainRequest;
return mcs_read_domain_mcspdu_header(s, &MCSPDU, &length); if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length))
return FALSE;
if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */
return FALSE;
if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */
return FALSE;
return TRUE;
} }
/** /**
@ -818,6 +829,54 @@ BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channel_id)
return (status < 0) ? FALSE : TRUE; return (status < 0) ? FALSE : TRUE;
} }
/**
* Receive MCS Disconnect Provider Ultimatum PDU.\n
* @param mcs mcs module
*/
BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason)
{
BYTE b1, b2;
/*
* http://msdn.microsoft.com/en-us/library/cc240872.aspx:
*
* PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
* 21 80
*
* 0x21:
* 0 - --\
* 0 - |
* 1 - | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
* 0 - | of type DisconnectProviderUltimatum
* 0 - |
* 0 - --/
* 0 - --\
* 1 - |
* | DisconnectProviderUltimatum::reason = rn-user-requested (3)
* 0x80: |
* 1 - --/
* 0 - padding
* 0 - padding
* 0 - padding
* 0 - padding
* 0 - padding
* 0 - padding
* 0 - padding
*/
if (Stream_GetRemainingLength(s) < 1)
return FALSE;
Stream_Rewind_UINT8(s);
Stream_Read_UINT8(s, b1);
Stream_Read_UINT8(s, b2);
*reason = ((b1 & 0x01) << 1) | (b2 >> 7);
return TRUE;
}
/** /**
* Send MCS Disconnect Provider Ultimatum PDU.\n * Send MCS Disconnect Provider Ultimatum PDU.\n
* @param mcs mcs module * @param mcs mcs module

View File

@ -20,6 +20,8 @@
#ifndef __MCS_H #ifndef __MCS_H
#define __MCS_H #define __MCS_H
typedef struct rdp_mcs rdpMcs;
#include "transport.h" #include "transport.h"
#include <freerdp/crypto/ber.h> #include <freerdp/crypto/ber.h>
@ -52,6 +54,15 @@ enum MCS_Result
MCS_Result_enum_length = 16 MCS_Result_enum_length = 16
}; };
enum MCS_Reason
{
MCS_Reason_domain_disconnected = 0,
MCS_Reason_provider_initiated = 1,
MCS_Reason_token_purged = 2,
MCS_Reason_user_requested = 3,
MCS_Reason_channel_purged = 4
};
enum DomainMCSPDU enum DomainMCSPDU
{ {
DomainMCSPDU_PlumbDomainIndication = 0, DomainMCSPDU_PlumbDomainIndication = 0,
@ -114,8 +125,11 @@ typedef struct
struct rdp_mcs struct rdp_mcs
{ {
rdpTransport* transport;
UINT16 user_id; UINT16 user_id;
struct rdp_transport* transport; UINT16 message_channel_id;
DomainParameters domainParameters; DomainParameters domainParameters;
DomainParameters targetParameters; DomainParameters targetParameters;
DomainParameters minimumParameters; DomainParameters minimumParameters;
@ -123,8 +137,8 @@ struct rdp_mcs
BOOL user_channel_joined; BOOL user_channel_joined;
BOOL global_channel_joined; BOOL global_channel_joined;
BOOL message_channel_joined;
}; };
typedef struct rdp_mcs rdpMcs;
#define MCS_SEND_DATA_HEADER_MAX_LENGTH 8 #define MCS_SEND_DATA_HEADER_MAX_LENGTH 8
@ -148,6 +162,7 @@ BOOL mcs_recv_channel_join_request(rdpMcs* mcs, wStream* s, UINT16* channel_id);
BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channel_id); BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channel_id);
BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channel_id); BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channel_id);
BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channel_id); BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channel_id);
BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason);
BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs); BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs);
BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length); BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length);
void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length, BYTE options); void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length, BYTE options);

View File

@ -0,0 +1,58 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* MULTITRANSPORT PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "multitransport.h"
int rdp_recv_multitransport_packet(rdpRdp* rdp, wStream* s)
{
UINT32 requestId;
UINT16 requestedProtocol;
UINT16 reserved;
BYTE securityCookie[16];
if (Stream_GetRemainingLength(s) < 24)
return -1;
Stream_Read_UINT32(s, requestId); /* requestId (4 bytes) */
Stream_Read_UINT16(s, requestedProtocol); /* requestedProtocol (2 bytes) */
Stream_Read_UINT16(s, reserved); /* reserved (2 bytes) */
Stream_Read(s, securityCookie, 16); /* securityCookie (16 bytes) */
return 0;
}
rdpMultitransport* multitransport_new(void)
{
rdpMultitransport* multitransport = (rdpMultitransport*)malloc(sizeof(rdpMultitransport));
if (multitransport)
{
memset(multitransport, 0, sizeof(rdpMultitransport));
}
return multitransport;
}
void multitransport_free(rdpMultitransport* multitransport)
{
free(multitransport);
}

View File

@ -0,0 +1,41 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multitransport PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MULTITRANSPORT_H
#define __MULTITRANSPORT_H
typedef struct rdp_multitransport rdpMultitransport;
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <winpr/stream.h>
struct rdp_multitransport
{
UINT32 placeholder;
};
int rdp_recv_multitransport_packet(rdpRdp* rdp, wStream* s);
rdpMultitransport* multitransport_new(void);
void multitransport_free(rdpMultitransport* multitransport);
#endif /* __MULTITRANSPORT_H */

View File

@ -491,6 +491,7 @@ BOOL nego_recv_response(rdpNego* nego)
status = nego_recv(nego->transport, s, nego); status = nego_recv(nego->transport, s, nego);
Stream_Free(s, TRUE); Stream_Free(s, TRUE);
if (status < 0) if (status < 0)
return FALSE; return FALSE;

View File

@ -147,8 +147,12 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
&settings->Username, &settings->Password, &settings->Domain); &settings->Username, &settings->Password, &settings->Domain);
if (!proceed) if (!proceed)
{
connectErrorCode = CANCELEDBYUSER;
return 0; return 0;
} }
}
} }
sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password); sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password);
@ -623,7 +627,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED)) if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
{ {
fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status); fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
return -1; return -1; /* Access Denied */
} }
/* send authentication token */ /* send authentication token */

View File

@ -229,6 +229,34 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp)
return s; return s;
} }
BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo)
{
rdp->errorInfo = errorInfo;
if (rdp->errorInfo != ERRINFO_SUCCESS)
{
ErrorInfoEventArgs e;
rdpContext* context = rdp->instance->context;
rdp_print_errinfo(rdp->errorInfo);
EventArgsInit(&e, "freerdp");
e.code = rdp->errorInfo;
PubSub_OnErrorInfo(context->pubSub, context, &e);
}
return TRUE;
}
wStream* rdp_message_channel_pdu_init(rdpRdp* rdp)
{
wStream* s;
s = transport_send_stream_init(rdp->transport, 2048);
Stream_Seek(s, RDP_PACKET_HEADER_MAX_LENGTH);
rdp_security_stream_init(rdp, s);
return s;
}
/** /**
* Read an RDP packet header.\n * Read an RDP packet header.\n
* @param rdp rdp module * @param rdp rdp module
@ -256,12 +284,30 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId)
if (MCSPDU == DomainMCSPDU_DisconnectProviderUltimatum) if (MCSPDU == DomainMCSPDU_DisconnectProviderUltimatum)
{ {
BYTE reason; int reason = 0;
TerminateEventArgs e; TerminateEventArgs e;
rdpContext* context = rdp->instance->context; rdpContext* context = rdp->instance->context;
(void) per_read_enumerated(s, &reason, 0); if (!mcs_recv_disconnect_provider_ultimatum(rdp->mcs, s, &reason))
DEBUG_RDP("DisconnectProviderUltimatum from server, reason code 0x%02x\n", reason); return FALSE;
if (rdp->errorInfo == ERRINFO_SUCCESS)
{
/**
* Some servers like Windows Server 2008 R2 do not send the error info pdu
* when the user logs off like they should. Map DisconnectProviderUltimatum
* to a ERRINFO_LOGOFF_BY_USER when the errinfo code is ERRINFO_SUCCESS.
*/
if (reason == MCS_Reason_provider_initiated)
rdp_set_error_info(rdp, ERRINFO_RPC_INITIATED_DISCONNECT);
else if (reason == MCS_Reason_user_requested)
rdp_set_error_info(rdp, ERRINFO_LOGOFF_BY_USER);
else
rdp_set_error_info(rdp, ERRINFO_RPC_INITIATED_DISCONNECT);
}
fprintf(stderr, "DisconnectProviderUltimatum: reason: %d\n", reason);
rdp->disconnect = TRUE; rdp->disconnect = TRUE;
@ -328,13 +374,12 @@ void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channelId)
Stream_Write_UINT16_BE(s, length); /* userData (OCTET_STRING) */ Stream_Write_UINT16_BE(s, length); /* userData (OCTET_STRING) */
} }
static UINT32 rdp_security_stream_out(rdpRdp* rdp, wStream* s, int length) static UINT32 rdp_security_stream_out(rdpRdp* rdp, wStream* s, int length, UINT32 sec_flags)
{ {
BYTE* data; BYTE* data;
UINT32 sec_flags;
UINT32 pad = 0; UINT32 pad = 0;
sec_flags = rdp->sec_flags; sec_flags |= rdp->sec_flags;
if (sec_flags != 0) if (sec_flags != 0)
{ {
@ -431,7 +476,7 @@ BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channel_id)
Stream_Seek(s, sec_bytes); Stream_Seek(s, sec_bytes);
Stream_SetPosition(s, secm); Stream_SetPosition(s, secm);
length += rdp_security_stream_out(rdp, s, length); length += rdp_security_stream_out(rdp, s, length, 0);
Stream_SetPosition(s, length); Stream_SetPosition(s, length);
Stream_SealLength(s); Stream_SealLength(s);
@ -460,7 +505,7 @@ BOOL rdp_send_pdu(rdpRdp* rdp, wStream* s, UINT16 type, UINT16 channel_id)
rdp_write_share_control_header(s, length - sec_bytes, type, channel_id); rdp_write_share_control_header(s, length - sec_bytes, type, channel_id);
Stream_SetPosition(s, sec_hold); Stream_SetPosition(s, sec_hold);
length += rdp_security_stream_out(rdp, s, length); length += rdp_security_stream_out(rdp, s, length, 0);
Stream_SetPosition(s, length); Stream_SetPosition(s, length);
Stream_SealLength(s); Stream_SealLength(s);
@ -490,7 +535,7 @@ BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id)
rdp_write_share_data_header(s, length - sec_bytes, type, rdp->settings->ShareId); rdp_write_share_data_header(s, length - sec_bytes, type, rdp->settings->ShareId);
Stream_SetPosition(s, sec_hold); Stream_SetPosition(s, sec_hold);
length += rdp_security_stream_out(rdp, s, length); length += rdp_security_stream_out(rdp, s, length, 0);
Stream_SetPosition(s, length); Stream_SetPosition(s, length);
Stream_SealLength(s); Stream_SealLength(s);
@ -501,23 +546,158 @@ BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id)
return TRUE; return TRUE;
} }
BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s) 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->message_channel_id);
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);
if (transport_write(rdp->transport, s) < 0)
return FALSE;
return TRUE;
}
BOOL rdp_recv_server_shutdown_denied_pdu(rdpRdp* rdp, wStream* s)
{
return TRUE;
}
BOOL rdp_recv_server_set_keyboard_indicators_pdu(rdpRdp* rdp, wStream* s)
{
UINT16 unitId;
UINT16 ledFlags;
if (Stream_GetRemainingLength(s) < 4) if (Stream_GetRemainingLength(s) < 4)
return FALSE; return FALSE;
Stream_Read_UINT32(s, rdp->errorInfo); /* errorInfo (4 bytes) */ Stream_Read_UINT16(s, unitId); /* unitId (2 bytes) */
Stream_Read_UINT16(s, ledFlags); /* ledFlags (2 bytes) */
if (rdp->errorInfo != ERRINFO_SUCCESS) return TRUE;
}
BOOL rdp_recv_server_set_keyboard_ime_status_pdu(rdpRdp* rdp, wStream* s)
{ {
ErrorInfoEventArgs e; UINT16 unitId;
rdpContext* context = rdp->instance->context; UINT32 imeState;
UINT32 imeConvMode;
rdp_print_errinfo(rdp->errorInfo); if (Stream_GetRemainingLength(s) < 10)
return FALSE;
EventArgsInit(&e, "freerdp"); Stream_Read_UINT16(s, unitId); /* unitId (2 bytes) */
e.code = rdp->errorInfo; Stream_Read_UINT32(s, imeState); /* imeState (4 bytes) */
PubSub_OnErrorInfo(context->pubSub, context, &e); Stream_Read_UINT32(s, imeConvMode); /* imeConvMode (4 bytes) */
return TRUE;
}
BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s)
{
UINT32 errorInfo;
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, errorInfo); /* errorInfo (4 bytes) */
rdp_set_error_info(rdp, errorInfo);
return TRUE;
}
BOOL rdp_recv_server_auto_reconnect_status_pdu(rdpRdp* rdp, wStream* s)
{
UINT32 arcStatus;
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, arcStatus); /* arcStatus (4 bytes) */
return TRUE;
}
BOOL rdp_recv_server_status_info_pdu(rdpRdp* rdp, wStream* s)
{
UINT32 statusCode;
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, statusCode); /* statusCode (4 bytes) */
return TRUE;
}
BOOL rdp_recv_monitor_layout_pdu(rdpRdp* rdp, wStream* s)
{
int index;
UINT32 monitorCount;
MONITOR_DEF* monitor;
MONITOR_DEF* monitorDefArray;
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT32(s, monitorCount); /* monitorCount (4 bytes) */
if (Stream_GetRemainingLength(s) < (monitorCount * 20))
return FALSE;
monitorDefArray = (MONITOR_DEF*) malloc(sizeof(MONITOR_DEF) * monitorCount);
ZeroMemory(monitorDefArray, sizeof(MONITOR_DEF) * monitorCount);
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) */
Stream_Read_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */
}
free(monitorDefArray);
return TRUE;
}
BOOL rdp_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount, MONITOR_DEF* monitorDefArray)
{
int 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) */
Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */
} }
return TRUE; return TRUE;
@ -589,29 +769,19 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
return -1; return -1;
break; break;
case DATA_PDU_TYPE_INPUT:
break;
case DATA_PDU_TYPE_SYNCHRONIZE: case DATA_PDU_TYPE_SYNCHRONIZE:
if (!rdp_recv_synchronize_pdu(rdp, cs)) if (!rdp_recv_synchronize_pdu(rdp, cs))
return -1; return -1;
break; break;
case DATA_PDU_TYPE_REFRESH_RECT:
break;
case DATA_PDU_TYPE_PLAY_SOUND: case DATA_PDU_TYPE_PLAY_SOUND:
if (!update_recv_play_sound(rdp->update, cs)) if (!update_recv_play_sound(rdp->update, cs))
return -1; return -1;
break; break;
case DATA_PDU_TYPE_SUPPRESS_OUTPUT:
break;
case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
break;
case DATA_PDU_TYPE_SHUTDOWN_DENIED: case DATA_PDU_TYPE_SHUTDOWN_DENIED:
if (!rdp_recv_server_shutdown_denied_pdu(rdp, cs))
return -1;
break; break;
case DATA_PDU_TYPE_SAVE_SESSION_INFO: case DATA_PDU_TYPE_SAVE_SESSION_INFO:
@ -619,27 +789,19 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
return -1; return -1;
break; break;
case DATA_PDU_TYPE_FONT_LIST:
break;
case DATA_PDU_TYPE_FONT_MAP: case DATA_PDU_TYPE_FONT_MAP:
if (!rdp_recv_font_map_pdu(rdp, cs)) if (!rdp_recv_font_map_pdu(rdp, cs))
return -1; return -1;
break; break;
case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS: case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS:
break; if (!rdp_recv_server_set_keyboard_indicators_pdu(rdp, cs))
return -1;
case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST:
break;
case DATA_PDU_TYPE_BITMAP_CACHE_ERROR:
break; break;
case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS: case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS:
break; if (!rdp_recv_server_set_keyboard_ime_status_pdu(rdp, cs))
return -1;
case DATA_PDU_TYPE_OFFSCREEN_CACHE_ERROR:
break; break;
case DATA_PDU_TYPE_SET_ERROR_INFO: case DATA_PDU_TYPE_SET_ERROR_INFO:
@ -647,19 +809,19 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
return -1; return -1;
break; break;
case DATA_PDU_TYPE_DRAW_NINEGRID_ERROR:
break;
case DATA_PDU_TYPE_DRAW_GDIPLUS_ERROR:
break;
case DATA_PDU_TYPE_ARC_STATUS: case DATA_PDU_TYPE_ARC_STATUS:
if (!rdp_recv_server_auto_reconnect_status_pdu(rdp, cs))
return -1;
break; break;
case DATA_PDU_TYPE_STATUS_INFO: case DATA_PDU_TYPE_STATUS_INFO:
if (!rdp_recv_server_status_info_pdu(rdp, cs))
return -1;
break; break;
case DATA_PDU_TYPE_MONITOR_LAYOUT: case DATA_PDU_TYPE_MONITOR_LAYOUT:
if (!rdp_recv_monitor_layout_pdu(rdp, cs))
return -1;
break; break;
default: default:
@ -672,6 +834,34 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
return 0; return 0;
} }
int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s)
{
UINT16 securityFlags;
if (!rdp_read_security_header(s, &securityFlags))
return -1;
if (securityFlags & SEC_AUTODETECT_REQ)
{
/* Server Auto-Detect Request PDU */
return rdp_recv_autodetect_packet(rdp, s);
}
if (securityFlags & SEC_HEARTBEAT)
{
/* Heartbeat PDU */
return rdp_recv_heartbeat_packet(rdp, s);
}
if (securityFlags & SEC_TRANSPORT_REQ)
{
/* Initiate Multitransport Request PDU */
return rdp_recv_multitransport_packet(rdp, s);
}
return -1;
}
int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s) int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s)
{ {
UINT16 type; UINT16 type;
@ -820,12 +1010,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
} }
} }
if (channelId != MCS_GLOBAL_CHANNEL_ID) if (channelId == MCS_GLOBAL_CHANNEL_ID)
{
if (!freerdp_channel_process(rdp->instance, s, channelId))
return -1;
}
else
{ {
while (Stream_GetRemainingLength(s) > 3) while (Stream_GetRemainingLength(s) > 3)
{ {
@ -865,6 +1050,15 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s)
Stream_SetPosition(s, nextPosition); Stream_SetPosition(s, nextPosition);
} }
} }
else if (channelId == rdp->mcs->message_channel_id)
{
return rdp_recv_message_channel_pdu(rdp, s);
}
else
{
if (!freerdp_channel_process(rdp->instance, s, channelId))
return -1;
}
return 0; return 0;
} }
@ -909,6 +1103,19 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
int status = 0; int status = 0;
rdpRdp* rdp = (rdpRdp*) extra; rdpRdp* rdp = (rdpRdp*) extra;
/*
* At any point in the connection sequence between when all
* MCS channels have been joined and when the RDP connection
* enters the active state, an auto-detect PDU can be received
* on the MCS message channel.
*/
if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) &&
(rdp->state < CONNECTION_STATE_ACTIVE))
{
if (rdp_client_connect_auto_detect(rdp, s))
return 0;
}
switch (rdp->state) switch (rdp->state)
{ {
case CONNECTION_STATE_NEGO: case CONNECTION_STATE_NEGO:
@ -1020,6 +1227,9 @@ rdpRdp* rdp_new(rdpContext* context)
rdp->nego = nego_new(rdp->transport); rdp->nego = nego_new(rdp->transport);
rdp->mcs = mcs_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport);
rdp->redirection = redirection_new(); rdp->redirection = redirection_new();
rdp->autodetect = autodetect_new();
rdp->heartbeat = heartbeat_new();
rdp->multitransport = multitransport_new();
rdp->mppc_dec = mppc_dec_new(); rdp->mppc_dec = mppc_dec_new();
rdp->mppc_enc = mppc_enc_new(PROTO_RDP_50); rdp->mppc_enc = mppc_enc_new(PROTO_RDP_50);
} }
@ -1092,6 +1302,9 @@ void rdp_free(rdpRdp* rdp)
nego_free(rdp->nego); nego_free(rdp->nego);
mcs_free(rdp->mcs); mcs_free(rdp->mcs);
redirection_free(rdp->redirection); redirection_free(rdp->redirection);
autodetect_free(rdp->autodetect);
heartbeat_free(rdp->heartbeat);
multitransport_free(rdp->multitransport);
mppc_dec_free(rdp->mppc_dec); mppc_dec_free(rdp->mppc_dec);
mppc_enc_free(rdp->mppc_enc); mppc_enc_free(rdp->mppc_enc);
free(rdp); free(rdp);

View File

@ -34,6 +34,9 @@
#include "license.h" #include "license.h"
#include "errinfo.h" #include "errinfo.h"
#include "extension.h" #include "extension.h"
#include "autodetect.h"
#include "heartbeat.h"
#include "multitransport.h"
#include "security.h" #include "security.h"
#include "transport.h" #include "transport.h"
#include "connection.h" #include "connection.h"
@ -51,6 +54,8 @@
/* Security Header Flags */ /* Security Header Flags */
#define SEC_EXCHANGE_PKT 0x0001 #define SEC_EXCHANGE_PKT 0x0001
#define SEC_TRANSPORT_REQ 0x0002
#define SEC_TRANSPORT_RSP 0x0004
#define SEC_ENCRYPT 0x0008 #define SEC_ENCRYPT 0x0008
#define SEC_RESET_SEQNO 0x0010 #define SEC_RESET_SEQNO 0x0010
#define SEC_IGNORE_SEQNO 0x0020 #define SEC_IGNORE_SEQNO 0x0020
@ -60,6 +65,9 @@
#define SEC_LICENSE_ENCRYPT_SC 0x0200 #define SEC_LICENSE_ENCRYPT_SC 0x0200
#define SEC_REDIRECTION_PKT 0x0400 #define SEC_REDIRECTION_PKT 0x0400
#define SEC_SECURE_CHECKSUM 0x0800 #define SEC_SECURE_CHECKSUM 0x0800
#define SEC_AUTODETECT_REQ 0x1000
#define SEC_AUTODETECT_RSP 0x2000
#define SEC_HEARTBEAT 0x4000
#define SEC_FLAGSHI_VALID 0x8000 #define SEC_FLAGSHI_VALID 0x8000
#define SEC_PKT_CS_MASK (SEC_EXCHANGE_PKT | SEC_INFO_PKT) #define SEC_PKT_CS_MASK (SEC_EXCHANGE_PKT | SEC_INFO_PKT)
@ -131,6 +139,9 @@ struct rdp_rdp
rdpSettings* settings; rdpSettings* settings;
rdpTransport* transport; rdpTransport* transport;
rdpExtension* extension; rdpExtension* extension;
rdpAutoDetect* autodetect;
rdpHeartbeat* heartbeat;
rdpMultitransport* multitransport;
struct rdp_mppc_dec* mppc_dec; struct rdp_mppc_dec* mppc_dec;
struct rdp_mppc_enc* mppc_enc; struct rdp_mppc_enc* mppc_enc;
struct crypto_rc4_struct* rc4_decrypt_key; struct crypto_rc4_struct* rc4_decrypt_key;
@ -191,6 +202,10 @@ BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channel_id);
int rdp_send_channel_data(rdpRdp* rdp, int channel_id, BYTE* data, int size); int rdp_send_channel_data(rdpRdp* rdp, int channel_id, BYTE* data, int size);
wStream* rdp_message_channel_pdu_init(rdpRdp* rdp);
BOOL rdp_send_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags);
int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s);
int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s);
void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking); void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking);

View File

@ -234,6 +234,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->DisableEncryption = FALSE; settings->DisableEncryption = FALSE;
settings->SaltedChecksum = TRUE; settings->SaltedChecksum = TRUE;
settings->ServerPort = 3389; settings->ServerPort = 3389;
settings->GatewayPort = 443;
settings->DesktopResize = TRUE; settings->DesktopResize = TRUE;
settings->ToggleFullscreen = TRUE; settings->ToggleFullscreen = TRUE;
settings->DesktopPosX = 0; settings->DesktopPosX = 0;
@ -248,8 +249,6 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->DisableThemes = FALSE; settings->DisableThemes = FALSE;
settings->ConnectionType = CONNECTION_TYPE_LAN; settings->ConnectionType = CONNECTION_TYPE_LAN;
settings->AutoReconnectionEnabled = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; settings->EncryptionMethods = ENCRYPTION_METHOD_NONE;
settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
@ -313,6 +312,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->DrawGdiPlusEnabled = FALSE; settings->DrawGdiPlusEnabled = FALSE;
settings->FrameMarkerCommandEnabled = FALSE; settings->FrameMarkerCommandEnabled = FALSE;
settings->SurfaceFrameMarkerEnabled = TRUE;
settings->BitmapCacheV3Enabled = FALSE; settings->BitmapCacheV3Enabled = FALSE;
settings->BitmapCacheEnabled = TRUE; settings->BitmapCacheEnabled = TRUE;
@ -379,7 +379,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->MultifragMaxRequestSize = 0xFFFF; settings->MultifragMaxRequestSize = 0xFFFF;
settings->GatewayUseSameCredentials = TRUE; settings->GatewayUseSameCredentials = FALSE;
settings->FastPathInput = TRUE; settings->FastPathInput = TRUE;
settings->FastPathOutput = TRUE; settings->FastPathOutput = TRUE;
@ -620,6 +620,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->MstscCookieMode = settings->MstscCookieMode; /* 1152 */ _settings->MstscCookieMode = settings->MstscCookieMode; /* 1152 */
_settings->SendPreconnectionPdu = settings->SendPreconnectionPdu; /* 1156 */ _settings->SendPreconnectionPdu = settings->SendPreconnectionPdu; /* 1156 */
_settings->IgnoreCertificate = settings->IgnoreCertificate; /* 1408 */ _settings->IgnoreCertificate = settings->IgnoreCertificate; /* 1408 */
_settings->ExternalCertificateManagement = settings->ExternalCertificateManagement; /* 1415 */
_settings->Workarea = settings->Workarea; /* 1536 */ _settings->Workarea = settings->Workarea; /* 1536 */
_settings->Fullscreen = settings->Fullscreen; /* 1537 */ _settings->Fullscreen = settings->Fullscreen; /* 1537 */
_settings->GrabKeyboard = settings->GrabKeyboard; /* 1539 */ _settings->GrabKeyboard = settings->GrabKeyboard; /* 1539 */
@ -667,6 +668,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->SoundBeepsEnabled = settings->SoundBeepsEnabled; /* 2944 */ _settings->SoundBeepsEnabled = settings->SoundBeepsEnabled; /* 2944 */
_settings->SurfaceCommandsEnabled = settings->SurfaceCommandsEnabled; /* 3520 */ _settings->SurfaceCommandsEnabled = settings->SurfaceCommandsEnabled; /* 3520 */
_settings->FrameMarkerCommandEnabled = settings->FrameMarkerCommandEnabled; /* 3521 */ _settings->FrameMarkerCommandEnabled = settings->FrameMarkerCommandEnabled; /* 3521 */
_settings->SurfaceFrameMarkerEnabled = settings->SurfaceFrameMarkerEnabled; /* 3522 */
_settings->RemoteFxOnly = settings->RemoteFxOnly; /* 3648 */ _settings->RemoteFxOnly = settings->RemoteFxOnly; /* 3648 */
_settings->RemoteFxCodec = settings->RemoteFxCodec; /* 3649 */ _settings->RemoteFxCodec = settings->RemoteFxCodec; /* 3649 */
_settings->RemoteFxImageCodec = settings->RemoteFxImageCodec; /* 3652 */ _settings->RemoteFxImageCodec = settings->RemoteFxImageCodec; /* 3652 */

View File

@ -67,6 +67,7 @@ void tcp_get_ip_address(rdpTcp * tcp)
struct sockaddr_in sockaddr; struct sockaddr_in sockaddr;
length = sizeof(sockaddr); length = sizeof(sockaddr);
ZeroMemory(&sockaddr, length);
if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0) if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0)
{ {
@ -76,19 +77,12 @@ void tcp_get_ip_address(rdpTcp * tcp)
} }
else else
{ {
strncpy(tcp->ip_address, "127.0.0.1", sizeof(tcp->ip_address)); strcpy(tcp->ip_address, "127.0.0.1");
} }
tcp->ip_address[sizeof(tcp->ip_address) - 1] = 0;
tcp->settings->IPv6Enabled = 0; tcp->settings->IPv6Enabled = 0;
if (tcp->settings->ClientAddress)
{
free(tcp->settings->ClientAddress); free(tcp->settings->ClientAddress);
tcp->settings->ClientAddress = NULL;
}
tcp->settings->ClientAddress = _strdup(tcp->ip_address); tcp->settings->ClientAddress = _strdup(tcp->ip_address);
} }
@ -125,7 +119,7 @@ void tcp_get_mac_address(rdpTcp * tcp)
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */
} }
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, UINT16 port) BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
{ {
UINT32 option_value; UINT32 option_value;
socklen_t option_len; socklen_t option_len;

View File

@ -29,6 +29,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#include <winpr/stream.h> #include <winpr/stream.h>
#include <winpr/winsock.h>
#ifndef MSG_NOSIGNAL #ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0 #define MSG_NOSIGNAL 0
@ -41,14 +42,14 @@ struct rdp_tcp
int sockfd; int sockfd;
char ip_address[32]; char ip_address[32];
BYTE mac_address[6]; BYTE mac_address[6];
struct rdp_settings* settings; rdpSettings* settings;
#ifdef _WIN32 #ifdef _WIN32
WSAEVENT wsa_event; WSAEVENT wsa_event;
#endif #endif
HANDLE event; HANDLE event;
}; };
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, UINT16 port); BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port);
BOOL tcp_disconnect(rdpTcp* tcp); BOOL tcp_disconnect(rdpTcp* tcp);
int tcp_read(rdpTcp* tcp, BYTE* data, int length); int tcp_read(rdpTcp* tcp, BYTE* data, int length);
int tcp_write(rdpTcp* tcp, BYTE* data, int length); int tcp_write(rdpTcp* tcp, BYTE* data, int length);

View File

@ -29,10 +29,10 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/stream.h>
#include <freerdp/error.h> #include <freerdp/error.h>
#include <freerdp/utils/tcp.h> #include <freerdp/utils/tcp.h>
#include <winpr/stream.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
@ -80,7 +80,7 @@ BOOL transport_disconnect(rdpTransport* transport)
if (transport->layer == TRANSPORT_LAYER_TLS) if (transport->layer == TRANSPORT_LAYER_TLS)
status &= tls_disconnect(transport->TlsIn); status &= tls_disconnect(transport->TlsIn);
if (transport->layer == TRANSPORT_LAYER_TSG || transport->layer == TRANSPORT_LAYER_TSG_TLS) if ((transport->layer == TRANSPORT_LAYER_TSG) || (transport->layer == TRANSPORT_LAYER_TSG_TLS))
{ {
tsg_disconnect(transport->tsg); tsg_disconnect(transport->tsg);
} }
@ -222,7 +222,13 @@ BOOL transport_connect_tls(rdpTransport* transport)
transport->layer = TRANSPORT_LAYER_TSG_TLS; transport->layer = TRANSPORT_LAYER_TSG_TLS;
if (tls_connect(transport->TsgTls) != TRUE) transport->TsgTls->hostname = transport->settings->ServerHostname;
transport->TsgTls->port = transport->settings->ServerPort;
if (transport->TsgTls->port == 0)
transport->TsgTls->port = 3389;
if (!tls_connect(transport->TsgTls))
{ {
if (!connectErrorCode) if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR; connectErrorCode = TLSCONNECTERROR;
@ -236,16 +242,22 @@ BOOL transport_connect_tls(rdpTransport* transport)
return TRUE; return TRUE;
} }
if (transport->TlsIn == NULL) if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings); transport->TlsIn = tls_new(transport->settings);
if (transport->TlsOut == NULL) if (!transport->TlsOut)
transport->TlsOut = transport->TlsIn; transport->TlsOut = transport->TlsIn;
transport->layer = TRANSPORT_LAYER_TLS; transport->layer = TRANSPORT_LAYER_TLS;
transport->TlsIn->sockfd = transport->TcpIn->sockfd; transport->TlsIn->sockfd = transport->TcpIn->sockfd;
if (tls_connect(transport->TlsIn) != TRUE) transport->TlsIn->hostname = transport->settings->ServerHostname;
transport->TlsIn->port = transport->settings->ServerPort;
if (transport->TlsIn->port == 0)
transport->TlsIn->port = 3389;
if (!tls_connect(transport->TlsIn))
{ {
if (!connectErrorCode) if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR; connectErrorCode = TLSCONNECTERROR;
@ -268,18 +280,18 @@ BOOL transport_connect_nla(rdpTransport* transport)
freerdp* instance; freerdp* instance;
rdpSettings* settings; rdpSettings* settings;
settings = transport->settings;
instance = (freerdp*) settings->instance;
if (!transport_connect_tls(transport)) if (!transport_connect_tls(transport))
return FALSE; return FALSE;
/* Network Level Authentication */ /* Network Level Authentication */
if (transport->settings->Authentication != TRUE) if (!settings->Authentication)
return TRUE; return TRUE;
settings = transport->settings; if (!transport->credssp)
instance = (freerdp*) settings->instance;
if (transport->credssp == NULL)
transport->credssp = credssp_new(instance, transport, settings); transport->credssp = credssp_new(instance, transport, settings);
if (credssp_authenticate(transport->credssp) < 0) if (credssp_authenticate(transport->credssp) < 0)
@ -296,6 +308,7 @@ BOOL transport_connect_nla(rdpTransport* transport)
} }
credssp_free(transport->credssp); credssp_free(transport->credssp);
transport->credssp = NULL;
return TRUE; return TRUE;
} }
@ -308,20 +321,30 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
transport->tsg = tsg; transport->tsg = tsg;
transport->SplitInputOutput = TRUE; transport->SplitInputOutput = TRUE;
if (transport->TlsIn == NULL) if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings); transport->TlsIn = tls_new(transport->settings);
transport->TlsIn->sockfd = transport->TcpIn->sockfd; transport->TlsIn->sockfd = transport->TcpIn->sockfd;
transport->TlsIn->hostname = transport->settings->GatewayHostname;
transport->TlsIn->port = transport->settings->GatewayPort;
if (transport->TlsOut == NULL) if (transport->TlsIn->port == 0)
transport->TlsIn->port = 443;
if (!transport->TlsOut)
transport->TlsOut = tls_new(transport->settings); transport->TlsOut = tls_new(transport->settings);
transport->TlsOut->sockfd = transport->TcpOut->sockfd; transport->TlsOut->sockfd = transport->TcpOut->sockfd;
transport->TlsOut->hostname = transport->settings->GatewayHostname;
transport->TlsOut->port = transport->settings->GatewayPort;
if (tls_connect(transport->TlsIn) != TRUE) if (transport->TlsOut->port == 0)
transport->TlsOut->port = 443;
if (!tls_connect(transport->TlsIn))
return FALSE; return FALSE;
if (tls_connect(transport->TlsOut) != TRUE) if (!tls_connect(transport->TlsOut))
return FALSE; return FALSE;
if (!tsg_connect(tsg, hostname, port)) if (!tsg_connect(tsg, hostname, port))
@ -342,10 +365,10 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
transport->layer = TRANSPORT_LAYER_TSG; transport->layer = TRANSPORT_LAYER_TSG;
transport->TcpOut = tcp_new(settings); transport->TcpOut = tcp_new(settings);
status = tcp_connect(transport->TcpIn, settings->GatewayHostname, 443); status = tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort);
if (status) if (status)
status = tcp_connect(transport->TcpOut, settings->GatewayHostname, 443); status = tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort);
if (status) if (status)
status = transport_tsg_connect(transport, hostname, port); status = transport_tsg_connect(transport, hostname, port);
@ -381,16 +404,16 @@ BOOL transport_accept_rdp(rdpTransport* transport)
BOOL transport_accept_tls(rdpTransport* transport) BOOL transport_accept_tls(rdpTransport* transport)
{ {
if (transport->TlsIn == NULL) if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings); transport->TlsIn = tls_new(transport->settings);
if (transport->TlsOut == NULL) if (!transport->TlsOut)
transport->TlsOut = transport->TlsIn; transport->TlsOut = transport->TlsIn;
transport->layer = TRANSPORT_LAYER_TLS; transport->layer = TRANSPORT_LAYER_TLS;
transport->TlsIn->sockfd = transport->TcpIn->sockfd; transport->TlsIn->sockfd = transport->TcpIn->sockfd;
if (tls_accept(transport->TlsIn, transport->settings->CertificateFile, transport->settings->PrivateKeyFile) != TRUE) if (!tls_accept(transport->TlsIn, transport->settings->CertificateFile, transport->settings->PrivateKeyFile))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -401,27 +424,27 @@ BOOL transport_accept_nla(rdpTransport* transport)
freerdp* instance; freerdp* instance;
rdpSettings* settings; rdpSettings* settings;
if (transport->TlsIn == NULL) settings = transport->settings;
instance = (freerdp*) settings->instance;
if (!transport->TlsIn)
transport->TlsIn = tls_new(transport->settings); transport->TlsIn = tls_new(transport->settings);
if (transport->TlsOut == NULL) if (!transport->TlsOut)
transport->TlsOut = transport->TlsIn; transport->TlsOut = transport->TlsIn;
transport->layer = TRANSPORT_LAYER_TLS; transport->layer = TRANSPORT_LAYER_TLS;
transport->TlsIn->sockfd = transport->TcpIn->sockfd; transport->TlsIn->sockfd = transport->TcpIn->sockfd;
if (tls_accept(transport->TlsIn, transport->settings->CertificateFile, transport->settings->PrivateKeyFile) != TRUE) if (!tls_accept(transport->TlsIn, transport->settings->CertificateFile, transport->settings->PrivateKeyFile))
return FALSE; return FALSE;
/* Network Level Authentication */ /* Network Level Authentication */
if (transport->settings->Authentication != TRUE) if (!settings->Authentication)
return TRUE; return TRUE;
settings = transport->settings; if (!transport->credssp)
instance = (freerdp*) settings->instance;
if (transport->credssp == NULL)
transport->credssp = credssp_new(instance, transport, settings); transport->credssp = credssp_new(instance, transport, settings);
if (credssp_authenticate(transport->credssp) < 0) if (credssp_authenticate(transport->credssp) < 0)
@ -429,6 +452,9 @@ BOOL transport_accept_nla(rdpTransport* transport)
fprintf(stderr, "client authentication failure\n"); fprintf(stderr, "client authentication failure\n");
credssp_free(transport->credssp); credssp_free(transport->credssp);
transport->credssp = NULL; transport->credssp = NULL;
tls_set_alert_code(transport->TlsIn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
return FALSE; return FALSE;
} }
@ -439,7 +465,7 @@ BOOL transport_accept_nla(rdpTransport* transport)
BOOL nla_verify_header(wStream* s) BOOL nla_verify_header(wStream* s)
{ {
if ((s->pointer[0] == 0x30) && (s->pointer[1] & 0x80)) if ((Stream_Pointer(s)[0] == 0x30) && (Stream_Pointer(s)[1] & 0x80))
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -449,17 +475,17 @@ UINT32 nla_read_header(wStream* s)
{ {
UINT32 length = 0; UINT32 length = 0;
if (s->pointer[1] & 0x80) if (Stream_Pointer(s)[1] & 0x80)
{ {
if ((s->pointer[1] & ~(0x80)) == 1) if ((Stream_Pointer(s)[1] & ~(0x80)) == 1)
{ {
length = s->pointer[2]; length = Stream_Pointer(s)[2];
length += 3; length += 3;
Stream_Seek(s, 3); Stream_Seek(s, 3);
} }
else if ((s->pointer[1] & ~(0x80)) == 2) else if ((Stream_Pointer(s)[1] & ~(0x80)) == 2)
{ {
length = (s->pointer[2] << 8) | s->pointer[3]; length = (Stream_Pointer(s)[2] << 8) | Stream_Pointer(s)[3];
length += 4; length += 4;
Stream_Seek(s, 4); Stream_Seek(s, 4);
} }
@ -470,7 +496,7 @@ UINT32 nla_read_header(wStream* s)
} }
else else
{ {
length = s->pointer[1]; length = Stream_Pointer(s)[1];
length += 2; length += 2;
Stream_Seek(s, 2); Stream_Seek(s, 2);
} }
@ -482,11 +508,11 @@ UINT32 nla_header_length(wStream* s)
{ {
UINT32 length = 0; UINT32 length = 0;
if (s->pointer[1] & 0x80) if (Stream_Pointer(s)[1] & 0x80)
{ {
if ((s->pointer[1] & ~(0x80)) == 1) if ((Stream_Pointer(s)[1] & ~(0x80)) == 1)
length = 3; length = 3;
else if ((s->pointer[1] & ~(0x80)) == 2) else if ((Stream_Pointer(s)[1] & ~(0x80)) == 2)
length = 4; length = 4;
else else
fprintf(stderr, "Error reading TSRequest!\n"); fprintf(stderr, "Error reading TSRequest!\n");
@ -499,7 +525,7 @@ UINT32 nla_header_length(wStream* s)
return length; return length;
} }
int transport_read_layer(rdpTransport* transport, UINT8* data, int bytes) int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
{ {
int read = 0; int read = 0;
int status = -1; int status = -1;
@ -542,10 +568,12 @@ int transport_read_layer(rdpTransport* transport, UINT8* data, int bytes)
int transport_read(rdpTransport* transport, wStream* s) int transport_read(rdpTransport* transport, wStream* s)
{ {
int status; int status;
int position;
int pduLength; int pduLength;
int streamPosition; BYTE header[4];
int transport_status; int transport_status;
position = 0;
pduLength = 0; pduLength = 0;
transport_status = 0; transport_status = 0;
@ -556,54 +584,57 @@ int transport_read(rdpTransport* transport, wStream* s)
return -1; return -1;
/* first check if we have header */ /* first check if we have header */
streamPosition = Stream_GetPosition(s); position = Stream_GetPosition(s);
if (streamPosition < 4) if (position < 4)
{ {
status = transport_read_layer(transport, Stream_Buffer(s) + streamPosition, 4 - streamPosition); status = transport_read_layer(transport, Stream_Buffer(s) + position, 4 - position);
if (status < 0) if (status < 0)
return status; return status;
transport_status += status; transport_status += status;
if ((status + streamPosition) < 4) if ((status + position) < 4)
return transport_status; return transport_status;
streamPosition += status; position += status;
} }
CopyMemory(header, Stream_Buffer(s), 4); /* peek at first 4 bytes */
/* if header is present, read in exactly one PDU */ /* if header is present, read in exactly one PDU */
if (s->buffer[0] == 0x03) if (header[0] == 0x03)
{ {
/* TPKT header */ /* TPKT header */
pduLength = (s->buffer[2] << 8) | s->buffer[3]; pduLength = (header[2] << 8) | header[3];
} }
else if (s->buffer[0] == 0x30) else if (header[0] == 0x30)
{ {
/* TSRequest (NLA) */ /* TSRequest (NLA) */
if (s->buffer[1] & 0x80) if (header[1] & 0x80)
{ {
if ((s->buffer[1] & ~(0x80)) == 1) if ((header[1] & ~(0x80)) == 1)
{ {
pduLength = s->buffer[2]; pduLength = header[2];
pduLength += 3; pduLength += 3;
} }
else if ((s->buffer[1] & ~(0x80)) == 2) else if ((header[1] & ~(0x80)) == 2)
{ {
pduLength = (s->buffer[2] << 8) | s->buffer[3]; pduLength = (header[2] << 8) | header[3];
pduLength += 4; pduLength += 4;
} }
else else
{ {
fprintf(stderr, "Error reading TSRequest!\n"); fprintf(stderr, "Error reading TSRequest!\n");
return -1;
} }
} }
else else
{ {
pduLength = s->buffer[1]; pduLength = header[1];
pduLength += 2; pduLength += 2;
} }
} }
@ -611,13 +642,13 @@ int transport_read(rdpTransport* transport, wStream* s)
{ {
/* Fast-Path Header */ /* Fast-Path Header */
if (s->buffer[1] & 0x80) if (header[1] & 0x80)
pduLength = ((s->buffer[1] & 0x7F) << 8) | s->buffer[2]; pduLength = ((header[1] & 0x7F) << 8) | header[2];
else else
pduLength = s->buffer[1]; pduLength = header[1];
} }
status = transport_read_layer(transport, Stream_Buffer(s) + streamPosition, pduLength - streamPosition); status = transport_read_layer(transport, Stream_Buffer(s) + position, pduLength - position);
if (status < 0) if (status < 0)
return status; return status;
@ -626,14 +657,14 @@ int transport_read(rdpTransport* transport, wStream* s)
#ifdef WITH_DEBUG_TRANSPORT #ifdef WITH_DEBUG_TRANSPORT
/* dump when whole PDU is read */ /* dump when whole PDU is read */
if (streamPosition + status >= pduLength) if (position + status >= pduLength)
{ {
fprintf(stderr, "Local < Remote\n"); fprintf(stderr, "Local < Remote\n");
winpr_HexDump(Stream_Buffer(s), pduLength); winpr_HexDump(Stream_Buffer(s), pduLength);
} }
#endif #endif
if (streamPosition + status >= pduLength) if (position + status >= pduLength)
{ {
WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), pduLength, WLOG_PACKET_INBOUND); WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), pduLength, WLOG_PACKET_INBOUND);
} }
@ -660,7 +691,7 @@ int transport_write(rdpTransport* transport, wStream* s)
int length; int length;
int status = -1; int status = -1;
WaitForSingleObject(transport->WriteMutex, INFINITE); EnterCriticalSection(&(transport->WriteLock));
length = Stream_GetPosition(s); length = Stream_GetPosition(s);
Stream_SetPosition(s, 0); Stream_SetPosition(s, 0);
@ -725,7 +756,7 @@ int transport_write(rdpTransport* transport, wStream* s)
if (s->pool) if (s->pool)
Stream_Release(s); Stream_Release(s);
ReleaseMutex(transport->WriteMutex); LeaveCriticalSection(&(transport->WriteLock));
return status; return status;
} }
@ -802,7 +833,7 @@ int transport_check_fds(rdpTransport* transport)
{ {
int pos; int pos;
int status; int status;
UINT16 length; int length;
int recv_status; int recv_status;
wStream* received; wStream* received;
@ -1041,8 +1072,8 @@ rdpTransport* transport_new(rdpSettings* settings)
transport->blocking = TRUE; transport->blocking = TRUE;
transport->ReadMutex = CreateMutex(NULL, FALSE, NULL); InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000);
transport->WriteMutex = CreateMutex(NULL, FALSE, NULL); InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000);
transport->layer = TRANSPORT_LAYER_TCP; transport->layer = TRANSPORT_LAYER_TCP;
} }
@ -1056,8 +1087,17 @@ void transport_free(rdpTransport* transport)
{ {
if (transport->async) if (transport->async)
{ {
assert(!transport->thread); if (transport->stopEvent)
assert(!transport->stopEvent); {
SetEvent(transport->stopEvent);
WaitForSingleObject(transport->thread, INFINITE);
CloseHandle(transport->thread);
CloseHandle(transport->stopEvent);
transport->thread = NULL;
transport->stopEvent = NULL;
}
} }
if (transport->ReceiveBuffer) if (transport->ReceiveBuffer)
@ -1089,8 +1129,8 @@ void transport_free(rdpTransport* transport)
tsg_free(transport->tsg); tsg_free(transport->tsg);
transport->tsg = NULL; transport->tsg = NULL;
CloseHandle(transport->ReadMutex); DeleteCriticalSection(&(transport->ReadLock));
CloseHandle(transport->WriteMutex); DeleteCriticalSection(&(transport->WriteLock));
free(transport); free(transport);
} }

View File

@ -75,8 +75,8 @@ struct rdp_transport
HANDLE stopEvent; HANDLE stopEvent;
HANDLE thread; HANDLE thread;
BOOL async; BOOL async;
HANDLE ReadMutex; CRITICAL_SECTION ReadLock;
HANDLE WriteMutex; CRITICAL_SECTION WriteLock;
wLog* log; wLog* log;
}; };

Some files were not shown because too many files have changed in this diff Show More