diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e41e9..3ae1759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,10 +217,6 @@ if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG") - if(NOT OPENBSD) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") - endif() CHECK_C_COMPILER_FLAG (-Wno-builtin-macro-redefined Wno-builtin-macro-redefined) if(Wno-builtin-macro-redefined) @@ -700,17 +696,17 @@ if (TARGET_ARCH MATCHES "sparc") endif() # Path to put FreeRDP data -set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp") +set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp${FREERDP_VERSION_MAJOR}") # Path to put plugins set(FREERDP_LIBRARY_PATH "${CMAKE_INSTALL_LIBDIR}") -set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp") +set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}") set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") # Path to put extensions -set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions") +set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions") # Include directories include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/ChangeLog b/ChangeLog index 6e422d1..5ac7fb3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,472 @@ +2016-03-17 11:06:39 +0100 akallabeth (75ae3f5) + + * Merge pull request #3243 from hardening/typofix (HEAD, + origin/master, origin/HEAD, master) + +2016-03-17 11:02:51 +0100 Bernhard Miklautz (14daecf) + + * Merge pull request #3240 from akallabeth/drive_fixes + +2016-03-17 10:44:11 +0100 David FORT (2cb3717) + + * Fixed a typo in debug messages + +2016-03-17 09:34:24 +0100 Armin Novak (43b13ff) + + * Replace SetFilePointerEx with SetFilePointer. + +2016-03-17 09:33:39 +0100 Armin Novak (f45be8d) + + * Print device name when loading channel. + +2016-03-16 15:19:11 +0100 Martin Fleisz (80cd647) + + * Merge pull request #3164 from akallabeth/windows_UnixChangeFileMode + +2016-03-16 14:05:55 +0100 Bernhard Miklautz (eb5e303) + + * Merge pull request #3215 from akallabeth/avc_444 + +2016-03-16 13:56:39 +0100 Bernhard Miklautz (90b3bf4) + + * Merge pull request #3204 from akallabeth/rdp_file_preference_fix + +2016-03-16 13:46:47 +0100 Armin Novak (7faff04) + + * Assume the update rectangle is inclusive. + +2016-03-14 09:01:57 +0100 Armin Novak (dfdc4c3) + + * Fixed comments. + +2016-03-14 08:57:00 +0100 Armin Novak (9ab3532) + + * Renamed GFX defines to conform to spec. + +2016-03-02 15:16:49 +0100 Armin Novak (5bc333c) + + * Implemented GFX AVC444 support. + +2016-03-02 14:53:55 +0100 Armin Novak (3309bf8) + + * Implemented YUV444 related primitives. + +2016-03-02 14:39:36 +0100 Armin Novak (3a3ec85) + + * Unified RDPGFX_RECT16 and RECTANGLE_16 + +2016-03-16 13:32:51 +0100 akallabeth (0c99d6a) + + * Merge pull request #3226 from rjcorrig/#3198 + +2016-03-16 13:32:29 +0100 akallabeth (2ea56c6) + + * Merge pull request #3234 from bmiklautz/rdkt_version + +2016-03-16 08:29:21 -0400 Robert Corrigan (a4f0089) + + * winpr_detect_windows_time_zone should have void argument + +2016-03-16 13:15:39 +0100 Armin Novak (fd26624) + + * Parse RDP and assistance files in parser. + +2016-03-16 13:05:00 +0100 Armin Novak (fb44b68) + + * Removed windows extra handling for RDP files. + +2016-03-16 13:15:24 +0100 Bernhard Miklautz (babbc4b) + + * Increase rdtk version to 2.0.0 + +2016-03-16 13:08:06 +0100 Armin Novak (3d23a77) + + * Updated ConvertToUnicode return check. + +2016-03-16 13:03:33 +0100 Bernhard Miklautz (228f6b1) + + * Merge pull request #3207 from akallabeth/mic_crash_fix + +2016-03-16 12:39:36 +0100 Armin Novak (059c754) + + * Fixed double free. + +2016-03-16 11:58:31 +0100 Bernhard Miklautz (1b15636) + + * Merge pull request #3214 from hardening/fix_systemd_appender + +2016-03-15 09:25:50 +0100 akallabeth (b35f306) + + * Merge pull request #3225 from mfleisz/fix_set_err_info + +2016-03-10 15:10:49 -0500 Robert Corrigan (16796b9) + + * winpr: Updates time zones and fixes bias values + +2016-03-14 15:28:56 +0100 Bernhard Miklautz (c5fd49c) + + * Merge pull request #3223 from comicfans/wayland_fix + +2016-03-14 15:27:15 +0100 Martin Fleisz (b2d24a4) + + * freerdp: Fix possible crash when setting error info in server-mode + +2016-03-14 15:13:52 +0100 Bernhard Miklautz (05bcec4) + + * Merge pull request #3224 from mfleisz/win32_bld_fix + +2016-03-14 14:08:48 +0100 Martin Fleisz (0249b09) + + * winpr: Fix definition of PathFileExists on Win32 + +2016-03-14 12:51:50 +0000 comicfans44 (6603039) + + * only compile wayland client when WAYLAND_FOUND + +2016-03-14 13:19:08 +0100 Armin Novak (2dbc1a0) + + * Reverted WTS API changes. + +2016-03-08 13:19:40 +0100 Armin Novak (d06723e) + + * Fixed return value for failed malloc. + +2016-03-07 12:54:49 +0100 Armin Novak (36cbf1b) + + * Fixed error handling for channel load failures. + +2016-03-14 13:00:52 +0100 Bernhard Miklautz (6ebf452) + + * Merge pull request #3209 from akallabeth/android_translation_fix + +2016-03-14 10:08:25 +0100 akallabeth (4ad3428) + + * Merge pull request #3221 from bmiklautz/fix_nightlies + +2016-03-14 09:57:33 +0100 Bernhard Miklautz (e13a327) + + * Merge pull request #3212 from realjiangms/fix_default_audin + +2016-03-14 09:53:45 +0100 Armin Novak (77d82f1) + + * Removed untranslatable strings from translated files. + +2016-03-14 09:38:35 +0100 Bernhard Miklautz (3bae203) + + * pkg/deb: adapt channel paths + +2016-03-14 09:20:30 +0100 Martin Fleisz (9554177) + + * Merge pull request #3213 from akallabeth/android_build_fixes + +2016-03-11 11:22:59 +0100 Martin Fleisz (66ae3f2) + + * Merge pull request #3177 from akallabeth/codec_reset_fix + +2016-03-10 23:41:12 +0100 Hardening (19494bd) + + * Make systemd appender honor layout and log off + +2016-03-10 22:07:30 +0100 Armin Novak (f60b8d5) + + * Replaced version patch with make argument. + +2016-03-10 21:54:11 +0100 Armin Novak (4a7816d) + + * Updated OpenSSL version in script. + +2016-03-10 21:52:40 +0100 Armin Novak (382626f) + + * Fixed settings load/store. + +2016-03-10 21:18:19 +0100 Armin Novak (cabcf7c) + + * Fixed paralell building issue. + +2016-03-11 01:52:18 +0800 zihao.jiang (40ea6e9) + + * audin: Fixed default sys argument for audin PR #3173 fixed argument + parsing. However it breaks the usage without specifying + subsystem: "/microphone" In particular, aFreerdp + microphone redirect is broken as it exactly uses + "/microphone" This PR fixes the regression. Fix: We should + not call CommandLineParseArgumentsA if argc is only 1 + (same case as rdpsnd_main.c) + +2016-03-10 08:22:30 +0100 Martin Fleisz (1feb03d) + + * Merge pull request #3210 from hardening/env_fix + +2016-03-09 14:10:31 +0100 David FORT (b3c0478) + + * Don't require HOME env var to be set for server-side code + +2016-03-08 20:34:19 +0100 Armin Novak (15498ea) + + * Marked non translatable strings as such. + +2016-03-08 16:27:51 +0100 Armin Novak (1d4fd05) + + * Reverted translation of internal VALUE arrays. + +2016-03-08 20:50:30 +0100 akallabeth (ff1eb25) + + * Merge pull request #3172 from + realjiangms/android_launch_by_scheme_2720 + +2016-02-27 18:31:43 +0800 zihao.jiang (0927114) + + * android: Allow freerdp mobile version to be launched from URI + (freerdp://) It would be good if we have a easy way to + call aFreeRDP in another Android APP (Requirement also + mentioned in #2720) We can define a scheme (freerdp://) as + unified way to launch FreeRDP from another APP or browser + and connect to compatible RDP server 1. Define scheme + freerdp:// 2. General form could be + freerdp://user@hostname:port/connect?key1=value&key2=-&key3=%2b&key4= + 3. [user] part would be translated to /u: 4. + [hostname:port] would be translated to /v: 5. The + [user@hostname:port] part would be used as app title, + currently it's just the progress dialog title 6. query + parameters would be translated to command line arguments. + Later same arguments will overwrite the formers: a. + key1=value: => /key1:value b. key2=-: + => -key2 c. key3=%2b => +key3 + (%2b is url encoded +) d. key4= + => /key4 e. Especially, drive=sdcard will be properly + handled with local sdcard path. On my device it will be + translated to /drive:sdcard,/storage/emulated/0 + +2016-03-08 10:05:57 +0100 Martin Fleisz (30325f1) + + * Merge pull request #3181 from akallabeth/wlog_filter_fix + +2016-03-07 15:39:59 +0100 Bernhard Miklautz (9f8baf3) + + * Merge pull request #3206 from akallabeth/openssl_unification + +2016-03-07 13:12:38 +0100 Armin Novak (bb3448f) + + * Set variable to NULL to prevent double free. + +2016-03-07 11:51:13 +0100 Armin Novak (2208a84) + + * Moved assistance to winpr crypto. + +2016-03-07 10:55:51 +0100 akallabeth (52f1e6b) + + * Merge pull request #3086 from DavBfr/fix-rdpdr + +2016-03-07 10:50:35 +0100 akallabeth (ece552d) + + * Merge pull request #3200 from dwmw2/master + +2016-03-07 09:43:35 +0100 Armin Novak (83ef642) + + * Use common command line parser. + +2016-03-07 09:43:53 +0100 Armin Novak (4bb33e9) + + * Reparse command line after RDP or assistance file. + +2016-03-07 09:44:07 +0100 Armin Novak (36241ed) + + * Fix memory leaks if parsed multiple times. + +2016-03-07 09:24:44 +0100 Martin Fleisz (f0cc927) + + * Merge pull request #3202 from akallabeth/file_bsd_fix + +2016-03-04 09:25:04 +0100 Armin Novak (34b1236) + + * Fixed FreeBSD support for filetime settings. + +2016-03-04 13:22:58 +0000 David Woodhouse (701f54e) + + * winpr: Bump API version to 2.0 + +2016-03-04 11:19:00 +0100 Hardening (fb63dd2) + + * Merge pull request #3194 from + nfedera/fix-convertfromunicode-hardening + +2016-03-04 11:17:42 +0100 Bernhard Miklautz (9fa85ae) + + * Merge pull request #1726 from grpomega/patch-3 + +2016-03-04 00:45:26 +0100 Norbert Federa (de4adef) + + * fix logon info processing + +2016-03-03 20:39:31 +0100 Bernhard Miklautz (120bd2d) + + * Merge pull request #3173 from akallabeth/audin_arg_fix + +2016-03-03 17:34:57 +0100 Martin Fleisz (151f435) + + * Merge pull request #3196 from akallabeth/exported_symbols_fix + +2016-03-03 17:11:26 +0100 Armin Novak (fb88ad0) + + * Fixed symbol export for sound plugins. + +2016-03-03 16:21:12 +0100 Norbert Federa (ef4b29e) + + * ConvertFromUnicode fixes and misc hardening + +2016-03-03 13:58:42 +0100 Bernhard Miklautz (167fd47) + + * Merge pull request #3192 from akallabeth/plugin_path_fix + +2016-03-03 12:07:10 +0100 Armin Novak (ee2839f) + + * Caching log filter after first use. + +2016-03-03 12:12:21 +0100 Martin Fleisz (f150575) + + * Merge pull request #3191 from hardening/saveInfoPdu_fix + +2016-03-03 11:45:12 +0100 David FORT (f5ce5e7) + + * Fix parsing of saveSessionInfo PDU + +2016-03-03 11:36:26 +0100 Armin Novak (767e6bb) + + * Updated freerdp plugin path to use major version. + +2016-03-03 11:06:24 +0100 Martin Fleisz (2710ebf) + + * Merge pull request #3187 from akallabeth/client_name_fix + +2016-03-03 09:08:30 +0100 Armin Novak (7dcba9a) + + * Removed additional '\0' from TUNNEL_AUTH message. + +2016-03-02 20:53:19 +0100 Hardening (9afa928) + + * Merge pull request #3184 from xhaakon/fix-ubuntu-gcc-build + +2016-02-23 15:27:33 +0100 Jakub Adam (bc750e9) + + * Fix build on older 32-bit Ubuntu releases + +2016-03-02 19:02:01 +0100 Armin Novak (0ea7aea) + + * Remember filter log level. + +2016-03-01 17:10:22 -0800 David PHAM-VAN (40504c5) + + * Fix Uninitialized Variable + +2016-03-02 19:03:46 +0100 akallabeth (e71369d) + + * Merge pull request #3183 from bmiklautz/timezone_regression + +2016-02-26 10:32:54 -0800 David PHAM-VAN (f4eb278) + + * Mount only removable devices and network drives in Windows; Adds + consistency with Linux and Mac + +2016-02-26 10:31:14 -0800 David PHAM-VAN (31d9599) + + * Move first_hotplug call to parent thread to avoid parallel access + to devman dictionary + +2016-02-26 10:19:21 -0800 David PHAM-VAN (2f28b6c) + + * Improve code using more winpr functions + +2015-09-07 12:16:03 +0200 David PHAM-VAN (2e1e6a4) + + * Add hotplug support for MacOS + +2016-01-07 11:04:10 -0800 David PHAM-VAN (a20950f) + + * Implement FileAllocationInformation + +2016-03-02 12:37:48 -0500 Bernhard Miklautz (7075353) + + * winpr: fix regression in timezone detection + +2016-03-02 10:33:41 -0500 Bernhard Miklautz (ee40be2) + + * Merge pull request #3182 from xhaakon/shadow-pkg-config + +2016-03-02 10:20:12 +0100 Jakub Adam (9f0b14f) + + * shadow/subsystem: fix pkgconfig file + +2016-03-01 17:30:08 +0100 Armin Novak (5bb68a0) + + * Fixed broken resource cleanup. + +2016-03-01 17:14:35 +0100 Armin Novak (ce8f3f2) + + * Fixed context reset of sample server. + +2016-03-01 16:56:36 +0100 Armin Novak (09e957f) + + * Fixed broken check. + +2016-03-01 16:39:53 +0100 Armin Novak (8997c6c) + + * Added log messages for unsupported surface commands. + +2016-03-01 16:17:28 +0100 Armin Novak (2e110c7) + + * Fixed codec reset, now resetting resolution too. + +2016-03-02 14:11:15 +0100 Armin Novak (41fdac2) + + * Respecting filter in WLog_GetLogLevel + +2016-03-02 09:43:46 +0100 Martin Fleisz (857c373) + + * Merge pull request #3163 from akallabeth/set_file_time + +2016-03-02 09:43:24 +0100 Martin Fleisz (cfe5923) + + * Merge pull request #3179 from akallabeth/minor_fixes + +2016-02-26 12:53:23 +0100 Armin Novak (c74e37d) + + * Implemented UnixChangeFileMode for windows. + +2016-03-02 09:16:59 +0100 Armin Novak (65cddbc) + + * Removed obsolete log message. + +2016-03-02 09:16:49 +0100 Armin Novak (227ecc4) + + * Fixed uninitialized variable. + +2016-03-01 23:34:57 +0100 Hardening (49a0a9c) + + * Merge pull request #3178 from hendwolt/master + +2016-03-01 21:49:21 +0100 Hendrik Woltersdorf (a5bb05b) + + * fix wayland-client.h not found + +2016-03-01 16:44:19 +0100 Bernhard Miklautz (e02af82) + + * Merge pull request #3160 from akallabeth/stream_fixes + +2016-03-01 11:40:11 +0100 Armin Novak (a79072a) + + * Added tests for remaining stream functions. + +2016-03-01 11:39:21 +0100 Armin Novak (e7814d5) + + * Fixed stream API for Stream_Copy. + +2016-03-01 10:29:51 +0100 Armin Novak (a98e0f9) + + * Reverted opaque structures. + 2016-02-29 17:39:18 +0100 Norbert Federa (b4b8239) - * Merge pull request #3176 from bmiklautz/shadow_subsystem (HEAD, - origin/master, origin/HEAD, master) + * Merge pull request #3176 from bmiklautz/shadow_subsystem 2016-02-29 17:10:53 +0100 Bernhard Miklautz (014f31d) @@ -48,6 +513,18 @@ * Fixed crypto tests. +2016-02-29 12:54:31 +0100 Armin Novak (b690470) + + * Replaced stream manipulation with EnsureCapacity. + +2016-02-29 12:51:54 +0100 Armin Novak (46fa7ec) + + * Fixed invalid stream copy length. + +2016-02-29 12:34:53 +0100 Armin Novak (8482fbf) + + * Fixed formatting. + 2016-02-29 11:12:32 +0100 Armin Novak (19568c6) * Fixed indentation. @@ -64,6 +541,10 @@ * Refactored crypto *_New functions. +2016-02-28 19:56:57 +0100 Armin Novak (71bea3e) + + * Fixed argument parsing for audin. + 2016-02-28 11:12:17 +0100 Armin Novak (92c1578) * Updated RC4 API, fixed crashing bug. @@ -101,6 +582,10 @@ * Removed crypto_nonce. +2016-02-27 22:16:41 +0100 Armin Novak (4929844) + + * Fixed const argument for Stream_Write. + 2016-02-27 22:13:59 +0100 Armin Novak (86436bc) * Added API export for uwac. @@ -129,6 +614,19 @@ * Fixed duplicate loading of smartcard and printers. +2016-02-26 12:13:02 +0100 Armin Novak (98d4a93) + + * Added support for android SetFileTime. Deactivated libjpeg support + for android. + +2016-02-26 11:22:56 +0100 Armin Novak (5537230) + + * Fixed missing iOS UTIME_OMIT. + +2016-02-26 10:48:53 +0100 Armin Novak (436be24) + + * Implemented SetFileTime + 2016-02-26 09:57:35 +0100 Martin Fleisz (4f22682) * Merge pull request #3151 from akallabeth/timezone_refactor @@ -165,6 +663,18 @@ * cmake/FindWayland: cleanup +2016-02-25 20:13:56 +0100 Armin Novak (cf9543e) + + * Converted Stream defines to inline functions. + +2016-02-25 20:01:12 +0100 Armin Novak (e79eee2) + + * Fixed Stream API misuse. + +2016-02-25 19:37:20 +0100 Armin Novak (b61ab5e) + + * Fixed stream copy in update_message_SurfaceCommand + 2016-02-25 16:57:48 +0100 akallabeth (16ba8f3) * Merge pull request #3159 from bmiklautz/disable_mipsel @@ -15949,6 +16459,10 @@ * libwinpr-crt: add byteswap macros +2014-03-06 10:04:53 -0600 grpomega (c005e81) + + * Need Week instead of Day for TZ transistion + 2014-03-05 18:03:39 -0500 Marc-André Moreau (95127d5) * libfreerdp-codec: start testing MPPC against large buffer diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index a3a7b3a..e49a1cc 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -522,6 +522,8 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* arg #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index b036437..737c828 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -82,7 +82,7 @@ struct _AUDIN_PLUGIN /* Parsed plugin data */ UINT16 fixed_format; - UINT16 fixed_channel; + UINT16 fixed_channel; UINT32 fixed_rate; char* subsystem; char* device_name; @@ -93,6 +93,8 @@ struct _AUDIN_PLUGIN rdpContext* rdpcontext; }; +static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); + /** * Function description * @@ -639,8 +641,12 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI { PFREERDP_AUDIN_DEVICE_ENTRY entry; FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; UINT error; + if (!audin_process_addin_args(audin, args)) + return CHANNEL_RC_INITIALIZATION_ERROR; + entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0); if (entry == NULL) @@ -660,6 +666,7 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI return error; } + WLog_INFO(TAG, "Loaded %s backend for audin", name); return CHANNEL_RC_OK; } @@ -707,18 +714,24 @@ static COMMAND_LINE_ARGUMENT_A audin_args[] = { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; -static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) +BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; UINT error; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; + if (args->argc == 1) + { + return TRUE; + } + + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_args, flags, audin, NULL, NULL); + if (status != 0) + return FALSE; arg = audin_args; @@ -788,7 +801,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) char *device; }; - UINT error = CHANNEL_RC_OK; + UINT error = CHANNEL_RC_INITIALIZATION_ERROR; ADDIN_ARGV* args; AUDIN_PLUGIN* audin; struct SubsystemEntry entries[] = @@ -819,51 +832,71 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) assert(pEntryPoints->GetPlugin); audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin"); - if (audin == NULL) + if (audin != NULL) + return CHANNEL_RC_ALREADY_INITIALIZED; + + audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN)); + if (!audin) { - audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN)); - if (!audin) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - audin->iface.Initialize = audin_plugin_initialize; - audin->iface.Connected = NULL; - audin->iface.Disconnected = NULL; - audin->iface.Terminated = audin_plugin_terminated; - - error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin); + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; } + audin->iface.Initialize = audin_plugin_initialize; + audin->iface.Connected = NULL; + audin->iface.Disconnected = NULL; + audin->iface.Terminated = audin_plugin_terminated; + args = pEntryPoints->GetPluginData(pEntryPoints); audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; - while (entry && entry->subsystem && !audin->device) + if (args) { - if ((error = audin_set_subsystem(audin, entry->subsystem))) - { - WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!", - entry->subsystem, error); - } - else if ((error = audin_set_device_name(audin, entry->device))) - { - WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!", - entry->subsystem, error); - } - else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) + if (!audin_process_addin_args(audin, args)) + goto out; + } + + if (audin->subsystem) + { + if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!", - entry->subsystem, error); + audin->subsystem, error); + goto out; } + } + else + { + while (entry && entry->subsystem && !audin->device) + { + if ((error = audin_set_subsystem(audin, entry->subsystem))) + { + WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_set_device_name(audin, entry->device))) + { + WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) + { + WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!", + entry->subsystem, error); + } - entry++; + entry++; + } } if (audin->device == NULL) - { WLog_ERR(TAG, "no sound device."); - } + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin); + +out: + if (error != CHANNEL_RC_OK) + audin_plugin_terminated((IWTSPlugin*)audin); return error; } diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c index 07b7894..d7d8db8 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.c @@ -402,6 +402,8 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index a9123c5..cd0d399 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -476,6 +476,9 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry \ opensles_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry \ + FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index e79937a..753298b 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -485,6 +485,8 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args) #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index 829e505..ad2f480 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -525,6 +525,8 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 5f7c6d9..e59a84e 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -393,6 +393,8 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index e686a7c..a7afae5 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -102,16 +102,25 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data formats[index].formatName = NULL; + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { + /* ensure null termination */ formats[index].formatName = (char*) malloc(32 + 1); if (!formats[index].formatName) { - WLog_ERR(TAG, "calloc failed!"); + WLog_ERR(TAG, "malloc failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } @@ -125,8 +134,16 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data if (wszFormatName[0]) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - 16, &(formats[index].formatName), 0, NULL, NULL); + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } } } @@ -185,8 +202,13 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data if (formatNameLength) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - -1, &(formats[index].formatName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } } Stream_Seek(s, (formatNameLength + 1) * 2); diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 18b594e..21fb784 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -159,10 +159,10 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* WLog_ERR(TAG, "cliprdr_get_client_interface failed!"); return ERROR_INTERNAL_ERROR; } - + Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ - + DEBUG_CLIPRDR("Version: %d", version); #ifdef WITH_DEBUG_CLIPRDR cliprdr_print_general_capability_flags(generalFlags); @@ -179,7 +179,7 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* if (cliprdr->canLockClipData) cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; - + cliprdr->capabilitiesReceived = TRUE; if (!context->custom) @@ -187,7 +187,7 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* WLog_ERR(TAG, "context->custom not set!"); return ERROR_INTERNAL_ERROR; } - + capabilities.cCapabilitiesSets = 1; capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; @@ -215,7 +215,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 UINT16 cCapabilitiesSets; UINT16 capabilitySetType; UINT error = CHANNEL_RC_OK; - + Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ @@ -235,7 +235,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 return error; } break; - + default: WLog_ERR(TAG, "unknown cliprdr capability set: %d", capabilitySetType); return CHANNEL_RC_BAD_PROC; @@ -273,13 +273,13 @@ static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI * When the server capabilities pdu is not used, default capabilities * corresponding to a generalFlags field set to zero are assumed. */ - + cliprdr->useLongFormatNames = FALSE; cliprdr->streamFileClipEnabled = FALSE; cliprdr->fileClipNoFilePaths = TRUE; cliprdr->canLockClipData = FALSE; } - + monitorReady.msgType = CB_MONITOR_READY; monitorReady.msgFlags = flags; monitorReady.dataLen = length; @@ -354,7 +354,7 @@ static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStrea WLog_ERR(TAG, "context->custom not set!"); return ERROR_INTERNAL_ERROR; } - + if (Stream_GetRemainingLength(s) < 4) { WLog_ERR(TAG, "not enought remaining data"); @@ -366,7 +366,7 @@ static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStrea response.dataLen = length; Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ - + response.cbRequested = length - 4; response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ @@ -434,7 +434,7 @@ static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, WLog_ERR(TAG, "context->custom not set!"); return ERROR_INTERNAL_ERROR; } - + if (Stream_GetRemainingLength(s) < 4) { WLog_ERR(TAG, "not enought remaining data"); @@ -637,7 +637,7 @@ UINT cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LI if (!cliprdr->useLongFormatNames) { length = formatList->numFormats * 36; - + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); if (!s) @@ -649,40 +649,40 @@ UINT cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LI for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); - + Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - + formatNameSize = 0; formatNameLength = 0; szFormatName = format->formatName; - + if (asciiNames) { if (szFormatName) formatNameLength = strlen(szFormatName); - + if (formatNameLength > 31) formatNameLength = 31; - + Stream_Write(s, szFormatName, formatNameLength); Stream_Zero(s, 32 - formatNameLength); } else { wszFormatName = NULL; - + if (szFormatName) formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0); - + if (formatNameSize > 15) formatNameSize = 15; - - if (wszFormatName) + + if (wszFormatName) Stream_Write(s, wszFormatName, formatNameSize * 2); Stream_Zero(s, 32 - (formatNameSize * 2)); - + free(wszFormatName); } } @@ -1218,9 +1218,9 @@ static UINT cliprdr_virtual_channel_event_disconnected(cliprdrPlugin* cliprdr) if (MessageQueue_PostQuit(cliprdr->queue, 0) && (WaitForSingleObject(cliprdr->thread, INFINITE) == WAIT_FAILED)) { - rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); - return rc; + rc = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); + return rc; } MessageQueue_Free(cliprdr->queue); @@ -1257,7 +1257,9 @@ static UINT cliprdr_virtual_channel_event_terminated(cliprdrPlugin* cliprdr) return CHANNEL_RC_OK; } -static VOID VCAPITYPE cliprdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +static VOID VCAPITYPE cliprdr_virtual_channel_init_event(LPVOID pInitHandle, + UINT event, LPVOID pData, + UINT dataLength) { cliprdrPlugin* cliprdr; UINT error = CHANNEL_RC_OK; @@ -1289,8 +1291,6 @@ static VOID VCAPITYPE cliprdr_virtual_channel_init_event(LPVOID pInitHandle, UIN } if (error && cliprdr->context->rdpcontext) setChannelError(cliprdr->context->rdpcontext, error, "cliprdr_virtual_channel_init_event reported an error"); - - return; } /* cliprdr is always built-in */ @@ -1358,14 +1358,14 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) cliprdr->streamFileClipEnabled = FALSE; cliprdr->fileClipNoFilePaths = TRUE; cliprdr->canLockClipData = FALSE; - + WLog_Print(cliprdr->log, WLOG_DEBUG, "VirtualChannelEntry"); CopyMemory(&(cliprdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); rc = cliprdr->channelEntryPoints.pVirtualChannelInit(&cliprdr->InitHandle, &cliprdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, cliprdr_virtual_channel_init_event); - + if (CHANNEL_RC_OK != rc) { WLog_ERR(TAG, "pVirtualChannelInit failed with %s [%08X]", diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 24a34c5..ed98170 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -597,8 +597,12 @@ static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* con free(cliprdr->temporaryDirectory); cliprdr->temporaryDirectory = NULL; - ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, - &(cliprdr->temporaryDirectory), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, + &(cliprdr->temporaryDirectory), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert temporary directory name"); + return ERROR_INVALID_DATA; + } length = strlen(cliprdr->temporaryDirectory); @@ -680,12 +684,21 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS formats[index].formatName = NULL; + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { + /* ensure null termination */ formats[index].formatName = (char*) malloc(32 + 1); CopyMemory(formats[index].formatName, szFormatName, 32); formats[index].formatName[32] = '\0'; @@ -697,8 +710,16 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (wszFormatName[0]) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - 16, &(formats[index].formatName), 0, NULL, NULL); + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INVALID_DATA; + goto out; + } } } @@ -757,8 +778,13 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (formatNameLength) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - -1, &(formats[index].formatName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INVALID_DATA; + goto out; + } } Stream_Seek(s, (formatNameLength + 1) * 2); @@ -775,6 +801,7 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (error) WLog_ERR(TAG, "ClientFormatList failed with error %lu!", error); +out: for (index = 0; index < formatList.numFormats; index++) { free(formatList.formats[index].formatName); diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 29111fd..ee052ad 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -241,7 +241,7 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) * * @return 0 on success, otherwise a Win32 error code */ -UINT dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings) +static UINT dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings) { DVCMAN_ENTRY_POINTS entryPoints; PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL; @@ -261,7 +261,7 @@ UINT dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, entryPoints.args = args; entryPoints.settings = settings; - pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints); + return pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints); } return CHANNEL_RC_OK; @@ -478,8 +478,8 @@ UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channe context = dvcman->drdynvc->context; IFCALLRET(context->OnChannelConnected, error, context, ChannelName, listener->iface.pInterface); - if (error) - WLog_ERR(TAG, "context.ReceiveSamples failed with error %lu", error); + if (error) + WLog_ERR(TAG, "context.ReceiveSamples failed with error %lu", error); return error; } @@ -958,8 +958,8 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int c Stream_Write_UINT8(data_out, 0x10 | cbChId); Stream_SetPosition(s, 1); - Stream_Copy(data_out, s, pos - 1); - + Stream_Copy(s, data_out, pos - 1); + if (channel_status == CHANNEL_RC_OK) { WLog_DBG(TAG, "channel created"); @@ -1056,7 +1056,7 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cb WLog_ERR(TAG, "dvcman_close_channel failed with error %lu!", error); return error; } - + data_out = Stream_New(NULL, 4); if (!data_out) @@ -1214,6 +1214,10 @@ void* drdynvc_get_open_handle_data(DWORD openHandle) void drdynvc_remove_open_handle_data(DWORD openHandle) { void* pOpenHandle = (void*) (size_t) openHandle; + + if (!g_OpenHandles) + return; + ListDictionary_Remove(g_OpenHandles, pOpenHandle); if (ListDictionary_Count(g_OpenHandles) < 1) @@ -1411,7 +1415,9 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO for (index = 0; index < settings->DynamicChannelCount; index++) { args = settings->DynamicChannelArray[index]; - dvcman_load_addin(drdynvc->channel_mgr, args, settings); + error = dvcman_load_addin(drdynvc->channel_mgr, args, settings); + if (CHANNEL_RC_OK != error) + goto error; } if ((error = dvcman_init(drdynvc->channel_mgr))) @@ -1434,8 +1440,6 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO error: drdynvc_remove_open_handle_data(drdynvc->OpenHandle); - MessageQueue_Free(drdynvc->queue); - drdynvc->queue = NULL; return error; } @@ -1449,11 +1453,11 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) UINT status; if (MessageQueue_PostQuit(drdynvc->queue, 0) && (WaitForSingleObject(drdynvc->thread, INFINITE) == WAIT_FAILED)) - { - status = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", status); - return status; - } + { + status = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", status); + return status; + } MessageQueue_Free(drdynvc->queue); CloseHandle(drdynvc->thread); @@ -1497,7 +1501,9 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc) return CHANNEL_RC_OK; } -static void VCAPITYPE drdynvc_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +static VOID VCAPITYPE drdynvc_virtual_channel_init_event(LPVOID pInitHandle, + UINT event, LPVOID pData, + UINT dataLength) { drdynvcPlugin* drdynvc; UINT error = CHANNEL_RC_OK; @@ -1529,7 +1535,6 @@ static void VCAPITYPE drdynvc_virtual_channel_init_event(LPVOID pInitHandle, UIN } if (error && drdynvc->rdpcontext) setChannelError(drdynvc->rdpcontext, error, "drdynvc_virtual_channel_init_event reported an error"); - } /** diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 7aec1c2..128e8ba 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -7,6 +7,8 @@ * Copyright 2012 Gerald Richter * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +61,8 @@ #ifdef _WIN32 #pragma comment(lib, "Shlwapi.lib") #include +#else +#include #endif #include "drive_file.h" @@ -507,18 +511,23 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN { char* s = NULL; mode_t m; - UINT64 size; + INT64 size; int status; char* fullpath; - struct STAT st; -#if defined(__linux__) && !defined(ANDROID) || defined(sun) - struct timespec tv[2]; -#else - struct timeval tv[2]; -#endif - UINT64 LastWriteTime; + ULARGE_INTEGER liCreationTime; + ULARGE_INTEGER liLastAccessTime; + ULARGE_INTEGER liLastWriteTime; + ULARGE_INTEGER liChangeTime; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + FILETIME* pftCreationTime = NULL; + FILETIME* pftLastAccessTime = NULL; + FILETIME* pftLastWriteTime = NULL; UINT32 FileAttributes; UINT32 FileNameLength; + HANDLE hFd; + LARGE_INTEGER liSize; m = 0; @@ -526,55 +535,73 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ - Stream_Seek_UINT64(input); /* CreationTime */ - Stream_Seek_UINT64(input); /* LastAccessTime */ - Stream_Read_UINT64(input, LastWriteTime); - Stream_Seek_UINT64(input); /* ChangeTime */ + Stream_Read_UINT64(input, liCreationTime.QuadPart); + Stream_Read_UINT64(input, liLastAccessTime.QuadPart); + Stream_Read_UINT64(input, liLastWriteTime.QuadPart); + Stream_Read_UINT64(input, liChangeTime.QuadPart); Stream_Read_UINT32(input, FileAttributes); - if (FSTAT(file->fd, &st) != 0) + if (!PathFileExistsA(file->fullpath)) return FALSE; - - tv[0].tv_sec = st.st_atime; - tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); -#ifndef WIN32 - /* TODO on win32 */ -#ifdef ANDROID - tv[0].tv_usec = 0; - tv[1].tv_usec = 0; - utimes(file->fullpath, tv); -#elif defined (__linux__) || defined (sun) - tv[0].tv_nsec = 0; - tv[1].tv_nsec = 0; - futimens(file->fd, tv); -#else - tv[0].tv_usec = 0; - tv[1].tv_usec = 0; - futimes(file->fd, tv); -#endif - - if (FileAttributes > 0) + hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFd == INVALID_HANDLE_VALUE) { - m = st.st_mode; - if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) - m |= S_IWUSR; - else - m &= ~S_IWUSR; - if (m != st.st_mode) - fchmod(file->fd, st.st_mode); + WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath); + return FALSE; } -#endif + if (liCreationTime.QuadPart != 0) + { + ftCreationTime.dwHighDateTime = liCreationTime.HighPart; + ftCreationTime.dwLowDateTime = liCreationTime.LowPart; + pftCreationTime = &ftCreationTime; + } + if (liLastAccessTime.QuadPart != 0) + { + ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart; + ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart; + pftLastAccessTime = &ftLastAccessTime; + } + if (liLastWriteTime.QuadPart != 0) + { + ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart; + ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart; + pftLastWriteTime = &ftLastWriteTime; + } + if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart) + { + ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart; + ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart; + pftLastWriteTime = &ftLastWriteTime; + } + if (!SetFileTime(hFd, pftCreationTime, pftLastAccessTime, pftLastWriteTime)) + { + WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath); + CloseHandle(hFd); + return FALSE; + } + CloseHandle(hFd); break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ - Stream_Read_UINT64(input, size); -#ifndef _WIN32 - if (ftruncate(file->fd, size) != 0) + Stream_Read_INT64(input, size); + + hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFd == INVALID_HANDLE_VALUE) + { + WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size); return FALSE; -#endif + } + liSize.QuadPart = size; + if (SetFilePointer(hFd, liSize.LowPart, &liSize.HighPart, FILE_BEGIN) == 0) + { + WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size); + CloseHandle(hFd); + return FALSE; + } + CloseHandle(hFd); break; case FileDispositionInformation: diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index b5bd141..d287eb4 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -7,6 +7,8 @@ * Copyright 2012 Gerald Richter * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,8 +86,6 @@ typedef UINT32 mode_t; #define FILE_TIME_SYSTEM_TO_RDP(_t) \ (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL) -#define FILE_TIME_RDP_TO_SYSTEM(_t) \ - (((_t) == 0LL || (_t) == (UINT64)(-1LL)) ? 0 : (time_t)((_t) / 10000000LL - EPOCH_DIFF)) #define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \ (S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \ diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c index 58cc812..8c7f921 100644 --- a/channels/echo/server/echo_main.c +++ b/channels/echo/server/echo_main.c @@ -116,12 +116,15 @@ static void* echo_server_thread_func(void* arg) DWORD BytesReturned = 0; echo_server* echo = (echo_server*) arg; UINT error; - DWORD status; + DWORD status; if ((error = echo_server_open_channel(echo))) { - IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + UINT error2 = 0; WLog_ERR(TAG, "echo_server_open_channel failed with error %lu!", error); + IFCALLRET(echo->context.OpenResult, error2, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + if (error2) + WLog_ERR(TAG, "echo server's OpenResult callback failed with error %lu", error2); goto out; } @@ -145,14 +148,14 @@ static void* echo_server_thread_func(void* arg) while (1) { - status = WaitForMultipleObjects(nCount, events, FALSE, 100); + status = WaitForMultipleObjects(nCount, events, FALSE, 100); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); + break; + } if (status == WAIT_OBJECT_0) { diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index 3386c63..239954c 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -1217,9 +1217,9 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp) if (MessageQueue_PostQuit(encomsp->queue, 0) && (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED)) { - rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); - return rc; + rc = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); + return rc; } MessageQueue_Free(encomsp->queue); @@ -1259,7 +1259,9 @@ static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp) return CHANNEL_RC_OK; } -static void VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +static VOID VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, + UINT event, LPVOID pData, + UINT dataLength) { encomspPlugin* encomsp; UINT error = CHANNEL_RC_OK; @@ -1293,8 +1295,6 @@ static void VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UIN if (error && encomsp->rdpcontext) setChannelError(encomsp->rdpcontext, error, "encomsp_virtual_channel_init_event reported an error"); - - return; } /* encomsp is always built-in */ diff --git a/channels/rail/client/rail_main.c b/channels/rail/client/rail_main.c index 4294cf6..618227b 100644 --- a/channels/rail/client/rail_main.c +++ b/channels/rail/client/rail_main.c @@ -741,9 +741,9 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) UINT rc; if (MessageQueue_PostQuit(rail->queue, 0) && (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED)) { - rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); - return rc; + rc = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); + return rc; } MessageQueue_Free(rail->queue); @@ -757,7 +757,7 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) { WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08X]", WTSErrorToString(rc), rc); - return rc; + return rc; } if (rail->data_in) @@ -798,7 +798,7 @@ static VOID VCAPITYPE rail_virtual_channel_init_event(LPVOID pInitHandle, UINT e case CHANNEL_EVENT_DISCONNECTED: if ((error = rail_virtual_channel_event_disconnected(rail))) - WLog_ERR(TAG, "rail_virtual_channel_event_disconnected failed with error %lu!", error); + WLog_ERR(TAG, "rail_virtual_channel_event_disconnected failed with error %lu!", error); break; case CHANNEL_EVENT_TERMINATED: @@ -808,8 +808,6 @@ static VOID VCAPITYPE rail_virtual_channel_init_event(LPVOID pInitHandle, UINT e if(error && rail->rdpcontext) setChannelError(rail->rdpcontext, error, "rail_virtual_channel_init_event reported an error"); - - return; } /* rail is always built-in */ diff --git a/channels/rdpdr/client/CMakeLists.txt b/channels/rdpdr/client/CMakeLists.txt index 488c174..4074eb6 100644 --- a/channels/rdpdr/client/CMakeLists.txt +++ b/channels/rdpdr/client/CMakeLists.txt @@ -2,6 +2,8 @@ # FreeRDP cmake build script # # Copyright 2012 Marc-Andre Moreau +# Copyright 2016 Inuvika Inc. +# Copyright 2016 David PHAM-VAN # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,6 +34,10 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} winpr freerdp) +if(APPLE AND (NOT IOS)) + find_library(CORESERVICES_LIBRARY CoreServices) + target_link_libraries(${MODULE_NAME} ${CORESERVICES_LIBRARY}) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 60a5cb4..3f5dd15 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -173,7 +173,10 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext return ERROR_INVALID_NAME; } - WLog_INFO(TAG, "Loading device service %s (static)", ServiceName); + if (device->Name) + WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name); + else + WLog_INFO(TAG, "Loading device service %s (static)", ServiceName); entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0); if (!entry) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 87ee6fb..cf41c7c 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -46,6 +46,15 @@ #include #endif +#ifdef __MACOSX__ +#include +#include +#include +#include +#include +#include +#endif + #ifdef HAVE_UNISTD_H #include #endif @@ -103,6 +112,45 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou #ifdef _WIN32 +BOOL check_path(char* path) +{ + UINT type = GetDriveTypeA(path); + if (!(type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE)) + return FALSE; + return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0); +} + +void first_hotplug(rdpdrPlugin *rdpdr) +{ + int i; + char drive_path[5] = { 'c', ':', '\\', '\0' }; + + DWORD unitmask = GetLogicalDrives(); + + for (i = 0; i < 26; i++) + { + if (unitmask & 0x01) + { + RDPDR_DRIVE* drive; + + drive_path[0] = 'A' + i; + drive_path[1] = ':'; + + if (check_path(drive_path)) + { + drive = (RDPDR_DRIVE*)malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + drive->Type = RDPDR_DTYP_FILESYSTEM; + drive->Path = _strdup(drive_path); + drive_path[1] = '\0'; + drive->Name = _strdup(drive_path); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); + } + } + unitmask = unitmask >> 1; + } +} + LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { rdpdrPlugin *rdpdr; @@ -131,17 +179,21 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) RDPDR_DRIVE* drive; drive_path[0] = 'A' + i; + drive_path[1] = ':'; - drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); - ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + if (check_path(drive_path)) + { + drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); - drive->Type = RDPDR_DTYP_FILESYSTEM; + drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = _strdup(drive_path); - drive_path[1] = '\0'; - drive->Name = _strdup(drive_path); - devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); - rdpdr_send_device_list_announce_request(rdpdr, TRUE); + drive->Path = _strdup(drive_path); + drive_path[1] = '\0'; + drive->Name = _strdup(drive_path); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); + rdpdr_send_device_list_announce_request(rdpdr, TRUE); + } } unitmask = unitmask >> 1; } @@ -275,6 +327,242 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) return error; } +#elif __MACOSX__ + +#define MAX_USB_DEVICES 100 + +typedef struct _hotplug_dev +{ + char* path; + BOOL to_add; +} hotplug_dev; + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT handle_hotplug(rdpdrPlugin* rdpdr) +{ + struct dirent *pDirent; + DIR *pDir; + char fullpath[PATH_MAX]; + char* szdir = (char*)"/Volumes"; + struct stat buf; + hotplug_dev dev_array[MAX_USB_DEVICES]; + int count; + DEVICE_DRIVE_EXT *device_ext; + ULONG_PTR *keys; + int i, j; + int size = 0; + UINT error; + UINT32 ids[1]; + + pDir = opendir (szdir); + if (pDir == NULL) + { + printf ("Cannot open directory\n"); + return ERROR_OPEN_FAILED; + } + + while ((pDirent = readdir(pDir)) != NULL) + { + if (pDirent->d_name[0] != '.') + { + sprintf(fullpath, "%s/%s", szdir, pDirent->d_name); + lstat(fullpath, &buf); + if(S_ISDIR(buf.st_mode)) + { + dev_array[size].path = _strdup(fullpath); + if (!dev_array[size].path) + { + closedir (pDir); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + dev_array[size++].to_add = TRUE; + } + } + } + closedir (pDir); + + /* delete removed devices */ + count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); + + for (j = 0; j < count; j++) + { + BOOL dev_found = FALSE; + + device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); + if (!device_ext) + continue; + + if (device_ext->path == NULL) + continue; + + /* not plugable device */ + if (strstr(device_ext->path, "/Volumes/") == NULL) + continue; + + for (i = 0; i < size; i++) + { + if (strstr(device_ext->path, dev_array[i].path) != NULL) + { + dev_found = TRUE; + dev_array[i].to_add = FALSE; + break; + } + } + + if (!dev_found) + { + devman_unregister_device(rdpdr->devman, (void *)keys[j]); + ids[0] = keys[j]; + if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %lu!", error); + goto cleanup; + } + } + } + + /* add new devices */ + for (i = 0; i < size; i++) + { + RDPDR_DRIVE* drive; + + if (dev_array[i].to_add) + { + char* name; + + drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); + if (!drive) + { + WLog_ERR(TAG, "calloc failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + + drive->Type = RDPDR_DTYP_FILESYSTEM; + + drive->Path = dev_array[i].path; + dev_array[i].path = NULL; + + name = strrchr(drive->Path, '/') + 1; + drive->Name = _strdup(name); + if (!drive->Name) + { + WLog_ERR(TAG, "_strdup failed!"); + free(drive->Path); + free(drive); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext))) + { + WLog_ERR(TAG, "devman_load_device_service failed!"); + free(drive->Path); + free(drive->Name); + free(drive); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + } + } + +cleanup: + for (i = 0; i < size; i++) + free (dev_array[i].path); + + return error; + } + + +static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, + size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) +{ + rdpdrPlugin* rdpdr; + int i; + UINT error; + char **paths = (char**)eventPaths; + + rdpdr = (rdpdrPlugin*) clientCallBackInfo; + + for (i=0; irunLoop = CFRunLoopGetCurrent(); + FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode); + FSEventStreamStart(fsev); + CFRunLoopRun(); + FSEventStreamStop(fsev); + FSEventStreamRelease(fsev); + + ExitThread(CHANNEL_RC_OK); + return NULL; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) +{ + UINT error; + if (rdpdr->hotplugThread) + { + CFRunLoopStop(rdpdr->runLoop); + + if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; + } + rdpdr->hotplugThread = NULL; + } + return CHANNEL_RC_OK; +} + #else #define MAX_USB_DEVICES 100 @@ -361,13 +649,13 @@ static char* get_word(char* str, unsigned int* offset) (*offset)++; word = malloc(wlen + 1); - + if (word != NULL) { CopyMemory(word, p, wlen); word[wlen] = '\0'; } - + return word; } @@ -506,7 +794,16 @@ cleanup: for (i = 0; i < size; i++) free (dev_array[i].path); - return error ? error : rdpdr_send_device_list_announce_request(rdpdr, TRUE); + return error; +} + +void first_hotplug(rdpdrPlugin *rdpdr) +{ + UINT error; + if ((error = handle_hotplug(rdpdr))) + { + WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); + } } static void* drive_hotplug_thread_func(void* arg) @@ -516,7 +813,7 @@ static void* drive_hotplug_thread_func(void* arg) fd_set rfds; struct timeval tv; int rv; - UINT error; + UINT error = 0; DWORD status; rdpdr = (rdpdrPlugin*) arg; @@ -542,12 +839,6 @@ static void* drive_hotplug_thread_func(void* arg) tv.tv_sec = 1; tv.tv_usec = 0; - if ((error = handle_hotplug(rdpdr))) - { - WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); - goto out; - } - while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) { status = WaitForSingleObject(rdpdr->stopEvent, 0); @@ -568,6 +859,8 @@ static void* drive_hotplug_thread_func(void* arg) WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); goto out; } + else + rdpdr_send_device_list_announce_request(rdpdr, TRUE); } FD_ZERO(&rfds); @@ -643,6 +936,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if (device->Name && (strcmp(device->Name, "*") == 0)) { + first_hotplug(rdpdr); if (!(rdpdr->hotplugThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL))) { @@ -1426,7 +1720,8 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr) free(rdpdr); } -static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, + LPVOID pData, UINT dataLength) { rdpdrPlugin* rdpdr; UINT error = CHANNEL_RC_OK; @@ -1464,7 +1759,6 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT if (error && rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, "rdpdr_virtual_channel_init_event reported an error"); - return; } /* rdpdr is always built-in */ diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 7f93acb..6ecb945 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -6,6 +6,8 @@ * Copyright 2010-2012 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +38,10 @@ #include #include +#ifdef __MACOSX__ +#include +#endif + #define TAG CHANNELS_TAG("rdpdr.client") typedef struct rdpdr_plugin rdpdrPlugin; @@ -64,6 +70,8 @@ struct rdpdr_plugin HANDLE hotplugThread; #ifdef _WIN32 HWND hotplug_wnd; +#elif __MACOSX__ + CFRunLoopRef runLoop; #else HANDLE stopEvent; #endif diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index 074d3e4..b29182f 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -152,9 +152,10 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */ Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ - if (Stream_GetRemainingLength(s) < ComputerNameLen) + + if (UnicodeFlag > 1) /* must be 0x00000000 or 0x00000001 */ { - WLog_ERR(TAG, "not enough data in stream!"); + WLog_ERR(TAG, "invalid UnicodeFlag value: 0x%08X", UnicodeFlag); return ERROR_INVALID_DATA; } @@ -164,6 +165,39 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context * not in characters, including the NULL terminator! */ + if (UnicodeFlag) + { + if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2) + { + WLog_ERR(TAG, "invalid unicode computer name length: %u", ComputerNameLen); + return ERROR_INVALID_DATA; + } + } + else + { + if (ComputerNameLen > 256 || ComputerNameLen < 1) + { + WLog_ERR(TAG, "invalid ascii computer name length: %u", ComputerNameLen); + return ERROR_INVALID_DATA; + } + } + + if (Stream_GetRemainingLength(s) < ComputerNameLen) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + /* ComputerName must be null terminated, check if it really is */ + + if (Stream_Pointer(s)[ComputerNameLen-1] || + (UnicodeFlag && Stream_Pointer(s)[ComputerNameLen-2])) + { + WLog_ERR(TAG, "computer name must be null terminated"); + return ERROR_INVALID_DATA; + } + + if (context->priv->ClientComputerName) { free(context->priv->ClientComputerName); @@ -172,12 +206,21 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context if (UnicodeFlag) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), - -1, &(context->priv->ClientComputerName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, + &(context->priv->ClientComputerName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client computer name"); + return ERROR_INVALID_DATA; + } } else { context->priv->ClientComputerName = _strdup((char*) Stream_Pointer(s)); + if (!context->priv->ClientComputerName) + { + WLog_ERR(TAG, "failed to duplicate client computer name"); + return CHANNEL_RC_NO_MEMORY; + } } Stream_Seek(s, ComputerNameLen); diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index 3eba6c3..bf28ddd 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -38,10 +38,11 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta) +static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, + RDPGFX_H264_METABLOCK* meta) { UINT32 index; - RDPGFX_RECT16* regionRect; + RECTANGLE_16* regionRect; RDPGFX_H264_QUANT_QUALITY* quantQualityVal; UINT error = ERROR_INVALID_DATA; @@ -56,13 +57,13 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H2 Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ - if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8)) + if (Stream_GetRemainingLength(s) < (meta->numRegionRects * sizeof(RECTANGLE_16))) { WLog_ERR(TAG, "not enough data!"); goto error_out; } - meta->regionRects = (RDPGFX_RECT16*) malloc(meta->numRegionRects * sizeof(RDPGFX_RECT16)); + meta->regionRects = (RECTANGLE_16*) malloc(meta->numRegionRects * sizeof(RECTANGLE_16)); if (!meta->regionRects) { @@ -128,11 +129,11 @@ error_out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) +static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { UINT error; wStream* s; - RDPGFX_H264_BITMAP_STREAM h264; + RDPGFX_AVC420_BITMAP_STREAM h264; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; s = Stream_New(cmd->data, cmd->length); @@ -169,6 +170,91 @@ static UINT rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) return error; } +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) +{ + UINT error; + UINT32 tmp; + size_t pos1, pos2; + wStream* s; + RDPGFX_AVC444_BITMAP_STREAM h264; + RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + + s = Stream_New(cmd->data, cmd->length); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, tmp); + h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL; + h264.LC = (tmp >> 30UL) & 0x03UL; + + if (h264.LC == 0x03) + return ERROR_INVALID_DATA; + + pos1 = Stream_GetPosition(s); + if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta)))) + { + WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %lu!", error); + return error; + } + pos2 = Stream_GetPosition(s); + + h264.bitstream[0].data = Stream_Pointer(s); + + if (h264.LC == 0) + { + tmp = h264.cbAvc420EncodedBitstream1 - pos2 + pos1; + if (Stream_GetRemainingLength(s) < tmp) + return ERROR_INVALID_DATA; + + h264.bitstream[0].length = tmp; + Stream_Seek(s, tmp); + + if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta)))) + { + WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %lu!", error); + return error; + } + + h264.bitstream[1].data = Stream_Pointer(s); + h264.bitstream[1].length = Stream_GetRemainingLength(s); + } + else + { + h264.bitstream[0].length = Stream_GetRemainingLength(s); + memset(&h264.bitstream[1], 0, sizeof(h264.bitstream[1])); + } + + Stream_Free(s, FALSE); + + cmd->extra = (void*) &h264; + + if (context) + { + IFCALLRET(context->SurfaceCommand, error, context, cmd); + if (error) + WLog_ERR(TAG, "context->SurfaceCommand failed with error %lu", error); + } + + free(h264.bitstream[0].meta.regionRects); + free(h264.bitstream[0].meta.quantQualityVals); + free(h264.bitstream[1].meta.regionRects); + free(h264.bitstream[1].meta.quantQualityVals); + + return error; +} + /** * Function description * @@ -181,10 +267,18 @@ UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) switch (cmd->codecId) { - case RDPGFX_CODECID_H264: - if ((error = rdpgfx_decode_h264(gfx, cmd))) + case RDPGFX_CODECID_AVC420: + if ((error = rdpgfx_decode_AVC420(gfx, cmd))) { - WLog_ERR(TAG, "rdpgfx_decode_h264 failed with error %lu", error); + WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %lu", error); + return error; + } + break; + + case RDPGFX_CODECID_AVC444: + if ((error = rdpgfx_decode_AVC444(gfx, cmd))) + { + WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %lu", error); return error; } break; diff --git a/channels/rdpgfx/client/rdpgfx_common.c b/channels/rdpgfx/client/rdpgfx_common.c index 8b6e073..a7518a5 100644 --- a/channels/rdpgfx/client/rdpgfx_common.c +++ b/channels/rdpgfx/client/rdpgfx_common.c @@ -77,8 +77,10 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId) return "RDPGFX_CODECID_CLEARCODEC"; case RDPGFX_CODECID_PLANAR: return "RDPGFX_CODECID_PLANAR"; - case RDPGFX_CODECID_H264: - return "RDPGFX_CODECID_H264"; + case RDPGFX_CODECID_AVC420: + return "RDPGFX_CODECID_AVC420"; + case RDPGFX_CODECID_AVC444: + return "RDPGFX_CODECID_AVC444"; case RDPGFX_CODECID_ALPHA: return "RDPGFX_CODECID_ALPHA"; case RDPGFX_CODECID_CAPROGRESSIVE: @@ -161,7 +163,7 @@ UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16) +UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16) { if (Stream_GetRemainingLength(s) < 8) { @@ -182,7 +184,7 @@ UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16) +UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16) { Stream_Write_UINT16(s, rect16->left); /* left (2 bytes) */ Stream_Write_UINT16(s, rect16->top); /* top (2 bytes) */ diff --git a/channels/rdpgfx/client/rdpgfx_common.h b/channels/rdpgfx/client/rdpgfx_common.h index 188102c..9d08205 100644 --- a/channels/rdpgfx/client/rdpgfx_common.h +++ b/channels/rdpgfx/client/rdpgfx_common.h @@ -36,8 +36,8 @@ UINT rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header); UINT rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16); UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16); -UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16); -UINT rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16); +UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16); +UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16); UINT rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32); UINT rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32); diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 07ec66c..1ae2882 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -58,7 +58,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; - RDPGFX_CAPSET capsSets[2]; + RDPGFX_CAPSET capsSets[3]; RDPGFX_CAPS_ADVERTISE_PDU pdu; gfx = (RDPGFX_PLUGIN*) callback->plugin; @@ -90,7 +90,17 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; if (gfx->H264) - capsSet->flags |= RDPGFX_CAPS_FLAG_H264ENABLED; + capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED; + + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_10; + capsSet->flags = 0; + + if (gfx->SmallCache) + capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; + + if (!gfx->H264) + capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); @@ -688,7 +698,7 @@ static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* cal UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; - RDPGFX_RECT16* fillRect; + RECTANGLE_16* fillRect; RDPGFX_SOLID_FILL_PDU pdu; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; @@ -714,7 +724,7 @@ UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) return ERROR_INVALID_DATA; } - pdu.fillRects = (RDPGFX_RECT16*) calloc(pdu.fillRectCount, sizeof(RDPGFX_RECT16)); + pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16)); if (!pdu.fillRects) { @@ -742,7 +752,7 @@ UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) if (error) WLog_ERR(TAG, "context->SolidFill failed with error %lu", error); } - + free(pdu.fillRects); return error; diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 36f8214..ea4230d 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -649,6 +649,8 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry alsa_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/ios/rdpsnd_ios.c b/channels/rdpsnd/client/ios/rdpsnd_ios.c index f307b23..148c846 100644 --- a/channels/rdpsnd/client/ios/rdpsnd_ios.c +++ b/channels/rdpsnd/client/ios/rdpsnd_ios.c @@ -281,6 +281,8 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device) #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry ios_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 5867480..a2162a2 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -345,6 +345,8 @@ static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry mac_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index c42f1b2..8c8b34e 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -407,6 +407,9 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry \ opensles_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry \ + FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index df01ec0..2a6d365 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -477,6 +477,8 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry oss_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 13899ec..5181d0d 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -636,6 +636,8 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry pulse_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 155dd22..2133339 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -116,39 +116,39 @@ static void* rdpsnd_schedule_thread(void* arg) while (1) { - status = WaitForMultipleObjects(2, events, FALSE, INFINITE); + status = WaitForMultipleObjects(2, events, FALSE, INFINITE); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); + break; + } - status = WaitForSingleObject(rdpsnd->stopEvent, 0); + status = WaitForSingleObject(rdpsnd->stopEvent, 0); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + break; + } - if (status == WAIT_OBJECT_0) - break; + if (status == WAIT_OBJECT_0) + break; - status = WaitForSingleObject(events[0], 0); + status = WaitForSingleObject(events[0], 0); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + break; + } - if (!MessageQueue_Peek(rdpsnd->MsgPipe->Out, &message, TRUE)) + if (!MessageQueue_Peek(rdpsnd->MsgPipe->Out, &message, TRUE)) { WLog_ERR(TAG, "MessageQueue_Peek failed!"); error = ERROR_INTERNAL_ERROR; @@ -811,6 +811,7 @@ static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD if ((error = entry(&entryPoints))) WLog_ERR(TAG, "%s entry returns error %lu", name, error); + WLog_INFO(TAG, "Loaded %s backend for rdpsnd", name); return error; } @@ -828,7 +829,7 @@ BOOL rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, const char* device_name) return (rdpsnd->device_name != NULL); } -COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = +static COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = { { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, @@ -1078,10 +1079,10 @@ static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) { SetEvent(rdpsnd->stopEvent); if (WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE) == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); - return; - } + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); + return; + } CloseHandle(rdpsnd->ScheduleThread); CloseHandle(rdpsnd->stopEvent); } @@ -1386,9 +1387,9 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) MessagePipe_PostQuit(rdpsnd->MsgPipe, 0); if (WaitForSingleObject(rdpsnd->thread, INFINITE) == WAIT_FAILED) { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - return error; + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; } CloseHandle(rdpsnd->thread); diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 5e14363..7eb1a5f 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -346,6 +346,8 @@ static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry winmm_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 7a74705..7e34d59 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -1030,11 +1030,11 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk) UINT rc; if (MessageQueue_PostQuit(remdesk->queue, 0) && (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED)) - { - rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); - return rc; - } + { + rc = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", rc); + return rc; + } MessageQueue_Free(remdesk->queue); CloseHandle(remdesk->thread); @@ -1066,7 +1066,9 @@ static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk) free(remdesk); } -static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) +static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, + UINT event, LPVOID pData, + UINT dataLength) { remdeskPlugin* remdesk; UINT error = CHANNEL_RC_OK; diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index 421cc61..766648b 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -707,7 +707,12 @@ void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReader if (unicode) { length = ret->cBytes / 2; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, (int)length, &mszA, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, (int)length, + &mszA, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "ConvertFromUnicode failed"); + return; + } } else { @@ -1767,7 +1772,12 @@ void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* r if (unicode) { length = ret->cBytes / 2; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int)length, &mszReaderNamesA, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int)length, + &mszReaderNamesA, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "ConvertFromUnicode failed"); + return; + } } else { diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index 91af225..078c7d8 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -233,6 +233,8 @@ static void tsmf_alsa_free(ITSMFAudioDevice *audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index e1b9f83..4e5beff 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -543,6 +543,8 @@ static BOOL initialized = FALSE; #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry +#else +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 0e35f73..466dd7d 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -1012,6 +1012,8 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry +#else +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) diff --git a/channels/tsmf/client/oss/tsmf_oss.c b/channels/tsmf/client/oss/tsmf_oss.c index fe97851..da792be 100644 --- a/channels/tsmf/client/oss/tsmf_oss.c +++ b/channels/tsmf/client/oss/tsmf_oss.c @@ -238,6 +238,8 @@ static void tsmf_oss_free(ITSMFAudioDevice* audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry oss_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index c0d6caa..5a8c90d 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -360,6 +360,8 @@ static void tsmf_pulse_free(ITSMFAudioDevice *audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry pulse_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index b4a84df..4c9da74 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -79,7 +79,7 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4)) return ERROR_OUTOFMEMORY; pos = Stream_GetPosition(ifman->output); - Stream_Copy(ifman->output, ifman->input, ifman->input_size); + Stream_Copy(ifman->input, ifman->output, ifman->input_size); Stream_SetPosition(ifman->output, pos); if (Stream_GetRemainingLength(ifman->output) < 4) diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 7dfa505..b8af3a4 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -579,6 +579,8 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) #ifdef STATIC_CHANNELS #define freerdp_urbdrc_client_subsystem_entry libusb_freerdp_urbdrc_client_subsystem_entry +#else +#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry #endif int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 1e5c772..bb8e4f6 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -36,7 +36,7 @@ if(FREERDP_VENDOR AND WITH_CLIENT) add_subdirectory(X11) endif() - if(WITH_WAYLAND) + if(WITH_WAYLAND AND WAYLAND_FOUND) add_subdirectory(Wayland) endif() diff --git a/client/DirectFB/dfreerdp.c b/client/DirectFB/dfreerdp.c index 56b9ff6..5c801cd 100644 --- a/client/DirectFB/dfreerdp.c +++ b/client/DirectFB/dfreerdp.c @@ -177,7 +177,8 @@ BOOL df_pre_connect(freerdp* instance) dfi->clrconv->palette = (rdpPalette*) malloc(sizeof(rdpPalette)); ZeroMemory(dfi->clrconv->palette, sizeof(rdpPalette)); - freerdp_channels_pre_connect(instance->context->channels, instance); + if (freerdp_channels_pre_connect(instance->context->channels, instance) != CHANNEL_RC_OK) + return FALSE; return (instance->context->cache = cache_new(instance->settings)) != NULL; } @@ -235,7 +236,7 @@ BOOL df_post_connect(freerdp* instance) pointer_cache_register_callbacks(instance->update); df_register_graphics(instance->context->graphics); - return freerdp_channels_post_connect(instance->context->channels, instance) >= 0; + return freerdp_channels_post_connect(instance->context->channels, instance) == CHANNEL_RC_OK; } BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) @@ -487,7 +488,8 @@ int main(int argc, char* argv[]) if (status < 0) exit(0); - freerdp_client_load_addins(instance->context->channels, instance->settings); + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) + exit(-1); data = (struct thread_data*) malloc(sizeof(struct thread_data)); ZeroMemory(data, sizeof(sizeof(struct thread_data))); diff --git a/client/Sample/freerdp.c b/client/Sample/freerdp.c index 5291cb7..2e0d92b 100644 --- a/client/Sample/freerdp.c +++ b/client/Sample/freerdp.c @@ -109,7 +109,8 @@ static BOOL tf_pre_connect(freerdp* instance) settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = TRUE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = TRUE; - freerdp_channels_pre_connect(instance->context->channels, instance); + if (freerdp_channels_pre_connect(instance->context->channels, instance) != CHANNEL_RC_OK) + return FALSE; return TRUE; } @@ -122,7 +123,7 @@ static BOOL tf_post_connect(freerdp* instance) instance->update->BeginPaint = tf_begin_paint; instance->update->EndPaint = tf_end_paint; - return (freerdp_channels_post_connect(instance->context->channels, instance) >= 0); + return (freerdp_channels_post_connect(instance->context->channels, instance) == CHANNEL_RC_OK); } static void* tf_client_thread_proc(freerdp* instance) @@ -200,7 +201,8 @@ int main(int argc, char* argv[]) exit(0); } - freerdp_client_load_addins(instance->context->channels, instance->settings); + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) + exit (-1); if (!(thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tf_client_thread_proc, instance, 0, NULL))) diff --git a/client/Wayland/CMakeLists.txt b/client/Wayland/CMakeLists.txt index 315be7d..25c69a2 100644 --- a/client/Wayland/CMakeLists.txt +++ b/client/Wayland/CMakeLists.txt @@ -19,6 +19,7 @@ set(MODULE_NAME "wlfreerdp") set(MODULE_PREFIX "FREERDP_CLIENT_WAYLAND") +include_directories(${WAYLAND_INCLUDE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/uwac/include) set(${MODULE_PREFIX}_SRCS diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index 308147c..1768969 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -114,7 +114,7 @@ static BOOL wl_pre_connect(freerdp* instance) { wlfContext* context; - if (freerdp_channels_pre_connect(instance->context->channels, instance)) + if (freerdp_channels_pre_connect(instance->context->channels, instance) != CHANNEL_RC_OK) return FALSE; context = (wlfContext*) instance->context; @@ -149,7 +149,7 @@ static BOOL wl_post_connect(freerdp* instance) instance->update->BeginPaint = wl_begin_paint; instance->update->EndPaint = wl_end_paint; - if (freerdp_channels_post_connect(instance->context->channels, instance) < 0) + if (freerdp_channels_post_connect(instance->context->channels, instance) != CHANNEL_RC_OK) return FALSE; @@ -317,14 +317,15 @@ int main(int argc, char* argv[]) freerdp_context_new(instance); - status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv, FALSE); + status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv, FALSE); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); - freerdp_client_load_addins(instance->context->channels, instance->settings); + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) + exit(-1); wlfreerdp_run(instance); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index baaf7e7..16c1a58 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1127,8 +1127,11 @@ BOOL xf_pre_connect(freerdp* instance) PubSub_SubscribeChannelDisconnected(instance->context->pubSub, (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); - freerdp_client_load_addins(channels, instance->settings); - freerdp_channels_pre_connect(channels, instance); + if (!freerdp_client_load_addins(channels, instance->settings)) + return FALSE; + + if (freerdp_channels_pre_connect(channels, instance) != CHANNEL_RC_OK) + return FALSE; if (!settings->Username && !settings->CredentialsFromStdin) { @@ -1312,7 +1315,7 @@ BOOL xf_post_connect(freerdp* instance) if (!(xfc->clipboard = xf_clipboard_new(xfc))) return FALSE; - if (freerdp_channels_post_connect(channels, instance) < 0) + if (freerdp_channels_post_connect(channels, instance) != CHANNEL_RC_OK) return FALSE; EventArgsInit(&e, "xfreerdp"); diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index a2a8f61..3c6363f 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -31,7 +31,7 @@ * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) +static UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) { int index; UINT16 count; @@ -48,21 +48,29 @@ UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* r if (!surface || !surface->outputMapped) continue; - freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL); + if (!freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL, + surface->width, surface->height)) + { + free(pSurfaceIds); + return ERROR_INTERNAL_ERROR; + } region16_clear(&surface->invalidRegion); } free(pSurfaceIds); - freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL); + if (!freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL, + xfc->settings->DesktopWidth, + xfc->settings->DesktopHeight)) + return ERROR_INTERNAL_ERROR; xfc->graphicsReset = TRUE; return CHANNEL_RC_OK; } -int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) +static int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) { UINT16 width, height; UINT32 surfaceX, surfaceY; @@ -124,7 +132,7 @@ int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) return 1; } -int xf_UpdateSurfaces(xfContext* xfc) +static int xf_UpdateSurfaces(xfContext* xfc) { UINT16 count; int index; @@ -212,7 +220,7 @@ int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height) * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame) +static UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame) { xfContext* xfc = (xfContext*) context->custom; @@ -226,7 +234,7 @@ UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFr * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) +static UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) { xfContext* xfc = (xfContext*) context->custom; @@ -242,7 +250,7 @@ UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { xfGfxSurface* surface; RECTANGLE_16 invalidRect; @@ -273,7 +281,7 @@ UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int j; UINT16 i; @@ -363,7 +371,7 @@ UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RD * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status; BYTE* DstData = NULL; @@ -407,7 +415,7 @@ UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status; BYTE* DstData = NULL; @@ -445,45 +453,46 @@ UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPG * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_AVC420(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status; UINT32 i; - BYTE* DstData = NULL; xfGfxSurface* surface; RDPGFX_H264_METABLOCK* meta; - RDPGFX_H264_BITMAP_STREAM* bs; + RDPGFX_AVC420_BITMAP_STREAM* bs; surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return ERROR_INTERNAL_ERROR; - if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_H264)) + if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC420)) return ERROR_INTERNAL_ERROR; - bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; + bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra; if (!bs) return ERROR_INTERNAL_ERROR; meta = &(bs->meta); - DstData = surface->data; - - status = h264_decompress(surface->codecs->h264, bs->data, bs->length, &DstData, - surface->format, surface->scanline , surface->width, - surface->height, meta->regionRects, meta->numRegionRects); + status = avc420_decompress(surface->codecs->h264, bs->data, bs->length, + surface->data, surface->format, + surface->scanline , surface->width, + surface->height, meta->regionRects, + meta->numRegionRects); if (status < 0) { - WLog_WARN(TAG, "h264_decompress failure: %d, ignoring update.", status); + WLog_WARN(TAG, "avc420_decompress failure: %d, ignoring update.", status); return CHANNEL_RC_OK; } for (i = 0; i < meta->numRegionRects; i++) { - region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, (RECTANGLE_16*) &(meta->regionRects[i])); + region16_union_rect(&surface->invalidRegion, + &surface->invalidRegion, + &(meta->regionRects[i])); } if (!xfc->inGfxFrame) @@ -497,7 +506,77 @@ UINT xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_AVC444(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + UINT32 i; + xfGfxSurface* surface; + RDPGFX_AVC444_BITMAP_STREAM* bs; + RDPGFX_AVC420_BITMAP_STREAM* avc1; + RDPGFX_AVC420_BITMAP_STREAM* avc2; + RDPGFX_H264_METABLOCK* meta1; + RDPGFX_H264_METABLOCK* meta2; + RECTANGLE_16* regionRects = NULL; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return ERROR_INTERNAL_ERROR; + + if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC444)) + return ERROR_INTERNAL_ERROR; + + bs = (RDPGFX_AVC444_BITMAP_STREAM*) cmd->extra; + + if (!bs) + return ERROR_INTERNAL_ERROR; + + avc1 = &bs->bitstream[0]; + avc2 = &bs->bitstream[1]; + meta1 = &avc1->meta; + meta2 = &avc2->meta; + + status = avc444_decompress(surface->codecs->h264, bs->LC, + meta1->regionRects, meta1->numRegionRects, + avc1->data, avc1->length, + meta2->regionRects, meta2->numRegionRects, + avc2->data, avc2->length, surface->data, + surface->format, surface->scanline, + surface->width, surface->height); + + if (status < 0) + { + WLog_WARN(TAG, "avc444_decompress failure: %d, ignoring update.", status); + return CHANNEL_RC_OK; + } + + for (i = 0; i < meta1->numRegionRects; i++) + { + region16_union_rect(&surface->invalidRegion, + &surface->invalidRegion, + &(meta1->regionRects[i])); + } + for (i = 0; i < meta2->numRegionRects; i++) + { + region16_union_rect(&surface->invalidRegion, + &surface->invalidRegion, + &(meta2->regionRects[i])); + } + + if (!xfc->inGfxFrame) + xf_UpdateSurfaces(xfc); + + free (regionRects); + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status = 0; xfGfxSurface* surface; @@ -535,7 +614,7 @@ UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGF * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int i, j; int status; @@ -637,7 +716,7 @@ UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { UINT status = CHANNEL_RC_OK; xfContext* xfc = (xfContext*) context->custom; @@ -660,8 +739,12 @@ UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd status = xf_SurfaceCommand_Planar(xfc, context, cmd); break; - case RDPGFX_CODECID_H264: - status = xf_SurfaceCommand_H264(xfc, context, cmd); + case RDPGFX_CODECID_AVC420: + status = xf_SurfaceCommand_AVC420(xfc, context, cmd); + break; + + case RDPGFX_CODECID_AVC444: + status = xf_SurfaceCommand_AVC444(xfc, context, cmd); break; case RDPGFX_CODECID_ALPHA: @@ -673,6 +756,11 @@ UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd break; case RDPGFX_CODECID_CAPROGRESSIVE_V2: + WLog_WARN(TAG, "SurfaceCommand %08X not implemented", cmd->codecId); + break; + + default: + WLog_WARN(TAG, "Invalid SurfaceCommand %08X", cmd->codecId); break; } @@ -684,7 +772,7 @@ UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext) +static UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext) { return CHANNEL_RC_OK; } @@ -694,7 +782,7 @@ UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODI * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface) +static UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface) { size_t size; UINT32 bytesPerPixel; @@ -714,6 +802,13 @@ UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* c return CHANNEL_RC_NO_MEMORY; } + if (!freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL, + createSurface->width, createSurface->height)) + { + free (surface); + return ERROR_INTERNAL_ERROR; + } + surface->surfaceId = createSurface->surfaceId; surface->width = (UINT32) createSurface->width; surface->height = (UINT32) createSurface->height; @@ -775,7 +870,7 @@ UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* c * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface) +static UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface) { rdpCodecs* codecs = NULL; xfGfxSurface* surface = NULL; @@ -807,13 +902,13 @@ UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* d * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) +static UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) { UINT16 index; UINT32 color; BYTE a, r, g, b; int nWidth, nHeight; - RDPGFX_RECT16* rect; + RECTANGLE_16* rect; xfGfxSurface* surface; RECTANGLE_16 invalidRect; xfContext* xfc = (xfContext*) context->custom; @@ -859,12 +954,12 @@ UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface) +static UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface) { UINT16 index; BOOL sameSurface; int nWidth, nHeight; - RDPGFX_RECT16* rectSrc; + RECTANGLE_16* rectSrc; RDPGFX_POINT16* destPt; RECTANGLE_16 invalidRect; xfGfxSurface* surfaceSrc; @@ -924,10 +1019,10 @@ UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) +static UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) { size_t size; - RDPGFX_RECT16* rect; + RECTANGLE_16* rect; xfGfxSurface* surface; xfGfxCacheEntry* cacheEntry; xfContext* xfc = (xfContext*) context->custom; @@ -977,7 +1072,7 @@ UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface) +static UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface) { UINT16 index; RDPGFX_POINT16* destPt; @@ -1019,7 +1114,7 @@ UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply) +static UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply) { return CHANNEL_RC_OK; } @@ -1029,7 +1124,7 @@ UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry) +static UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry) { xfGfxCacheEntry* cacheEntry; @@ -1051,7 +1146,7 @@ UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_P * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) +static UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) { xfGfxSurface* surface; @@ -1074,7 +1169,7 @@ UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_O * * @return 0 on success, otherwise a Win32 error code */ -UINT xf_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow) +static UINT xf_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow) { return CHANNEL_RC_OK; } diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 22a941c..6b49d56 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -290,15 +290,29 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + /* error handled below */ + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + /* error handled below */ + } appWindow->title = title; } else { - appWindow->title = _strdup("RdpRailWindow"); + if (!(appWindow->title = _strdup("RdpRailWindow"))) + WLog_ERR(TAG, "failed to duplicate default window title string"); } + if (!appWindow->title) { free(appWindow); @@ -365,9 +379,20 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); - + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + return FALSE; + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + return FALSE; + } free(appWindow->title); appWindow->title = title; } diff --git a/client/common/client.c b/client/common/client.c index a847c9b..7d4cea6 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -195,17 +195,6 @@ int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, status = freerdp_client_settings_parse_command_line_arguments(settings, argc, argv, allowUnknown); - if (settings->ConnectionFile) - { - status = freerdp_client_settings_parse_connection_file(settings, settings->ConnectionFile); - } - - if (settings->AssistanceFile) - { - status = freerdp_client_settings_parse_assistance_file(settings, settings->AssistanceFile); - } - - /* Only call post processing if no status/error was returned*/ if (status < 0) return status; diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 76a5b8d..93c3c1c 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -321,6 +321,9 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, int if (!(settings->ConnectionFile = _strdup(argv[index]))) return COMMAND_LINE_ERROR_MEMORY; + if (freerdp_client_settings_parse_connection_file(settings, settings->ConnectionFile)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + return 1; } } @@ -333,6 +336,9 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, int if (!(settings->AssistanceFile = _strdup(argv[index]))) return COMMAND_LINE_ERROR_MEMORY; + if (freerdp_client_settings_parse_assistance_file(settings, settings->AssistanceFile) < 0) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + return 1; } } @@ -1474,6 +1480,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "v") { + free (settings->ServerHostname); + settings->ServerHostname = NULL; + p = strchr(arg->Value, '['); /* ipv4 */ if (!p) @@ -1515,6 +1524,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "spn-class") { + free (settings->AuthenticationServiceClass); if (!(settings->AuthenticationServiceClass = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; @@ -1531,6 +1541,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { settings->SendPreconnectionPdu = TRUE; + free (settings->PreconnectionBlob); if (!(settings->PreconnectionBlob = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -1622,6 +1633,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "t") { + free (settings->WindowTitle); if (!(settings->WindowTitle = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -1663,11 +1675,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->ConsoleSession = TRUE; settings->RestrictedAdminModeRequired = TRUE; + free (settings->PasswordHash); if (!(settings->PasswordHash = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "client-hostname") { + free (settings->ClientHostname); if (!(settings->ClientHostname = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -1715,16 +1729,19 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "d") { + free (settings->Domain); if (!(settings->Domain = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "p") { + free (settings->Password); if (!(settings->Password = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "g") { + free (settings->GatewayHostname); if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { p = strchr(arg->Value, ':'); @@ -1764,12 +1781,14 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "gd") { + free (settings->GatewayDomain); if (!(settings->GatewayDomain = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; settings->GatewayUseSameCredentials = FALSE; } CommandLineSwitchCase(arg, "gp") { + free (settings->GatewayPassword); if (!(settings->GatewayPassword = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; settings->GatewayUseSameCredentials = FALSE; @@ -1815,6 +1834,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "app") { + free (settings->RemoteApplicationProgram); if (!(settings->RemoteApplicationProgram = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; @@ -1826,33 +1846,39 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "load-balance-info") { + free (settings->LoadBalanceInfo); if (!(settings->LoadBalanceInfo = (BYTE*) _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; settings->LoadBalanceInfoLength = (UINT32) strlen((char*) settings->LoadBalanceInfo); } CommandLineSwitchCase(arg, "app-name") { + free (settings->RemoteApplicationName); if (!(settings->RemoteApplicationName = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-icon") { + free (settings->RemoteApplicationIcon); if (!(settings->RemoteApplicationIcon = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-cmd") { + free (settings->RemoteApplicationCmdLine); if (!(settings->RemoteApplicationCmdLine = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-file") { + free (settings->RemoteApplicationFile); if (!(settings->RemoteApplicationFile = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "app-guid") { + free (settings->RemoteApplicationGuid); if (!(settings->RemoteApplicationGuid = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -1878,11 +1904,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "shell") { + free (settings->AlternateShell); if (!(settings->AlternateShell = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "shell-dir") { + free (settings->ShellWorkingDirectory); if (!(settings->ShellWorkingDirectory = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -2037,6 +2065,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "pcb") { settings->SendPreconnectionPdu = TRUE; + free (settings->PreconnectionBlob); if (!(settings->PreconnectionBlob = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -2141,6 +2170,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "tls-ciphers") { + free (settings->AllowedTlsCiphers); if (strcmp(arg->Value, "netmon") == 0) { if (!(settings->AllowedTlsCiphers = _strdup("ALL:!ECDH"))) @@ -2159,6 +2189,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "cert-name") { + free (settings->CertificateName); if (!(settings->CertificateName = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -2253,11 +2284,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "wm-class") { + free (settings->WmClass); if (!(settings->WmClass = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } CommandLineSwitchCase(arg, "play-rfx") { + free (settings->PlayRemoteFxFile); if (!(settings->PlayRemoteFxFile = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; settings->PlayRemoteFx = TRUE; @@ -2293,6 +2326,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "assistance") { settings->RemoteAssistanceMode = TRUE; + free (settings->RemoteAssistancePassword); if (!(settings->RemoteAssistancePassword = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } @@ -2353,9 +2387,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + free (settings->Username); if (!settings->Domain && user) { BOOL ret; + free (settings->Domain); + ret = freerdp_parse_username(user, &settings->Username, &settings->Domain); free(user); if (!ret) @@ -2364,9 +2401,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, else settings->Username = user; + free (settings->GatewayUsername); if (!settings->GatewayDomain && gwUser) { BOOL ret; + free (settings->GatewayDomain); ret = freerdp_parse_username(gwUser, &settings->GatewayUsername, &settings->GatewayDomain); free(gwUser); diff --git a/include/freerdp/channels/channels.h b/include/freerdp/channels/channels.h index 7e408f1..816afbb 100644 --- a/include/freerdp/channels/channels.h +++ b/include/freerdp/channels/channels.h @@ -38,9 +38,9 @@ FREERDP_API int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* PVIRTUALCHANNELENTRY entry, void* data); FREERDP_API int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name, void* data); -FREERDP_API int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance); -FREERDP_API int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance); -FREERDP_API int freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance); +FREERDP_API UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance); +FREERDP_API UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance); +FREERDP_API UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance); FREERDP_API BOOL freerdp_channels_get_fds(rdpChannels* channels, freerdp* instance, void** read_fds, int* read_count, void** write_fds, int* write_count); FREERDP_API BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance); diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index 24943ff..e197149 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -37,15 +37,6 @@ struct _RDPGFX_POINT16 }; typedef struct _RDPGFX_POINT16 RDPGFX_POINT16; -struct _RDPGFX_RECT16 -{ - UINT16 left; - UINT16 top; - UINT16 right; - UINT16 bottom; -}; -typedef struct _RDPGFX_RECT16 RDPGFX_RECT16; - struct _RDPGFX_COLOR32 { BYTE B; @@ -99,6 +90,7 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_8 0x00080004 #define RDPGFX_CAPVERSION_81 0x00080105 +#define RDPGFX_CAPVERSION_10 0x000A0002 #define RDPGFX_CAPSET_SIZE 12 @@ -111,7 +103,8 @@ typedef struct _RDPGFX_CAPSET RDPGFX_CAPSET; #define RDPGFX_CAPS_FLAG_THINCLIENT 0x00000001 /* 8.0+ */ #define RDPGFX_CAPS_FLAG_SMALL_CACHE 0x00000002 /* 8.0+ */ -#define RDPGFX_CAPS_FLAG_H264ENABLED 0x00000010 /* 8.1+ */ +#define RDPGFX_CAPS_FLAG_AVC420_ENABLED 0x00000010 /* 8.1+ */ +#define RDPGFX_CAPS_FLAG_AVC_DISABLED 0x00000020 /* 10.0+ */ struct _RDPGFX_CAPSET_VERSION8 { @@ -129,6 +122,14 @@ struct _RDPGFX_CAPSET_VERSION81 }; typedef struct _RDPGFX_CAPSET_VERSION81 RDPGFX_CAPSET_VERSION81; +struct _RDPGFX_CAPSET_VERSION10 +{ + UINT32 version; + UINT32 capsDataLength; + UINT32 flags; +}; +typedef struct _RDPGFX_CAPSET_VERSION10 RDPGFX_CAPSET_VERSION10; + /** * Graphics Messages */ @@ -137,15 +138,16 @@ typedef struct _RDPGFX_CAPSET_VERSION81 RDPGFX_CAPSET_VERSION81; #define RDPGFX_CODECID_CAVIDEO 0x0003 #define RDPGFX_CODECID_CLEARCODEC 0x0008 #define RDPGFX_CODECID_PLANAR 0x000A -#define RDPGFX_CODECID_H264 0x000B +#define RDPGFX_CODECID_AVC420 0x000B #define RDPGFX_CODECID_ALPHA 0x000C +#define RDPGFX_CODECID_AVC444 0x000E struct _RDPGFX_WIRE_TO_SURFACE_PDU_1 { UINT16 surfaceId; UINT16 codecId; RDPGFX_PIXELFORMAT pixelFormat; - RDPGFX_RECT16 destRect; + RECTANGLE_16 destRect; UINT32 bitmapDataLength; BYTE* bitmapData; }; @@ -195,7 +197,7 @@ struct _RDPGFX_SOLID_FILL_PDU UINT16 surfaceId; RDPGFX_COLOR32 fillPixel; UINT16 fillRectCount; - RDPGFX_RECT16* fillRects; + RECTANGLE_16* fillRects; }; typedef struct _RDPGFX_SOLID_FILL_PDU RDPGFX_SOLID_FILL_PDU; @@ -203,7 +205,7 @@ struct _RDPGFX_SURFACE_TO_SURFACE_PDU { UINT16 surfaceIdSrc; UINT16 surfaceIdDest; - RDPGFX_RECT16 rectSrc; + RECTANGLE_16 rectSrc; UINT16 destPtsCount; RDPGFX_POINT16* destPts; }; @@ -214,7 +216,7 @@ struct _RDPGFX_SURFACE_TO_CACHE_PDU UINT16 surfaceId; UINT64 cacheKey; UINT16 cacheSlot; - RDPGFX_RECT16 rectSrc; + RECTANGLE_16 rectSrc; }; typedef struct _RDPGFX_SURFACE_TO_CACHE_PDU RDPGFX_SURFACE_TO_CACHE_PDU; @@ -349,18 +351,27 @@ typedef struct _RDPGFX_H264_QUANT_QUALITY RDPGFX_H264_QUANT_QUALITY; struct _RDPGFX_H264_METABLOCK { UINT32 numRegionRects; - RDPGFX_RECT16* regionRects; + RECTANGLE_16* regionRects; RDPGFX_H264_QUANT_QUALITY* quantQualityVals; }; typedef struct _RDPGFX_H264_METABLOCK RDPGFX_H264_METABLOCK; -struct _RDPGFX_H264_BITMAP_STREAM +struct _RDPGFX_AVC420_BITMAP_STREAM { RDPGFX_H264_METABLOCK meta; UINT32 length; BYTE* data; }; -typedef struct _RDPGFX_H264_BITMAP_STREAM RDPGFX_H264_BITMAP_STREAM; +typedef struct _RDPGFX_AVC420_BITMAP_STREAM RDPGFX_AVC420_BITMAP_STREAM; + +struct _RDPGFX_AVC444_BITMAP_STREAM +{ + UINT32 cbAvc420EncodedBitstream1; + BYTE LC; + RDPGFX_AVC420_BITMAP_STREAM bitstream[2]; +}; +typedef struct _RDPGFX_AVC444_BITMAP_STREAM RDPGFX_AVC444_BITMAP_STREAM; + #endif /* FREERDP_CHANNEL_RDPGFX_H */ diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index cc946d5..baca737 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -71,7 +71,7 @@ FREERDP_API int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcS FREERDP_API int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); -FREERDP_API int clear_context_reset(CLEAR_CONTEXT* clear); +FREERDP_API BOOL clear_context_reset(CLEAR_CONTEXT* clear); FREERDP_API CLEAR_CONTEXT* clear_context_new(BOOL Compressor); FREERDP_API void clear_context_free(CLEAR_CONTEXT* clear); @@ -81,4 +81,4 @@ FREERDP_API void clear_context_free(CLEAR_CONTEXT* clear); #endif #endif /* FREERDP_CODEC_CLEAR_H */ - + diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h index 410ad49..83e3ca5 100644 --- a/include/freerdp/codec/h264.h +++ b/include/freerdp/codec/h264.h @@ -29,8 +29,10 @@ typedef struct _H264_CONTEXT H264_CONTEXT; typedef BOOL (*pfnH264SubsystemInit)(H264_CONTEXT* h264); typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264); -typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize); -typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize); +typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, + UINT32 SrcSize, UINT32 plane); +typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, BYTE** ppDstData, + UINT32* pDstSize, UINT32 plane); struct _H264_CONTEXT_SUBSYSTEM { @@ -61,10 +63,15 @@ struct _H264_CONTEXT FLOAT FrameRate; UINT32 QP; UINT32 NumberOfThreads; - - int iStride[3]; - BYTE* pYUVData[3]; + UINT32 iStride[2][3]; + BYTE* pYUVData[2][3]; + + UINT32 iYUV444Size[3]; + UINT32 iYUV444Stride[3]; + BYTE* pYUV444Data[3]; + + UINT32 numSystemData; void* pSystemData; H264_CONTEXT_SUBSYSTEM* subsystem; }; @@ -73,14 +80,32 @@ struct _H264_CONTEXT extern "C" { #endif -FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat, - int nSrcStep, int nSrcWidth, int nSrcHeight, BYTE** ppDstData, UINT32* pDstSize); +FREERDP_API INT32 avc420_compress(H264_CONTEXT* h264, BYTE* pSrcData, + DWORD SrcFormat, UINT32 nSrcStep, + UINT32 nSrcWidth, UINT32 nSrcHeight, + BYTE** ppDstData, UINT32* pDstSize); -FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, - BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstWidth, int nDstHeight, - RDPGFX_RECT16* regionRects, int numRegionRect); +FREERDP_API INT32 avc420_decompress(H264_CONTEXT* h264, BYTE* pSrcData, + UINT32 SrcSize, BYTE* pDstData, + DWORD DstFormat, UINT32 nDstStep, + UINT32 nDstWidth, UINT32 nDstHeight, + RECTANGLE_16* regionRects, UINT32 numRegionRect); -FREERDP_API int h264_context_reset(H264_CONTEXT* h264); +FREERDP_API INT32 avc444_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat, + UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, + BYTE* op, + BYTE** pDstData, UINT32* pDstSize, + BYTE** pAuxDstData, UINT32* pAuxDstSize); + +FREERDP_API INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, + RECTANGLE_16* regionRects, UINT32 numRegionRect, + BYTE* pSrcData, UINT32 SrcSize, + RECTANGLE_16* auxRegionRects, UINT32 numAuxRegionRect, + BYTE* pAuxSrcData, UINT32 AuxSrcSize, + BYTE* pDstData, DWORD DstFormat, + UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight); + +FREERDP_API BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height); FREERDP_API H264_CONTEXT* h264_context_new(BOOL Compressor); FREERDP_API void h264_context_free(H264_CONTEXT* h264); diff --git a/include/freerdp/codec/interleaved.h b/include/freerdp/codec/interleaved.h index 205bc44..1d75f86 100644 --- a/include/freerdp/codec/interleaved.h +++ b/include/freerdp/codec/interleaved.h @@ -48,7 +48,7 @@ FREERDP_API int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, FREERDP_API int interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize, int nWidth, int nHeight, BYTE* pSrcData, DWORD SrcFormat, int nSrcStep, int nXSrc, int nYSrc, BYTE* palette, int bpp); -FREERDP_API int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved); +FREERDP_API BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved); FREERDP_API BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor); FREERDP_API void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved); diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index 2ba5623..0439308 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -93,7 +93,7 @@ FREERDP_API NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, i FREERDP_API int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message); FREERDP_API int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message); -FREERDP_API int nsc_context_reset(NSC_CONTEXT* context); +FREERDP_API BOOL nsc_context_reset(NSC_CONTEXT* context, UINT32 width, UINT32 height); FREERDP_API NSC_CONTEXT* nsc_context_new(void); FREERDP_API void nsc_context_free(NSC_CONTEXT* context); diff --git a/include/freerdp/codec/planar.h b/include/freerdp/codec/planar.h index 781ae08..4bc0e24 100644 --- a/include/freerdp/codec/planar.h +++ b/include/freerdp/codec/planar.h @@ -109,7 +109,7 @@ FREERDP_API BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], in FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* dstData, int* pDstSize); -FREERDP_API int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context); +FREERDP_API BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context); FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h index a2cc7ad..cc2d75c 100644 --- a/include/freerdp/codec/progressive.h +++ b/include/freerdp/codec/progressive.h @@ -242,7 +242,7 @@ FREERDP_API int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* p FREERDP_API int progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId, UINT32 width, UINT32 height); FREERDP_API int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId); -FREERDP_API int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive); +FREERDP_API BOOL progressive_context_reset(PROGRESSIVE_CONTEXT* progressive); FREERDP_API PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor); FREERDP_API void progressive_context_free(PROGRESSIVE_CONTEXT* progressive); @@ -252,4 +252,4 @@ FREERDP_API void progressive_context_free(PROGRESSIVE_CONTEXT* progressive); #endif #endif /* FREERDP_CODEC_PROGRESSIVE_H */ - + diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index 9bb2ff4..d9d5a99 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -183,7 +183,7 @@ FREERDP_API RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_REC BYTE* data, int width, int height, int scanline, int* numMessages, int maxDataSize); FREERDP_API BOOL rfx_write_message(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message); -FREERDP_API void rfx_context_reset(RFX_CONTEXT* context); +FREERDP_API BOOL rfx_context_reset(RFX_CONTEXT* context, UINT32 width, UINT32 height); FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); FREERDP_API void rfx_context_free(RFX_CONTEXT* context); diff --git a/include/freerdp/codecs.h b/include/freerdp/codecs.h index 5298d14..9066d90 100644 --- a/include/freerdp/codecs.h +++ b/include/freerdp/codecs.h @@ -39,7 +39,8 @@ #define FREERDP_CODEC_CLEARCODEC 0x00000010 #define FREERDP_CODEC_ALPHACODEC 0x00000020 #define FREERDP_CODEC_PROGRESSIVE 0x00000040 -#define FREERDP_CODEC_H264 0x00000080 +#define FREERDP_CODEC_AVC420 0x00000080 +#define FREERDP_CODEC_AVC444 0x00000100 #define FREERDP_CODEC_ALL 0xFFFFFFFF struct rdp_codecs @@ -60,7 +61,8 @@ struct rdp_codecs #endif FREERDP_API BOOL freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags); -FREERDP_API BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags); +FREERDP_API BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags, + UINT32 width, UINT32 height); FREERDP_API rdpCodecs* codecs_new(rdpContext* context); FREERDP_API void codecs_free(rdpCodecs* codecs); diff --git a/include/freerdp/primitives.h b/include/freerdp/primitives.h index 1eb51b2..c6a9cb3 100644 --- a/include/freerdp/primitives.h +++ b/include/freerdp/primitives.h @@ -58,8 +58,8 @@ typedef INT32 pstatus_t; /* match IppStatus. */ /* Structures compatible with IPP */ typedef struct { - INT32 width; - INT32 height; + UINT32 width; + UINT32 height; } prim_size_t; /* like IppiSize */ /* Function prototypes for all of the supported primitives. */ @@ -74,7 +74,7 @@ typedef pstatus_t (*__copy_8u_t)( typedef pstatus_t (*__copy_8u_AC4r_t)( const BYTE *pSrc, INT32 srcStep, /* bytes */ - BYTE *pDst, + BYTE *pDst, INT32 dstStep, /* bytes */ INT32 width, INT32 height); /* pixels */ typedef pstatus_t (*__set_8u_t)( @@ -169,13 +169,31 @@ typedef pstatus_t (*__RGB565ToARGB_16u32u_C3C4_t)( UINT32 width, UINT32 height, BOOL alpha, BOOL invert); typedef pstatus_t (*__YUV420ToRGB_8u_P3AC4R_t)( - const BYTE* pSrc[3], INT32 srcStep[3], - BYTE* pDst, INT32 dstStep, + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pDst, UINT32 dstStep, + const prim_size_t* roi); +typedef pstatus_t (*__YUV444ToRGB_8u_P3AC4R_t)( + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pDst, UINT32 dstStep, const prim_size_t* roi); typedef pstatus_t (*__RGBToYUV420_8u_P3AC4R_t)( - const BYTE* pSrc, INT32 srcStep, - BYTE* pDst[3], INT32 dstStep[3], + const BYTE* pSrc, UINT32 srcStep, + BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi); +typedef pstatus_t (*__RGBToYUV444_8u_P3AC4R_t)( + const BYTE* pSrc, UINT32 srcStep, + BYTE* pDst[3], UINT32 dstStep[3], + const prim_size_t* roi); +typedef pstatus_t (*__YUV420CombineToYUV444_t)( + const BYTE* pMainSrc[3], const UINT32 srcMainStep[3], + const BYTE* pAuxSrc[3], const UINT32 srcAuxStep[3], + BYTE* pDst[3], const UINT32 dstStep[3], + const prim_size_t* roi); +typedef pstatus_t (*__YUV444SplitToYUV420_t)( + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pMainDst[3], const UINT32 dstMainStep[3], + BYTE* pAuxDst[3], const UINT32 srcAuxStep[3], + const prim_size_t* roi); typedef pstatus_t (*__andC_32u_t)( const UINT32 *pSrc, UINT32 val, @@ -224,6 +242,10 @@ typedef struct __RGB565ToARGB_16u32u_C3C4_t RGB565ToARGB_16u32u_C3C4; __YUV420ToRGB_8u_P3AC4R_t YUV420ToRGB_8u_P3AC4R; __RGBToYUV420_8u_P3AC4R_t RGBToYUV420_8u_P3AC4R; + __RGBToYUV444_8u_P3AC4R_t RGBToYUV444_8u_P3AC4R; + __YUV420CombineToYUV444_t YUV420CombineToYUV444; + __YUV444SplitToYUV420_t YUV444SplitToYUV420; + __YUV420ToRGB_8u_P3AC4R_t YUV444ToRGB_8u_P3AC4R; } primitives_t; #ifdef __cplusplus diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 41159a5..95fa781 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -234,7 +234,7 @@ endif() if(WITH_SSE2) if(CMAKE_COMPILER_IS_GNUCC) - set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -O2 -Wdeclaration-after-statement") + set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -Wdeclaration-after-statement") endif() if(MSVC) @@ -251,12 +251,6 @@ if(DEFINED OPTIMIZATION) set_source_files_properties(${PRIMITIVES_OPT_SRCS} PROPERTIES COMPILE_FLAGS ${OPTIMIZATION}) endif() - -# always compile with optimization -if(CMAKE_COMPILER_IS_GNUCC) - set_source_files_properties(${PRIMITIVES_SRCS} PROPERTIES COMPILE_FLAGS "-O2") -endif() - set(PRIMITIVES_SRCS ${PRIMITIVES_SRCS} ${PRIMITIVES_OPT_SRCS}) freerdp_module_add(${PRIMITIVES_SRCS}) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index 922a83a..ab4e5de 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -830,12 +830,16 @@ int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** return 1; } -int clear_context_reset(CLEAR_CONTEXT* clear) +BOOL clear_context_reset(CLEAR_CONTEXT* clear) { + if (!clear) + return FALSE; + clear->seqNumber = 0; clear->VBarStorageCursor = 0; clear->ShortVBarStorageCursor = 0; - return 1; + + return TRUE; } CLEAR_CONTEXT* clear_context_new(BOOL Compressor) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index da2e083..fe2d0a6 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -35,7 +35,7 @@ * Dummy subsystem */ -static int dummy_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +static int dummy_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, UINT32 plane) { return -1; } @@ -103,17 +103,17 @@ typedef interface IMFDXGIDeviceManager IMFDXGIDeviceManager; #define __IMFDXGIDeviceManager_INTERFACE_DEFINED__ typedef struct IMFDXGIDeviceManagerVtbl -{ +{ HRESULT (STDMETHODCALLTYPE * QueryInterface)(IMFDXGIDeviceManager* This, REFIID riid, void** ppvObject); ULONG (STDMETHODCALLTYPE * AddRef)(IMFDXGIDeviceManager* This); - ULONG (STDMETHODCALLTYPE * Release)(IMFDXGIDeviceManager* This); - HRESULT (STDMETHODCALLTYPE * CloseDeviceHandle)(IMFDXGIDeviceManager* This, HANDLE hDevice); - HRESULT (STDMETHODCALLTYPE * GetVideoService)(IMFDXGIDeviceManager* This, HANDLE hDevice, REFIID riid, void** ppService); - HRESULT (STDMETHODCALLTYPE * LockDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice, REFIID riid, void** ppUnkDevice, BOOL fBlock); - HRESULT (STDMETHODCALLTYPE * OpenDeviceHandle)(IMFDXGIDeviceManager* This, HANDLE* phDevice); - HRESULT (STDMETHODCALLTYPE * ResetDevice)(IMFDXGIDeviceManager* This, IUnknown* pUnkDevice, UINT resetToken); - HRESULT (STDMETHODCALLTYPE * TestDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice); - HRESULT (STDMETHODCALLTYPE * UnlockDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice, BOOL fSaveState); + ULONG (STDMETHODCALLTYPE * Release)(IMFDXGIDeviceManager* This); + HRESULT (STDMETHODCALLTYPE * CloseDeviceHandle)(IMFDXGIDeviceManager* This, HANDLE hDevice); + HRESULT (STDMETHODCALLTYPE * GetVideoService)(IMFDXGIDeviceManager* This, HANDLE hDevice, REFIID riid, void** ppService); + HRESULT (STDMETHODCALLTYPE * LockDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice, REFIID riid, void** ppUnkDevice, BOOL fBlock); + HRESULT (STDMETHODCALLTYPE * OpenDeviceHandle)(IMFDXGIDeviceManager* This, HANDLE* phDevice); + HRESULT (STDMETHODCALLTYPE * ResetDevice)(IMFDXGIDeviceManager* This, IUnknown* pUnkDevice, UINT resetToken); + HRESULT (STDMETHODCALLTYPE * TestDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice); + HRESULT (STDMETHODCALLTYPE * UnlockDevice)(IMFDXGIDeviceManager* This, HANDLE hDevice, BOOL fSaveState); } IMFDXGIDeviceManagerVtbl; @@ -231,7 +231,7 @@ error: return hr; } -static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, UINT32 plane) { HRESULT hr; BYTE* pbBuffer = NULL; @@ -243,6 +243,8 @@ static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) IMFMediaBuffer* outputBuffer = NULL; MFT_OUTPUT_DATA_BUFFER outputDataBuffer; H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*) h264->pSystemData; + INT32* iStride = h264->iStride[plane]; + BYTE** pYUVData = h264->pYUVData[plane]; hr = sys->MFCreateMemoryBuffer(SrcSize, &inputBuffer); @@ -321,7 +323,7 @@ static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { - BYTE* pYUVData; + BYTE* pTmpYUVData; int offset = 0; UINT32 stride = 0; UINT64 frameSize = 0; @@ -376,27 +378,27 @@ static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) goto error; } - h264->iStride[0] = stride; - h264->iStride[1] = stride / 2; - h264->iStride[2] = stride / 2; + iStride[0] = stride; + iStride[1] = stride / 2; + iStride[2] = stride / 2; - pYUVData = (BYTE*) calloc(1, 2 * stride * sys->frameHeight); + pTmpYUVData = (BYTE*) calloc(1, 2 * stride * sys->frameHeight); - h264->pYUVData[0] = &pYUVData[offset]; - pYUVData += h264->iStride[0] * sys->frameHeight; + pYUVData[0] = &pTmpYUVData[offset]; + pTmpYUVData += iStride[0] * sys->frameHeight; - h264->pYUVData[1] = &pYUVData[offset]; - pYUVData += h264->iStride[1] * (sys->frameHeight / 2); + pYUVData[1] = &pTmpYUVData[offset]; + pTmpYUVData += iStride[1] * (sys->frameHeight / 2); - h264->pYUVData[2] = &pYUVData[offset]; - pYUVData += h264->iStride[2] * (sys->frameHeight / 2); + pYUVData[2] = &pTmpYUVData[offset]; + pTmpYUVData += iStride[2] * (sys->frameHeight / 2); h264->width = sys->frameWidth; h264->height = sys->frameHeight; } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - + } else if (FAILED(hr)) { @@ -435,14 +437,14 @@ static int mf_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) goto error; } - CopyMemory(h264->pYUVData[0], &buffer[offset], h264->iStride[0] * sys->frameHeight); - offset += h264->iStride[0] * sys->frameHeight; + CopyMemory(pYUVData[0], &buffer[offset], iStride[0] * sys->frameHeight); + offset += iStride[0] * sys->frameHeight; - CopyMemory(h264->pYUVData[1], &buffer[offset], h264->iStride[1] * (sys->frameHeight / 2)); - offset += h264->iStride[1] * (sys->frameHeight / 2); + CopyMemory(pYUVData[1], &buffer[offset], iStride[1] * (sys->frameHeight / 2)); + offset += iStride[1] * (sys->frameHeight / 2); - CopyMemory(h264->pYUVData[2], &buffer[offset], h264->iStride[2] * (sys->frameHeight / 2)); - offset += h264->iStride[2] * (sys->frameHeight / 2); + CopyMemory(pYUVData[2], &buffer[offset], iStride[2] * (sys->frameHeight / 2)); + offset += iStride[2] * (sys->frameHeight / 2); hr = outputBuffer->lpVtbl->Unlock(outputBuffer); @@ -464,7 +466,7 @@ error: return -1; } -static int mf_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int mf_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize, UINT32 plane) { H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*) h264->pSystemData; @@ -473,6 +475,7 @@ static int mf_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) static void mf_uninit(H264_CONTEXT* h264) { + UINT32 x; H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*) h264->pSystemData; if (sys) @@ -513,12 +516,14 @@ static void mf_uninit(H264_CONTEXT* h264) sys->mfplat = NULL; } - free(h264->pYUVData[0]); - h264->pYUVData[0] = h264->pYUVData[1] = h264->pYUVData[2] = NULL; - h264->iStride[0] = h264->iStride[1] = h264->iStride[2] = 0; + for (x=0; xpYUVData) / sizeof(h264->pYUVData[0]); x++) + free (h264->pYUVData[x][0]); + + memset(h264->pYUVData, 0, sizeof(h264->pYUVData)); + memset(h264->iStride, 0, sizeof(h264->iStride)); sys->MFShutdown(); - + CoUninitialize(); free(sys); @@ -592,7 +597,7 @@ static BOOL mf_init(H264_CONTEXT* h264) var.vt = VT_UI4; var.ulVal = 1; - + hr = sys->codecApi->lpVtbl->SetValue(sys->codecApi, &CODECAPI_AVLowLatencyMode, &var); if (FAILED(hr)) @@ -618,7 +623,7 @@ static BOOL mf_init(H264_CONTEXT* h264) } hr = sys->inputType->lpVtbl->SetGUID(sys->inputType, &MF_MT_SUBTYPE, &MFVideoFormat_H264); - + if (FAILED(hr)) { WLog_ERR(TAG, "SetGUID(MF_MT_SUBTYPE) failure: 0x%04X", hr); @@ -708,14 +713,14 @@ struct _H264_CONTEXT_X264 }; typedef struct _H264_CONTEXT_X264 H264_CONTEXT_X264; -static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, UINT32 plane) { //H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; return 1; } -static int x264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int x264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize, UINT32 plane) { //H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; @@ -737,7 +742,9 @@ static BOOL x264_init(H264_CONTEXT* h264) { H264_CONTEXT_X264* sys; - sys = (H264_CONTEXT_X264*) calloc(1, sizeof(H264_CONTEXT_X264)); + h264->numSystemData = 1; + sys = (H264_CONTEXT_X264*) calloc(h264->numSystemData, + sizeof(H264_CONTEXT_X264)); if (!sys) { @@ -815,12 +822,16 @@ static void openh264_trace_callback(H264_CONTEXT* h264, int level, const char* m WLog_INFO(TAG, "%d - %s", level, message); } -static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, UINT32 plane) { DECODING_STATE state; SBufferInfo sBufferInfo; SSysMEMBuffer* pSystemBuffer; H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; + UINT32* iStride = h264->iStride[plane]; + BYTE** pYUVData = h264->pYUVData[plane]; + + sys = &((H264_CONTEXT_OPENH264*) h264->pSystemData)[0]; if (!sys->pDecoder) return -2001; @@ -829,25 +840,25 @@ static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSiz * Decompress the image. The RDP host only seems to send I420 format. */ - h264->pYUVData[0] = NULL; - h264->pYUVData[1] = NULL; - h264->pYUVData[2] = NULL; + pYUVData[0] = NULL; + pYUVData[1] = NULL; + pYUVData[2] = NULL; ZeroMemory(&sBufferInfo, sizeof(sBufferInfo)); - state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, pSrcData, SrcSize, h264->pYUVData, &sBufferInfo); + state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, pSrcData, SrcSize, pYUVData, &sBufferInfo); if (sBufferInfo.iBufferStatus != 1) { if (state == dsNoParamSets) { /* this happens on the first frame due to missing parameter sets */ - state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, h264->pYUVData, &sBufferInfo); + state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, pYUVData, &sBufferInfo); } else if (state == dsErrorFree) { /* call DecodeFrame2 again to decode without delay */ - state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, h264->pYUVData, &sBufferInfo); + state = (*sys->pDecoder)->DecodeFrame2(sys->pDecoder, NULL, 0, pYUVData, &sBufferInfo); } else { @@ -856,6 +867,12 @@ static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSiz } } + pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer; + + iStride[0] = pSystemBuffer->iStride[0]; + iStride[1] = pSystemBuffer->iStride[1]; + iStride[2] = pSystemBuffer->iStride[1]; + if (sBufferInfo.iBufferStatus != 1) { WLog_WARN(TAG, "DecodeFrame2 iBufferStatus: %d", sBufferInfo.iBufferStatus); @@ -868,44 +885,39 @@ static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSiz return -2003; } - pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer; - #if 0 WLog_INFO(TAG, "h264_decompress: state=%u, pYUVData=[%p,%p,%p], bufferStatus=%d, width=%d, height=%d, format=%d, stride=[%d,%d]", - state, h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2], sBufferInfo.iBufferStatus, - pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iFormat, - pSystemBuffer->iStride[0], pSystemBuffer->iStride[1]); + state, pYUVData[0], pYUVData[1], pYUVData[2], sBufferInfo.iBufferStatus, + pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iFormat, + pSystemBuffer->iStride[0], pSystemBuffer->iStride[1]); #endif if (pSystemBuffer->iFormat != videoFormatI420) return -2004; - if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2]) + if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2]) return -2005; - h264->iStride[0] = pSystemBuffer->iStride[0]; - h264->iStride[1] = pSystemBuffer->iStride[1]; - h264->iStride[2] = pSystemBuffer->iStride[1]; - - h264->width = pSystemBuffer->iWidth; - h264->height = pSystemBuffer->iHeight; - return 1; } -static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize, UINT32 plane) { int i, j; int status; SFrameBSInfo info; SSourcePicture pic; SBitrateInfo bitrate; - H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; + H264_CONTEXT_OPENH264* sys; + BYTE** pYUVData = h264->pYUVData[plane]; + UINT32* iStride = h264->iStride[plane]; + + sys = &((H264_CONTEXT_OPENH264*) h264->pSystemData)[0]; if (!sys->pEncoder) return -1; - if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2]) + if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2]) return -1; if ((sys->EncParamExt.iPicWidth != h264->width) || (sys->EncParamExt.iPicHeight != h264->height)) @@ -935,16 +947,16 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstS switch (h264->RateControlMode) { - case H264_RATECONTROL_VBR: - sys->EncParamExt.iRCMode = RC_BITRATE_MODE; - sys->EncParamExt.iTargetBitrate = h264->BitRate; - sys->EncParamExt.sSpatialLayers[0].iSpatialBitrate = sys->EncParamExt.iTargetBitrate; - break; + case H264_RATECONTROL_VBR: + sys->EncParamExt.iRCMode = RC_BITRATE_MODE; + sys->EncParamExt.iTargetBitrate = h264->BitRate; + sys->EncParamExt.sSpatialLayers[0].iSpatialBitrate = sys->EncParamExt.iTargetBitrate; + break; - case H264_RATECONTROL_CQP: - sys->EncParamExt.iRCMode = RC_OFF_MODE; - sys->EncParamExt.sSpatialLayers[0].iDLayerQp = h264->QP; - break; + case H264_RATECONTROL_CQP: + sys->EncParamExt.iRCMode = RC_OFF_MODE; + sys->EncParamExt.sSpatialLayers[0].iDLayerQp = h264->QP; + break; } if (sys->EncParamExt.iMultipleThreadIdc > 1) @@ -961,7 +973,7 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstS } status = (*sys->pEncoder)->GetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, - &sys->EncParamExt); + &sys->EncParamExt); if (status < 0) { @@ -973,52 +985,52 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstS { switch (h264->RateControlMode) { - case H264_RATECONTROL_VBR: - if (sys->EncParamExt.iTargetBitrate != h264->BitRate) + case H264_RATECONTROL_VBR: + if (sys->EncParamExt.iTargetBitrate != h264->BitRate) + { + sys->EncParamExt.iTargetBitrate = h264->BitRate; + bitrate.iLayer = SPATIAL_LAYER_ALL; + bitrate.iBitrate = h264->BitRate; + + status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_BITRATE, + &bitrate); + + if (status < 0) { - sys->EncParamExt.iTargetBitrate = h264->BitRate; - bitrate.iLayer = SPATIAL_LAYER_ALL; - bitrate.iBitrate = h264->BitRate; - - status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_BITRATE, - &bitrate); - - if (status < 0) - { - WLog_ERR(TAG, "Failed to set encoder bitrate (status=%ld)", status); - return status; - } + WLog_ERR(TAG, "Failed to set encoder bitrate (status=%ld)", status); + return status; } - if (sys->EncParamExt.fMaxFrameRate != h264->FrameRate) + } + if (sys->EncParamExt.fMaxFrameRate != h264->FrameRate) + { + sys->EncParamExt.fMaxFrameRate = h264->FrameRate; + + status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_FRAME_RATE, + &sys->EncParamExt.fMaxFrameRate); + + if (status < 0) { - sys->EncParamExt.fMaxFrameRate = h264->FrameRate; - - status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_FRAME_RATE, - &sys->EncParamExt.fMaxFrameRate); - - if (status < 0) - { - WLog_ERR(TAG, "Failed to set encoder framerate (status=%ld)", status); - return status; - } + WLog_ERR(TAG, "Failed to set encoder framerate (status=%ld)", status); + return status; } - break; + } + break; - case H264_RATECONTROL_CQP: - if (sys->EncParamExt.sSpatialLayers[0].iDLayerQp != h264->QP) + case H264_RATECONTROL_CQP: + if (sys->EncParamExt.sSpatialLayers[0].iDLayerQp != h264->QP) + { + sys->EncParamExt.sSpatialLayers[0].iDLayerQp = h264->QP; + + status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, + &sys->EncParamExt); + + if (status < 0) { - sys->EncParamExt.sSpatialLayers[0].iDLayerQp = h264->QP; - - status = (*sys->pEncoder)->SetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, - &sys->EncParamExt); - - if (status < 0) - { - WLog_ERR(TAG, "Failed to set encoder parameters (status=%ld)", status); - return status; - } + WLog_ERR(TAG, "Failed to set encoder parameters (status=%ld)", status); + return status; } - break; + } + break; } } @@ -1027,12 +1039,12 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstS pic.iPicWidth = h264->width; pic.iPicHeight = h264->height; pic.iColorFormat = videoFormatI420; - pic.iStride[0] = h264->iStride[0]; - pic.iStride[1] = h264->iStride[1]; - pic.iStride[2] = h264->iStride[2]; - pic.pData[0] = h264->pYUVData[0]; - pic.pData[1] = h264->pYUVData[1]; - pic.pData[2] = h264->pYUVData[2]; + pic.iStride[0] = iStride[0]; + pic.iStride[1] = iStride[1]; + pic.iStride[2] = iStride[2]; + pic.pData[0] = pYUVData[0]; + pic.pData[1] = pYUVData[1]; + pic.pData[2] = pYUVData[2]; status = (*sys->pEncoder)->EncodeFrame(sys->pEncoder, &pic, &info); @@ -1058,108 +1070,138 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstS static void openh264_uninit(H264_CONTEXT* h264) { - H264_CONTEXT_OPENH264* sys = (H264_CONTEXT_OPENH264*) h264->pSystemData; + UINT32 x; + H264_CONTEXT_OPENH264* sysContexts = (H264_CONTEXT_OPENH264*) h264->pSystemData; - if (sys) + if (sysContexts) { - if (sys->pDecoder) + for (x=0; xnumSystemData; x++) { - (*sys->pDecoder)->Uninitialize(sys->pDecoder); - WelsDestroyDecoder(sys->pDecoder); - sys->pDecoder = NULL; - } + H264_CONTEXT_OPENH264* sys = &sysContexts[x]; - if (sys->pEncoder) - { - (*sys->pEncoder)->Uninitialize(sys->pEncoder); - WelsDestroySVCEncoder(sys->pEncoder); - sys->pEncoder = NULL; - } + if (sys->pDecoder) + { + (*sys->pDecoder)->Uninitialize(sys->pDecoder); + WelsDestroyDecoder(sys->pDecoder); + sys->pDecoder = NULL; + } - free(sys); + if (sys->pEncoder) + { + (*sys->pEncoder)->Uninitialize(sys->pEncoder); + WelsDestroySVCEncoder(sys->pEncoder); + sys->pEncoder = NULL; + } + } + free(h264->pSystemData); h264->pSystemData = NULL; } } static BOOL openh264_init(H264_CONTEXT* h264) { + UINT32 x; long status; SDecodingParam sDecParam; - H264_CONTEXT_OPENH264* sys; + H264_CONTEXT_OPENH264* sysContexts; static int traceLevel = WELS_LOG_DEBUG; static EVideoFormatType videoFormat = videoFormatI420; static WelsTraceCallback traceCallback = (WelsTraceCallback) openh264_trace_callback; - sys = (H264_CONTEXT_OPENH264*) calloc(1, sizeof(H264_CONTEXT_OPENH264)); + h264->numSystemData = 1; - if (!sys) - { + sysContexts = (H264_CONTEXT_OPENH264*) calloc(h264->numSystemData, + sizeof(H264_CONTEXT_OPENH264)); + + if (!sysContexts) goto EXCEPTION; - } - h264->pSystemData = (void*) sys; + h264->pSystemData = (void*) sysContexts; - if (h264->Compressor) + for (x=0; xnumSystemData; x++) { - WelsCreateSVCEncoder(&sys->pEncoder); + H264_CONTEXT_OPENH264* sys = &sysContexts[x]; - if (!sys->pEncoder) + if (h264->Compressor) { - WLog_ERR(TAG, "Failed to create OpenH264 encoder"); - goto EXCEPTION; - } - } - else - { - WelsCreateDecoder(&sys->pDecoder); + WelsCreateSVCEncoder(&sys->pEncoder); - if (!sys->pDecoder) - { - WLog_ERR(TAG, "Failed to create OpenH264 decoder"); - goto EXCEPTION; - } - - ZeroMemory(&sDecParam, sizeof(sDecParam)); - sDecParam.eOutputColorFormat = videoFormatI420; - sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY; - sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC; - - status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam); - - if (status != 0) - { - WLog_ERR(TAG, "Failed to initialize OpenH264 decoder (status=%ld)", status); - goto EXCEPTION; - } - - status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat); - - if (status != 0) - { - WLog_ERR(TAG, "Failed to set data format option on OpenH264 decoder (status=%ld)", status); - } - - if (g_openh264_trace_enabled) - { - status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel); - - if (status != 0) + if (!sys->pEncoder) { - WLog_ERR(TAG, "Failed to set trace level option on OpenH264 decoder (status=%ld)", status); + WLog_ERR(TAG, "Failed to create OpenH264 encoder"); + goto EXCEPTION; + } + } + else + { + WelsCreateDecoder(&sys->pDecoder); + + if (!sys->pDecoder) + { + WLog_ERR(TAG, "Failed to create OpenH264 decoder"); + goto EXCEPTION; } - status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, &traceCallback); + ZeroMemory(&sDecParam, sizeof(sDecParam)); + sDecParam.eOutputColorFormat = videoFormatI420; + sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY; + sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC; + + status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam); if (status != 0) { - WLog_ERR(TAG, "Failed to set trace callback option on OpenH264 decoder (status=%ld)", status); + WLog_ERR(TAG, "Failed to initialize OpenH264 decoder (status=%ld)", + status); + goto EXCEPTION; } - status = (*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &h264); + status = (*sys->pDecoder)->SetOption( + sys->pDecoder, DECODER_OPTION_DATAFORMAT, + &videoFormat); if (status != 0) { - WLog_ERR(TAG, "Failed to set trace callback context option on OpenH264 decoder (status=%ld)", status); + WLog_ERR(TAG, "Failed to set data format option on OpenH264 decoder (status=%ld)", + status); + goto EXCEPTION; + } + + if (g_openh264_trace_enabled) + { + status = (*sys->pDecoder)->SetOption( + sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, + &traceLevel); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace level option on OpenH264 decoder (status=%ld)", + status); + goto EXCEPTION; + } + + status = (*sys->pDecoder)->SetOption( + sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK, + &traceCallback); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace callback option on OpenH264 decoder (status=%ld)", + status); + goto EXCEPTION; + } + + status = (*sys->pDecoder)->SetOption( + sys->pDecoder, + DECODER_OPTION_TRACE_CALLBACK_CONTEXT, + &h264); + + if (status != 0) + { + WLog_ERR(TAG, "Failed to set trace callback context option on OpenH264 decoder (status=%ld)", + status); + goto EXCEPTION; + } } } } @@ -1201,12 +1243,14 @@ struct _H264_CONTEXT_LIBAVCODEC }; typedef struct _H264_CONTEXT_LIBAVCODEC H264_CONTEXT_LIBAVCODEC; -static int libavcodec_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) +static int libavcodec_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, UINT32 plane) { int status; int gotFrame = 0; AVPacket packet; H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*) h264->pSystemData; + BYTE** pYUVData = h264->pYUVData[plane]; + INT32* iStride = h264->iStride[plane]; av_init_packet(&packet); @@ -1223,21 +1267,21 @@ static int libavcodec_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcS #if 0 WLog_INFO(TAG, "libavcodec_decompress: frame decoded (status=%d, gotFrame=%d, width=%d, height=%d, Y=[%p,%d], U=[%p,%d], V=[%p,%d])", - status, gotFrame, sys->videoFrame->width, sys->videoFrame->height, - sys->videoFrame->data[0], sys->videoFrame->linesize[0], - sys->videoFrame->data[1], sys->videoFrame->linesize[1], - sys->videoFrame->data[2], sys->videoFrame->linesize[2]); + status, gotFrame, sys->videoFrame->width, sys->videoFrame->height, + sys->videoFrame->data[0], sys->videoFrame->linesize[0], + sys->videoFrame->data[1], sys->videoFrame->linesize[1], + sys->videoFrame->data[2], sys->videoFrame->linesize[2]); #endif if (gotFrame) { - h264->pYUVData[0] = sys->videoFrame->data[0]; - h264->pYUVData[1] = sys->videoFrame->data[1]; - h264->pYUVData[2] = sys->videoFrame->data[2]; + pYUVData[0] = sys->videoFrame->data[0]; + pYUVData[1] = sys->videoFrame->data[1]; + pYUVData[2] = sys->videoFrame->data[2]; - h264->iStride[0] = sys->videoFrame->linesize[0]; - h264->iStride[1] = sys->videoFrame->linesize[1]; - h264->iStride[2] = sys->videoFrame->linesize[2]; + iStride[0] = sys->videoFrame->linesize[0]; + iStride[1] = sys->videoFrame->linesize[1]; + iStride[2] = sys->videoFrame->linesize[2]; h264->width = sys->videoFrame->width; h264->height = sys->videoFrame->height; @@ -1351,34 +1395,111 @@ static H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = #endif -int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, - BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstWidth, - int nDstHeight, RDPGFX_RECT16* regionRects, int numRegionRects) +static BOOL check_rect(const H264_CONTEXT* h264, const RECTANGLE_16* rect, + UINT32 nDstWidth, UINT32 nDstHeight) { - int index; - int status; - int* iStride; - BYTE* pDstData; + /* Check, if the output rectangle is valid in decoded h264 frame. */ + if ((rect->right > h264->width) || (rect->left > h264->width)) + return FALSE; + if ((rect->top > h264->height) || (rect->bottom > h264->height)) + return FALSE; + + /* Check, if the output rectangle is valid in destination buffer. */ + if ((rect->right > nDstWidth) || (rect->left > nDstWidth)) + return FALSE; + if ((rect->bottom > nDstHeight) || (rect->top > nDstHeight)) + return FALSE; + + return TRUE; +} + +static BOOL avc_yuv_to_rgb(H264_CONTEXT* h264, const RECTANGLE_16* regionRects, + UINT32 numRegionRects, UINT32 nDstWidth, + UINT32 nDstHeight, UINT32 nDstStep, BYTE* pDstData, + DWORD DstFormat, BOOL use444) +{ + UINT32 x; BYTE* pDstPoint; prim_size_t roi; - BYTE** pYUVData; int width, height; - BYTE* pYUVPoint[3]; - RDPGFX_RECT16* rect; + const BYTE* pYUVPoint[3]; primitives_t* prims = primitives_get(); + for (x=0; xiYUV444Stride; + ppYUVData = h264->pYUV444Data; + } + else + { + iStride = h264->iStride[0]; + ppYUVData = h264->pYUVData[0]; + } + + if (!check_rect(h264, rect, nDstWidth, nDstHeight)) + return -1003; + + width = rect->right - rect->left; + height = rect->bottom - rect->top; + + pDstPoint = pDstData + rect->top * nDstStep + rect->left * 4; + + pYUVPoint[0] = ppYUVData[0] + rect->top * iStride[0] + rect->left; + pYUVPoint[1] = ppYUVData[1]; + pYUVPoint[2] = ppYUVData[2]; + if (use444) + { + pYUVPoint[1] += rect->top * iStride[1] + rect->left; + pYUVPoint[2] += rect->top * iStride[2] + rect->left; + } + else + { + pYUVPoint[1] += rect->top/2 * iStride[1] + rect->left/2; + pYUVPoint[2] += rect->top/2 * iStride[2] + rect->left/2; + } + + + roi.width = width; + roi.height = height; + + if (use444) + { + if (prims->YUV444ToRGB_8u_P3AC4R( + pYUVPoint, iStride, pDstPoint, + nDstStep, &roi) != PRIMITIVES_SUCCESS) + { + return FALSE; + } + } + else + { + if (prims->YUV420ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, + nDstStep, &roi) != PRIMITIVES_SUCCESS) + return FALSE; + } + } + + return TRUE; +} + +INT32 avc420_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, + BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, + UINT32 nDstWidth, UINT32 nDstHeight, + RECTANGLE_16* regionRects, UINT32 numRegionRects) +{ + int status; + if (!h264) return -1001; -#if 0 - WLog_INFO(TAG, "h264_decompress: pSrcData=%p, SrcSize=%u, pDstData=%p, nDstStep=%d, nDstHeight=%d, numRegionRects=%d", - pSrcData, SrcSize, *ppDstData, nDstStep, nDstHeight, numRegionRects); -#endif - - if (!(pDstData = *ppDstData)) - return -1002; - - status = h264->subsystem->Decompress(h264, pSrcData, SrcSize); + status = h264->subsystem->Decompress(h264, pSrcData, SrcSize, 0); if (status == 0) return 1; @@ -1386,93 +1507,324 @@ int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, if (status < 0) return status; - pYUVData = h264->pYUVData; - iStride = h264->iStride; - - for (index = 0; index < numRegionRects; index++) - { - rect = &(regionRects[index]); - - /* Check, if the output rectangle is valid in decoded h264 frame. */ - if ((rect->right > h264->width) || (rect->left > h264->width)) - return -1003; - if ((rect->top > h264->height) || (rect->bottom > h264->height)) - return -1004; - - /* Check, if the output rectangle is valid in destination buffer. */ - if ((rect->right > nDstWidth) || (rect->left > nDstWidth)) - return -1005; - if ((rect->bottom > nDstHeight) || (rect->top > nDstHeight)) - return -1006; - - width = rect->right - rect->left; - height = rect->bottom - rect->top; - - pDstPoint = pDstData + rect->top * nDstStep + rect->left * 4; - pYUVPoint[0] = pYUVData[0] + rect->top * iStride[0] + rect->left; - - pYUVPoint[1] = pYUVData[1] + rect->top/2 * iStride[1] + rect->left/2; - pYUVPoint[2] = pYUVData[2] + rect->top/2 * iStride[2] + rect->left/2; - -#if 0 - WLog_INFO(TAG, "regionRect: x: %d y: %d width: %d height: %d", - rect->left, rect->top, width, height); -#endif - - roi.width = width; - roi.height = height; - - prims->YUV420ToRGB_8u_P3AC4R((const BYTE**) pYUVPoint, iStride, pDstPoint, nDstStep, &roi); - } + if (!avc_yuv_to_rgb(h264, regionRects, numRegionRects, nDstWidth, + nDstHeight, nDstStep, pDstData, DstFormat, FALSE)) + return -1002; return 1; } -int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat, - int nSrcStep, int nSrcWidth, int nSrcHeight, BYTE** ppDstData, UINT32* pDstSize) +INT32 avc420_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat, + UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, + BYTE** ppDstData, UINT32* pDstSize) { int status = -1; prim_size_t roi; int nWidth, nHeight; primitives_t* prims = primitives_get(); + UINT32* iStride; + BYTE** pYUVData; if (!h264) return -1; + if (!h264->subsystem->Compress) return -1; + iStride = h264->iStride[0]; + pYUVData = h264->pYUVData[0]; + nWidth = (nSrcWidth + 1) & ~1; nHeight = (nSrcHeight + 1) & ~1; - if (!(h264->pYUVData[0] = (BYTE*) malloc(nWidth * nHeight))) + if (!(pYUVData[0] = (BYTE*) malloc(nWidth * nHeight))) return -1; - h264->iStride[0] = nWidth; + iStride[0] = nWidth; - if (!(h264->pYUVData[1] = (BYTE*) malloc(nWidth * nHeight / 4))) + if (!(pYUVData[1] = (BYTE*) malloc(nWidth * nHeight))) goto error_1; - h264->iStride[1] = nWidth / 2; + iStride[1] = nWidth / 2; - if (!(h264->pYUVData[2] = (BYTE*) malloc(nWidth * nHeight / 4))) + if (!(pYUVData[2] = (BYTE*) malloc(nWidth * nHeight))) goto error_2; - h264->iStride[2] = nWidth / 2; + iStride[2] = nWidth / 2; - h264->width = nWidth; - h264->height = nHeight; roi.width = nSrcWidth; roi.height = nSrcHeight; - prims->RGBToYUV420_8u_P3AC4R(pSrcData, nSrcStep, h264->pYUVData, h264->iStride, &roi); + prims->RGBToYUV420_8u_P3AC4R(pSrcData, nSrcStep, pYUVData, iStride, &roi); - status = h264->subsystem->Compress(h264, ppDstData, pDstSize); + status = h264->subsystem->Compress(h264, ppDstData, pDstSize, 0); - free(h264->pYUVData[2]); - h264->pYUVData[2] = NULL; + free(pYUVData[2]); + pYUVData[2] = NULL; error_2: - free(h264->pYUVData[1]); - h264->pYUVData[1] = NULL; + free(pYUVData[1]); + pYUVData[1] = NULL; error_1: - free(h264->pYUVData[0]); - h264->pYUVData[0] = NULL; + free(pYUVData[0]); + pYUVData[0] = NULL; + + return status; +} + +INT32 avc444_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat, + UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, + BYTE* op, BYTE** ppDstData, UINT32* pDstSize, + BYTE** ppAuxDstData, UINT32* pAuxDstSize) +{ + return -1; +} + +static BOOL avc444_process_rect(H264_CONTEXT* h264, + const RECTANGLE_16* rect, + UINT32 nDstWidth, UINT32 nDstHeight) +{ + const primitives_t* prims = primitives_get(); + prim_size_t roi; + UINT16 width, height; + const BYTE* pYUVMainPoint[3]; + const BYTE* pYUVAuxPoint[3]; + BYTE* pYUVDstPoint[3]; + + UINT32* piDstStride = h264->iYUV444Stride; + BYTE** ppYUVDstData = h264->pYUV444Data; + const UINT32* piAuxStride = h264->iStride[1]; + const UINT32* piMainStride = h264->iStride[0]; + BYTE** ppYUVAuxData = h264->pYUVData[1]; + BYTE** ppYUVMainData = h264->pYUVData[0]; + + if (!check_rect(h264, rect, nDstWidth, nDstHeight)) + return FALSE; + + width = rect->right - rect->left + 1; + height = rect->bottom - rect->top + 1; + + roi.width = width; + roi.height = height; + + pYUVMainPoint[0] = ppYUVMainData[0] + rect->top * piMainStride[0] + + rect->left; + pYUVMainPoint[1] = ppYUVMainData[1] + rect->top/2 * piMainStride[1] + + rect->left/2; + pYUVMainPoint[2] = ppYUVMainData[2] + rect->top/2 * piMainStride[2] + + rect->left/2; + pYUVDstPoint[0] = ppYUVDstData[0] + rect->top * piDstStride[0] + + rect->left; + pYUVDstPoint[1] = ppYUVDstData[1] + rect->top * piDstStride[1] + + rect->left; + pYUVDstPoint[2] = ppYUVDstData[2] + rect->top * piDstStride[2] + + rect->left; + + pYUVAuxPoint[0] = ppYUVAuxData[0] + rect->top * piAuxStride[0] + + rect->left; + pYUVAuxPoint[1] = ppYUVAuxData[1] + rect->top/2 * piAuxStride[1] + + rect->left/2; + pYUVAuxPoint[2] = ppYUVAuxData[2] + rect->top/2 * piAuxStride[2] + + rect->left/2; + pYUVDstPoint[0] = ppYUVDstData[0] + rect->top * piDstStride[0] + + rect->left; + pYUVDstPoint[1] = ppYUVDstData[1] + rect->top * piDstStride[1] + + rect->left; + pYUVDstPoint[2] = ppYUVDstData[2] + rect->top * piDstStride[2] + + rect->left; + + if (prims->YUV420CombineToYUV444(pYUVMainPoint, piMainStride, + NULL, NULL, + pYUVDstPoint, piDstStride, + &roi) != PRIMITIVES_SUCCESS) + return FALSE; + return TRUE; +} + +static void avc444_rectangle_max(RECTANGLE_16* dst, const RECTANGLE_16* add) +{ + if (dst->left > add->left) + dst->left = add->left; + if (dst->right < add->right) + dst->right = add->right; + if (dst->top > add->top) + dst->top = add->top; + if (dst->bottom < add->bottom) + dst->bottom = add->bottom; +} + +static BOOL avc444_combine_yuv(H264_CONTEXT* h264, + const RECTANGLE_16* mainRegionRects, + UINT32 numMainRegionRect, + const RECTANGLE_16* auxRegionRects, + UINT32 numAuxRegionRect, UINT32 nDstWidth, + DWORD nDstHeight, UINT32 nDstStep) +{ + UINT32 x; + RECTANGLE_16 rect; + const UINT32* piMainStride = h264->iStride[0]; + UINT32* piDstSize = h264->iYUV444Size; + UINT32* piDstStride = h264->iYUV444Stride; + BYTE** ppYUVDstData = h264->pYUV444Data; + UINT32 padDstHeight = nDstHeight + 16; /* Need alignment to 16x16 blocks */ + + if ((piMainStride[0] != piDstStride[0]) || + (piDstSize[0] != piMainStride[0] * padDstHeight)) + { + for (x=0; x<3; x++) + { + BYTE* ppYUVTmpData; + + piDstStride[x] = piMainStride[0]; + piDstSize[x] = piDstStride[x] * padDstHeight; + + ppYUVTmpData = realloc(ppYUVDstData[x], piDstSize[x]); + + if (!ppYUVTmpData) + goto fail; + + ppYUVDstData[x] = ppYUVTmpData; + + memset(ppYUVDstData[x], 0, piDstSize[x]); + } + } + + for (x=0; x<3; x++) + { + if (!ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0)) + { + WLog_ERR(TAG, "YUV buffer not initialized! check your decoder settings"); + goto fail; + } + } + + rect.right = 0; + rect.bottom = 0; + rect.left = 0xFFFF; + rect.top = 0xFFFF; + for (x=0; xsubsystem->Decompress(h264, pSrcData, SrcSize, 0); + if (status >= 0) + status = h264->subsystem->Decompress(h264, pAuxSrcData, AuxSrcSize, 1); + break; + case 2: /* Chroma420 in stream 1 */ + status = h264->subsystem->Decompress(h264, pSrcData, SrcSize, 1); + numChromaRects = numRegionRects; + chromaRects = regionRects; + break; + case 1: /* YUV420 in stream 1 */ + status = h264->subsystem->Decompress(h264, pSrcData, SrcSize, 0); + numYuvRects = numRegionRects; + yuvRects = regionRects; + break; + default: /* WTF? */ + break; + } + +#if defined(AVC444_FRAME_STAT) + switch(op) + { + case 0: + op1sum = avg(&op1, op1sum, SrcSize + AuxSrcSize); + break; + case 1: + op2sum = avg(&op2, op2sum, SrcSize); + break; + case 2: + op3sum = avg(&op3, op3sum, SrcSize); + break; + default: + break; + } + + WLog_INFO(TAG, "luma=%llu [avg=%lf] chroma=%llu [avg=%lf] combined=%llu [avg=%lf]", + op1, op1sum, op2, op2sum, op3, op3sum); +#endif + + if (status >= 0) + { + if (!avc444_combine_yuv(h264, yuvRects, numYuvRects, + chromaRects, numChromaRects, + nDstWidth, nDstHeight, nDstStep)) + status = -1002; + else + { + if (numYuvRects > 0) + { + if (!avc_yuv_to_rgb(h264, regionRects, numRegionRects, nDstWidth, + nDstHeight, nDstStep, pDstData, DstFormat, TRUE)) + status = -1003; + } + + if (numChromaRects > 0) + { + if (!avc_yuv_to_rgb(h264, auxRegionRects, numAuxRegionRect, + nDstWidth, nDstHeight, nDstStep, pDstData, + DstFormat, TRUE)) + status = -1004; + } + } + } return status; } @@ -1514,9 +1866,15 @@ BOOL h264_context_init(H264_CONTEXT* h264) return FALSE; } -int h264_context_reset(H264_CONTEXT* h264) +BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height) { - return 1; + if (!h264) + return FALSE; + + h264->width = width; + h264->height = height; + + return TRUE; } H264_CONTEXT* h264_context_new(BOOL Compressor) @@ -1554,6 +1912,9 @@ void h264_context_free(H264_CONTEXT* h264) { h264->subsystem->Uninit(h264); + free (h264->pYUV444Data[0]); + free (h264->pYUV444Data[1]); + free (h264->pYUV444Data[2]); free(h264); } } diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index 1da6349..ea269d8 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -413,9 +413,12 @@ int interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData return status; } -int bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) +BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) { - return 1; + if (!interleaved) + return FALSE; + + return TRUE; } BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index cff1768..9d78d78 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -266,9 +266,15 @@ static void nsc_profiler_print(NSC_CONTEXT* context) PROFILER_PRINT_FOOTER; } -int nsc_context_reset(NSC_CONTEXT* context) +BOOL nsc_context_reset(NSC_CONTEXT* context, UINT32 width, UINT32 height) { - return 1; + if (!context) + return FALSE; + + context->width = width; + context->height = height; + + return TRUE; } NSC_CONTEXT* nsc_context_new(void) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 37bd7bd..9b874b0 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -1160,9 +1160,12 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, return dstData; } -int freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context) +BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context) { - return 1; + if (!context) + return FALSE; + + return TRUE; } BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 2923660..2c067f9 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -1880,9 +1880,12 @@ int progressive_compress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT3 return 1; } -int progressive_context_reset(PROGRESSIVE_CONTEXT* progressive) +BOOL progressive_context_reset(PROGRESSIVE_CONTEXT* progressive) { - return 1; + if (!progressive) + return FALSE; + + return TRUE; } PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index e3a36ba..636b830 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -357,6 +357,9 @@ void rfx_context_free(RFX_CONTEXT* context) { RFX_CONTEXT_PRIV *priv; + if (!context) + return; + assert(NULL != context); assert(NULL != context->priv); assert(NULL != context->priv->TilePool); @@ -419,10 +422,17 @@ void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_f } } -void rfx_context_reset(RFX_CONTEXT* context) +BOOL rfx_context_reset(RFX_CONTEXT* context, UINT32 width, UINT32 height) { + if (!context) + return FALSE; + + context->width = width; + context->height = height; context->state = RFX_STATE_SEND_HEADERS; context->frameIdx = 0; + + return TRUE; } static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) diff --git a/libfreerdp/common/CMakeLists.txt b/libfreerdp/common/CMakeLists.txt index 05cadf4..1683f44 100644 --- a/libfreerdp/common/CMakeLists.txt +++ b/libfreerdp/common/CMakeLists.txt @@ -25,10 +25,9 @@ set(${MODULE_PREFIX}_SRCS freerdp_module_add(${${MODULE_PREFIX}_SRCS}) -freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR}) freerdp_include_directory_add(${ZLIB_INCLUDE_DIRS}) -freerdp_library_add(${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) +freerdp_library_add(${ZLIB_LIBRARIES}) if(BUILD_TESTING) add_subdirectory(test) diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c index 63970de..9f231be 100644 --- a/libfreerdp/common/assistance.c +++ b/libfreerdp/common/assistance.c @@ -26,11 +26,6 @@ #include #include -#include -#include -#include -#include - #include #include #include @@ -77,11 +72,12 @@ int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) { + int rc = -1; int i; BYTE* buffer; BYTE pad1[64]; BYTE pad2[64]; - SHA_CTX hashCtx; + WINPR_SHA1_CTX hashCtx; memset(pad1, 0x36, 64); memset(pad2, 0x5C, 64); @@ -95,21 +91,29 @@ int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* k buffer = (BYTE*) calloc(1, hashLength * 2); if (!buffer) - return -1; + goto fail; - SHA1_Init(&hashCtx); - SHA1_Update(&hashCtx, pad1, 64); - SHA1_Final((void*) buffer, &hashCtx); + if (!winpr_SHA1_Init(&hashCtx)) + goto fail; + if (!winpr_SHA1_Update(&hashCtx, pad1, 64)) + goto fail; + if (!winpr_SHA1_Final(&hashCtx, buffer, hashLength)) + goto fail; - SHA1_Init(&hashCtx); - SHA1_Update(&hashCtx, pad2, 64); - SHA1_Final((void*) &buffer[hashLength], &hashCtx); + if (!winpr_SHA1_Init(&hashCtx)) + goto fail; + if (!winpr_SHA1_Update(&hashCtx, pad2, 64)) + goto fail; + if (!winpr_SHA1_Final(&hashCtx, &buffer[hashLength], hashLength)) + goto fail; CopyMemory(key, buffer, keyLength); + rc = 1; +fail: free(buffer); - return 1; + return rc; } int freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list) @@ -543,15 +547,16 @@ char* freerdp_assistance_generate_pass_stub(DWORD flags) BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize) { + BOOL rc; int status; WINPR_MD5_CTX md5Ctx; int cbPasswordW; int cbPassStubW; int EncryptedSize; BYTE PasswordHash[WINPR_MD5_DIGEST_LENGTH]; - EVP_CIPHER_CTX rc4Ctx; + WINPR_CIPHER_CTX* rc4Ctx; BYTE* pbIn, *pbOut; - int cbOut, cbIn, cbFinal; + size_t cbOut, cbIn, cbFinal; WCHAR* PasswordW = NULL; WCHAR* PassStubW = NULL; @@ -617,21 +622,9 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas free(PasswordW); free(PassStubW); - EVP_CIPHER_CTX_init(&rc4Ctx); - - status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, NULL, NULL); - - if (!status) - { - WLog_ERR(TAG, "EVP_CipherInit_ex failure"); - free (pbOut); - free (pbIn); - return NULL; - } - - status = EVP_EncryptInit_ex(&rc4Ctx, NULL, NULL, PasswordHash, NULL); - - if (!status) + rc4Ctx = winpr_Cipher_New(WINPR_CIPHER_ARC4_128, WINPR_ENCRYPT, + PasswordHash, NULL); + if (!rc4Ctx) { WLog_ERR(TAG, "EVP_CipherInit_ex failure"); free (pbOut); @@ -642,26 +635,26 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas cbOut = cbFinal = 0; cbIn = EncryptedSize; - status = EVP_EncryptUpdate(&rc4Ctx, pbOut, &cbOut, pbIn, cbIn); + rc = winpr_Cipher_Update(rc4Ctx, pbIn, cbIn, pbOut, &cbOut); free(pbIn); - if (!status) + if (!rc) { WLog_ERR(TAG, "EVP_CipherUpdate failure"); + winpr_Cipher_Free(rc4Ctx); free (pbOut); return NULL; } - status = EVP_EncryptFinal_ex(&rc4Ctx, pbOut + cbOut, &cbFinal); - - if (!status) + if (!winpr_Cipher_Final(rc4Ctx, pbOut + cbOut, &cbFinal)) { WLog_ERR(TAG, "EVP_CipherFinal_ex failure"); + winpr_Cipher_Free(rc4Ctx); free (pbOut); return NULL; } - EVP_CIPHER_CTX_cleanup(&rc4Ctx); + winpr_Cipher_Free(rc4Ctx); *pEncryptedSize = EncryptedSize; @@ -671,17 +664,17 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) { int status; - SHA_CTX shaCtx; + WINPR_SHA1_CTX shaCtx; int cbPasswordW; int cchOutW = 0; WCHAR* pbOutW = NULL; - EVP_CIPHER_CTX aesDec; + WINPR_CIPHER_CTX* aesDec; WCHAR* PasswordW = NULL; BYTE* pbIn, *pbOut; - int cbOut, cbIn, cbFinal; - BYTE DerivedKey[AES_BLOCK_SIZE]; - BYTE InitializationVector[AES_BLOCK_SIZE]; - BYTE PasswordHash[SHA_DIGEST_LENGTH]; + size_t cbOut, cbIn, cbFinal; + BYTE DerivedKey[WINPR_AES_BLOCK_SIZE]; + BYTE InitializationVector[WINPR_AES_BLOCK_SIZE]; + BYTE PasswordHash[WINPR_SHA1_DIGEST_LENGTH]; status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); @@ -690,9 +683,13 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) cbPasswordW = (status - 1) * 2; - SHA1_Init(&shaCtx); - SHA1_Update(&shaCtx, PasswordW, cbPasswordW); - SHA1_Final((void*) PasswordHash, &shaCtx); + if (!winpr_SHA1_Init(&shaCtx) || + !winpr_SHA1_Update(&shaCtx, (BYTE*)PasswordW, cbPasswordW) || + !winpr_SHA1_Final(&shaCtx, PasswordHash, sizeof(PasswordHash))) + { + free (PasswordW); + return -1; + } status = freerdp_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey, sizeof(DerivedKey)); @@ -705,22 +702,9 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) ZeroMemory(InitializationVector, sizeof(InitializationVector)); - EVP_CIPHER_CTX_init(&aesDec); - - status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, NULL, NULL); - - if (status != 1) - { - free(PasswordW); - return -1; - } - - EVP_CIPHER_CTX_set_key_length(&aesDec, (128 / 8)); - EVP_CIPHER_CTX_set_padding(&aesDec, 0); - - status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, DerivedKey, InitializationVector); - - if (status != 1) + aesDec = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, + DerivedKey, InitializationVector); + if (!aesDec) { free(PasswordW); return -1; @@ -729,34 +713,33 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) cbOut = cbFinal = 0; cbIn = file->EncryptedLHTicketLength; pbIn = (BYTE*) file->EncryptedLHTicket; - pbOut = (BYTE*) calloc(1, cbIn + AES_BLOCK_SIZE + 2); + pbOut = (BYTE*) calloc(1, cbIn + WINPR_AES_BLOCK_SIZE + 2); if (!pbOut) { + winpr_Cipher_Free(aesDec); free(PasswordW); return -1; } - status = EVP_DecryptUpdate(&aesDec, pbOut, &cbOut, pbIn, cbIn); - - if (status != 1) + if (!winpr_Cipher_Update(aesDec, pbIn, cbIn, pbOut, &cbOut)) { + winpr_Cipher_Free(aesDec); free(PasswordW); free(pbOut); return -1; } - status = EVP_DecryptFinal_ex(&aesDec, pbOut + cbOut, &cbFinal); - - if (status != 1) + if (!winpr_Cipher_Final(aesDec, pbOut + cbOut, &cbFinal)) { WLog_ERR(TAG, "EVP_DecryptFinal_ex failure"); + winpr_Cipher_Free(aesDec); free(PasswordW); free(pbOut); return -1; } - EVP_CIPHER_CTX_cleanup(&aesDec); + winpr_Cipher_Free(aesDec); cbOut += cbFinal; cbFinal = 0; diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 114cfd2..d6e46e8 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -3392,10 +3392,10 @@ BOOL rdp_print_capability_sets(wStream* s, UINT16 numberCapabilities, BOOL recei break; } - if (s->pointer != em) + if (Stream_Pointer(s) != em) { WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", - type, (int)(s->pointer - bm), (int)(em - bm)); + type, (int)(Stream_Pointer(s) - bm), (int)(em - bm)); } Stream_SetPointer(s, em); @@ -3617,10 +3617,10 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa } } - if (s->pointer != em) + if (Stream_Pointer(s) != em) { WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", - type, (int)(s->pointer - bm), (int)(em - bm)); + type, (int)(Stream_Pointer(s) - bm), (int)(em - bm)); } Stream_SetPointer(s, em); diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index 604f192..d950510 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -200,8 +200,9 @@ UINT freerdp_drdynvc_on_channel_disconnected(DrdynvcClientContext* context, cons * go through and inform all the libraries that we are initialized * called only from main thread */ -int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) +UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) { + UINT error = CHANNEL_RC_OK; int index; CHANNEL_CLIENT_DATA* pChannelClientData; @@ -212,10 +213,14 @@ int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) pChannelClientData = &channels->clientDataList[index]; if (pChannelClientData->pChannelInitEventProc) - pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle, CHANNEL_EVENT_INITIALIZED, 0, 0); + pChannelClientData->pChannelInitEventProc( + pChannelClientData->pInitHandle, + CHANNEL_EVENT_INITIALIZED, 0, 0); + if (CHANNEL_RC_OK != getChannelError(instance->context)) + break; } - return 0; + return error; } /** @@ -223,10 +228,11 @@ int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) * this will tell the libraries that its ok to call MyVirtualChannelOpen * called only from main thread */ -int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) +UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) { + UINT error = CHANNEL_RC_OK; int index; - char* name; + char* name = NULL; char* hostname; int hostnameLength; CHANNEL_CLIENT_DATA* pChannelClientData; @@ -246,11 +252,17 @@ int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) pChannelOpenData = &channels->openDataList[index]; - pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle, CHANNEL_EVENT_CONNECTED, hostname, hostnameLength); + pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle, + CHANNEL_EVENT_CONNECTED, hostname, hostnameLength); + if (getChannelError(instance->context) != CHANNEL_RC_OK) + goto fail; name = (char*) malloc(9); if (!name) - return -1; + { + error = CHANNEL_RC_NO_MEMORY; + goto fail; + } CopyMemory(name, pChannelOpenData->name, 8); name[8] = '\0'; @@ -260,6 +272,7 @@ int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) PubSub_OnChannelConnected(instance->context->pubSub, instance->context, &e); free(name); + name = NULL; } } @@ -272,7 +285,9 @@ int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) channels->drdynvc->OnChannelDisconnected = freerdp_drdynvc_on_channel_disconnected; } - return 0; +fail: + free (name); + return error; } int freerdp_channels_data(freerdp* instance, UINT16 channelId, BYTE* data, int dataSize, int flags, int totalSize) @@ -437,8 +452,9 @@ BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance) return TRUE; } -int freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) +UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) { + UINT error = CHANNEL_RC_OK; int index; char* name; CHANNEL_OPEN_DATA* pChannelOpenData; @@ -458,7 +474,11 @@ int freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) pChannelClientData = &channels->clientDataList[index]; if (pChannelClientData->pChannelInitEventProc) - pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle, CHANNEL_EVENT_DISCONNECTED, 0, 0); + pChannelClientData->pChannelInitEventProc( + pChannelClientData->pInitHandle, + CHANNEL_EVENT_DISCONNECTED, 0, 0); + if (getChannelError(instance->context) != CHANNEL_RC_OK) + goto fail; pChannelOpenData = &channels->openDataList[index]; @@ -476,7 +496,8 @@ int freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) free(name); } - return 0; +fail: + return error; } void freerdp_channels_close(rdpChannels* channels, freerdp* instance) diff --git a/libfreerdp/core/codecs.c b/libfreerdp/core/codecs.c index 31cdbcd..af1d9b1 100644 --- a/libfreerdp/core/codecs.c +++ b/libfreerdp/core/codecs.c @@ -88,7 +88,7 @@ BOOL freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags) } } - if ((flags & FREERDP_CODEC_H264) && !codecs->h264) + if ((flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) && !codecs->h264) { if (!(codecs->h264 = h264_context_new(FALSE))) { @@ -100,13 +100,19 @@ BOOL freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags) return TRUE; } -BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) +BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags, + UINT32 width, UINT32 height) { + BOOL rc = TRUE; + + if (!freerdp_client_codecs_prepare(codecs, flags)) + return FALSE; + if (flags & FREERDP_CODEC_INTERLEAVED) { if (codecs->interleaved) { - bitmap_interleaved_context_reset(codecs->interleaved); + rc &= bitmap_interleaved_context_reset(codecs->interleaved); } } @@ -114,7 +120,7 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) { if (codecs->planar) { - freerdp_bitmap_planar_context_reset(codecs->planar); + rc &= freerdp_bitmap_planar_context_reset(codecs->planar); } } @@ -122,7 +128,7 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) { if (codecs->nsc) { - nsc_context_reset(codecs->nsc); + rc &= nsc_context_reset(codecs->nsc, width, height); } } @@ -130,7 +136,7 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) { if (codecs->rfx) { - rfx_context_reset(codecs->rfx); + rc &= rfx_context_reset(codecs->rfx, width, height); } } @@ -138,7 +144,7 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) { if (codecs->clear) { - clear_context_reset(codecs->clear); + rc &= clear_context_reset(codecs->clear); } } @@ -151,19 +157,19 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags) { if (codecs->progressive) { - progressive_context_reset(codecs->progressive); + rc &= progressive_context_reset(codecs->progressive); } } - if (flags & FREERDP_CODEC_H264) + if (flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) { if (codecs->h264) { - h264_context_reset(codecs->h264); + rc &= h264_context_reset(codecs->h264, width, height); } } - return TRUE; + return rc; } rdpCodecs* codecs_new(rdpContext* context) @@ -173,9 +179,7 @@ rdpCodecs* codecs_new(rdpContext* context) codecs = (rdpCodecs*) calloc(1, sizeof(rdpCodecs)); if (codecs) - { codecs->context = context; - } return codecs; } diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 99b2e59..f3a13f9 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -400,7 +400,7 @@ BOOL rdp_client_reconnect(rdpRdp* rdp) status = rdp_client_connect(rdp); if (status) - status = (freerdp_channels_post_connect(channels, context->instance) >= 0); + status = (freerdp_channels_post_connect(channels, context->instance) == CHANNEL_RC_OK); return status; } diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 79fa00d..411d0e9 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -45,7 +45,7 @@ * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises * server output packets from the first byte with the goal of improving * bandwidth. - * + * * Slow-Path packet always starts with TPKT header, which has the first * byte 0x03, while Fast-Path packet starts with 2 zero bits in the first * two less significant bits of the first byte. @@ -282,7 +282,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s if (!fastpath_recv_update_synchronize(fastpath, s)) WLog_ERR(TAG, "fastpath_recv_update_synchronize failure but we continue"); else - IFCALL(update->Synchronize, context); + IFCALL(update->Synchronize, context); break; case FASTPATH_UPDATETYPE_SURFCMDS: @@ -463,7 +463,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) Stream_SetPosition(fastpath->updateData, 0); - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); } else if (fragmentation == FASTPATH_FRAGMENT_NEXT) { @@ -491,7 +491,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) goto out_fail; } - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); } else if (fragmentation == FASTPATH_FRAGMENT_LAST) { @@ -519,7 +519,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) goto out_fail; } - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); Stream_SealLength(fastpath->updateData); Stream_SetPosition(fastpath->updateData, 0); @@ -546,7 +546,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) out_fail: if (cs != s) { - Stream_Release(cs); + Stream_Release(cs); } return -1; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 0f45f12..d2d4f0c 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -627,7 +627,11 @@ UINT32 freerdp_error_info(freerdp* instance) return instance->context->rdp->errorInfo; } -void freerdp_set_error_info(rdpRdp* rdp, UINT32 error) { +void freerdp_set_error_info(rdpRdp* rdp, UINT32 error) +{ + if (!rdp) + return; + rdp_set_error_info(rdp, error); } diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index f12423f..a3d5da3 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -407,7 +407,7 @@ wStream* http_request_write(HttpContext* context, HttpRequest* request) free(lines); Stream_Write(s, "\0", 1); /* append null terminator */ Stream_Rewind(s, 1); /* don't include null terminator in length */ - Stream_Length(s) = Stream_GetPosition(s); + Stream_SetLength(s, Stream_GetPosition(s)); return s; out_free: diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 3f3bab8..474ed85 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -206,7 +206,7 @@ BOOL rdg_send_tunnel_authorization(rdpRdg* rdg) if (!clientName) return FALSE; - packetSize = 12 + clientNameLen * 2 + sizeof(WCHAR); + packetSize = 12 + clientNameLen * sizeof(WCHAR); s = Stream_New(NULL, packetSize); if (!s) @@ -225,8 +225,6 @@ BOOL rdg_send_tunnel_authorization(rdpRdg* rdg) for (i = 0; i < clientNameLen; i++) Stream_Write_UINT16(s, clientName[i]); - Stream_Write_UINT16(s, 0); - Stream_SealLength(s); status = rdg_write_packet(rdg, s); diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 2d63fa7..e19e019 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -226,7 +226,7 @@ void gcc_write_conference_create_request(wStream* s, wStream* userData) per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */ /* userData::value (OCTET_STRING) */ - per_write_octet_string(s, userData->buffer, Stream_GetPosition(userData), 0); /* array of client data blocks */ + per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData), 0); /* array of client data blocks */ } BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs) @@ -320,7 +320,7 @@ void gcc_write_conference_create_response(wStream* s, wStream* userData) per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */ /* userData (OCTET_STRING) */ - per_write_octet_string(s, userData->buffer, Stream_GetPosition(userData), 0); /* array of server data blocks */ + per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData), 0); /* array of server data blocks */ } BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length) @@ -509,7 +509,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) break; } offset += blockLength; - Stream_Pointer(s) = holdp + blockLength; + Stream_SetPointer(s, holdp + blockLength); } return TRUE; @@ -590,7 +590,12 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */ /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, + &str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client host name"); + return FALSE; + } Stream_Seek(s, 32); free(settings->ClientHostname); settings->ClientHostname = str; @@ -644,10 +649,17 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) settings->EarlyCapabilityFlags = (UINT32) earlyCapabilityFlags; blockLength -= 2; + /* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */ + if (blockLength < 64) break; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, + &str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert the client product identifier"); + return FALSE; + } Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */ free(settings->ClientProductId); settings->ClientProductId = str; diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index e7b2d46..57d1894 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -199,6 +199,7 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) UINT16 cbClientDir; UINT16 cbAutoReconnectLen; rdpSettings* settings = rdp->settings; + WCHAR* wstr; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -206,6 +207,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ + /* cbClientAddress is the size in bytes of the character data in the clientAddress field. + * This size includes the length of the mandatory null terminator. + * The maximum allowed value is 80 bytes + */ + + if ((cbClientAddress % 2) || cbClientAddress < 2 || cbClientAddress > 80) + { + WLog_ERR(TAG, "protocol error: invalid cbClientAddress value: %u", cbClientAddress); + return FALSE; + } + settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); if (Stream_GetRemainingLength(s) < cbClientAddress) @@ -217,7 +229,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) settings->ClientAddress = NULL; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientAddress / 2, &settings->ClientAddress, 0, NULL, NULL); + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientAddress / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: clientAddress must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ClientAddress, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client address"); + return FALSE; + } Stream_Seek(s, cbClientAddress); if (Stream_GetRemainingLength(s) < 2) @@ -225,6 +247,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ + /* cbClientDir is the size in bytes of the character data in the clientDir field. + * This size includes the length of the mandatory null terminator. + * The maximum allowed value is 512 bytes + */ + + if ((cbClientDir % 2) || cbClientDir < 2 || cbClientDir > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbClientDir value: %u", cbClientDir); + return FALSE; + } + if (Stream_GetRemainingLength(s) < cbClientDir) return FALSE; @@ -234,7 +267,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) settings->ClientDir = NULL; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientDir / 2, &settings->ClientDir, 0, NULL, NULL); + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientDir / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: clientDir must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &settings->ClientDir, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client directory"); + return FALSE; + } Stream_Seek(s, cbClientDir); if (!rdp_read_client_time_zone(s, settings)) @@ -337,6 +380,7 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) UINT16 cbWorkingDir; UINT32 CompressionLevel; rdpSettings* settings = rdp->settings; + WCHAR* wstr; if (Stream_GetRemainingLength(s) < 18) return FALSE; @@ -357,6 +401,12 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) settings->CompressionLevel = CompressionLevel; } + if (!(flags & INFO_UNICODE)) + { + WLog_ERR(TAG, "Client without INFO_UNICODE flag: this is currently not supported"); + return FALSE; + } + Stream_Read_UINT16(s, cbDomain); /* cbDomain (2 bytes) */ Stream_Read_UINT16(s, cbUserName); /* cbUserName (2 bytes) */ Stream_Read_UINT16(s, cbPassword); /* cbPassword (2 bytes) */ @@ -368,7 +418,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbDomain > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbDomain / 2, &settings->Domain, 0, NULL, NULL); + /* cbDomain is the size in bytes of the character data in the Domain field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbDomain % 2) || cbDomain > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %u", cbDomain); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2]) + { + WLog_ERR(TAG, "protocol error: Domain must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Domain, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert Domain string"); + return FALSE; + } Stream_Seek(s, cbDomain); } Stream_Seek(s, 2); @@ -378,7 +447,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbUserName > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbUserName / 2, &settings->Username, 0, NULL, NULL); + /* cbUserName is the size in bytes of the character data in the UserName field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbUserName % 2) || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %u", cbUserName); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2]) + { + WLog_ERR(TAG, "protocol error: UserName must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Username, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert UserName string"); + return FALSE; + } Stream_Seek(s, cbUserName); } Stream_Seek(s, 2); @@ -388,7 +476,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbPassword > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbPassword / 2, &settings->Password, 0, NULL, NULL); + /* cbPassword is the size in bytes of the character data in the Password field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbPassword % 2) || cbPassword > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbPassword value: %u", cbPassword); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbPassword / 2]) + { + WLog_ERR(TAG, "protocol error: Password must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Password, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert Password string"); + return FALSE; + } Stream_Seek(s, cbPassword); } Stream_Seek(s, 2); @@ -398,7 +505,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbAlternateShell > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbAlternateShell / 2, &settings->AlternateShell, 0, NULL, NULL); + /* cbAlternateShell is the size in bytes of the character data in the AlternateShell field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbAlternateShell % 2) || cbAlternateShell > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbAlternateShell value: %u", cbAlternateShell); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbAlternateShell / 2]) + { + WLog_ERR(TAG, "protocol error: AlternateShell must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->AlternateShell, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert AlternateShell string"); + return FALSE; + } Stream_Seek(s, cbAlternateShell); } Stream_Seek(s, 2); @@ -408,7 +534,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbWorkingDir > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbWorkingDir / 2, &settings->ShellWorkingDirectory, 0, NULL, NULL); + /* cbWorkingDir is the size in bytes of the character data in the WorkingDir field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbWorkingDir % 2) || cbWorkingDir > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbWorkingDir value: %u", cbWorkingDir); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbWorkingDir / 2]) + { + WLog_ERR(TAG, "protocol error: WorkingDir must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ShellWorkingDirectory, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert AlternateShell string"); + return FALSE; + } Stream_Seek(s, cbWorkingDir); } Stream_Seek(s, 2); @@ -664,33 +809,76 @@ BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info *info) { UINT32 cbDomain; UINT32 cbUserName; + WCHAR* wstr; + + ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) return FALSE; Stream_Read_UINT32(s, cbDomain); /* cbDomain (4 bytes) */ - if (cbDomain > 52) - return FALSE; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbDomain, &info->domain, 0, NULL, FALSE); - if (!info->domain) - return FALSE; + + /* cbDomain is the size of the Unicode character data (including the mandatory + * null terminator) in bytes present in the fixed-length (52 bytes) Domain field + */ + if (cbDomain) + { + if ((cbDomain % 2) || cbDomain > 52) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %lu", cbDomain); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: Domain must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } + } Stream_Seek(s, 52); /* domain (52 bytes) */ + Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ - if (cbUserName > 512) - goto error_username; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbUserName, &info->username, 0, NULL, FALSE); - if (!info->username) - goto error_username; + + /* cbUserName is the size of the Unicode character data (including the mandatory + * null terminator) in bytes present in the fixed-length (512 bytes) UserName field. + */ + if (cbUserName) + { + if ((cbUserName % 2) || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %lu", cbUserName); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: UserName must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the UserName string"); + goto fail; + } + } Stream_Seek(s, 512); /* userName (512 bytes) */ Stream_Read_UINT32(s, info->sessionId); /* SessionId (4 bytes) */ - WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%04X", info->sessionId); + WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%04X UserName: [%s] Domain: [%s]", + info->sessionId, info->username, info->domain); return TRUE; -error_username: +fail: + free(info->username); + info->username = NULL; free(info->domain); info->domain = NULL; return FALSE; @@ -702,6 +890,9 @@ BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) UINT32 Size; UINT32 cbDomain; UINT32 cbUserName; + WCHAR* wstr; + + ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) return FALSE; @@ -713,26 +904,82 @@ BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ Stream_Seek(s, 558); /* pad (558 bytes) */ - if (Stream_GetRemainingLength(s) < (cbDomain + cbUserName)) - return FALSE; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbDomain, &info->domain, 0, NULL, FALSE); - if (!info->domain) - return FALSE; + /* cbDomain is the size in bytes of the Unicode character data in the Domain field. + * The size of the mandatory null terminator is include in this value. + * Note: Since MS-RDPBCGR 2.2.10.1.1.2 does not mention any size limits we assume + * that the maximum value is 52 bytes, according to the fixed size of the + * Domain field in the Logon Info Version 1 (TS_LOGON_INFO) structure. + */ + if (cbDomain) + { + if ((cbDomain % 2) || cbDomain > 52) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %lu", cbDomain); + goto fail; + } + if (Stream_GetRemainingLength(s) < (size_t) cbDomain) + { + WLog_ERR(TAG, "insufficient remaining stream length"); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: Domain field must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } + } Stream_Seek(s, cbDomain); /* domain */ - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbUserName, &info->username, 0, NULL, FALSE); - if (!info->username) + /* cbUserName is the size in bytes of the Unicode character data in the UserName field. + * The size of the mandatory null terminator is include in this value. + * Note: Since MS-RDPBCGR 2.2.10.1.1.2 does not mention any size limits we assume + * that the maximum value is 512 bytes, according to the fixed size of the + * Username field in the Logon Info Version 1 (TS_LOGON_INFO) structure. + */ + if (cbUserName) { - free(info->domain); - info->domain = NULL; - return FALSE; + if ((cbUserName % 2) || cbUserName < 2 || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %lu", cbUserName); + goto fail; + } + if (Stream_GetRemainingLength(s) < (size_t) cbUserName) + { + WLog_ERR(TAG, "insufficient remaining stream length"); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: UserName field must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } } Stream_Seek(s, cbUserName); /* userName */ - WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%04X", info->sessionId); + WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%04X UserName: [%s] Domain: [%s]", + info->sessionId, info->username, info->domain); return TRUE; + +fail: + free(info->username); + info->username = NULL; + free(info->domain); + info->domain = NULL; + return FALSE; } BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index 8d082b1..27c9126 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -571,7 +571,7 @@ BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData) goto out; /* userData (OCTET_STRING) */ - ber_write_octet_string(tmps, userData->buffer, Stream_GetPosition(userData)); + ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)); length = Stream_GetPosition(tmps); /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */ @@ -608,7 +608,7 @@ BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData) if (!mcs_write_domain_parameters(tmps, &(mcs->domainParameters))) goto out; /* userData (OCTET_STRING) */ - ber_write_octet_string(tmps, userData->buffer, Stream_GetPosition(userData)); + ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)); length = Stream_GetPosition(tmps); ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length); diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index adc0e0f..a56d1b5 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -188,19 +188,12 @@ static BOOL update_message_SurfaceCommand(rdpContext* context, wStream* s) { wStream* wParam; - wParam = (wStream*) malloc(sizeof(wStream)); + wParam = Stream_New(NULL, Stream_GetRemainingLength(s)); if (!wParam) return FALSE; - wParam->capacity = Stream_Capacity(s); - wParam->buffer = (BYTE*) malloc(wParam->capacity); - if (!wParam->buffer) - { - free(wParam); - return FALSE; - } - - wParam->pointer = wParam->buffer; + Stream_Copy(s, wParam, Stream_GetRemainingLength(s)); + Stream_SetPosition(wParam, 0); return MessageQueue_Post(context->update->queue, (void*) context, MakeMessageId(Update, SurfaceCommand), (void*) wParam, NULL); @@ -2058,7 +2051,7 @@ int update_message_free_pointer_update_class(wMessage* msg, int type) free(wParam); } break; - + case PointerUpdate_PointerNew: { POINTER_NEW_UPDATE* wParam = (POINTER_NEW_UPDATE*) msg->wParam; @@ -2091,11 +2084,11 @@ static int update_message_process_pointer_update_class(rdpUpdateProxy* proxy, wM break; case PointerUpdate_PointerColor: - IFCALL(proxy->PointerColor, msg->context, (POINTER_COLOR_UPDATE*) msg->wParam); + IFCALL(proxy->PointerColor, msg->context, (POINTER_COLOR_UPDATE*) msg->wParam); break; case PointerUpdate_PointerNew: - IFCALL(proxy->PointerNew, msg->context, (POINTER_NEW_UPDATE*) msg->wParam); + IFCALL(proxy->PointerNew, msg->context, (POINTER_NEW_UPDATE*) msg->wParam); break; case PointerUpdate_PointerCached: @@ -2220,7 +2213,7 @@ int update_message_queue_free_message(wMessage *message) int msgType; assert(message); - + if (message->id == WMQ_QUIT) return 0; diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 60aed90..49df89a 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1728,7 +1728,7 @@ BOOL update_read_fast_glyph_order(wStream* s, ORDER_INFO* orderInfo, FAST_GLYPH_ } } - Stream_Pointer(s) = phold + fastGlyph->cbData; + Stream_SetPointer(s, phold + fastGlyph->cbData); } return TRUE; @@ -3546,7 +3546,7 @@ BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flags) break; } - Stream_Pointer(s) = next; + Stream_SetPointer(s, next); return TRUE; } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 61a44dc..43115fa 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -67,7 +67,7 @@ const char* DATA_PDU_TYPE_STRINGS[80] = "ARC Status", /* 0x32 */ "?", "?", "?", /* 0x33 - 0x35 */ "Status Info", /* 0x36 */ - "Monitor Layout" /* 0x37 */ + "Monitor Layout", /* 0x37 */ "FrameAcknowledge", "?", "?", /* 0x38 - 0x40 */ "?", "?", "?", "?", "?", "?" /* 0x41 - 0x46 */ }; @@ -248,15 +248,19 @@ BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo) if (rdp->errorInfo != ERRINFO_SUCCESS) { - ErrorInfoEventArgs e; - rdpContext* context = rdp->instance->context; - - rdp->context->LastError = MAKE_FREERDP_ERROR(ERRINFO, errorInfo); + rdpContext* context = rdp->context; rdp_print_errinfo(rdp->errorInfo); - - EventArgsInit(&e, "freerdp"); - e.code = rdp->errorInfo; - PubSub_OnErrorInfo(context->pubSub, context, &e); + if (context) + { + context->LastError = MAKE_FREERDP_ERROR(ERRINFO, errorInfo); + if (context->pubSub) + { + ErrorInfoEventArgs e; + EventArgsInit(&e, "freerdp"); + e.code = rdp->errorInfo; + PubSub_OnErrorInfo(context->pubSub, context, &e); + } + } } else { @@ -1056,7 +1060,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) return FALSE; /* TODO */ } - Stream_Length(s) -= pad; + Stream_SetLength(s, Stream_Length(s) - pad); return TRUE; } diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 6d31257..0922902 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -30,7 +30,7 @@ #define TAG FREERDP_TAG("core.redirection") -void rdp_print_redirection_flags(UINT32 flags) +static void rdp_print_redirection_flags(UINT32 flags) { WLog_DBG(TAG, "redirectionFlags = {"); @@ -76,9 +76,10 @@ void rdp_print_redirection_flags(UINT32 flags) WLog_DBG(TAG, "}"); } -BOOL rdp_redirection_read_string(wStream* s, char** str) +static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t maxLength) { UINT32 length; + WCHAR* wstr = NULL; if (Stream_GetRemainingLength(s) < 4) { @@ -88,13 +89,31 @@ BOOL rdp_redirection_read_string(wStream* s, char** str) Stream_Read_UINT32(s, length); - if (Stream_GetRemainingLength(s) < length) + if ((length % 2) || length < 2 || length > maxLength) { - WLog_ERR(TAG, "rdp_redirection_read_string failure: incorrect length %d", length); + WLog_ERR(TAG, "rdp_redirection_read_string failure: invalid unicode string length: %lu", length); return FALSE; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), length / 2, str, 0, NULL, NULL); + if (Stream_GetRemainingLength(s) < length) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: insufficient stream length (%lu bytes required)", length); + return FALSE; + } + + wstr = (WCHAR*) Stream_Pointer(s); + + if (wstr[length / 2 - 1]) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: unterminated unicode string"); + return FALSE; + } + + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed"); + return FALSE; + } Stream_Seek(s, length); return TRUE; } @@ -173,7 +192,10 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) /* Password may be a cookie without a null terminator */ free(settings->RedirectionPassword); settings->RedirectionPasswordLength = redirection->PasswordLength; - settings->RedirectionPassword = (BYTE*) malloc(settings->RedirectionPasswordLength); + /* For security reasons we'll allocate an additional zero WCHAR at the + * end of the buffer that is not included in RedirectionPasswordLength + */ + settings->RedirectionPassword = (BYTE*) calloc(1, settings->RedirectionPasswordLength + sizeof(WCHAR)); if (!settings->RedirectionPassword) return -1; CopyMemory(settings->RedirectionPassword, redirection->Password, settings->RedirectionPasswordLength); @@ -219,7 +241,7 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) return 0; } -BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) +static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { UINT16 flags; UINT16 length; @@ -238,14 +260,33 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) rdp_print_redirection_flags(redirection->flags); + /* Although MS-RDPBCGR does not mention any length constraints limits for the + * variable length null-terminated unicode strings in the RDP_SERVER_REDIRECTION_PACKET + * structure we will use the following limits in bytes including the null terminator: + * + * TargetNetAddress: 80 bytes + * UserName: 512 bytes + * Domain: 52 bytes + * Password(Cookie): 512 bytes + * TargetFQDN: 512 bytes + * TargetNetBiosName: 32 bytes + */ + if (redirection->flags & LB_TARGET_NET_ADDRESS) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddress))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80)) return -1; } if (redirection->flags & LB_LOAD_BALANCE_INFO) { + /* See [MSFT-SDLBTS] (a.k.a. TS_Session_Directory.doc) + * load balance info example data: + * 0000 43 6f 6f 6b 69 65 3a 20 6d 73 74 73 3d 32 31 33 Cookie: msts=213 + * 0010 34 30 32 36 34 33 32 2e 31 35 36 32 39 2e 30 30 4026432.15629.00 + * 0020 30 30 0d 0a 00.. + */ + if (Stream_GetRemainingLength(s) < 4) return -1; @@ -265,7 +306,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_USERNAME) { - if (!rdp_redirection_read_string(s, &(redirection->Username))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512)) return -1; WLog_DBG(TAG, "Username: %s", redirection->Username); @@ -273,7 +314,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_DOMAIN) { - if (!rdp_redirection_read_string(s, &(redirection->Domain))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52)) return FALSE; WLog_DBG(TAG, "Domain: %s", redirection->Domain); @@ -281,12 +322,45 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_PASSWORD) { - /* Note: length (hopefully) includes double zero termination */ + /* Note: Password is a variable-length array of bytes containing the + * password used by the user in Unicode format, including a null-terminator + * or (!) or a cookie value that MUST be passed to the target server on + * successful connection. + * Since the format of the password cookie (probably some salted hash) is + * currently unknown we'll treat it as opaque data. All cookies seen so far + * are 120 bytes including \0\0 termination. + * Here is an observed example of a redirection password cookie: + * + * 0000 02 00 00 80 44 53 48 4c 60 ab 69 2f 07 d6 9e 2d ....DSHL`.i/...- + * 0010 f0 3a 97 3b a9 c5 ec 7e 66 bd b3 84 6c b1 ef b9 .:.;...~f...l... + * 0020 b6 82 4e cc 3a df 64 b7 7b 25 04 54 c2 58 98 f8 ..N.:.d.{%.T.X.. + * 0030 97 87 d4 93 c7 c1 e1 5b c2 85 f8 22 49 1f 81 88 .......[..."I... + * 0040 43 44 83 f6 9a 72 40 24 dc 4d 43 cb d9 92 3c 8f CD...r@$.MC...<. + * 0050 3a 37 5c 77 13 a0 72 3c 72 08 64 2a 29 fb dc eb :7\w..rPasswordLength); - redirection->Password = (BYTE*) malloc(redirection->PasswordLength); + + /* [MS-RDPBCGR] specifies 512 bytes as the upper limit for the password length + * including the null terminatior(s). This should also be enough for the unknown + * password cookie format (see previous comment). + */ + + if (Stream_GetRemainingLength(s) < redirection->PasswordLength) + return -1; + + if (redirection->PasswordLength > 512) + return -1; + + redirection->Password = (BYTE*) calloc(1, redirection->PasswordLength + sizeof(WCHAR)); if (!redirection->Password) return -1; Stream_Read(s, redirection->Password, redirection->PasswordLength); @@ -297,7 +371,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_FQDN) { - if (!rdp_redirection_read_string(s, &(redirection->TargetFQDN))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512)) return -1; WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN); @@ -305,7 +379,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_NETBIOS_NAME) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetBiosName))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32)) return -1; WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName); @@ -352,7 +426,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) for (i = 0; i < (int) count; i++) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddresses[i]))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80)) return FALSE; WLog_DBG(TAG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]); @@ -371,13 +445,6 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) return 1; } -int rdp_recv_redirection_packet(rdpRdp* rdp, wStream* s) -{ - int status = 0; - status = rdp_recv_server_redirection_pdu(rdp, s); - return status; -} - int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) { int status = 0; diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 1002d17..28ed134 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -493,40 +493,46 @@ rdpSettings* freerdp_settings_new(DWORD flags) if(!settings->DynamicChannelArray) goto out_fail; - settings->HomePath = GetKnownPath(KNOWN_PATH_HOME); - if (!settings->HomePath) - goto out_fail; - /* For default FreeRDP continue using same config directory - * as in old releases. - * Custom builds use / as config folder. */ - if (_stricmp(FREERDP_VENDOR_STRING, FREERDP_PRODUCT_STRING)) + if (!settings->ServerMode) { - base = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, - FREERDP_VENDOR_STRING); - if (base) + /* these values are used only by the client part */ + + settings->HomePath = GetKnownPath(KNOWN_PATH_HOME); + if (!settings->HomePath) + goto out_fail; + + /* For default FreeRDP continue using same config directory + * as in old releases. + * Custom builds use / as config folder. */ + if (_stricmp(FREERDP_VENDOR_STRING, FREERDP_PRODUCT_STRING)) { - settings->ConfigPath = GetCombinedPath( - base, - FREERDP_PRODUCT_STRING); + base = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, + FREERDP_VENDOR_STRING); + if (base) + { + settings->ConfigPath = GetCombinedPath( + base, + FREERDP_PRODUCT_STRING); + } + free (base); + } else { + int i; + char product[sizeof(FREERDP_PRODUCT_STRING)]; + + memset(product, 0, sizeof(product)); + for (i=0; iConfigPath = GetKnownSubPath( + KNOWN_PATH_XDG_CONFIG_HOME, + product); } - free (base); - } else { - int i; - char product[sizeof(FREERDP_PRODUCT_STRING)]; - memset(product, 0, sizeof(product)); - for (i=0; iConfigPath = GetKnownSubPath( - KNOWN_PATH_XDG_CONFIG_HOME, - product); + if (!settings->ConfigPath) + goto out_fail; } - if (!settings->ConfigPath) - goto out_fail; - settings_load_hkey_local_machine(settings); settings->SettingsModified = (BYTE*) calloc(1, sizeof(rdpSettings) / 8 ); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 6f928cc..147913f 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -733,8 +733,7 @@ out_cleanup: transport->layer = TRANSPORT_LAYER_CLOSED; } - if (s->pool) - Stream_Release(s); + Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); return status; diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c index e31fe45..e197b76 100644 --- a/libfreerdp/core/window.c +++ b/libfreerdp/core/window.c @@ -371,6 +371,7 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -382,20 +383,20 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I if (!update_read_window_icon_order(s, orderInfo, &window->window_icon)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "WindowIcon"); - IFCALL(window->WindowIcon, context, orderInfo, &window->window_icon); + IFCALLRET(window->WindowIcon, result, context, orderInfo, &window->window_icon); } else if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) { if (!update_read_window_cached_icon_order(s, orderInfo, &window->window_cached_icon)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "WindowCachedIcon"); - IFCALL(window->WindowCachedIcon, context, orderInfo, &window->window_cached_icon); + IFCALLRET(window->WindowCachedIcon, result, context, orderInfo, &window->window_cached_icon); } else if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_DELETED) { update_read_window_delete_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "WindowDelete"); - IFCALL(window->WindowDelete, context, orderInfo); + IFCALLRET(window->WindowDelete, result, context, orderInfo); } else { @@ -405,16 +406,16 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) { WLog_Print(update->log, WLOG_DEBUG, "WindowCreate"); - IFCALL(window->WindowCreate, context, orderInfo, &window->window_state); + IFCALLRET(window->WindowCreate, result, context, orderInfo, &window->window_state); } else { WLog_Print(update->log, WLOG_DEBUG, "WindowUpdate"); - IFCALL(window->WindowUpdate, context, orderInfo, &window->window_state); + IFCALLRET(window->WindowUpdate, result, context, orderInfo, &window->window_state); } } - return TRUE; + return result; } BOOL update_read_notification_icon_state_order(wStream* s, WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notify_icon_state) @@ -470,6 +471,7 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (Stream_GetRemainingLength(s) < 8) return FALSE; @@ -481,7 +483,7 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN { update_read_notification_icon_delete_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "NotifyIconDelete"); - IFCALL(window->NotifyIconDelete, context, orderInfo); + IFCALLRET(window->NotifyIconDelete, result, context, orderInfo); } else { @@ -491,16 +493,16 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) { WLog_Print(update->log, WLOG_DEBUG, "NotifyIconCreate"); - IFCALL(window->NotifyIconCreate, context, orderInfo, &window->notify_icon_state); + IFCALLRET(window->NotifyIconCreate, result, context, orderInfo, &window->notify_icon_state); } else { WLog_Print(update->log, WLOG_DEBUG, "NotifyIconUpdate"); - IFCALL(window->NotifyIconUpdate, context, orderInfo, &window->notify_icon_state); + IFCALLRET(window->NotifyIconUpdate, result, context, orderInfo, &window->notify_icon_state); } } - return TRUE; + return result; } BOOL update_read_desktop_actively_monitored_order(wStream* s, WINDOW_ORDER_INFO* orderInfo, MONITORED_DESKTOP_ORDER* monitored_desktop) @@ -560,22 +562,23 @@ BOOL update_recv_desktop_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_ { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_NONE) { update_read_desktop_non_monitored_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "NonMonitoredDesktop"); - IFCALL(window->NonMonitoredDesktop, context, orderInfo); + IFCALLRET(window->NonMonitoredDesktop, result, context, orderInfo); } else { if (!update_read_desktop_actively_monitored_order(s, orderInfo, &window->monitored_desktop)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "ActivelyMonitoredDesktop"); - IFCALL(window->MonitoredDesktop, context, orderInfo, &window->monitored_desktop); + IFCALLRET(window->MonitoredDesktop, result, context, orderInfo, &window->monitored_desktop); } - return TRUE; + return result; } BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s) diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c index 5d8ba59..df53ca0 100644 --- a/libfreerdp/gdi/gfx.c +++ b/libfreerdp/gdi/gfx.c @@ -65,14 +65,21 @@ UINT gdi_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* if (!surface || !surface->outputMapped) continue; - freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL); + if (!freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL, + surface->width, surface->height)) + { + free (pSurfaceIds); + return ERROR_INTERNAL_ERROR; + } region16_clear(&surface->invalidRegion); } free(pSurfaceIds); - freerdp_client_codecs_reset(gdi->codecs, FREERDP_CODEC_ALL); + if (!freerdp_client_codecs_reset(gdi->codecs, FREERDP_CODEC_ALL, + gdi->width, gdi->height)) + return ERROR_INTERNAL_ERROR; gdi->graphicsReset = TRUE; @@ -454,39 +461,38 @@ UINT gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX * * @return 0 on success, otherwise a Win32 error code */ -UINT gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +static UINT gdi_SurfaceCommand_AVC420(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status; UINT32 i; - BYTE* DstData = NULL; gdiGfxSurface* surface; RDPGFX_H264_METABLOCK* meta; - RDPGFX_H264_BITMAP_STREAM* bs; + RDPGFX_AVC420_BITMAP_STREAM* bs; surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return ERROR_INTERNAL_ERROR; - if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_H264)) + if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC420)) return ERROR_INTERNAL_ERROR; - bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; + bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra; if (!bs) return ERROR_INTERNAL_ERROR; meta = &(bs->meta); - DstData = surface->data; - - status = h264_decompress(surface->codecs->h264, bs->data, bs->length, &DstData, - PIXEL_FORMAT_XRGB32, surface->scanline, surface->width, surface->height, - meta->regionRects, meta->numRegionRects); + status = avc420_decompress(surface->codecs->h264, bs->data, bs->length, + surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, surface->width, + surface->height, meta->regionRects, + meta->numRegionRects); if (status < 0) { - WLog_WARN(TAG, "h264_decompress failure: %d, ignoring update.", status); + WLog_WARN(TAG, "avc420_decompress failure: %d, ignoring update.", status); return CHANNEL_RC_OK; } @@ -501,6 +507,77 @@ UINT gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_S return CHANNEL_RC_OK; } +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + UINT32 i; + gdiGfxSurface* surface; + RDPGFX_AVC444_BITMAP_STREAM* bs; + RDPGFX_AVC420_BITMAP_STREAM* avc1; + RDPGFX_H264_METABLOCK* meta1; + RDPGFX_AVC420_BITMAP_STREAM* avc2; + RDPGFX_H264_METABLOCK* meta2; + RECTANGLE_16* regionRects = NULL; + + surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return ERROR_INTERNAL_ERROR; + + if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC444)) + return ERROR_INTERNAL_ERROR; + + bs = (RDPGFX_AVC444_BITMAP_STREAM*) cmd->extra; + + if (!bs) + return ERROR_INTERNAL_ERROR; + + avc1 = &bs->bitstream[0]; + avc2 = &bs->bitstream[1]; + meta1 = &avc1->meta; + meta2 = &avc2->meta; + status = avc444_decompress(surface->codecs->h264, bs->LC, + meta1->regionRects, meta1->numRegionRects, + avc1->data, avc1->length, + meta2->regionRects, meta2->numRegionRects, + avc2->data, avc2->length, + surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, surface->width, + surface->height); + + if (status < 0) + { + WLog_WARN(TAG, "avc444_decompress failure: %d, ignoring update.", status); + return CHANNEL_RC_OK; + } + + for (i = 0; i < meta1->numRegionRects; i++) + { + region16_union_rect(&(surface->invalidRegion), + &(surface->invalidRegion), + &(meta1->regionRects[i])); + } + + for (i = 0; i < meta2->numRegionRects; i++) + { + region16_union_rect(&(surface->invalidRegion), + &(surface->invalidRegion), + &(meta2->regionRects[i])); + } + + if (!gdi->inGfxFrame) + gdi_UpdateSurfaces(gdi); + + free(regionRects); + + return CHANNEL_RC_OK; +} + /** * Function description * @@ -670,8 +747,12 @@ UINT gdi_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cm status = gdi_SurfaceCommand_Planar(gdi, context, cmd); break; - case RDPGFX_CODECID_H264: - status = gdi_SurfaceCommand_H264(gdi, context, cmd); + case RDPGFX_CODECID_AVC420: + status = gdi_SurfaceCommand_AVC420(gdi, context, cmd); + break; + + case RDPGFX_CODECID_AVC444: + status = gdi_SurfaceCommand_AVC444(gdi, context, cmd); break; case RDPGFX_CODECID_ALPHA: @@ -683,6 +764,11 @@ UINT gdi_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cm break; case RDPGFX_CODECID_CAPROGRESSIVE_V2: + WLog_WARN(TAG, "SurfaceCommand %08X not implemented", cmd->codecId); + break; + + default: + WLog_WARN(TAG, "Invalid SurfaceCommand %08X", cmd->codecId); break; } @@ -722,6 +808,13 @@ UINT gdi_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* return CHANNEL_RC_NO_MEMORY; } + if (!freerdp_client_codecs_reset(surface->codecs, FREERDP_CODEC_ALL, + createSurface->width, createSurface->height)) + { + free (surface); + return ERROR_INTERNAL_ERROR; + } + surface->surfaceId = createSurface->surfaceId; surface->width = (UINT32) createSurface->width; surface->height = (UINT32) createSurface->height; @@ -788,7 +881,7 @@ UINT gdi_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFil UINT32 color; BYTE a, r, g, b; int nWidth, nHeight; - RDPGFX_RECT16* rect; + RECTANGLE_16* rect; gdiGfxSurface* surface; RECTANGLE_16 invalidRect; rdpGdi* gdi = (rdpGdi*) context->custom; @@ -842,7 +935,7 @@ UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFAC UINT16 index; BOOL sameSurface; int nWidth, nHeight; - RDPGFX_RECT16* rectSrc; + RECTANGLE_16* rectSrc; RDPGFX_POINT16* destPt; RECTANGLE_16 invalidRect; gdiGfxSurface* surfaceSrc; @@ -903,7 +996,7 @@ UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFAC */ UINT gdi_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache) { - RDPGFX_RECT16* rect; + RECTANGLE_16* rect; gdiGfxSurface* surface; gdiGfxCacheEntry* cacheEntry; rdpGdi* gdi = (rdpGdi*) context->custom; diff --git a/libfreerdp/primitives/prim_YUV.c b/libfreerdp/primitives/prim_YUV.c index c8cddd5..9e8b293 100644 --- a/libfreerdp/primitives/prim_YUV.c +++ b/libfreerdp/primitives/prim_YUV.c @@ -26,43 +26,368 @@ #include "prim_YUV.h" +static INLINE BYTE CLIP(INT32 X) +{ + if (X > 255L) + return 255L; + if (X < 0L) + return 0L; + return X; +} + +/** + * @brief general_YUV420CombineToYUV444 + * + * @param pMainSrc Pointer to luma YUV420 data + * @param srcMainStep Step width in luma YUV420 data + * @param pAuxSrc Pointer to chroma YUV420 data + * @param srcAuxStep Step width in chroma YUV420 data + * @param pDst Pointer to YUV444 data + * @param dstStep Step width in YUV444 data + * @param roi Region of source to combine in destination. + * + * @return PRIMITIVES_SUCCESS on success, an error code otherwise. + */ +static pstatus_t general_YUV420CombineToYUV444( + const BYTE* pMainSrc[3], const UINT32 srcMainStep[3], + const BYTE* pAuxSrc[3], const UINT32 srcAuxStep[3], + BYTE* pDst[3], const UINT32 dstStep[3], + const prim_size_t* roi) +{ + const UINT32 mod = 16; + UINT32 uY = 0; + UINT32 vY = 0; + UINT32 x, y; + UINT32 nWidth, nHeight; + UINT32 halfWidth, halfHeight; + const UINT32 oddY = 1; + const UINT32 evenY = 0; + const UINT32 oddX = 1; + const UINT32 evenX = 0; + + /* The auxilary frame is aligned to multiples of 16x16. + * We need the padded height for B4 and B5 conversion. */ + const UINT32 padHeigth = roi->height + 16 - roi->height % 16; + + nWidth = roi->width; + nHeight = roi->height; + halfWidth = (nWidth ) / 2; + halfHeight = (nHeight) / 2; + + if (pMainSrc) + { + /* Y data is already here... */ + /* B1 */ + for (y=0; y= nHeight) + continue; + pX = pDst[1] + dstStep[1] * pos; + } + else + { + const UINT32 pos = (2 * vY++ + oddY); + if (pos >= nHeight) + continue; + pX = pDst[2] + dstStep[2] * pos; + } + + memcpy(pX, Ya, nWidth); + } + + /* B6 and B7 */ + for (y=0; y nHeight) + continue; + + for (x=0; x nWidth) + continue; + + u2020 = up - pU[val2x1] - pU1[val2x] - pU1[val2x1]; + v2020 = vp - pV[val2x1] - pV1[val2x] - pV1[val2x1]; + + pU[val2x] = CLIP(u2020); + pV[val2x] = CLIP(v2020); + } + } + + return PRIMITIVES_SUCCESS; +} + +static pstatus_t general_YUV444SplitToYUV420( + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pMainDst[3], const UINT32 dstMainStep[3], + BYTE* pAuxDst[3], const UINT32 dstAuxStep[3], + const prim_size_t* roi) +{ + UINT32 x, y, uY = 0, vY = 0; + UINT32 halfWidth, halfHeight; + /* The auxilary frame is aligned to multiples of 16x16. + * We need the padded height for B4 and B5 conversion. */ + const UINT32 padHeigth = roi->height + 16 - roi->height % 16; + + halfWidth = (roi->width + 1) / 2; + halfHeight = (roi->height + 1) / 2; + + /* B1 */ + for (y=0; yheight; y++) + { + const BYTE* pSrcY = pSrc[0] + y * srcStep[0]; + BYTE* pY = pMainDst[0] + y * dstMainStep[0]; + memcpy(pY, pSrcY, roi->width); + } + + /* B2 and B3 */ + for (y=0; y= roi->height) + continue; + memcpy(pY, pSrcU, roi->width); + } + else + { + const UINT32 pos = (2 * vY++ + 1); + const BYTE* pSrcV = pSrc[2] + pos * srcStep[2]; + if (pos >= roi->height) + continue; + memcpy(pY, pSrcV, roi->width); + } + } + + /* B6 and B7 */ + for (y=0; y> 8 + * | B | ( | 256 475 0 | | V - 128 | ) + */ +static INLINE INT32 C(INT32 Y) +{ + return (Y) - 0L; +} + +static INLINE INT32 D(INT32 U) +{ + return (U) - 128L; +} + +static INLINE INT32 E(INT32 V) +{ + return (V) - 128L; +} + +static INLINE BYTE YUV2R(INT32 Y, INT32 U, INT32 V) +{ + const INT32 r = ( 256L * C(Y) + 0L * D(U) + 403L * E(V)); + const INT32 r8 = r >> 8L; + return CLIP(r8); +} + +static INLINE BYTE YUV2G(INT32 Y, INT32 U, INT32 V) +{ + const INT32 g = ( 256L * C(Y) - 48L * D(U) - 120L * E(V)); + const INT32 g8 = g >> 8L; + return CLIP(g8); +} + +static INLINE BYTE YUV2B(INT32 Y, INT32 U, INT32 V) +{ + const INT32 b = ( 256L * C(Y) + 475L * D(U) + 0L * E(V)); + const INT32 b8 = b >> 8L; + return CLIP(b8); +} + +static pstatus_t general_YUV444ToRGB_8u_P3AC4R( + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pDst, UINT32 dstStep, const prim_size_t* roi) +{ + UINT32 x, y; + UINT32 nWidth, nHeight; + + nWidth = roi->width; + nHeight = roi->height; + + for (y = 0; y < nHeight; y++) + { + const BYTE* pY = pSrc[0] + y * srcStep[0]; + const BYTE* pU = pSrc[1] + y * srcStep[1]; + const BYTE* pV = pSrc[2] + y * srcStep[2]; + BYTE* pRGB = pDst + y * dstStep; + + for (x = 0; x < nWidth; x++) + { + const BYTE Y = pY[x]; + const INT32 U = pU[x]; + const INT32 V = pV[x]; + + pRGB[4*x+0] = YUV2B(Y, U, V); + pRGB[4*x+1] = YUV2G(Y, U, V); + pRGB[4*x+2] = YUV2R(Y, U, V); + pRGB[4*x+3] = 0xFF; + } + } + + return PRIMITIVES_SUCCESS; +} + /** * | R | ( | 256 0 403 | | Y | ) * | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8 * | B | ( | 256 475 0 | | V - 128 | ) - * - * | Y | ( | 54 183 18 | | R | ) | 0 | - * | U | = ( | -29 -99 128 | | G | ) >> 8 + | 128 | - * | V | ( | 128 -116 -12 | | B | ) | 128 | */ -pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], - BYTE* pDst, int dstStep, const prim_size_t* roi) +static pstatus_t general_YUV420ToRGB_8u_P3AC4R( + const BYTE* pSrc[3], const UINT32 srcStep[3], + BYTE* pDst, UINT32 dstStep, const prim_size_t* roi) { - int x, y; - int dstPad; - int srcPad[3]; + UINT32 x, y; + UINT32 dstPad; + UINT32 srcPad[3]; BYTE Y, U, V; - int halfWidth; - int halfHeight; + UINT32 halfWidth; + UINT32 halfHeight; const BYTE* pY; const BYTE* pU; const BYTE* pV; - int R, G, B; - int Yp, Up, Vp; - int Up48, Up475; - int Vp403, Vp120; BYTE* pRGB = pDst; - int nWidth, nHeight; - int lastRow, lastCol; + UINT32 nWidth, nHeight; + UINT32 lastRow, lastCol; pY = pSrc[0]; pU = pSrc[1]; pV = pSrc[2]; - + lastCol = roi->width & 0x01; lastRow = roi->height & 0x01; - + nWidth = (roi->width + 1) & ~0x0001; nHeight = (roi->height + 1) & ~0x0001; @@ -88,73 +413,22 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], U = *pU++; V = *pV++; - Up = U - 128; - Vp = V - 128; - - Up48 = 48 * Up; - Up475 = 475 * Up; - - Vp403 = Vp * 403; - Vp120 = Vp * 120; - /* 1st pixel */ - Y = *pY++; - Yp = Y << 8; - R = (Yp + Vp403) >> 8; - G = (Yp - Up48 - Vp120) >> 8; - B = (Yp + Up475) >> 8; - - if (R < 0) - R = 0; - else if (R > 255) - R = 255; - - if (G < 0) - G = 0; - else if (G > 255) - G = 255; - - if (B < 0) - B = 0; - else if (B > 255) - B = 255; - - *pRGB++ = (BYTE) B; - *pRGB++ = (BYTE) G; - *pRGB++ = (BYTE) R; + *pRGB++ = YUV2B(Y, U, V); + *pRGB++ = YUV2G(Y, U, V); + *pRGB++ = YUV2R(Y, U, V); *pRGB++ = 0xFF; /* 2nd pixel */ - if (!(lastCol & 0x02)) { Y = *pY++; - Yp = Y << 8; - R = (Yp + Vp403) >> 8; - G = (Yp - Up48 - Vp120) >> 8; - B = (Yp + Up475) >> 8; - - if (R < 0) - R = 0; - else if (R > 255) - R = 255; - - if (G < 0) - G = 0; - else if (G > 255) - G = 255; - - if (B < 0) - B = 0; - else if (B > 255) - B = 255; - - *pRGB++ = (BYTE) B; - *pRGB++ = (BYTE) G; - *pRGB++ = (BYTE) R; + *pRGB++ = YUV2B(Y, U, V); + *pRGB++ = YUV2G(Y, U, V); + *pRGB++ = YUV2R(Y, U, V); *pRGB++ = 0xFF; } else @@ -170,6 +444,9 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], pV -= halfWidth; pRGB += dstPad; + if (lastRow & 0x02) + break; + for (x = 0; x < halfWidth; ) { if (++x == halfWidth) @@ -178,73 +455,22 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], U = *pU++; V = *pV++; - Up = U - 128; - Vp = V - 128; - - Up48 = 48 * Up; - Up475 = 475 * Up; - - Vp403 = Vp * 403; - Vp120 = Vp * 120; - /* 3rd pixel */ - Y = *pY++; - Yp = Y << 8; - R = (Yp + Vp403) >> 8; - G = (Yp - Up48 - Vp120) >> 8; - B = (Yp + Up475) >> 8; - - if (R < 0) - R = 0; - else if (R > 255) - R = 255; - - if (G < 0) - G = 0; - else if (G > 255) - G = 255; - - if (B < 0) - B = 0; - else if (B > 255) - B = 255; - - *pRGB++ = (BYTE) B; - *pRGB++ = (BYTE) G; - *pRGB++ = (BYTE) R; + *pRGB++ = YUV2B(Y, U, V); + *pRGB++ = YUV2G(Y, U, V); + *pRGB++ = YUV2R(Y, U, V); *pRGB++ = 0xFF; /* 4th pixel */ - if (!(lastCol & 0x02)) { Y = *pY++; - Yp = Y << 8; - R = (Yp + Vp403) >> 8; - G = (Yp - Up48 - Vp120) >> 8; - B = (Yp + Up475) >> 8; - - if (R < 0) - R = 0; - else if (R > 255) - R = 255; - - if (G < 0) - G = 0; - else if (G > 255) - G = 255; - - if (B < 0) - B = 0; - else if (B > 255) - B = 255; - - *pRGB++ = (BYTE) B; - *pRGB++ = (BYTE) G; - *pRGB++ = (BYTE) R; + *pRGB++ = YUV2B(Y, U, V); + *pRGB++ = YUV2G(Y, U, V); + *pRGB++ = YUV2R(Y, U, V); *pRGB++ = 0xFF; } else @@ -264,102 +490,142 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3], return PRIMITIVES_SUCCESS; } -pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* pSrc, INT32 srcStep, - BYTE* pDst[3], INT32 dstStep[3], const prim_size_t* roi) +/** + * | Y | ( | 54 183 18 | | R | ) | 0 | + * | U | = ( | -29 -99 128 | | G | ) >> 8 + | 128 | + * | V | ( | 128 -116 -12 | | B | ) | 128 | + */ +static INLINE BYTE RGB2Y(INT32 R, INT32 G, INT32 B) { - int x, y; - int dstPad[3]; - int halfWidth; - int halfHeight; - BYTE* pY; - BYTE* pU; - BYTE* pV; - int Y, U, V; - int R, G, B; - int Ra, Ga, Ba; - const BYTE* pRGB; - int nWidth, nHeight; + const INT32 y = ( 54L * (R) + 183L * (G) + 18L * (B)); + const INT32 y8 = (y >> 8L); - pU = pDst[1]; - pV = pDst[2]; + return CLIP(y8); +} - nWidth = (roi->width + 1) & ~0x0001; - nHeight = (roi->height + 1) & ~0x0001; +static INLINE BYTE RGB2U(INT32 R, INT32 G, INT32 B) +{ + const INT32 u = ( -29L * (R) - 99L * (G) + 128L * (B)); + const INT32 u8 = (u >> 8L) + 128L; - halfWidth = nWidth / 2; - halfHeight = nHeight / 2; + return CLIP(u8); +} - dstPad[0] = (dstStep[0] - nWidth); - dstPad[1] = (dstStep[1] - halfWidth); - dstPad[2] = (dstStep[2] - halfWidth); +static INLINE BYTE RGB2V(INT32 R, INT32 G, INT32 B) +{ + const INT32 v = ( 128L * (R) - 116L * (G) - 12L * (B)); + const INT32 v8 = (v >> 8L) + 128L; + + return CLIP(v8); +} + +static pstatus_t general_RGBToYUV444_8u_P3AC4R( + const BYTE* pSrc, const UINT32 srcStep, + BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi) +{ + UINT32 x, y; + UINT32 nWidth, nHeight; + + nWidth = roi->width; + nHeight = roi->height; + + for (y=0; ywidth + roi->width % 2; + nHeight = roi->height + roi->height % 2; + + halfWidth = (nWidth + nWidth % 2) / 2; + halfHeight = (nHeight + nHeight % 2) / 2; for (y = 0; y < halfHeight; y++) { + const UINT32 val2y = (y * 2); + const UINT32 val2y1 = val2y + 1; + const BYTE* pRGB = pSrc + val2y * srcStep; + const BYTE* pRGB1 = pSrc + val2y1 * srcStep; + + BYTE* pY = pDst[0] + val2y * dstStep[0]; + BYTE* pY1 = pDst[0] + val2y1 * dstStep[0]; + BYTE* pU = pDst[1] + y * dstStep[1]; + BYTE* pV = pDst[2] + y * dstStep[2]; + for (x = 0; x < halfWidth; x++) { - /* 1st pixel */ - pRGB = pSrc + y * 2 * srcStep + x * 2 * 4; - pY = pDst[0] + y * 2 * dstStep[0] + x * 2; - Ba = B = pRGB[0]; - Ga = G = pRGB[1]; - Ra = R = pRGB[2]; - Y = (54 * R + 183 * G + 18 * B) >> 8; - pY[0] = (BYTE) Y; + INT32 R, G, B; + INT32 Ra, Ga, Ba; + const UINT32 val2x = (x * 2); + const UINT32 val2x1 = val2x + 1; - if (x * 2 + 1 < roi->width) + /* 1st pixel */ + Ba = B = pRGB[val2x * 4 + 0]; + Ga = G = pRGB[val2x * 4 + 1]; + Ra = R = pRGB[val2x * 4 + 2]; + pY[val2x] = RGB2Y(R, G, B); + + if (val2x1 < nWidth) { /* 2nd pixel */ - Ba += B = pRGB[4]; - Ga += G = pRGB[5]; - Ra += R = pRGB[6]; - Y = (54 * R + 183 * G + 18 * B) >> 8; - pY[1] = (BYTE) Y; + Ba += B = pRGB[val2x * 4 + 4]; + Ga += G = pRGB[val2x * 4 + 5]; + Ra += R = pRGB[val2x * 4 + 6]; + pY[val2x1] = RGB2Y(R, G, B); } - if (y * 2 + 1 < roi->height) + if (val2y1 < nHeight) { /* 3rd pixel */ - pRGB += srcStep; - pY += dstStep[0]; - Ba += B = pRGB[0]; - Ga += G = pRGB[1]; - Ra += R = pRGB[2]; - Y = (54 * R + 183 * G + 18 * B) >> 8; - pY[0] = (BYTE) Y; + Ba += B = pRGB1[val2x * 4 + 0]; + Ga += G = pRGB1[val2x * 4 + 1]; + Ra += R = pRGB1[val2x * 4 + 2]; + pY1[val2x] = RGB2Y(R, G, B); - if (x * 2 + 1 < roi->width) + if (val2x1 < nWidth) { /* 4th pixel */ - Ba += B = pRGB[4]; - Ga += G = pRGB[5]; - Ra += R = pRGB[6]; - Y = (54 * R + 183 * G + 18 * B) >> 8; - pY[1] = (BYTE) Y; + Ba += B = pRGB1[val2x * 4 + 4]; + Ga += G = pRGB1[val2x * 4 + 5]; + Ra += R = pRGB1[val2x * 4 + 6]; + pY1[val2x1] = RGB2Y(R, G, B); } } - /* U */ Ba >>= 2; Ga >>= 2; Ra >>= 2; - U = ((-29 * Ra - 99 * Ga + 128 * Ba) >> 8) + 128; - if (U < 0) - U = 0; - else if (U > 255) - U = 255; - *pU++ = (BYTE) U; - /* V */ - V = ((128 * Ra - 116 * Ga - 12 * Ba) >> 8) + 128; - if (V < 0) - V = 0; - else if (V > 255) - V = 255; - *pV++ = (BYTE) V; + pU[x] = RGB2U(Ra, Ga, Ba); + pV[x] = RGB2V(Ra, Ga, Ba); } - - pU += dstPad[1]; - pV += dstPad[2]; } return PRIMITIVES_SUCCESS; @@ -368,8 +634,12 @@ pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* pSrc, INT32 srcStep, void primitives_init_YUV(primitives_t* prims) { prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R; + prims->YUV444ToRGB_8u_P3AC4R = general_YUV444ToRGB_8u_P3AC4R; prims->RGBToYUV420_8u_P3AC4R = general_RGBToYUV420_8u_P3AC4R; - + prims->RGBToYUV444_8u_P3AC4R = general_RGBToYUV444_8u_P3AC4R; + prims->YUV420CombineToYUV444 = general_YUV420CombineToYUV444; + prims->YUV444SplitToYUV420 = general_YUV444SplitToYUV420; + primitives_init_YUV_opt(prims); } diff --git a/libfreerdp/primitives/prim_YUV_opt.c b/libfreerdp/primitives/prim_YUV_opt.c index 7b80a45..45688df 100644 --- a/libfreerdp/primitives/prim_YUV_opt.c +++ b/libfreerdp/primitives/prim_YUV_opt.c @@ -22,27 +22,27 @@ #include #include -pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, - BYTE *pDst, int dstStep, const prim_size_t *roi) +pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, const UINT32 *srcStep, + BYTE *pDst, UINT32 dstStep, const prim_size_t *roi) { - int lastRow, lastCol; + UINT32 lastRow, lastCol; BYTE *UData,*VData,*YData; - int i,nWidth,nHeight,VaddDst,VaddY,VaddU,VaddV; + UINT32 i,nWidth,nHeight,VaddDst,VaddY,VaddU,VaddV; __m128i r0,r1,r2,r3,r4,r5,r6,r7; __m128i *buffer; - + /* last_line: if the last (U,V doubled) line should be skipped, set to 10B * last_column: if it's the last column in a line, set to 10B (for handling line-endings not multiple by four) */ buffer = _aligned_malloc(4 * 16, 16); - + YData = (BYTE*) pSrc[0]; UData = (BYTE*) pSrc[1]; VData = (BYTE*) pSrc[2]; - + nWidth = roi->width; nHeight = roi->height; - + if ((lastCol = (nWidth & 3))) { switch (lastCol) @@ -63,26 +63,26 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, _mm_store_si128(buffer+3,r7); lastCol = 1; } - + nWidth += 3; nWidth = nWidth >> 2; - + lastRow = nHeight & 1; nHeight++; nHeight = nHeight >> 1; - + VaddDst = (dstStep << 1) - (nWidth << 4); VaddY = (srcStep[0] << 1) - (nWidth << 2); VaddU = srcStep[1] - (((nWidth << 1) + 2) & 0xFFFC); VaddV = srcStep[2] - (((nWidth << 1) + 2) & 0xFFFC); - + while (nHeight-- > 0) { if (nHeight == 0) lastRow <<= 1; i = 0; - + do { if (!(i & 0x01)) @@ -97,16 +97,16 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r0 = _mm_cvtsi32_si128(*(UINT32 *)UData); r5 = _mm_set_epi32(0x80038003,0x80028002,0x80018001,0x80008000); r0 = _mm_shuffle_epi8(r0,r5); - + UData += 4; - + /* then we subtract 128 from each value, so we get D */ r3 = _mm_set_epi16(128,128,128,128,128,128,128,128); r0 = _mm_subs_epi16(r0,r3); - + /* we need to do two things with our D, so let's store it for later use */ r2 = r0; - + /* now we can multiply our D with 48 and unpack it to xmm4:xmm0 * this is what we need to get G data later on */ r4 = r0; @@ -116,7 +116,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r7 = r0; r0 = _mm_unpacklo_epi16(r0,r4); r4 = _mm_unpackhi_epi16(r7,r4); - + /* to get B data, we need to prepare a second value, D*475 */ r1 = r2; r7 = _mm_set_epi16(475,475,475,475,475,475,475,475); @@ -125,23 +125,23 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r7 = r1; r1 = _mm_unpacklo_epi16(r1,r2); r7 = _mm_unpackhi_epi16(r7,r2); - + /* so we got something like this: xmm7:xmm1 * this pair contains values for 16 pixel: * aabbccdd * aabbccdd, but we can only work on four pixel at once, so we need to save upper values */ _mm_store_si128(buffer+1,r7); - + /* Now we've prepared U-data. Preparing V-data is actually the same, just with other coefficients */ r2 = _mm_cvtsi32_si128(*(UINT32 *)VData); r2 = _mm_shuffle_epi8(r2,r5); - + VData += 4; - + r2 = _mm_subs_epi16(r2,r3); - + r5 = r2; - + /* this is also known as E*403, we need it to convert R data */ r3 = r2; r7 = _mm_set_epi16(403,403,403,403,403,403,403,403); @@ -150,10 +150,10 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r7 = r2; r2 = _mm_unpacklo_epi16(r2,r3); r7 = _mm_unpackhi_epi16(r7,r3); - + /* and preserve upper four values for future ... */ _mm_store_si128(buffer+2,r7); - + /* doing this step: E*120 */ r3 = r5; r7 = _mm_set_epi16(120,120,120,120,120,120,120,120); @@ -162,12 +162,12 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r7 = r3; r3 = _mm_unpacklo_epi16(r3,r5); r7 = _mm_unpackhi_epi16(r7,r5); - + /* now we complete what we've begun above: * (48*D) + (120*E) = (48*D +120*E) */ r0 = _mm_add_epi32(r0,r3); r4 = _mm_add_epi32(r4,r7); - + /* and store to memory ! */ _mm_store_si128(buffer,r4); } @@ -180,25 +180,25 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r2 = _mm_load_si128(buffer+2); r0 = _mm_load_si128(buffer); } - + if (++i == nWidth) lastCol <<= 1; - + /* We didn't produce any output yet, so let's do so! * Ok, fetch four pixel from the Y-data array and shuffle them like this: * 00d0 00c0 00b0 00a0, to get signed dwords and multiply by 256 */ r4 = _mm_cvtsi32_si128(*(UINT32 *)YData); r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080); r4 = _mm_shuffle_epi8(r4,r7); - + r5 = r4; r6 = r4; - + /* no we can perform the "real" conversion itself and produce output! */ r4 = _mm_add_epi32(r4,r2); r5 = _mm_sub_epi32(r5,r0); r6 = _mm_add_epi32(r6,r1); - + /* in the end, we only need bytes for RGB values. * So, what do we do? right! shifting left makes values bigger and thats always good. * before we had dwords of data, and by shifting left and treating the result @@ -208,7 +208,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r4 = _mm_slli_epi32(r4,8); r5 = _mm_slli_epi32(r5,8); r6 = _mm_slli_epi32(r6,8); - + /* one thing we still have to face is the clip() function ... * we have still signed words, and there are those min/max instructions in SSE2 ... * the max instruction takes always the bigger of the two operands and stores it in the first one, @@ -219,35 +219,35 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r4 = _mm_max_epi16(r4,r7); r5 = _mm_max_epi16(r5,r7); r6 = _mm_max_epi16(r6,r7); - + /* the same thing just completely different can be used to limit our values to 255, * but now using the min instruction and 255s */ r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); r4 = _mm_min_epi16(r4,r7); r5 = _mm_min_epi16(r5,r7); r6 = _mm_min_epi16(r6,r7); - + /* Now we got our bytes. * the moment has come to assemble the three channels R,G and B to the xrgb dwords * on Red channel we just have to and each futural dword with 00FF0000H */ //r7=_mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); r4 = _mm_and_si128(r4,r7); - + /* on Green channel we have to shuffle somehow, so we get something like this: * 00d0 00c0 00b0 00a0 */ r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280); r5 = _mm_shuffle_epi8(r5,r7); - + /* and on Blue channel that one: * 000d 000c 000b 000a */ r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002); r6 = _mm_shuffle_epi8(r6,r7); - + /* and at last we or it together and get this one: * xrgb xrgb xrgb xrgb */ r4 = _mm_or_si128(r4,r5); r4 = _mm_or_si128(r4,r6); - + /* Only thing to do know is writing data to memory, but this gets a bit more * complicated if the width is not a multiple of four and it is the last column in line. */ if (lastCol & 0x02) @@ -269,7 +269,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r4 = _mm_or_si128(r4,r6); } _mm_storeu_si128((__m128i *)pDst,r4); - + if (!(lastRow & 0x02)) { /* Because UV data is the same for two lines, we can process the secound line just here, @@ -280,40 +280,40 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r4 = _mm_cvtsi32_si128(*(UINT32 *)(YData+srcStep[0])); r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080); r4 = _mm_shuffle_epi8(r4,r7); - + r5 = r4; r6 = r4; - + r4 = _mm_add_epi32(r4,r2); r5 = _mm_sub_epi32(r5,r0); r6 = _mm_add_epi32(r6,r1); - + r4 = _mm_slli_epi32(r4,8); r5 = _mm_slli_epi32(r5,8); r6 = _mm_slli_epi32(r6,8); - + r7 = _mm_set_epi32(0,0,0,0); r4 = _mm_max_epi16(r4,r7); r5 = _mm_max_epi16(r5,r7); r6 = _mm_max_epi16(r6,r7); - + r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); r4 = _mm_min_epi16(r4,r7); r5 = _mm_min_epi16(r5,r7); r6 = _mm_min_epi16(r6,r7); - + r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000); r4 = _mm_and_si128(r4,r7); - + r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280); r5 = _mm_shuffle_epi8(r5,r7); - + r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002); r6 = _mm_shuffle_epi8(r6,r7); - + r4 = _mm_or_si128(r4,r5); r4 = _mm_or_si128(r4,r6); - + if (lastCol & 0x02) { r6 = _mm_load_si128(buffer+3); @@ -321,20 +321,20 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, r5 = _mm_lddqu_si128((__m128i *)(pDst+dstStep)); r6 = _mm_andnot_si128(r6,r5); r4 = _mm_or_si128(r4,r6); - + /* only thing is, we should shift [rbp-42] back here, because we have processed the last column, * and this "special condition" can be released */ lastCol >>= 1; } _mm_storeu_si128((__m128i *)(pDst+dstStep),r4); } - + /* after all we have to increase the destination- and Y-data pointer by four pixel */ pDst += 16; YData += 4; } while (i < nWidth); - + /* after each line we have to add the scanline to the destination pointer, because * we are processing two lines at once, but only increasing the destination pointer * in the first line. Well, we only have one pointer, so it's the easiest way to access @@ -343,10 +343,10 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, * output buffer was "designed" for 1920p HD, we have to add the remaining length for each line, * to get into the next line. */ pDst += VaddDst; - + /* same thing has to be done for Y-data, but with iStride[0] instead of the target scanline */ YData += VaddY; - + /* and again for UV data, but here it's enough to add the remaining length, because * UV data is the same for two lines and there exists only one "UV line" on two "real lines" */ UData += VaddU; @@ -354,7 +354,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep, } _aligned_free(buffer); - + return PRIMITIVES_SUCCESS; } #endif diff --git a/libfreerdp/primitives/test/CMakeLists.txt b/libfreerdp/primitives/test/CMakeLists.txt index 9a652a3..caf651b 100644 --- a/libfreerdp/primitives/test/CMakeLists.txt +++ b/libfreerdp/primitives/test/CMakeLists.txt @@ -14,6 +14,7 @@ set(${MODULE_PREFIX}_TESTS TestPrimitivesSet.c TestPrimitivesShift.c TestPrimitivesSign.c + TestPrimitivesYUV.c TestPrimitivesYCbCr.c TestPrimitivesYCoCg.c) diff --git a/libfreerdp/primitives/test/TestPrimitives16to32bpp.c b/libfreerdp/primitives/test/TestPrimitives16to32bpp.c index 03a070e..ed985bd 100644 --- a/libfreerdp/primitives/test/TestPrimitives16to32bpp.c +++ b/libfreerdp/primitives/test/TestPrimitives16to32bpp.c @@ -57,8 +57,10 @@ static BOOL try_16To32( const UINT16 *src; UINT32 ALIGN(outNN1[4096+3]), ALIGN(outAN1[4096+3]), ALIGN(outNI1[4096+3]), ALIGN(outAI1[4096+3]); +#ifdef WITH_SSE2 UINT32 ALIGN(outNN2[4096+3]), ALIGN(outAN2[4096+3]), ALIGN(outNI2[4096+3]), ALIGN(outAI2[4096+3]); +#endif assert(sOffset < 4); assert(dOffset < 4); @@ -161,7 +163,7 @@ int test_RGB565ToARGB_16u32u_C3C4_func(void) STD_SPEED_TEST( test16to32_speed, UINT16, UINT32, PRIM_NOP, TRUE, general_RGB565ToARGB_16u32u_C3C4( - (const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4, + (const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4, 64,64, TRUE, TRUE), #ifdef WITH_SSE2 TRUE, sse3_RGB565ToARGB_16u32u_C3C4( @@ -182,7 +184,7 @@ int test_RGB565ToARGB_16u32u_C3C4_speed(void) get_random_data(src, sizeof(src)); - test16to32_speed("16-to-32bpp", "aligned", + test16to32_speed("16-to-32bpp", "aligned", (const UINT16 *) src, 0, 0, (UINT32 *) dst, size_array, 1, RGB_TRIAL_ITERATIONS, TEST_TIME); return SUCCESS; diff --git a/libfreerdp/primitives/test/TestPrimitivesYCoCg.c b/libfreerdp/primitives/test/TestPrimitivesYCoCg.c index 4c6a4b8..9fb0fd3 100644 --- a/libfreerdp/primitives/test/TestPrimitivesYCoCg.c +++ b/libfreerdp/primitives/test/TestPrimitivesYCoCg.c @@ -38,12 +38,14 @@ extern pstatus_t ssse3_YCoCgRToRGB_8u_AC4R(const BYTE *pSrc, INT32 srcStep, /* ------------------------------------------------------------------------- */ int test_YCoCgRToRGB_8u_AC4R_func(void) { +#ifdef WITH_SSE2 + int i; + INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]); +#endif INT32 ALIGN(in[4098]); INT32 ALIGN(out_c[4098]), ALIGN(out_c_inv[4098]); - INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]); char testStr[256]; BOOL failed = FALSE; - int i; testStr[0] = '\0'; get_random_data(in, sizeof(in)); diff --git a/libfreerdp/primitives/test/TestPrimitivesYUV.c b/libfreerdp/primitives/test/TestPrimitivesYUV.c new file mode 100644 index 0000000..a4b34f7 --- /dev/null +++ b/libfreerdp/primitives/test/TestPrimitivesYUV.c @@ -0,0 +1,427 @@ + +#include "prim_test.h" + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define TAG __FILE__ + +/* YUV to RGB conversion is lossy, so consider every value only + * differing by less than 2 abs equal. */ +static BOOL similar(const BYTE* src, const BYTE* dst, size_t size) +{ + size_t x; + + for (x=0; x 2) + { + fprintf(stderr, "%zd %02X : %02X diff=%lf\n", x, val1, val2, diff); + return FALSE; + } + } + + return TRUE; +} + +static void get_size(UINT32* width, UINT32* height) +{ + winpr_RAND((BYTE*)width, sizeof(*width)); + winpr_RAND((BYTE*)height, sizeof(*height)); + + // TODO: Algorithm only works on even resolutions... + *width = (*width % 4000) << 1; + *height = (*height % 4000 << 1); +} + +static BOOL check_padding(const BYTE* psrc, size_t size, size_t padding, const char* buffer) +{ + size_t x; + BOOL rc = TRUE; + const BYTE* src; + const BYTE* esrc; + size_t halfPad = (padding+1)/2; + + if (!psrc) + return FALSE; + + src = psrc - halfPad; + esrc = src + size + halfPad; + for (x=0; xYUV420CombineToYUV444) + goto fail; + + for (x=0; x<3; x++) + { + size_t halfStride = ((x>0)?awidth/2:awidth); + size_t size = aheight * awidth; + size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight); + + yuvStride[x] = awidth; + if (!(yuv[x] = set_padding(size, padding))) + goto fail; + + lumaStride[x] = halfStride; + if (!(luma[x] = set_padding(halfSize, padding))) + goto fail; + + if (!(pmain[x] = set_padding(halfSize, padding))) + goto fail; + + chromaStride[x] = halfStride; + if (!(chroma[x] = set_padding(halfSize, padding))) + goto fail; + + if (!(paux[x] = set_padding(halfSize, padding))) + goto fail; + + memset(luma[x], 0xAB + 3*x, halfSize); + memset(chroma[x], 0x80 + 2*x, halfSize); + + if (!check_padding(luma[x], halfSize, padding, "luma")) + goto fail; + if (!check_padding(chroma[x], halfSize, padding, "chroma")) + goto fail; + if (!check_padding(pmain[x], halfSize, padding, "main")) + goto fail; + if (!check_padding(paux[x], halfSize, padding, "aux")) + goto fail; + if (!check_padding(yuv[x], size, padding, "yuv")) + goto fail; + } + + if (prims->YUV420CombineToYUV444((const BYTE**)luma, lumaStride, + (const BYTE**) chroma, chromaStride, + yuv, yuvStride, &roi) != PRIMITIVES_SUCCESS) + goto fail; + + for (x=0; x<3; x++) + { + size_t halfStride = ((x>0)?awidth/2:awidth); + size_t size = aheight * awidth; + size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight); + + if (!check_padding(luma[x], halfSize, padding, "luma")) + goto fail; + if (!check_padding(chroma[x], halfSize, padding, "chroma")) + goto fail; + if (!check_padding(yuv[x], size, padding, "yuv")) + goto fail; + } + + if (prims->YUV444SplitToYUV420(yuv, yuvStride, pmain, lumaStride, + paux, chromaStride, &roi) != PRIMITIVES_SUCCESS) + goto fail; + + for (x=0; x<3; x++) + { + size_t halfStride = ((x>0)?awidth/2:awidth); + size_t size = aheight * awidth; + size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight); + + if (!check_padding(pmain[x], halfSize, padding, "main")) + goto fail; + if (!check_padding(paux[x], halfSize, padding, "aux")) + goto fail; + if (!check_padding(yuv[x], size, padding, "yuv")) + goto fail; + } + + for (i=0; i<3; i++) + { + for (y=0; y 0) + { + w = (roi.width+3) / 4; + if (roi.height > (roi.height+1)/2) + continue; + } + + if (!similar(luma[i] + y * lstride, + pmain[i] + y * lstride, + w)) + goto fail; + + /* Need to ignore lines of destination Y plane, + * if the lines are not a multiple of 16 + * as the UV planes are packed in 8 line stripes. */ + if (i == 0) + { + /* TODO: This check is not perfect, it does not + * include the last V lines packed to the Y + * frame. */ + UINT32 rem = roi.height % 16; + if (y > roi.height - rem) + continue; + } + + if (!similar(chroma[i] + y * cstride, + paux[i] + y * cstride, + w)) + goto fail; + } + } + + rc = TRUE; +fail: + for (x=0; x<3; x++) + { + free_padding(yuv[x], padding); + free_padding(luma[x], padding); + free_padding(chroma[x], padding); + free_padding(pmain[x], padding); + free_padding(paux[x], padding); + } + + return rc; +} + +static BOOL TestPrimitiveYUV(BOOL use444) +{ + BOOL rc = FALSE; + UINT32 x, y; + UINT32 awidth, aheight; + BYTE* yuv[3] = {0}; + UINT32 yuv_step[3]; + prim_size_t roi; + BYTE* rgb = NULL; + BYTE* rgb_dst = NULL; + size_t size; + primitives_t* prims = primitives_get(); + size_t uvsize, uvwidth; + size_t padding = 10000; + size_t stride; + + get_size(&roi.width, &roi.height); + + /* Buffers need to be 16x16 aligned. */ + awidth = roi.width + 16 - roi.width % 16; + aheight = roi.height + 16 - roi.height % 16; + + stride = awidth * sizeof(UINT32); + size = awidth * aheight; + if (use444) + { + uvwidth = awidth; + uvsize = size; + if (!prims || !prims->RGBToYUV444_8u_P3AC4R || !prims->YUV444ToRGB_8u_P3AC4R) + return FALSE; + } + else + { + uvwidth = (awidth + 1) / 2; + uvsize = (aheight + 1) / 2 * uvwidth; + if (!prims || !prims->RGBToYUV420_8u_P3AC4R || !prims->YUV420ToRGB_8u_P3AC4R) + return FALSE; + } + + fprintf(stderr, "Running AVC%s on frame size %lux%lu\n", use444 ? "444" : "420", + roi.width, roi.height); + + /* Test RGB to YUV444 conversion and vice versa */ + if (!(rgb = set_padding(size * sizeof(UINT32), padding))) + goto fail; + + if (!(rgb_dst = set_padding(size * sizeof(UINT32), padding))) + goto fail; + + if (!(yuv[0] = set_padding(size, padding))) + goto fail; + + if (!(yuv[1] = set_padding(uvsize, padding))) + goto fail; + + if (!(yuv[2] = set_padding(uvsize, padding))) + goto fail; + + for (y=0; yRGBToYUV444_8u_P3AC4R(rgb, stride, yuv, yuv_step, &roi) != PRIMITIVES_SUCCESS) + goto fail; + } + else if (prims->RGBToYUV420_8u_P3AC4R(rgb, stride, yuv, yuv_step, &roi) != PRIMITIVES_SUCCESS) + goto fail; + + if (!check_padding(rgb, size * sizeof(UINT32), padding, "rgb")) + goto fail; + + if ((!check_padding(yuv[0], size, padding, "Y")) || + (!check_padding(yuv[1], uvsize, padding, "U")) || + (!check_padding(yuv[2], uvsize, padding, "V"))) + goto fail; + + if (use444) + { + if (prims->YUV444ToRGB_8u_P3AC4R((const BYTE**)yuv, yuv_step, rgb_dst, stride, &roi) != PRIMITIVES_SUCCESS) + goto fail; + } + else if (prims->YUV420ToRGB_8u_P3AC4R((const BYTE**)yuv, yuv_step, rgb_dst, stride, &roi) != PRIMITIVES_SUCCESS) + goto fail; + + if (!check_padding(rgb_dst, size * sizeof(UINT32), padding, "rgb dst")) + goto fail; + + if ((!check_padding(yuv[0], size, padding, "Y")) || + (!check_padding(yuv[1], uvsize, padding, "U")) || + (!check_padding(yuv[2], uvsize, padding, "V"))) + goto fail; + + for (y=0; y= 0) - { - sbias = (offset.Hours * 60) + offset.Minutes; - tz.Bias = (UInt32) sbias; - } - else - { - sbias = (offset.Hours * 60) + offset.Minutes; - tz.Bias = (UInt32) (1440 + sbias); - } + tz.Bias = -(Int32)offset.TotalMinutes; tz.SupportsDST = timeZone.SupportsDaylightSavingTime; @@ -233,7 +208,7 @@ namespace TimeZones stream.WriteLine("\t{"); stream.WriteLine("\t\t\"{0}\", {1}, {2}, \"{3}\",", - tz.Id, tz.Bias, tz.SupportsDST ? "true" : "false", tz.DisplayName); + tz.Id, tz.Bias, tz.SupportsDST ? "TRUE" : "FALSE", tz.DisplayName); stream.WriteLine("\t\t\"{0}\", \"{1}\",", tz.StandardName, tz.DaylightName); stream.WriteLine("\t\t{0}, {1}", tz.RuleTable, tz.RuleTableCount); diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index a522f86..73ce021 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -80,6 +80,7 @@ fi common_run mkdir -p $BUILD_SRC CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \ + -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \ -DCMAKE_TOOLCHAIN_FILE=$SRC_DIR/cmake/AndroidToolchain.cmake \ -DCMAKE_INSTALL_PREFIX=$BUILD_DST \ -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ diff --git a/scripts/android-build-openssl.sh b/scripts/android-build-openssl.sh index 3e376fe..3a36006 100755 --- a/scripts/android-build-openssl.sh +++ b/scripts/android-build-openssl.sh @@ -47,7 +47,8 @@ function build { common_run cd $BUILD_SRC common_run git clean -xdf common_run ./Configure --openssldir=$DST_DIR $CONFIG shared - common_run make -j build_libs + common_run make CALC_VERSIONS="SHLIB_COMPAT=; SHLIB_SOVER=" depend + common_run make CALC_VERSIONS="SHLIB_COMPAT=; SHLIB_SOVER=" build_libs if [ ! -d $DST_DIR ]; then @@ -65,12 +66,6 @@ common_check_requirements common_update $SCM_URL $SCM_TAG $BUILD_SRC common_clean $BUILD_DST -# Patch openssl -BASE=$(pwd) -common_run cd $BUILD_SRC -common_run git am $(dirname "${BASH_SOURCE[0]}")/openssl-disable-library-versioning.patch -common_run cd $BASE - ORG_PATH=$PATH for ARCH in $BUILD_ARCH do diff --git a/scripts/android-build.conf b/scripts/android-build.conf index fff1ab2..b8c836e 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -4,14 +4,15 @@ SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") SCRIPT_PATH=$(realpath "$SCRIPT_PATH") -WITH_JPEG=1 +WITH_JPEG=0 WITH_OPENH264=1 WITH_OPENSSL=1 BUILD_DEPS=1 +ANDROID_NATIVE_API_LEVEL=android-12 JPEG_TAG=master OPENH264_TAG=v1.5.0 -OPENSSL_TAG=OpenSSL_1_0_2f +OPENSSL_TAG=OpenSSL_1_0_2g SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/openssl-disable-library-versioning.patch b/scripts/openssl-disable-library-versioning.patch deleted file mode 100644 index 9f2f691..0000000 --- a/scripts/openssl-disable-library-versioning.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 12f0521bbb3f046db8c7854364135d8247cf982e Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Fri, 29 Jan 2016 17:04:12 +0100 -Subject: [PATCH] Disabled library versioning. - ---- - Makefile.shared | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/Makefile.shared b/Makefile.shared -index e753f44..5cffcc2 100644 ---- a/Makefile.shared -+++ b/Makefile.shared -@@ -81,7 +81,6 @@ CALC_VERSIONS= \ - prev=""; \ - for v in `echo "$(LIBVERSION) $(LIBCOMPATVERSIONS)" | cut -d';' -f1`; do \ - SHLIB_SOVER_NODOT=$$v; \ -- SHLIB_SOVER=.$$v; \ - if [ -n "$$prev" ]; then \ - SHLIB_COMPAT="$$SHLIB_COMPAT .$$prev"; \ - fi; \ --- -2.1.4 - diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index ba2cf9e..7e33947 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -59,9 +59,12 @@ BOOL test_peer_context_new(freerdp_peer* client, testPeerContext* context) if (!(context->rfx_context = rfx_context_new(TRUE))) goto fail_rfx_context; + if (!rfx_context_reset(context->rfx_context, SAMPLE_SERVER_DEFAULT_WIDTH, + SAMPLE_SERVER_DEFAULT_HEIGHT)) + goto fail_rfx_context; + context->rfx_context->mode = RLGR3; - context->rfx_context->width = SAMPLE_SERVER_DEFAULT_WIDTH; - context->rfx_context->height = SAMPLE_SERVER_DEFAULT_HEIGHT; + rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_R8G8B8); if (!(context->nsc_context = nsc_context_new())) @@ -441,20 +444,16 @@ BOOL tf_peer_dump_rfx(freerdp_peer* client) while (pcap_has_next_record(pcap_rfx)) { - BYTE* tmp = NULL; if (!pcap_get_next_record_header(pcap_rfx, &record)) break; - tmp = realloc(Stream_Buffer(s), record.length); - if (!tmp) + if (!Stream_EnsureCapacity(s, record.length)) break; - Stream_Buffer(s) = tmp; record.data = Stream_Buffer(s); - Stream_Capacity(s) = record.length; pcap_get_next_record_content(pcap_rfx, &record); - Stream_Pointer(s) = Stream_Buffer(s) + Stream_Capacity(s); + Stream_SetPointer(s, Stream_Buffer(s) + Stream_Capacity(s)); if (test_dump_rfx_realtime && test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec, record.header.ts_usec) == FALSE) break; @@ -551,9 +550,12 @@ BOOL tf_peer_post_connect(freerdp_peer* client) WLog_DBG(TAG, ""); WLog_DBG(TAG, "Client requested desktop: %dx%dx%d", client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); + #if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1) - context->rfx_context->width = client->settings->DesktopWidth; - context->rfx_context->height = client->settings->DesktopHeight; + if (!rfx_context_reset(context->rfx_context, client->settings->DesktopWidth, + client->settings->DesktopHeight)) + return FALSE; + WLog_DBG(TAG, "Using resolution requested by client."); #else client->settings->DesktopWidth = context->rfx_context->width; @@ -617,7 +619,6 @@ BOOL tf_peer_activate(freerdp_peer* client) { testPeerContext* context = (testPeerContext*) client->context; - rfx_context_reset(context->rfx_context); context->activated = TRUE; //client->settings->CompressionLevel = PACKET_COMPR_TYPE_8K; @@ -662,8 +663,10 @@ BOOL tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) client->settings->DesktopWidth = SAMPLE_SERVER_DEFAULT_WIDTH; client->settings->DesktopHeight = SAMPLE_SERVER_DEFAULT_HEIGHT; } - context->rfx_context->width = client->settings->DesktopWidth; - context->rfx_context->height = client->settings->DesktopHeight; + if (!rfx_context_reset(context->rfx_context, client->settings->DesktopWidth, + client->settings->DesktopHeight)) + return FALSE; + update->DesktopResize(update->context); context->activated = FALSE; } diff --git a/server/shadow/Win/win_rdp.c b/server/shadow/Win/win_rdp.c index b254f2a..231996e 100644 --- a/server/shadow/Win/win_rdp.c +++ b/server/shadow/Win/win_rdp.c @@ -133,9 +133,11 @@ BOOL shw_pre_connect(freerdp* instance) PubSub_SubscribeChannelDisconnected(context->pubSub, (pChannelDisconnectedEventHandler) shw_OnChannelDisconnectedEventHandler); - freerdp_client_load_addins(context->channels, instance->settings); + if (!freerdp_client_load_addins(context->channels, instance->settings)) + return FALSE; - freerdp_channels_pre_connect(context->channels, instance); + if (freerdp_channels_pre_connect(context->channels, instance) != CHANNEL_RC_OK) + return FALSE; return TRUE; } @@ -159,7 +161,7 @@ BOOL shw_post_connect(freerdp* instance) instance->update->DesktopResize = shw_desktop_resize; instance->update->SurfaceFrameMarker = shw_surface_frame_marker; - return (freerdp_channels_post_connect(instance->context->channels, instance) >= 0) ; + return (freerdp_channels_post_connect(instance->context->channels, instance) == CHANNEL_RC_OK) ; } void* shw_client_thread(void* arg) diff --git a/server/shadow/Win/win_wds.c b/server/shadow/Win/win_wds.c index 44a12d2..2bfc423 100644 --- a/server/shadow/Win/win_wds.c +++ b/server/shadow/Win/win_wds.c @@ -744,7 +744,7 @@ int win_shadow_wds_init(winShadowSubsystem* subsystem) return -1; } - subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation, &bstrConnectionString); + hr = subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation, &bstrConnectionString); if (FAILED(hr)) { @@ -752,10 +752,24 @@ int win_shadow_wds_init(winShadowSubsystem* subsystem) return -1; } + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) bstrConnectionString, + ((UINT32*) bstrConnectionString)[-1], &(file->ConnectionString2), 0, NULL, NULL); + + SysFreeString(bstrConnectionString); + + if (status < 1) + { + WLog_ERR(TAG, "failed to convert connection string"); + return -1; + } + file = subsystem->pAssistanceFile = freerdp_assistance_file_new(); - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) bstrConnectionString, - ((UINT32*) bstrConnectionString)[-1], &(file->ConnectionString2), 0, NULL, NULL); + if (!file) + { + WLog_ERR(TAG, "freerdp_assistance_file_new() failed"); + return -1; + } status = freerdp_assistance_parse_connection_string2(file); diff --git a/server/shadow/freerdp-shadow.pc.in b/server/shadow/freerdp-shadow.pc.in index 49449e8..5c8c462 100644 --- a/server/shadow/freerdp-shadow.pc.in +++ b/server/shadow/freerdp-shadow.pc.in @@ -2,14 +2,14 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=${prefix}/@FREERDP_INCLUDE_DIR@ -libs=-lfreerdp-shadow +libs=-lfreerdp-shadow -lfreerdp-shadow-subsystem Name: FreeRDP shadow Description: FreeRDP: A Remote Desktop Protocol Implementation URL: http://www.freerdp.com/ Version: @FREERDP_VERSION@ Requires: -Requires.private: @WINPR_PKG_CONFIG_FILENAME@ freerdp@FREERDP_VERSION_MAJOR@ freerdp-shadow@FREERDP_VERSION_MAJOR@ +Requires.private: @WINPR_PKG_CONFIG_FILENAME@ freerdp@FREERDP_VERSION_MAJOR@ Libs: -L${libdir} ${libs} Libs.private: -ldl -lpthread Cflags: -I${includedir} diff --git a/server/shadow/shadow_channels.c b/server/shadow/shadow_channels.c index eaf787e..bc90ab4 100644 --- a/server/shadow/shadow_channels.c +++ b/server/shadow/shadow_channels.c @@ -24,7 +24,7 @@ #include "shadow_channels.h" -int shadow_client_channels_post_connect(rdpShadowClient* client) +UINT shadow_client_channels_post_connect(rdpShadowClient* client) { if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, ENCOMSP_SVC_CHANNEL_NAME)) { @@ -43,7 +43,7 @@ int shadow_client_channels_post_connect(rdpShadowClient* client) shadow_client_audin_init(client); - return 1; + return CHANNEL_RC_OK; } void shadow_client_channels_free(rdpShadowClient* client) diff --git a/server/shadow/shadow_channels.h b/server/shadow/shadow_channels.h index d6abef9..edba39c 100644 --- a/server/shadow/shadow_channels.h +++ b/server/shadow/shadow_channels.h @@ -33,7 +33,7 @@ extern "C" { #endif -int shadow_client_channels_post_connect(rdpShadowClient* client); +UINT shadow_client_channels_post_connect(rdpShadowClient* client); void shadow_client_channels_free(rdpShadowClient* client); #ifdef __cplusplus diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 6c5d80b..9c48579 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -235,7 +235,8 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) peer->update->DesktopResize(peer->update->context); - shadow_client_channels_post_connect(client); + if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK) + return FALSE; invalidRect.left = 0; invalidRect.top = 0; diff --git a/server/shadow/shadow_encoder.c b/server/shadow/shadow_encoder.c index 1f3edff..07bf880 100644 --- a/server/shadow/shadow_encoder.c +++ b/server/shadow/shadow_encoder.c @@ -34,9 +34,9 @@ int shadow_encoder_preferred_fps(rdpShadowEncoder* encoder) UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder) { - /* Return inflight frame count = + /* Return inflight frame count = * - - * Note: This function is exported so that subsystem could + * Note: This function is exported so that subsystem could * implement its own strategy to tune fps. */ return encoder->frameId - encoder->lastAckframeId; @@ -137,7 +137,10 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) encoder->rfx = rfx_context_new(TRUE); if (!encoder->rfx) - return -1; + goto fail; + + if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height)) + goto fail; encoder->rfx->mode = RLGR3; encoder->rfx->width = encoder->width; @@ -154,6 +157,10 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder) encoder->codecs |= FREERDP_CODEC_REMOTEFX; return 1; + +fail: + rfx_context_free(encoder->rfx); + return -1; } int shadow_encoder_init_nsc(rdpShadowEncoder* encoder) diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 2e3b673..ae5280e 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -48,8 +48,8 @@ include(GNUInstallDirsWrapper) include(CMakePackageConfigHelpers) # Soname versioning -set(WINPR_VERSION_MAJOR "1") -set(WINPR_VERSION_MINOR "2") +set(WINPR_VERSION_MAJOR "2") +set(WINPR_VERSION_MINOR "0") set(WINPR_VERSION_REVISION "0") set(WINPR_VERSION "${WINPR_VERSION_MAJOR}.${WINPR_VERSION_MINOR}.${WINPR_VERSION_REVISION}") set(WINPR_VERSION_FULL "${WINPR_VERSION}") diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index 54a12ac..7e05124 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -913,6 +913,8 @@ WINPR_API void winpr_RC4_Free(WINPR_RC4_CTX* ctx); * Generic Cipher API */ +#define WINPR_AES_BLOCK_SIZE 16 + /* cipher operation types */ #define WINPR_ENCRYPT 0 #define WINPR_DECRYPT 1 diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index f0129e2..386705e 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -288,6 +288,9 @@ WINPR_API BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffse WINPR_API BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); +WINPR_API BOOL SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime); + WINPR_API HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); WINPR_API HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData); diff --git a/winpr/include/winpr/path.h b/winpr/include/winpr/path.h index eba1329..685ee74 100644 --- a/winpr/include/winpr/path.h +++ b/winpr/include/winpr/path.h @@ -287,17 +287,23 @@ WINPR_API char* GetCombinedPath(const char* basePath, const char* subPath); WINPR_API BOOL PathMakePathA(LPCSTR path, LPSECURITY_ATTRIBUTES lpAttributes); +#ifndef WIN32 WINPR_API BOOL PathFileExistsA(LPCSTR pszPath); WINPR_API BOOL PathFileExistsW(LPCWSTR pszPath); +#endif #ifdef __cplusplus } #endif +#ifdef WIN32 +#include +#else #ifdef UNICODE #define PathFileExists PathFileExistsW #else #define PathFileExists PathFileExistsA #endif +#endif #endif /* WINPR_PATH_H */ diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index 2e9f89f..7571a13 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -50,35 +50,51 @@ WINPR_API BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size); WINPR_API wStream* Stream_New(BYTE* buffer, size_t size); WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); -#define _stream_read_n8(_t, _s, _v, _p) do { _v = \ - (_t)(*_s->pointer); \ - _s->pointer += _p; } while (0) +static INLINE void Stream_Seek(wStream* s, size_t _offset) +{ + s->pointer += (_offset); +} -#define _stream_read_n16_le(_t, _s, _v, _p) do { _v = \ +static INLINE void Stream_Rewind(wStream* s, size_t _offset) +{ + s->pointer -= (_offset); +} + +#define _stream_read_n8(_t, _s, _v, _p) do { \ + _v = \ + (_t)(*_s->pointer); \ + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) + +#define _stream_read_n16_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8); \ - if (_p) _s->pointer += 2; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n16_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n16_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*_s->pointer)) << 8) + \ (_t)(*(_s->pointer + 1)); \ - if (_p) _s->pointer += 2; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n32_le(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n32_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8) + \ (((_t)(*(_s->pointer + 2))) << 16) + \ (((_t)(*(_s->pointer + 3))) << 24); \ - if (_p) _s->pointer += 4; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n32_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n32_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*(_s->pointer))) << 24) + \ (((_t)(*(_s->pointer + 1))) << 16) + \ (((_t)(*(_s->pointer + 2))) << 8) + \ (((_t)(*(_s->pointer + 3)))); \ - if (_p) _s->pointer += 4; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n64_le(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n64_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8) + \ (((_t)(*(_s->pointer + 2))) << 16) + \ @@ -87,9 +103,10 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); (((_t)(*(_s->pointer + 5))) << 40) + \ (((_t)(*(_s->pointer + 6))) << 48) + \ (((_t)(*(_s->pointer + 7))) << 56); \ - if (_p) _s->pointer += 8; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n64_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n64_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*(_s->pointer))) << 56) + \ (((_t)(*(_s->pointer + 1))) << 48) + \ (((_t)(*(_s->pointer + 2))) << 40) + \ @@ -98,102 +115,108 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); (((_t)(*(_s->pointer + 5))) << 16) + \ (((_t)(*(_s->pointer + 6))) << 8) + \ (((_t)(*(_s->pointer + 7)))); \ - if (_p) _s->pointer += 8; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) +#define Stream_Read_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, TRUE) +#define Stream_Read_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, TRUE) -#define Stream_Read_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, 1) -#define Stream_Read_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, 1) +#define Stream_Read_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, TRUE) +#define Stream_Read_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, TRUE) -#define Stream_Read_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, 1) -#define Stream_Read_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, 1) +#define Stream_Read_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, TRUE) +#define Stream_Read_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, TRUE) -#define Stream_Read_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, 1) -#define Stream_Read_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, 1) +#define Stream_Read_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, TRUE) +#define Stream_Read_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, TRUE) -#define Stream_Read_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, 1) -#define Stream_Read_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, 1) +#define Stream_Read_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, TRUE) +#define Stream_Read_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, TRUE) -#define Stream_Read_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, 1) -#define Stream_Read_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, 1) +#define Stream_Read_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, TRUE) +#define Stream_Read_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, TRUE) -#define Stream_Read_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, 1) -#define Stream_Read_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, 1) +#define Stream_Read_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, TRUE) +#define Stream_Read_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, TRUE) -#define Stream_Read_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, 1) -#define Stream_Read_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, 1) +static INLINE void Stream_Read(wStream* _s, void* _b, size_t _n) +{ + memcpy(_b, (_s->pointer), (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Read(_s, _b, _n) do { \ - memcpy(_b, (_s->pointer), (_n)); \ - _s->pointer += (_n); \ - } while (0) +#define Stream_Peek_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, FALSE) +#define Stream_Peek_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, FALSE) +#define Stream_Peek_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, FALSE) +#define Stream_Peek_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, FALSE) -#define Stream_Peek_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, 0) -#define Stream_Peek_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, 0) +#define Stream_Peek_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, FALSE) +#define Stream_Peek_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, FALSE) -#define Stream_Peek_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, 0) -#define Stream_Peek_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, 0) +#define Stream_Peek_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, FALSE) +#define Stream_Peek_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, FALSE) -#define Stream_Peek_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, 0) -#define Stream_Peek_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, 0) +#define Stream_Peek_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, FALSE) +#define Stream_Peek_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, FALSE) -#define Stream_Peek_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, 0) -#define Stream_Peek_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, 0) +#define Stream_Peek_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, FALSE) +#define Stream_Peek_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, FALSE) -#define Stream_Peek_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, 0) -#define Stream_Peek_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, 0) +#define Stream_Peek_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, FALSE) +#define Stream_Peek_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, FALSE) -#define Stream_Peek_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, 0) -#define Stream_Peek_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, 0) +static INLINE void Stream_Peek(wStream* _s, void* _b, size_t _n) +{ + memcpy(_b, (_s->pointer), (_n)); +} -#define Stream_Peek_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, 0) -#define Stream_Peek_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, 0) +static INLINE void Stream_Write_UINT8(wStream* _s, UINT8 _v) +{ + *_s->pointer++ = (UINT8)(_v); +} -#define Stream_Peek(_s, _b, _n) do { \ - memcpy(_b, (_s->pointer), (_n)); \ - } while (0) +static INLINE void Stream_Write_UINT16(wStream* _s, UINT16 _v) +{ + *_s->pointer++ = (_v) & 0xFF; + *_s->pointer++ = ((_v) >> 8) & 0xFF; +} +static INLINE void Stream_Write_UINT16_BE(wStream* _s, UINT16 _v) +{ + *_s->pointer++ = ((_v) >> 8) & 0xFF; + *_s->pointer++ = (_v) & 0xFF; +} -#define Stream_Write_UINT8(_s, _v) do { \ - *_s->pointer++ = (UINT8)(_v); } while (0) +static INLINE void Stream_Write_UINT32(wStream* _s, UINT32 _v) +{ + *_s->pointer++ = (_v) & 0xFF; + *_s->pointer++ = ((_v) >> 8) & 0xFF; + *_s->pointer++ = ((_v) >> 16) & 0xFF; + *_s->pointer++ = ((_v) >> 24) & 0xFF; +} -#define Stream_Write_UINT16(_s, _v) do { \ - *_s->pointer++ = (_v) & 0xFF; \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; } while (0) +static INLINE void Stream_Write_UINT32_BE(wStream* _s, UINT32 _v) +{ + Stream_Write_UINT16_BE(_s, ((_v) >> 16 & 0xFFFF)); + Stream_Write_UINT16_BE(_s, ((_v) & 0xFFFF)); +} -#define Stream_Write_UINT16_BE(_s, _v) do { \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; \ - *_s->pointer++ = (_v) & 0xFF; } while (0) - -#define Stream_Write_UINT32(_s, _v) do { \ - *_s->pointer++ = (_v) & 0xFF; \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; \ - *_s->pointer++ = ((_v) >> 16) & 0xFF; \ - *_s->pointer++ = ((_v) >> 24) & 0xFF; } while (0) - -#define Stream_Write_UINT32_BE(_s, _v) do { \ - Stream_Write_UINT16_BE(_s, ((_v) >> 16 & 0xFFFF)); \ - Stream_Write_UINT16_BE(_s, ((_v) & 0xFFFF)); \ - } while (0) - -#define Stream_Write_UINT64(_s, _v) do { \ - *_s->pointer++ = (UINT64)(_v) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 24) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 32) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 40) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 48) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 56) & 0xFF; } while (0) - -#define Stream_Write(_s, _b, _n) do { \ - memcpy(_s->pointer, (_b), (_n)); \ - _s->pointer += (_n); \ - } while (0) - - -#define Stream_Seek(_s,_offset) _s->pointer += (_offset) -#define Stream_Rewind(_s,_offset) _s->pointer -= (_offset) +static INLINE void Stream_Write_UINT64(wStream* _s, UINT64 _v) +{ + *_s->pointer++ = (UINT64)(_v) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 24) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 32) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 40) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 48) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 56) & 0xFF; +} +static INLINE void Stream_Write(wStream* _s, const void* _b, size_t _n) +{ + memcpy(_s->pointer, (_b), (_n)); + Stream_Seek(_s, _n); +} #define Stream_Seek_UINT8(_s) Stream_Seek(_s, 1) #define Stream_Seek_UINT16(_s) Stream_Seek(_s, 2) @@ -205,45 +228,93 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); #define Stream_Rewind_UINT32(_s) Stream_Rewind(_s, 4) #define Stream_Rewind_UINT64(_s) Stream_Rewind(_s, 8) -#define Stream_Zero(_s, _n) do { \ - memset(_s->pointer, '\0', (_n)); \ - _s->pointer += (_n); \ - } while (0) +static INLINE void Stream_Zero(wStream* _s, size_t _n) +{ + memset(_s->pointer, '\0', (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Fill(_s, _v, _n) do { \ - memset(_s->pointer, _v, (_n)); \ - _s->pointer += (_n); \ - } while (0) +static INLINE void Stream_Fill(wStream* _s, int _v, size_t _n) +{ + memset(_s->pointer, _v, (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Copy(_dst, _src, _n) do { \ - memcpy(_dst->pointer, _src->pointer, _n); \ - _dst->pointer += _n; \ - _src->pointer += _n; \ - } while (0) +static INLINE void Stream_Copy(wStream* _src, wStream* _dst, size_t _n) +{ + memcpy(_dst->pointer, _src->pointer, _n); + Stream_Seek(_dst, _n); + Stream_Seek(_src, _n); +} -#define Stream_Buffer(_s) _s->buffer -#define Stream_GetBuffer(_s, _b) _b = _s->buffer -#define Stream_SetBuffer(_s, _b) _s->buffer = _b +static INLINE BYTE* Stream_Buffer(wStream* _s) +{ + return _s->buffer; +} -#define Stream_Pointer(_s) _s->pointer -#define Stream_GetPointer(_s, _p) _p = _s->pointer -#define Stream_SetPointer(_s, _p) _s->pointer = _p +#define Stream_GetBuffer(_s, _b) _b = Stream_Buffer(_s) +static INLINE void Stream_SetBuffer(wStream* _s, BYTE* _b) +{ + _s->buffer = _b; +} -#define Stream_Length(_s) _s->length -#define Stream_GetLength(_s, _l) _l = _s->length -#define Stream_SetLength(_s, _l) _s->length = _l +static INLINE BYTE* Stream_Pointer(wStream* _s) +{ + return _s->pointer; +} -#define Stream_Capacity(_s) _s->capacity -#define Stream_GetCapacity(_s, _c) _c = _s->capacity -#define Stream_SetCapacity(_s, _c) _s->capacity = _c +#define Stream_GetPointer(_s, _p) _p = Stream_Pointer(_s) +static INLINE void Stream_SetPointer(wStream* _s, BYTE* _p) +{ + _s->pointer = _p; +} -#define Stream_GetPosition(_s) (_s->pointer - _s->buffer) -#define Stream_SetPosition(_s, _p) _s->pointer = _s->buffer + (_p) +static INLINE size_t Stream_Length(wStream* _s) +{ + return _s->length; +} -#define Stream_SealLength(_s) _s->length = (_s->pointer - _s->buffer) -#define Stream_GetRemainingLength(_s) (_s->length - (_s->pointer - _s->buffer)) +#define Stream_GetLength(_s, _l) _l = Stream_Length(_s) +static INLINE void Stream_SetLength(wStream* _s, size_t _l) +{ + _s->length = _l; +} -#define Stream_Clear(_s) memset(_s->buffer, 0, _s->capacity) +static INLINE size_t Stream_Capacity(wStream* _s) +{ + return _s->capacity; +} + +#define Stream_GetCapacity(_s, _c) _c = Stream_Capacity(_s); +static INLINE void Stream_SetCapacity(wStream* _s, size_t _c) +{ + _s->capacity = _c; +} + +static INLINE size_t Stream_GetPosition(wStream* _s) +{ + return (_s->pointer - _s->buffer); +} + +static INLINE void Stream_SetPosition(wStream* _s, size_t _p) +{ + _s->pointer = _s->buffer + (_p); +} + +static INLINE void Stream_SealLength(wStream* _s) +{ + _s->length = (_s->pointer - _s->buffer); +} + +static INLINE size_t Stream_GetRemainingLength(wStream* _s) +{ + return (_s->length - (_s->pointer - _s->buffer)); +} + +static INLINE void Stream_Clear(wStream* _s) +{ + memset(_s->buffer, 0, _s->capacity); +} static INLINE BOOL Stream_SafeSeek(wStream* s, size_t size) { if (Stream_GetRemainingLength(s) < size) diff --git a/winpr/include/winpr/wtypes.h.in b/winpr/include/winpr/wtypes.h.in index 1bfa553..93543f9 100644 --- a/winpr/include/winpr/wtypes.h.in +++ b/winpr/include/winpr/wtypes.h.in @@ -285,7 +285,7 @@ typedef void *PVOID64, *LPVOID64; #if WINPR_HAVE_STDINT_H typedef intptr_t INT_PTR; typedef uintptr_t UINT_PTR; -#elif __x86_64__ +#elif defined (__x86_64__) typedef __int64 INT_PTR; typedef unsigned __int64 UINT_PTR; #else diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index f49cb8d..7c65ad3 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -113,6 +113,7 @@ if (WIN32) @ONLY) set (WINPR_SRCS ${WINPR_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) + list(APPEND WINPR_LIBS "Shlwapi") endif() add_library(${MODULE_NAME} ${WINPR_SRCS}) diff --git a/winpr/libwinpr/crt/test/TestUnicodeConversion.c b/winpr/libwinpr/crt/test/TestUnicodeConversion.c index 559c919..08497bf 100644 --- a/winpr/libwinpr/crt/test/TestUnicodeConversion.c +++ b/winpr/libwinpr/crt/test/TestUnicodeConversion.c @@ -260,7 +260,7 @@ int convert_utf16_to_utf8(BYTE* lpWideCharStr, BYTE* expected_lpMultiByteStr, in return length; } -int test_unicode_uppercasing(BYTE* lower, BYTE* upper) +BOOL test_unicode_uppercasing(BYTE* lower, BYTE* upper) { WCHAR* lowerW = NULL; int lowerLength; @@ -280,13 +280,182 @@ int test_unicode_uppercasing(BYTE* lower, BYTE* upper) printf("Uppercase String:\n"); string_hexdump((BYTE*) upperW, upperLength * 2); - return -1; + return FALSE; } free(lowerW); free(upperW); - return 0; + printf("success\n\n"); + return TRUE; +} + +BOOL test_ConvertFromUnicode_wrapper() +{ + /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */ + WCHAR src1[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T','@','@','@' }; + WCHAR src2[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + CHAR cmp0[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + CHAR* dst = NULL; + int i; + + /* Test unterminated unicode string: + * ConvertFromUnicode must always null-terminate, even if the src string isn't + */ + + printf("Input UTF16 String:\n"); + string_hexdump((BYTE*) src1, 19 * sizeof(WCHAR)); + + i = ConvertFromUnicode(CP_UTF8, 0, src1, 16, &dst, 0, NULL, NULL); + if (i != 16) + { + fprintf(stderr, "ConvertFromUnicode failure A1: unexpectedly returned %d instead of 16\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertFromUnicode failure A2: destination ist NULL\n"); + goto fail; + } + if ((i = strlen(dst)) != 16) + { + fprintf(stderr, "ConvertFromUnicode failure A3: dst length is %d instead of 16\n", i); + goto fail; + } + if (strcmp(dst, cmp0)) + { + fprintf(stderr, "ConvertFromUnicode failure A4: data mismatch\n"); + goto fail; + } + printf("Output UTF8 String:\n"); + string_hexdump((BYTE*) dst, i + 1); + + free(dst); + dst = NULL; + + /* Test null-terminated string */ + + printf("Input UTF16 String:\n"); + string_hexdump((BYTE*) src2, (_wcslen(src2) + 1 ) * sizeof(WCHAR)); + + i = ConvertFromUnicode(CP_UTF8, 0, src2, -1, &dst, 0, NULL, NULL); + if (i != 17) + { + fprintf(stderr, "ConvertFromUnicode failure B1: unexpectedly returned %d instead of 17\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertFromUnicode failure B2: destination ist NULL\n"); + goto fail; + } + if ((i = strlen(dst)) != 16) + { + fprintf(stderr, "ConvertFromUnicode failure B3: dst length is %d instead of 16\n", i); + goto fail; + } + if (strcmp(dst, cmp0)) + { + fprintf(stderr, "ConvertFromUnicode failure B: data mismatch\n"); + goto fail; + } + printf("Output UTF8 String:\n"); + string_hexdump((BYTE*) dst, i + 1); + + free(dst); + dst = NULL; + + printf("success\n\n"); + + return TRUE; + +fail: + free(dst); + return FALSE; +} + +BOOL test_ConvertToUnicode_wrapper() +{ + /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */ + CHAR src1[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T','@','@','@' }; + CHAR src2[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + WCHAR cmp0[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + WCHAR* dst = NULL; + int i; + + /* Test unterminated unicode string: + * ConvertToUnicode must always null-terminate, even if the src string isn't + */ + + printf("Input UTF8 String:\n"); + string_hexdump((BYTE*) src1, 19); + + i = ConvertToUnicode(CP_UTF8, 0, src1, 16, &dst, 0); + if (i != 16) + { + fprintf(stderr, "ConvertToUnicode failure A1: unexpectedly returned %d instead of 16\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertToUnicode failure A2: destination ist NULL\n"); + goto fail; + } + if ((i = _wcslen(dst)) != 16) + { + fprintf(stderr, "ConvertToUnicode failure A3: dst length is %d instead of 16\n", i); + goto fail; + } + if (_wcscmp(dst, cmp0)) + { + fprintf(stderr, "ConvertToUnicode failure A4: data mismatch\n"); + goto fail; + } + printf("Output UTF16 String:\n"); + string_hexdump((BYTE*) dst, (i + 1) * sizeof(WCHAR)); + + free(dst); + dst = NULL; + + /* Test null-terminated string */ + + printf("Input UTF8 String:\n"); + string_hexdump((BYTE*) src2, strlen(src2) + 1); + + i = ConvertToUnicode(CP_UTF8, 0, src2, -1, &dst, 0); + if (i != 17) + { + fprintf(stderr, "ConvertToUnicode failure B1: unexpectedly returned %d instead of 17\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertToUnicode failure B2: destination ist NULL\n"); + goto fail; + } + if ((i = _wcslen(dst)) != 16) + { + fprintf(stderr, "ConvertToUnicode failure B3: dst length is %d instead of 16\n", i); + goto fail; + } + if (_wcscmp(dst, cmp0)) + { + fprintf(stderr, "ConvertToUnicode failure B: data mismatch\n"); + goto fail; + } + printf("Output UTF16 String:\n"); + string_hexdump((BYTE*) dst, (i + 1) * 2); + + free(dst); + dst = NULL; + + printf("success\n\n"); + + return TRUE; + +fail: + free(dst); + return FALSE; } int TestUnicodeConversion(int argc, char* argv[]) @@ -375,7 +544,47 @@ int TestUnicodeConversion(int argc, char* argv[]) printf("Uppercasing\n"); - test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper); + if (!test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper)) + return -1; + /* ConvertFromUnicode */ + + printf("ConvertFromUnicode\n"); + + if (!test_ConvertFromUnicode_wrapper()) + return -1; + + /* ConvertToUnicode */ + + printf("ConvertToUnicode\n"); + + if (!test_ConvertToUnicode_wrapper()) + return -1; +/* + + printf("----------------------------------------------------------\n\n"); + + if (0) + { + BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + //BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 0,0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + //BYTE src[] = { 0,0,'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + char* dst = NULL; + int num; + num = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) src, 16, &dst, 0, NULL, NULL); + printf("ConvertFromUnicode returned %d dst=[%s]\n", num, dst); + string_hexdump((BYTE*)dst, num+1); + } + if (1) + { + char src[] = "RICH TEXT FORMAT@@@@@@"; + WCHAR *dst = NULL; + int num; + num = ConvertToUnicode(CP_UTF8, 0, src, 16, &dst, 0); + printf("ConvertToUnicode returned %d dst=%p\n", num, dst); + string_hexdump((BYTE*)dst, num * 2 + 2); + + } +*/ return 0; } diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index fc5134f..0816fe0 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -276,6 +276,19 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int #endif +/** + * ConvertToUnicode is a convenience wrapper for MultiByteToWideChar: + * + * If the lpWideCharStr prarameter for the converted string points to NULL + * or if the cchWideChar parameter is set to 0 this function will automatically + * allocate the required memory which is guaranteed to be null-terminated + * after the conversion, even if the source c string isn't. + * + * If the cbMultiByte parameter is set to -1 the passed lpMultiByteStr must + * be null-terminated and the required length for the converted string will be + * calculated accordingly. + */ + int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR* lpWideCharStr, int cchWideChar) { @@ -305,7 +318,7 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, if (allocate) { - *lpWideCharStr = (LPWSTR) calloc(cchWideChar, sizeof(WCHAR)); + *lpWideCharStr = (LPWSTR) calloc(cchWideChar + 1, sizeof(WCHAR)); if (!(*lpWideCharStr)) { @@ -317,11 +330,31 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar); if (status != cchWideChar) + { + if (allocate) + { + free(*lpWideCharStr); + *lpWideCharStr = NULL; + } status = 0; + } return status; } +/** + * ConvertFromUnicode is a convenience wrapper for WideCharToMultiByte: + * + * If the lpMultiByteStr parameter for the converted string points to NULL + * or if the cbMultiByte parameter is set to 0 this function will automatically + * allocate the required memory which is guaranteed to be null-terminated + * after the conversion, even if the source unicode string isn't. + * + * If the cchWideChar parameter is set to -1 the passed lpWideCharStr must + * be null-terminated and the required length for the converted string will be + * calculated accordingly. + */ + int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar) { diff --git a/winpr/libwinpr/crypto/crypto.c b/winpr/libwinpr/crypto/crypto.c index 4729a76..144222a 100644 --- a/winpr/libwinpr/crypto/crypto.c +++ b/winpr/libwinpr/crypto/crypto.c @@ -150,7 +150,7 @@ BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) { BYTE* pCipherText; size_t cbOut, cbFinal; - WINPR_CIPHER_CTX* enc; + WINPR_CIPHER_CTX* enc = NULL; BYTE randomKey[256]; WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock; diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 862703b..4af0cb6 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include static BOOL FileIsHandled(HANDLE handle) { @@ -346,6 +348,128 @@ static BOOL FileUnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfByte return TRUE; } +static BOOL FileSetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime) +{ + int rc; +#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) + struct stat buf; +#endif +/* OpenBSD, NetBSD and DragonflyBSD support POSIX futimens */ +#if defined(ANDROID) || defined(__FreeBSD__) + struct timeval timevals[2]; +#else + struct timespec times[2]; /* last access, last modification */ +#endif + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + const UINT64 EPOCH_DIFF = 11644473600ULL; + + if (!hFile) + return FALSE; + +#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) + rc = fstat(fileno(pFile->fp), &buf); + if (rc < 0) + return FALSE; +#endif + if (!lpLastAccessTime) + { +#if defined(__APPLE__) +#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) + times[0] = buf.st_atimespec; +#else + times[0].tv_sec = buf.st_atime; + times[0].tv_nsec = buf.st_atimensec; +#endif +#elif defined(__FreeBSD__) + timevals[0].tv_sec = buf.st_atime; +#ifdef _POSIX_SOURCE + TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atim); +#else + TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atimespec); +#endif +#elif defined(ANDROID) + timevals[0].tv_sec = buf.st_atime; + timevals[0].tv_usec = buf.st_atimensec / 1000UL; +#else + times[0].tv_sec = UTIME_OMIT; + times[0].tv_nsec = UTIME_OMIT; +#endif + } + else + { + UINT64 tmp = ((UINT64)lpLastAccessTime->dwHighDateTime) << 32 + | lpLastAccessTime->dwLowDateTime; + tmp -= EPOCH_DIFF; + tmp /= 10ULL; + +#if defined(ANDROID) || defined(__FreeBSD__) + tmp /= 10000ULL; + + timevals[0].tv_sec = tmp / 10000ULL; + timevals[0].tv_usec = tmp % 10000ULL; +#else + times[0].tv_sec = tmp / 10000000ULL; + times[0].tv_nsec = tmp % 10000000ULL; +#endif + } + if (!lpLastWriteTime) + { +#ifdef __APPLE__ +#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) + times[1] = buf.st_mtimespec; +#else + times[1].tv_sec = buf.st_mtime; + times[1].tv_nsec = buf.st_mtimensec; +#endif +#elif defined(__FreeBSD__) + timevals[1].tv_sec = buf.st_mtime; +#ifdef _POSIX_SOURCE + TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtim); +#else + TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtimespec); +#endif +#elif defined(ANDROID) + timevals[1].tv_sec = buf.st_mtime; + timevals[1].tv_usec = buf.st_mtimensec / 1000UL; +#else + times[1].tv_sec = UTIME_OMIT; + times[1].tv_nsec = UTIME_OMIT; +#endif + } + else + { + UINT64 tmp = ((UINT64)lpLastWriteTime->dwHighDateTime) << 32 + | lpLastWriteTime->dwLowDateTime; + tmp -= EPOCH_DIFF; + tmp /= 10ULL; + +#if defined(ANDROID) || defined(__FreeBSD__) + tmp /= 10000ULL; + + timevals[1].tv_sec = tmp / 10000ULL; + timevals[1].tv_usec = tmp % 10000ULL; +#else + times[1].tv_sec = tmp / 10000000ULL; + times[1].tv_nsec = tmp % 10000000ULL; +#endif + } + + // TODO: Creation time can not be handled! +#ifdef __APPLE__ + rc = futimes(fileno(pFile->fp), times); +#elif defined(ANDROID) || defined(__FreeBSD__) + rc = utimes(pFile->lpFileName, timevals); +#else + rc = futimens(fileno(pFile->fp), times); +#endif + if (rc != 0) + return FALSE; + + return TRUE; + +} + static HANDLE_OPS fileOps = { FileIsHandled, FileCloseHandle, @@ -365,7 +489,8 @@ static HANDLE_OPS fileOps = { NULL, /* FileLockFile */ FileLockFileEx, FileUnlockFile, - FileUnlockFileEx + FileUnlockFileEx, + FileSetFileTime }; static HANDLE_OPS shmOps = { @@ -387,8 +512,8 @@ static HANDLE_OPS shmOps = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ - + NULL, /* FileUnlockFileEx */ + NULL /* FileSetFileTime */ }; @@ -507,7 +632,7 @@ BOOL IsFileDevice(LPCTSTR lpDeviceName) return TRUE; } -HANDLE_CREATOR _FileHandleCreator = +HANDLE_CREATOR _FileHandleCreator = { IsFileDevice, FileCreateFileA diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 8719787..96d3c12 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -37,8 +37,10 @@ #include "../log.h" #define TAG WINPR_TAG("file") -#ifndef _WIN32 - +#ifdef _WIN32 +#include +#include +#else #include #include #include @@ -274,7 +276,7 @@ HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSTR lpFileNameA = NULL; HANDLE hdl; - if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1) return NULL; hdl= CreateFileA(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes, @@ -296,7 +298,7 @@ BOOL DeleteFileW(LPCWSTR lpFileName) LPSTR lpFileNameA = NULL; BOOL rc = FALSE; - if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1) return FALSE; rc = DeleteFileA(lpFileNameA); free (lpFileNameA); @@ -623,6 +625,27 @@ BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLo return FALSE; } +BOOL WINAPI SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime) +{ + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->SetFileTime) + return handle->ops->SetFileTime(handle, lpCreationTime, + lpLastAccessTime, lpLastWriteTime); + + WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__); + return FALSE; +} + struct _WIN32_FILE_SEARCH { DIR* pDir; @@ -828,6 +851,20 @@ int UnixChangeFileMode(const char* filename, int flags) fl |= (flags & 0x0001) ? S_IXOTH : 0; return chmod(filename, fl); #else - return 0; + int rc; + WCHAR *wfl = NULL; + + int fl = 0; + + if (ConvertToUnicode(CP_UTF8, 0, filename, -1, &wfl, 0) <= 0) + return -1; + + /* Check for unsupported flags. */ + if (flags & ~(_S_IREAD | _S_IWRITE) != 0) + WLog_WARN(TAG, "Unsupported file mode %d for _wchmod", flags); + + rc = _wchmod(wfl, flags); + free (wfl); + return rc; #endif } diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c index b78f8eb..a318c94 100644 --- a/winpr/libwinpr/file/namedPipeClient.c +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -51,14 +51,14 @@ static HANDLE_CREATOR _NamedPipeClientHandleCreator; static BOOL NamedPipeClientIsHandled(HANDLE handle) { - WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; + WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; - if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - return TRUE; + if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + return TRUE; } BOOL NamedPipeClientCloseHandle(HANDLE handle) @@ -124,7 +124,8 @@ static HANDLE_OPS ops = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ + NULL, /* FileUnlockFileEx */ + NULL /* SetFileTime */ }; static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index d2669ba..fc49e64 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -77,6 +77,8 @@ typedef BOOL (*pcUnlockFile)(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOf DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh); typedef BOOL (*pcUnlockFileEx)(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); +typedef BOOL (*pcSetFileTime)(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime); typedef struct _HANDLE_OPS { @@ -99,6 +101,7 @@ typedef struct _HANDLE_OPS pcLockFileEx LockFileEx; pcUnlockFile UnlockFile; pcUnlockFileEx UnlockFileEx; + pcSetFileTime SetFileTime; } HANDLE_OPS; struct winpr_handle diff --git a/winpr/libwinpr/path/shell.c b/winpr/libwinpr/path/shell.c index b35f629..84ffcdc 100644 --- a/winpr/libwinpr/path/shell.c +++ b/winpr/libwinpr/path/shell.c @@ -481,6 +481,7 @@ BOOL PathMakePathA(LPCSTR path, LPSECURITY_ATTRIBUTES lpAttributes) return PathFileExistsA(path); } +#ifndef WIN32 BOOL PathFileExistsA(LPCSTR pszPath) { struct stat stat_info; @@ -495,4 +496,4 @@ BOOL PathFileExistsW(LPCWSTR pszPath) { return FALSE; } - +#endif diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 02beb5d..0d8a6b6 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -191,7 +191,8 @@ static HANDLE_OPS ops = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ + NULL, /* FileUnlockFileEx */ + NULL /* SetFileTime */ }; diff --git a/winpr/libwinpr/timezone/timezone.c b/winpr/libwinpr/timezone/timezone.c index 79cb6f3..f534033 100644 --- a/winpr/libwinpr/timezone/timezone.c +++ b/winpr/libwinpr/timezone/timezone.c @@ -32,6 +32,7 @@ #include #include + struct _TIME_ZONE_RULE_ENTRY { UINT64 TicksStart; @@ -45,7 +46,7 @@ typedef struct _TIME_ZONE_RULE_ENTRY TIME_ZONE_RULE_ENTRY; struct _TIME_ZONE_ENTRY { const char* Id; - UINT32 Bias; + INT32 Bias; BOOL SupportsDST; const char* DisplayName; const char* StandardName; @@ -57,521 +58,600 @@ typedef struct _TIME_ZONE_ENTRY TIME_ZONE_ENTRY; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_3[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_4[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_5[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_7[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_8[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_10[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_11[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_14[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_15[] = { - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_16[] = +{ + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_17[] = { - { 633662964000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } + { 633031380000000000ULL, 180000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_18[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633662964000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 2, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 2, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 4, 6, 2, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 3, 6, 4, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 3, 6, 4, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 3, 6, 3, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 3, 6, 5, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 3, 6, 5, 23, 59 }, { 0, 9, 6, 5, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 3, 6, 4, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 3, 6, 4, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 3, 6, 3, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 3, 6, 5, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_19[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_21[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_20[] = { - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 5, 6, 1, 23, 59 }, { 0, 8, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 2, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 5, 0, 0 }, { 0, 10, 0, 2, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 3, 0, 0 }, { 0, 10, 6, 3, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 2, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 2, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_22[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 1 }, { 0, 4, 0, 1, 0, 1 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 0, 1 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 0, 1 }, { 0, 4, 0, 1, 0, 1 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 2, 0, 1 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 2, 0, 1 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 2, 0, 1 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 2, 0, 1 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 0, 1 }, }, + { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 2, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_23[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 2, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 5, 0, 0 }, { 0, 10, 0, 2, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 3, 0, 0 }, { 0, 10, 6, 3, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 2, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 2, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, }, + { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 3, 23, 59 }, { 0, 10, 6, 3, 23, 59 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_24[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_25[] = { - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 1, 1, 1, 0, 0 }, { 0, 12, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 1, 4, 1, 0, 0 }, } + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 1, 1, 1, 0, 0 }, { 0, 12, 0, 5, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 3, 0, 0 }, { 0, 10, 6, 3, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 2, 23, 59 }, { 0, 1, 4, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_26[] = { - { 633662964000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, } + { 633662964000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 4, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 4, 22, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 4, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 4, 22, 0 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 4, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 5, 23, 0 }, { 0, 3, 6, 5, 22, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_27[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 9, 0, 2, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 3, 0, 2, 2, 0 }, { 0, 1, 4, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_28[] = { - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 10, 6, 3, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 4, 23, 59 }, { 0, 1, 0, 1, 0, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_30[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_29[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 2, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 6, 5, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 2, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 2, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 5, 6, 1, 23, 59 }, { 0, 8, 6, 3, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 4, 6, 5, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 4, 6, 5, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 4, 6, 5, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_31[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 9, 0, 5, 2, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_33[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_32[] = { - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 0, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 5, 0, 1, 23, 59 }, }, + { 634609044000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 0, 5, 1, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 3155378292000000000ULL, 634926132000000000ULL, 60, { 0, 10, 0, 5, 1, 0 }, { 0, 3, 0, 5, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_34[] = +{ + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 0, 5, 23, 59 }, { 0, 5, 6, 5, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 3, 23, 59 }, { 0, 5, 0, 5, 23, 59 }, }, { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 8, 6, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 7, 6, 1, 23, 59 }, { 0, 4, 6, 1, 23, 59 }, } + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 7, 6, 5, 23, 59 }, { 0, 4, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 0, 5, 3, 0 }, { 0, 4, 0, 5, 2, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 4, 0, 5, 2, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 3155378292000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_35[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_36[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 0, 1, 1, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_37[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 0, 5, 1, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_38[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_39[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_40[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_42[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_41[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_43[] = { { 634293684000000000ULL, 180000000000ULL, -60, { 0, 9, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_43[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 5, 1, 1, 0 }, { 0, 3, 4, 1, 0, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 10, 5, 1, 1, 0 }, { 0, 3, 4, 1, 23, 59 }, } -}; - static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_44[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 5, 5, 1, 0 }, { 0, 3, 4, 5, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 1, 0, 1, 0, 0 }, { 0, 3, 4, 5, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 12, 5, 3, 0, 0 }, { 0, 1, 2, 1, 0, 0 }, }, + { 3155378292000000000ULL, 635241492000000000ULL, 60, { 0, 10, 5, 5, 1, 0 }, { 0, 3, 4, 5, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_45[] = { - { 633978324000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 0 }, { 0, 3, 0, 1, 0, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_46[] = { - { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } + { 633978324000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 0, 0 }, { 0, 3, 0, 5, 0, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 4, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 4, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 4, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 4, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 3, 6, 5, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_47[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 3, 1, 23, 59 }, { 0, 3, 5, 1, 23, 59 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 3155378292000000000ULL, 636188436000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } + { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 4, 5, 23, 59 }, { 0, 4, 5, 5, 0, 0 }, }, + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 9, 4, 3, 23, 59 }, { 0, 4, 5, 5, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 5, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 4, 5, 23, 59 }, { 0, 4, 4, 5, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 3, 23, 59 }, { 0, 4, 4, 4, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 4, 5, 23, 59 }, { 0, 4, 4, 5, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 9, 4, 5, 23, 59 }, { 0, 5, 4, 3, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_48[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 3, 3, 23, 59 }, { 0, 3, 5, 5, 23, 59 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 4, 1, 23, 59 }, { 0, 3, 4, 5, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 3, 4, 5, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 3, 4, 5, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 3, 4, 5, 23, 59 }, }, + { 3155378292000000000ULL, 636188436000000000ULL, 60, { 0, 10, 4, 5, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_49[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_50[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 1, 1, 3, 0 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_51[] = { - { 632716020000000000ULL, 632401524000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_52[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 1, 5, 3, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 1, 5, 3, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 11, 0, 2, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, }, + { 3155378292000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 5, 4, 0 }, { 0, 3, 0, 5, 3, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_53[] = +{ + { 632716020000000000ULL, 632401524000000000ULL, 60, { 0, 10, 0, 2, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 0, 3, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 9, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 0, 2, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 0, 4, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 4, 2, 0 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 4, 2, 0 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 5, 2, 0 }, }, + { 3155378292000000000ULL, 638081460000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 3, 5, 4, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_54[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_55[] = +{ + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 11, 6, 2, 2, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 1, 2, 1, 0, 0 }, { 0, 3, 5, 5, 1, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_56[] = { { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, }, { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 10, 1, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_54[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_58[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_57[] = -{ - { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 2, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 9, 6, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 3155378292000000000ULL, 633663828000000000ULL, 60, { 0, 9, 1, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_59[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 5, 0 }, { 0, 3, 0, 1, 4, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_60[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_61[] = { - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 1, 2, 1, 0, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 1, 4, 1, 0, 0 }, } + { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 2, 4, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 9, 6, 3, 23, 59 }, { 0, 3, 4, 3, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 9, 1, 3, 23, 59 }, { 0, 3, 6, 3, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 9, 2, 3, 23, 59 }, { 0, 3, 0, 3, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 9, 4, 3, 23, 59 }, { 0, 3, 2, 3, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 9, 5, 3, 23, 59 }, { 0, 3, 3, 3, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 9, 6, 3, 23, 59 }, { 0, 3, 4, 3, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 9, 0, 3, 23, 59 }, { 0, 3, 5, 3, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 9, 2, 3, 23, 59 }, { 0, 3, 0, 3, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 9, 3, 3, 23, 59 }, { 0, 3, 1, 3, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 9, 4, 3, 23, 59 }, { 0, 3, 2, 3, 23, 59 }, }, + { 3155378292000000000ULL, 638396820000000000ULL, 60, { 0, 9, 5, 3, 23, 59 }, { 0, 3, 3, 3, 23, 59 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_63[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 5, 0 }, { 0, 3, 0, 5, 4, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_65[] = { - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 4, 2, 1, 23, 59 }, } + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 1, 2, 1, 0, 0 }, { 0, 10, 0, 5, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 5, 2, 0 }, { 0, 1, 4, 1, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_67[] = +{ + { 634609044000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_70[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_71[] = { - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 12, 4, 1, 23, 59 }, { 0, 6, 5, 1, 23, 0 }, } + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 5, 23, 59 }, { 0, 5, 6, 5, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 5, 23, 59 }, { 0, 4, 2, 2, 23, 59 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_72[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_76[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_75[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 12, 4, 5, 23, 59 }, { 0, 6, 5, 3, 23, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_77[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_79[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_80[] = { - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 1, 0, 1, 0, 0 }, { 0, 12, 0, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 1, 4, 1, 0, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_82[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_85[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_84[] = { - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 1, 0, 1, 0, 0 }, { 0, 12, 0, 1, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 5, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 5, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 1, 4, 1, 0, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_88[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_86[] = { - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } + { 3155378292000000000ULL, 635556852000000000ULL, 60, { 0, 9, 5, 5, 23, 59 }, { 0, 3, 6, 5, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_90[] = { - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_91[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_93[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 5, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_94[] = { - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, } + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 5, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_96[] = { - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 1, 4, 1, 0, 0 }, { 0, 11, 0, 1, 2, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 1, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 634926132000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_97[] = { - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 120, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_98[] = { - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 3, 0, 5, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 0, 5, 2, 0 }, { 0, 1, 3, 1, 0, 0 }, } }; -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_100[] = +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_102[] = { - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 1, 5, 1, 0, 0 }, { 0, 9, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 1, 0 }, { 0, 9, 0, 1, 0, 0 }, } + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 3, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 3, 3, 0 }, { 0, 9, 0, 5, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 9, 0, 5, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_104[] = +{ + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 1, 4, 1, 0, 0 }, { 0, 11, 0, 5, 2, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 3, 0, 5, 3, 0 }, { 0, 10, 0, 4, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 4, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 1, 0, 4, 3, 0 }, { 0, 10, 0, 3, 2, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 1, 0, 3, 3, 0 }, { 0, 10, 0, 4, 2, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 1, 0, 3, 2, 0 }, { 0, 11, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 635556852000000000ULL, 60, { 0, 1, 0, 3, 3, 0 }, { 0, 11, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_105[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 5, 3, 0 }, { 0, 3, 0, 5, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_107[] = +{ + { 633978324000000000ULL, 180000000000ULL, 0, { 0, 1, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 1, 5, 1, 0, 0 }, { 0, 9, 6, 5, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 1, 0 }, { 0, 9, 0, 5, 0, 0 }, }, + { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 4, 0, 1, 1, 0 }, { 0, 9, 0, 5, 0, 0 }, } }; static const TIME_ZONE_ENTRY TimeZoneTable[] = @@ -582,169 +662,174 @@ static const TIME_ZONE_ENTRY TimeZoneTable[] = NULL, 0 }, { - "UTC-11", 780, FALSE, "(UTC-11:00) Coordinated Universal Time-11", + "UTC-11", 660, FALSE, "(UTC-11:00) Coordinated Universal Time-11", "UTC-11", "UTC-11", NULL, 0 }, { - "Hawaiian Standard Time", 840, FALSE, "(UTC-10:00) Hawaii", + "Hawaiian Standard Time", 600, FALSE, "(UTC-10:00) Hawaii", "Hawaiian Standard Time", "Hawaiian Daylight Time", NULL, 0 }, { - "Alaskan Standard Time", 900, TRUE, "(UTC-09:00) Alaska", + "Alaskan Standard Time", 540, TRUE, "(UTC-09:00) Alaska", "Alaskan Standard Time", "Alaskan Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_3, 2 }, { - "Pacific Standard Time (Mexico)", 960, TRUE, "(UTC-08:00) Baja California", + "Pacific Standard Time (Mexico)", 480, TRUE, "(UTC-08:00) Baja California", "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_4, 1 }, { - "Pacific Standard Time", 960, TRUE, "(UTC-08:00) Pacific Time (US & Canada)", + "Pacific Standard Time", 480, TRUE, "(UTC-08:00) Pacific Time (US & Canada)", "Pacific Standard Time", "Pacific Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_5, 2 }, { - "US Mountain Standard Time", 1020, FALSE, "(UTC-07:00) Arizona", + "US Mountain Standard Time", 420, FALSE, "(UTC-07:00) Arizona", "US Mountain Standard Time", "US Mountain Daylight Time", NULL, 0 }, { - "Mountain Standard Time (Mexico)", 1020, TRUE, "(UTC-07:00) Chihuahua, La Paz, Mazatlan", + "Mountain Standard Time (Mexico)", 420, TRUE, "(UTC-07:00) Chihuahua, La Paz, Mazatlan", "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_7, 1 }, { - "Mountain Standard Time", 1020, TRUE, "(UTC-07:00) Mountain Time (US & Canada)", + "Mountain Standard Time", 420, TRUE, "(UTC-07:00) Mountain Time (US & Canada)", "Mountain Standard Time", "Mountain Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_8, 2 }, { - "Central America Standard Time", 1080, FALSE, "(UTC-06:00) Central America", + "Central America Standard Time", 360, FALSE, "(UTC-06:00) Central America", "Central America Standard Time", "Central America Daylight Time", NULL, 0 }, { - "Central Standard Time", 1080, TRUE, "(UTC-06:00) Central Time (US & Canada)", + "Central Standard Time", 360, TRUE, "(UTC-06:00) Central Time (US & Canada)", "Central Standard Time", "Central Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_10, 2 }, { - "Central Standard Time (Mexico)", 1080, TRUE, "(UTC-06:00) Guadalajara, Mexico City, Monterrey", + "Central Standard Time (Mexico)", 360, TRUE, "(UTC-06:00) Guadalajara, Mexico City, Monterrey", "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_11, 1 }, { - "Canada Central Standard Time", 1080, FALSE, "(UTC-06:00) Saskatchewan", + "Canada Central Standard Time", 360, FALSE, "(UTC-06:00) Saskatchewan", "Canada Central Standard Time", "Canada Central Daylight Time", NULL, 0 }, { - "SA Pacific Standard Time", 1140, FALSE, "(UTC-05:00) Bogota, Lima, Quito", + "SA Pacific Standard Time", 300, FALSE, "(UTC-05:00) Bogota, Lima, Quito, Rio Branco", "SA Pacific Standard Time", "SA Pacific Daylight Time", NULL, 0 }, { - "Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Eastern Time (US & Canada)", - "Eastern Standard Time", "Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_14, 2 - }, - { - "US Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Indiana (East)", - "US Eastern Standard Time", "US Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_15, 2 - }, - { - "Venezuela Standard Time", 1170, FALSE, "(UTC-04:30) Caracas", - "Venezuela Standard Time", "Venezuela Daylight Time", + "Eastern Standard Time (Mexico)", 300, FALSE, "(UTC-05:00) Chetumal", + "Eastern Standard Time (Mexico)", "Eastern Daylight Time (Mexico)", NULL, 0 }, { - "Paraguay Standard Time", 1200, TRUE, "(UTC-04:00) Asuncion", + "Eastern Standard Time", 300, TRUE, "(UTC-05:00) Eastern Time (US & Canada)", + "Eastern Standard Time", "Eastern Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_15, 2 + }, + { + "US Eastern Standard Time", 300, TRUE, "(UTC-05:00) Indiana (East)", + "US Eastern Standard Time", "US Eastern Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_16, 2 + }, + { + "Venezuela Standard Time", 270, TRUE, "(UTC-04:30) Caracas", + "Venezuela Standard Time", "Venezuela Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_17, 1 + }, + { + "Paraguay Standard Time", 240, TRUE, "(UTC-04:00) Asuncion", "Paraguay Standard Time", "Paraguay Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_17, 14 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_18, 14 }, { - "Atlantic Standard Time", 1200, TRUE, "(UTC-04:00) Atlantic Time (Canada)", + "Atlantic Standard Time", 240, TRUE, "(UTC-04:00) Atlantic Time (Canada)", "Atlantic Standard Time", "Atlantic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_18, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_19, 2 }, { - "Central Brazilian Standard Time", 1200, TRUE, "(UTC-04:00) Cuiaba", + "Central Brazilian Standard Time", 240, TRUE, "(UTC-04:00) Cuiaba", "Central Brazilian Standard Time", "Central Brazilian Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_19, 35 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_20, 35 }, { - "SA Western Standard Time", 1200, FALSE, "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", + "SA Western Standard Time", 240, FALSE, "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", "SA Western Standard Time", "SA Western Daylight Time", NULL, 0 }, { - "Pacific SA Standard Time", 1200, TRUE, "(UTC-04:00) Santiago", - "Pacific SA Standard Time", "Pacific SA Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_21, 6 - }, - { - "Newfoundland Standard Time", 1230, TRUE, "(UTC-03:30) Newfoundland", + "Newfoundland Standard Time", 210, TRUE, "(UTC-03:30) Newfoundland", "Newfoundland Standard Time", "Newfoundland Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_22, 7 }, { - "E. South America Standard Time", 1260, TRUE, "(UTC-03:00) Brasilia", + "E. South America Standard Time", 180, TRUE, "(UTC-03:00) Brasilia", "E. South America Standard Time", "E. South America Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_23, 35 }, { - "Argentina Standard Time", 1260, TRUE, "(UTC-03:00) Buenos Aires", - "Argentina Standard Time", "Argentina Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_24, 3 - }, - { - "SA Eastern Standard Time", 1260, FALSE, "(UTC-03:00) Cayenne, Fortaleza", + "SA Eastern Standard Time", 180, FALSE, "(UTC-03:00) Cayenne, Fortaleza", "SA Eastern Standard Time", "SA Eastern Daylight Time", NULL, 0 }, { - "Greenland Standard Time", 1260, TRUE, "(UTC-03:00) Greenland", + "Argentina Standard Time", 180, TRUE, "(UTC-03:00) City of Buenos Aires", + "Argentina Standard Time", "Argentina Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_25, 3 + }, + { + "Greenland Standard Time", 180, TRUE, "(UTC-03:00) Greenland", "Greenland Standard Time", "Greenland Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_26, 14 }, { - "Montevideo Standard Time", 1260, TRUE, "(UTC-03:00) Montevideo", + "Montevideo Standard Time", 180, TRUE, "(UTC-03:00) Montevideo", "Montevideo Standard Time", "Montevideo Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_27, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_27, 10 }, { - "Bahia Standard Time", 1260, TRUE, "(UTC-03:00) Salvador", + "Bahia Standard Time", 180, TRUE, "(UTC-03:00) Salvador", "Bahia Standard Time", "Bahia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_28, 30 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_28, 2 }, { - "UTC-02", 1320, FALSE, "(UTC-02:00) Coordinated Universal Time-02", + "Pacific SA Standard Time", 180, TRUE, "(UTC-03:00) Santiago", + "Pacific SA Standard Time", "Pacific SA Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_29, 8 + }, + { + "UTC-02", 120, FALSE, "(UTC-02:00) Coordinated Universal Time-02", "UTC-02", "UTC-02", NULL, 0 }, { - "Mid-Atlantic Standard Time", 1320, TRUE, "(UTC-02:00) Mid-Atlantic", + "Mid-Atlantic Standard Time", 120, TRUE, "(UTC-02:00) Mid-Atlantic - Old", "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_30, 1 - }, - { - "Azores Standard Time", 1380, TRUE, "(UTC-01:00) Azores", - "Azores Standard Time", "Azores Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_31, 1 }, { - "Cape Verde Standard Time", 1380, FALSE, "(UTC-01:00) Cape Verde Is.", - "Cape Verde Standard Time", "Cape Verde Daylight Time", + "Azores Standard Time", 60, TRUE, "(UTC-01:00) Azores", + "Azores Standard Time", "Azores Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_32, 3 + }, + { + "Cape Verde Standard Time", 60, FALSE, "(UTC-01:00) Cabo Verde Is.", + "Cabo Verde Standard Time", "Cabo Verde Daylight Time", NULL, 0 }, { "Morocco Standard Time", 0, TRUE, "(UTC) Casablanca", "Morocco Standard Time", "Morocco Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_33, 4 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_34, 9 }, { "UTC", 0, FALSE, "(UTC) Coordinated Universal Time", @@ -754,7 +839,7 @@ static const TIME_ZONE_ENTRY TimeZoneTable[] = { "GMT Standard Time", 0, TRUE, "(UTC) Dublin, Edinburgh, Lisbon, London", "GMT Standard Time", "GMT Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_35, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_36, 1 }, { "Greenwich Standard Time", 0, FALSE, "(UTC) Monrovia, Reykjavik", @@ -762,324 +847,359 @@ static const TIME_ZONE_ENTRY TimeZoneTable[] = NULL, 0 }, { - "W. Europe Standard Time", 60, TRUE, "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", + "W. Europe Standard Time", -60, TRUE, "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", "W. Europe Standard Time", "W. Europe Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_37, 1 - }, - { - "Central Europe Standard Time", 60, TRUE, "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", - "Central Europe Standard Time", "Central Europe Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_38, 1 }, { - "Romance Standard Time", 60, TRUE, "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", - "Romance Standard Time", "Romance Daylight Time", + "Central Europe Standard Time", -60, TRUE, "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", + "Central Europe Standard Time", "Central Europe Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_39, 1 }, { - "Central European Standard Time", 60, TRUE, "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", - "Central European Standard Time", "Central European Daylight Time", + "Romance Standard Time", -60, TRUE, "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", + "Romance Standard Time", "Romance Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_40, 1 }, { - "W. Central Africa Standard Time", 60, FALSE, "(UTC+01:00) West Central Africa", + "Central European Standard Time", -60, TRUE, "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", + "Central European Standard Time", "Central European Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_41, 1 + }, + { + "W. Central Africa Standard Time", -60, FALSE, "(UTC+01:00) West Central Africa", "W. Central Africa Standard Time", "W. Central Africa Daylight Time", NULL, 0 }, { - "Namibia Standard Time", 60, TRUE, "(UTC+01:00) Windhoek", + "Namibia Standard Time", -60, TRUE, "(UTC+01:00) Windhoek", "Namibia Standard Time", "Namibia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_42, 2 - }, - { - "Jordan Standard Time", 120, TRUE, "(UTC+02:00) Amman", - "Jordan Standard Time", "Jordan Daylight Time", (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_43, 2 }, { - "GTB Standard Time", 120, TRUE, "(UTC+02:00) Athens, Bucharest, Istanbul", + "Jordan Standard Time", -120, TRUE, "(UTC+02:00) Amman", + "Jordan Standard Time", "Jordan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_44, 9 + }, + { + "GTB Standard Time", -120, TRUE, "(UTC+02:00) Athens, Bucharest", "GTB Standard Time", "GTB Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_44, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_45, 1 }, { - "Middle East Standard Time", 120, TRUE, "(UTC+02:00) Beirut", + "Middle East Standard Time", -120, TRUE, "(UTC+02:00) Beirut", "Middle East Standard Time", "Middle East Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_45, 13 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_46, 13 }, { - "Egypt Standard Time", 120, TRUE, "(UTC+02:00) Cairo", + "Egypt Standard Time", -120, TRUE, "(UTC+02:00) Cairo", "Egypt Standard Time", "Egypt Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_46, 6 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_47, 7 }, { - "Syria Standard Time", 120, TRUE, "(UTC+02:00) Damascus", + "Syria Standard Time", -120, TRUE, "(UTC+02:00) Damascus", "Syria Standard Time", "Syria Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_47, 12 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_48, 12 }, { - "South Africa Standard Time", 120, FALSE, "(UTC+02:00) Harare, Pretoria", + "E. Europe Standard Time", -120, TRUE, "(UTC+02:00) E. Europe", + "E. Europe Standard Time", "E. Europe Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_49, 1 + }, + { + "South Africa Standard Time", -120, FALSE, "(UTC+02:00) Harare, Pretoria", "South Africa Standard Time", "South Africa Daylight Time", NULL, 0 }, { - "FLE Standard Time", 120, TRUE, "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", + "FLE Standard Time", -120, TRUE, "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", "FLE Standard Time", "FLE Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_49, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_51, 1 }, { - "Turkey Standard Time", 120, TRUE, "(UTC+02:00) Istanbul", + "Turkey Standard Time", -120, TRUE, "(UTC+02:00) Istanbul", "Turkey Standard Time", "Turkey Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_50, 3 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_52, 7 }, { - "Israel Standard Time", 120, TRUE, "(UTC+02:00) Jerusalem", + "Israel Standard Time", -120, TRUE, "(UTC+02:00) Jerusalem", "Jerusalem Standard Time", "Jerusalem Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_51, 18 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_53, 19 }, { - "E. Europe Standard Time", 120, TRUE, "(UTC+02:00) Nicosia", - "E. Europe Standard Time", "E. Europe Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_52, 1 + "Kaliningrad Standard Time", -120, TRUE, "(UTC+02:00) Kaliningrad (RTZ 1)", + "Russia TZ 1 Standard Time", "Russia TZ 1 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_54, 5 }, { - "Arabic Standard Time", 180, TRUE, "(UTC+03:00) Baghdad", + "Libya Standard Time", -120, TRUE, "(UTC+02:00) Tripoli", + "Libya Standard Time", "Libya Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_55, 2 + }, + { + "Arabic Standard Time", -180, TRUE, "(UTC+03:00) Baghdad", "Arabic Standard Time", "Arabic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_53, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_56, 2 }, { - "Kaliningrad Standard Time", 180, TRUE, "(UTC+03:00) Kaliningrad, Minsk", - "Kaliningrad Standard Time", "Kaliningrad Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_54, 1 - }, - { - "Arab Standard Time", 180, FALSE, "(UTC+03:00) Kuwait, Riyadh", + "Arab Standard Time", -180, FALSE, "(UTC+03:00) Kuwait, Riyadh", "Arab Standard Time", "Arab Daylight Time", NULL, 0 }, { - "E. Africa Standard Time", 180, FALSE, "(UTC+03:00) Nairobi", + "Belarus Standard Time", -180, TRUE, "(UTC+03:00) Minsk", + "Belarus Standard Time", "Belarus Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_58, 2 + }, + { + "Russian Standard Time", -180, TRUE, "(UTC+03:00) Moscow, St. Petersburg, Volgograd (RTZ 2)", + "Russia TZ 2 Standard Time", "Russia TZ 2 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_59, 5 + }, + { + "E. Africa Standard Time", -180, FALSE, "(UTC+03:00) Nairobi", "E. Africa Standard Time", "E. Africa Daylight Time", NULL, 0 }, { - "Iran Standard Time", 210, TRUE, "(UTC+03:30) Tehran", + "Iran Standard Time", -210, TRUE, "(UTC+03:30) Tehran", "Iran Standard Time", "Iran Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_57, 3 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_61, 18 }, { - "Arabian Standard Time", 240, FALSE, "(UTC+04:00) Abu Dhabi, Muscat", + "Arabian Standard Time", -240, FALSE, "(UTC+04:00) Abu Dhabi, Muscat", "Arabian Standard Time", "Arabian Daylight Time", NULL, 0 }, { - "Azerbaijan Standard Time", 240, TRUE, "(UTC+04:00) Baku", + "Azerbaijan Standard Time", -240, TRUE, "(UTC+04:00) Baku", "Azerbaijan Standard Time", "Azerbaijan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_59, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_63, 1 }, { - "Russian Standard Time", 240, TRUE, "(UTC+04:00) Moscow, St. Petersburg, Volgograd", - "Russian Standard Time", "Russian Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_60, 1 + "Russia Time Zone 3", -240, FALSE, "(UTC+04:00) Izhevsk, Samara (RTZ 3)", + "Russia TZ 3 Standard Time", "Russia TZ 3 Daylight Time", + NULL, 0 }, { - "Mauritius Standard Time", 240, TRUE, "(UTC+04:00) Port Louis", + "Mauritius Standard Time", -240, TRUE, "(UTC+04:00) Port Louis", "Mauritius Standard Time", "Mauritius Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_61, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_65, 2 }, { - "Georgian Standard Time", 240, FALSE, "(UTC+04:00) Tbilisi", + "Georgian Standard Time", -240, FALSE, "(UTC+04:00) Tbilisi", "Georgian Standard Time", "Georgian Daylight Time", NULL, 0 }, { - "Caucasus Standard Time", 240, TRUE, "(UTC+04:00) Yerevan", + "Caucasus Standard Time", -240, TRUE, "(UTC+04:00) Yerevan", "Caucasus Standard Time", "Caucasus Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_63, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_67, 1 }, { - "Afghanistan Standard Time", 270, FALSE, "(UTC+04:30) Kabul", + "Afghanistan Standard Time", -270, FALSE, "(UTC+04:30) Kabul", "Afghanistan Standard Time", "Afghanistan Daylight Time", NULL, 0 }, { - "Pakistan Standard Time", 300, TRUE, "(UTC+05:00) Islamabad, Karachi", - "Pakistan Standard Time", "Pakistan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_65, 2 - }, - { - "West Asia Standard Time", 300, FALSE, "(UTC+05:00) Tashkent", + "West Asia Standard Time", -300, FALSE, "(UTC+05:00) Ashgabat, Tashkent", "West Asia Standard Time", "West Asia Daylight Time", NULL, 0 }, { - "India Standard Time", 330, FALSE, "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", + "Ekaterinburg Standard Time", -300, TRUE, "(UTC+05:00) Ekaterinburg (RTZ 4)", + "Russia TZ 4 Standard Time", "Russia TZ 4 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_70, 5 + }, + { + "Pakistan Standard Time", -300, TRUE, "(UTC+05:00) Islamabad, Karachi", + "Pakistan Standard Time", "Pakistan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_71, 2 + }, + { + "India Standard Time", -330, FALSE, "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", "India Standard Time", "India Daylight Time", NULL, 0 }, { - "Sri Lanka Standard Time", 330, FALSE, "(UTC+05:30) Sri Jayawardenepura", + "Sri Lanka Standard Time", -330, FALSE, "(UTC+05:30) Sri Jayawardenepura", "Sri Lanka Standard Time", "Sri Lanka Daylight Time", NULL, 0 }, { - "Nepal Standard Time", 345, FALSE, "(UTC+05:45) Kathmandu", + "Nepal Standard Time", -345, FALSE, "(UTC+05:45) Kathmandu", "Nepal Standard Time", "Nepal Daylight Time", NULL, 0 }, { - "Central Asia Standard Time", 360, FALSE, "(UTC+06:00) Astana", + "Central Asia Standard Time", -360, FALSE, "(UTC+06:00) Astana", "Central Asia Standard Time", "Central Asia Daylight Time", NULL, 0 }, { - "Bangladesh Standard Time", 360, TRUE, "(UTC+06:00) Dhaka", + "Bangladesh Standard Time", -360, TRUE, "(UTC+06:00) Dhaka", "Bangladesh Standard Time", "Bangladesh Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_71, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_76, 1 }, { - "Ekaterinburg Standard Time", 360, TRUE, "(UTC+06:00) Ekaterinburg", - "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_72, 1 + "N. Central Asia Standard Time", -360, TRUE, "(UTC+06:00) Novosibirsk (RTZ 5)", + "Russia TZ 5 Standard Time", "Russia TZ 5 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_77, 5 }, { - "Myanmar Standard Time", 390, FALSE, "(UTC+06:30) Yangon (Rangoon)", + "Myanmar Standard Time", -390, FALSE, "(UTC+06:30) Yangon (Rangoon)", "Myanmar Standard Time", "Myanmar Daylight Time", NULL, 0 }, { - "SE Asia Standard Time", 420, FALSE, "(UTC+07:00) Bangkok, Hanoi, Jakarta", + "SE Asia Standard Time", -420, FALSE, "(UTC+07:00) Bangkok, Hanoi, Jakarta", "SE Asia Standard Time", "SE Asia Daylight Time", NULL, 0 }, { - "N. Central Asia Standard Time", 420, TRUE, "(UTC+07:00) Novosibirsk", - "N. Central Asia Standard Time", "N. Central Asia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_75, 1 + "North Asia Standard Time", -420, TRUE, "(UTC+07:00) Krasnoyarsk (RTZ 6)", + "Russia TZ 6 Standard Time", "Russia TZ 6 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_80, 5 }, { - "China Standard Time", 480, FALSE, "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", + "China Standard Time", -480, FALSE, "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", "China Standard Time", "China Daylight Time", NULL, 0 }, { - "North Asia Standard Time", 480, TRUE, "(UTC+08:00) Krasnoyarsk", - "North Asia Standard Time", "North Asia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_77, 1 + "North Asia East Standard Time", -480, TRUE, "(UTC+08:00) Irkutsk (RTZ 7)", + "Russia TZ 7 Standard Time", "Russia TZ 7 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_82, 5 }, { - "Singapore Standard Time", 480, FALSE, "(UTC+08:00) Kuala Lumpur, Singapore", + "Singapore Standard Time", -480, FALSE, "(UTC+08:00) Kuala Lumpur, Singapore", "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", NULL, 0 }, { - "W. Australia Standard Time", 480, TRUE, "(UTC+08:00) Perth", + "W. Australia Standard Time", -480, TRUE, "(UTC+08:00) Perth", "W. Australia Standard Time", "W. Australia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_79, 4 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_84, 4 }, { - "Taipei Standard Time", 480, FALSE, "(UTC+08:00) Taipei", + "Taipei Standard Time", -480, FALSE, "(UTC+08:00) Taipei", "Taipei Standard Time", "Taipei Daylight Time", NULL, 0 }, { - "Ulaanbaatar Standard Time", 480, FALSE, "(UTC+08:00) Ulaanbaatar", + "Ulaanbaatar Standard Time", -480, TRUE, "(UTC+08:00) Ulaanbaatar", "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_86, 1 + }, + { + "North Korea Standard Time", -510, FALSE, "(UTC+08:30) Pyongyang", + "North Korea Standard Time", "North Korea Daylight Time", NULL, 0 }, { - "North Asia East Standard Time", 540, TRUE, "(UTC+09:00) Irkutsk", - "North Asia East Standard Time", "North Asia East Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_82, 1 - }, - { - "Tokyo Standard Time", 540, FALSE, "(UTC+09:00) Osaka, Sapporo, Tokyo", + "Tokyo Standard Time", -540, FALSE, "(UTC+09:00) Osaka, Sapporo, Tokyo", "Tokyo Standard Time", "Tokyo Daylight Time", NULL, 0 }, { - "Korea Standard Time", 540, FALSE, "(UTC+09:00) Seoul", + "Korea Standard Time", -540, FALSE, "(UTC+09:00) Seoul", "Korea Standard Time", "Korea Daylight Time", NULL, 0 }, { - "Cen. Australia Standard Time", 570, TRUE, "(UTC+09:30) Adelaide", - "Cen. Australia Standard Time", "Cen. Australia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_85, 2 + "Yakutsk Standard Time", -540, TRUE, "(UTC+09:00) Yakutsk (RTZ 8)", + "Russia TZ 8 Standard Time", "Russia TZ 8 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_90, 5 }, { - "AUS Central Standard Time", 570, FALSE, "(UTC+09:30) Darwin", + "Cen. Australia Standard Time", -570, TRUE, "(UTC+09:30) Adelaide", + "Cen. Australia Standard Time", "Cen. Australia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_91, 2 + }, + { + "AUS Central Standard Time", -570, FALSE, "(UTC+09:30) Darwin", "AUS Central Standard Time", "AUS Central Daylight Time", NULL, 0 }, { - "E. Australia Standard Time", 600, FALSE, "(UTC+10:00) Brisbane", + "E. Australia Standard Time", -600, FALSE, "(UTC+10:00) Brisbane", "E. Australia Standard Time", "E. Australia Daylight Time", NULL, 0 }, { - "AUS Eastern Standard Time", 600, TRUE, "(UTC+10:00) Canberra, Melbourne, Sydney", + "AUS Eastern Standard Time", -600, TRUE, "(UTC+10:00) Canberra, Melbourne, Sydney", "AUS Eastern Standard Time", "AUS Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_88, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_94, 2 }, { - "West Pacific Standard Time", 600, FALSE, "(UTC+10:00) Guam, Port Moresby", + "West Pacific Standard Time", -600, FALSE, "(UTC+10:00) Guam, Port Moresby", "West Pacific Standard Time", "West Pacific Daylight Time", NULL, 0 }, { - "Tasmania Standard Time", 600, TRUE, "(UTC+10:00) Hobart", + "Tasmania Standard Time", -600, TRUE, "(UTC+10:00) Hobart", "Tasmania Standard Time", "Tasmania Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_90, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_96, 2 }, { - "Yakutsk Standard Time", 600, TRUE, "(UTC+10:00) Yakutsk", - "Yakutsk Standard Time", "Yakutsk Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_91, 1 + "Magadan Standard Time", -600, TRUE, "(UTC+10:00) Magadan", + "Magadan Standard Time", "Magadan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_97, 5 }, { - "Central Pacific Standard Time", 660, FALSE, "(UTC+11:00) Solomon Is., New Caledonia", + "Vladivostok Standard Time", -600, TRUE, "(UTC+10:00) Vladivostok, Magadan (RTZ 9)", + "Russia TZ 9 Standard Time", "Russia TZ 9 Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_98, 5 + }, + { + "Russia Time Zone 10", -660, FALSE, "(UTC+11:00) Chokurdakh (RTZ 10)", + "Russia TZ 10 Standard Time", "Russia TZ 10 Daylight Time", + NULL, 0 + }, + { + "Central Pacific Standard Time", -660, FALSE, "(UTC+11:00) Solomon Is., New Caledonia", "Central Pacific Standard Time", "Central Pacific Daylight Time", NULL, 0 }, { - "Vladivostok Standard Time", 660, TRUE, "(UTC+11:00) Vladivostok", - "Vladivostok Standard Time", "Vladivostok Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_93, 1 + "Russia Time Zone 11", -720, FALSE, "(UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky (RTZ 11)", + "Russia TZ 11 Standard Time", "Russia TZ 11 Daylight Time", + NULL, 0 }, { - "New Zealand Standard Time", 720, TRUE, "(UTC+12:00) Auckland, Wellington", + "New Zealand Standard Time", -720, TRUE, "(UTC+12:00) Auckland, Wellington", "New Zealand Standard Time", "New Zealand Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_94, 3 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_102, 3 }, { - "UTC+12", 720, FALSE, "(UTC+12:00) Coordinated Universal Time+12", + "UTC+12", -720, FALSE, "(UTC+12:00) Coordinated Universal Time+12", "UTC+12", "UTC+12", NULL, 0 }, { - "Fiji Standard Time", 720, TRUE, "(UTC+12:00) Fiji", + "Fiji Standard Time", -720, TRUE, "(UTC+12:00) Fiji", "Fiji Standard Time", "Fiji Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_96, 5 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_104, 7 }, { - "Magadan Standard Time", 720, TRUE, "(UTC+12:00) Magadan", - "Magadan Standard Time", "Magadan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_97, 1 - }, - { - "Kamchatka Standard Time", 720, TRUE, "(UTC+12:00) Petropavlovsk-Kamchatsky - Old", + "Kamchatka Standard Time", -720, TRUE, "(UTC+12:00) Petropavlovsk-Kamchatsky - Old", "Kamchatka Standard Time", "Kamchatka Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_98, 1 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_105, 1 }, { - "Tonga Standard Time", 780, FALSE, "(UTC+13:00) Nuku'alofa", + "Tonga Standard Time", -780, FALSE, "(UTC+13:00) Nuku'alofa", "Tonga Standard Time", "Tonga Daylight Time", NULL, 0 }, { - "Samoa Standard Time", 780, TRUE, "(UTC+13:00) Samoa", + "Samoa Standard Time", -780, TRUE, "(UTC+13:00) Samoa", "Samoa Standard Time", "Samoa Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_100, 2 + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_107, 4 + }, + { + "Line Islands Standard Time", -840, FALSE, "(UTC+14:00) Kiritimati Island", + "Line Islands Standard Time", "Line Islands Daylight Time", + NULL, 0 } }; @@ -1095,8 +1215,7 @@ typedef struct _WINDOWS_TZID_ENTRY WINDOWS_TZID_ENTRY; const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { { "Afghanistan Standard Time", "Asia/Kabul" }, - { "Alaskan Standard Time", "America/Anchorage America/Juneau " - "America/Nome America/Sitka America/Yakutat" }, + { "Alaskan Standard Time", "America/Anchorage America/Juneau America/Metlakatla America/Nome America/Sitka America/Yakutat" }, { "Alaskan Standard Time", "America/Anchorage" }, { "Arab Standard Time", "Asia/Aden" }, { "Arab Standard Time", "Asia/Bahrain" }, @@ -1107,14 +1226,9 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Arabian Standard Time", "Asia/Muscat" }, { "Arabian Standard Time", "Etc/GMT-4" }, { "Arabic Standard Time", "Asia/Baghdad" }, - { "Argentina Standard Time", "America/Buenos_Aires America/Argentina/La_Rioja " - "America/Argentina/Rio_Gallegos America/Argentina/Salta " - "America/Argentina/San_Juan America/Argentina/San_Luis " - "America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca " - "America/Cordoba America/Jujuy America/Mendoza" }, + { "Argentina Standard Time", "America/Buenos_Aires America/Argentina/La_Rioja America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca America/Cordoba America/Jujuy America/Mendoza" }, { "Argentina Standard Time", "America/Buenos_Aires" }, - { "Atlantic Standard Time", "America/Halifax America/Glace_Bay " - "America/Goose_Bay America/Moncton" }, + { "Atlantic Standard Time", "America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton" }, { "Atlantic Standard Time", "America/Halifax" }, { "Atlantic Standard Time", "America/Thule" }, { "Atlantic Standard Time", "Atlantic/Bermuda" }, @@ -1127,6 +1241,7 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Bahia Standard Time", "America/Bahia" }, { "Bangladesh Standard Time", "Asia/Dhaka" }, { "Bangladesh Standard Time", "Asia/Thimphu" }, + { "Belarus Standard Time", "Europe/Minsk" }, { "Canada Central Standard Time", "America/Regina America/Swift_Current" }, { "Canada Central Standard Time", "America/Regina" }, { "Cape Verde Standard Time", "Atlantic/Cape_Verde" }, @@ -1146,6 +1261,7 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Central Asia Standard Time", "Asia/Almaty Asia/Qyzylorda" }, { "Central Asia Standard Time", "Asia/Almaty" }, { "Central Asia Standard Time", "Asia/Bishkek" }, + { "Central Asia Standard Time", "Asia/Urumqi" }, { "Central Asia Standard Time", "Etc/GMT-6" }, { "Central Asia Standard Time", "Indian/Chagos" }, { "Central Brazilian Standard Time", "America/Cuiaba America/Campo_Grande" }, @@ -1163,25 +1279,21 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Central European Standard Time", "Europe/Zagreb" }, { "Central Pacific Standard Time", "Antarctica/Macquarie" }, { "Central Pacific Standard Time", "Etc/GMT-11" }, + { "Central Pacific Standard Time", "Pacific/Bougainville" }, { "Central Pacific Standard Time", "Pacific/Efate" }, { "Central Pacific Standard Time", "Pacific/Guadalcanal" }, + { "Central Pacific Standard Time", "Pacific/Norfolk" }, { "Central Pacific Standard Time", "Pacific/Noumea" }, { "Central Pacific Standard Time", "Pacific/Ponape Pacific/Kosrae" }, - { "Central Standard Time (Mexico)", "America/Mexico_City America/Bahia_Banderas " - "America/Cancun America/Merida America/Monterrey" }, + { "Central Standard Time (Mexico)", "America/Mexico_City America/Bahia_Banderas America/Merida America/Monterrey" }, { "Central Standard Time (Mexico)", "America/Mexico_City" }, - { "Central Standard Time", "America/Chicago America/Indiana/Knox " - "America/Indiana/Tell_City America/Menominee " - "America/North_Dakota/Beulah America/North_Dakota/Center " - "America/North_Dakota/New_Salem" }, + { "Central Standard Time", "America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem" }, { "Central Standard Time", "America/Chicago" }, { "Central Standard Time", "America/Matamoros" }, - { "Central Standard Time", "America/Winnipeg America/Rainy_River " - "America/Rankin_Inlet America/Resolute" }, + { "Central Standard Time", "America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute" }, { "Central Standard Time", "CST6CDT" }, { "China Standard Time", "Asia/Hong_Kong" }, { "China Standard Time", "Asia/Macau" }, - { "China Standard Time", "Asia/Shanghai Asia/Chongqing Asia/Harbin Asia/Kashgar Asia/Urumqi" }, { "China Standard Time", "Asia/Shanghai" }, { "Dateline Standard Time", "Etc/GMT+12" }, { "E. Africa Standard Time", "Africa/Addis_Ababa" }, @@ -1200,23 +1312,21 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "E. Africa Standard Time", "Indian/Mayotte" }, { "E. Australia Standard Time", "Australia/Brisbane Australia/Lindeman" }, { "E. Australia Standard Time", "Australia/Brisbane" }, - { "E. Europe Standard Time", "Asia/Nicosia" }, + { "E. Europe Standard Time", "Europe/Chisinau" }, { "E. South America Standard Time", "America/Sao_Paulo" }, - { "Eastern Standard Time", "America/Grand_Turk" }, + { "Eastern Standard Time (Mexico)", "America/Cancun" }, + { "Eastern Standard Time", "America/Havana" }, { "Eastern Standard Time", "America/Nassau" }, - { "Eastern Standard Time", "America/New_York America/Detroit " - "America/Indiana/Petersburg America/Indiana/Vincennes " - "America/Indiana/Winamac America/Kentucky/Monticello America/Louisville" }, + { "Eastern Standard Time", "America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville" }, { "Eastern Standard Time", "America/New_York" }, - { "Eastern Standard Time", "America/Toronto America/Iqaluit America/Montreal " - "America/Nipigon America/Pangnirtung America/Thunder_Bay" }, + { "Eastern Standard Time", "America/Port-au-Prince" }, + { "Eastern Standard Time", "America/Toronto America/Iqaluit America/Montreal America/Nipigon America/Pangnirtung America/Thunder_Bay" }, { "Eastern Standard Time", "EST5EDT" }, { "Egypt Standard Time", "Africa/Cairo" }, - { "Egypt Standard Time", "Asia/Gaza Asia/Hebron" }, { "Ekaterinburg Standard Time", "Asia/Yekaterinburg" }, { "Fiji Standard Time", "Pacific/Fiji" }, { "FLE Standard Time", "Europe/Helsinki" }, - { "FLE Standard Time", "Europe/Kiev Europe/Simferopol Europe/Uzhgorod Europe/Zaporozhye" }, + { "FLE Standard Time", "Europe/Kiev Europe/Uzhgorod Europe/Zaporozhye" }, { "FLE Standard Time", "Europe/Kiev" }, { "FLE Standard Time", "Europe/Mariehamn" }, { "FLE Standard Time", "Europe/Riga" }, @@ -1240,7 +1350,6 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Greenwich Standard Time", "Africa/Bissau" }, { "Greenwich Standard Time", "Africa/Conakry" }, { "Greenwich Standard Time", "Africa/Dakar" }, - { "Greenwich Standard Time", "Africa/El_Aaiun" }, { "Greenwich Standard Time", "Africa/Freetown" }, { "Greenwich Standard Time", "Africa/Lome" }, { "Greenwich Standard Time", "Africa/Monrovia" }, @@ -1249,25 +1358,23 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Greenwich Standard Time", "Africa/Sao_Tome" }, { "Greenwich Standard Time", "Atlantic/Reykjavik" }, { "Greenwich Standard Time", "Atlantic/St_Helena" }, + { "GTB Standard Time", "Asia/Nicosia" }, { "GTB Standard Time", "Europe/Athens" }, { "GTB Standard Time", "Europe/Bucharest" }, - { "GTB Standard Time", "Europe/Chisinau" }, - { "GTB Standard Time", "Europe/Istanbul" }, { "Hawaiian Standard Time", "Etc/GMT+10" }, - { "Hawaiian Standard Time", "Pacific/Fakaofo" }, { "Hawaiian Standard Time", "Pacific/Honolulu" }, { "Hawaiian Standard Time", "Pacific/Johnston" }, { "Hawaiian Standard Time", "Pacific/Rarotonga" }, { "Hawaiian Standard Time", "Pacific/Tahiti" }, - { "India Standard Time", "Asia/Calcutta Asia/Kolkata" }, + { "India Standard Time", "Asia/Calcutta" }, { "Iran Standard Time", "Asia/Tehran" }, { "Israel Standard Time", "Asia/Jerusalem" }, { "Jordan Standard Time", "Asia/Amman" }, { "Kaliningrad Standard Time", "Europe/Kaliningrad" }, - { "Kaliningrad Standard Time", "Europe/Minsk" }, - { "Korea Standard Time", "Asia/Pyongyang" }, { "Korea Standard Time", "Asia/Seoul" }, - { "Magadan Standard Time", "Asia/Magadan Asia/Anadyr Asia/Kamchatka" }, + { "Libya Standard Time", "Africa/Tripoli" }, + { "Line Islands Standard Time", "Etc/GMT-14" }, + { "Line Islands Standard Time", "Pacific/Kiritimati" }, { "Magadan Standard Time", "Asia/Magadan" }, { "Mauritius Standard Time", "Indian/Mahe" }, { "Mauritius Standard Time", "Indian/Mauritius" }, @@ -1275,30 +1382,31 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Middle East Standard Time", "Asia/Beirut" }, { "Montevideo Standard Time", "America/Montevideo" }, { "Morocco Standard Time", "Africa/Casablanca" }, + { "Morocco Standard Time", "Africa/El_Aaiun" }, { "Mountain Standard Time (Mexico)", "America/Chihuahua America/Mazatlan" }, { "Mountain Standard Time (Mexico)", "America/Chihuahua" }, - { "Mountain Standard Time", "America/Denver America/Boise America/Shiprock" }, + { "Mountain Standard Time", "America/Denver America/Boise" }, { "Mountain Standard Time", "America/Denver" }, - { "Mountain Standard Time", "America/Edmonton " - "America/Cambridge_Bay America/Inuvik America/Yellowknife" }, + { "Mountain Standard Time", "America/Edmonton America/Cambridge_Bay America/Inuvik America/Yellowknife" }, { "Mountain Standard Time", "America/Ojinaga" }, { "Mountain Standard Time", "MST7MDT" }, { "Myanmar Standard Time", "Asia/Rangoon" }, { "Myanmar Standard Time", "Indian/Cocos" }, - { "N. Central Asia Standard Time", "Asia/Novosibirsk Asia/Novokuznetsk Asia/Omsk" }, + { "N. Central Asia Standard Time", "Asia/Novosibirsk Asia/Omsk" }, { "N. Central Asia Standard Time", "Asia/Novosibirsk" }, { "Namibia Standard Time", "Africa/Windhoek" }, - { "Nepal Standard Time", "Asia/Katmandu Asia/Kathmandu" }, - { "New Zealand Standard Time", "Antarctica/South_Pole Antarctica/McMurdo" }, + { "Nepal Standard Time", "Asia/Katmandu" }, + { "New Zealand Standard Time", "Antarctica/McMurdo" }, { "New Zealand Standard Time", "Pacific/Auckland" }, { "Newfoundland Standard Time", "America/St_Johns" }, { "North Asia East Standard Time", "Asia/Irkutsk" }, + { "North Asia Standard Time", "Asia/Krasnoyarsk Asia/Novokuznetsk" }, { "North Asia Standard Time", "Asia/Krasnoyarsk" }, + { "North Korea Standard Time", "Asia/Pyongyang" }, { "Pacific SA Standard Time", "America/Santiago" }, { "Pacific SA Standard Time", "Antarctica/Palmer" }, - { "Pacific Standard Time (Mexico)", "America/Santa_Isabel" }, { "Pacific Standard Time", "America/Los_Angeles" }, - { "Pacific Standard Time", "America/Tijuana America/Ensenada" }, + { "Pacific Standard Time", "America/Tijuana America/Santa_Isabel" }, { "Pacific Standard Time", "America/Vancouver America/Dawson America/Whitehorse" }, { "Pacific Standard Time", "PST8PDT" }, { "Pakistan Standard Time", "Asia/Karachi" }, @@ -1307,13 +1415,17 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Romance Standard Time", "Europe/Copenhagen" }, { "Romance Standard Time", "Europe/Madrid Africa/Ceuta" }, { "Romance Standard Time", "Europe/Paris" }, - { "Russian Standard Time", "Europe/Moscow Europe/Samara Europe/Volgograd" }, + { "Russia Time Zone 10", "Asia/Srednekolymsk" }, + { "Russia Time Zone 11", "Asia/Kamchatka Asia/Anadyr" }, + { "Russia Time Zone 11", "Asia/Kamchatka" }, + { "Russia Time Zone 3", "Europe/Samara" }, + { "Russian Standard Time", "Europe/Moscow Europe/Simferopol Europe/Volgograd" }, { "Russian Standard Time", "Europe/Moscow" }, { "SA Eastern Standard Time", "America/Cayenne" }, - { "SA Eastern Standard Time", "America/Fortaleza America/Araguaina " - "America/Belem America/Maceio America/Recife America/Santarem" }, + { "SA Eastern Standard Time", "America/Fortaleza America/Araguaina America/Belem America/Maceio America/Recife America/Santarem" }, { "SA Eastern Standard Time", "America/Paramaribo" }, { "SA Eastern Standard Time", "Antarctica/Rothera" }, + { "SA Eastern Standard Time", "Atlantic/Stanley" }, { "SA Eastern Standard Time", "Etc/GMT+3" }, { "SA Pacific Standard Time", "America/Bogota" }, { "SA Pacific Standard Time", "America/Cayman" }, @@ -1322,8 +1434,9 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "SA Pacific Standard Time", "America/Jamaica" }, { "SA Pacific Standard Time", "America/Lima" }, { "SA Pacific Standard Time", "America/Panama" }, - { "SA Pacific Standard Time", "America/Port-au-Prince" }, + { "SA Pacific Standard Time", "America/Rio_Branco America/Eirunepe" }, { "SA Pacific Standard Time", "Etc/GMT+5" }, + { "SA Pacific Standard Time", "Pacific/Easter" }, { "SA Western Standard Time", "America/Anguilla" }, { "SA Western Standard Time", "America/Antigua" }, { "SA Western Standard Time", "America/Aruba" }, @@ -1331,12 +1444,14 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "SA Western Standard Time", "America/Blanc-Sablon" }, { "SA Western Standard Time", "America/Curacao" }, { "SA Western Standard Time", "America/Dominica" }, + { "SA Western Standard Time", "America/Grand_Turk" }, { "SA Western Standard Time", "America/Grenada" }, { "SA Western Standard Time", "America/Guadeloupe" }, { "SA Western Standard Time", "America/Guyana" }, + { "SA Western Standard Time", "America/Kralendijk" }, { "SA Western Standard Time", "America/La_Paz" }, - { "SA Western Standard Time", "America/Manaus America/Boa_Vista " - "America/Eirunepe America/Porto_Velho America/Rio_Branco" }, + { "SA Western Standard Time", "America/Lower_Princes" }, + { "SA Western Standard Time", "America/Manaus America/Boa_Vista America/Porto_Velho" }, { "SA Western Standard Time", "America/Marigot" }, { "SA Western Standard Time", "America/Martinique" }, { "SA Western Standard Time", "America/Montserrat" }, @@ -1350,13 +1465,12 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "SA Western Standard Time", "America/St_Vincent" }, { "SA Western Standard Time", "America/Tortola" }, { "SA Western Standard Time", "Etc/GMT+4" }, - { "Samoa Standard Time", "Pacific/Apia Pacific/Samoa" }, + { "Samoa Standard Time", "Pacific/Apia" }, { "SE Asia Standard Time", "Antarctica/Davis" }, { "SE Asia Standard Time", "Asia/Bangkok" }, - { "SE Asia Standard Time", "Asia/Hovd" }, { "SE Asia Standard Time", "Asia/Jakarta Asia/Pontianak" }, { "SE Asia Standard Time", "Asia/Phnom_Penh" }, - { "SE Asia Standard Time", "Asia/Saigon Asia/Ho_Chi_Minh" }, + { "SE Asia Standard Time", "Asia/Saigon" }, { "SE Asia Standard Time", "Asia/Vientiane" }, { "SE Asia Standard Time", "Etc/GMT-7" }, { "SE Asia Standard Time", "Indian/Christmas" }, @@ -1377,7 +1491,6 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "South Africa Standard Time", "Africa/Maputo" }, { "South Africa Standard Time", "Africa/Maseru" }, { "South Africa Standard Time", "Africa/Mbabane" }, - { "South Africa Standard Time", "Africa/Tripoli" }, { "South Africa Standard Time", "Etc/GMT-2" }, { "Sri Lanka Standard Time", "Asia/Colombo" }, { "Syria Standard Time", "Asia/Damascus" }, @@ -1391,14 +1504,14 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "Tokyo Standard Time", "Pacific/Palau" }, { "Tonga Standard Time", "Etc/GMT-13" }, { "Tonga Standard Time", "Pacific/Enderbury" }, + { "Tonga Standard Time", "Pacific/Fakaofo" }, { "Tonga Standard Time", "Pacific/Tongatapu" }, - /* { "Turkey Standard Time", "Europe/Istanbul" }, */ + { "Turkey Standard Time", "Europe/Istanbul" }, { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar Asia/Choibalsan" }, { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar" }, - { "US Eastern Standard Time", "America/Indianapolis " - "America/Indiana/Marengo America/Indiana/Vevay" }, + { "US Eastern Standard Time", "America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay" }, { "US Eastern Standard Time", "America/Indianapolis" }, - { "US Mountain Standard Time", "America/Dawson_Creek" }, + { "US Mountain Standard Time", "America/Dawson_Creek America/Creston America/Fort_Nelson" }, { "US Mountain Standard Time", "America/Hermosillo" }, { "US Mountain Standard Time", "America/Phoenix" }, { "US Mountain Standard Time", "Etc/GMT+7" }, @@ -1419,7 +1532,7 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "UTC-11", "Pacific/Niue" }, { "UTC-11", "Pacific/Pago_Pago" }, { "Venezuela Standard Time", "America/Caracas" }, - { "Vladivostok Standard Time", "Asia/Vladivostok Asia/Sakhalin" }, + { "Vladivostok Standard Time", "Asia/Vladivostok Asia/Sakhalin Asia/Ust-Nera" }, { "Vladivostok Standard Time", "Asia/Vladivostok" }, { "W. Australia Standard Time", "Antarctica/Casey" }, { "W. Australia Standard Time", "Australia/Perth" }, @@ -1440,6 +1553,7 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "W. Europe Standard Time", "Arctic/Longyearbyen" }, { "W. Europe Standard Time", "Europe/Amsterdam" }, { "W. Europe Standard Time", "Europe/Andorra" }, + { "W. Europe Standard Time", "Europe/Berlin Europe/Busingen" }, { "W. Europe Standard Time", "Europe/Berlin" }, { "W. Europe Standard Time", "Europe/Gibraltar" }, { "W. Europe Standard Time", "Europe/Luxembourg" }, @@ -1468,7 +1582,8 @@ const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = { "West Pacific Standard Time", "Pacific/Port_Moresby" }, { "West Pacific Standard Time", "Pacific/Saipan" }, { "West Pacific Standard Time", "Pacific/Truk" }, - { "Yakutsk Standard Time", "Asia/Yakutsk" } + { "Yakutsk Standard Time", "Asia/Yakutsk Asia/Chita Asia/Khandyga" }, + { "Yakutsk Standard Time", "Asia/Yakutsk" }, }; static UINT64 winpr_windows_gmtime() @@ -1625,7 +1740,7 @@ static BOOL winpr_match_unix_timezone_identifier_with_list(const char* tzid, con return FALSE; } -static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(UINT32 bias) +static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void) { int i, j; char* tzid; @@ -1654,7 +1769,6 @@ static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(UINT32 bias) if (!timezone) return NULL; memcpy((void*) timezone, (void*) &TimeZoneTable[i], sizeof(TIME_ZONE_ENTRY)); - timezone->Bias = bias; return timezone; } } @@ -1700,35 +1814,40 @@ DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation) memset(tz, 0, sizeof(TIME_ZONE_INFORMATION)); #ifdef HAVE_TM_GMTOFF - #if defined(__FreeBSD__) || defined(__OpenBSD__) - if (local_time->tm_gmtoff >= 0) - tz->Bias = (UINT32) (local_time->tm_gmtoff / 60); - else - tz->Bias = (UINT32) (1440 + (INT32) (local_time->tm_gmtoff / 60)); - #else - tz->Bias = (UINT32) (local_time->tm_gmtoff / 60); - #endif + tz->Bias = -(local_time->tm_gmtoff / 60); #else tz->Bias = 0; #endif - WLog_DBG(TAG, "tzname[std]: %s, tzname[dst]: %s, timezone: %ld, Daylight: %d", - tzname[0], tzname[1], timezone, daylight); - dtz = winpr_detect_windows_time_zone(tz->Bias); + dtz = winpr_detect_windows_time_zone(); if (dtz!= NULL) { + int status; WLog_DBG(TAG, "tz: Bias=%d sn='%s' dln='%s'", dtz->Bias, dtz->StandardName, dtz->DaylightName); tz->Bias = dtz->Bias; - tz->StandardBias = dtz->Bias; - tz->DaylightBias = dtz->Bias; + tz->StandardBias = 0; + tz->DaylightBias = 0; - ConvertToUnicode(CP_UTF8, 0, dtz->StandardName, sizeof(dtz->StandardName), - (WCHAR**)&tz->StandardName, sizeof(tz->StandardName)/sizeof(WCHAR)); - ConvertToUnicode(CP_UTF8, 0, dtz->DaylightName, sizeof(dtz->DaylightName), - (WCHAR**)&tz->DaylightName, sizeof(tz->DaylightName)/sizeof(WCHAR)); + ZeroMemory(tz->StandardName, sizeof(tz->StandardName)); + ZeroMemory(tz->DaylightName, sizeof(tz->DaylightName)); + status = MultiByteToWideChar(CP_UTF8, 0, dtz->StandardName, -1, tz->StandardName, + sizeof(tz->StandardName)/sizeof(WCHAR)-1); + if (status < 1) + { + WLog_ERR(TAG, "StandardName conversion failed - using default"); + goto out_error; + } + + status = MultiByteToWideChar(CP_UTF8, 0, dtz->DaylightName, -1, tz->DaylightName, + sizeof(tz->DaylightName)/sizeof(WCHAR)-1); + if (status < 1) + { + WLog_ERR(TAG, "DaylightName conversion failed - using default"); + goto out_error; + } if ((dtz->SupportsDST) && (dtz->RuleTableCount > 0)) { @@ -1751,10 +1870,11 @@ DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation) } else { - /* could not detect timezone, fallback to using GMT */ - WLog_DBG(TAG, "tz not found, using GMT."); - memcpy(tz->StandardName, L"GMT Standard Time", sizeof(tz->StandardName)); - memcpy(tz->DaylightName, L"GMT Daylight Time", sizeof(tz->DaylightName)); + /* could not detect timezone, use computed bias from tm_gmtoff */ + WLog_DBG(TAG, "tz not found, using computed bias %d.", tz->Bias); +out_error: + memcpy(tz->StandardName, L"Client Local Time", sizeof(tz->StandardName)); + memcpy(tz->DaylightName, L"Client Local Time", sizeof(tz->DaylightName)); return 0; /* TIME_ZONE_ID_UNKNOWN */ } } diff --git a/winpr/libwinpr/utils/test/TestStream.c b/winpr/libwinpr/utils/test/TestStream.c index 005dcef..7b0a751 100644 --- a/winpr/libwinpr/utils/test/TestStream.c +++ b/winpr/libwinpr/utils/test/TestStream.c @@ -261,6 +261,252 @@ static BOOL TestStream_Reading(void) return result; } +static BOOL TestStream_Write(void) +{ + BOOL rc = FALSE; + UINT8 u8; + UINT16 u16; + UINT32 u32; + UINT64 u64; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) == 0) + rc = TRUE; + if (s->pointer != s->buffer + sizeof(data)) + goto out; + + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Write_UINT8(s, 42); + if (s->pointer != s->buffer + 1) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT8(s, u8); + if (u8 != 42) + goto out; + + Stream_Write_UINT16(s, 0x1234); + if (s->pointer != s->buffer + 2) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT16(s, u16); + if (u16 != 0x1234) + goto out; + + Stream_Write_UINT32(s, 0x12345678UL); + if (s->pointer != s->buffer + 4) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT32(s, u32); + if (u32 != 0x12345678UL) + goto out; + + Stream_Write_UINT64(s, 0x1234567890ABCDEFULL); + if (s->pointer != s->buffer + 8) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT64(s, u64); + if (u64 != 0x1234567890ABCDEFULL) + goto out; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Seek(void) +{ + BOOL rc = FALSE; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + + if (s->pointer != s->buffer) + goto out; + + Stream_Seek(s, 5); + if (s->pointer != s->buffer + 5) + goto out; + Stream_Seek_UINT8(s); + if (s->pointer != s->buffer + 6) + goto out; + + Stream_Seek_UINT16(s); + if (s->pointer != s->buffer + 8) + goto out; + + Stream_Seek_UINT32(s); + if (s->pointer != s->buffer + 12) + goto out; + Stream_Seek_UINT64(s); + if (s->pointer != s->buffer + 20) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Rewind(void) +{ + BOOL rc = FALSE; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Seek(s, 100); + if (s->pointer != s->buffer + 100) + goto out; + + Stream_Rewind(s, 10); + if (s->pointer != s->buffer + 90) + goto out; + Stream_Rewind_UINT8(s); + if (s->pointer != s->buffer + 89) + goto out; + Stream_Rewind_UINT16(s); + if (s->pointer != s->buffer + 87) + goto out; + + Stream_Rewind_UINT32(s); + if (s->pointer != s->buffer + 83) + goto out; + Stream_Rewind_UINT64(s); + if (s->pointer != s->buffer + 75) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Zero(void) +{ + UINT32 x; + BOOL rc = FALSE; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + if (!s) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Zero(s, 5); + if (s->pointer != s->buffer + 5) + goto out; + if (memcmp(Stream_Pointer(s), data+5, sizeof(data)-5) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + for (x=0; x<5; x++) + { + UINT8 val; + Stream_Read_UINT8(s, val); + if (val != 0) + goto out; + } + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Fill(void) +{ + BOOL rc = FALSE; + const BYTE fill[7] = "XXXXXXX"; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + if (!s) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Fill(s, fill[0], sizeof(fill)); + if (s->pointer != s->buffer + sizeof(fill)) + goto out; + if (memcmp(Stream_Pointer(s), data+sizeof(fill), sizeof(data)-sizeof(fill)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + if (memcmp(Stream_Pointer(s), fill, sizeof(fill)) != 0) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Copy(void) +{ + BOOL rc = FALSE; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + wStream* d = Stream_New(NULL, sizeof(data)); + if (!s || !d) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + if (s->pointer != s->buffer + sizeof(data)) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + + Stream_Copy(s, d, sizeof(data)); + if (s->pointer != s->buffer + sizeof(data)) + goto out; + if (d->pointer != d->buffer + sizeof(data)) + goto out; + if (Stream_GetPosition(s) != Stream_GetPosition(d)) + goto out; + + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + if (memcmp(Stream_Buffer(d), data, sizeof(data)) != 0) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + Stream_Free(d, TRUE); + return rc; +} + int TestStream(int argc, char* argv[]) { @@ -278,15 +524,24 @@ int TestStream(int argc, char* argv[]) if (!TestStream_New()) return 5; - /** - * FIXME: Add tests for - * Stream_Write_* - * Stream_Seek_* - * Stream_Rewind_* - * Stream_Zero - * Stream_Fill - * Stream_Copy - */ + + if (!TestStream_Write()) + return 6; + + if (!TestStream_Seek()) + return 7; + + if (!TestStream_Rewind()) + return 8; + + if (!TestStream_Zero()) + return 9; + + if (!TestStream_Fill()) + return 10; + + if (!TestStream_Copy()) + return 11; return 0; } diff --git a/winpr/libwinpr/utils/wlog/JournaldAppender.c b/winpr/libwinpr/utils/wlog/JournaldAppender.c index 31ac150..875682e 100644 --- a/winpr/libwinpr/utils/wlog/JournaldAppender.c +++ b/winpr/libwinpr/utils/wlog/JournaldAppender.c @@ -79,6 +79,7 @@ static BOOL WLog_JournaldAppender_WriteMessage(wLog* log, wLogAppender* appender { char *formatStr; wLogJournaldAppender* journaldAppender; + char prefix[WLOG_MAX_PREFIX_SIZE]; if (!log || !appender || !message) return FALSE; @@ -89,19 +90,19 @@ static BOOL WLog_JournaldAppender_WriteMessage(wLog* log, wLogAppender* appender { case WLOG_TRACE: case WLOG_DEBUG: - formatStr = "<7>%s\n"; + formatStr = "<7>%s%s\n"; break; case WLOG_INFO: - formatStr = "<6>%s\n"; + formatStr = "<6>%s%s\n"; break; case WLOG_WARN: - formatStr = "<4>%s\n"; + formatStr = "<4>%s%s\n"; break; case WLOG_ERROR: - formatStr = "<3>%s\n"; + formatStr = "<3>%s%s\n"; break; case WLOG_FATAL: - formatStr = "<2>%s\n"; + formatStr = "<2>%s%s\n"; break; case WLOG_OFF: return TRUE; @@ -110,7 +111,11 @@ static BOOL WLog_JournaldAppender_WriteMessage(wLog* log, wLogAppender* appender return FALSE; } - fprintf(journaldAppender->stream, formatStr, message->TextString); + message->PrefixString = prefix; + WLog_Layout_GetMessagePrefix(log, appender->Layout, message); + + if (message->Level != WLOG_OFF) + fprintf(journaldAppender->stream, formatStr, message->PrefixString, message->TextString); return TRUE; } diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c index e00421e..8124ec4 100644 --- a/winpr/libwinpr/utils/wlog/wlog.c +++ b/winpr/libwinpr/utils/wlog/wlog.c @@ -69,6 +69,7 @@ LPCSTR WLOG_LEVELS[7] = static DWORD g_FilterCount = 0; static wLogFilter* g_Filters = NULL; +static LONG WLog_GetFilterLogLevel(wLog* log); static int WLog_ParseLogLevel(LPCSTR level); static BOOL WLog_ParseFilter(wLogFilter* filter, LPCSTR name); @@ -295,14 +296,14 @@ BOOL WLog_PrintMessage(wLog* log, wLogMessage* message, ...) DWORD WLog_GetLogLevel(wLog* log) { - if (log->Level == WLOG_LEVEL_INHERIT) - { - return WLog_GetLogLevel(log->Parent); - } - else - { - return log->Level; - } + if (log->FilterLevel < 0) + log->FilterLevel = WLog_GetFilterLogLevel(log); + + if ((log->FilterLevel >= 0) && (log->FilterLevel != WLOG_LEVEL_INHERIT)) + return log->FilterLevel; + else if (log->Level == WLOG_LEVEL_INHERIT) + log->Level = WLog_GetLogLevel(log->Parent); + return log->Level; } BOOL WLog_SetStringLogLevel(wLog* log, LPCSTR level) @@ -393,9 +394,7 @@ BOOL WLog_SetLogLevel(wLog* log, DWORD logLevel) return FALSE; if ((logLevel > WLOG_OFF) && (logLevel != WLOG_LEVEL_INHERIT)) - { logLevel = WLOG_OFF; - } log->Level = logLevel; return TRUE; @@ -501,7 +500,7 @@ BOOL WLog_ParseFilter(wLogFilter* filter, LPCSTR name) return TRUE; } -BOOL WLog_ParseFilters() +BOOL WLog_ParseFilters(void) { BOOL res; char* env; @@ -530,12 +529,14 @@ BOOL WLog_ParseFilters() return res; } -int WLog_GetFilterLogLevel(wLog* log) +LONG WLog_GetFilterLogLevel(wLog* log) { DWORD i, j; - int iLevel = -1; BOOL match = FALSE; + if (log->FilterLevel >= 0) + return log->FilterLevel; + for (i = 0; i < g_FilterCount; i++) { for (j = 0; j < g_Filters[i].NameCount; j++) @@ -564,11 +565,11 @@ int WLog_GetFilterLogLevel(wLog* log) } if (match) - { - iLevel = (int) g_Filters[i].Level; - } + log->FilterLevel = g_Filters[i].Level; + else + log->FilterLevel = WLOG_LEVEL_INHERIT; - return iLevel; + return log->FilterLevel; } BOOL WLog_ParseName(wLog* log, LPCSTR name) @@ -622,35 +623,36 @@ wLog* WLog_New(LPCSTR name, wLog* rootLogger) if (!log) return NULL; - log->Name = _strdup(name); + log->Name = _strdup(name); - if (!log->Name) + if (!log->Name) goto out_fail; - if (!WLog_ParseName(log, name)) + if (!WLog_ParseName(log, name)) goto out_fail; - log->Parent = rootLogger; - log->ChildrenCount = 0; - log->ChildrenSize = 16; + log->Parent = rootLogger; + log->ChildrenCount = 0; + log->ChildrenSize = 16; + log->FilterLevel = -1; - if (!(log->Children = (wLog**) calloc(log->ChildrenSize, sizeof(wLog*)))) + if (!(log->Children = (wLog**) calloc(log->ChildrenSize, sizeof(wLog*)))) goto out_fail; - log->Appender = NULL; + log->Appender = NULL; - if (rootLogger) - { - log->Level = WLOG_LEVEL_INHERIT; - } - else - { - log->Level = WLOG_INFO; - nSize = GetEnvironmentVariableA("WLOG_LEVEL", NULL, 0); + if (rootLogger) + { + log->Level = WLOG_LEVEL_INHERIT; + } + else + { + log->Level = WLOG_INFO; + nSize = GetEnvironmentVariableA("WLOG_LEVEL", NULL, 0); - if (nSize) - { - env = (LPSTR) malloc(nSize); + if (nSize) + { + env = (LPSTR) malloc(nSize); if (!env) goto out_fail; @@ -666,13 +668,13 @@ wLog* WLog_New(LPCSTR name, wLog* rootLogger) if (iLevel >= 0) log->Level = (DWORD) iLevel; - } - } + } + } - iLevel = WLog_GetFilterLogLevel(log); + iLevel = WLog_GetFilterLogLevel(log); - if (iLevel >= 0) - log->Level = (DWORD) iLevel; + if ((iLevel >= 0) && (iLevel != WLOG_LEVEL_INHERIT)) + log->Level = (DWORD) iLevel; return log; @@ -703,7 +705,7 @@ void WLog_Free(wLog* log) static wLog* g_RootLog = NULL; -wLog* WLog_GetRoot() +wLog* WLog_GetRoot(void) { char* env; DWORD nSize; @@ -775,7 +777,6 @@ BOOL WLog_AddChild(wLog* parent, wLog* child) if (parent->Children) free (parent->Children); parent->Children = NULL; - } else { diff --git a/winpr/libwinpr/utils/wlog/wlog.h b/winpr/libwinpr/utils/wlog/wlog.h index c3cc83e..596005d 100644 --- a/winpr/libwinpr/utils/wlog/wlog.h +++ b/winpr/libwinpr/utils/wlog/wlog.h @@ -63,6 +63,7 @@ struct _wLogAppender struct _wLog { LPSTR Name; + LONG FilterLevel; DWORD Level; BOOL IsRoot;