Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,268 @@
# WinPR: Windows Portable Runtime
# winpr cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include(CheckFunctionExists)
include(JsonDetect)
set(WINPR_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(WINPR_SRCS "")
set(WINPR_LIBS_PRIVATE "")
set(WINPR_LIBS_PUBLIC "")
set(WINPR_INCLUDES "")
set(WINPR_SYSTEM_INCLUDES "")
set(WINPR_DEFINITIONS "")
set(WINPR_COMPILE_OPTIONS "")
set(WINPR_LINK_OPTIONS "")
set(WINPR_LINK_DIRS "")
macro(winpr_module_add)
file(RELATIVE_PATH _relPath "${WINPR_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
foreach(_src ${ARGN})
if(_relPath)
list(APPEND WINPR_SRCS "${_relPath}/${_src}")
else()
list(APPEND WINPR_SRCS "${_src}")
endif()
endforeach()
if(_relPath)
set(WINPR_SRCS ${WINPR_SRCS} PARENT_SCOPE)
endif()
endmacro()
macro(winpr_include_directory_add)
file(RELATIVE_PATH _relPath "${WINPR_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
foreach(_inc ${ARGN})
if(IS_ABSOLUTE ${_inc})
list(APPEND WINPR_INCLUDES "${_inc}")
else()
if(_relPath)
list(APPEND WINPR_INCLUDES "${_relPath}/${_inc}")
else()
list(APPEND WINPR_INCLUDES "${_inc}")
endif()
endif()
endforeach()
if(_relPath)
set(WINPR_INCLUDES ${WINPR_INCLUDES} PARENT_SCOPE)
endif()
endmacro()
macro(winpr_system_include_directory_add)
file(RELATIVE_PATH _relPath "${WINPR_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
foreach(_inc ${ARGN})
if(IS_ABSOLUTE ${_inc})
list(APPEND WINPR_SYSTEM_INCLUDES "${_inc}")
else()
if(_relPath)
list(APPEND WINPR_SYSTEM_INCLUDES "${_relPath}/${_inc}")
else()
list(APPEND WINPR_SYSTEM_INCLUDES "${_inc}")
endif()
endif()
endforeach()
if(_relPath)
set(WINPR_SYSTEM_INCLUDES ${WINPR_SYSTEM_INCLUDES} PARENT_SCOPE)
endif()
endmacro()
macro(winpr_library_add_private)
foreach(_lib ${ARGN})
list(APPEND WINPR_LIBS_PRIVATE "${_lib}")
endforeach()
set(WINPR_LIBS_PRIVATE ${WINPR_LIBS_PRIVATE} PARENT_SCOPE)
endmacro()
macro(winpr_library_add_public)
foreach(_lib ${ARGN})
list(APPEND WINPR_LIBS_PUBLIC "${_lib}")
endforeach()
set(WINPR_LIBS_PUBLIC ${WINPR_LIBS_PUBLIC} PARENT_SCOPE)
endmacro()
macro(winpr_definition_add)
foreach(_define ${ARGN})
list(APPEND WINPR_DEFINITIONS "${_define}")
endforeach()
set(WINPR_DEFINITIONS ${WINPR_DEFINITIONS} PARENT_SCOPE)
endmacro()
macro(winpr_library_add_compile_options)
foreach(_define ${ARGN})
list(APPEND WINPR_COMPILE_OPTIONS "${_define}")
endforeach()
set(WINPR_COMPILE_OPTIONS ${WINPR_COMPILE_OPTIONS} PARENT_SCOPE)
endmacro()
macro(winpr_library_add_link_options)
foreach(_define ${ARGN})
list(APPEND WINPR_LINK_OPTIONS "${_define}")
endforeach()
set(WINPR_LINK_OPTIONS ${WINPR_LINK_OPTIONS} PARENT_SCOPE)
endmacro()
macro(winpr_library_add_link_directory)
foreach(_define ${ARGN})
list(APPEND WINPR_LINK_DIRS "${_define}")
endforeach()
set(WINPR_LINK_DIRS ${WINPR_LINK_DIRS} PARENT_SCOPE)
endmacro()
set(CMAKE_REQUIRED_LIBRARIES rt)
find_package(uriparser)
option(WITH_URIPARSER "use uriparser library to handle URIs" ${uriparser_FOUND})
if(WITH_URIPARSER)
find_package(uriparser CONFIG COMPONENTS char)
if(uriparser_FOUND)
winpr_library_add_private(uriparser::uriparser)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(uriparser REQUIRED liburiparser)
winpr_system_include_directory_add(${uriparser_INCLUDEDIR})
winpr_system_include_directory_add(${uriparser_INCLUDE_DIRS})
winpr_library_add_private(${uriparser_LIBRARIES})
endif()
add_compile_definitions("WITH_URIPARSER")
winpr_pc_add_requires_private("liburiparser")
endif()
if(NOT IOS)
check_function_exists(timer_create TIMER_CREATE)
check_function_exists(timer_delete TIMER_DELETE)
check_function_exists(timer_settime TIMER_SETTIME)
check_function_exists(timer_gettime TIMER_GETTIME)
if(TIMER_CREATE AND TIMER_DELETE AND TIMER_SETTIME AND TIMER_GETTIME)
add_compile_definitions(WITH_POSIX_TIMER)
winpr_library_add_private(rt)
endif()
endif()
check_function_exists(pthread_setschedprio PTHREAD_SETSCHEDPRIO)
if(PTHREAD_SETSCHEDPRIO)
winpr_definition_add(PTHREAD_SETSCHEDPRIO)
endif()
if(ANDROID)
winpr_library_add_private(log)
endif()
# Level "1" API as defined for MinCore.lib
set(WINPR_CORE
synch
library
file
comm
credentials
pipe
interlocked
security
environment
crypto
registry
path
io
memory
ncrypt
input
shell
utils
error
timezone
sysinfo
pool
handle
thread
)
foreach(DIR ${WINPR_CORE})
add_subdirectory(${DIR})
source_group("${DIR}" REGULAR_EXPRESSION "${DIR}/.*\\.[ch]")
endforeach()
set(WINPR_LEVEL2
winsock
sspi
sspicli
crt
bcrypt
rpc
wtsapi
dsparse
smartcard
nt
clipboard
)
foreach(DIR ${WINPR_LEVEL2})
add_subdirectory(${DIR})
source_group("${DIR}" REGULAR_EXPRESSION "${DIR}/.*\\.[ch]")
endforeach()
set(MODULE_NAME winpr)
list(REMOVE_DUPLICATES WINPR_DEFINITIONS)
list(REMOVE_DUPLICATES WINPR_COMPILE_OPTIONS)
list(REMOVE_DUPLICATES WINPR_LINK_OPTIONS)
list(REMOVE_DUPLICATES WINPR_LINK_DIRS)
list(REMOVE_DUPLICATES WINPR_INCLUDES)
list(REMOVE_DUPLICATES WINPR_SYSTEM_INCLUDES)
addtargetwithresourcefile(${MODULE_NAME} FALSE "${WINPR_VERSION}" WINPR_SRCS)
if(WITH_RESOURCE_VERSIONING)
target_compile_definitions(${MODULE_NAME} PRIVATE WITH_RESOURCE_VERSIONING)
endif()
if(WINPR_USE_VENDOR_PRODUCT_CONFIG_DIR)
target_compile_definitions(${MODULE_NAME} PRIVATE WINPR_USE_VENDOR_PRODUCT_CONFIG_DIR)
endif()
if(APPLE)
set_target_properties(${MODULE_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION FALSE)
endif()
if(NOT BUILD_SHARED_LIBS)
set(LINK_OPTS_MODE PUBLIC)
else()
set(LINK_OPTS_MODE PRIVATE)
endif()
target_link_options(${MODULE_NAME} ${LINK_OPTS_MODE} ${WINPR_LINK_OPTIONS})
target_include_directories(${MODULE_NAME} PRIVATE ${WINPR_INCLUDES})
target_include_directories(${MODULE_NAME} SYSTEM PRIVATE ${WINPR_SYSTEM_INCLUDES})
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include/winpr${WINPR_VERSION_MAJOR}>)
target_link_directories(${MODULE_NAME} PRIVATE ${WINPR_LINK_DIRS})
target_compile_options(${MODULE_NAME} PRIVATE ${WINPR_COMPILE_OPTIONS})
target_compile_definitions(${MODULE_NAME} PRIVATE ${WINPR_DEFINITIONS})
target_link_libraries(${MODULE_NAME} PRIVATE ${WINPR_LIBS_PRIVATE} PUBLIC ${WINPR_LIBS_PUBLIC})
installwithrpath(
TARGETS
${MODULE_NAME}
COMPONENT
libraries
EXPORT
WinPRTargets
ARCHIVE
DESTINATION
${CMAKE_INSTALL_LIBDIR}
LIBRARY
DESTINATION
${CMAKE_INSTALL_LIBDIR}
RUNTIME
DESTINATION
${CMAKE_INSTALL_BINDIR}
)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr")

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-bcrypt cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(bcrypt.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "bcrypt")
set(MINWIN_LONG_NAME "Cryptography API: Next Generation (CNG)")
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")

View File

@@ -0,0 +1,154 @@
/**
* WinPR: Windows Portable Runtime
* Cryptography API: Next Generation
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/wlog.h>
#ifndef _WIN32
#include <winpr/bcrypt.h>
/**
* Cryptography API: Next Generation:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa376210/
*/
NTSTATUS BCryptOpenAlgorithmProvider(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE* phAlgorithm,
WINPR_ATTR_UNUSED LPCWSTR pszAlgId,
WINPR_ATTR_UNUSED LPCWSTR pszImplementation,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptCloseAlgorithmProvider(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptGetProperty(WINPR_ATTR_UNUSED BCRYPT_HANDLE hObject,
WINPR_ATTR_UNUSED LPCWSTR pszProperty, WINPR_ATTR_UNUSED PUCHAR pbOutput,
WINPR_ATTR_UNUSED ULONG cbOutput, WINPR_ATTR_UNUSED ULONG* pcbResult,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptCreateHash(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED BCRYPT_HASH_HANDLE* phHash,
WINPR_ATTR_UNUSED PUCHAR pbHashObject,
WINPR_ATTR_UNUSED ULONG cbHashObject, WINPR_ATTR_UNUSED PUCHAR pbSecret,
WINPR_ATTR_UNUSED ULONG cbSecret, WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptDestroyHash(WINPR_ATTR_UNUSED BCRYPT_HASH_HANDLE hHash)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptHashData(WINPR_ATTR_UNUSED BCRYPT_HASH_HANDLE hHash,
WINPR_ATTR_UNUSED PUCHAR pbInput, WINPR_ATTR_UNUSED ULONG cbInput,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptFinishHash(WINPR_ATTR_UNUSED BCRYPT_HASH_HANDLE hHash,
WINPR_ATTR_UNUSED PUCHAR pbOutput, WINPR_ATTR_UNUSED ULONG cbOutput,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptGenRandom(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED PUCHAR pbBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptGenerateSymmetricKey(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE* phKey,
WINPR_ATTR_UNUSED PUCHAR pbKeyObject,
WINPR_ATTR_UNUSED ULONG cbKeyObject,
WINPR_ATTR_UNUSED PUCHAR pbSecret,
WINPR_ATTR_UNUSED ULONG cbSecret,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptGenerateKeyPair(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE* phKey,
WINPR_ATTR_UNUSED ULONG dwLength, WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptImportKey(WINPR_ATTR_UNUSED BCRYPT_ALG_HANDLE hAlgorithm,
WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE hImportKey,
WINPR_ATTR_UNUSED LPCWSTR pszBlobType,
WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE* phKey,
WINPR_ATTR_UNUSED PUCHAR pbKeyObject, WINPR_ATTR_UNUSED ULONG cbKeyObject,
WINPR_ATTR_UNUSED PUCHAR pbInput, WINPR_ATTR_UNUSED ULONG cbInput,
WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptDestroyKey(WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE hKey)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptEncrypt(WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE hKey, WINPR_ATTR_UNUSED PUCHAR pbInput,
WINPR_ATTR_UNUSED ULONG cbInput, WINPR_ATTR_UNUSED VOID* pPaddingInfo,
WINPR_ATTR_UNUSED PUCHAR pbIV, WINPR_ATTR_UNUSED ULONG cbIV,
WINPR_ATTR_UNUSED PUCHAR pbOutput, WINPR_ATTR_UNUSED ULONG cbOutput,
WINPR_ATTR_UNUSED ULONG* pcbResult, WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
NTSTATUS BCryptDecrypt(WINPR_ATTR_UNUSED BCRYPT_KEY_HANDLE hKey, WINPR_ATTR_UNUSED PUCHAR pbInput,
WINPR_ATTR_UNUSED ULONG cbInput, WINPR_ATTR_UNUSED VOID* pPaddingInfo,
WINPR_ATTR_UNUSED PUCHAR pbIV, WINPR_ATTR_UNUSED ULONG cbIV,
WINPR_ATTR_UNUSED PUCHAR pbOutput, WINPR_ATTR_UNUSED ULONG cbOutput,
WINPR_ATTR_UNUSED ULONG* pcbResult, WINPR_ATTR_UNUSED ULONG dwFlags)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
#endif /* _WIN32 */

View File

@@ -0,0 +1,21 @@
set(MODULE_NAME "TestBCrypt")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(DRIVER ${MODULE_NAME}.c)
set(TESTS TestBCryptDefine.c)
create_test_sourcelist(SRCS ${DRIVER} ${TESTS})
add_executable(${MODULE_NAME} ${SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,129 @@
#include <stdio.h>
#include <winpr/string.h>
#include <winpr/bcrypt.h>
#define STR(x) #x
static BOOL test_wchar_len(void)
{
struct test_case
{
size_t bytelen;
const char* name;
const WCHAR* value;
};
const struct test_case test_cases[] = {
{ sizeof(BCRYPT_RSA_ALGORITHM), STR(BCRYPT_RSA_ALGORITHM), BCRYPT_RSA_ALGORITHM },
{ sizeof(BCRYPT_RSA_SIGN_ALGORITHM), STR(BCRYPT_RSA_SIGN_ALGORITHM),
BCRYPT_RSA_SIGN_ALGORITHM },
{ sizeof(BCRYPT_DH_ALGORITHM), STR(BCRYPT_DH_ALGORITHM), BCRYPT_DH_ALGORITHM },
{ sizeof(BCRYPT_DSA_ALGORITHM), STR(BCRYPT_DSA_ALGORITHM), BCRYPT_DSA_ALGORITHM },
{ sizeof(BCRYPT_RC2_ALGORITHM), STR(BCRYPT_RC2_ALGORITHM), BCRYPT_RC2_ALGORITHM },
{ sizeof(BCRYPT_RC4_ALGORITHM), STR(BCRYPT_RC4_ALGORITHM), BCRYPT_RC4_ALGORITHM },
{ sizeof(BCRYPT_AES_ALGORITHM), STR(BCRYPT_AES_ALGORITHM), BCRYPT_AES_ALGORITHM },
{ sizeof(BCRYPT_DES_ALGORITHM), STR(BCRYPT_DES_ALGORITHM), BCRYPT_DES_ALGORITHM },
{ sizeof(BCRYPT_DESX_ALGORITHM), STR(BCRYPT_DESX_ALGORITHM), BCRYPT_DESX_ALGORITHM },
{ sizeof(BCRYPT_3DES_ALGORITHM), STR(BCRYPT_3DES_ALGORITHM), BCRYPT_3DES_ALGORITHM },
{ sizeof(BCRYPT_3DES_112_ALGORITHM), STR(BCRYPT_3DES_112_ALGORITHM),
BCRYPT_3DES_112_ALGORITHM },
{ sizeof(BCRYPT_MD2_ALGORITHM), STR(BCRYPT_MD2_ALGORITHM), BCRYPT_MD2_ALGORITHM },
{ sizeof(BCRYPT_MD4_ALGORITHM), STR(BCRYPT_MD4_ALGORITHM), BCRYPT_MD4_ALGORITHM },
{ sizeof(BCRYPT_MD5_ALGORITHM), STR(BCRYPT_MD5_ALGORITHM), BCRYPT_MD5_ALGORITHM },
{ sizeof(BCRYPT_SHA1_ALGORITHM), STR(BCRYPT_SHA1_ALGORITHM), BCRYPT_SHA1_ALGORITHM },
{ sizeof(BCRYPT_SHA256_ALGORITHM), STR(BCRYPT_SHA256_ALGORITHM), BCRYPT_SHA256_ALGORITHM },
{ sizeof(BCRYPT_SHA384_ALGORITHM), STR(BCRYPT_SHA384_ALGORITHM), BCRYPT_SHA384_ALGORITHM },
{ sizeof(BCRYPT_SHA512_ALGORITHM), STR(BCRYPT_SHA512_ALGORITHM), BCRYPT_SHA512_ALGORITHM },
{ sizeof(BCRYPT_AES_GMAC_ALGORITHM), STR(BCRYPT_AES_GMAC_ALGORITHM),
BCRYPT_AES_GMAC_ALGORITHM },
{ sizeof(BCRYPT_AES_CMAC_ALGORITHM), STR(BCRYPT_AES_CMAC_ALGORITHM),
BCRYPT_AES_CMAC_ALGORITHM },
{ sizeof(BCRYPT_ECDSA_P256_ALGORITHM), STR(BCRYPT_ECDSA_P256_ALGORITHM),
BCRYPT_ECDSA_P256_ALGORITHM },
{ sizeof(BCRYPT_ECDSA_P384_ALGORITHM), STR(BCRYPT_ECDSA_P384_ALGORITHM),
BCRYPT_ECDSA_P384_ALGORITHM },
{ sizeof(BCRYPT_ECDSA_P521_ALGORITHM), STR(BCRYPT_ECDSA_P521_ALGORITHM),
BCRYPT_ECDSA_P521_ALGORITHM },
{ sizeof(BCRYPT_ECDH_P256_ALGORITHM), STR(BCRYPT_ECDH_P256_ALGORITHM),
BCRYPT_ECDH_P256_ALGORITHM },
{ sizeof(BCRYPT_ECDH_P384_ALGORITHM), STR(BCRYPT_ECDH_P384_ALGORITHM),
BCRYPT_ECDH_P384_ALGORITHM },
{ sizeof(BCRYPT_ECDH_P521_ALGORITHM), STR(BCRYPT_ECDH_P521_ALGORITHM),
BCRYPT_ECDH_P521_ALGORITHM },
{ sizeof(BCRYPT_RNG_ALGORITHM), STR(BCRYPT_RNG_ALGORITHM), BCRYPT_RNG_ALGORITHM },
{ sizeof(BCRYPT_RNG_FIPS186_DSA_ALGORITHM), STR(BCRYPT_RNG_FIPS186_DSA_ALGORITHM),
BCRYPT_RNG_FIPS186_DSA_ALGORITHM },
{ sizeof(BCRYPT_RNG_DUAL_EC_ALGORITHM), STR(BCRYPT_RNG_DUAL_EC_ALGORITHM),
BCRYPT_RNG_DUAL_EC_ALGORITHM },
// The following algorithms are only supported on windows 10 onward.
#if !defined(_WIN32) || _WIN32_WINNT >= 0x0A00
{ sizeof(BCRYPT_ECDSA_ALGORITHM), STR(BCRYPT_ECDSA_ALGORITHM), BCRYPT_ECDSA_ALGORITHM },
{ sizeof(BCRYPT_ECDH_ALGORITHM), STR(BCRYPT_ECDH_ALGORITHM), BCRYPT_ECDH_ALGORITHM },
{ sizeof(BCRYPT_XTS_AES_ALGORITHM), STR(BCRYPT_XTS_AES_ALGORITHM),
BCRYPT_XTS_AES_ALGORITHM },
#endif
{ sizeof(MS_PRIMITIVE_PROVIDER), STR(MS_PRIMITIVE_PROVIDER), MS_PRIMITIVE_PROVIDER },
{ sizeof(MS_PLATFORM_CRYPTO_PROVIDER), STR(MS_PLATFORM_CRYPTO_PROVIDER),
MS_PLATFORM_CRYPTO_PROVIDER },
{ sizeof(BCRYPT_OBJECT_LENGTH), STR(BCRYPT_OBJECT_LENGTH), BCRYPT_OBJECT_LENGTH },
{ sizeof(BCRYPT_ALGORITHM_NAME), STR(BCRYPT_ALGORITHM_NAME), BCRYPT_ALGORITHM_NAME },
{ sizeof(BCRYPT_PROVIDER_HANDLE), STR(BCRYPT_PROVIDER_HANDLE), BCRYPT_PROVIDER_HANDLE },
{ sizeof(BCRYPT_CHAINING_MODE), STR(BCRYPT_CHAINING_MODE), BCRYPT_CHAINING_MODE },
{ sizeof(BCRYPT_BLOCK_LENGTH), STR(BCRYPT_BLOCK_LENGTH), BCRYPT_BLOCK_LENGTH },
{ sizeof(BCRYPT_KEY_LENGTH), STR(BCRYPT_KEY_LENGTH), BCRYPT_KEY_LENGTH },
{ sizeof(BCRYPT_KEY_OBJECT_LENGTH), STR(BCRYPT_KEY_OBJECT_LENGTH),
BCRYPT_KEY_OBJECT_LENGTH },
{ sizeof(BCRYPT_KEY_STRENGTH), STR(BCRYPT_KEY_STRENGTH), BCRYPT_KEY_STRENGTH },
{ sizeof(BCRYPT_KEY_LENGTHS), STR(BCRYPT_KEY_LENGTHS), BCRYPT_KEY_LENGTHS },
{ sizeof(BCRYPT_BLOCK_SIZE_LIST), STR(BCRYPT_BLOCK_SIZE_LIST), BCRYPT_BLOCK_SIZE_LIST },
{ sizeof(BCRYPT_EFFECTIVE_KEY_LENGTH), STR(BCRYPT_EFFECTIVE_KEY_LENGTH),
BCRYPT_EFFECTIVE_KEY_LENGTH },
{ sizeof(BCRYPT_HASH_LENGTH), STR(BCRYPT_HASH_LENGTH), BCRYPT_HASH_LENGTH },
{ sizeof(BCRYPT_HASH_OID_LIST), STR(BCRYPT_HASH_OID_LIST), BCRYPT_HASH_OID_LIST },
{ sizeof(BCRYPT_PADDING_SCHEMES), STR(BCRYPT_PADDING_SCHEMES), BCRYPT_PADDING_SCHEMES },
{ sizeof(BCRYPT_SIGNATURE_LENGTH), STR(BCRYPT_SIGNATURE_LENGTH), BCRYPT_SIGNATURE_LENGTH },
{ sizeof(BCRYPT_HASH_BLOCK_LENGTH), STR(BCRYPT_HASH_BLOCK_LENGTH),
BCRYPT_HASH_BLOCK_LENGTH },
{ sizeof(BCRYPT_AUTH_TAG_LENGTH), STR(BCRYPT_AUTH_TAG_LENGTH), BCRYPT_AUTH_TAG_LENGTH },
{ sizeof(BCRYPT_PRIMITIVE_TYPE), STR(BCRYPT_PRIMITIVE_TYPE), BCRYPT_PRIMITIVE_TYPE },
{ sizeof(BCRYPT_IS_KEYED_HASH), STR(BCRYPT_IS_KEYED_HASH), BCRYPT_IS_KEYED_HASH },
{ sizeof(BCRYPT_KEY_DATA_BLOB), STR(BCRYPT_KEY_DATA_BLOB), BCRYPT_KEY_DATA_BLOB }
};
BOOL rc = TRUE;
for (size_t x = 0; x < ARRAYSIZE(test_cases); x++)
{
const struct test_case* cur = &test_cases[x];
// sizeof(WCHAR) == 2, so all strings must have even byte length
if (cur->bytelen % 2 != 0)
{
(void)fprintf(stderr, "[%s] invalid bytelength %" PRIuz, cur->name, cur->bytelen);
rc = FALSE;
continue;
}
// each string must be '\0' terminated
const size_t len = _wcsnlen(cur->value, cur->bytelen / sizeof(WCHAR));
if (len == cur->bytelen / sizeof(WCHAR))
{
(void)fprintf(stderr, "[%s] missing '\0' termination", cur->name);
rc = FALSE;
continue;
}
}
return rc;
}
int TestBCryptDefine(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_wchar_len())
return -1;
return 0;
}

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-clipboard cmake build script
#
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(synthetic.c clipboard.c clipboard.h synthetic_file.h synthetic_file.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "clipboard")
set(MINWIN_LONG_NAME "Clipboard Functions")
set(MODULE_LIBRARY_NAME "clipboard")

View File

@@ -0,0 +1,771 @@
/**
* WinPR: Windows Portable Runtime
* Clipboard Functions
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/collections.h>
#include <winpr/wlog.h>
#include <winpr/clipboard.h>
#include "clipboard.h"
#include "synthetic_file.h"
#include "../log.h"
#define TAG WINPR_TAG("clipboard")
const char* const mime_text_plain = "text/plain";
/**
* Clipboard (Windows):
* msdn.microsoft.com/en-us/library/windows/desktop/ms648709/
*
* W3C Clipboard API and events:
* http://www.w3.org/TR/clipboard-apis/
*/
static const char* CF_STANDARD_STRINGS[] = {
"CF_RAW", /* 0 */
"CF_TEXT", /* 1 */
"CF_BITMAP", /* 2 */
"CF_METAFILEPICT", /* 3 */
"CF_SYLK", /* 4 */
"CF_DIF", /* 5 */
"CF_TIFF", /* 6 */
"CF_OEMTEXT", /* 7 */
"CF_DIB", /* 8 */
"CF_PALETTE", /* 9 */
"CF_PENDATA", /* 10 */
"CF_RIFF", /* 11 */
"CF_WAVE", /* 12 */
"CF_UNICODETEXT", /* 13 */
"CF_ENHMETAFILE", /* 14 */
"CF_HDROP", /* 15 */
"CF_LOCALE", /* 16 */
"CF_DIBV5" /* 17 */
};
const char* ClipboardGetFormatIdString(UINT32 formatId)
{
if (formatId < ARRAYSIZE(CF_STANDARD_STRINGS))
return CF_STANDARD_STRINGS[formatId];
return "CF_REGISTERED_FORMAT";
}
static wClipboardFormat* ClipboardFindFormat(wClipboard* clipboard, UINT32 formatId,
const char* name)
{
wClipboardFormat* format = nullptr;
if (!clipboard)
return nullptr;
if (formatId)
{
for (UINT32 index = 0; index < clipboard->numFormats; index++)
{
wClipboardFormat* cformat = &clipboard->formats[index];
if (formatId == cformat->formatId)
{
format = cformat;
break;
}
}
}
else if (name)
{
for (UINT32 index = 0; index < clipboard->numFormats; index++)
{
wClipboardFormat* cformat = &clipboard->formats[index];
if (!cformat->formatName)
continue;
if (strcmp(name, cformat->formatName) == 0)
{
format = cformat;
break;
}
}
}
else
{
/* special "CF_RAW" case */
if (clipboard->numFormats > 0)
{
format = &clipboard->formats[0];
if (format->formatId)
return nullptr;
if (!format->formatName || (strcmp(format->formatName, CF_STANDARD_STRINGS[0]) == 0))
return format;
}
}
return format;
}
static wClipboardSynthesizer* ClipboardFindSynthesizer(wClipboardFormat* format, UINT32 formatId)
{
if (!format)
return nullptr;
for (UINT32 index = 0; index < format->numSynthesizers; index++)
{
wClipboardSynthesizer* synthesizer = &(format->synthesizers[index]);
if (formatId == synthesizer->syntheticId)
return synthesizer;
}
return nullptr;
}
void ClipboardLock(wClipboard* clipboard)
{
if (!clipboard)
return;
EnterCriticalSection(&(clipboard->lock));
}
void ClipboardUnlock(wClipboard* clipboard)
{
if (!clipboard)
return;
LeaveCriticalSection(&(clipboard->lock));
}
BOOL ClipboardEmpty(wClipboard* clipboard)
{
if (!clipboard)
return FALSE;
if (clipboard->data)
{
free(clipboard->data);
clipboard->data = nullptr;
}
clipboard->size = 0;
clipboard->formatId = 0;
clipboard->sequenceNumber++;
return TRUE;
}
UINT32 ClipboardCountRegisteredFormats(wClipboard* clipboard)
{
if (!clipboard)
return 0;
return clipboard->numFormats;
}
UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** ppFormatIds)
{
UINT32* pFormatIds = nullptr;
wClipboardFormat* format = nullptr;
if (!clipboard)
return 0;
if (!ppFormatIds)
return 0;
pFormatIds = *ppFormatIds;
if (!pFormatIds)
{
pFormatIds = calloc(clipboard->numFormats, sizeof(UINT32));
if (!pFormatIds)
return 0;
*ppFormatIds = pFormatIds;
}
for (UINT32 index = 0; index < clipboard->numFormats; index++)
{
format = &(clipboard->formats[index]);
pFormatIds[index] = format->formatId;
}
return clipboard->numFormats;
}
UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name)
{
wClipboardFormat* format = nullptr;
if (!clipboard)
return 0;
format = ClipboardFindFormat(clipboard, 0, name);
if (format)
return format->formatId;
if ((clipboard->numFormats + 1) >= clipboard->maxFormats)
{
UINT32 numFormats = clipboard->maxFormats * 2;
wClipboardFormat* tmpFormat = nullptr;
tmpFormat =
(wClipboardFormat*)realloc(clipboard->formats, numFormats * sizeof(wClipboardFormat));
if (!tmpFormat)
return 0;
clipboard->formats = tmpFormat;
clipboard->maxFormats = numFormats;
}
format = &(clipboard->formats[clipboard->numFormats]);
ZeroMemory(format, sizeof(wClipboardFormat));
if (name)
{
format->formatName = _strdup(name);
if (!format->formatName)
return 0;
}
format->formatId = clipboard->nextFormatId++;
clipboard->numFormats++;
return format->formatId;
}
BOOL ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, UINT32 syntheticId,
CLIPBOARD_SYNTHESIZE_FN pfnSynthesize)
{
UINT32 index = 0;
wClipboardFormat* format = nullptr;
wClipboardSynthesizer* synthesizer = nullptr;
if (!clipboard)
return FALSE;
format = ClipboardFindFormat(clipboard, formatId, nullptr);
if (!format)
return FALSE;
if (format->formatId == syntheticId)
return FALSE;
synthesizer = ClipboardFindSynthesizer(format, formatId);
if (!synthesizer)
{
wClipboardSynthesizer* tmpSynthesizer = nullptr;
UINT32 numSynthesizers = format->numSynthesizers + 1;
tmpSynthesizer = (wClipboardSynthesizer*)realloc(
format->synthesizers, numSynthesizers * sizeof(wClipboardSynthesizer));
if (!tmpSynthesizer)
return FALSE;
format->synthesizers = tmpSynthesizer;
format->numSynthesizers = numSynthesizers;
index = numSynthesizers - 1;
synthesizer = &(format->synthesizers[index]);
}
synthesizer->syntheticId = syntheticId;
synthesizer->pfnSynthesize = pfnSynthesize;
return TRUE;
}
UINT32 ClipboardCountFormats(wClipboard* clipboard)
{
UINT32 count = 0;
wClipboardFormat* format = nullptr;
if (!clipboard)
return 0;
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
if (!format)
return 0;
count = 1 + format->numSynthesizers;
return count;
}
UINT32 ClipboardGetFormatIds(wClipboard* clipboard, UINT32** ppFormatIds)
{
UINT32 count = 0;
UINT32* pFormatIds = nullptr;
wClipboardFormat* format = nullptr;
wClipboardSynthesizer* synthesizer = nullptr;
if (!clipboard)
return 0;
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
if (!format)
return 0;
count = 1 + format->numSynthesizers;
if (!ppFormatIds)
return 0;
pFormatIds = *ppFormatIds;
if (!pFormatIds)
{
pFormatIds = calloc(count, sizeof(UINT32));
if (!pFormatIds)
return 0;
*ppFormatIds = pFormatIds;
}
pFormatIds[0] = format->formatId;
for (UINT32 index = 1; index < count; index++)
{
synthesizer = &(format->synthesizers[index - 1]);
pFormatIds[index] = synthesizer->syntheticId;
}
return count;
}
static void ClipboardUninitFormats(wClipboard* clipboard)
{
WINPR_ASSERT(clipboard);
for (UINT32 formatId = 0; formatId < clipboard->numFormats; formatId++)
{
wClipboardFormat* format = &clipboard->formats[formatId];
free(format->formatName);
free(format->synthesizers);
format->formatName = nullptr;
format->synthesizers = nullptr;
}
}
static BOOL ClipboardInitFormats(wClipboard* clipboard)
{
UINT32 formatId = 0;
wClipboardFormat* format = nullptr;
if (!clipboard)
return FALSE;
for (formatId = 0; formatId < CF_MAX; formatId++, clipboard->numFormats++)
{
format = &(clipboard->formats[clipboard->numFormats]);
ZeroMemory(format, sizeof(wClipboardFormat));
format->formatId = formatId;
format->formatName = _strdup(CF_STANDARD_STRINGS[formatId]);
if (!format->formatName)
goto error;
}
if (!ClipboardInitSynthesizers(clipboard))
goto error;
return TRUE;
error:
ClipboardUninitFormats(clipboard);
return FALSE;
}
UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name)
{
wClipboardFormat* format = nullptr;
if (!clipboard)
return 0;
format = ClipboardFindFormat(clipboard, 0, name);
if (!format)
return 0;
return format->formatId;
}
const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId)
{
wClipboardFormat* format = nullptr;
if (!clipboard)
return nullptr;
format = ClipboardFindFormat(clipboard, formatId, nullptr);
if (!format)
return nullptr;
return format->formatName;
}
void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize)
{
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
void* pSrcData = nullptr;
void* pDstData = nullptr;
wClipboardFormat* format = nullptr;
wClipboardSynthesizer* synthesizer = nullptr;
if (!clipboard || !pSize)
{
WLog_ERR(TAG, "Invalid parameters clipboard=%p, pSize=%p",
WINPR_CXX_COMPAT_CAST(const void*, clipboard),
WINPR_CXX_COMPAT_CAST(const void*, pSize));
return nullptr;
}
*pSize = 0;
format = ClipboardFindFormat(clipboard, clipboard->formatId, nullptr);
if (!format)
{
WLog_ERR(TAG, "Format [0x%08" PRIx32 "] not found", clipboard->formatId);
return nullptr;
}
SrcSize = clipboard->size;
pSrcData = clipboard->data;
if (formatId == format->formatId)
{
DstSize = SrcSize;
pDstData = malloc(DstSize);
if (!pDstData)
return nullptr;
CopyMemory(pDstData, pSrcData, SrcSize);
*pSize = DstSize;
}
else
{
synthesizer = ClipboardFindSynthesizer(format, formatId);
if (!synthesizer || !synthesizer->pfnSynthesize)
{
WLog_ERR(TAG, "No synthesizer for format %s [0x%08" PRIx32 "] --> %s [0x%08" PRIx32 "]",
ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId,
ClipboardGetFormatName(clipboard, formatId), formatId);
return nullptr;
}
DstSize = SrcSize;
pDstData = synthesizer->pfnSynthesize(clipboard, format->formatId, pSrcData, &DstSize);
if (pDstData)
*pSize = DstSize;
}
WLog_DBG(TAG, "getting formatId=%s [0x%08" PRIx32 "] data=%p, size=%" PRIu32,
ClipboardGetFormatName(clipboard, formatId), formatId, pDstData, *pSize);
return pDstData;
}
BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size)
{
wClipboardFormat* format = nullptr;
WLog_DBG(TAG, "setting formatId=%s [0x%08" PRIx32 "], size=%" PRIu32,
ClipboardGetFormatName(clipboard, formatId), formatId, size);
if (!clipboard)
return FALSE;
format = ClipboardFindFormat(clipboard, formatId, nullptr);
if (!format)
return FALSE;
free(clipboard->data);
clipboard->data = calloc(size + sizeof(WCHAR), sizeof(char));
if (!clipboard->data)
return FALSE;
memcpy(clipboard->data, data, size);
/* For string values we don´t know if they are '\0' terminated.
* so set the size to the full length in bytes (e.g. string length + 1)
*/
switch (formatId)
{
case CF_TEXT:
case CF_OEMTEXT:
clipboard->size = (UINT32)(strnlen(clipboard->data, size) + 1UL);
break;
case CF_UNICODETEXT:
clipboard->size =
(UINT32)((_wcsnlen(clipboard->data, size / sizeof(WCHAR)) + 1UL) * sizeof(WCHAR));
break;
default:
clipboard->size = size;
break;
}
clipboard->formatId = formatId;
clipboard->sequenceNumber++;
return TRUE;
}
UINT64 ClipboardGetOwner(wClipboard* clipboard)
{
if (!clipboard)
return 0;
return clipboard->ownerId;
}
void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId)
{
if (!clipboard)
return;
clipboard->ownerId = ownerId;
}
wClipboardDelegate* ClipboardGetDelegate(wClipboard* clipboard)
{
if (!clipboard)
return nullptr;
return &clipboard->delegate;
}
static void ClipboardInitLocalFileSubsystem(wClipboard* clipboard)
{
/*
* There can be only one local file subsystem active.
* Return as soon as initialization succeeds.
*/
if (ClipboardInitSyntheticFileSubsystem(clipboard))
{
WLog_DBG(TAG, "initialized synthetic local file subsystem");
return;
}
else
{
WLog_WARN(TAG, "failed to initialize synthetic local file subsystem");
}
WLog_INFO(TAG, "failed to initialize local file subsystem, file transfer not available");
}
wClipboard* ClipboardCreate(void)
{
wClipboard* clipboard = (wClipboard*)calloc(1, sizeof(wClipboard));
if (!clipboard)
return nullptr;
clipboard->nextFormatId = 0xC000;
clipboard->sequenceNumber = 0;
if (!InitializeCriticalSectionAndSpinCount(&(clipboard->lock), 4000))
goto fail;
clipboard->numFormats = 0;
clipboard->maxFormats = 64;
clipboard->formats = (wClipboardFormat*)calloc(clipboard->maxFormats, sizeof(wClipboardFormat));
if (!clipboard->formats)
goto fail;
if (!ClipboardInitFormats(clipboard))
goto fail;
clipboard->delegate.clipboard = clipboard;
ClipboardInitLocalFileSubsystem(clipboard);
return clipboard;
fail:
ClipboardDestroy(clipboard);
return nullptr;
}
void ClipboardDestroy(wClipboard* clipboard)
{
if (!clipboard)
return;
ArrayList_Free(clipboard->localFiles);
clipboard->localFiles = nullptr;
ClipboardUninitFormats(clipboard);
free(clipboard->data);
clipboard->data = nullptr;
clipboard->size = 0;
clipboard->numFormats = 0;
free(clipboard->formats);
DeleteCriticalSection(&(clipboard->lock));
free(clipboard);
}
static BOOL is_dos_drive(const char* path, size_t len)
{
if (len < 2)
return FALSE;
WINPR_ASSERT(path);
if (path[1] == ':' || path[1] == '|')
{
if (((path[0] >= 'A') && (path[0] <= 'Z')) || ((path[0] >= 'a') && (path[0] <= 'z')))
return TRUE;
}
return FALSE;
}
char* parse_uri_to_local_file(const char* uri, size_t uri_len)
{
// URI is specified by RFC 8089: https://datatracker.ietf.org/doc/html/rfc8089
const char prefix[] = "file:";
const char prefixTraditional[] = "file://";
const char* localName = nullptr;
size_t localLen = 0;
char* buffer = nullptr;
const size_t prefixLen = strnlen(prefix, sizeof(prefix));
const size_t prefixTraditionalLen = strnlen(prefixTraditional, sizeof(prefixTraditional));
WINPR_ASSERT(uri || (uri_len == 0));
WLog_VRB(TAG, "processing URI: %.*s", WINPR_ASSERTING_INT_CAST(int, uri_len), uri);
if ((uri_len <= prefixLen) || strncmp(uri, prefix, prefixLen) != 0)
{
WLog_ERR(TAG, "non-'file:' URI schemes are not supported");
return nullptr;
}
do
{
/* https://datatracker.ietf.org/doc/html/rfc8089#appendix-F
* - The minimal representation of a local file in a DOS- or Windows-
* based environment with no authority field and an absolute path
* that begins with a drive letter.
*
* "file:c:/path/to/file"
*
* - Regular DOS or Windows file URIs with vertical line characters in
* the drive letter construct.
*
* "file:c|/path/to/file"
*
*/
if (uri[prefixLen] != '/')
{
if (is_dos_drive(&uri[prefixLen], uri_len - prefixLen))
{
// Dos and Windows file URI
localName = &uri[prefixLen];
localLen = uri_len - prefixLen;
break;
}
else
{
WLog_ERR(TAG, "URI format are not supported: %s", uri);
return nullptr;
}
}
/*
* - The minimal representation of a local file with no authority field
* and an absolute path that begins with a slash "/". For example:
*
* "file:/path/to/file"
*
*/
else if ((uri_len > prefixLen + 1) && (uri[prefixLen + 1] != '/'))
{
if (is_dos_drive(&uri[prefixLen + 1], uri_len - prefixLen - 1))
{
// Dos and Windows file URI
localName = (uri + prefixLen + 1);
localLen = uri_len - prefixLen - 1;
}
else
{
localName = &uri[prefixLen];
localLen = uri_len - prefixLen;
}
break;
}
/*
* - A traditional file URI for a local file with an empty authority.
*
* "file:///path/to/file"
*/
if ((uri_len < prefixTraditionalLen) ||
strncmp(uri, prefixTraditional, prefixTraditionalLen) != 0)
{
WLog_ERR(TAG, "non-'file:' URI schemes are not supported");
return nullptr;
}
localName = &uri[prefixTraditionalLen];
localLen = uri_len - prefixTraditionalLen;
if (localLen < 1)
{
WLog_ERR(TAG, "empty 'file:' URI schemes are not supported");
return nullptr;
}
/*
* "file:///c:/path/to/file"
* "file:///c|/path/to/file"
*/
if (localName[0] != '/')
{
WLog_ERR(TAG, "URI format are not supported: %s", uri);
return nullptr;
}
if (is_dos_drive(&localName[1], localLen - 1))
{
localName++;
localLen--;
}
} while (0);
buffer = winpr_str_url_decode(localName, localLen);
if (buffer)
{
if (buffer[1] == '|' &&
((buffer[0] >= 'A' && buffer[0] <= 'Z') || (buffer[0] >= 'a' && buffer[0] <= 'z')))
buffer[1] = ':';
return buffer;
}
return nullptr;
}

View File

@@ -0,0 +1,77 @@
/**
* WinPR: Windows Portable Runtime
* Clipboard Functions
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_CLIPBOARD_PRIVATE_H
#define WINPR_CLIPBOARD_PRIVATE_H
#include <winpr/winpr.h>
#include <winpr/clipboard.h>
#include <winpr/collections.h>
typedef struct
{
UINT32 syntheticId;
CLIPBOARD_SYNTHESIZE_FN pfnSynthesize;
} wClipboardSynthesizer;
typedef struct
{
UINT32 formatId;
char* formatName;
UINT32 numSynthesizers;
wClipboardSynthesizer* synthesizers;
} wClipboardFormat;
struct s_wClipboard
{
UINT64 ownerId;
/* clipboard formats */
UINT32 numFormats;
UINT32 maxFormats;
UINT32 nextFormatId;
wClipboardFormat* formats;
/* clipboard data */
UINT32 size;
void* data;
UINT32 formatId;
UINT32 sequenceNumber;
/* clipboard file handling */
wArrayList* localFiles;
UINT32 fileListSequenceNumber;
wClipboardDelegate delegate;
CRITICAL_SECTION lock;
};
WINPR_LOCAL BOOL ClipboardInitSynthesizers(wClipboard* clipboard);
WINPR_LOCAL char* parse_uri_to_local_file(const char* uri, size_t uri_len);
extern const char* const mime_text_plain;
#endif /* WINPR_CLIPBOARD_PRIVATE_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
/**
* WinPR: Windows Portable Runtime
* Clipboard Functions: POSIX file handling
*
* Copyright 2017 Alexei Lozovsky <a.lozovsky@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_CLIPBOARD_POSIX_H
#define WINPR_CLIPBOARD_POSIX_H
#include <winpr/clipboard.h>
BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard);
#endif /* WINPR_CLIPBOARD_POSIX_H */

View File

@@ -0,0 +1,40 @@
set(MODULE_NAME "TestClipboard")
set(MODULE_PREFIX "TEST_CLIPBOARD")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(DRIVER ${MODULE_NAME}.c)
set(TESTS TestClipboardFormats.c)
if(BUILD_TESTING_INTERNAL)
list(APPEND TESTS TestUri.c)
endif()
set(TEST_CLIP_PNG "${CMAKE_SOURCE_DIR}/resources/FreeRDP_Icon.png")
file(TO_NATIVE_PATH "${TEST_CLIP_PNG}" TEST_CLIP_PNG)
set(TEST_CLIP_BMP "${CMAKE_SOURCE_DIR}/resources/FreeRDP_Install.bmp")
file(TO_NATIVE_PATH "${TEST_CLIP_BMP}" TEST_CLIP_BMP)
if(WIN32)
string(REPLACE "\\" "\\\\" TEST_CLIP_PNG "${TEST_CLIP_PNG}")
string(REPLACE "\\" "\\\\" TEST_CLIP_BMP "${TEST_CLIP_BMP}")
endif()
add_compile_definitions(TEST_CLIP_BMP="${TEST_CLIP_BMP}")
add_compile_definitions(TEST_CLIP_PNG="${TEST_CLIP_PNG}")
create_test_sourcelist(SRCS ${DRIVER} ${TESTS})
add_executable(${MODULE_NAME} ${SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,243 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/image.h>
#include <winpr/clipboard.h>
int TestClipboardFormats(int argc, char* argv[])
{
int rc = -1;
UINT32 count = 0;
UINT32* pFormatIds = nullptr;
const char* formatName = nullptr;
wClipboard* clipboard = nullptr;
UINT32 utf8StringFormatId = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
clipboard = ClipboardCreate();
if (!clipboard)
return -1;
const char* mime_types[] = { "text/html", "text/html", "image/bmp",
"image/png", "image/webp", "image/jpeg" };
for (size_t x = 0; x < ARRAYSIZE(mime_types); x++)
{
const char* mime = mime_types[x];
UINT32 id = ClipboardRegisterFormat(clipboard, mime);
(void)fprintf(stderr, "ClipboardRegisterFormat(%s) -> 0x%08" PRIx32 "\n", mime, id);
if (id == 0)
goto fail;
}
utf8StringFormatId = ClipboardRegisterFormat(clipboard, "UTF8_STRING");
pFormatIds = nullptr;
count = ClipboardGetRegisteredFormatIds(clipboard, &pFormatIds);
for (UINT32 index = 0; index < count; index++)
{
UINT32 formatId = pFormatIds[index];
formatName = ClipboardGetFormatName(clipboard, formatId);
(void)fprintf(stderr, "Format: 0x%08" PRIX32 " %s\n", formatId, formatName);
}
free(pFormatIds);
if (1)
{
BOOL bSuccess = 0;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
const char pSrcData[] = "this is a test string";
char* pDstData = nullptr;
SrcSize = (UINT32)(strnlen(pSrcData, ARRAYSIZE(pSrcData)) + 1);
bSuccess = ClipboardSetData(clipboard, utf8StringFormatId, pSrcData, SrcSize);
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
DstSize = 0;
pDstData = (char*)ClipboardGetData(clipboard, utf8StringFormatId, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: %s\n", pDstData);
free(pDstData);
}
if (1)
{
UINT32 DstSize = 0;
char* pSrcData = nullptr;
WCHAR* pDstData = nullptr;
DstSize = 0;
pDstData = (WCHAR*)ClipboardGetData(clipboard, CF_UNICODETEXT, &DstSize);
pSrcData = ConvertWCharNToUtf8Alloc(pDstData, DstSize / sizeof(WCHAR), nullptr);
(void)fprintf(stderr, "ClipboardGetData (synthetic): %s\n", pSrcData);
free(pDstData);
free(pSrcData);
}
pFormatIds = nullptr;
count = ClipboardGetFormatIds(clipboard, &pFormatIds);
for (UINT32 index = 0; index < count; index++)
{
UINT32 formatId = pFormatIds[index];
formatName = ClipboardGetFormatName(clipboard, formatId);
(void)fprintf(stderr, "Format: 0x%08" PRIX32 " %s\n", formatId, formatName);
}
if (1)
{
const char* name = TEST_CLIP_BMP;
BOOL bSuccess = FALSE;
UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/bmp");
wImage* img = winpr_image_new();
if (!img)
goto fail;
if (winpr_image_read(img, name) <= 0)
{
winpr_image_free(img, TRUE);
goto fail;
}
size_t bmpsize = 0;
void* data = winpr_image_write_buffer(img, WINPR_IMAGE_BITMAP, &bmpsize);
bSuccess = ClipboardSetData(clipboard, idBmp, data, bmpsize);
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
free(data);
winpr_image_free(img, TRUE);
if (!bSuccess)
goto fail;
{
UINT32 id = CF_DIB;
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [CF_DIB] %p [%" PRIu32 "]\n", pDstData,
DstSize);
if (!pDstData)
goto fail;
bSuccess = ClipboardSetData(clipboard, id, pDstData, DstSize);
free(pDstData);
if (!bSuccess)
goto fail;
}
{
const uint32_t id = ClipboardGetFormatId(clipboard, "HTML Format");
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
if (!pDstData)
goto fail;
{
FILE* fp = fopen("test.html", "w");
if (fp)
{
(void)fwrite(pDstData, 1, DstSize, fp);
(void)fclose(fp);
}
}
free(pDstData);
}
{
UINT32 id = ClipboardRegisterFormat(clipboard, "image/bmp");
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [image/bmp] %p [%" PRIu32 "]\n", pDstData,
DstSize);
if (!pDstData)
goto fail;
free(pDstData);
if (DstSize != bmpsize)
goto fail;
}
#if defined(WINPR_UTILS_IMAGE_PNG)
{
UINT32 id = ClipboardRegisterFormat(clipboard, "image/png");
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [image/png] %p\n", pDstData);
if (!pDstData)
goto fail;
free(pDstData);
}
{
const char* name = TEST_CLIP_PNG;
BOOL bSuccess = FALSE;
UINT32 idBmp = ClipboardRegisterFormat(clipboard, "image/png");
wImage* img = winpr_image_new();
if (!img)
goto fail;
if (winpr_image_read(img, name) <= 0)
{
winpr_image_free(img, TRUE);
goto fail;
}
size_t bmpsize = 0;
void* data = winpr_image_write_buffer(img, WINPR_IMAGE_PNG, &bmpsize);
bSuccess = ClipboardSetData(clipboard, idBmp, data, bmpsize);
(void)fprintf(stderr, "ClipboardSetData: %" PRId32 "\n", bSuccess);
free(data);
winpr_image_free(img, TRUE);
if (!bSuccess)
goto fail;
}
{
UINT32 id = CF_DIB;
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [CF_DIB] %p [%" PRIu32 "]\n", pDstData,
DstSize);
if (!pDstData)
goto fail;
bSuccess = ClipboardSetData(clipboard, id, pDstData, DstSize);
free(pDstData);
if (!bSuccess)
goto fail;
}
#endif
#if defined(WINPR_UTILS_IMAGE_WEBP)
{
UINT32 id = ClipboardRegisterFormat(clipboard, "image/webp");
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [image/webp] %p\n", pDstData);
if (!pDstData)
goto fail;
free(pDstData);
}
#endif
#if defined(WINPR_UTILS_IMAGE_JPEG)
{
UINT32 id = ClipboardRegisterFormat(clipboard, "image/jpeg");
UINT32 DstSize = 0;
void* pDstData = ClipboardGetData(clipboard, id, &DstSize);
(void)fprintf(stderr, "ClipboardGetData: [image/jpeg] %p\n", pDstData);
if (!pDstData)
goto fail;
free(pDstData);
}
#endif
}
rc = 0;
fail:
free(pFormatIds);
ClipboardDestroy(clipboard);
return rc;
}

View File

@@ -0,0 +1,69 @@
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <stdlib.h>
#include <winpr/winpr.h>
#include "winpr/wlog.h"
#include "../clipboard.h"
#define WINPR_TAG(tag) "com.winpr." tag
#define TAG WINPR_TAG("clipboard.posix")
int TestUri(int argc, char* argv[])
{
int nRet = 0;
const char* input[] = { /*uri, file or nullptr*/
"file://root/a.txt",
nullptr,
"file:a.txt",
nullptr,
"file:///c:/windows/a.txt",
"c:/windows/a.txt",
"file:c:/windows/a.txt",
"c:/windows/a.txt",
"file:c|/windows/a.txt",
"c:/windows/a.txt",
"file:///root/a.txt",
"/root/a.txt",
"file:/root/a.txt",
"/root/a.txt"
};
const size_t nLen = ARRAYSIZE(input);
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
printf("input length:%" PRIuz "\n", nLen / 2);
for (size_t i = 0; i < nLen; i += 2)
{
const char* in = input[i];
const char* cmp = input[i + 1];
int bTest = 0;
char* name = parse_uri_to_local_file(in, strlen(in));
if (name && cmp)
{
bTest = !strcmp(name, cmp);
if (!bTest)
{
printf("Test error: input: %s; Expected value: %s; output: %s\n", in, cmp, name);
nRet++;
}
free(name);
}
else
{
if (cmp)
{
printf("Test error: input: %s; Expected value: %s; output: %s\n", in, cmp, name);
nRet++;
}
}
}
printf("TestUri return value: %d\n", nRet);
return nRet;
}

View File

@@ -0,0 +1,49 @@
# WinPR: Windows Portable Runtime
# libwinpr-comm cmake build script
#
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "winpr-comm")
set(MODULE_PREFIX "WINPR_COMM")
if(NOT WIN32)
set(${MODULE_PREFIX}_SRCS comm.c comm.h)
if(NOT EMSCRIPTEN AND NOT APPLE)
winpr_definition_add(WINPR_HAVE_SERIAL_SUPPORT)
list(
APPEND
${MODULE_PREFIX}_SRCS
comm_io.c
comm_ioctl.c
comm_ioctl.h
comm_serial_sys.c
comm_serial_sys.h
comm_sercx_sys.c
comm_sercx_sys.h
comm_sercx2_sys.c
comm_sercx2_sys.h
)
else()
list(APPEND ${MODULE_PREFIX}_SRCS comm_ioctl_dummy.c comm_ioctl.h)
endif()
winpr_module_add(${${MODULE_PREFIX}_SRCS})
if(NOT EMSCRIPTEN)
if(BUILD_TESTING_INTERNAL AND BUILD_COMM_TESTS)
add_subdirectory(test)
endif()
endif()
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "comm")
set(MINWIN_LONG_NAME "Serial Communication API")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_COMM_PRIVATE_H
#define WINPR_COMM_PRIVATE_H
#if defined(__linux__)
#define WINPR_HAVE_COMM_COUNTERS
#include <linux/serial.h>
#endif
#include <winpr/comm.h>
#include "../handle/handle.h"
#include <winpr/config.h>
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
#include <sys/eventfd.h>
#endif
struct winpr_comm
{
WINPR_HANDLE common;
int fd;
int fd_read;
int fd_read_event; /* as of today, only used by _purge() */
CRITICAL_SECTION ReadLock;
int fd_write;
int fd_write_event; /* as of today, only used by _purge() */
CRITICAL_SECTION WriteLock;
/* permissive mode on errors. If TRUE (default is FALSE)
* CommDeviceIoControl always return TRUE.
*
* Not all features are supported yet and an error is then returned when
* an application turns them on (e.g: i/o buffers > 4096). It appeared
* though that devices and applications can be still functional on such
* errors.
*
* see also: comm_ioctl.c
*
* FIXME: getting rid of this flag once all features supported.
*/
BOOL permissive;
SERIAL_DRIVER_ID serverSerialDriverId;
COMMTIMEOUTS timeouts;
CRITICAL_SECTION
EventsLock; /* protects counters, WaitEventMask and PendingEvents */
#if defined(WINPR_HAVE_COMM_COUNTERS)
struct serial_icounter_struct counters;
#endif
ULONG WaitEventMask;
ULONG PendingEvents;
BYTE eventChar;
/* NB: CloseHandle() has to free resources */
ULONG XOnLimit;
ULONG XOffLimit;
#if defined(WINPR_HAVE_COMM_COUNTERS)
BOOL TIOCGICOUNTSupported;
#endif
};
typedef struct winpr_comm WINPR_COMM;
#define SERIAL_EV_RXCHAR 0x0001
#define SERIAL_EV_RXFLAG 0x0002
#define SERIAL_EV_TXEMPTY 0x0004
#define SERIAL_EV_CTS 0x0008
#define SERIAL_EV_DSR 0x0010
#define SERIAL_EV_RLSD 0x0020
#define SERIAL_EV_BREAK 0x0040
#define SERIAL_EV_ERR 0x0080
#define SERIAL_EV_RING 0x0100
#define SERIAL_EV_PERR 0x0200
#define SERIAL_EV_RX80FULL 0x0400
#define SERIAL_EV_EVENT1 0x0800
#define SERIAL_EV_EVENT2 0x1000
#define SERIAL_EV_WINPR_WAITING 0x4000 /* bit today unused by other SERIAL_EV_* */
#define SERIAL_EV_WINPR_STOP 0x8000 /* bit today unused by other SERIAL_EV_* */
#define WINPR_PURGE_TXABORT 0x00000001 /* abort pending transmission */
#define WINPR_PURGE_RXABORT 0x00000002 /* abort pending reception */
#define CommLog_Print(level, ...) CommLog_PrintEx(level, __FILE__, __LINE__, __func__, __VA_ARGS__)
WINPR_ATTR_FORMAT_ARG(5, 6)
void CommLog_PrintEx(DWORD level, const char* file, size_t line, const char* fkt,
WINPR_FORMAT_ARG const char* fmt, ...);
BOOL CommIsHandled(HANDLE handle);
BOOL CommIsHandleValid(HANDLE handle);
BOOL CommCloseHandle(HANDLE handle);
const HANDLE_CREATOR* GetCommHandleCreator(void);
#define CommIoCtl(pComm, ctl, data) \
CommIoCtl_int((pComm), (ctl), (data), __FILE__, __func__, __LINE__)
BOOL CommIoCtl_int(WINPR_COMM* pComm, unsigned long int ctl, void* data, const char* file,
const char* fkt, size_t line);
BOOL CommUpdateIOCount(HANDLE handle, BOOL checkSupportStatus);
const char* CommSerialEvString(ULONG status, char* buffer, size_t size);
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
#ifndef WITH_EVENTFD_READ_WRITE
int eventfd_read(int fd, eventfd_t* value);
int eventfd_write(int fd, eventfd_t value);
#endif
#endif
#endif /* WINPR_COMM_PRIVATE_H */

View File

@@ -0,0 +1,567 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <winpr/io.h>
#include <winpr/wlog.h>
#include <winpr/wtypes.h>
#include "comm.h"
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
{
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
if (!CommIsHandled(hDevice))
return FALSE;
pComm->permissive = permissive;
return TRUE;
}
/* Computes VTIME in deciseconds from Ti in milliseconds */
static UCHAR svtime(ULONG Ti)
{
/* FIXME: look for an equivalent math function otherwise let
* do the compiler do the optimization */
if (Ti == 0)
return 0;
else if (Ti < 100)
return 1;
else if (Ti > 25500)
return 255; /* 0xFF */
else
return (UCHAR)(Ti / 100);
}
/**
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_NOT_SUPPORTED
* ERROR_INVALID_PARAMETER
* ERROR_TIMEOUT
* ERROR_IO_DEVICE
* ERROR_BAD_DEVICE
*/
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
int biggestFd = -1;
fd_set read_set;
int nbFds = 0;
COMMTIMEOUTS* pTimeouts = nullptr;
UCHAR vmin = 0;
UCHAR vtime = 0;
LONGLONG Tmax = 0;
struct timeval tmaxTimeout;
struct timeval* pTmaxTimeout = nullptr;
struct termios currentTermios;
EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */
if (!CommIsHandled(hDevice))
goto return_false;
if (lpOverlapped != nullptr)
{
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
if (lpNumberOfBytesRead == nullptr)
{
SetLastError(
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
goto return_false;
}
*lpNumberOfBytesRead = 0; /* will be adjusted if required ... */
if (nNumberOfBytesToRead <= 0) /* N */
{
goto return_true; /* FIXME: or FALSE? */
}
if (tcgetattr(pComm->fd, &currentTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (currentTermios.c_lflag & ICANON)
{
CommLog_Print(WLOG_WARN, "Canonical mode not supported"); /* the timeout could not be set */
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
/* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx
* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
*
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME |
* TMAX | 0 | 0 | 0 | N | 0 |
* INDEF | Blocks for N bytes available. 0< Ti <MAXULONG | 0 | 0 |
* N | Ti | INDEF | Blocks on first byte, then use Ti between bytes. MAXULONG | 0 | 0
* | 0 | 0 | 0 | Returns immediately with bytes available (don't block) MAXULONG |
* MAXULONG | 0< Tc <MAXULONG | N | 0 | Tc | Blocks on first byte
* during Tc or returns immediately with bytes available MAXULONG | m |
* MAXULONG | | Invalid 0 | m | 0< Tc
* <MAXULONG | N | 0 | Tmax | Blocks on first byte during Tmax or returns
* immediately with bytes available 0< Ti <MAXULONG | m | 0<
* Tc <MAXULONG | N | Ti | Tmax | Blocks on first byte, then use Ti between bytes.
* Tmax is used for the whole system call.
*/
/* NB: timeouts are in milliseconds, VTIME are in deciseconds and is an unsigned char */
/* FIXME: double check whether open(pComm->fd_read_event, O_NONBLOCK) doesn't conflict with
* above use cases */
pTimeouts = &(pComm->timeouts);
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
(pTimeouts->ReadTotalTimeoutConstant == MAXULONG))
{
CommLog_Print(
WLOG_WARN,
"ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG");
SetLastError(ERROR_INVALID_PARAMETER);
goto return_false;
}
/* VMIN */
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
(pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0))
{
vmin = 0;
}
else
{
/* N */
/* vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255;*/ /* 0xFF */
/* NB: we might wait endlessly with vmin=N, prefer to
* force vmin=1 and return with bytes
* available. FIXME: is a feature disarded here? */
vmin = 1;
}
/* VTIME */
if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG))
{
/* Ti */
vtime = svtime(pTimeouts->ReadIntervalTimeout);
}
/* TMAX */
pTmaxTimeout = &tmaxTimeout;
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
(pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG))
{
/* Tc */
Tmax = pTimeouts->ReadTotalTimeoutConstant;
}
else
{
/* Tmax */
Tmax = 1ll * nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier +
1ll * pTimeouts->ReadTotalTimeoutConstant;
/* INDEFinitely */
if ((Tmax == 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG) &&
(pTimeouts->ReadTotalTimeoutMultiplier == 0))
pTmaxTimeout = nullptr;
}
if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime))
{
currentTermios.c_cc[VMIN] = vmin;
currentTermios.c_cc[VTIME] = vtime;
if (tcsetattr(pComm->fd, TCSANOW, &currentTermios) < 0)
{
CommLog_Print(WLOG_WARN,
"CommReadFile failure, could not apply new timeout values: VMIN=%" PRIu8
", VTIME=%" PRIu8 "",
vmin, vtime);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
/* wait indefinitely if pTmaxTimeout is nullptr */
if (pTmaxTimeout != nullptr)
{
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
if (Tmax > 0) /* return immdiately if Tmax == 0 */
{
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
}
}
/* FIXME: had expected eventfd_write() to return EAGAIN when
* there is no eventfd_read() but this not the case. */
/* discard a possible and no more relevant event */
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
{
eventfd_t val = 0;
(void)eventfd_read(pComm->fd_read_event, &val);
}
#endif
biggestFd = pComm->fd_read;
if (pComm->fd_read_event > biggestFd)
biggestFd = pComm->fd_read_event;
FD_ZERO(&read_set);
WINPR_ASSERT(pComm->fd_read_event < FD_SETSIZE);
WINPR_ASSERT(pComm->fd_read < FD_SETSIZE);
FD_SET(pComm->fd_read_event, &read_set);
FD_SET(pComm->fd_read, &read_set);
nbFds = select(biggestFd + 1, &read_set, nullptr, nullptr, pTmaxTimeout);
if (nbFds < 0)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (nbFds == 0)
{
/* timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
/* read_set */
if (FD_ISSET(pComm->fd_read_event, &read_set))
{
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
eventfd_t event = 0;
if (eventfd_read(pComm->fd_read_event, &event) < 0)
{
if (errno == EAGAIN)
{
WINPR_ASSERT(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN,
"unexpected error on reading fd_read_event, errno=[%d] %s\n", errno,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
/* FIXME: goto return_false ? */
}
WINPR_ASSERT(errno == EAGAIN);
}
if (event == WINPR_PURGE_RXABORT)
{
SetLastError(ERROR_CANCELLED);
goto return_false;
}
WINPR_ASSERT(event == WINPR_PURGE_RXABORT); /* no other expected event so far */
#endif
}
if (FD_ISSET(pComm->fd_read, &read_set))
{
ssize_t nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead);
if ((nbRead < 0) || (nbRead > nNumberOfBytesToRead))
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN,
"CommReadFile failed, ReadIntervalTimeout=%" PRIu32
", ReadTotalTimeoutMultiplier=%" PRIu32
", ReadTotalTimeoutConstant=%" PRIu32 " VMIN=%u, VTIME=%u",
pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier,
pTimeouts->ReadTotalTimeoutConstant, currentTermios.c_cc[VMIN],
currentTermios.c_cc[VTIME]);
CommLog_Print(
WLOG_WARN, "CommReadFile failed, nNumberOfBytesToRead=%" PRIu32 ", errno=[%d] %s",
nNumberOfBytesToRead, errno, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
if (errno == EAGAIN)
{
/* keep on */
goto return_true; /* expect a read-loop to be implemented on the server side */
}
else if (errno == EBADF)
{
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
goto return_false;
}
else
{
WINPR_ASSERT(FALSE);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
if (nbRead == 0)
{
/* termios timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
*lpNumberOfBytesRead = WINPR_ASSERTING_INT_CAST(UINT32, nbRead);
EnterCriticalSection(&pComm->EventsLock);
if (pComm->PendingEvents & SERIAL_EV_WINPR_WAITING)
{
if (pComm->eventChar != '\0' &&
memchr(lpBuffer, pComm->eventChar, WINPR_ASSERTING_INT_CAST(size_t, nbRead)))
pComm->PendingEvents |= SERIAL_EV_RXCHAR;
}
LeaveCriticalSection(&pComm->EventsLock);
goto return_true;
}
WINPR_ASSERT(FALSE);
*lpNumberOfBytesRead = 0;
return_false:
LeaveCriticalSection(&pComm->ReadLock);
return FALSE;
return_true:
LeaveCriticalSection(&pComm->ReadLock);
return TRUE;
}
/**
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_NOT_SUPPORTED
* ERROR_INVALID_PARAMETER
* ERROR_BAD_DEVICE
*/
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
struct timeval tmaxTimeout;
struct timeval* pTmaxTimeout = nullptr;
EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */
if (!CommIsHandled(hDevice))
goto return_false;
if (lpOverlapped != nullptr)
{
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
if (lpNumberOfBytesWritten == nullptr)
{
SetLastError(
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
goto return_false;
}
*lpNumberOfBytesWritten = 0; /* will be adjusted if required ... */
if (nNumberOfBytesToWrite <= 0)
{
goto return_true; /* FIXME: or FALSE? */
}
/* FIXME: had expected eventfd_write() to return EAGAIN when
* there is no eventfd_read() but this not the case. */
/* discard a possible and no more relevant event */
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
{
eventfd_t val = 0;
(void)eventfd_read(pComm->fd_write_event, &val);
}
#endif
{
/* ms */
const LONGLONG Tmax =
1ll * nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier +
1ll * pComm->timeouts.WriteTotalTimeoutConstant;
/* NB: select() may update the timeout argument to indicate
* how much time was left. Keep the timeout variable out of
* the while() */
pTmaxTimeout = &tmaxTimeout;
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
if (Tmax > 0)
{
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
}
else if ((pComm->timeouts.WriteTotalTimeoutMultiplier == 0) &&
(pComm->timeouts.WriteTotalTimeoutConstant == 0))
{
pTmaxTimeout = nullptr;
}
}
/* else return immdiately */
while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite)
{
int biggestFd = -1;
fd_set event_set;
fd_set write_set;
int nbFds = 0;
biggestFd = pComm->fd_write;
if (pComm->fd_write_event > biggestFd)
biggestFd = pComm->fd_write_event;
FD_ZERO(&event_set);
FD_ZERO(&write_set);
WINPR_ASSERT(pComm->fd_write_event < FD_SETSIZE);
WINPR_ASSERT(pComm->fd_write < FD_SETSIZE);
FD_SET(pComm->fd_write_event, &event_set);
FD_SET(pComm->fd_write, &write_set);
nbFds = select(biggestFd + 1, &event_set, &write_set, nullptr, pTmaxTimeout);
if (nbFds < 0)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (nbFds == 0)
{
/* timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
/* event_set */
if (FD_ISSET(pComm->fd_write_event, &event_set))
{
#if defined(WINPR_HAVE_SYS_EVENTFD_H)
eventfd_t event = 0;
if (eventfd_read(pComm->fd_write_event, &event) < 0)
{
if (errno == EAGAIN)
{
WINPR_ASSERT(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN,
"unexpected error on reading fd_write_event, errno=[%d] %s\n",
errno, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
/* FIXME: goto return_false ? */
}
WINPR_ASSERT(errno == EAGAIN);
}
if (event == WINPR_PURGE_TXABORT)
{
SetLastError(ERROR_CANCELLED);
goto return_false;
}
WINPR_ASSERT(event == WINPR_PURGE_TXABORT); /* no other expected event so far */
#endif
}
/* write_set */
if (FD_ISSET(pComm->fd_write, &write_set))
{
ssize_t nbWritten = 0;
const BYTE* ptr = lpBuffer;
nbWritten = write(pComm->fd_write, &ptr[*lpNumberOfBytesWritten],
nNumberOfBytesToWrite - (*lpNumberOfBytesWritten));
if (nbWritten < 0)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN,
"CommWriteFile failed after %" PRIu32
" bytes written, errno=[%d] %s\n",
*lpNumberOfBytesWritten, errno,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
if (errno == EAGAIN)
{
/* keep on */
continue;
}
else if (errno == EBADF)
{
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
goto return_false;
}
else
{
WINPR_ASSERT(FALSE);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
*lpNumberOfBytesWritten += nbWritten;
}
} /* while */
/* FIXME: this call to tcdrain() doesn't look correct and
* might hide a bug but was required while testing a serial
* printer. Its driver was expecting the modem line status
* SERIAL_MSR_DSR true after the sending which was never
* happening otherwise. A purge was also done before each
* Write operation. The serial port was opened with:
* DesiredAccess=0x0012019F. The printer worked fine with
* mstsc. */
tcdrain(pComm->fd_write);
return_true:
LeaveCriticalSection(&pComm->WriteLock);
return TRUE;
return_false:
LeaveCriticalSection(&pComm->WriteLock);
return FALSE;
}

View File

@@ -0,0 +1,759 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <winpr/wlog.h>
#include "comm.h"
#include "comm_ioctl.h"
#include "comm_serial_sys.h"
#include "comm_sercx_sys.h"
#include "comm_sercx2_sys.h"
static const char* comm_ioctl_modem_status_string(ULONG status, char* buffer, size_t size);
/* NB: MS-RDPESP's recommendation:
*
* <2> Section 3.2.5.1.6: Windows Implementations use IOCTL constants
* for IoControlCode values. The content and values of the IOCTLs are
* opaque to the protocol. On the server side, the data contained in
* an IOCTL is simply packaged and sent to the client side. For
* maximum compatibility between the different versions of the Windows
* operating system, the client implementation only singles out
* critical IOCTLs and invokes the applicable Win32 port API. The
* other IOCTLS are passed directly to the client-side driver, and the
* processing of this value depends on the drivers installed on the
* client side. The values and parameters for these IOCTLS can be
* found in [MSFT-W2KDDK] Volume 2, Part 2—Serial and Parallel
* Drivers, and in [MSDN-PORTS].
*/
static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
char buffer[128] = WINPR_C_ARRAY_INIT;
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
const SERIAL_DRIVER* pServerSerialDriver = nullptr;
if (!CommIsHandleValid(hDevice))
return FALSE;
if (lpOverlapped)
{
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
if (lpBytesReturned == nullptr)
{
SetLastError(
ERROR_INVALID_PARAMETER); /* since we doesn't support lpOverlapped != nullptr */
return FALSE;
}
/* clear any previous last error */
SetLastError(ERROR_SUCCESS);
*lpBytesReturned = 0; /* will be adjusted if required ... */
CommLog_Print(WLOG_DEBUG, "CommDeviceIoControl: IoControlCode: %s [0x%08" PRIx32 "]",
_comm_serial_ioctl_name(dwIoControlCode), dwIoControlCode);
/* remoteSerialDriver to be use ...
*
* FIXME: might prefer to use an automatic rather than static structure
*/
switch (pComm->serverSerialDriverId)
{
case SerialDriverSerialSys:
pServerSerialDriver = SerialSys_s();
break;
case SerialDriverSerCxSys:
pServerSerialDriver = SerCxSys_s();
break;
case SerialDriverSerCx2Sys:
pServerSerialDriver = SerCx2Sys_s();
break;
case SerialDriverUnknown:
default:
CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%u), using SerCx2.sys",
pComm->serverSerialDriverId);
pServerSerialDriver = SerCx2Sys_s();
break;
}
WINPR_ASSERT(pServerSerialDriver != nullptr);
switch (dwIoControlCode)
{
case IOCTL_USBPRINT_GET_1284_ID:
{
/* FIXME:
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */
*lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
case IOCTL_SERIAL_SET_BAUD_RATE:
{
if (pServerSerialDriver->set_baud_rate)
{
SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
}
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE:
{
if (pServerSerialDriver->get_baud_rate)
{
SERIAL_BAUD_RATE* pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
return TRUE;
}
break;
}
case IOCTL_SERIAL_GET_PROPERTIES:
{
if (pServerSerialDriver->get_properties)
{
COMMPROP* pProperties = (COMMPROP*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(COMMPROP));
if (nOutBufferSize < sizeof(COMMPROP))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_properties(pComm, pProperties))
return FALSE;
*lpBytesReturned = sizeof(COMMPROP);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_CHARS:
{
if (pServerSerialDriver->set_serial_chars)
{
SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_CHARS));
if (nInBufferSize < sizeof(SERIAL_CHARS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
}
break;
}
case IOCTL_SERIAL_GET_CHARS:
{
if (pServerSerialDriver->get_serial_chars)
{
SERIAL_CHARS* pSerialChars = (SERIAL_CHARS*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_CHARS));
if (nOutBufferSize < sizeof(SERIAL_CHARS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_CHARS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_LINE_CONTROL:
{
if (pServerSerialDriver->set_line_control)
{
SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL));
if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_line_control(pComm, pLineControl);
}
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL:
{
if (pServerSerialDriver->get_line_control)
{
SERIAL_LINE_CONTROL* pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL));
if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_LINE_CONTROL);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_HANDFLOW:
{
if (pServerSerialDriver->set_handflow)
{
SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nInBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_handflow(pComm, pHandflow);
}
break;
}
case IOCTL_SERIAL_GET_HANDFLOW:
{
if (pServerSerialDriver->get_handflow)
{
SERIAL_HANDFLOW* pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nOutBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_HANDFLOW);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_TIMEOUTS:
{
if (pServerSerialDriver->set_timeouts)
{
SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_TIMEOUTS));
if (nInBufferSize < sizeof(SERIAL_TIMEOUTS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_timeouts(pComm, pHandflow);
}
break;
}
case IOCTL_SERIAL_GET_TIMEOUTS:
{
if (pServerSerialDriver->get_timeouts)
{
SERIAL_TIMEOUTS* pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS));
if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_TIMEOUTS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_DTR:
{
if (pServerSerialDriver->set_dtr)
{
return pServerSerialDriver->set_dtr(pComm);
}
break;
}
case IOCTL_SERIAL_CLR_DTR:
{
if (pServerSerialDriver->clear_dtr)
{
return pServerSerialDriver->clear_dtr(pComm);
}
break;
}
case IOCTL_SERIAL_SET_RTS:
{
if (pServerSerialDriver->set_rts)
{
return pServerSerialDriver->set_rts(pComm);
}
break;
}
case IOCTL_SERIAL_CLR_RTS:
{
if (pServerSerialDriver->clear_rts)
{
return pServerSerialDriver->clear_rts(pComm);
}
break;
}
case IOCTL_SERIAL_GET_MODEMSTATUS:
{
if (pServerSerialDriver->get_modemstatus)
{
ULONG* pRegister = (ULONG*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
return FALSE;
CommLog_Print(WLOG_DEBUG, "modem status %s" PRIx32,
comm_ioctl_modem_status_string(*pRegister, buffer, sizeof(buffer)));
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_WAIT_MASK:
{
if (pServerSerialDriver->set_wait_mask)
{
ULONG* pWaitMask = (ULONG*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
if (nInBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
const BOOL rc = pServerSerialDriver->set_wait_mask(pComm, pWaitMask);
CommLog_Print(WLOG_DEBUG, "set_wait_mask %s -> %d",
CommSerialEvString(*pWaitMask, buffer, sizeof(buffer)), rc);
return rc;
}
break;
}
case IOCTL_SERIAL_GET_WAIT_MASK:
{
if (pServerSerialDriver->get_wait_mask)
{
ULONG* pWaitMask = (ULONG*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
return FALSE;
CommLog_Print(WLOG_DEBUG, "get_wait_mask %s",
CommSerialEvString(*pWaitMask, buffer, sizeof(buffer)));
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_WAIT_ON_MASK:
{
if (pServerSerialDriver->wait_on_mask)
{
ULONG* pOutputMask = (ULONG*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
const BOOL rc = pServerSerialDriver->wait_on_mask(pComm, pOutputMask);
*lpBytesReturned = sizeof(ULONG);
CommLog_Print(WLOG_DEBUG, "wait_on_mask %s -> %d",
CommSerialEvString(*pOutputMask, buffer, sizeof(buffer)), rc);
return rc;
}
break;
}
case IOCTL_SERIAL_SET_QUEUE_SIZE:
{
if (pServerSerialDriver->set_queue_size)
{
SERIAL_QUEUE_SIZE* pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE));
if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
}
break;
}
case IOCTL_SERIAL_PURGE:
{
if (pServerSerialDriver->purge)
{
ULONG* pPurgeMask = (ULONG*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(ULONG));
if (nInBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->purge(pComm, pPurgeMask);
}
break;
}
case IOCTL_SERIAL_GET_COMMSTATUS:
{
if (pServerSerialDriver->get_commstatus)
{
SERIAL_STATUS* pCommstatus = (SERIAL_STATUS*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(SERIAL_STATUS));
if (nOutBufferSize < sizeof(SERIAL_STATUS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_STATUS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_BREAK_ON:
{
if (pServerSerialDriver->set_break_on)
{
return pServerSerialDriver->set_break_on(pComm);
}
break;
}
case IOCTL_SERIAL_SET_BREAK_OFF:
{
if (pServerSerialDriver->set_break_off)
{
return pServerSerialDriver->set_break_off(pComm);
}
break;
}
case IOCTL_SERIAL_SET_XOFF:
{
if (pServerSerialDriver->set_xoff)
{
return pServerSerialDriver->set_xoff(pComm);
}
break;
}
case IOCTL_SERIAL_SET_XON:
{
if (pServerSerialDriver->set_xon)
{
return pServerSerialDriver->set_xon(pComm);
}
break;
}
case IOCTL_SERIAL_GET_DTRRTS:
{
if (pServerSerialDriver->get_dtrrts)
{
ULONG* pMask = (ULONG*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_CONFIG_SIZE:
{
if (pServerSerialDriver->config_size)
{
ULONG* pSize = (ULONG*)lpOutBuffer;
WINPR_ASSERT(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->config_size(pComm, pSize))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_IMMEDIATE_CHAR:
{
if (pServerSerialDriver->immediate_char)
{
UCHAR* pChar = (UCHAR*)lpInBuffer;
WINPR_ASSERT(nInBufferSize >= sizeof(UCHAR));
if (nInBufferSize < sizeof(UCHAR))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->immediate_char(pComm, pChar);
}
break;
}
case IOCTL_SERIAL_RESET_DEVICE:
{
if (pServerSerialDriver->reset_device)
{
return pServerSerialDriver->reset_device(pComm);
}
break;
}
default:
break;
}
CommLog_Print(
WLOG_WARN, _T("unsupported IoControlCode=[0x%08" PRIX32 "] %s (remote serial driver: %s)"),
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */
return FALSE;
}
/**
* FIXME: to be used through winpr-io's DeviceIoControl
*
* Any previous error as returned by GetLastError is cleared.
*
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_INVALID_PARAMETER
* ERROR_NOT_SUPPORTED lpOverlapped is not supported
* ERROR_INSUFFICIENT_BUFFER
* ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl
*/
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
BOOL result = 0;
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!CommIsHandled(hDevice))
return FALSE;
if (!pComm->fd)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
result = s_CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped);
if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
{
/* This might be a hint for a bug, especially when result==TRUE */
CommLog_Print(WLOG_WARN,
"IoControlCode=[0x%08" PRIX32 "] %s: lpBytesReturned=%" PRIu32
" and nOutBufferSize=%" PRIu32 " are different!",
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), *lpBytesReturned,
nOutBufferSize);
}
if (pComm->permissive)
{
if (!result)
{
CommLog_Print(WLOG_WARN,
"[permissive]: IoControlCode=[0x%08" PRIX32 "] %s failed, ignoring",
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode));
}
return TRUE; /* always! */
}
return result;
}
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
{
struct termios currentState = WINPR_C_ARRAY_INIT;
size_t count = 0;
do
{
const int src = tcsetattr(fd, optional_actions, termios_p);
if (src < 0)
{
char buffer[64] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN, "[%" PRIuz "] tcsetattr failure, errno: %s [%d]", count,
winpr_strerror(errno, buffer, sizeof(buffer)), errno);
return src;
}
/* NB: tcsetattr() can succeed even if not all changes have been applied. */
const int rrc = tcgetattr(fd, &currentState);
if (rrc < 0)
{
char buffer[64] = WINPR_C_ARRAY_INIT;
CommLog_Print(WLOG_WARN, "[%" PRIuz "] tcgetattr failure, errno: %s [%d]", count,
winpr_strerror(errno, buffer, sizeof(buffer)), errno);
return rrc;
}
// NOLINTNEXTLINE(bugprone-suspicious-memory-comparison,cert-exp42-c,cert-flp37-c)
} while ((memcmp(&currentState, termios_p, sizeof(struct termios)) != 0) && (count++ < 2));
return 0;
}
static const char* comm_ioctl_modem_flag_str(ULONG flag)
{
switch (flag)
{
case SERIAL_MSR_DCTS:
return "SERIAL_MSR_DCTS";
case SERIAL_MSR_DDSR:
return "SERIAL_MSR_DDSR";
case SERIAL_MSR_TERI:
return "SERIAL_MSR_TERI";
case SERIAL_MSR_DDCD:
return "SERIAL_MSR_DDCD";
case SERIAL_MSR_CTS:
return "SERIAL_MSR_CTS";
case SERIAL_MSR_DSR:
return "SERIAL_MSR_DSR";
case SERIAL_MSR_RI:
return "SERIAL_MSR_RI";
case SERIAL_MSR_DCD:
return "SERIAL_MSR_DCD";
default:
return "SERIAL_MSR_UNKNOWN";
}
}
const char* comm_ioctl_modem_status_string(ULONG status, char* buffer, size_t size)
{
const ULONG flags[] = { SERIAL_MSR_DCTS, SERIAL_MSR_DDSR, SERIAL_MSR_TERI, SERIAL_MSR_DDCD,
SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI, SERIAL_MSR_DCD
};
winpr_str_append("{", buffer, size, "");
const char* sep = "";
for (size_t x = 0; x < ARRAYSIZE(flags); x++)
{
const ULONG flag = flags[x];
if (status & flag)
{
winpr_str_append(comm_ioctl_modem_flag_str(flag), buffer, size, sep);
sep = "|";
}
}
char number[32] = WINPR_C_ARRAY_INIT;
(void)_snprintf(number, sizeof(number), "}[0x%08" PRIx32 "]", status);
winpr_str_append(number, buffer, size, "");
return buffer;
}

View File

@@ -0,0 +1,232 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_COMM_IOCTL_H_
#define WINPR_COMM_IOCTL_H_
#include <termios.h>
#include <winpr/io.h>
#include <winpr/tchar.h>
#include <winpr/wtypes.h>
#include "comm.h"
/* Serial I/O Request Interface: http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
* Ntddser.h http://msdn.microsoft.com/en-us/cc308432.aspx
* Ntddpar.h http://msdn.microsoft.com/en-us/cc308431.aspx
*/
#ifdef __cplusplus
extern "C"
{
#endif
/* TODO: defines and types below are very similar to those in comm.h, keep only
* those that differ more than the names */
#define STOP_BIT_1 0
#define STOP_BITS_1_5 1
#define STOP_BITS_2 2
#define NO_PARITY 0
#define ODD_PARITY 1
#define EVEN_PARITY 2
#define MARK_PARITY 3
#define SPACE_PARITY 4
typedef struct
{
ULONG BaudRate;
} SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE;
typedef struct
{
UCHAR EofChar;
UCHAR ErrorChar;
UCHAR BreakChar;
UCHAR EventChar;
UCHAR XonChar;
UCHAR XoffChar;
} SERIAL_CHARS, *PSERIAL_CHARS;
typedef struct
{
UCHAR StopBits;
UCHAR Parity;
UCHAR WordLength;
} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL;
typedef struct
{
ULONG ControlHandShake;
ULONG FlowReplace;
ULONG XonLimit;
ULONG XoffLimit;
} SERIAL_HANDFLOW, *PSERIAL_HANDFLOW;
#define SERIAL_DTR_MASK ((ULONG)0x03)
#define SERIAL_DTR_CONTROL ((ULONG)0x01)
#define SERIAL_DTR_HANDSHAKE ((ULONG)0x02)
#define SERIAL_CTS_HANDSHAKE ((ULONG)0x08)
#define SERIAL_DSR_HANDSHAKE ((ULONG)0x10)
#define SERIAL_DCD_HANDSHAKE ((ULONG)0x20)
#define SERIAL_OUT_HANDSHAKEMASK ((ULONG)0x38)
#define SERIAL_DSR_SENSITIVITY ((ULONG)0x40)
#define SERIAL_ERROR_ABORT ((ULONG)0x80000000)
#define SERIAL_CONTROL_INVALID ((ULONG)0x7fffff84)
#define SERIAL_AUTO_TRANSMIT ((ULONG)0x01)
#define SERIAL_AUTO_RECEIVE ((ULONG)0x02)
#define SERIAL_ERROR_CHAR ((ULONG)0x04)
#define SERIAL_NULL_STRIPPING ((ULONG)0x08)
#define SERIAL_BREAK_CHAR ((ULONG)0x10)
#define SERIAL_RTS_MASK ((ULONG)0xc0)
#define SERIAL_RTS_CONTROL ((ULONG)0x40)
#define SERIAL_RTS_HANDSHAKE ((ULONG)0x80)
#define SERIAL_TRANSMIT_TOGGLE ((ULONG)0xc0)
#define SERIAL_XOFF_CONTINUE ((ULONG)0x80000000)
#define SERIAL_FLOW_INVALID ((ULONG)0x7fffff20)
#define SERIAL_SP_SERIALCOMM ((ULONG)0x00000001)
#define SERIAL_SP_UNSPECIFIED ((ULONG)0x00000000)
#define SERIAL_SP_RS232 ((ULONG)0x00000001)
#define SERIAL_SP_PARALLEL ((ULONG)0x00000002)
#define SERIAL_SP_RS422 ((ULONG)0x00000003)
#define SERIAL_SP_RS423 ((ULONG)0x00000004)
#define SERIAL_SP_RS449 ((ULONG)0x00000005)
#define SERIAL_SP_MODEM ((ULONG)0x00000006)
#define SERIAL_SP_FAX ((ULONG)0x00000021)
#define SERIAL_SP_SCANNER ((ULONG)0x00000022)
#define SERIAL_SP_BRIDGE ((ULONG)0x00000100)
#define SERIAL_SP_LAT ((ULONG)0x00000101)
#define SERIAL_SP_TELNET ((ULONG)0x00000102)
#define SERIAL_SP_X25 ((ULONG)0x00000103)
typedef struct
{
ULONG ReadIntervalTimeout;
ULONG ReadTotalTimeoutMultiplier;
ULONG ReadTotalTimeoutConstant;
ULONG WriteTotalTimeoutMultiplier;
ULONG WriteTotalTimeoutConstant;
} SERIAL_TIMEOUTS, *PSERIAL_TIMEOUTS;
#define SERIAL_MSR_DCTS 0x01
#define SERIAL_MSR_DDSR 0x02
#define SERIAL_MSR_TERI 0x04
#define SERIAL_MSR_DDCD 0x08
#define SERIAL_MSR_CTS 0x10
#define SERIAL_MSR_DSR 0x20
#define SERIAL_MSR_RI 0x40
#define SERIAL_MSR_DCD 0x80
typedef struct
{
ULONG InSize;
ULONG OutSize;
} SERIAL_QUEUE_SIZE, *PSERIAL_QUEUE_SIZE;
#define SERIAL_PURGE_TXABORT 0x00000001
#define SERIAL_PURGE_RXABORT 0x00000002
#define SERIAL_PURGE_TXCLEAR 0x00000004
#define SERIAL_PURGE_RXCLEAR 0x00000008
typedef struct
{
ULONG Errors;
ULONG HoldReasons;
ULONG AmountInInQueue;
ULONG AmountInOutQueue;
BOOLEAN EofReceived;
BOOLEAN WaitForImmediate;
} SERIAL_STATUS, *PSERIAL_STATUS;
#define SERIAL_TX_WAITING_FOR_CTS ((ULONG)0x00000001)
#define SERIAL_TX_WAITING_FOR_DSR ((ULONG)0x00000002)
#define SERIAL_TX_WAITING_FOR_DCD ((ULONG)0x00000004)
#define SERIAL_TX_WAITING_FOR_XON ((ULONG)0x00000008)
#define SERIAL_TX_WAITING_XOFF_SENT ((ULONG)0x00000010)
#define SERIAL_TX_WAITING_ON_BREAK ((ULONG)0x00000020)
#define SERIAL_RX_WAITING_FOR_DSR ((ULONG)0x00000040)
#define SERIAL_ERROR_BREAK ((ULONG)0x00000001)
#define SERIAL_ERROR_FRAMING ((ULONG)0x00000002)
#define SERIAL_ERROR_OVERRUN ((ULONG)0x00000004)
#define SERIAL_ERROR_QUEUEOVERRUN ((ULONG)0x00000008)
#define SERIAL_ERROR_PARITY ((ULONG)0x00000010)
#define SERIAL_DTR_STATE ((ULONG)0x00000001)
#define SERIAL_RTS_STATE ((ULONG)0x00000002)
#define SERIAL_CTS_STATE ((ULONG)0x00000010)
#define SERIAL_DSR_STATE ((ULONG)0x00000020)
#define SERIAL_RI_STATE ((ULONG)0x00000040)
#define SERIAL_DCD_STATE ((ULONG)0x00000080)
/**
* A function might be nullptr if not supported by the underlying driver.
*
* FIXME: better have to use input and output buffers for all functions?
*/
typedef struct
{
SERIAL_DRIVER_ID id;
TCHAR* name;
BOOL (*set_baud_rate)(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate);
BOOL (*get_baud_rate)(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate);
BOOL (*get_properties)(WINPR_COMM* pComm, COMMPROP* pProperties);
BOOL (*set_serial_chars)(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars);
BOOL (*get_serial_chars)(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars);
BOOL (*set_line_control)(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLineControl);
BOOL (*get_line_control)(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineControl);
BOOL (*set_handflow)(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow);
BOOL (*get_handflow)(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow);
BOOL (*set_timeouts)(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts);
BOOL (*get_timeouts)(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts);
BOOL (*set_dtr)(WINPR_COMM* pComm);
BOOL (*clear_dtr)(WINPR_COMM* pComm);
BOOL (*set_rts)(WINPR_COMM* pComm);
BOOL (*clear_rts)(WINPR_COMM* pComm);
BOOL (*get_modemstatus)(WINPR_COMM* pComm, ULONG* pRegister);
BOOL (*set_wait_mask)(WINPR_COMM* pComm, const ULONG* pWaitMask);
BOOL (*get_wait_mask)(WINPR_COMM* pComm, ULONG* pWaitMask);
BOOL (*wait_on_mask)(WINPR_COMM* pComm, ULONG* pOutputMask);
BOOL (*set_queue_size)(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSize);
BOOL (*purge)(WINPR_COMM* pComm, const ULONG* pPurgeMask);
BOOL (*get_commstatus)(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus);
BOOL (*set_break_on)(WINPR_COMM* pComm);
BOOL (*set_break_off)(WINPR_COMM* pComm);
BOOL (*set_xoff)(WINPR_COMM* pComm);
BOOL (*set_xon)(WINPR_COMM* pComm);
BOOL (*get_dtrrts)(WINPR_COMM* pComm, ULONG* pMask);
BOOL (*config_size)(WINPR_COMM* pComm, ULONG* pSize);
BOOL (*immediate_char)(WINPR_COMM* pComm, const UCHAR* pChar);
BOOL (*reset_device)(WINPR_COMM* pComm);
} SERIAL_DRIVER;
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p);
#ifdef __cplusplus
}
#endif
#endif /* WINPR_COMM_IOCTL_H_ */

View File

@@ -0,0 +1,87 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API - Dummy implementation
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* Copyright 2024 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/comm.h>
#include "comm_ioctl.h"
#include <../log.h>
#define TAG WINPR_TAG("comm")
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
WINPR_UNUSED(hDevice);
WINPR_UNUSED(dwIoControlCode);
WINPR_UNUSED(lpInBuffer);
WINPR_UNUSED(nInBufferSize);
WINPR_UNUSED(lpOutBuffer);
WINPR_UNUSED(nOutBufferSize);
WINPR_UNUSED(lpBytesReturned);
WINPR_UNUSED(lpOverlapped);
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
return FALSE;
}
int comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
{
WINPR_UNUSED(fd);
WINPR_UNUSED(optional_actions);
WINPR_UNUSED(termios_p);
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
return -1;
}
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
{
WINPR_UNUSED(hDevice);
WINPR_UNUSED(permissive);
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
return FALSE;
}
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
WINPR_UNUSED(hDevice);
WINPR_UNUSED(lpBuffer);
WINPR_UNUSED(nNumberOfBytesToRead);
WINPR_UNUSED(lpNumberOfBytesRead);
WINPR_UNUSED(lpOverlapped);
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
return FALSE;
}
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
WINPR_UNUSED(hDevice);
WINPR_UNUSED(lpBuffer);
WINPR_UNUSED(nNumberOfBytesToWrite);
WINPR_UNUSED(lpNumberOfBytesWritten);
WINPR_UNUSED(lpOverlapped);
WLog_ERR(TAG, "TODO: Function not implemented for this platform");
return FALSE;
}

View File

@@ -0,0 +1,210 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/wlog.h>
#include "comm_serial_sys.h"
#include "comm_sercx_sys.h"
#include "comm_sercx2_sys.h"
/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
*
* SerCx2 does not support special characters. SerCx2 always completes
* an IOCTL_SERIAL_SET_CHARS request with a STATUS_SUCCESS status
* code, but does not set any special characters or perform any other
* operation in response to this request. For an
* IOCTL_SERIAL_GET_CHARS request, SerCx2 sets all the character
* values in the SERIAL_CHARS structure to null, and completes the
* request with a STATUS_SUCCESS status code.
*/
static BOOL set_serial_chars(WINPR_ATTR_UNUSED WINPR_COMM* pComm,
WINPR_ATTR_UNUSED const SERIAL_CHARS* pSerialChars)
{
WINPR_ASSERT(pComm);
WINPR_ASSERT(pSerialChars);
return TRUE;
}
static BOOL get_serial_chars(WINPR_ATTR_UNUSED WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
{
WINPR_ASSERT(pComm);
WINPR_ASSERT(pSerialChars);
ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
return TRUE;
}
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
/* FIXME: only using the Serial.sys' events, complete the support of the remaining events */
static const ULONG SERCX2_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING |
/* SERIAL_EV_PERR | */
SERIAL_EV_RX80FULL /*|
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/
;
/* use Serial.sys for basis (not SerCx.sys) */
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
{
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
WINPR_ASSERT(pComm);
WINPR_ASSERT(pWaitMask);
WINPR_ASSERT(pSerialSys);
const ULONG possibleMask = *pWaitMask & SERCX2_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
CommLog_Print(WLOG_WARN,
"Not all wait events supported (SerCx2.sys), requested events= 0x%08" PRIX32
", possible events= 0x%08" PRIX32 "",
*pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->WaitEventMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
static BOOL purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
{
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
WINPR_ASSERT(pComm);
WINPR_ASSERT(pPurgeMask);
WINPR_ASSERT(pSerialSys);
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */
if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT))
{
CommLog_Print(WLOG_WARN,
"Expecting SERIAL_PURGE_RXABORT since SERIAL_PURGE_RXCLEAR is set");
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
return FALSE;
}
if ((*pPurgeMask & SERIAL_PURGE_TXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_TXABORT))
{
CommLog_Print(WLOG_WARN,
"Expecting SERIAL_PURGE_TXABORT since SERIAL_PURGE_TXCLEAR is set");
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
return FALSE;
}
return pSerialSys->purge(pComm, pPurgeMask);
}
/* specific functions only */
static SERIAL_DRIVER SerCx2Sys = {
.id = SerialDriverSerCx2Sys,
.name = _T("SerCx2.sys"),
.set_baud_rate = nullptr,
.get_baud_rate = nullptr,
.get_properties = nullptr,
.set_serial_chars = set_serial_chars,
.get_serial_chars = get_serial_chars,
.set_line_control = nullptr,
.get_line_control = nullptr,
.set_handflow = nullptr,
.get_handflow = nullptr,
.set_timeouts = nullptr,
.get_timeouts = nullptr,
.set_dtr = nullptr,
.clear_dtr = nullptr,
.set_rts = nullptr,
.clear_rts = nullptr,
.get_modemstatus = nullptr,
.set_wait_mask = set_wait_mask,
.get_wait_mask = nullptr,
.wait_on_mask = nullptr,
.set_queue_size = nullptr,
.purge = purge,
.get_commstatus = nullptr,
.set_break_on = nullptr,
.set_break_off = nullptr,
.set_xoff = nullptr, /* not supported by SerCx2.sys */
.set_xon = nullptr, /* not supported by SerCx2.sys */
.get_dtrrts = nullptr,
.config_size = nullptr, /* not supported by SerCx2.sys */
.immediate_char = nullptr, /* not supported by SerCx2.sys */
.reset_device = nullptr, /* not supported by SerCx2.sys */
};
const SERIAL_DRIVER* SerCx2Sys_s(void)
{
/* SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
const SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
if (!pSerialSys || !pSerCxSys)
return nullptr;
SerCx2Sys.set_baud_rate = pSerialSys->set_baud_rate;
SerCx2Sys.get_baud_rate = pSerialSys->get_baud_rate;
SerCx2Sys.get_properties = pSerialSys->get_properties;
SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
/* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really
* required by SerCx2.sys http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx
*/
SerCx2Sys.set_handflow = pSerialSys->set_handflow;
SerCx2Sys.get_handflow = pSerialSys->get_handflow;
SerCx2Sys.set_timeouts = pSerialSys->set_timeouts;
SerCx2Sys.get_timeouts = pSerialSys->get_timeouts;
SerCx2Sys.set_dtr = pSerialSys->set_dtr;
SerCx2Sys.clear_dtr = pSerialSys->clear_dtr;
SerCx2Sys.set_rts = pSerialSys->set_rts;
SerCx2Sys.clear_rts = pSerialSys->clear_rts;
SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
SerCx2Sys.set_queue_size = pSerialSys->set_queue_size;
SerCx2Sys.get_commstatus = pSerialSys->get_commstatus;
SerCx2Sys.set_break_on = pSerialSys->set_break_on;
SerCx2Sys.set_break_off = pSerialSys->set_break_off;
SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts;
return &SerCx2Sys;
}

View File

@@ -0,0 +1,36 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERCX2_SYS_H
#define COMM_SERCX2_SYS_H
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C"
{
#endif
const SERIAL_DRIVER* SerCx2Sys_s(void);
#ifdef __cplusplus
}
#endif
#endif /* COMM_SERCX2_SYS_H */

View File

@@ -0,0 +1,261 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <termios.h>
#include <winpr/wlog.h>
#include "comm_serial_sys.h"
#include "comm_sercx_sys.h"
static BOOL set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
{
SERIAL_HANDFLOW SerCxHandflow;
BOOL result = TRUE;
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW));
/* filter out unsupported bits by SerCx.sys
*
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
*/
SerCxHandflow.ControlHandShake =
pHandflow->ControlHandShake &
(SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
SerCxHandflow.FlowReplace =
pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake)
{
if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
{
CommLog_Print(WLOG_WARN,
"SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
{
CommLog_Print(WLOG_WARN,
"SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
{
CommLog_Print(WLOG_WARN,
"SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys");
}
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE;
}
if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace)
{
if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT)
{
CommLog_Print(WLOG_WARN,
"SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE)
{
CommLog_Print(WLOG_WARN,
"SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR)
{
CommLog_Print(WLOG_WARN,
"SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING)
{
CommLog_Print(WLOG_WARN,
"SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR)
{
CommLog_Print(WLOG_WARN,
"SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE)
{
CommLog_Print(WLOG_WARN,
"SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys");
}
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE;
}
if (!pSerialSys->set_handflow(pComm, &SerCxHandflow))
return FALSE;
return result;
}
static BOOL get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
{
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
BOOL result = pSerialSys->get_handflow(pComm, pHandflow);
/* filter out unsupported bits by SerCx.sys
*
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
*/
pHandflow->ControlHandShake =
pHandflow->ControlHandShake &
(SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
return result;
}
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
static const ULONG SERCX_SYS_SUPPORTED_EV_MASK = SERIAL_EV_RXCHAR |
/* SERIAL_EV_RXFLAG | */
SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR |
SERIAL_EV_RING /* |
SERIAL_EV_PERR |
SERIAL_EV_RX80FULL |
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/
;
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
{
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
WINPR_ASSERT(pWaitMask);
const ULONG possibleMask = *pWaitMask & SERCX_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
CommLog_Print(WLOG_WARN,
"Not all wait events supported (SerCx.sys), requested events= 0x%08" PRIX32
", possible events= 0x%08" PRIX32 "",
*pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->WaitEventMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
/* specific functions only */
static SERIAL_DRIVER SerCxSys = {
.id = SerialDriverSerCxSys,
.name = _T("SerCx.sys"),
.set_baud_rate = nullptr,
.get_baud_rate = nullptr,
.get_properties = nullptr,
.set_serial_chars = nullptr,
.get_serial_chars = nullptr,
.set_line_control = nullptr,
.get_line_control = nullptr,
.set_handflow = set_handflow,
.get_handflow = get_handflow,
.set_timeouts = nullptr,
.get_timeouts = nullptr,
.set_dtr = nullptr,
.clear_dtr = nullptr,
.set_rts = nullptr,
.clear_rts = nullptr,
.get_modemstatus = nullptr,
.set_wait_mask = set_wait_mask,
.get_wait_mask = nullptr,
.wait_on_mask = nullptr,
.set_queue_size = nullptr,
.purge = nullptr,
.get_commstatus = nullptr,
.set_break_on = nullptr,
.set_break_off = nullptr,
.set_xoff = nullptr,
.set_xon = nullptr,
.get_dtrrts = nullptr,
.config_size = nullptr, /* not supported by SerCx.sys */
.immediate_char = nullptr,
.reset_device = nullptr, /* not supported by SerCx.sys */
};
const SERIAL_DRIVER* SerCxSys_s(void)
{
/* _SerCxSys completed with inherited functions from SerialSys */
const SERIAL_DRIVER* pSerialSys = SerialSys_s();
if (!pSerialSys)
return nullptr;
SerCxSys.set_baud_rate = pSerialSys->set_baud_rate;
SerCxSys.get_baud_rate = pSerialSys->get_baud_rate;
SerCxSys.get_properties = pSerialSys->get_properties;
SerCxSys.set_serial_chars = pSerialSys->set_serial_chars;
SerCxSys.get_serial_chars = pSerialSys->get_serial_chars;
SerCxSys.set_line_control = pSerialSys->set_line_control;
SerCxSys.get_line_control = pSerialSys->get_line_control;
SerCxSys.set_timeouts = pSerialSys->set_timeouts;
SerCxSys.get_timeouts = pSerialSys->get_timeouts;
SerCxSys.set_dtr = pSerialSys->set_dtr;
SerCxSys.clear_dtr = pSerialSys->clear_dtr;
SerCxSys.set_rts = pSerialSys->set_rts;
SerCxSys.clear_rts = pSerialSys->clear_rts;
SerCxSys.get_modemstatus = pSerialSys->get_modemstatus;
SerCxSys.set_wait_mask = pSerialSys->set_wait_mask;
SerCxSys.get_wait_mask = pSerialSys->get_wait_mask;
SerCxSys.wait_on_mask = pSerialSys->wait_on_mask;
SerCxSys.set_queue_size = pSerialSys->set_queue_size;
SerCxSys.purge = pSerialSys->purge;
SerCxSys.get_commstatus = pSerialSys->get_commstatus;
SerCxSys.set_break_on = pSerialSys->set_break_on;
SerCxSys.set_break_off = pSerialSys->set_break_off;
SerCxSys.set_xoff = pSerialSys->set_xoff;
SerCxSys.set_xon = pSerialSys->set_xon;
SerCxSys.get_dtrrts = pSerialSys->get_dtrrts;
SerCxSys.immediate_char = pSerialSys->immediate_char;
return &SerCxSys;
}

View File

@@ -0,0 +1,36 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERCX_SYS_H
#define COMM_SERCX_SYS_H
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C"
{
#endif
const SERIAL_DRIVER* SerCxSys_s(void);
#ifdef __cplusplus
}
#endif
#endif /* COMM_SERCX_SYS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERIAL_SYS_H
#define COMM_SERIAL_SYS_H
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C"
{
#endif
const SERIAL_DRIVER* SerialSys_s(void);
#ifdef __cplusplus
}
#endif
#endif /* COMM_SERIAL_SYS_H */

View File

@@ -0,0 +1,34 @@
set(MODULE_NAME "TestComm")
set(MODULE_PREFIX "TEST_COMM")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestCommDevice.c
TestCommConfig.c
TestGetCommState.c
TestSetCommState.c
TestSerialChars.c
TestControlSettings.c
TestHandflow.c
TestTimeouts.c
TestCommMonitor.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
set_tests_properties(${TestName} PROPERTIES LABELS "comm")
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,151 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/stat.h>
#include <winpr/crt.h>
#include <winpr/comm.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
int TestCommConfig(int argc, char* argv[])
{
DCB dcb = WINPR_C_ARRAY_INIT;
BOOL success = FALSE;
LPCSTR lpFileName = "\\\\.\\COM1";
COMMPROP commProp = WINPR_C_ARRAY_INIT;
struct stat statbuf = WINPR_C_ARRAY_INIT;
HANDLE hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
0, nullptr);
if (hComm && (hComm != INVALID_HANDLE_VALUE))
{
(void)fprintf(
stderr, "CreateFileA failure: could create a handle on a not yet defined device: %s\n",
lpFileName);
return EXIT_FAILURE;
}
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
success = DefineCommDevice(lpFileName, "/dev/ttyS0");
if (!success)
{
(void)fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName);
return EXIT_FAILURE;
}
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, /* invalid parameter */
nullptr, CREATE_NEW, /* invalid parameter */
0, (HANDLE)1234); /* invalid parameter */
if (hComm != INVALID_HANDLE_VALUE)
{
(void)fprintf(
stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n",
lpFileName);
return EXIT_FAILURE;
}
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0,
nullptr);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
(void)fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%08x\n", lpFileName,
GetLastError());
return EXIT_FAILURE;
}
/* TODO: a second call to CreateFileA should failed and
* GetLastError should return ERROR_SHARING_VIOLATION */
dcb.DCBlength = sizeof(DCB);
success = GetCommState(hComm, &dcb);
if (!success)
{
(void)fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", GetLastError());
return EXIT_FAILURE;
}
(void)fprintf(stderr,
"BaudRate: %" PRIu32 " ByteSize: %" PRIu8 " Parity: %" PRIu8 " StopBits: %" PRIu8
"\n",
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
if (!GetCommProperties(hComm, &commProp))
{
(void)fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x%08x\n",
GetLastError());
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_57600) <= 0)
{
(void)fprintf(stderr, "BAUD_57600 unsupported!\n");
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_14400) > 0)
{
(void)fprintf(stderr, "BAUD_14400 supported!\n");
return EXIT_FAILURE;
}
dcb.BaudRate = CBR_57600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
success = SetCommState(hComm, &dcb);
if (!success)
{
(void)fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
success = GetCommState(hComm, &dcb);
if (!success)
{
(void)fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", GetLastError());
return 0;
}
if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) ||
(dcb.StopBits != ONESTOPBIT))
{
(void)fprintf(stderr,
"Got an unexpected value among: BaudRate: %" PRIu32 " ByteSize: %" PRIu8
" Parity: %" PRIu8 " StopBits: %" PRIu8 "\n",
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
}
(void)CloseHandle(hComm);
return 0;
}

View File

@@ -0,0 +1,115 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <winpr/comm.h>
#include <winpr/tchar.h>
static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult)
{
TCHAR lpTargetPath[MAX_PATH] = WINPR_C_ARRAY_INIT;
BOOL result = DefineCommDevice(lpDeviceName, _T("/dev/test"));
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
{
_tprintf(_T("DefineCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName, (expectedResult ? "TRUE" : "FALSE"), (result ? "TRUE" : "FALSE"));
return FALSE;
}
result = IsCommDevice(lpDeviceName);
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
{
_tprintf(_T("IsCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName, (expectedResult ? "TRUE" : "FALSE"), (result ? "TRUE" : "FALSE"));
return FALSE;
}
const size_t tclen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH);
if (expectedResult)
{
const size_t tlen = _tcsnlen(lpTargetPath, ARRAYSIZE(lpTargetPath) - 1);
if (tclen <= tlen) /* at least 2 more TCHAR are expected */
{
_tprintf(_T("QueryCommDevice failure: didn't find the device name: %s\n"),
lpDeviceName);
return FALSE;
}
if (_tcsncmp(_T("/dev/test"), lpTargetPath, ARRAYSIZE(lpTargetPath)) != 0)
{
_tprintf(
_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName, _T("/dev/test"), lpTargetPath);
return FALSE;
}
if ((tlen >= (ARRAYSIZE(lpTargetPath) - 1)) || (lpTargetPath[tlen + 1] != 0))
{
_tprintf(
_T("QueryCommDevice failure: device name: %s, the second nullptr character is ")
_T("missing at the end of the buffer\n"),
lpDeviceName);
return FALSE;
}
}
else
{
if (tclen > 0)
{
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: <none>, ")
_T("result: %") _T(PRIuz) _T(" %s\n"),
lpDeviceName, tclen, lpTargetPath);
return FALSE;
}
}
return TRUE;
}
int TestCommDevice(int argc, char* argv[])
{
if (!test_CommDevice(_T("COM0"), FALSE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM1"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM1"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM10"), FALSE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.COM10"), FALSE))
return EXIT_FAILURE;
return 0;
}

View File

@@ -0,0 +1,70 @@
#include <winpr/crt.h>
#include <winpr/comm.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
int TestCommMonitor(int argc, char* argv[])
{
HANDLE hComm = nullptr;
DWORD dwError = 0;
BOOL fSuccess = 0;
DWORD dwEvtMask = 0;
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
LPCSTR lpFileName = "\\\\.\\COM1";
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, nullptr);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
printf("CreateFileA failure: %s\n", lpFileName);
return -1;
}
fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR);
if (!fSuccess)
{
printf("SetCommMask failure: GetLastError() = %" PRIu32 "\n", GetLastError());
return -1;
}
if (!(overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
{
printf("CreateEvent failed: GetLastError() = %" PRIu32 "\n", GetLastError());
return -1;
}
if (WaitCommEvent(hComm, &dwEvtMask, &overlapped))
{
if (dwEvtMask & EV_DSR)
{
printf("EV_DSR\n");
}
if (dwEvtMask & EV_CTS)
{
printf("EV_CTS\n");
}
}
else
{
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
printf("ERROR_IO_PENDING\n");
}
else
{
printf("WaitCommEvent failure: GetLastError() = %" PRIu32 "\n", dwError);
return -1;
}
}
(void)CloseHandle(hComm);
return 0;
}

View File

@@ -0,0 +1,123 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
int TestControlSettings(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
DCB dcb = WINPR_C_ARRAY_INIT;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.ByteSize = 5;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = MARKPARITY;
if (!SetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY))
{
(void)fprintf(stderr, "test1 failed.\n");
return FALSE;
}
/* Test 2 */
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if (!SetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY))
{
(void)fprintf(stderr, "test2 failed.\n");
return FALSE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,140 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_generic(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
DCB* pDcb = nullptr;
BOOL result = 0;
ZeroMemory(&dcb, sizeof(DCB));
result = GetCommState(hComm, &dcb);
if (result)
{
printf("GetCommState failure, should have returned false because dcb.DCBlength has been "
"let uninitialized\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB) / 2; /* improper value */
result = GetCommState(hComm, &dcb);
if (result)
{
printf("GetCommState failure, should have return false because dcb.DCBlength was not "
"correctly initialized\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
result = GetCommState(hComm, &dcb);
if (!result)
{
printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError());
return FALSE;
}
pDcb = (DCB*)calloc(2, sizeof(DCB));
if (!pDcb)
return FALSE;
pDcb->DCBlength = sizeof(DCB) * 2;
result = GetCommState(hComm, pDcb);
result = result && (pDcb->DCBlength == sizeof(DCB) * 2);
free(pDcb);
if (!result)
{
printf("GetCommState failure: 0x%x, with bigger DCBlength\n", GetLastError());
return FALSE;
}
return TRUE;
}
int TestGetCommState(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
printf("DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm =
CreateFileA("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
printf("CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverUnknown)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerialSys)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerCxSys)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerCx2Sys)\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,92 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <termios.h>
#endif
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerialSys(HANDLE hComm)
{
// TMP: TODO:
return TRUE;
}
int TestHandflow(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_SerialSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */
/* if (!test_SerCxSys(hComm)) */
/* { */
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */
/* if (!test_SerCx2Sys(hComm)) */
/* { */
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,180 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <termios.h>
#endif
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerCxSys(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
UCHAR XonChar = 0;
UCHAR XoffChar = 0;
struct termios currentTermios = WINPR_C_ARRAY_INIT;
if (tcgetattr(((WINPR_COMM*)hComm)->fd, &currentTermios) < 0)
{
(void)fprintf(stderr, "tcgetattr failure.\n");
return FALSE;
}
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0'))
{
(void)fprintf(stderr, "test_SerCxSys failure, expected XonChar and XoffChar to be set\n");
return FALSE;
}
/* retrieve Xon/Xoff chars */
if ((dcb.XonChar != currentTermios.c_cc[VSTART]) ||
(dcb.XoffChar != currentTermios.c_cc[VSTOP]))
{
(void)fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n");
return FALSE;
}
/* swap XonChar/XoffChar */
XonChar = dcb.XonChar;
XoffChar = dcb.XoffChar;
dcb.XonChar = XoffChar;
dcb.XoffChar = XonChar;
if (!SetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "SetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar))
{
(void)fprintf(stderr, "test_SerCxSys, expected XonChar and XoffChar to be swapped\n");
return FALSE;
}
/* same XonChar / XoffChar */
dcb.XonChar = dcb.XoffChar;
if (SetCommState(hComm, &dcb))
{
(void)fprintf(stderr,
"test_SerCxSys failure, SetCommState() was supposed to failed because "
"XonChar and XoffChar are the same\n");
return FALSE;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
(void)fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed with "
"GetLastError()=ERROR_INVALID_PARAMETER\n");
return FALSE;
}
return TRUE;
}
static BOOL test_SerCx2Sys(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') ||
(dcb.XonChar != '\0') || (dcb.XoffChar != '\0'))
{
(void)fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n");
return FALSE;
}
return TRUE;
}
int TestSerialChars(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_SerCxSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_SerCx2Sys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,335 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static void init_empty_dcb(DCB* pDcb)
{
WINPR_ASSERT(pDcb);
ZeroMemory(pDcb, sizeof(DCB));
pDcb->DCBlength = sizeof(DCB);
pDcb->XonChar = 1;
pDcb->XoffChar = 2;
}
static BOOL test_fParity(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
/* test 1 */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
return FALSE;
}
/* test 2 */
dcb.fParity = FALSE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of FALSE\n", dcb.fParity);
return FALSE;
}
/* test 3 (redo test 1) */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
return FALSE;
}
return TRUE;
}
static BOOL test_SerialSys(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.BaudRate = CBR_115200;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_115200)
{
(void)fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n",
CBR_115200);
return FALSE;
}
/* Test 2 using a different baud rate */
dcb.BaudRate = CBR_57600;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_57600)
{
(void)fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_57600)\n",
CBR_57600);
return FALSE;
}
/* Test 3 using an unsupported baud rate on Linux */
dcb.BaudRate = CBR_128000;
result = SetCommState(hComm, &dcb);
if (result)
{
(void)fprintf(stderr,
"SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n",
CBR_128000);
return FALSE;
}
return TRUE;
}
static BOOL test_SerCxSys(HANDLE hComm)
{
/* as of today there is no difference */
return test_SerialSys(hComm);
}
static BOOL test_SerCx2Sys(HANDLE hComm)
{
/* as of today there is no difference */
return test_SerialSys(hComm);
}
static BOOL test_generic(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
DCB dcb2 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Checks whether we get the same information before and after SetCommState */
memcpy(&dcb2, &dcb, sizeof(DCB));
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
return FALSE;
}
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0)
{
(void)fprintf(stderr,
"DCB is different after SetCommState() whereas it should have not changed\n");
return FALSE;
}
// TODO: a more complete and generic test using GetCommProperties()
/* TMP: TODO: fBinary tests */
/* fParity tests */
if (!test_fParity(hComm))
{
(void)fprintf(stderr, "test_fParity failure\n");
return FALSE;
}
return TRUE;
}
int TestSetCommState(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n");
return EXIT_FAILURE;
}
if (!test_SerialSys(hComm))
{
(void)fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n");
return EXIT_FAILURE;
}
if (!test_SerCxSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n");
return EXIT_FAILURE;
}
if (!test_SerCx2Sys(hComm))
{
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,141 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <termios.h>
#endif
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_generic(HANDLE hComm)
{
COMMTIMEOUTS timeouts = WINPR_C_ARRAY_INIT;
COMMTIMEOUTS timeouts2 = WINPR_C_ARRAY_INIT;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 2;
timeouts.ReadTotalTimeoutConstant = 3;
timeouts.WriteTotalTimeoutMultiplier = 4;
timeouts.WriteTotalTimeoutConstant = 5;
if (!SetCommTimeouts(hComm, &timeouts))
{
(void)fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
return FALSE;
}
if (!GetCommTimeouts(hComm, &timeouts2))
{
(void)fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
return FALSE;
}
if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0)
{
(void)fprintf(stderr, "TestTimeouts failure, didn't get back the same timeouts.\n");
return FALSE;
}
/* not supported combination */
timeouts.ReadIntervalTimeout = MAXULONG;
timeouts.ReadTotalTimeoutConstant = MAXULONG;
if (SetCommTimeouts(hComm, &timeouts))
{
(void)fprintf(
stderr,
"SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant "
"set to MAXULONG. GetLastError: 0x%08x\n",
GetLastError());
return FALSE;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
(void)fprintf(
stderr,
"SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER "
"and got: 0x%08x\n",
GetLastError());
return FALSE;
}
return TRUE;
}
int TestTimeouts(int argc, char* argv[])
{
struct stat statbuf;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-credentials cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(credentials.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "security")
set(MINWIN_MAJOR_VERSION "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "credentials")
set(MINWIN_LONG_NAME "Credentials Management Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

View File

@@ -0,0 +1,303 @@
/**
* WinPR: Windows Portable Runtime
* Credentials Management
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2025 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/cred.h>
#include <winpr/error.h>
#include <winpr/wlog.h>
#include "../log.h"
#define TAG WINPR_TAG("Cred")
/*
* Low-Level Credentials Management Functions:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx#low_level_credentials_management_functions
*/
#ifndef _WIN32
static BYTE char_decode(char c)
{
if (c >= 'A' && c <= 'Z')
return (BYTE)(c - 'A');
if (c >= 'a' && c <= 'z')
return (BYTE)(c - 'a' + 26);
if (c >= '0' && c <= '9')
return (BYTE)(c - '0' + 52);
if (c == '#')
return 62;
if (c == '-')
return 63;
return 64;
}
static BOOL cred_decode(const char* cred, size_t len, BYTE* buf)
{
size_t i = 0;
const char* p = cred;
while (len >= 4)
{
BYTE c0 = char_decode(p[0]);
if (c0 > 63)
return FALSE;
BYTE c1 = char_decode(p[1]);
if (c1 > 63)
return FALSE;
BYTE c2 = char_decode(p[2]);
if (c2 > 63)
return FALSE;
BYTE c3 = char_decode(p[3]);
if (c3 > 63)
return FALSE;
buf[i + 0] = (BYTE)((c1 << 6) | c0);
buf[i + 1] = (BYTE)((c2 << 4) | (c1 >> 2));
buf[i + 2] = (BYTE)((c3 << 2) | (c2 >> 4));
len -= 4;
i += 3;
p += 4;
}
if (len == 3)
{
BYTE c0 = char_decode(p[0]);
if (c0 > 63)
return FALSE;
BYTE c1 = char_decode(p[1]);
if (c1 > 63)
return FALSE;
BYTE c2 = char_decode(p[2]);
if (c2 > 63)
return FALSE;
buf[i + 0] = (BYTE)((c1 << 6) | c0);
buf[i + 1] = (BYTE)((c2 << 4) | (c1 >> 2));
}
else if (len == 2)
{
BYTE c0 = char_decode(p[0]);
if (c0 > 63)
return FALSE;
BYTE c1 = char_decode(p[1]);
if (c1 > 63)
return FALSE;
buf[i + 0] = (BYTE)((c1 << 6) | c0);
}
else if (len == 1)
{
WLog_ERR(TAG, "invalid string length");
return FALSE;
}
return TRUE;
}
static size_t cred_encode(const BYTE* bin, size_t len, char* cred, size_t credlen)
{
static const char encodingChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"#-";
size_t n = 0;
size_t offset = 0;
while (offset < len)
{
if (n >= credlen)
break;
cred[n++] = encodingChars[bin[offset] & 0x3f];
BYTE x = (bin[offset] & 0xc0) >> 6;
offset++;
if (offset >= len)
{
cred[n++] = encodingChars[x];
break;
}
if (n >= credlen)
break;
cred[n++] = encodingChars[((bin[offset] & 0xf) << 2) | x];
x = (bin[offset] & 0xf0) >> 4;
offset++;
if (offset >= len)
{
cred[n++] = encodingChars[x];
break;
}
if (n >= credlen)
break;
cred[n++] = encodingChars[((bin[offset] & 0x3) << 4) | x];
if (n >= credlen)
break;
cred[n++] = encodingChars[(bin[offset] & 0xfc) >> 2];
offset++;
}
return n;
}
BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID Credential,
LPWSTR* MarshaledCredential)
{
char* b = nullptr;
if (!CredMarshalCredentialA(CredType, Credential, &b) || !b)
return FALSE;
*MarshaledCredential = ConvertUtf8ToWCharAlloc(b, nullptr);
free(b);
return (*MarshaledCredential != nullptr);
}
BOOL CredMarshalCredentialA(CRED_MARSHAL_TYPE CredType, PVOID Credential,
LPSTR* MarshaledCredential)
{
CERT_CREDENTIAL_INFO* cert = Credential;
if (!cert || ((CredType == CertCredential) && (cert->cbSize < sizeof(CERT_CREDENTIAL_INFO))) ||
!MarshaledCredential)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
switch (CredType)
{
case CertCredential:
{
char buffer[3ULL + (sizeof(cert->rgbHashOfCert) * 4 / 3) + 1ULL /* rounding error */] =
WINPR_C_ARRAY_INIT;
const char c = WINPR_ASSERTING_INT_CAST(char, 'A' + CredType);
(void)_snprintf(buffer, sizeof(buffer), "@@%c", c);
size_t len = cred_encode(cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), &buffer[3],
sizeof(buffer) - 3);
*MarshaledCredential = strndup(buffer, len + 3);
return TRUE;
}
default:
WLog_ERR(TAG, "unhandled type 0x%x", CredType);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
BOOL CredUnmarshalCredentialW(LPCWSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential)
{
char* str = nullptr;
if (cred)
str = ConvertWCharToUtf8Alloc(cred, nullptr);
const BOOL rc = CredUnmarshalCredentialA(str, CredType, Credential);
free(str);
return rc;
}
BOOL CredUnmarshalCredentialA(LPCSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential)
{
if (!cred)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
const size_t len = strlen(cred);
if ((len < 3) || !CredType || !Credential || (cred[0] != '@') || (cred[1] != '@'))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
BYTE b = char_decode(cred[2]);
if (!b || (b > BinaryBlobForSystem))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*CredType = (CRED_MARSHAL_TYPE)b;
switch (*CredType)
{
case CertCredential:
{
BYTE hash[CERT_HASH_LENGTH] = WINPR_C_ARRAY_INIT;
if ((len != 30) || !cred_decode(&cred[3], len - 3, hash))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
CERT_CREDENTIAL_INFO* cert = calloc(1, sizeof(CERT_CREDENTIAL_INFO));
if (!cert)
return FALSE;
cert->cbSize = sizeof(CERT_CREDENTIAL_INFO);
memcpy(cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert));
*Credential = cert;
break;
}
default:
WLog_ERR(TAG, "unhandled credType 0x%x", *CredType);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
BOOL CredIsMarshaledCredentialW(LPCWSTR MarshaledCredential)
{
CRED_MARSHAL_TYPE t = BinaryBlobForSystem;
void* out = nullptr;
BOOL ret = CredUnmarshalCredentialW(MarshaledCredential, &t, &out);
if (out)
CredFree(out);
return ret;
}
BOOL CredIsMarshaledCredentialA(LPCSTR MarshaledCredential)
{
CRED_MARSHAL_TYPE t = BinaryBlobForSystem;
void* out = nullptr;
BOOL ret = CredUnmarshalCredentialA(MarshaledCredential, &t, &out);
if (out)
CredFree(out);
return ret;
}
VOID CredFree(PVOID Buffer)
{
free(Buffer);
}
#endif /* _WIN32 */

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestCredentials")
set(MODULE_PREFIX "TEST_CREDENTIALS")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestMarshalUnmarshal.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
target_link_libraries(${MODULE_NAME} winpr ${OPENSSL_LIBRARIES})
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,95 @@
/**
* WinPR: Windows Portable Runtime
* Buffer Manipulation
*
* Copyright 2025 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <winpr/cred.h>
typedef struct
{
LPCSTR marshalled;
BYTE source[CERT_HASH_LENGTH];
} TestItem;
static const TestItem testValues[] = {
{ "@@BQ9eNR0KWVU-CT8sPCp8z37POZHJ",
{ 0x50, 0xef, 0x35, 0x11, 0xad, 0x58, 0x15, 0xf5, 0x0b, 0x13,
0xcf, 0x3e, 0x42, 0xca, 0xcf, 0xf7, 0xfe, 0x38, 0xd9, 0x91 } },
{ "@@BKay-HwJsFZzclXAWZ#nO6Eluc7P",
{ 0x8a, 0x26, 0xff, 0x07, 0x9c, 0xb0, 0x45, 0x36, 0x73, 0xe5,
0x05, 0x58, 0x99, 0x7f, 0x3a, 0x3a, 0x51, 0xba, 0xdc, 0xfe }
}
};
static int TestUnmarshal(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char** argv)
{
for (size_t i = 0; i < ARRAYSIZE(testValues); i++)
{
CRED_MARSHAL_TYPE t = BinaryBlobForSystem;
CERT_CREDENTIAL_INFO* certInfo = nullptr;
const TestItem* const val = &testValues[i];
if (!CredUnmarshalCredentialA(val->marshalled, &t, (void**)&certInfo) || !certInfo ||
(t != CertCredential))
return -1;
const BOOL ok =
memcmp(val->source, certInfo->rgbHashOfCert, sizeof(certInfo->rgbHashOfCert)) == 0;
free(certInfo);
if (!ok)
return -1;
}
return 0;
}
static int TestMarshal(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char** argv)
{
for (size_t i = 0; i < ARRAYSIZE(testValues); i++)
{
CERT_CREDENTIAL_INFO certInfo = { sizeof(certInfo), { 0 } };
const TestItem* const val = &testValues[i];
memcpy(certInfo.rgbHashOfCert, val->source, sizeof(certInfo.rgbHashOfCert));
LPSTR out = nullptr;
if (!CredMarshalCredentialA(CertCredential, &certInfo, &out) || !out)
return -1;
BOOL ok = (strcmp(val->marshalled, out) == 0);
free(out);
if (!ok)
return -1;
}
return 0;
}
int TestMarshalUnmarshal(int argc, char** argv)
{
int ret = TestUnmarshal(argc, argv);
if (ret)
return ret;
ret = TestMarshal(argc, argv);
return ret;
}

View File

@@ -0,0 +1,52 @@
# WinPR: Windows Portable Runtime
# libwinpr-crt cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(CRT_FILES
alignment.c
conversion.c
buffer.c
memory.c
unicode.c
string.c
assert.c
)
if(WITH_UNICODE_BUILTIN)
list(APPEND CRT_FILES unicode_builtin.c)
else()
if(ANDROID)
list(APPEND CRT_FILES unicode_android.c)
elseif(NOT APPLE AND NOT WIN32)
find_package(ICU REQUIRED i18n uc io data)
winpr_pc_add_requires_private("icu-uc")
winpr_pc_add_requires_private("icu-io")
winpr_pc_add_requires_private("icu-i18n")
list(APPEND CRT_FILES unicode_icu.c)
winpr_system_include_directory_add(${ICU_INCLUDE_DIRS})
winpr_library_add_private(${ICU_LIBRARIES})
elseif(APPLE)
list(APPEND CRT_FILES unicode_apple.m)
find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
winpr_library_add_private(${FOUNDATION_FRAMEWORK})
endif()
endif()
winpr_module_add(${CRT_FILES})
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "crt")
set(MINWIN_LONG_NAME "Microsoft C Run-Time")
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")

View File

@@ -0,0 +1,261 @@
/**
* WinPR: Windows Portable Runtime
* Data Alignment
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <winpr/config.h>
#include <winpr/crt.h>
/* Data Alignment: http://msdn.microsoft.com/en-us/library/fs9stz4e/ */
#if !defined(_WIN32) || (defined(__MINGW32__) && !defined(_UCRT))
#include <stdint.h>
#include <limits.h>
#define WINPR_ALIGNED_MEM_SIGNATURE 0x0BA0BAB
#define WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(_memptr) \
(WINPR_ALIGNED_MEM*)(((size_t)(((BYTE*)(_memptr)) - sizeof(WINPR_ALIGNED_MEM))))
#include <stdlib.h>
#include "../log.h"
#define TAG WINPR_TAG("crt")
struct winpr_aligned_mem
{
UINT32 sig;
size_t size;
void* base_addr;
};
typedef struct winpr_aligned_mem WINPR_ALIGNED_MEM;
void* winpr_aligned_malloc(size_t size, size_t alignment)
{
return winpr_aligned_offset_malloc(size, alignment, 0);
}
void* winpr_aligned_calloc(size_t count, size_t size, size_t alignment)
{
return winpr_aligned_recalloc(nullptr, count, size, alignment);
}
void* winpr_aligned_realloc(void* memblock, size_t size, size_t alignment)
{
return winpr_aligned_offset_realloc(memblock, size, alignment, 0);
}
void* winpr_aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment)
{
return winpr_aligned_offset_recalloc(memblock, num, size, alignment, 0);
}
void* winpr_aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
{
size_t header = 0;
size_t alignsize = 0;
uintptr_t basesize = 0;
void* base = nullptr;
void* memblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
/* alignment must be a power of 2 */
if (alignment % 2 == 1)
return nullptr;
/* offset must be less than size */
if (offset >= size)
return nullptr;
/* minimum alignment is pointer size */
if (alignment < sizeof(void*))
alignment = sizeof(void*);
if (alignment > SIZE_MAX - sizeof(WINPR_ALIGNED_MEM))
return nullptr;
header = sizeof(WINPR_ALIGNED_MEM) + alignment;
if (size > SIZE_MAX - header)
return nullptr;
alignsize = size + header;
/* malloc size + alignment to make sure we can align afterwards */
#if defined(_ISOC11_SOURCE)
base = aligned_alloc(alignment, alignsize);
#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)
if (posix_memalign(&base, alignment, alignsize) != 0)
return nullptr;
#else
base = malloc(alignsize);
#endif
if (!base)
return nullptr;
basesize = (uintptr_t)base;
if ((offset > UINTPTR_MAX) || (header > UINTPTR_MAX - offset) ||
(basesize > UINTPTR_MAX - header - offset))
{
free(base);
return nullptr;
}
memblock = (void*)(((basesize + header + offset) & ~(alignment - 1)) - offset);
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
pMem->sig = WINPR_ALIGNED_MEM_SIGNATURE;
pMem->base_addr = base;
pMem->size = size;
return memblock;
}
void* winpr_aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset)
{
size_t copySize = 0;
void* newMemblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
WINPR_ALIGNED_MEM* pNewMem = nullptr;
if (!memblock)
return winpr_aligned_offset_malloc(size, alignment, offset);
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG,
"_aligned_offset_realloc: memory block was not allocated by _aligned_malloc!");
return nullptr;
}
if (size == 0)
{
winpr_aligned_free(memblock);
return nullptr;
}
newMemblock = winpr_aligned_offset_malloc(size, alignment, offset);
if (!newMemblock)
return nullptr;
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
copySize = (pNewMem->size < pMem->size) ? pNewMem->size : pMem->size;
CopyMemory(newMemblock, memblock, copySize);
winpr_aligned_free(memblock);
return newMemblock;
}
static inline size_t cMIN(size_t a, size_t b)
{
if (a > b)
return b;
return a;
}
void* winpr_aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment,
size_t offset)
{
char* newMemblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
WINPR_ALIGNED_MEM* pNewMem = nullptr;
if (!memblock)
{
newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
if (newMemblock)
{
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
ZeroMemory(newMemblock, pNewMem->size);
}
return newMemblock;
}
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG,
"_aligned_offset_recalloc: memory block was not allocated by _aligned_malloc!");
goto fail;
}
if ((num == 0) || (size == 0))
goto fail;
if (pMem->size > (1ull * num * size) + alignment)
return memblock;
newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
if (!newMemblock)
goto fail;
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
{
const size_t csize = cMIN(pMem->size, pNewMem->size);
memcpy(newMemblock, memblock, csize);
ZeroMemory(newMemblock + csize, pNewMem->size - csize);
}
fail:
winpr_aligned_free(memblock);
return newMemblock;
}
size_t winpr_aligned_msize(void* memblock, WINPR_ATTR_UNUSED size_t alignment,
WINPR_ATTR_UNUSED size_t offset)
{
WINPR_ALIGNED_MEM* pMem = nullptr;
if (!memblock)
return 0;
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG, "_aligned_msize: memory block was not allocated by _aligned_malloc!");
return 0;
}
return pMem->size;
}
void winpr_aligned_free(void* memblock)
{
WINPR_ALIGNED_MEM* pMem = nullptr;
if (!memblock)
return;
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG, "_aligned_free: memory block was not allocated by _aligned_malloc!");
return;
}
free(pMem->base_addr);
}
#endif /* _WIN32 */

View File

@@ -0,0 +1,31 @@
/**
* WinPR: Windows Portable Runtime
* Runtime ASSERT macros
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* Copyright 2021 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/wlog.h>
#include <winpr/debug.h>
void winpr_int_assert(const char* condstr, const char* file, const char* fkt, size_t line)
{
wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert");
WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", condstr, file, fkt, line);
winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20);
abort();
}

View File

@@ -0,0 +1,50 @@
/**
* WinPR: Windows Portable Runtime
* Buffer Manipulation
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
/* Buffer Manipulation: http://msdn.microsoft.com/en-us/library/b3893xdy/ */
#ifndef _WIN32
#include <string.h>
errno_t memmove_s(void* dest, size_t numberOfElements, const void* src, size_t count)
{
if (count > numberOfElements)
return -1;
memmove(dest, src, count);
return 0;
}
errno_t wmemmove_s(WCHAR* dest, size_t numberOfElements, const WCHAR* src, size_t count)
{
if (count * sizeof(WCHAR) > numberOfElements)
return -1;
memmove(dest, src, count * 2);
return 0;
}
#endif

View File

@@ -0,0 +1,726 @@
/**
* Unicode case mappings
*
* This code is generated by wine's make_unicode script
* which downloads data from unicode.org and produces
* readily usable conversion tables.
*
* After asking permission from Alexandre Julliard in May 2011,
* it was clarified that no copyright was claimed by the wine
* project on the script's generated output.
*/
#define WINPR_TOLOWERW(_wch) \
(_wch + winpr_casemap_lower[winpr_casemap_lower[_wch >> 8] + (_wch & 0xFF)])
#define WINPR_TOUPPERW(_wch) \
(_wch + winpr_casemap_upper[winpr_casemap_upper[_wch >> 8] + (_wch & 0xFF)])
static const WCHAR winpr_casemap_lower[3807] = {
/* index */
0x01bf, 0x02bf, 0x03bf, 0x044f, 0x054f, 0x064f, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x06af, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x07af, 0x08ae, 0x0100, 0x09ab, 0x0100, 0x0100,
0x0a2f, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0b2f, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0c22, 0x0d00,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0ddf,
/* defaults */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0041 .. 0x00ff */
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0100 .. 0x01ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0xff39, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0xff87, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x00d2, 0x0001, 0x0000,
0x0001, 0x0000, 0x00ce, 0x0001, 0x0000, 0x00cd, 0x00cd, 0x0001, 0x0000, 0x0000, 0x004f, 0x00ca,
0x00cb, 0x0001, 0x0000, 0x00cd, 0x00cf, 0x0000, 0x00d3, 0x00d1, 0x0001, 0x0000, 0x0000, 0x0000,
0x00d3, 0x00d5, 0x0000, 0x00d6, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001,
0x0000, 0x00da, 0x0000, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001, 0x0000, 0x00d9, 0x00d9, 0x0001,
0x0000, 0x0001, 0x0000, 0x00db, 0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0000, 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0xff9f, 0xffc8, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x0200 .. 0x02ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0xff7e, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2a2b, 0x0001,
0x0000, 0xff5d, 0x2a28, 0x0000, 0x0000, 0x0001, 0x0000, 0xff3d, 0x0045, 0x0047, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0370 .. 0x03ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0026, 0x0000,
0x0025, 0x0025, 0x0025, 0x0000, 0x0040, 0x0000, 0x003f, 0x003f, 0x0000, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0xffc4, 0x0000, 0x0000, 0x0001, 0x0000, 0xfff9, 0x0001, 0x0000, 0x0000, 0xff7e, 0xff7e, 0xff7e,
/* 0x0400 .. 0x04ff */
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050,
0x0050, 0x0050, 0x0050, 0x0050, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x000f, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x0500 .. 0x05ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x10a0 .. 0x10ff */
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x0000, 0x1c60, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c60, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x1e00 .. 0x1eff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xe241, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x1f01 .. 0x1fff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xffb6, 0xffb6, 0xfff7, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffaa, 0xffaa, 0xffaa, 0xffaa, 0xfff7,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xff9c, 0xff9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xff90, 0xff90, 0xfff9, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff80, 0xff80, 0xff82, 0xff82, 0xfff7,
0x0000, 0x0000, 0x0000,
/* 0x2103 .. 0x21ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe2a3,
0x0000, 0x0000, 0x0000, 0xdf41, 0xdfba, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001c,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000,
/* 0x247c .. 0x24ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001a, 0x001a,
0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a,
0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x2c00 .. 0x2cff */
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0000, 0xd609, 0xf11a, 0xd619, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0xd5e4, 0xd603, 0xd5e1, 0xd5e2, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd5c1, 0xd5c1, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa60d .. 0xa6ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000,
/* 0xa722 .. 0xa7ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x75fc, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x5ad8,
0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x5abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xff21 .. 0xffff */
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
static const WCHAR winpr_casemap_upper[3994] = {
/* index */
0x019f, 0x029f, 0x039f, 0x045a, 0x0556, 0x0656, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x06dd, 0x07dc, 0x08dc, 0x0100, 0x09d0, 0x0100, 0x0100,
0x0a55, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0b3f, 0x0c3f, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0cfe, 0x0ddb,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0e9a,
/* defaults */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0061 .. 0x00ff */
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x02e7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0079,
/* 0x0100 .. 0x01ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xff18, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xfed4, 0x00c3, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0061, 0x0000, 0x0000, 0x0000, 0xffff, 0x00a3, 0x0000,
0x0000, 0x0000, 0x0082, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0038,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff,
0xfffe, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xffb1, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff,
/* 0x0200 .. 0x02ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x2a3f, 0x2a3f, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x2a1f, 0x2a1c, 0x2a1e, 0xff2e,
0xff32, 0x0000, 0xff33, 0xff33, 0x0000, 0xff36, 0x0000, 0xff35, 0x0000, 0x0000, 0x0000, 0x0000,
0xff33, 0x0000, 0x0000, 0xff31, 0x0000, 0xa528, 0xa544, 0x0000, 0xff2f, 0xff2d, 0x0000, 0x29f7,
0x0000, 0x0000, 0x0000, 0xff2d, 0x0000, 0x29fd, 0xff2b, 0x0000, 0x0000, 0xff2a, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x29e7, 0x0000, 0x0000, 0xff26, 0x0000, 0x0000, 0xff26,
0x0000, 0x0000, 0x0000, 0x0000, 0xff26, 0xffbb, 0xff27, 0xff27, 0xffb9, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xff25, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0345 .. 0x03ff */
0x0054, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0082, 0x0082, 0x0082, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffda, 0xffdb, 0xffdb, 0xffdb, 0x0000,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe1, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffc0, 0xffc1, 0xffc1, 0x0000, 0xffc2, 0xffc7, 0x0000, 0x0000, 0x0000,
0xffd1, 0xffca, 0xfff8, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0xffaa, 0xffb0, 0x0007, 0x0000, 0x0000, 0xffa0, 0x0000, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0404 .. 0x04ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0,
0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xfff1,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
/* 0x0500 .. 0x05ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x1d79 .. 0x1dff */
0x8a04, 0x0000, 0x0000, 0x0000, 0x0ee6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000,
/* 0x1e01 .. 0x1eff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc5, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff,
/* 0x1f00 .. 0x1fff */
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008,
0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x0008,
0x0000, 0x0008, 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x004a, 0x004a, 0x0056, 0x0056, 0x0056, 0x0056, 0x0064, 0x0064,
0x0080, 0x0080, 0x0070, 0x0070, 0x007e, 0x007e, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008,
0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0009,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe3db, 0x0000,
0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x210c .. 0x21ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0,
0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0x0000, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x247b .. 0x24ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6,
0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6,
0xffe6, 0xffe6, 0xffe6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000,
/* 0x2c16 .. 0x2cff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xd5d5, 0xd5d8, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x2d00 .. 0x2dff */
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0x0000, 0xe3a0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe3a0, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa641 .. 0xa6ff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa723 .. 0xa7ff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xff41 .. 0xffff */
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};

View File

@@ -0,0 +1,44 @@
/**
* WinPR: Windows Portable Runtime
* Data Conversion
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/string.h>
/* Data Conversion: http://msdn.microsoft.com/en-us/library/0heszx3w/ */
#ifndef _WIN32
errno_t _itoa_s(int value, char* buffer, size_t sizeInCharacters, WINPR_ATTR_UNUSED int radix)
{
int length = sprintf_s(nullptr, 0, "%d", value);
if (length < 0)
return -1;
if (sizeInCharacters < (size_t)length)
return -1;
(void)sprintf_s(buffer, WINPR_ASSERTING_INT_CAST(size_t, length + 1), "%d", value);
return 0;
}
#endif

View File

@@ -0,0 +1,42 @@
/**
* WinPR: Windows Portable Runtime
* Memory Allocation
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
/* Memory Allocation: http://msdn.microsoft.com/en-us/library/hk1k7x6x.aspx */
/* Memory Management Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366781/ */
#ifndef _WIN32
PVOID SecureZeroMemory(PVOID ptr, size_t cnt)
{
volatile BYTE* p = ptr;
while (cnt--)
{
*p = 0;
p++;
}
return ptr;
}
#endif

View File

@@ -0,0 +1,843 @@
/**
* WinPR: Windows Portable Runtime
* String Manipulation (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <wctype.h>
#include <wchar.h>
#include <winpr/crt.h>
#include <winpr/endian.h>
#if defined(WITH_URIPARSER)
#include <uriparser/Uri.h>
#endif
/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
#include "../log.h"
#define TAG WINPR_TAG("crt")
#if defined(WITH_URIPARSER)
char* winpr_str_url_decode(const char* str, size_t len)
{
char* dst = strndup(str, len);
if (!dst)
return nullptr;
if (!uriUnescapeInPlaceExA(dst, URI_FALSE, URI_BR_DONT_TOUCH))
{
free(dst);
return nullptr;
}
return dst;
}
char* winpr_str_url_encode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char) * 3);
if (!dst)
return nullptr;
if (!uriEscapeA(str, dst, URI_FALSE, URI_FALSE))
{
free(dst);
return nullptr;
}
return dst;
}
#else
static const char rfc3986[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char hex2bin(char what)
{
if (what >= 'a')
what -= 'a' - 'A';
if (what >= 'A')
what -= ('A' - 10);
else
what -= '0';
return what;
}
static char unescape(const char* what, size_t* px)
{
if ((*what == '%') && (isxdigit(what[1]) && isxdigit(what[2])))
{
*px += 2;
return 16 * hex2bin(what[1]) + hex2bin(what[2]);
}
return *what;
}
char* winpr_str_url_decode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char));
if (!dst)
return nullptr;
size_t pos = 0;
for (size_t x = 0; x < strnlen(str, len); x++)
{
const char* cur = &str[x];
dst[pos++] = unescape(cur, &x);
}
return dst;
}
static char* escape(char* dst, char what)
{
if (rfc3986[what & 0xff])
{
*dst = what;
return dst + 1;
}
sprintf(dst, "%%%02" PRIX8, (BYTE)(what & 0xff));
return dst + 3;
}
char* winpr_str_url_encode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char) * 3);
if (!dst)
return nullptr;
char* ptr = dst;
for (size_t x = 0; x < strnlen(str, len); x++)
{
const char cur = str[x];
ptr = escape(ptr, cur);
}
return dst;
}
#endif
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
{
const size_t used = strnlen(buffer, size);
const size_t add = strnlen(what, size);
const size_t sep_len = separator ? strnlen(separator, size) : 0;
const size_t sep = (used > 0) ? sep_len : 0;
if (used + add + sep >= size)
return FALSE;
if ((used > 0) && (sep_len > 0))
strncat(buffer, separator, sep_len);
strncat(buffer, what, add);
return TRUE;
}
WINPR_ATTR_FORMAT_ARG(3, 4)
int winpr_asprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, templ);
int rc = winpr_vasprintf(s, slen, templ, ap);
va_end(ap);
return rc;
}
WINPR_ATTR_FORMAT_ARG(3, 0)
int winpr_vasprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, va_list oap)
{
va_list ap = WINPR_C_ARRAY_INIT;
*s = nullptr;
*slen = 0;
va_copy(ap, oap);
const int length = vsnprintf(nullptr, 0, templ, ap);
va_end(ap);
if (length < 0)
return length;
char* str = calloc((size_t)length + 1UL, sizeof(char));
if (!str)
return -1;
va_copy(ap, oap);
const int plen = vsnprintf(str, (size_t)length + 1UL, templ, ap);
va_end(ap);
if (length != plen)
{
free(str);
return -1;
}
*s = str;
*slen = (size_t)length;
return length;
}
#ifndef _WIN32
char* _strdup(const char* strSource)
{
if (strSource == nullptr)
return nullptr;
char* strDestination = strdup(strSource);
if (strDestination == nullptr)
WLog_ERR(TAG, "strdup");
return strDestination;
}
WCHAR* _wcsdup(const WCHAR* strSource)
{
if (!strSource)
return nullptr;
size_t len = _wcslen(strSource);
WCHAR* strDestination = calloc(len + 1, sizeof(WCHAR));
if (strDestination != nullptr)
memcpy(strDestination, strSource, len * sizeof(WCHAR));
if (strDestination == nullptr)
WLog_ERR(TAG, "wcsdup");
return strDestination;
}
WCHAR* _wcsncat(WCHAR* dst, const WCHAR* src, size_t sz)
{
WINPR_ASSERT(dst);
WINPR_ASSERT(src || (sz == 0));
const size_t dlen = _wcslen(dst);
const size_t slen = _wcsnlen(src, sz);
for (size_t x = 0; x < slen; x++)
dst[dlen + x] = src[x];
dst[dlen + slen] = '\0';
return dst;
}
int _stricmp(const char* string1, const char* string2)
{
return strcasecmp(string1, string2);
}
int _strnicmp(const char* string1, const char* string2, size_t count)
{
return strncasecmp(string1, string2, count);
}
/* _wcscmp -> wcscmp */
int _wcscmp(const WCHAR* string1, const WCHAR* string2)
{
WINPR_ASSERT(string1);
WINPR_ASSERT(string2);
while (TRUE)
{
const WCHAR w1 = *string1++;
const WCHAR w2 = *string2++;
if (w1 != w2)
return (int)w1 - w2;
else if ((w1 == '\0') || (w2 == '\0'))
return (int)w1 - w2;
}
}
int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count)
{
WINPR_ASSERT(string1);
WINPR_ASSERT(string2);
for (size_t x = 0; x < count; x++)
{
const WCHAR a = string1[x];
const WCHAR b = string2[x];
if (a != b)
return (int)a - b;
else if ((a == '\0') || (b == '\0'))
return (int)a - b;
}
return 0;
}
/* _wcslen -> wcslen */
size_t _wcslen(const WCHAR* str)
{
const WCHAR* p = str;
WINPR_ASSERT(p);
while (*p)
p++;
return (size_t)(p - str);
}
/* _wcsnlen -> wcsnlen */
size_t _wcsnlen(const WCHAR* str, size_t max)
{
WINPR_ASSERT(str);
size_t x = 0;
for (; x < max; x++)
{
if (str[x] == 0)
return x;
}
return x;
}
/* _wcsstr -> wcsstr */
WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch)
{
WINPR_ASSERT(str);
WINPR_ASSERT(strSearch);
if (strSearch[0] == '\0')
return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
const size_t searchLen = _wcslen(strSearch);
while (*str)
{
if (_wcsncmp(str, strSearch, searchLen) == 0)
return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
str++;
}
return nullptr;
}
/* _wcschr -> wcschr */
WCHAR* _wcschr(const WCHAR* str, WCHAR c)
{
union
{
const WCHAR* cc;
WCHAR* c;
} cnv;
const WCHAR* p = str;
while (*p && (*p != c))
p++;
cnv.cc = (*p == c) ? p : nullptr;
return cnv.c;
}
/* _wcsrchr -> wcsrchr */
WCHAR* _wcsrchr(const WCHAR* str, WCHAR c)
{
union
{
const WCHAR* cc;
WCHAR* c;
} cnv;
const WCHAR* p = nullptr;
if (!str)
return nullptr;
for (; *str != '\0'; str++)
{
const WCHAR ch = *str;
if (ch == c)
p = str;
}
cnv.cc = p;
return cnv.c;
}
char* strtok_s(char* strToken, const char* strDelimit, char** context)
{
return strtok_r(strToken, strDelimit, context);
}
WCHAR* wcstok_s(WCHAR* strToken, const WCHAR* strDelimit, WCHAR** context)
{
WCHAR* nextToken = nullptr;
WCHAR value = 0;
if (!strToken)
strToken = *context;
value = *strToken;
while (*strToken && _wcschr(strDelimit, value))
{
strToken++;
value = *strToken;
}
if (!*strToken)
return nullptr;
nextToken = strToken++;
value = *strToken;
while (*strToken && !(_wcschr(strDelimit, value)))
{
strToken++;
value = *strToken;
}
if (*strToken)
*strToken++ = 0;
*context = strToken;
return nextToken;
}
#endif
#if !defined(_WIN32) || defined(_UWP)
/* Windows API Sets - api-ms-win-core-string-l2-1-0.dll
* http://msdn.microsoft.com/en-us/library/hh802935/
*/
#include "casing.h"
LPSTR CharUpperA(LPSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return nullptr;
length = strlen(lpsz);
if (length < 1)
return (LPSTR) nullptr;
if (length == 1)
{
char c = *lpsz;
if ((c >= 'a') && (c <= 'z'))
c = (char)(c - 'a' + 'A');
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
}
return lpsz;
}
LPWSTR CharUpperW(LPWSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return nullptr;
length = _wcslen(lpsz);
if (length < 1)
return (LPWSTR) nullptr;
if (length == 1)
{
WCHAR c = *lpsz;
if ((c >= L'a') && (c <= L'z'))
c = c - L'a' + L'A';
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= L'a') && (lpsz[i] <= L'z'))
lpsz[i] = lpsz[i] - L'a' + L'A';
}
return lpsz;
}
DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
{
if (cchLength < 1)
return 0;
for (DWORD i = 0; i < cchLength; i++)
{
if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
}
return cchLength;
}
DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
{
for (DWORD i = 0; i < cchLength; i++)
{
WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
value = WINPR_TOUPPERW(value);
winpr_Data_Write_UINT16(&lpsz[i], value);
}
return cchLength;
}
LPSTR CharLowerA(LPSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return (LPSTR) nullptr;
length = strlen(lpsz);
if (length < 1)
return (LPSTR) nullptr;
if (length == 1)
{
char c = *lpsz;
if ((c >= 'A') && (c <= 'Z'))
c = (char)(c - 'A' + 'a');
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
}
return lpsz;
}
LPWSTR CharLowerW(LPWSTR lpsz)
{
const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
if (len > UINT32_MAX)
return nullptr;
CharLowerBuffW(lpsz, (UINT32)len);
return lpsz;
}
DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
{
if (cchLength < 1)
return 0;
for (DWORD i = 0; i < cchLength; i++)
{
if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
}
return cchLength;
}
DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
{
for (DWORD i = 0; i < cchLength; i++)
{
WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
value = WINPR_TOLOWERW(value);
winpr_Data_Write_UINT16(&lpsz[i], value);
}
return cchLength;
}
BOOL IsCharAlphaA(CHAR ch)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
return 1;
else
return 0;
}
BOOL IsCharAlphaW(WCHAR ch)
{
if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')))
return 1;
else
return 0;
}
BOOL IsCharAlphaNumericA(CHAR ch)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')))
return 1;
else
return 0;
}
BOOL IsCharAlphaNumericW(WCHAR ch)
{
if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')) ||
((ch >= L'0') && (ch <= L'9')))
return 1;
else
return 0;
}
BOOL IsCharUpperA(CHAR ch)
{
if ((ch >= 'A') && (ch <= 'Z'))
return 1;
else
return 0;
}
BOOL IsCharUpperW(WCHAR ch)
{
if ((ch >= L'A') && (ch <= L'Z'))
return 1;
else
return 0;
}
BOOL IsCharLowerA(CHAR ch)
{
if ((ch >= 'a') && (ch <= 'z'))
return 1;
else
return 0;
}
BOOL IsCharLowerW(WCHAR ch)
{
if ((ch >= L'a') && (ch <= L'z'))
return 1;
else
return 0;
}
#endif
size_t ConvertLineEndingToLF(char* str, size_t size)
{
size_t skip = 0;
WINPR_ASSERT(str || (size == 0));
for (size_t x = 0; x < size; x++)
{
char c = str[x];
switch (c)
{
case '\r':
str[x - skip] = '\n';
if ((x + 1 < size) && (str[x + 1] == '\n'))
skip++;
break;
default:
str[x - skip] = c;
break;
}
}
return size - skip;
}
char* ConvertLineEndingToCRLF(const char* str, size_t* size)
{
WINPR_ASSERT(size);
const size_t s = *size;
WINPR_ASSERT(str || (s == 0));
*size = 0;
if (s == 0)
return nullptr;
size_t linebreaks = 0;
for (size_t x = 0; x < s - 1; x++)
{
char c = str[x];
switch (c)
{
case '\r':
case '\n':
linebreaks++;
break;
default:
break;
}
}
char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
if (!cnv)
return nullptr;
size_t pos = 0;
for (size_t x = 0; x < s; x++)
{
const char c = str[x];
switch (c)
{
case '\r':
cnv[pos++] = '\r';
cnv[pos++] = '\n';
break;
case '\n':
/* Do not duplicate existing \r\n sequences */
if ((x > 0) && (str[x - 1] != '\r'))
{
cnv[pos++] = '\r';
cnv[pos++] = '\n';
}
break;
default:
cnv[pos++] = c;
break;
}
}
*size = pos;
return cnv;
}
char* StrSep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p = nullptr;
p = (start != nullptr) ? strpbrk(start, delim) : nullptr;
if (!p)
*stringp = nullptr;
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
{
#if defined(_WIN32)
char c;
char* n;
size_t step = 32;
size_t used = 0;
if (!lineptr || !size)
{
errno = EINVAL;
return -1;
}
do
{
if (used + 2 >= *size)
{
*size += step;
n = realloc(*lineptr, *size);
if (!n)
{
return -1;
}
*lineptr = n;
}
c = fgetc(stream);
if (c != EOF)
(*lineptr)[used++] = c;
} while ((c != '\n') && (c != '\r') && (c != EOF));
(*lineptr)[used] = '\0';
return used;
#elif !defined(ANDROID) && !defined(IOS)
return getline(lineptr, size, stream);
#else
return -1;
#endif
}
#if !defined(WINPR_HAVE_STRNDUP)
char* strndup(const char* src, size_t n)
{
char* dst = calloc(n + 1, sizeof(char));
if (dst)
strncpy(dst, src, n);
return dst;
}
#endif
const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
{
WINPR_ASSERT(str);
WINPR_ASSERT(buffer || (len == 0));
(void)ConvertUtf8ToWChar(str, buffer, len);
return buffer;
}
WCHAR* wcsndup(const WCHAR* s, size_t n)
{
if (!s)
return nullptr;
WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
if (!copy)
return nullptr;
memcpy(copy, s, n * sizeof(WCHAR));
return copy;
}

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestCrt")
set(MODULE_PREFIX "TEST_CRT")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestTypes.c TestFormatSpecifiers.c TestAlignment.c TestString.c TestUnicodeConversion.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,87 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
int TestAlignment(int argc, char* argv[])
{
void* ptr = nullptr;
size_t alignment = 0;
size_t offset = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Alignment should be 2^N where N is a positive integer */
alignment = 16;
offset = 8;
/* _aligned_malloc */
ptr = winpr_aligned_malloc(100, alignment);
if (ptr == nullptr)
{
printf("Error allocating aligned memory.\n");
return -1;
}
if (((size_t)ptr % alignment) != 0)
{
printf("This pointer, %p, is not aligned on %" PRIuz "\n", ptr, alignment);
return -1;
}
/* _aligned_realloc */
ptr = winpr_aligned_realloc(ptr, 200, alignment);
if (((size_t)ptr % alignment) != 0)
{
printf("This pointer, %p, is not aligned on %" PRIuz "\n", ptr, alignment);
return -1;
}
winpr_aligned_free(ptr);
/* _aligned_offset_malloc */
ptr = winpr_aligned_offset_malloc(200, alignment, offset);
if (ptr == nullptr)
{
printf("Error reallocating aligned offset memory.");
return -1;
}
if (((((size_t)ptr) + offset) % alignment) != 0)
{
printf("This pointer, %p, does not satisfy offset %" PRIuz " and alignment %" PRIuz "\n",
ptr, offset, alignment);
return -1;
}
/* _aligned_offset_realloc */
ptr = winpr_aligned_offset_realloc(ptr, 200, alignment, offset);
if (ptr == nullptr)
{
printf("Error reallocating aligned offset memory.");
return -1;
}
if (((((size_t)ptr) + offset) % alignment) != 0)
{
printf("This pointer, %p, does not satisfy offset %" PRIuz " and alignment %" PRIuz "\n",
ptr, offset, alignment);
return -1;
}
/* _aligned_free works for both _aligned_malloc and _aligned_offset_malloc. free() should not be
* used. */
winpr_aligned_free(ptr);
return 0;
}

View File

@@ -0,0 +1,169 @@
#include <stdio.h>
#include <winpr/wtypes.h>
#include <winpr/string.h>
int TestFormatSpecifiers(int argc, char* argv[])
{
unsigned errors = 0;
char fmt[4096];
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* size_t */
{
size_t arg = 0xabcd;
const char* chk = "uz:43981 oz:125715 xz:abcd Xz:ABCD";
(void)sprintf_s(fmt, sizeof(fmt), "uz:%" PRIuz " oz:%" PRIoz " xz:%" PRIxz " Xz:%" PRIXz "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed size_t test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT8 */
{
INT8 arg = -16;
const char* chk = "d8:-16 x8:f0 X8:F0";
(void)sprintf_s(fmt, sizeof(fmt), "d8:%" PRId8 " x8:%" PRIx8 " X8:%" PRIX8 "", arg,
(UINT8)arg, (UINT8)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT8 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT8 */
{
UINT8 arg = 0xFE;
const char* chk = "u8:254 o8:376 x8:fe X8:FE";
(void)sprintf_s(fmt, sizeof(fmt), "u8:%" PRIu8 " o8:%" PRIo8 " x8:%" PRIx8 " X8:%" PRIX8 "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT8 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* INT16 */
{
INT16 arg = -16;
const char* chk = "d16:-16 x16:fff0 X16:FFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d16:%" PRId16 " x16:%" PRIx16 " X16:%" PRIX16 "", arg,
(UINT16)arg, (UINT16)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT16 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT16 */
{
UINT16 arg = 0xFFFE;
const char* chk = "u16:65534 o16:177776 x16:fffe X16:FFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u16:%" PRIu16 " o16:%" PRIo16 " x16:%" PRIx16 " X16:%" PRIX16 "", arg, arg,
arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT32 */
{
INT32 arg = -16;
const char* chk = "d32:-16 x32:fffffff0 X32:FFFFFFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d32:%" PRId32 " x32:%" PRIx32 " X32:%" PRIX32 "", arg,
(UINT32)arg, (UINT32)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT32 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT32 */
{
UINT32 arg = 0xFFFFFFFE;
const char* chk = "u32:4294967294 o32:37777777776 x32:fffffffe X32:FFFFFFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u32:%" PRIu32 " o32:%" PRIo32 " x32:%" PRIx32 " X32:%" PRIX32 "", arg, arg,
arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT64 */
{
INT64 arg = -16;
const char* chk = "d64:-16 x64:fffffffffffffff0 X64:FFFFFFFFFFFFFFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d64:%" PRId64 " x64:%" PRIx64 " X64:%" PRIX64 "", arg,
(UINT64)arg, (UINT64)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT64 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT64 */
{
UINT64 arg = 0xFFFFFFFFFFFFFFFE;
const char* chk = "u64:18446744073709551614 o64:1777777777777777777776 "
"x64:fffffffffffffffe X64:FFFFFFFFFFFFFFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u64:%" PRIu64 " o64:%" PRIo64 " x64:%016" PRIx64 " X64:%016" PRIX64 "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT64 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
if (errors)
{
(void)fprintf(stderr, "%s produced %u errors\n", __func__, errors);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,222 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/string.h>
#include <winpr/windows.h>
static const CHAR testStringA[] = { 'T', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b',
'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u',
'm', 'p', 's', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h',
'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g', '\0' };
#define testStringA_Length ((sizeof(testStringA) / sizeof(CHAR)) - 1)
static const CHAR testToken1A[] = { 'q', 'u', 'i', 'c', 'k', '\0' };
static const CHAR testToken2A[] = { 'b', 'r', 'o', 'w', 'n', '\0' };
static const CHAR testToken3A[] = { 'f', 'o', 'x', '\0' };
#define testToken1A_Length ((sizeof(testToken1A) / sizeof(CHAR)) - 1)
#define testToken2A_Length ((sizeof(testToken2A) / sizeof(CHAR)) - 1)
#define testToken3A_Length ((sizeof(testToken3A) / sizeof(CHAR)) - 1)
static const CHAR testTokensA[] = { 'q', 'u', 'i', 'c', 'k', '\r', '\n', 'b', 'r', 'o',
'w', 'n', '\r', '\n', 'f', 'o', 'x', '\r', '\n', '\0' };
#define testTokensA_Length ((sizeof(testTokensA) / sizeof(CHAR)) - 1)
static const CHAR testDelimiterA[] = { '\r', '\n', '\0' };
#define testDelimiterA_Length ((sizeof(testDelimiter) / sizeof(CHAR)) - 1)
struct url_test_pair
{
const char* what;
const char* escaped;
};
static const struct url_test_pair url_tests[] = {
{ "xxx%bar ga<ka>ee#%%#%{h}g{f{e%d|c\\b^a~p[q]r`s;t/u?v:w@x=y&z$xxx",
"xxx%25bar%20ga%3Cka%3Eee%23%25%25%23%25%7Bh%7Dg%7Bf%7Be%25d%7Cc%5Cb%5Ea~p%5Bq%5Dr%60s%3Bt%"
"2Fu%3Fv%3Aw%40x%3Dy%26z%24xxx" },
{ "äöúëü", "%C3%A4%C3%B6%C3%BA%C3%AB%C3%BC" },
{ "🎅🏄🤘😈", "%F0%9F%8E%85%F0%9F%8F%84%F0%9F%A4%98%F0%9F%98%88" },
{ "foo$.%.^.&.\\.txt+", "foo%24.%25.%5E.%26.%5C.txt%2B" }
};
static BOOL test_url_escape(void)
{
for (size_t x = 0; x < ARRAYSIZE(url_tests); x++)
{
const struct url_test_pair* cur = &url_tests[x];
char* escaped = winpr_str_url_encode(cur->what, strlen(cur->what) + 1);
char* what = winpr_str_url_decode(cur->escaped, strlen(cur->escaped) + 1);
const size_t elen = strlen(escaped);
const size_t wlen = strlen(what);
const size_t pelen = strlen(cur->escaped);
const size_t pwlen = strlen(cur->what);
BOOL rc = TRUE;
if (!escaped || (elen != pelen) || (strcmp(escaped, cur->escaped) != 0))
{
printf("expected: [%" PRIuz "] %s\n", pelen, cur->escaped);
printf("got : [%" PRIuz "] %s\n", elen, escaped);
rc = FALSE;
}
else if (!what || (wlen != pwlen) || (strcmp(what, cur->what) != 0))
{
printf("expected: [%" PRIuz "] %s\n", pwlen, cur->what);
printf("got : [%" PRIuz "] %s\n", wlen, what);
rc = FALSE;
}
free(escaped);
free(what);
if (!rc)
return FALSE;
}
return TRUE;
}
static BOOL test_winpr_asprintf(void)
{
BOOL rc = FALSE;
const char test[] = "test string case";
const size_t len = strnlen(test, sizeof(test));
char* str = nullptr;
size_t slen = 0;
const int res = winpr_asprintf(&str, &slen, "%s", test);
if (!str)
goto fail;
if (res < 0)
goto fail;
if ((size_t)res != len)
goto fail;
if (len != slen)
goto fail;
if (strnlen(str, slen + 10) != slen)
goto fail;
rc = TRUE;
fail:
free(str);
return rc;
}
int TestString(int argc, char* argv[])
{
const WCHAR* p = nullptr;
size_t pos = 0;
size_t length = 0;
WCHAR* context = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_winpr_asprintf())
return -1;
if (!test_url_escape())
return -1;
/* _wcslen */
WCHAR testStringW[ARRAYSIZE(testStringA)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testStringA, ARRAYSIZE(testStringA), testStringW,
ARRAYSIZE(testStringW));
const size_t testStringW_Length = testStringA_Length;
length = _wcslen(testStringW);
if (length != testStringW_Length)
{
printf("_wcslen error: length mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", length,
testStringW_Length);
return -1;
}
/* _wcschr */
union
{
char c[2];
WCHAR w;
} search;
search.c[0] = 'r';
search.c[1] = '\0';
p = _wcschr(testStringW, search.w);
pos = (p - testStringW);
if (pos != 11)
{
printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 11\n", pos);
return -1;
}
p = _wcschr(&testStringW[pos + 1], search.w);
pos = (p - testStringW);
if (pos != 29)
{
printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 29\n", pos);
return -1;
}
p = _wcschr(&testStringW[pos + 1], search.w);
if (p != nullptr)
{
printf("_wcschr error: return value mismatch: Actual: %p, Expected: nullptr\n",
(const void*)p);
return -1;
}
/* wcstok_s */
WCHAR testDelimiterW[ARRAYSIZE(testDelimiterA)] = WINPR_C_ARRAY_INIT;
WCHAR testTokensW[ARRAYSIZE(testTokensA)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testTokensA, ARRAYSIZE(testTokensA), testTokensW,
ARRAYSIZE(testTokensW));
(void)ConvertUtf8NToWChar(testDelimiterA, ARRAYSIZE(testDelimiterA), testDelimiterW,
ARRAYSIZE(testDelimiterW));
p = wcstok_s(testTokensW, testDelimiterW, &context);
WCHAR testToken1W[ARRAYSIZE(testToken1A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken1A, ARRAYSIZE(testToken1A), testToken1W,
ARRAYSIZE(testToken1W));
if (memcmp(p, testToken1W, sizeof(testToken1W)) != 0)
{
printf("wcstok_s error: token #1 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
WCHAR testToken2W[ARRAYSIZE(testToken2A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken2A, ARRAYSIZE(testToken2A), testToken2W,
ARRAYSIZE(testToken2W));
if (memcmp(p, testToken2W, sizeof(testToken2W)) != 0)
{
printf("wcstok_s error: token #2 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
WCHAR testToken3W[ARRAYSIZE(testToken3A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken3A, ARRAYSIZE(testToken3A), testToken3W,
ARRAYSIZE(testToken3W));
if (memcmp(p, testToken3W, sizeof(testToken3W)) != 0)
{
printf("wcstok_s error: token #3 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
if (p != nullptr)
{
printf("wcstok_s error: return value is not nullptr\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,115 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#define EXPECTED_SIZEOF_BYTE 1
#define EXPECTED_SIZEOF_BOOLEAN 1
#define EXPECTED_SIZEOF_CHAR 1
#define EXPECTED_SIZEOF_UCHAR 1
#define EXPECTED_SIZEOF_INT8 1
#define EXPECTED_SIZEOF_UINT8 1
#define EXPECTED_SIZEOF_INT16 2
#define EXPECTED_SIZEOF_UINT16 2
#define EXPECTED_SIZEOF_WORD 2
#define EXPECTED_SIZEOF_WCHAR 2
#define EXPECTED_SIZEOF_SHORT 2
#define EXPECTED_SIZEOF_USHORT 2
#define EXPECTED_SIZEOF_BOOL 4
#define EXPECTED_SIZEOF_INT 4
#define EXPECTED_SIZEOF_UINT 4
#define EXPECTED_SIZEOF_INT32 4
#define EXPECTED_SIZEOF_UINT32 4
#define EXPECTED_SIZEOF_DWORD 4
#define EXPECTED_SIZEOF_DWORD32 4
#define EXPECTED_SIZEOF_LONG 4
#define EXPECTED_SIZEOF_LONG32 4
#define EXPECTED_SIZEOF_INT64 8
#define EXPECTED_SIZEOF_UINT64 8
#define EXPECTED_SIZEOF_DWORD64 8
#define EXPECTED_SIZEOF_DWORDLONG 8
#define EXPECTED_SIZEOF_LONG64 8
#define EXPECTED_SIZEOF_ULONGLONG 8
#define EXPECTED_SIZEOF_LUID 8
#define EXPECTED_SIZEOF_FILETIME 8
#define EXPECTED_SIZEOF_LARGE_INTEGER 8
#define EXPECTED_SIZEOF_ULARGE_INTEGER 8
#define EXPECTED_SIZEOF_GUID 16
#define EXPECTED_SIZEOF_SYSTEMTIME 16
#define EXPECTED_SIZEOF_size_t sizeof(void*)
#define EXPECTED_SIZEOF_INT_PTR sizeof(void*)
#define EXPECTED_SIZEOF_UINT_PTR sizeof(void*)
#define EXPECTED_SIZEOF_DWORD_PTR sizeof(void*)
#define EXPECTED_SIZEOF_LONG_PTR sizeof(void*)
#define EXPECTED_SIZEOF_ULONG_PTR sizeof(void*)
#define TEST_SIZEOF_TYPE(_name) \
if (sizeof(_name) != EXPECTED_SIZEOF_##_name) \
{ \
(void)fprintf(stderr, "sizeof(%s) mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", \
#_name, sizeof(_name), (size_t)EXPECTED_SIZEOF_##_name); \
status = -1; \
}
int TestTypes(int argc, char* argv[])
{
int status = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
TEST_SIZEOF_TYPE(INT8)
TEST_SIZEOF_TYPE(UINT8)
TEST_SIZEOF_TYPE(BYTE)
TEST_SIZEOF_TYPE(BOOLEAN)
TEST_SIZEOF_TYPE(CHAR)
TEST_SIZEOF_TYPE(UCHAR)
TEST_SIZEOF_TYPE(INT16)
TEST_SIZEOF_TYPE(UINT16)
TEST_SIZEOF_TYPE(WORD)
TEST_SIZEOF_TYPE(WCHAR)
TEST_SIZEOF_TYPE(SHORT)
TEST_SIZEOF_TYPE(USHORT)
/* fails on OS X */
// TEST_SIZEOF_TYPE(BOOL)
TEST_SIZEOF_TYPE(INT)
TEST_SIZEOF_TYPE(UINT)
TEST_SIZEOF_TYPE(DWORD)
TEST_SIZEOF_TYPE(DWORD32)
TEST_SIZEOF_TYPE(LONG)
TEST_SIZEOF_TYPE(LONG32)
TEST_SIZEOF_TYPE(INT32)
TEST_SIZEOF_TYPE(UINT32)
TEST_SIZEOF_TYPE(INT64)
TEST_SIZEOF_TYPE(UINT64)
TEST_SIZEOF_TYPE(DWORD64)
TEST_SIZEOF_TYPE(DWORDLONG)
TEST_SIZEOF_TYPE(LONG64)
TEST_SIZEOF_TYPE(ULONGLONG)
TEST_SIZEOF_TYPE(LUID)
TEST_SIZEOF_TYPE(FILETIME)
TEST_SIZEOF_TYPE(LARGE_INTEGER)
TEST_SIZEOF_TYPE(ULARGE_INTEGER)
TEST_SIZEOF_TYPE(GUID)
TEST_SIZEOF_TYPE(SYSTEMTIME)
TEST_SIZEOF_TYPE(size_t)
TEST_SIZEOF_TYPE(INT_PTR)
TEST_SIZEOF_TYPE(UINT_PTR)
TEST_SIZEOF_TYPE(DWORD_PTR)
TEST_SIZEOF_TYPE(LONG_PTR)
TEST_SIZEOF_TYPE(ULONG_PTR)
return status;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,652 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <wctype.h>
#include <winpr/crt.h>
#include <winpr/error.h>
#include <winpr/print.h>
#ifndef _WIN32
#include "unicode.h"
/**
* Notes on cross-platform Unicode portability:
*
* Unicode has many possible Unicode Transformation Format (UTF) encodings,
* where some of the most commonly used are UTF-8, UTF-16 and sometimes UTF-32.
*
* The number in the UTF encoding name (8, 16, 32) refers to the number of bits
* per code unit. A code unit is the minimal bit combination that can represent
* a unit of encoded text in the given encoding. For instance, UTF-8 encodes
* the English alphabet using 8 bits (or one byte) each, just like in ASCII.
*
* However, the total number of code points (values in the Unicode codespace)
* only fits completely within 32 bits. This means that for UTF-8 and UTF-16,
* more than one code unit may be required to fully encode a specific value.
* UTF-8 and UTF-16 are variable-width encodings, while UTF-32 is fixed-width.
*
* UTF-8 has the advantage of being backwards compatible with ASCII, and is
* one of the most commonly used Unicode encoding.
*
* UTF-16 is used everywhere in the Windows API. The strategy employed by
* Microsoft to provide backwards compatibility in their API was to create
* an ANSI and a Unicode version of the same function, ending with A (ANSI)
* and W (Wide character, or UTF-16 Unicode). In headers, the original
* function name is replaced by a macro that defines to either the ANSI
* or Unicode version based on the definition of the _UNICODE macro.
*
* UTF-32 has the advantage of being fixed width, but wastes a lot of space
* for English text (4x more than UTF-8, 2x more than UTF-16).
*
* In C, wide character strings are often defined with the wchar_t type.
* Many functions are provided to deal with those wide character strings,
* such as wcslen (strlen equivalent) or wprintf (printf equivalent).
*
* This may lead to some confusion, since many of these functions exist
* on both Windows and Linux, but they are *not* the same!
*
* This sample hello world is a good example:
*
* #include <wchar.h>
*
* wchar_t hello[] = L"Hello, World!\n";
*
* int main(int argc, char** argv)
* {
* wprintf(hello);
* wprintf(L"sizeof(wchar_t): %d\n", sizeof(wchar_t));
* return 0;
* }
*
* There is a reason why the sample prints the size of the wchar_t type:
* On Windows, wchar_t is two bytes (UTF-16), while on most other systems
* it is 4 bytes (UTF-32). This means that if you write code on Windows,
* use L"" to define a string which is meant to be UTF-16 and not UTF-32,
* you will have a little surprise when trying to port your code to Linux.
*
* Since the Windows API uses UTF-16, not UTF-32, WinPR defines the WCHAR
* type to always be 2-bytes long and uses it instead of wchar_t. Do not
* ever use wchar_t with WinPR unless you know what you are doing.
*
* As for L"", it is unfortunately unusable in a portable way, unless a
* special option is passed to GCC to define wchar_t as being two bytes.
* For string constants that must be UTF-16, it is a pain, but they can
* be defined in a portable way like this:
*
* WCHAR hello[] = { 'H','e','l','l','o','\0' };
*
* Such strings cannot be passed to native functions like wcslen(), which
* may expect a different wchar_t size. For this reason, WinPR provides
* _wcslen, which expects UTF-16 WCHAR strings on all platforms.
*
*/
/** \deprecated We no longer export this function, see ConvertUtf8ToWChar family of functions for a
* replacement
*
* Conversion to Unicode (UTF-16)
* MultiByteToWideChar: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072/
*
* cbMultiByte is an input size in bytes (BYTE)
* cchWideChar is an output size in wide characters (WCHAR)
*
* Null-terminated UTF-8 strings:
*
* cchWideChar *cannot* be assumed to be cbMultiByte since UTF-8 is variable-width!
*
* Instead, obtain the required cchWideChar output size like this:
* cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, nullptr, 0);
*
* A value of -1 for cbMultiByte indicates that the input string is null-terminated,
* and the null terminator *will* be processed. The size returned by MultiByteToWideChar
* will therefore include the null terminator. Equivalent behavior can be obtained by
* computing the length in bytes of the input buffer, including the null terminator:
*
* cbMultiByte = strlen((char*) lpMultiByteStr) + 1;
*
* An output buffer of the proper size can then be allocated:
*
* lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
*
* Since cchWideChar is an output size in wide characters, the actual buffer size is:
* (cchWideChar * sizeof(WCHAR)) or (cchWideChar * 2)
*
* Finally, perform the conversion:
*
* cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, lpWideCharStr,
* cchWideChar);
*
* The value returned by MultiByteToWideChar corresponds to the number of wide characters written
* to the output buffer, and should match the value obtained on the first call to
* MultiByteToWideChar.
*
*/
#if !defined(WITH_WINPR_DEPRECATED)
static
#endif
int
MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
return int_MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr,
cchWideChar);
}
/** \deprecated We no longer export this function, see ConvertWCharToUtf8 family of functions for a
* replacement
*
* Conversion from Unicode (UTF-16)
* WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
*
* cchWideChar is an input size in wide characters (WCHAR)
* cbMultiByte is an output size in bytes (BYTE)
*
* Null-terminated UTF-16 strings:
*
* cbMultiByte *cannot* be assumed to be cchWideChar since UTF-8 is variable-width!
*
* Instead, obtain the required cbMultiByte output size like this:
* cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, nullptr, 0, nullptr,
* nullptr);
*
* A value of -1 for cbMultiByte indicates that the input string is null-terminated,
* and the null terminator *will* be processed. The size returned by WideCharToMultiByte
* will therefore include the null terminator. Equivalent behavior can be obtained by
* computing the length in bytes of the input buffer, including the null terminator:
*
* cchWideChar = _wcslen((WCHAR*) lpWideCharStr) + 1;
*
* An output buffer of the proper size can then be allocated:
* lpMultiByteStr = (LPSTR) malloc(cbMultiByte);
*
* Since cbMultiByte is an output size in bytes, it is the same as the buffer size
*
* Finally, perform the conversion:
*
* cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, lpMultiByteStr,
* cbMultiByte, nullptr, nullptr);
*
* The value returned by WideCharToMultiByte corresponds to the number of bytes written
* to the output buffer, and should match the value obtained on the first call to
* WideCharToMultiByte.
*
*/
#if !defined(WITH_WINPR_DEPRECATED)
static
#endif
int
WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
return int_WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr,
cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
}
#endif
/**
* ConvertToUnicode is a convenience wrapper for MultiByteToWideChar:
*
* If the lpWideCharStr parameter for the converted string points to nullptr
* 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.
*/
#if defined(WITH_WINPR_DEPRECATED)
int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR* lpWideCharStr, int cchWideChar)
{
int status = 0;
BOOL allocate = FALSE;
if (!lpMultiByteStr)
return 0;
if (!lpWideCharStr)
return 0;
if (cbMultiByte == -1)
{
size_t len = strnlen(lpMultiByteStr, INT_MAX);
if (len >= INT_MAX)
return 0;
cbMultiByte = (int)(len + 1);
}
if (cchWideChar == 0)
{
cchWideChar =
MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, nullptr, 0);
allocate = TRUE;
}
else if (!(*lpWideCharStr))
allocate = TRUE;
if (cchWideChar < 1)
return 0;
if (allocate)
{
*lpWideCharStr = (LPWSTR)calloc((size_t)cchWideChar + 1ull, sizeof(WCHAR));
if (!(*lpWideCharStr))
{
// SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
}
status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr,
cchWideChar);
if (status != cchWideChar)
{
if (allocate)
{
free(*lpWideCharStr);
*lpWideCharStr = nullptr;
status = 0;
}
}
return status;
}
#endif
/**
* ConvertFromUnicode is a convenience wrapper for WideCharToMultiByte:
*
* If the lpMultiByteStr parameter for the converted string points to nullptr
* 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.
*/
#if defined(WITH_WINPR_DEPRECATED)
int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
int status = 0;
BOOL allocate = FALSE;
if (!lpWideCharStr)
return 0;
if (!lpMultiByteStr)
return 0;
if (cchWideChar == -1)
cchWideChar = (int)(_wcslen(lpWideCharStr) + 1);
if (cbMultiByte == 0)
{
cbMultiByte = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, nullptr, 0,
nullptr, nullptr);
allocate = TRUE;
}
else if (!(*lpMultiByteStr))
allocate = TRUE;
if (cbMultiByte < 1)
return 0;
if (allocate)
{
*lpMultiByteStr = (LPSTR)calloc(1, (size_t)cbMultiByte + 1ull);
if (!(*lpMultiByteStr))
{
// SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
}
status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, *lpMultiByteStr,
cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
if ((status != cbMultiByte) && allocate)
{
status = 0;
}
if ((status <= 0) && allocate)
{
free(*lpMultiByteStr);
*lpMultiByteStr = nullptr;
}
return status;
}
#endif
/**
* Swap Unicode byte order (UTF16LE <-> UTF16BE)
*/
const WCHAR* ByteSwapUnicode(WCHAR* wstr, size_t length)
{
WINPR_ASSERT(wstr || (length == 0));
for (size_t x = 0; x < length; x++)
wstr[x] = _byteswap_ushort(wstr[x]);
return wstr;
}
SSIZE_T ConvertWCharToUtf8(const WCHAR* wstr, char* str, size_t len)
{
if (!wstr)
{
if (str && len)
str[0] = 0;
return 0;
}
const size_t wlen = _wcslen(wstr);
return ConvertWCharNToUtf8(wstr, wlen + 1, str, len);
}
SSIZE_T ConvertWCharNToUtf8(const WCHAR* wstr, size_t wlen, char* str, size_t len)
{
BOOL isNullTerminated = FALSE;
if (wlen == 0)
return 0;
WINPR_ASSERT(wstr);
size_t iwlen = _wcsnlen(wstr, wlen);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
if (iwlen < wlen)
{
isNullTerminated = TRUE;
iwlen++;
}
const int rc =
WideCharToMultiByte(CP_UTF8, 0, wstr, (int)iwlen, str, (int)len, nullptr, nullptr);
if ((rc <= 0) || ((len > 0) && ((size_t)rc > len)))
return -1;
else if (!isNullTerminated)
{
if (str && ((size_t)rc < len))
str[rc] = '\0';
return rc;
}
else if ((size_t)rc == len)
{
if (str && (str[rc - 1] != '\0'))
return rc;
}
return rc - 1;
}
SSIZE_T ConvertMszWCharNToUtf8(const WCHAR* wstr, size_t wlen, char* str, size_t len)
{
if (wlen == 0)
return 0;
WINPR_ASSERT(wstr);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
const int iwlen = (int)len;
const int rc = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wlen, str, iwlen, nullptr, nullptr);
if ((rc <= 0) || ((len > 0) && (rc > iwlen)))
return -1;
return rc;
}
SSIZE_T ConvertUtf8ToWChar(const char* str, WCHAR* wstr, size_t wlen)
{
if (!str)
{
if (wstr && wlen)
wstr[0] = 0;
return 0;
}
const size_t len = strlen(str);
return ConvertUtf8NToWChar(str, len + 1, wstr, wlen);
}
SSIZE_T ConvertUtf8NToWChar(const char* str, size_t len, WCHAR* wstr, size_t wlen)
{
size_t ilen = strnlen(str, len);
BOOL isNullTerminated = FALSE;
if (len == 0)
return 0;
WINPR_ASSERT(str);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
if (ilen < len)
{
isNullTerminated = TRUE;
ilen++;
}
const int iwlen = (int)wlen;
const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (int)ilen, wstr, iwlen);
if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
return -1;
if (!isNullTerminated)
{
if (wstr && (rc < iwlen))
wstr[rc] = '\0';
return rc;
}
else if (rc == iwlen)
{
if (wstr && (wstr[rc - 1] != '\0'))
return rc;
}
return rc - 1;
}
SSIZE_T ConvertMszUtf8NToWChar(const char* str, size_t len, WCHAR* wstr, size_t wlen)
{
if (len == 0)
return 0;
WINPR_ASSERT(str);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
const int iwlen = (int)wlen;
const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, iwlen);
if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
return -1;
return rc;
}
char* ConvertWCharToUtf8Alloc(const WCHAR* wstr, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertWCharToUtf8(wstr, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertWCharToUtf8(wstr, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
char* ConvertWCharNToUtf8Alloc(const WCHAR* wstr, size_t wlen, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertWCharNToUtf8(wstr, wlen, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertWCharNToUtf8(wstr, wlen, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
char* ConvertMszWCharNToUtf8Alloc(const WCHAR* wstr, size_t wlen, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertMszWCharNToUtf8(wstr, wlen, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertMszWCharNToUtf8(wstr, wlen, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
WCHAR* ConvertUtf8ToWCharAlloc(const char* str, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertUtf8ToWChar(str, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertUtf8ToWChar(str, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}
WCHAR* ConvertUtf8NToWCharAlloc(const char* str, size_t len, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertUtf8NToWChar(str, len, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertUtf8NToWChar(str, len, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}
WCHAR* ConvertMszUtf8NToWCharAlloc(const char* str, size_t len, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertMszUtf8NToWChar(str, len, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertMszUtf8NToWChar(str, len, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}

View File

@@ -0,0 +1,32 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_CRT_UNICODE_INTERNAL
#define WINPR_CRT_UNICODE_INTERNAL
#include <winpr/wtypes.h>
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar);
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar);
#endif

View File

@@ -0,0 +1,184 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <winpr/string.h>
#include "../utils/android.h"
#include "unicode.h"
#ifndef MIN
#define MIN(a, b) (a) < (b) ? (a) : (b)
#endif
#include "../log.h"
#define TAG WINPR_TAG("unicode")
static int convert_int(JNIEnv* env, const void* data, size_t size, void* buffer, size_t buffersize,
BOOL toUTF16)
{
WINPR_ASSERT(env);
WINPR_ASSERT(data || (size == 0));
WINPR_ASSERT(buffer || (buffersize == 0));
jstring utf8 = (*env)->NewStringUTF(env, "UTF-8");
jstring utf16 = (*env)->NewStringUTF(env, "UTF-16LE");
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
if (!utf8 || !utf16 || !stringClass)
{
WLog_ERR(TAG, "utf8-%p, utf16=%p, stringClass=%p", utf8, utf16, stringClass);
return -1;
}
jmethodID constructorID =
(*env)->GetMethodID(env, stringClass, "<init>", "([BLjava/lang/String;)V");
jmethodID getBytesID =
(*env)->GetMethodID(env, stringClass, "getBytes", "(Ljava/lang/String;)[B");
if (!constructorID || !getBytesID)
{
WLog_ERR(TAG, "constructorID=%p, getBytesID=%p", constructorID, getBytesID);
return -2;
}
jbyteArray ret = (*env)->NewByteArray(env, size);
if (!ret)
{
WLog_ERR(TAG, "NewByteArray(%" PRIuz ") failed", size);
return -3;
}
(*env)->SetByteArrayRegion(env, ret, 0, size, data);
jobject obj = (*env)->NewObject(env, stringClass, constructorID, ret, toUTF16 ? utf8 : utf16);
if (!obj)
{
WLog_ERR(TAG, "NewObject(String, byteArray, UTF-%d) failed", toUTF16 ? 16 : 8);
return -4;
}
jbyteArray res = (*env)->CallObjectMethod(env, obj, getBytesID, toUTF16 ? utf16 : utf8);
if (!res)
{
WLog_ERR(TAG, "CallObjectMethod(String, getBytes, UTF-%d) failed", toUTF16 ? 16 : 8);
return -4;
}
jsize rlen = (*env)->GetArrayLength(env, res);
if (buffersize > 0)
{
if (rlen > buffersize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
rlen = MIN(rlen, buffersize);
(*env)->GetByteArrayRegion(env, res, 0, rlen, buffer);
}
if (toUTF16)
rlen /= sizeof(WCHAR);
return rlen;
}
static int convert(const void* data, size_t size, void* buffer, size_t buffersize, BOOL toUTF16)
{
int rc;
JNIEnv* env = nullptr;
jboolean attached = winpr_jni_attach_thread(&env);
rc = convert_int(env, data, size, buffer, buffersize, toUTF16);
if (attached)
winpr_jni_detach_thread();
return rc;
}
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
size_t cbCharLen = (size_t)cbMultiByte;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
return 0;
if (cchWideChar < 0)
return -1;
if (cbMultiByte < 0)
{
const size_t len = strlen(lpMultiByteStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cbMultiByte;
WINPR_ASSERT(lpMultiByteStr);
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
return 0;
}
return convert(lpMultiByteStr, cbCharLen, lpWideCharStr, cchWideChar * sizeof(WCHAR), TRUE);
}
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
size_t cbCharLen = (size_t)cchWideChar;
WINPR_UNUSED(dwFlags);
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
return 0;
if (cbMultiByte < 0)
return -1;
WINPR_ASSERT(lpWideCharStr);
/* If cchWideChar is -1, the string is null-terminated */
if (cchWideChar == -1)
{
const size_t len = _wcslen(lpWideCharStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cchWideChar;
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
return convert(lpWideCharStr, cbCharLen * sizeof(WCHAR), lpMultiByteStr, cbMultiByte, FALSE);
}

View File

@@ -0,0 +1,149 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <wctype.h>
#include <winpr/crt.h>
#include <winpr/error.h>
#include <winpr/print.h>
#include "unicode.h"
#ifndef MIN
#define MIN(a, b) (a) < (b) ? (a) : (b)
#endif
#include "../log.h"
#define TAG WINPR_TAG("unicode")
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
const BOOL isNullTerminated = cbMultiByte < 0;
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
return 0;
/* If cbMultiByte is -1, the string is null-terminated */
if (isNullTerminated)
{
size_t len = strnlen(lpMultiByteStr, INT32_MAX);
if (len >= INT32_MAX)
return 0;
cbMultiByte = (int)len + 1;
}
NSString *utf = [[NSString alloc] initWithBytes:lpMultiByteStr
length:cbMultiByte
encoding:NSUTF8StringEncoding];
if (!utf)
{
WLog_WARN(TAG, "[NSString alloc] NSUTF8StringEncoding failed [%d] '%s'", cbMultiByte,
lpMultiByteStr);
return -1;
}
const WCHAR *utf16 =
(const WCHAR *)[utf cStringUsingEncoding:NSUTF16LittleEndianStringEncoding];
const size_t utf16ByteLen = [utf lengthOfBytesUsingEncoding:NSUTF16LittleEndianStringEncoding];
const size_t utf16CharLen = utf16ByteLen / sizeof(WCHAR);
if (!utf16)
{
WLog_WARN(TAG, "[utf cStringUsingEncoding:NSUTF16LittleEndianStringEncoding] failed");
return -1;
}
if (cchWideChar == 0)
return utf16CharLen;
else if (cchWideChar < utf16CharLen)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
else
{
const size_t mlen = MIN((size_t)utf16CharLen, cchWideChar);
const size_t len = _wcsnlen(utf16, mlen);
memcpy(lpWideCharStr, utf16, len * sizeof(WCHAR));
if ((len < (size_t)cchWideChar) &&
((len == 0) || ((len > 0) && (lpWideCharStr[len - 1] != '\0'))))
lpWideCharStr[len] = '\0';
return utf16CharLen;
}
}
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
const BOOL isNullTerminated = cchWideChar < 0;
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
return 0;
/* If cchWideChar is -1, the string is null-terminated */
if (isNullTerminated)
{
size_t len = _wcslen(lpWideCharStr);
if (len >= INT32_MAX)
return 0;
cchWideChar = (int)len + 1;
}
NSString *utf = [[NSString alloc] initWithCharacters:lpWideCharStr length:cchWideChar];
if (!utf)
{
WLog_WARN(TAG, "[NSString alloc] initWithCharacters failed [%d] 'XXX'", cchWideChar);
return -1;
}
const char *utf8 = [utf cStringUsingEncoding:NSUTF8StringEncoding];
const size_t utf8Len = [utf lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if (!utf8)
{
WLog_WARN(TAG, "[utf cStringUsingEncoding:NSUTF8StringEncoding] failed");
return -1;
}
if (cbMultiByte == 0)
return utf8Len;
else if (cbMultiByte < utf8Len)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
else
{
const size_t mlen = MIN((size_t)cbMultiByte, utf8Len);
const size_t len = strnlen(utf8, mlen);
memcpy(lpMultiByteStr, utf8, len * sizeof(char));
if ((len < (size_t)cbMultiByte) && (len > 0) && (lpMultiByteStr[len - 1] != '\0'))
lpMultiByteStr[len] = '\0';
return utf8Len;
}
}

View File

@@ -0,0 +1,729 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "utf.h" for complete documentation.
------------------------------------------------------------------------ */
#include <winpr/wtypes.h>
#include <winpr/string.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include "unicode.h"
#include "../log.h"
#define TAG WINPR_TAG("unicode")
/*
* Character Types:
*
* UTF8: uint8_t 8 bits
* UTF16: uint16_t 16 bits
* UTF32: uint32_t 32 bits
*/
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (uint32_t)0x0000FFFD
#define UNI_MAX_BMP (uint32_t)0x0000FFFF
#define UNI_MAX_UTF16 (uint32_t)0x0010FFFF
#define UNI_MAX_UTF32 (uint32_t)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (uint32_t)0x0010FFFF
typedef enum
{
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum
{
strictConversion = 0,
lenientConversion
} ConversionFlags;
static const int halfShift = 10; /* used for shifting by 10 bits */
static const uint32_t halfBase = 0x0010000UL;
static const uint32_t halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (uint32_t)0xD800
#define UNI_SUR_HIGH_END (uint32_t)0xDBFF
#define UNI_SUR_LOW_START (uint32_t)0xDC00
#define UNI_SUR_LOW_END (uint32_t)0xDFFF
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const uint32_t offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequence
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* We always need UTF-16LE, even on big endian systems! */
static WCHAR setWcharFrom(WCHAR w)
{
#if defined(__BIG_ENDIAN__)
union
{
WCHAR w;
char c[2];
} cnv;
cnv.w = w;
const char c = cnv.c[0];
cnv.c[0] = cnv.c[1];
cnv.c[1] = c;
return cnv.w;
#else
return w;
#endif
}
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
static ConversionResult winpr_ConvertUTF16toUTF8_Internal(const uint16_t** sourceStart,
const uint16_t* sourceEnd,
uint8_t** targetStart,
const uint8_t* targetEnd,
ConversionFlags flags)
{
bool computeLength = (!targetEnd) ? true : false;
const uint16_t* source = *sourceStart;
uint8_t* target = *targetStart;
ConversionResult result = conversionOK;
while (source < sourceEnd)
{
uint32_t ch = 0;
unsigned short bytesToWrite = 0;
const uint32_t byteMask = 0xBF;
const uint32_t byteMark = 0x80;
const uint16_t* oldSource =
source; /* In case we have to back up because of target overflow. */
ch = setWcharFrom(*source++);
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
{
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd)
{
uint32_t ch2 = setWcharFrom(*source);
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
{
ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) +
halfBase;
++source;
}
else if (flags == strictConversion)
{
/* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
else
{
/* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
}
else if (flags == strictConversion)
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (uint32_t)0x80)
{
bytesToWrite = 1;
}
else if (ch < (uint32_t)0x800)
{
bytesToWrite = 2;
}
else if (ch < (uint32_t)0x10000)
{
bytesToWrite = 3;
}
else if (ch < (uint32_t)0x110000)
{
bytesToWrite = 4;
}
else
{
bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if ((target > targetEnd) && (!computeLength))
{
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite;
result = targetExhausted;
break;
}
if (!computeLength)
{
switch (bytesToWrite)
{
/* note: everything falls through. */
case 4:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
*--target = (uint8_t)(ch | firstByteMark[bytesToWrite]);
break;
default:
return sourceIllegal;
}
}
else
{
switch (bytesToWrite)
{
/* note: everything falls through. */
case 4:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
--target;
break;
default:
return sourceIllegal;
}
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static bool isLegalUTF8(const uint8_t* source, int length)
{
uint8_t a = 0;
const uint8_t* srcptr = source + length;
switch (length)
{
default:
return false;
/* Everything else falls through when "true"... */
case 4:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return false;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return false;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
if ((a = (*--srcptr)) > 0xBF)
return false;
switch (*source)
{
/* no fall-through in this inner switch */
case 0xE0:
if (a < 0xA0)
return false;
break;
case 0xED:
if (a > 0x9F)
return false;
break;
case 0xF0:
if (a < 0x90)
return false;
break;
case 0xF4:
if (a > 0x8F)
return false;
break;
default:
if (a < 0x80)
return false;
break;
}
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
if (*source >= 0x80 && *source < 0xC2)
return false;
}
if (*source > 0xF4)
return false;
return true;
}
/* --------------------------------------------------------------------- */
static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** sourceStart,
const uint8_t* sourceEnd,
uint16_t** targetStart,
const uint16_t* targetEnd,
ConversionFlags flags)
{
bool computeLength = (!targetEnd) ? true : false;
ConversionResult result = conversionOK;
const uint8_t* source = *sourceStart;
uint16_t* target = *targetStart;
while (source < sourceEnd)
{
uint32_t ch = 0;
unsigned short extraBytesToRead =
WINPR_ASSERTING_INT_CAST(unsigned short, trailingBytesForUTF8[*source]);
if ((source + extraBytesToRead) >= sourceEnd)
{
result = sourceExhausted;
break;
}
/* Do this check whether lenient or strict */
if (!isLegalUTF8(source, extraBytesToRead + 1))
{
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead)
{
case 5:
ch += *source++;
ch <<= 6; /* remember, illegal UTF-8 */
/* fallthrough */
WINPR_FALLTHROUGH
case 4:
ch += *source++;
ch <<= 6; /* remember, illegal UTF-8 */
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 0:
ch += *source++;
break;
default:
return sourceIllegal;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if ((target >= targetEnd) && (!computeLength))
{
source -= (extraBytesToRead + 1); /* Back up source pointer! */
result = targetExhausted;
break;
}
if (ch <= UNI_MAX_BMP)
{
/* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
if (flags == strictConversion)
{
source -= (extraBytesToRead + 1); /* return to the illegal value itself */
result = sourceIllegal;
break;
}
else
{
if (!computeLength)
*target++ = setWcharFrom(UNI_REPLACEMENT_CHAR);
else
target++;
}
}
else
{
if (!computeLength)
*target++ = setWcharFrom((WCHAR)ch); /* normal case */
else
target++;
}
}
else if (ch > UNI_MAX_UTF16)
{
if (flags == strictConversion)
{
result = sourceIllegal;
source -= (extraBytesToRead + 1); /* return to the start */
break; /* Bail out; shouldn't continue */
}
else
{
if (!computeLength)
*target++ = setWcharFrom(UNI_REPLACEMENT_CHAR);
else
target++;
}
}
else
{
/* target is a character in range 0xFFFF - 0x10FFFF. */
if ((target + 1 >= targetEnd) && (!computeLength))
{
source -= (extraBytesToRead + 1); /* Back up source pointer! */
result = targetExhausted;
break;
}
ch -= halfBase;
if (!computeLength)
{
*target++ = setWcharFrom((WCHAR)((ch >> halfShift) + UNI_SUR_HIGH_START));
*target++ = setWcharFrom((WCHAR)((ch & halfMask) + UNI_SUR_LOW_START));
}
else
{
target++;
target++;
}
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/**
* WinPR built-in Unicode API
*/
static int winpr_ConvertUTF8toUTF16(const uint8_t* src, int cchSrc, uint16_t* dst, int cchDst)
{
size_t length = 0;
uint16_t* dstBeg = nullptr;
uint16_t* dstEnd = nullptr;
const uint8_t* srcBeg = nullptr;
const uint8_t* srcEnd = nullptr;
ConversionResult result = sourceIllegal;
if (cchSrc == -1)
cchSrc = (int)strnlen((const char*)src, INT32_MAX - 1) + 1;
srcBeg = src;
srcEnd = &src[cchSrc];
if (cchDst == 0)
{
result =
winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - (uint16_t*)nullptr;
}
else
{
dstBeg = dst;
dstEnd = &dst[cchDst];
result =
winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - dst;
}
if (result == targetExhausted)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
}
static int winpr_ConvertUTF16toUTF8(const uint16_t* src, int cchSrc, uint8_t* dst, int cchDst)
{
size_t length = 0;
uint8_t* dstBeg = nullptr;
uint8_t* dstEnd = nullptr;
const uint16_t* srcBeg = nullptr;
const uint16_t* srcEnd = nullptr;
ConversionResult result = sourceIllegal;
if (cchSrc == -1)
cchSrc = (int)_wcsnlen((const WCHAR*)src, INT32_MAX - 1) + 1;
srcBeg = src;
srcEnd = &src[cchSrc];
if (cchDst == 0)
{
result =
winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - ((uint8_t*)nullptr);
}
else
{
dstBeg = dst;
dstEnd = &dst[cchDst];
result =
winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - dst;
}
if (result == targetExhausted)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
}
/* --------------------------------------------------------------------- */
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
size_t cbCharLen = (size_t)cbMultiByte;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
return 0;
if (cchWideChar < 0)
return -1;
if (cbMultiByte < 0)
{
const size_t len = strlen(lpMultiByteStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cbMultiByte;
WINPR_ASSERT(lpMultiByteStr);
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
return 0;
}
return winpr_ConvertUTF8toUTF16((const uint8_t*)lpMultiByteStr,
WINPR_ASSERTING_INT_CAST(int, cbCharLen),
(uint16_t*)lpWideCharStr, cchWideChar);
}
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
size_t cbCharLen = (size_t)cchWideChar;
WINPR_UNUSED(dwFlags);
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
return 0;
if (cbMultiByte < 0)
return -1;
WINPR_ASSERT(lpWideCharStr);
/* If cchWideChar is -1, the string is null-terminated */
if (cchWideChar == -1)
{
const size_t len = _wcslen(lpWideCharStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cchWideChar;
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
return winpr_ConvertUTF16toUTF8((const uint16_t*)lpWideCharStr,
WINPR_ASSERTING_INT_CAST(int, cbCharLen),
(uint8_t*)lpMultiByteStr, cbMultiByte);
}

View File

@@ -0,0 +1,234 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <wctype.h>
#include <winpr/crt.h>
#include <winpr/error.h>
#include <winpr/print.h>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
#include "unicode.h"
#include "../log.h"
#define TAG WINPR_TAG("unicode")
#define UCNV_CONVERT 1
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
const BOOL isNullTerminated = cbMultiByte < 0;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
size_t len = 0;
if (isNullTerminated)
len = strlen(lpMultiByteStr) + 1;
else
len = WINPR_ASSERTING_INT_CAST(size_t, cbMultiByte);
if (len >= INT_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
cbMultiByte = WINPR_ASSERTING_INT_CAST(int, len);
/*
* if cchWideChar is 0, the function returns the required buffer size
* in characters for lpWideCharStr and makes no use of the output parameter itself.
*/
{
UErrorCode error = U_ZERO_ERROR;
int32_t targetLength = -1;
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
const int32_t targetCapacity = cchWideChar;
#if defined(UCNV_CONVERT)
char* targetStart = (char*)lpWideCharStr;
targetLength =
ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * (int32_t)sizeof(WCHAR),
lpMultiByteStr, cbMultiByte, &error);
if (targetLength > 0)
targetLength /= sizeof(WCHAR);
#else
WCHAR* targetStart = lpWideCharStr;
u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte,
&error);
#endif
switch (error)
{
case U_BUFFER_OVERFLOW_ERROR:
if (targetCapacity > 0)
{
cchWideChar = 0;
WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
targetCapacity, targetLength);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
cchWideChar = targetLength;
break;
case U_STRING_NOT_TERMINATED_WARNING:
cchWideChar = targetLength;
break;
case U_ZERO_ERROR:
cchWideChar = targetLength;
break;
default:
WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
WINPR_CXX_COMPAT_CAST(unsigned, error));
if (U_FAILURE(error))
{
WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
u_errorName(error), WINPR_CXX_COMPAT_CAST(unsigned, error));
cchWideChar = 0;
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
}
else
cchWideChar = targetLength;
break;
}
}
return cchWideChar;
}
int int_WideCharToMultiByte(UINT CodePage, WINPR_ATTR_UNUSED DWORD dwFlags, LPCWSTR lpWideCharStr,
int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte,
WINPR_ATTR_UNUSED LPCSTR lpDefaultChar,
WINPR_ATTR_UNUSED LPBOOL lpUsedDefaultChar)
{
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
/* If cchWideChar is -1, the string is null-terminated */
size_t len = 0;
if (cchWideChar == -1)
len = _wcslen(lpWideCharStr) + 1;
else
len = WINPR_ASSERTING_INT_CAST(size_t, cchWideChar);
if (len >= INT32_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
cchWideChar = WINPR_ASSERTING_INT_CAST(int, len);
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
{
UErrorCode error = U_ZERO_ERROR;
int32_t targetLength = -1;
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
char* targetStart = lpMultiByteStr;
const int32_t targetCapacity = cbMultiByte;
#if defined(UCNV_CONVERT)
const char* str = (const char*)lpWideCharStr;
targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity, str,
cchWideChar * (int32_t)sizeof(WCHAR), &error);
#else
u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar, &error);
#endif
switch (error)
{
case U_BUFFER_OVERFLOW_ERROR:
if (targetCapacity > 0)
{
WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
targetCapacity, targetLength);
cbMultiByte = 0;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
cbMultiByte = targetLength;
break;
case U_STRING_NOT_TERMINATED_WARNING:
cbMultiByte = targetLength;
break;
case U_ZERO_ERROR:
cbMultiByte = targetLength;
break;
default:
WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
WINPR_CXX_COMPAT_CAST(unsigned, error));
if (U_FAILURE(error))
{
WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
u_errorName(error), WINPR_CXX_COMPAT_CAST(unsigned, error));
cbMultiByte = 0;
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
}
else
cbMultiByte = targetLength;
break;
}
}
return cbMultiByte;
}

View File

@@ -0,0 +1,50 @@
# WinPR: Windows Portable Runtime
# libwinpr-crypto cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(SRCS hash.c rand.c cipher.c cert.c crypto.c crypto.h)
if(WITH_INTERNAL_RC4)
list(APPEND SRCS rc4.c rc4.h)
endif()
if(WITH_INTERNAL_MD4)
list(APPEND SRCS md4.c md4.h)
endif()
if(WITH_INTERNAL_MD5)
list(APPEND SRCS md5.c md5.h)
list(APPEND SRCS hmac_md5.c hmac_md5.h)
endif()
winpr_module_add(${SRCS})
if(OPENSSL_FOUND)
winpr_system_include_directory_add(${OPENSSL_INCLUDE_DIR})
winpr_library_add_private(${OPENSSL_LIBRARIES})
endif()
if(MBEDTLS_FOUND)
winpr_system_include_directory_add(${MBEDTLS_INCLUDE_DIR})
winpr_library_add_private(${MBEDTLS_LIBRARIES})
endif()
if(WIN32)
winpr_library_add_public(crypt32)
endif()
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "crypto")
set(MINWIN_LONG_NAME "Cryptography API (CryptoAPI)")
set(MODULE_LIBRARY_NAME "crypt32")

View File

@@ -0,0 +1,239 @@
/**
* WinPR: Windows Portable Runtime
* Cryptography API (CryptoAPI)
*
* Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crypto.h>
/**
* CertOpenStore
* CertCloseStore
* CertControlStore
* CertDuplicateStore
* CertSaveStore
* CertRegisterPhysicalStore
* CertRegisterSystemStore
* CertAddStoreToCollection
* CertRemoveStoreFromCollection
* CertOpenSystemStoreA
* CertOpenSystemStoreW
* CertEnumPhysicalStore
* CertEnumSystemStore
* CertEnumSystemStoreLocation
* CertSetStoreProperty
* CertUnregisterPhysicalStore
* CertUnregisterSystemStore
*
* CertAddCertificateContextToStore
* CertAddCertificateLinkToStore
* CertAddCRLContextToStore
* CertAddCRLLinkToStore
* CertAddCTLContextToStore
* CertAddCTLLinkToStore
* CertAddEncodedCertificateToStore
* CertAddEncodedCertificateToSystemStoreA
* CertAddEncodedCertificateToSystemStoreW
* CertAddEncodedCRLToStore
* CertAddEncodedCTLToStore
* CertAddSerializedElementToStore
* CertDeleteCertificateFromStore
* CertDeleteCRLFromStore
* CertDeleteCTLFromStore
* CertGetCRLFromStore
* CertEnumCertificatesInStore
* CertEnumCRLsInStore
* CertEnumCTLsInStore
* CertFindCertificateInStore
* CertFindChainInStore
* CertFindCRLInStore
* CertFindCTLInStore
* CertGetIssuerCertificateFromStore
* CertGetStoreProperty
* CertGetSubjectCertificateFromStore
* CertSerializeCertificateStoreElement
* CertSerializeCRLStoreElement
* CertSerializeCTLStoreElement
*
* CertAddEnhancedKeyUsageIdentifier
* CertAddRefServerOcspResponse
* CertAddRefServerOcspResponseContext
* CertAlgIdToOID
* CertCloseServerOcspResponse
* CertCompareCertificate
* CertCompareCertificateName
* CertCompareIntegerBlob
* CertComparePublicKeyInfo
* CertCreateCertificateChainEngine
* CertCreateCertificateContext
* CertCreateContext
* CertCreateCRLContext
* CertCreateCTLContext
* CertCreateCTLEntryFromCertificateContextProperties
* CertCreateSelfSignCertificate
* CertDuplicateCertificateChain
* CertDuplicateCertificateContext
* CertDuplicateCRLContext
* CertDuplicateCTLContext
* CertEnumCertificateContextProperties
* CertEnumCRLContextProperties
* CertEnumCTLContextProperties
* CertEnumSubjectInSortedCTL
* CertFindAttribute
* CertFindCertificateInCRL
* CertFindExtension
* CertFindRDNAttr
* CertFindSubjectInCTL
* CertFindSubjectInSortedCTL
* CertFreeCertificateChain
* CertFreeCertificateChainEngine
* CertFreeCertificateChainList
* CertFreeCertificateContext
* CertFreeCRLContext
* CertFreeCTLContext
* CertFreeServerOcspResponseContext
* CertGetCertificateChain
* CertGetCertificateContextProperty
* CertGetCRLContextProperty
* CertGetCTLContextProperty
* CertGetEnhancedKeyUsage
* CertGetIntendedKeyUsage
* CertGetNameStringA
* CertGetNameStringW
* CertGetPublicKeyLength
* CertGetServerOcspResponseContext
* CertGetValidUsages
* CertIsRDNAttrsInCertificateName
* CertIsStrongHashToSign
* CertIsValidCRLForCertificate
* CertNameToStrA
* CertNameToStrW
* CertOIDToAlgId
* CertOpenServerOcspResponse
* CertRDNValueToStrA
* CertRDNValueToStrW
* CertRemoveEnhancedKeyUsageIdentifier
* CertResyncCertificateChainEngine
* CertRetrieveLogoOrBiometricInfo
* CertSelectCertificateChains
* CertSetCertificateContextPropertiesFromCTLEntry
* CertSetCertificateContextProperty
* CertSetCRLContextProperty
* CertSetCTLContextProperty
* CertSetEnhancedKeyUsage
* CertStrToNameA
* CertStrToNameW
* CertVerifyCertificateChainPolicy
* CertVerifyCRLRevocation
* CertVerifyCRLTimeValidity
* CertVerifyCTLUsage
* CertVerifyRevocation
* CertVerifySubjectCertificateContext
* CertVerifyTimeValidity
* CertVerifyValidityNesting
*/
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/wincrypt.h>
#ifndef _WIN32
#include "crypto.h"
HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType,
WINPR_ATTR_UNUSED HCRYPTPROV_LEGACY hCryptProv,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED const void* pvPara)
{
WINPR_CERTSTORE* certstore = nullptr;
certstore = (WINPR_CERTSTORE*)calloc(1, sizeof(WINPR_CERTSTORE));
if (certstore)
{
certstore->lpszStoreProvider = lpszStoreProvider;
certstore->dwMsgAndCertEncodingType = dwMsgAndCertEncodingType;
}
return (HCERTSTORE)certstore;
}
HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
WINPR_ATTR_UNUSED LPCWSTR szSubsystemProtocol)
{
HCERTSTORE hCertStore = nullptr;
hCertStore = CertOpenStore(CERT_STORE_PROV_FILE, X509_ASN_ENCODING, hProv, 0, nullptr);
return hCertStore;
}
HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
WINPR_ATTR_UNUSED LPCSTR szSubsystemProtocol)
{
return CertOpenSystemStoreW(hProv, nullptr);
}
BOOL CertCloseStore(HCERTSTORE hCertStore, WINPR_ATTR_UNUSED DWORD dwFlags)
{
WINPR_CERTSTORE* certstore = nullptr;
certstore = (WINPR_CERTSTORE*)hCertStore;
free(certstore);
return TRUE;
}
PCCERT_CONTEXT CertFindCertificateInStore(WINPR_ATTR_UNUSED HCERTSTORE hCertStore,
WINPR_ATTR_UNUSED DWORD dwCertEncodingType,
WINPR_ATTR_UNUSED DWORD dwFindFlags,
WINPR_ATTR_UNUSED DWORD dwFindType,
WINPR_ATTR_UNUSED const void* pvFindPara,
WINPR_ATTR_UNUSED PCCERT_CONTEXT pPrevCertContext)
{
WLog_ERR("TODO", "TODO: Implement");
return (PCCERT_CONTEXT)1;
}
PCCERT_CONTEXT CertEnumCertificatesInStore(WINPR_ATTR_UNUSED HCERTSTORE hCertStore,
WINPR_ATTR_UNUSED PCCERT_CONTEXT pPrevCertContext)
{
WLog_ERR("TODO", "TODO: Implement");
return (PCCERT_CONTEXT) nullptr;
}
DWORD CertGetNameStringW(WINPR_ATTR_UNUSED PCCERT_CONTEXT pCertContext,
WINPR_ATTR_UNUSED DWORD dwType, WINPR_ATTR_UNUSED DWORD dwFlags,
WINPR_ATTR_UNUSED void* pvTypePara, WINPR_ATTR_UNUSED LPWSTR pszNameString,
WINPR_ATTR_UNUSED DWORD cchNameString)
{
WLog_ERR("TODO", "TODO: Implement");
return 0;
}
DWORD CertGetNameStringA(WINPR_ATTR_UNUSED PCCERT_CONTEXT pCertContext,
WINPR_ATTR_UNUSED DWORD dwType, WINPR_ATTR_UNUSED DWORD dwFlags,
WINPR_ATTR_UNUSED void* pvTypePara, WINPR_ATTR_UNUSED LPSTR pszNameString,
WINPR_ATTR_UNUSED DWORD cchNameString)
{
WLog_ERR("TODO", "TODO: Implement");
return 0;
}
#endif

View File

@@ -0,0 +1,881 @@
/**
* WinPR: Windows Portable Runtime
*
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/crypto.h>
#include "../log.h"
#define TAG WINPR_TAG("crypto.cipher")
#if defined(WITH_INTERNAL_RC4)
#include "rc4.h"
#endif
#ifdef WITH_OPENSSL
#include <openssl/aes.h>
#include <openssl/rc4.h>
#include <openssl/des.h>
#include <openssl/evp.h>
#endif
#ifdef WITH_MBEDTLS
#include <mbedtls/md.h>
#include <mbedtls/aes.h>
#include <mbedtls/des.h>
#include <mbedtls/cipher.h>
#if MBEDTLS_VERSION_MAJOR < 3
#define mbedtls_cipher_info_get_iv_size(_info) (_info->iv_size)
#define mbedtls_cipher_info_get_key_bitlen(_info) (_info->key_bitlen)
#endif
#endif
struct winpr_cipher_ctx_private_st
{
WINPR_CIPHER_TYPE cipher;
WINPR_CRYPTO_OPERATION op;
#ifdef WITH_OPENSSL
EVP_CIPHER_CTX* ectx;
#endif
#ifdef WITH_MBEDTLS
mbedtls_cipher_context_t* mctx;
#endif
};
/**
* RC4
*/
struct winpr_rc4_ctx_private_st
{
#if defined(WITH_INTERNAL_RC4)
winpr_int_RC4_CTX* ictx;
#else
#if defined(WITH_OPENSSL)
EVP_CIPHER_CTX* ctx;
#endif
#endif
};
static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOOL override_fips)
{
if (!key || (keylen == 0))
return nullptr;
WINPR_RC4_CTX* ctx = (WINPR_RC4_CTX*)calloc(1, sizeof(WINPR_RC4_CTX));
if (!ctx)
return nullptr;
#if defined(WITH_INTERNAL_RC4)
WINPR_UNUSED(override_fips);
ctx->ictx = winpr_int_rc4_new(key, keylen);
if (!ctx->ictx)
goto fail;
#elif defined(WITH_OPENSSL)
const EVP_CIPHER* evp = nullptr;
if (keylen > INT_MAX)
goto fail;
ctx->ctx = EVP_CIPHER_CTX_new();
if (!ctx->ctx)
goto fail;
evp = EVP_rc4();
if (!evp)
goto fail;
EVP_CIPHER_CTX_reset(ctx->ctx);
if (EVP_EncryptInit_ex(ctx->ctx, evp, nullptr, nullptr, nullptr) != 1)
goto fail;
/* EVP_CIPH_FLAG_NON_FIPS_ALLOW does not exist before openssl 1.0.1 */
#if !(OPENSSL_VERSION_NUMBER < 0x10001000L)
if (override_fips == TRUE)
EVP_CIPHER_CTX_set_flags(ctx->ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW);
#endif
EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)keylen);
if (EVP_EncryptInit_ex(ctx->ctx, nullptr, nullptr, key, nullptr) != 1)
goto fail;
#endif
return ctx;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
winpr_RC4_Free(ctx);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const void* key, size_t keylen)
{
return winpr_RC4_New_Internal(key, keylen, TRUE);
}
WINPR_RC4_CTX* winpr_RC4_New(const void* key, size_t keylen)
{
return winpr_RC4_New_Internal(key, keylen, FALSE);
}
BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const void* input, void* output)
{
WINPR_ASSERT(ctx);
#if defined(WITH_INTERNAL_RC4)
return winpr_int_rc4_update(ctx->ictx, length, input, output);
#elif defined(WITH_OPENSSL)
WINPR_ASSERT(ctx->ctx);
int outputLength = 0;
if (length > INT_MAX)
return FALSE;
WINPR_ASSERT(ctx);
if (EVP_CipherUpdate(ctx->ctx, output, &outputLength, input, (int)length) != 1)
return FALSE;
return TRUE;
#endif
return FALSE;
}
void winpr_RC4_Free(WINPR_RC4_CTX* ctx)
{
if (!ctx)
return;
#if defined(WITH_INTERNAL_RC4)
winpr_int_rc4_free(ctx->ictx);
#elif defined(WITH_OPENSSL)
EVP_CIPHER_CTX_free(ctx->ctx);
#endif
free(ctx);
}
/**
* Generic Cipher API
*/
#ifdef WITH_OPENSSL
extern const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md);
#endif
#ifdef WITH_MBEDTLS
extern mbedtls_md_type_t winpr_mbedtls_get_md_type(int md);
#endif
struct cipher_map
{
WINPR_CIPHER_TYPE md;
const char* name;
};
static const struct cipher_map s_cipher_map[] = {
{ WINPR_CIPHER_NONE, "none" },
{ WINPR_CIPHER_NULL, "null" },
{ WINPR_CIPHER_AES_128_ECB, "aes-128-ecb" },
{ WINPR_CIPHER_AES_192_ECB, "aes-192-ecb" },
{ WINPR_CIPHER_AES_256_ECB, "aes-256-ecb" },
{ WINPR_CIPHER_AES_128_CBC, "aes-128-cbc" },
{ WINPR_CIPHER_AES_192_CBC, "aes-192-cbc" },
{ WINPR_CIPHER_AES_256_CBC, "aes-256-cbc" },
{ WINPR_CIPHER_AES_128_CFB128, "aes-128-cfb128" },
{ WINPR_CIPHER_AES_192_CFB128, "aes-192-cfb128" },
{ WINPR_CIPHER_AES_256_CFB128, "aes-256-cfb128" },
{ WINPR_CIPHER_AES_128_CTR, "aes-128-ctr" },
{ WINPR_CIPHER_AES_192_CTR, "aes-192-ctr" },
{ WINPR_CIPHER_AES_256_CTR, "aes-256-ctr" },
{ WINPR_CIPHER_AES_128_GCM, "aes-128-gcm" },
{ WINPR_CIPHER_AES_192_GCM, "aes-192-gcm" },
{ WINPR_CIPHER_AES_256_GCM, "aes-256-gcm" },
{ WINPR_CIPHER_CAMELLIA_128_ECB, "camellia-128-ecb" },
{ WINPR_CIPHER_CAMELLIA_192_ECB, "camellia-192-ecb" },
{ WINPR_CIPHER_CAMELLIA_256_ECB, "camellia-256-ecb" },
{ WINPR_CIPHER_CAMELLIA_128_CBC, "camellia-128-cbc" },
{ WINPR_CIPHER_CAMELLIA_192_CBC, "camellia-192-cbc" },
{ WINPR_CIPHER_CAMELLIA_256_CBC, "camellia-256-cbc" },
{ WINPR_CIPHER_CAMELLIA_128_CFB128, "camellia-128-cfb128" },
{ WINPR_CIPHER_CAMELLIA_192_CFB128, "camellia-192-cfb128" },
{ WINPR_CIPHER_CAMELLIA_256_CFB128, "camellia-256-cfb128" },
{ WINPR_CIPHER_CAMELLIA_128_CTR, "camellia-128-ctr" },
{ WINPR_CIPHER_CAMELLIA_192_CTR, "camellia-192-ctr" },
{ WINPR_CIPHER_CAMELLIA_256_CTR, "camellia-256-ctr" },
{ WINPR_CIPHER_CAMELLIA_128_GCM, "camellia-128-gcm" },
{ WINPR_CIPHER_CAMELLIA_192_GCM, "camellia-192-gcm" },
{ WINPR_CIPHER_CAMELLIA_256_GCM, "camellia-256-gcm" },
{ WINPR_CIPHER_DES_ECB, "des-ecb" },
{ WINPR_CIPHER_DES_CBC, "des-cbc" },
{ WINPR_CIPHER_DES_EDE_ECB, "des-ede-ecb" },
{ WINPR_CIPHER_DES_EDE_CBC, "des-ede-cbc" },
{ WINPR_CIPHER_DES_EDE3_ECB, "des-ede3-ecb" },
{ WINPR_CIPHER_DES_EDE3_CBC, "des-ede3-cbc" },
{ WINPR_CIPHER_BLOWFISH_ECB, "blowfish-ecb" },
{ WINPR_CIPHER_BLOWFISH_CBC, "blowfish-cbc" },
{ WINPR_CIPHER_BLOWFISH_CFB64, "blowfish-cfb64" },
{ WINPR_CIPHER_BLOWFISH_CTR, "blowfish-ctr" },
{ WINPR_CIPHER_ARC4_128, "rc4" },
{ WINPR_CIPHER_AES_128_CCM, "aes-128-ccm" },
{ WINPR_CIPHER_AES_192_CCM, "aes-192-ccm" },
{ WINPR_CIPHER_AES_256_CCM, "aes-256-ccm" },
{ WINPR_CIPHER_CAMELLIA_128_CCM, "camellia-128-ccm" },
{ WINPR_CIPHER_CAMELLIA_192_CCM, "camellia-192-ccm" },
{ WINPR_CIPHER_CAMELLIA_256_CCM, "camellia-256-ccm" },
};
static int cipher_compare(const void* a, const void* b)
{
const WINPR_CIPHER_TYPE* cipher = a;
const struct cipher_map* map = b;
if (*cipher == map->md)
return 0;
return *cipher > map->md ? 1 : -1;
}
const char* winpr_cipher_type_to_string(WINPR_CIPHER_TYPE md)
{
WINPR_CIPHER_TYPE lc = md;
const struct cipher_map* ret = bsearch(&lc, s_cipher_map, ARRAYSIZE(s_cipher_map),
sizeof(struct cipher_map), cipher_compare);
if (!ret)
return "unknown";
return ret->name;
}
static int cipher_string_compare(const void* a, const void* b)
{
const char* cipher = a;
const struct cipher_map* map = b;
return strcmp(cipher, map->name);
}
WINPR_CIPHER_TYPE winpr_cipher_type_from_string(const char* name)
{
const struct cipher_map* ret = bsearch(name, s_cipher_map, ARRAYSIZE(s_cipher_map),
sizeof(struct cipher_map), cipher_string_compare);
if (!ret)
return WINPR_CIPHER_NONE;
return ret->md;
}
#if defined(WITH_OPENSSL)
static const EVP_CIPHER* winpr_openssl_get_evp_cipher(WINPR_CIPHER_TYPE cipher)
{
const EVP_CIPHER* evp = nullptr;
switch (cipher)
{
case WINPR_CIPHER_NULL:
evp = EVP_enc_null();
break;
case WINPR_CIPHER_AES_128_ECB:
evp = EVP_get_cipherbyname("aes-128-ecb");
break;
case WINPR_CIPHER_AES_192_ECB:
evp = EVP_get_cipherbyname("aes-192-ecb");
break;
case WINPR_CIPHER_AES_256_ECB:
evp = EVP_get_cipherbyname("aes-256-ecb");
break;
case WINPR_CIPHER_AES_128_CBC:
evp = EVP_get_cipherbyname("aes-128-cbc");
break;
case WINPR_CIPHER_AES_192_CBC:
evp = EVP_get_cipherbyname("aes-192-cbc");
break;
case WINPR_CIPHER_AES_256_CBC:
evp = EVP_get_cipherbyname("aes-256-cbc");
break;
case WINPR_CIPHER_AES_128_CFB128:
evp = EVP_get_cipherbyname("aes-128-cfb128");
break;
case WINPR_CIPHER_AES_192_CFB128:
evp = EVP_get_cipherbyname("aes-192-cfb128");
break;
case WINPR_CIPHER_AES_256_CFB128:
evp = EVP_get_cipherbyname("aes-256-cfb128");
break;
case WINPR_CIPHER_AES_128_CTR:
evp = EVP_get_cipherbyname("aes-128-ctr");
break;
case WINPR_CIPHER_AES_192_CTR:
evp = EVP_get_cipherbyname("aes-192-ctr");
break;
case WINPR_CIPHER_AES_256_CTR:
evp = EVP_get_cipherbyname("aes-256-ctr");
break;
case WINPR_CIPHER_AES_128_GCM:
evp = EVP_get_cipherbyname("aes-128-gcm");
break;
case WINPR_CIPHER_AES_192_GCM:
evp = EVP_get_cipherbyname("aes-192-gcm");
break;
case WINPR_CIPHER_AES_256_GCM:
evp = EVP_get_cipherbyname("aes-256-gcm");
break;
case WINPR_CIPHER_AES_128_CCM:
evp = EVP_get_cipherbyname("aes-128-ccm");
break;
case WINPR_CIPHER_AES_192_CCM:
evp = EVP_get_cipherbyname("aes-192-ccm");
break;
case WINPR_CIPHER_AES_256_CCM:
evp = EVP_get_cipherbyname("aes-256-ccm");
break;
case WINPR_CIPHER_CAMELLIA_128_ECB:
evp = EVP_get_cipherbyname("camellia-128-ecb");
break;
case WINPR_CIPHER_CAMELLIA_192_ECB:
evp = EVP_get_cipherbyname("camellia-192-ecb");
break;
case WINPR_CIPHER_CAMELLIA_256_ECB:
evp = EVP_get_cipherbyname("camellia-256-ecb");
break;
case WINPR_CIPHER_CAMELLIA_128_CBC:
evp = EVP_get_cipherbyname("camellia-128-cbc");
break;
case WINPR_CIPHER_CAMELLIA_192_CBC:
evp = EVP_get_cipherbyname("camellia-192-cbc");
break;
case WINPR_CIPHER_CAMELLIA_256_CBC:
evp = EVP_get_cipherbyname("camellia-256-cbc");
break;
case WINPR_CIPHER_CAMELLIA_128_CFB128:
evp = EVP_get_cipherbyname("camellia-128-cfb128");
break;
case WINPR_CIPHER_CAMELLIA_192_CFB128:
evp = EVP_get_cipherbyname("camellia-192-cfb128");
break;
case WINPR_CIPHER_CAMELLIA_256_CFB128:
evp = EVP_get_cipherbyname("camellia-256-cfb128");
break;
case WINPR_CIPHER_CAMELLIA_128_CTR:
evp = EVP_get_cipherbyname("camellia-128-ctr");
break;
case WINPR_CIPHER_CAMELLIA_192_CTR:
evp = EVP_get_cipherbyname("camellia-192-ctr");
break;
case WINPR_CIPHER_CAMELLIA_256_CTR:
evp = EVP_get_cipherbyname("camellia-256-ctr");
break;
case WINPR_CIPHER_CAMELLIA_128_GCM:
evp = EVP_get_cipherbyname("camellia-128-gcm");
break;
case WINPR_CIPHER_CAMELLIA_192_GCM:
evp = EVP_get_cipherbyname("camellia-192-gcm");
break;
case WINPR_CIPHER_CAMELLIA_256_GCM:
evp = EVP_get_cipherbyname("camellia-256-gcm");
break;
case WINPR_CIPHER_CAMELLIA_128_CCM:
evp = EVP_get_cipherbyname("camellia-128-ccm");
break;
case WINPR_CIPHER_CAMELLIA_192_CCM:
evp = EVP_get_cipherbyname("camellia-192-ccm");
break;
case WINPR_CIPHER_CAMELLIA_256_CCM:
evp = EVP_get_cipherbyname("camellia-256-ccm");
break;
case WINPR_CIPHER_DES_ECB:
evp = EVP_get_cipherbyname("des-ecb");
break;
case WINPR_CIPHER_DES_CBC:
evp = EVP_get_cipherbyname("des-cbc");
break;
case WINPR_CIPHER_DES_EDE_ECB:
evp = EVP_get_cipherbyname("des-ede-ecb");
break;
case WINPR_CIPHER_DES_EDE_CBC:
evp = EVP_get_cipherbyname("des-ede-cbc");
break;
case WINPR_CIPHER_DES_EDE3_ECB:
evp = EVP_get_cipherbyname("des-ede3-ecb");
break;
case WINPR_CIPHER_DES_EDE3_CBC:
evp = EVP_get_cipherbyname("des-ede3-cbc");
break;
case WINPR_CIPHER_ARC4_128:
evp = EVP_get_cipherbyname("rc4");
break;
case WINPR_CIPHER_BLOWFISH_ECB:
evp = EVP_get_cipherbyname("blowfish-ecb");
break;
case WINPR_CIPHER_BLOWFISH_CBC:
evp = EVP_get_cipherbyname("blowfish-cbc");
break;
case WINPR_CIPHER_BLOWFISH_CFB64:
evp = EVP_get_cipherbyname("blowfish-cfb64");
break;
case WINPR_CIPHER_BLOWFISH_CTR:
evp = EVP_get_cipherbyname("blowfish-ctr");
break;
default:
break;
}
return evp;
}
#elif defined(WITH_MBEDTLS)
mbedtls_cipher_type_t winpr_mbedtls_get_cipher_type(int cipher)
{
mbedtls_cipher_type_t type = MBEDTLS_CIPHER_NONE;
switch (cipher)
{
case WINPR_CIPHER_NONE:
type = MBEDTLS_CIPHER_NONE;
break;
case WINPR_CIPHER_NULL:
type = MBEDTLS_CIPHER_NULL;
break;
case WINPR_CIPHER_AES_128_ECB:
type = MBEDTLS_CIPHER_AES_128_ECB;
break;
case WINPR_CIPHER_AES_192_ECB:
type = MBEDTLS_CIPHER_AES_192_ECB;
break;
case WINPR_CIPHER_AES_256_ECB:
type = MBEDTLS_CIPHER_AES_256_ECB;
break;
case WINPR_CIPHER_AES_128_CBC:
type = MBEDTLS_CIPHER_AES_128_CBC;
break;
case WINPR_CIPHER_AES_192_CBC:
type = MBEDTLS_CIPHER_AES_192_CBC;
break;
case WINPR_CIPHER_AES_256_CBC:
type = MBEDTLS_CIPHER_AES_256_CBC;
break;
case WINPR_CIPHER_AES_128_CFB128:
type = MBEDTLS_CIPHER_AES_128_CFB128;
break;
case WINPR_CIPHER_AES_192_CFB128:
type = MBEDTLS_CIPHER_AES_192_CFB128;
break;
case WINPR_CIPHER_AES_256_CFB128:
type = MBEDTLS_CIPHER_AES_256_CFB128;
break;
case WINPR_CIPHER_AES_128_CTR:
type = MBEDTLS_CIPHER_AES_128_CTR;
break;
case WINPR_CIPHER_AES_192_CTR:
type = MBEDTLS_CIPHER_AES_192_CTR;
break;
case WINPR_CIPHER_AES_256_CTR:
type = MBEDTLS_CIPHER_AES_256_CTR;
break;
case WINPR_CIPHER_AES_128_GCM:
type = MBEDTLS_CIPHER_AES_128_GCM;
break;
case WINPR_CIPHER_AES_192_GCM:
type = MBEDTLS_CIPHER_AES_192_GCM;
break;
case WINPR_CIPHER_AES_256_GCM:
type = MBEDTLS_CIPHER_AES_256_GCM;
break;
case WINPR_CIPHER_AES_128_CCM:
type = MBEDTLS_CIPHER_AES_128_CCM;
break;
case WINPR_CIPHER_AES_192_CCM:
type = MBEDTLS_CIPHER_AES_192_CCM;
break;
case WINPR_CIPHER_AES_256_CCM:
type = MBEDTLS_CIPHER_AES_256_CCM;
break;
}
return type;
}
#endif
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
WINPR_CIPHER_CTX* winpr_Cipher_New(WINPR_CIPHER_TYPE cipher, WINPR_CRYPTO_OPERATION op,
const void* key, const void* iv)
{
return winpr_Cipher_NewEx(cipher, op, key, 0, iv, 0);
}
#endif
WINPR_API WINPR_CIPHER_CTX* winpr_Cipher_NewEx(WINPR_CIPHER_TYPE cipher, WINPR_CRYPTO_OPERATION op,
const void* key, WINPR_ATTR_UNUSED size_t keylen,
const void* iv, WINPR_ATTR_UNUSED size_t ivlen)
{
if (cipher == WINPR_CIPHER_ARC4_128)
{
WLog_ERR(TAG,
"WINPR_CIPHER_ARC4_128 (RC4) cipher not supported, use winpr_RC4_new instead");
return nullptr;
}
WINPR_CIPHER_CTX* ctx = calloc(1, sizeof(WINPR_CIPHER_CTX));
if (!ctx)
return nullptr;
ctx->cipher = cipher;
ctx->op = op;
#if defined(WITH_OPENSSL)
const EVP_CIPHER* evp = winpr_openssl_get_evp_cipher(cipher);
if (!evp)
goto fail;
ctx->ectx = EVP_CIPHER_CTX_new();
if (!ctx->ectx)
goto fail;
{
const int operation = (op == WINPR_ENCRYPT) ? 1 : 0;
if (EVP_CipherInit_ex(ctx->ectx, evp, nullptr, key, iv, operation) != 1)
goto fail;
}
EVP_CIPHER_CTX_set_padding(ctx->ectx, 0);
#elif defined(WITH_MBEDTLS)
mbedtls_cipher_type_t cipher_type = winpr_mbedtls_get_cipher_type(cipher);
const mbedtls_cipher_info_t* cipher_info = mbedtls_cipher_info_from_type(cipher_type);
if (!cipher_info)
goto fail;
ctx->mctx = calloc(1, sizeof(mbedtls_cipher_context_t));
if (!ctx->mctx)
goto fail;
const mbedtls_operation_t operation = (op == WINPR_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT;
mbedtls_cipher_init(ctx->mctx);
if (mbedtls_cipher_setup(ctx->mctx, cipher_info) != 0)
goto fail;
const int key_bitlen = mbedtls_cipher_get_key_bitlen(ctx->mctx);
if (mbedtls_cipher_setkey(ctx->mctx, key, key_bitlen, operation) != 0)
goto fail;
if (mbedtls_cipher_set_padding_mode(ctx->mctx, MBEDTLS_PADDING_NONE) != 0)
goto fail;
#endif
return ctx;
fail:
winpr_Cipher_Free(ctx);
return nullptr;
}
BOOL winpr_Cipher_SetPadding(WINPR_CIPHER_CTX* ctx, BOOL enabled)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
if (!ctx->ectx)
return FALSE;
EVP_CIPHER_CTX_set_padding(ctx->ectx, enabled);
#elif defined(WITH_MBEDTLS)
mbedtls_cipher_padding_t option = enabled ? MBEDTLS_PADDING_PKCS7 : MBEDTLS_PADDING_NONE;
if (mbedtls_cipher_set_padding_mode((mbedtls_cipher_context_t*)ctx, option) != 0)
return FALSE;
#else
return FALSE;
#endif
return TRUE;
}
BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const void* input, size_t ilen, void* output,
size_t* olen)
{
WINPR_ASSERT(ctx);
WINPR_ASSERT(olen);
#if defined(WITH_OPENSSL)
int outl = (int)*olen;
if (ilen > INT_MAX)
{
WLog_ERR(TAG, "input length %" PRIuz " > %d, abort", ilen, INT_MAX);
return FALSE;
}
WINPR_ASSERT(ctx->ectx);
if (EVP_CipherUpdate(ctx->ectx, output, &outl, input, (int)ilen) == 1)
{
*olen = (size_t)outl;
return TRUE;
}
#elif defined(WITH_MBEDTLS)
WINPR_ASSERT(ctx->mctx);
if (mbedtls_cipher_update(ctx->mctx, input, ilen, output, olen) == 0)
return TRUE;
#endif
WLog_ERR(TAG, "Failed to update the data");
return FALSE;
}
BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, void* output, size_t* olen)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
int outl = (int)*olen;
WINPR_ASSERT(ctx->ectx);
if (EVP_CipherFinal_ex(ctx->ectx, output, &outl) == 1)
{
*olen = (size_t)outl;
return TRUE;
}
#elif defined(WITH_MBEDTLS)
WINPR_ASSERT(ctx->mctx);
if (mbedtls_cipher_finish(ctx->mctx, output, olen) == 0)
return TRUE;
#endif
return FALSE;
}
void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx)
{
if (!ctx)
return;
#if defined(WITH_OPENSSL)
if (ctx->ectx)
EVP_CIPHER_CTX_free(ctx->ectx);
#elif defined(WITH_MBEDTLS)
if (ctx->mctx)
{
mbedtls_cipher_free(ctx->mctx);
free(ctx->mctx);
}
#endif
free(ctx);
}
/**
* Key Generation
*/
int winpr_Cipher_BytesToKey(int cipher, WINPR_MD_TYPE md, const void* salt, const void* data,
size_t datal, size_t count, void* key, void* iv)
{
/**
* Key and IV generation compatible with OpenSSL EVP_BytesToKey():
* https://www.openssl.org/docs/manmaster/crypto/EVP_BytesToKey.html
*/
#if defined(WITH_OPENSSL)
const EVP_MD* evp_md = nullptr;
const EVP_CIPHER* evp_cipher = nullptr;
evp_md = winpr_openssl_get_evp_md(md);
evp_cipher = winpr_openssl_get_evp_cipher(WINPR_ASSERTING_INT_CAST(WINPR_CIPHER_TYPE, cipher));
WINPR_ASSERT(datal <= INT_MAX);
WINPR_ASSERT(count <= INT_MAX);
return EVP_BytesToKey(evp_cipher, evp_md, salt, data, (int)datal, (int)count, key, iv);
#elif defined(WITH_MBEDTLS)
int rv = 0;
BYTE md_buf[64];
int niv, nkey, addmd = 0;
unsigned int mds = 0;
mbedtls_md_context_t ctx;
const mbedtls_md_info_t* md_info;
mbedtls_cipher_type_t cipher_type;
const mbedtls_cipher_info_t* cipher_info;
mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
md_info = mbedtls_md_info_from_type(md_type);
cipher_type = winpr_mbedtls_get_cipher_type(cipher);
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
nkey = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
niv = mbedtls_cipher_info_get_iv_size(cipher_info);
if ((nkey > 64) || (niv > 64))
return 0;
if (!data)
return nkey;
mbedtls_md_init(&ctx);
if (mbedtls_md_setup(&ctx, md_info, 0) != 0)
goto err;
while (1)
{
if (mbedtls_md_starts(&ctx) != 0)
goto err;
if (addmd++)
{
if (mbedtls_md_update(&ctx, md_buf, mds) != 0)
goto err;
}
if (mbedtls_md_update(&ctx, data, datal) != 0)
goto err;
if (salt)
{
if (mbedtls_md_update(&ctx, salt, 8) != 0)
goto err;
}
if (mbedtls_md_finish(&ctx, md_buf) != 0)
goto err;
mds = mbedtls_md_get_size(md_info);
for (unsigned int i = 1; i < (unsigned int)count; i++)
{
if (mbedtls_md_starts(&ctx) != 0)
goto err;
if (mbedtls_md_update(&ctx, md_buf, mds) != 0)
goto err;
if (mbedtls_md_finish(&ctx, md_buf) != 0)
goto err;
}
unsigned int i = 0;
if (nkey)
{
while (1)
{
if (nkey == 0)
break;
if (i == mds)
break;
if (key)
*(BYTE*)(key++) = md_buf[i];
nkey--;
i++;
}
}
if (niv && (i != mds))
{
while (1)
{
if (niv == 0)
break;
if (i == mds)
break;
if (iv)
*(BYTE*)(iv++) = md_buf[i];
niv--;
i++;
}
}
if ((nkey == 0) && (niv == 0))
break;
}
rv = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
err:
mbedtls_md_free(&ctx);
SecureZeroMemory(md_buf, 64);
return rv;
#else
return 0;
#endif
}

View File

@@ -0,0 +1,324 @@
/**
* WinPR: Windows Portable Runtime
* Cryptography API (CryptoAPI)
*
* Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/wlog.h>
#include <winpr/crypto.h>
/**
* CryptAcquireCertificatePrivateKey
* CryptBinaryToStringA
* CryptBinaryToStringW
* CryptCloseAsyncHandle
* CryptCreateAsyncHandle
* CryptCreateKeyIdentifierFromCSP
* CryptDecodeMessage
* CryptDecodeObject
* CryptDecodeObjectEx
* CryptDecryptAndVerifyMessageSignature
* CryptDecryptMessage
* CryptEncodeObject
* CryptEncodeObjectEx
* CryptEncryptMessage
* CryptEnumKeyIdentifierProperties
* CryptEnumOIDFunction
* CryptEnumOIDInfo
* CryptExportPKCS8
* CryptExportPublicKeyInfo
* CryptExportPublicKeyInfoEx
* CryptExportPublicKeyInfoFromBCryptKeyHandle
* CryptFindCertificateKeyProvInfo
* CryptFindLocalizedName
* CryptFindOIDInfo
* CryptFormatObject
* CryptFreeOIDFunctionAddress
* CryptGetAsyncParam
* CryptGetDefaultOIDDllList
* CryptGetDefaultOIDFunctionAddress
* CryptGetKeyIdentifierProperty
* CryptGetMessageCertificates
* CryptGetMessageSignerCount
* CryptGetOIDFunctionAddress
* CryptGetOIDFunctionValue
* CryptHashCertificate
* CryptHashCertificate2
* CryptHashMessage
* CryptHashPublicKeyInfo
* CryptHashToBeSigned
* CryptImportPKCS8
* CryptImportPublicKeyInfo
* CryptImportPublicKeyInfoEx
* CryptImportPublicKeyInfoEx2
* CryptInitOIDFunctionSet
* CryptInstallDefaultContext
* CryptInstallOIDFunctionAddress
* CryptLoadSip
* CryptMemAlloc
* CryptMemFree
* CryptMemRealloc
* CryptMsgCalculateEncodedLength
* CryptMsgClose
* CryptMsgControl
* CryptMsgCountersign
* CryptMsgCountersignEncoded
* CryptMsgDuplicate
* CryptMsgEncodeAndSignCTL
* CryptMsgGetAndVerifySigner
* CryptMsgGetParam
* CryptMsgOpenToDecode
* CryptMsgOpenToEncode
* CryptMsgSignCTL
* CryptMsgUpdate
* CryptMsgVerifyCountersignatureEncoded
* CryptMsgVerifyCountersignatureEncodedEx
* CryptQueryObject
* CryptRegisterDefaultOIDFunction
* CryptRegisterOIDFunction
* CryptRegisterOIDInfo
* CryptRetrieveTimeStamp
* CryptSetAsyncParam
* CryptSetKeyIdentifierProperty
* CryptSetOIDFunctionValue
* CryptSignAndEncodeCertificate
* CryptSignAndEncryptMessage
* CryptSignCertificate
* CryptSignMessage
* CryptSignMessageWithKey
* CryptSIPAddProvider
* CryptSIPCreateIndirectData
* CryptSIPGetCaps
* CryptSIPGetSignedDataMsg
* CryptSIPLoad
* CryptSIPPutSignedDataMsg
* CryptSIPRemoveProvider
* CryptSIPRemoveSignedDataMsg
* CryptSIPRetrieveSubjectGuid
* CryptSIPRetrieveSubjectGuidForCatalogFile
* CryptSIPVerifyIndirectData
* CryptUninstallDefaultContext
* CryptUnregisterDefaultOIDFunction
* CryptUnregisterOIDFunction
* CryptUnregisterOIDInfo
* CryptUpdateProtectedState
* CryptVerifyCertificateSignature
* CryptVerifyCertificateSignatureEx
* CryptVerifyDetachedMessageHash
* CryptVerifyDetachedMessageSignature
* CryptVerifyMessageHash
* CryptVerifyMessageSignature
* CryptVerifyMessageSignatureWithKey
* CryptVerifyTimeStampSignature
* DbgInitOSS
* DbgPrintf
* PFXExportCertStore
* PFXExportCertStore2
* PFXExportCertStoreEx
* PFXImportCertStore
* PFXIsPFXBlob
* PFXVerifyPassword
*/
#ifndef _WIN32
#include "crypto.h"
#include <winpr/crt.h>
#include <winpr/collections.h>
static wListDictionary* g_ProtectedMemoryBlocks = nullptr;
BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
BYTE* pCipherText = nullptr;
size_t cbOut = 0;
size_t cbFinal = 0;
WINPR_CIPHER_CTX* enc = nullptr;
BYTE randomKey[256] = WINPR_C_ARRAY_INIT;
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = nullptr;
if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
return FALSE;
if (winpr_RAND(randomKey, sizeof(randomKey)) < 0)
return FALSE;
if (!g_ProtectedMemoryBlocks)
{
g_ProtectedMemoryBlocks = ListDictionary_New(TRUE);
if (!g_ProtectedMemoryBlocks)
return FALSE;
}
pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*)calloc(1, sizeof(WINPR_PROTECTED_MEMORY_BLOCK));
if (!pMemBlock)
return FALSE;
pMemBlock->pData = pData;
pMemBlock->cbData = cbData;
pMemBlock->dwFlags = dwFlags;
if (winpr_RAND(pMemBlock->salt, 8) < 0)
goto out;
if (winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1, pMemBlock->salt, randomKey,
sizeof(randomKey), 4, pMemBlock->key, pMemBlock->iv) <= 0)
goto out;
SecureZeroMemory(randomKey, sizeof(randomKey));
cbOut = pMemBlock->cbData + 16 - 1;
pCipherText = (BYTE*)calloc(1, cbOut);
if (!pCipherText)
goto out;
if ((enc = winpr_Cipher_NewEx(WINPR_CIPHER_AES_256_CBC, WINPR_ENCRYPT, pMemBlock->key,
sizeof(pMemBlock->key), pMemBlock->iv, sizeof(pMemBlock->iv))) ==
nullptr)
goto out;
if (!winpr_Cipher_Update(enc, pMemBlock->pData, pMemBlock->cbData, pCipherText, &cbOut))
goto out;
if (!winpr_Cipher_Final(enc, pCipherText + cbOut, &cbFinal))
goto out;
winpr_Cipher_Free(enc);
CopyMemory(pMemBlock->pData, pCipherText, pMemBlock->cbData);
free(pCipherText);
return ListDictionary_Add(g_ProtectedMemoryBlocks, pData, pMemBlock);
out:
free(pMemBlock);
free(pCipherText);
winpr_Cipher_Free(enc);
return FALSE;
}
BOOL CryptUnprotectMemory(LPVOID pData, WINPR_ATTR_UNUSED DWORD cbData, DWORD dwFlags)
{
BYTE* pPlainText = nullptr;
size_t cbOut = 0;
size_t cbFinal = 0;
WINPR_CIPHER_CTX* dec = nullptr;
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = nullptr;
if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
return FALSE;
if (!g_ProtectedMemoryBlocks)
return FALSE;
pMemBlock =
(WINPR_PROTECTED_MEMORY_BLOCK*)ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData);
if (!pMemBlock)
goto out;
cbOut = pMemBlock->cbData + 16 - 1;
pPlainText = (BYTE*)malloc(cbOut);
if (!pPlainText)
goto out;
if ((dec = winpr_Cipher_NewEx(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, pMemBlock->key,
sizeof(pMemBlock->key), pMemBlock->iv, sizeof(pMemBlock->iv))) ==
nullptr)
goto out;
if (!winpr_Cipher_Update(dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut))
goto out;
if (!winpr_Cipher_Final(dec, pPlainText + cbOut, &cbFinal))
goto out;
winpr_Cipher_Free(dec);
CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData);
SecureZeroMemory(pPlainText, pMemBlock->cbData);
free(pPlainText);
ListDictionary_Remove(g_ProtectedMemoryBlocks, pData);
free(pMemBlock);
return TRUE;
out:
free(pPlainText);
free(pMemBlock);
winpr_Cipher_Free(dec);
return FALSE;
}
BOOL CryptProtectData(WINPR_ATTR_UNUSED DATA_BLOB* pDataIn, WINPR_ATTR_UNUSED LPCWSTR szDataDescr,
WINPR_ATTR_UNUSED DATA_BLOB* pOptionalEntropy,
WINPR_ATTR_UNUSED PVOID pvReserved,
WINPR_ATTR_UNUSED CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED DATA_BLOB* pDataOut)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptUnprotectData(WINPR_ATTR_UNUSED DATA_BLOB* pDataIn,
WINPR_ATTR_UNUSED LPWSTR* ppszDataDescr,
WINPR_ATTR_UNUSED DATA_BLOB* pOptionalEntropy,
WINPR_ATTR_UNUSED PVOID pvReserved,
WINPR_ATTR_UNUSED CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED DATA_BLOB* pDataOut)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptStringToBinaryW(WINPR_ATTR_UNUSED LPCWSTR pszString, WINPR_ATTR_UNUSED DWORD cchString,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED BYTE* pbBinary,
WINPR_ATTR_UNUSED DWORD* pcbBinary, WINPR_ATTR_UNUSED DWORD* pdwSkip,
WINPR_ATTR_UNUSED DWORD* pdwFlags)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptStringToBinaryA(WINPR_ATTR_UNUSED LPCSTR pszString, WINPR_ATTR_UNUSED DWORD cchString,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED BYTE* pbBinary,
WINPR_ATTR_UNUSED DWORD* pcbBinary, WINPR_ATTR_UNUSED DWORD* pdwSkip,
WINPR_ATTR_UNUSED DWORD* pdwFlags)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptBinaryToStringW(WINPR_ATTR_UNUSED CONST BYTE* pbBinary, WINPR_ATTR_UNUSED DWORD cbBinary,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED LPWSTR pszString,
WINPR_ATTR_UNUSED DWORD* pcchString)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptBinaryToStringA(WINPR_ATTR_UNUSED CONST BYTE* pbBinary, WINPR_ATTR_UNUSED DWORD cbBinary,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED LPSTR pszString,
WINPR_ATTR_UNUSED DWORD* pcchString)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
#endif

View File

@@ -0,0 +1,43 @@
/**
* WinPR: Windows Portable Runtime
* Cryptography API (CryptoAPI)
*
* Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_CRYPTO_PRIVATE_H
#define WINPR_CRYPTO_PRIVATE_H
#ifndef _WIN32
typedef struct
{
BYTE* pData;
DWORD cbData;
DWORD dwFlags;
BYTE key[32];
BYTE iv[32];
BYTE salt[8];
} WINPR_PROTECTED_MEMORY_BLOCK;
typedef struct
{
LPCSTR lpszStoreProvider;
DWORD dwMsgAndCertEncodingType;
} WINPR_CERTSTORE;
#endif
#endif /* WINPR_CRYPTO_PRIVATE_H */

View File

@@ -0,0 +1,776 @@
/**
* WinPR: Windows Portable Runtime
*
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/crypto.h>
#ifdef WITH_OPENSSL
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/core_names.h>
#endif
#endif
#ifdef WITH_MBEDTLS
#ifdef MBEDTLS_MD5_C
#include <mbedtls/md5.h>
#endif
#include <mbedtls/sha1.h>
#include <mbedtls/md.h>
#if MBEDTLS_VERSION_MAJOR < 3
#define mbedtls_md_info_from_ctx(_ctx) (_ctx->md_info)
#endif
#endif
#if defined(WITH_INTERNAL_MD4)
#include "md4.h"
#endif
#if defined(WITH_INTERNAL_MD5)
#include "md5.h"
#include "hmac_md5.h"
#endif
#include "../log.h"
#define TAG WINPR_TAG("crypto.hash")
/**
* HMAC
*/
#ifdef WITH_OPENSSL
extern const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md);
#endif
#ifdef WITH_OPENSSL
const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md)
{
const char* name = winpr_md_type_to_string(md);
if (!name)
return nullptr;
return EVP_get_digestbyname(name);
}
#endif
#ifdef WITH_MBEDTLS
mbedtls_md_type_t winpr_mbedtls_get_md_type(int md)
{
mbedtls_md_type_t type = MBEDTLS_MD_NONE;
switch (md)
{
case WINPR_MD_MD5:
type = MBEDTLS_MD_MD5;
break;
case WINPR_MD_SHA1:
type = MBEDTLS_MD_SHA1;
break;
case WINPR_MD_SHA224:
type = MBEDTLS_MD_SHA224;
break;
case WINPR_MD_SHA256:
type = MBEDTLS_MD_SHA256;
break;
case WINPR_MD_SHA384:
type = MBEDTLS_MD_SHA384;
break;
case WINPR_MD_SHA512:
type = MBEDTLS_MD_SHA512;
break;
}
return type;
}
#endif
struct hash_map
{
const char* name;
WINPR_MD_TYPE md;
};
static const struct hash_map hashes[] = {
{ "md2", WINPR_MD_MD2 }, { "md4", WINPR_MD_MD4 },
{ "md5", WINPR_MD_MD5 }, { "sha1", WINPR_MD_SHA1 },
{ "sha224", WINPR_MD_SHA224 }, { "sha256", WINPR_MD_SHA256 },
{ "sha384", WINPR_MD_SHA384 }, { "sha512", WINPR_MD_SHA512 },
{ "sha3_224", WINPR_MD_SHA3_224 }, { "sha3_256", WINPR_MD_SHA3_256 },
{ "sha3_384", WINPR_MD_SHA3_384 }, { "sha3_512", WINPR_MD_SHA3_512 },
{ "shake128", WINPR_MD_SHAKE128 }, { "shake256", WINPR_MD_SHAKE256 },
{ nullptr, WINPR_MD_NONE }
};
WINPR_MD_TYPE winpr_md_type_from_string(const char* name)
{
const struct hash_map* cur = hashes;
while (cur->name)
{
if (_stricmp(cur->name, name) == 0)
return cur->md;
cur++;
}
return WINPR_MD_NONE;
}
const char* winpr_md_type_to_string(WINPR_MD_TYPE md)
{
const struct hash_map* cur = hashes;
while (cur->name)
{
if (cur->md == md)
return cur->name;
cur++;
}
return nullptr;
}
struct winpr_hmac_ctx_private_st
{
WINPR_MD_TYPE md;
#if defined(WITH_INTERNAL_MD5)
WINPR_HMAC_MD5_CTX hmac_md5;
#endif
#if defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC_CTX* xhmac;
#else
HMAC_CTX* hmac;
#endif
#endif
#if defined(WITH_MBEDTLS)
mbedtls_md_context_t hmac;
#endif
};
WINPR_HMAC_CTX* winpr_HMAC_New(void)
{
WINPR_HMAC_CTX* ctx = (WINPR_HMAC_CTX*)calloc(1, sizeof(WINPR_HMAC_CTX));
if (!ctx)
return nullptr;
#if defined(WITH_OPENSSL)
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
if (!(ctx->hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX))))
goto fail;
HMAC_CTX_init(ctx->hmac);
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
if (!(ctx->hmac = HMAC_CTX_new()))
goto fail;
#else
EVP_MAC* emac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
if (!emac)
goto fail;
ctx->xhmac = EVP_MAC_CTX_new(emac);
EVP_MAC_free(emac);
if (!ctx->xhmac)
goto fail;
#endif
#elif defined(WITH_MBEDTLS)
mbedtls_md_init(&ctx->hmac);
#endif
return ctx;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
winpr_HMAC_Free(ctx);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const void* key, size_t keylen)
{
WINPR_ASSERT(ctx);
ctx->md = md;
switch (ctx->md)
{
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
hmac_md5_init(&ctx->hmac_md5, key, keylen);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
char* hash = WINPR_CAST_CONST_PTR_AWAY(winpr_md_type_to_string(md), char*);
if (!ctx->xhmac)
return FALSE;
const char* param_name = OSSL_MAC_PARAM_DIGEST;
const OSSL_PARAM param[] = { OSSL_PARAM_construct_utf8_string(param_name, hash, 0),
OSSL_PARAM_construct_end() };
return EVP_MAC_init(ctx->xhmac, key, keylen, param) == 1;
#else
HMAC_CTX* hmac = ctx->hmac;
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
if (!evp || !hmac)
return FALSE;
if (keylen > INT_MAX)
return FALSE;
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
HMAC_Init_ex(hmac, key, (int)keylen, evp, nullptr); /* no return value on OpenSSL 0.9.x */
return TRUE;
#else
if (HMAC_Init_ex(hmac, key, (int)keylen, evp, nullptr) == 1)
return TRUE;
#endif
#endif
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* hmac = &ctx->hmac;
mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
if (!md_info || !hmac)
return FALSE;
if (mbedtls_md_info_from_ctx(hmac) != md_info)
{
mbedtls_md_free(hmac); /* can be called at any time after mbedtls_md_init */
if (mbedtls_md_setup(hmac, md_info, 1) != 0)
return FALSE;
}
if (mbedtls_md_hmac_starts(hmac, key, keylen) == 0)
return TRUE;
#endif
return FALSE;
}
BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const void* input, size_t ilen)
{
WINPR_ASSERT(ctx);
switch (ctx->md)
{
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
hmac_md5_update(&ctx->hmac_md5, input, ilen);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
return EVP_MAC_update(ctx->xhmac, input, ilen) == 1;
#else
HMAC_CTX* hmac = ctx->hmac;
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */
return TRUE;
#else
if (HMAC_Update(hmac, input, ilen) == 1)
return TRUE;
#endif
#endif
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* mdctx = &ctx->hmac;
if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0)
return TRUE;
#endif
return FALSE;
}
BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, void* output, size_t olen)
{
WINPR_ASSERT(ctx);
switch (ctx->md)
{
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
if (olen < WINPR_MD5_DIGEST_LENGTH)
return FALSE;
hmac_md5_finalize(&ctx->hmac_md5, output);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
const int rc = EVP_MAC_final(ctx->xhmac, output, nullptr, olen);
return (rc == 1);
#else
HMAC_CTX* hmac = ctx->hmac;
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
HMAC_Final(hmac, output, nullptr); /* no return value on OpenSSL 0.9.x */
return TRUE;
#else
if (HMAC_Final(hmac, output, nullptr) == 1)
return TRUE;
#endif
#endif
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* mdctx = &ctx->hmac;
if (mbedtls_md_hmac_finish(mdctx, output) == 0)
return TRUE;
#endif
return FALSE;
}
void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx)
{
if (!ctx)
return;
#if defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_MAC_CTX_free(ctx->xhmac);
#else
HMAC_CTX* hmac = ctx->hmac;
if (hmac)
{
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
HMAC_CTX_cleanup(hmac);
free(hmac);
#else
HMAC_CTX_free(hmac);
#endif
}
#endif
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* hmac = &ctx->hmac;
if (hmac)
mbedtls_md_free(hmac);
#endif
free(ctx);
}
BOOL winpr_HMAC(WINPR_MD_TYPE md, const void* key, size_t keylen, const void* input, size_t ilen,
void* output, size_t olen)
{
BOOL result = FALSE;
WINPR_HMAC_CTX* ctx = winpr_HMAC_New();
if (!ctx)
return FALSE;
if (!winpr_HMAC_Init(ctx, md, key, keylen))
goto out;
if (!winpr_HMAC_Update(ctx, input, ilen))
goto out;
if (!winpr_HMAC_Final(ctx, output, olen))
goto out;
result = TRUE;
out:
winpr_HMAC_Free(ctx);
return result;
}
/**
* Generic Digest API
*/
struct winpr_digest_ctx_private_st
{
WINPR_MD_TYPE md;
#if defined(WITH_INTERNAL_MD4)
WINPR_MD4_CTX md4;
#endif
#if defined(WITH_INTERNAL_MD5)
WINPR_MD5_CTX md5;
#endif
#if defined(WITH_OPENSSL)
EVP_MD_CTX* mdctx;
#endif
#if defined(WITH_MBEDTLS)
mbedtls_md_context_t* mdctx;
#endif
};
WINPR_DIGEST_CTX* winpr_Digest_New(void)
{
WINPR_DIGEST_CTX* ctx = calloc(1, sizeof(WINPR_DIGEST_CTX));
if (!ctx)
return nullptr;
#if defined(WITH_OPENSSL)
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
ctx->mdctx = EVP_MD_CTX_create();
#else
ctx->mdctx = EVP_MD_CTX_new();
#endif
if (!ctx->mdctx)
goto fail;
#elif defined(WITH_MBEDTLS)
ctx->mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t));
if (!ctx->mdctx)
goto fail;
mbedtls_md_init(ctx->mdctx);
#endif
return ctx;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
winpr_Digest_Free(ctx);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
#if defined(WITH_OPENSSL)
static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp)
{
WINPR_ASSERT(ctx);
EVP_MD_CTX* mdctx = ctx->mdctx;
if (!mdctx || !evp)
return FALSE;
if (EVP_DigestInit_ex(mdctx, evp, nullptr) != 1)
{
WLog_ERR(TAG, "Failed to initialize digest %s", winpr_md_type_to_string(ctx->md));
return FALSE;
}
return TRUE;
}
#elif defined(WITH_MBEDTLS)
static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
{
WINPR_ASSERT(ctx);
mbedtls_md_context_t* mdctx = ctx->mdctx;
mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
if (!md_info)
return FALSE;
if (mbedtls_md_info_from_ctx(mdctx) != md_info)
{
mbedtls_md_free(mdctx); /* can be called at any time after mbedtls_md_init */
if (mbedtls_md_setup(mdctx, md_info, 0) != 0)
return FALSE;
}
if (mbedtls_md_starts(mdctx) != 0)
return FALSE;
return TRUE;
}
#endif
BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
{
WINPR_ASSERT(ctx);
ctx->md = md;
switch (md)
{
case WINPR_MD_MD5:
{
#if defined(WITH_INTERNAL_MD5)
winpr_MD5_Init(&ctx->md5);
return TRUE;
#elif defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if !defined(WITH_INTERNAL_MD5)
if (md == WINPR_MD_MD5)
{
EVP_MD* md5 = EVP_MD_fetch(nullptr, "MD5", "fips=no");
BOOL rc = winpr_Digest_Init_Internal(ctx, md5);
EVP_MD_free(md5);
return rc;
}
#endif
#endif
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
return winpr_Digest_Init_Internal(ctx, evp);
#elif defined(WITH_MBEDTLS)
return winpr_Digest_Init_Internal(ctx, md);
#endif
}
default:
WLog_ERR(TAG, "Invalid FIPS digest %s requested", winpr_md_type_to_string(md));
return FALSE;
}
}
BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
{
WINPR_ASSERT(ctx);
ctx->md = md;
switch (md)
{
#if defined(WITH_INTERNAL_MD4)
case WINPR_MD_MD4:
winpr_MD4_Init(&ctx->md4);
return TRUE;
#endif
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
winpr_MD5_Init(&ctx->md5);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
return winpr_Digest_Init_Internal(ctx, evp);
#else
return winpr_Digest_Init_Internal(ctx, md);
#endif
}
BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const void* input, size_t ilen)
{
WINPR_ASSERT(ctx);
switch (ctx->md)
{
#if defined(WITH_INTERNAL_MD4)
case WINPR_MD_MD4:
winpr_MD4_Update(&ctx->md4, input, ilen);
return TRUE;
#endif
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
winpr_MD5_Update(&ctx->md5, input, ilen);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
EVP_MD_CTX* mdctx = ctx->mdctx;
return EVP_DigestUpdate(mdctx, input, ilen) == 1;
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* mdctx = ctx->mdctx;
if (mbedtls_md_update(mdctx, input, ilen) != 0)
return FALSE;
#endif
return TRUE;
}
BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, void* output, WINPR_ATTR_UNUSED size_t olen)
{
WINPR_ASSERT(ctx);
switch (ctx->md)
{
#if defined(WITH_INTERNAL_MD4)
case WINPR_MD_MD4:
if (olen < WINPR_MD4_DIGEST_LENGTH)
return FALSE;
winpr_MD4_Final(output, &ctx->md4);
return TRUE;
#endif
#if defined(WITH_INTERNAL_MD5)
case WINPR_MD_MD5:
if (olen < WINPR_MD5_DIGEST_LENGTH)
return FALSE;
winpr_MD5_Final(output, &ctx->md5);
return TRUE;
#endif
default:
break;
}
#if defined(WITH_OPENSSL)
EVP_MD_CTX* mdctx = ctx->mdctx;
return EVP_DigestFinal_ex(mdctx, output, nullptr) == 1;
#elif defined(WITH_MBEDTLS)
mbedtls_md_context_t* mdctx = ctx->mdctx;
if (mbedtls_md_finish(mdctx, output) == 0)
return TRUE;
#endif
return FALSE;
}
BOOL winpr_DigestSign_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md, void* key)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
if (!evp)
return FALSE;
const int rdsi = EVP_DigestSignInit(ctx->mdctx, nullptr, evp, nullptr, key);
return (rdsi > 0);
#else
return FALSE;
#endif
}
BOOL winpr_DigestSign_Update(WINPR_DIGEST_CTX* ctx, const void* input, size_t ilen)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
EVP_MD_CTX* mdctx = ctx->mdctx;
return (EVP_DigestSignUpdate(mdctx, input, ilen) == 1);
#else
return FALSE;
#endif
}
BOOL winpr_DigestSign_Final(WINPR_DIGEST_CTX* ctx, void* output, size_t* piolen)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
EVP_MD_CTX* mdctx = ctx->mdctx;
return EVP_DigestSignFinal(mdctx, output, piolen) == 1;
#else
return FALSE;
#endif
}
void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx)
{
if (!ctx)
return;
#if defined(WITH_OPENSSL)
if (ctx->mdctx)
{
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
EVP_MD_CTX_destroy(ctx->mdctx);
#else
EVP_MD_CTX_free(ctx->mdctx);
#endif
}
#elif defined(WITH_MBEDTLS)
if (ctx->mdctx)
{
mbedtls_md_free(ctx->mdctx);
free(ctx->mdctx);
}
#endif
free(ctx);
}
BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const void* input, size_t ilen, void* output,
size_t olen)
{
BOOL result = FALSE;
WINPR_DIGEST_CTX* ctx = winpr_Digest_New();
if (!ctx)
return FALSE;
if (!winpr_Digest_Init_Allow_FIPS(ctx, md))
goto out;
if (!winpr_Digest_Update(ctx, input, ilen))
goto out;
if (!winpr_Digest_Final(ctx, output, olen))
goto out;
result = TRUE;
out:
winpr_Digest_Free(ctx);
return result;
}
BOOL winpr_Digest(WINPR_MD_TYPE md, const void* input, size_t ilen, void* output, size_t olen)
{
BOOL result = FALSE;
WINPR_DIGEST_CTX* ctx = winpr_Digest_New();
if (!ctx)
return FALSE;
if (!winpr_Digest_Init(ctx, md))
goto out;
if (!winpr_Digest_Update(ctx, input, ilen))
goto out;
if (!winpr_Digest_Final(ctx, output, olen))
goto out;
result = TRUE;
out:
winpr_Digest_Free(ctx);
return result;
}

View File

@@ -0,0 +1,56 @@
#include <assert.h>
#include <string.h>
#include "hmac_md5.h"
#include "md5.h"
void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* key, size_t key_len)
{
const WINPR_HMAC_MD5_CTX empty = WINPR_C_ARRAY_INIT;
unsigned char k_ipad[KEY_IOPAD_SIZE] = WINPR_C_ARRAY_INIT;
unsigned char k_opad[KEY_IOPAD_SIZE] = WINPR_C_ARRAY_INIT;
assert(ctx);
*ctx = empty;
if (key_len <= KEY_IOPAD_SIZE)
{
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
}
else
{
WINPR_MD5_CTX lctx = WINPR_C_ARRAY_INIT;
winpr_MD5_Init(&lctx);
winpr_MD5_Update(&lctx, key, key_len);
winpr_MD5_Final(k_ipad, &lctx);
memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE);
}
for (size_t i = 0; i < KEY_IOPAD_SIZE; i++)
{
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
winpr_MD5_Init(&ctx->icontext);
winpr_MD5_Update(&ctx->icontext, k_ipad, KEY_IOPAD_SIZE);
winpr_MD5_Init(&ctx->ocontext);
winpr_MD5_Update(&ctx->ocontext, k_opad, KEY_IOPAD_SIZE);
}
void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* text, size_t text_len)
{
assert(ctx);
winpr_MD5_Update(&ctx->icontext, text, text_len);
}
void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac)
{
assert(ctx);
winpr_MD5_Final(hmac, &ctx->icontext);
winpr_MD5_Update(&ctx->ocontext, hmac, 16);
winpr_MD5_Final(hmac, &ctx->ocontext);
}

View File

@@ -0,0 +1,19 @@
#ifndef WINPR_HMAC_MD5
#define WINPR_HMAC_MD5
#include <stddef.h>
#include "md5.h"
#define KEY_IOPAD_SIZE 64
typedef struct
{
WINPR_MD5_CTX icontext;
WINPR_MD5_CTX ocontext;
} WINPR_HMAC_MD5_CTX;
void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* key, size_t key_len);
void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* text, size_t text_len);
void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac);
#endif

View File

@@ -0,0 +1,271 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#include <string.h>
#include "md4.h"
/*
* The basic MD4 functions.
*
* F and G are optimized compared to their RFC 1320 definitions, with the
* optimization for F borrowed from Colin Plumb's MD5 implementation.
*/
static inline winpr_MD4_u32plus F(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return ((z) ^ ((x) & ((y) ^ (z))));
}
static inline winpr_MD4_u32plus G(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return (((x) & ((y) | (z))) | ((y) & (z)));
}
static inline winpr_MD4_u32plus H(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return ((x) ^ (y) ^ (z));
}
/*
* The MD4 transformation for all three rounds.
*/
#define STEP(f, a, b, c, d, x, s) \
(a) += f((b), (c), (d)) + (x); \
(a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s))));
/*
* SET reads 4 input bytes in little-endian byte order and stores them in a
* properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned memory
* accesses is just an optimization. Nothing will break if it fails to detect
* a suitable architecture.
*
* Unfortunately, this optimization may be a C strict aliasing rules violation
* if the caller's data buffer has effective type that cannot be aliased by
* winpr_MD4_u32plus. In practice, this problem may occur if these MD4 routines are
* inlined into a calling function, or with future and dangerously advanced
* link-time optimizations. For the time being, keeping these MD4 routines in
* their own translation unit avoids the problem.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) (*(const winpr_MD4_u32plus*)&ptr[4ULL * (n)])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = (winpr_MD4_u32plus)ptr[4ULL * (n)] | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 1] << 8) | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 2] << 16) | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 3] << 24))
#define GET(n) (ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update the bit
* counters. There are no alignment requirements.
*/
static const void* body(WINPR_MD4_CTX* ctx, const void* data, size_t size)
{
const winpr_MD4_u32plus ac1 = 0x5a827999;
const winpr_MD4_u32plus ac2 = 0x6ed9eba1;
const unsigned char* ptr = (const unsigned char*)data;
winpr_MD4_u32plus a = ctx->a;
winpr_MD4_u32plus b = ctx->b;
winpr_MD4_u32plus c = ctx->c;
winpr_MD4_u32plus d = ctx->d;
do
{
const winpr_MD4_u32plus saved_a = a;
const winpr_MD4_u32plus saved_b = b;
const winpr_MD4_u32plus saved_c = c;
const winpr_MD4_u32plus saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 3)
STEP(F, d, a, b, c, SET(1), 7)
STEP(F, c, d, a, b, SET(2), 11)
STEP(F, b, c, d, a, SET(3), 19)
STEP(F, a, b, c, d, SET(4), 3)
STEP(F, d, a, b, c, SET(5), 7)
STEP(F, c, d, a, b, SET(6), 11)
STEP(F, b, c, d, a, SET(7), 19)
STEP(F, a, b, c, d, SET(8), 3)
STEP(F, d, a, b, c, SET(9), 7)
STEP(F, c, d, a, b, SET(10), 11)
STEP(F, b, c, d, a, SET(11), 19)
STEP(F, a, b, c, d, SET(12), 3)
STEP(F, d, a, b, c, SET(13), 7)
STEP(F, c, d, a, b, SET(14), 11)
STEP(F, b, c, d, a, SET(15), 19)
/* Round 2 */
STEP(G, a, b, c, d, GET(0) + ac1, 3)
STEP(G, d, a, b, c, GET(4) + ac1, 5)
STEP(G, c, d, a, b, GET(8) + ac1, 9)
STEP(G, b, c, d, a, GET(12) + ac1, 13)
STEP(G, a, b, c, d, GET(1) + ac1, 3)
STEP(G, d, a, b, c, GET(5) + ac1, 5)
STEP(G, c, d, a, b, GET(9) + ac1, 9)
STEP(G, b, c, d, a, GET(13) + ac1, 13)
STEP(G, a, b, c, d, GET(2) + ac1, 3)
STEP(G, d, a, b, c, GET(6) + ac1, 5)
STEP(G, c, d, a, b, GET(10) + ac1, 9)
STEP(G, b, c, d, a, GET(14) + ac1, 13)
STEP(G, a, b, c, d, GET(3) + ac1, 3)
STEP(G, d, a, b, c, GET(7) + ac1, 5)
STEP(G, c, d, a, b, GET(11) + ac1, 9)
STEP(G, b, c, d, a, GET(15) + ac1, 13)
/* Round 3 */
STEP(H, a, b, c, d, GET(0) + ac2, 3)
STEP(H, d, a, b, c, GET(8) + ac2, 9)
STEP(H, c, d, a, b, GET(4) + ac2, 11)
STEP(H, b, c, d, a, GET(12) + ac2, 15)
STEP(H, a, b, c, d, GET(2) + ac2, 3)
STEP(H, d, a, b, c, GET(10) + ac2, 9)
STEP(H, c, d, a, b, GET(6) + ac2, 11)
STEP(H, b, c, d, a, GET(14) + ac2, 15)
STEP(H, a, b, c, d, GET(1) + ac2, 3)
STEP(H, d, a, b, c, GET(9) + ac2, 9)
STEP(H, c, d, a, b, GET(5) + ac2, 11)
STEP(H, b, c, d, a, GET(13) + ac2, 15)
STEP(H, a, b, c, d, GET(3) + ac2, 3)
STEP(H, d, a, b, c, GET(11) + ac2, 9)
STEP(H, c, d, a, b, GET(7) + ac2, 11)
STEP(H, b, c, d, a, GET(15) + ac2, 15)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
void winpr_MD4_Init(WINPR_MD4_CTX* ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
}
void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, size_t size)
{
winpr_MD4_u32plus saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
size_t used = saved_lo & 0x3f;
if (used)
{
size_t available = 64 - used;
if (size < available)
{
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char*)data + available;
size -= available;
body(ctx, ctx->buffer, 64);
}
if (size >= 64)
{
data = body(ctx, data, size & ~(size_t)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
static inline void mdOUT(unsigned char* dst, winpr_MD4_u32plus src)
{
(dst)[0] = (unsigned char)(src);
(dst)[1] = (unsigned char)((src) >> 8);
(dst)[2] = (unsigned char)((src) >> 16);
(dst)[3] = (unsigned char)((src) >> 24);
}
void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx)
{
size_t used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
size_t available = 64 - used;
if (available < 8)
{
memset(&ctx->buffer[used], 0, available);
body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->buffer[used], 0, available - 8);
ctx->lo <<= 3;
mdOUT(&ctx->buffer[56], ctx->lo);
mdOUT(&ctx->buffer[60], ctx->hi);
body(ctx, ctx->buffer, 64);
mdOUT(&result[0], ctx->a);
mdOUT(&result[4], ctx->b);
mdOUT(&result[8], ctx->c);
mdOUT(&result[12], ctx->d);
memset(ctx, 0, sizeof(*ctx));
}

View File

@@ -0,0 +1,46 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md4.c for more information.
*/
#if !defined(WINPR_MD4_H)
#define WINPR_MD4_H
#include <winpr/wtypes.h>
/* Any 32-bit or wider unsigned integer data type will do */
typedef UINT32 winpr_MD4_u32plus;
typedef struct
{
winpr_MD4_u32plus lo, hi;
winpr_MD4_u32plus a, b, c, d;
unsigned char buffer[64];
winpr_MD4_u32plus block[16];
} WINPR_MD4_CTX;
extern void winpr_MD4_Init(WINPR_MD4_CTX* ctx);
extern void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, size_t size);
extern void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx);
#endif

View File

@@ -0,0 +1,296 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#include <string.h>
#include "md5.h"
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
static inline winpr_MD5_u32plus F(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((z) ^ ((x) & ((y) ^ (z))));
}
static inline winpr_MD5_u32plus G(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((y) ^ ((z) & ((x) ^ (y))));
}
static inline winpr_MD5_u32plus H(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return (((x) ^ (y)) ^ (z));
}
static inline winpr_MD5_u32plus H2(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((x) ^ ((y) ^ (z)));
}
static inline winpr_MD5_u32plus I(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((y) ^ ((x) | ~(z)));
}
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them in a
* properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned memory
* accesses is just an optimization. Nothing will break if it fails to detect
* a suitable architecture.
*
* Unfortunately, this optimization may be a C strict aliasing rules violation
* if the caller's data buffer has effective type that cannot be aliased by
* MD5_u32plus. In practice, this problem may occur if these MD5 routines are
* inlined into a calling function, or with future and dangerously advanced
* link-time optimizations. For the time being, keeping these MD5 routines in
* their own translation unit avoids the problem.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) (*(const winpr_MD5_u32plus*)&ptr[4ULL * (n)])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = (winpr_MD5_u32plus)ptr[4ULL * (n)] | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 1] << 8) | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 2] << 16) | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 3] << 24))
#define GET(n) (ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update the bit
* counters. There are no alignment requirements.
*/
static const void* body(WINPR_MD5_CTX* ctx, const void* data, size_t size)
{
const unsigned char* ptr = (const unsigned char*)data;
winpr_MD5_u32plus a = ctx->a;
winpr_MD5_u32plus b = ctx->b;
winpr_MD5_u32plus c = ctx->c;
winpr_MD5_u32plus d = ctx->d;
do
{
const winpr_MD5_u32plus saved_a = a;
const winpr_MD5_u32plus saved_b = b;
const winpr_MD5_u32plus saved_c = c;
const winpr_MD5_u32plus saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
void winpr_MD5_Init(WINPR_MD5_CTX* ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
}
void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, size_t size)
{
winpr_MD5_u32plus saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
size_t used = saved_lo & 0x3f;
if (used)
{
size_t available = 64 - used;
if (size < available)
{
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char*)data + available;
size -= available;
body(ctx, ctx->buffer, 64);
}
if (size >= 64)
{
data = body(ctx, data, size & ~(size_t)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
static inline void mdOUT(unsigned char* dst, winpr_MD5_u32plus src)
{
(dst)[0] = (unsigned char)(src);
(dst)[1] = (unsigned char)((src) >> 8);
(dst)[2] = (unsigned char)((src) >> 16);
(dst)[3] = (unsigned char)((src) >> 24);
}
void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx)
{
size_t used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
size_t available = 64 - used;
if (available < 8)
{
memset(&ctx->buffer[used], 0, available);
body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->buffer[used], 0, available - 8);
ctx->lo <<= 3;
mdOUT(&ctx->buffer[56], ctx->lo);
mdOUT(&ctx->buffer[60], ctx->hi);
body(ctx, ctx->buffer, 64);
mdOUT(&result[0], ctx->a);
mdOUT(&result[4], ctx->b);
mdOUT(&result[8], ctx->c);
mdOUT(&result[12], ctx->d);
memset(ctx, 0, sizeof(*ctx));
}

View File

@@ -0,0 +1,48 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
#if !defined(WINPR_MD5_H)
#define WINPR_MD5_H
#include <winpr/wtypes.h>
/* Any 32-bit or wider unsigned integer data type will do */
typedef UINT32 winpr_MD5_u32plus;
typedef struct
{
winpr_MD5_u32plus lo, hi;
winpr_MD5_u32plus a, b, c, d;
unsigned char buffer[64];
winpr_MD5_u32plus block[16];
} WINPR_MD5_CTX;
extern void winpr_MD5_Init(WINPR_MD5_CTX* ctx);
extern void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, size_t size);
extern void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx);
#endif

View File

@@ -0,0 +1,83 @@
/**
* WinPR: Windows Portable Runtime
*
* Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/crypto.h>
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
#include <openssl/rand.h>
#endif
#ifdef WITH_MBEDTLS
#include <mbedtls/md.h>
#include <mbedtls/entropy.h>
#ifdef MBEDTLS_HAVEGE_C
#include <mbedtls/havege.h>
#endif
#include <mbedtls/hmac_drbg.h>
#endif
int winpr_RAND(void* output, size_t len)
{
#if defined(WITH_OPENSSL)
if (len > INT_MAX)
return -1;
if (RAND_bytes(output, (int)len) != 1)
return -1;
#elif defined(WITH_MBEDTLS)
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_state hs;
mbedtls_havege_init(&hs);
if (mbedtls_havege_random(&hs, output, len) != 0)
return -1;
mbedtls_havege_free(&hs);
#else
int status;
mbedtls_entropy_context entropy;
mbedtls_hmac_drbg_context hmac_drbg;
const mbedtls_md_info_t* md_info;
mbedtls_entropy_init(&entropy);
mbedtls_hmac_drbg_init(&hmac_drbg);
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
if ((status = mbedtls_hmac_drbg_seed(&hmac_drbg, md_info, mbedtls_entropy_func, &entropy,
nullptr, 0)) != 0)
return -1;
status = mbedtls_hmac_drbg_random(&hmac_drbg, output, len);
mbedtls_hmac_drbg_free(&hmac_drbg);
mbedtls_entropy_free(&entropy);
if (status != 0)
return -1;
#endif
#endif
return 0;
}
int winpr_RAND_pseudo(void* output, size_t len)
{
return winpr_RAND(output, len);
}

View File

@@ -0,0 +1,89 @@
/**
* WinPR: Windows Portable Runtime
* RC4 implementation for RDP
*
* Copyright 2023 Armin Novak <anovak@thincast.com>
* Copyright 2023 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/cast.h>
#include "rc4.h"
#define CTX_SIZE 256
struct winpr_int_rc4_ctx
{
size_t i;
size_t j;
BYTE s[CTX_SIZE];
BYTE t[CTX_SIZE];
};
static void swap(BYTE* p1, BYTE* p2)
{
BYTE t = *p1;
*p1 = *p2;
*p2 = t;
}
winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength)
{
winpr_int_RC4_CTX* ctx = calloc(1, sizeof(winpr_int_RC4_CTX));
if (!ctx)
return nullptr;
for (size_t i = 0; i < CTX_SIZE; i++)
{
ctx->s[i] = WINPR_ASSERTING_INT_CAST(BYTE, i);
ctx->t[i] = key[i % keylength];
}
size_t j = 0;
for (size_t i = 0; i < CTX_SIZE; i++)
{
j = (j + ctx->s[i] + ctx->t[i]) % CTX_SIZE;
swap(&ctx->s[i], &ctx->s[j]);
}
return ctx;
}
void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx)
{
free(ctx);
}
BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output)
{
WINPR_ASSERT(ctx);
size_t t1 = ctx->i;
size_t t2 = ctx->j;
for (size_t i = 0; i < length; i++)
{
t1 = (t1 + 1) % CTX_SIZE;
t2 = (t2 + ctx->s[t1]) % CTX_SIZE;
swap(&ctx->s[t1], &ctx->s[t2]);
const size_t idx = ((size_t)ctx->s[t1] + ctx->s[t2]) % CTX_SIZE;
const BYTE val = ctx->s[idx];
const BYTE out = *input++ ^ val;
*output++ = out;
}
ctx->i = t1;
ctx->j = t2;
return TRUE;
}

View File

@@ -0,0 +1,35 @@
/**
* WinPR: Windows Portable Runtime
* RC4 implementation for RDP
*
* Copyright 2023 Armin Novak <anovak@thincast.com>
* Copyright 2023 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_RC4_H
#define WINPR_RC4_H
#include <winpr/wtypes.h>
#include <winpr/winpr.h>
typedef struct winpr_int_rc4_ctx winpr_int_RC4_CTX;
void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx);
WINPR_ATTR_MALLOC(winpr_int_rc4_free, 1)
WINPR_ATTR_NODISCARD
winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength);
BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output);
#endif

View File

@@ -0,0 +1,29 @@
set(MODULE_NAME "TestCrypto")
set(MODULE_PREFIX "TEST_CRYPTO")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestCryptoHash.c TestCryptoRand.c TestCryptoCipher.c TestCryptoProtectData.c
TestCryptoProtectMemory.c TestCryptoCertEnumCertificatesInStore.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
if(WIN32)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} secur32 crypt32 cryptui)
endif()
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,88 @@
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/crypto.h>
#ifdef _WIN32
//#define WITH_CRYPTUI 1
#endif
#ifdef WITH_CRYPTUI
#include <cryptuiapi.h>
#endif
int TestCryptoCertEnumCertificatesInStore(int argc, char* argv[])
{
int index = 0;
DWORD status = 0;
LPTSTR pszNameString = nullptr;
HCERTSTORE hCertStore = nullptr;
PCCERT_CONTEXT pCertContext = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/**
* System Store Locations:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa388136/
*/
/**
* Requires elevated rights:
* hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
* CERT_SYSTEM_STORE_LOCAL_MACHINE, _T("Remote Desktop"));
*/
hCertStore = CertOpenSystemStore(0, _T("MY"));
// hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
// CERT_SYSTEM_STORE_CURRENT_USER, _T("MY"));
if (!hCertStore)
{
printf("Failed to open system store\n");
return -1;
}
index = 0;
while ((pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)))
{
status =
CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
if (status == 0)
return -1;
pszNameString = (LPTSTR)calloc(status, sizeof(TCHAR));
if (!pszNameString)
{
printf("Unable to allocate memory\n");
return -1;
}
status = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr,
pszNameString, status);
if (status == 0)
{
free(pszNameString);
return -1;
}
_tprintf(_T("Certificate #%d: %s\n"), index++, pszNameString);
free(pszNameString);
#ifdef WITH_CRYPTUI
CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, pCertContext, nullptr, nullptr, 0,
nullptr);
#endif
}
if (!CertCloseStore(hCertStore, 0))
{
printf("Failed to close system store\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,251 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
#include <winpr/ssl.h>
static BOOL test_crypto_cipher_aes_128_cbc(BOOL ex)
{
BOOL result = FALSE;
BYTE key[16] = "0123456789abcdeF";
BYTE iv[16] = "1234567887654321";
BYTE ibuf[1024] = WINPR_C_ARRAY_INIT;
BYTE obuf[1024] = WINPR_C_ARRAY_INIT;
size_t ilen = 0;
size_t olen = 0;
size_t xlen = 0;
const char plaintext[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
"eiusmod tempor incididunt ut labore et dolore magna aliqua.";
/* encrypt */
WINPR_CIPHER_CTX* ctx = nullptr;
if (ex)
ctx = winpr_Cipher_NewEx(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, sizeof(key), iv,
sizeof(iv));
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
else
ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, iv);
#endif
if (!ctx)
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __func__);
return FALSE;
}
ilen = strnlen(plaintext, sizeof(plaintext)) + 1;
memcpy(ibuf, plaintext, ilen);
ilen = ((ilen + 15) / 16) * 16;
olen = 0;
xlen = 0;
if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_Final (encrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
(void)fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (encrypt)\n",
__func__, xlen, ilen);
goto out;
}
winpr_Cipher_Free(ctx);
ctx = nullptr;
/* decrypt */
if (ex)
ctx = winpr_Cipher_NewEx(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, sizeof(key), iv,
sizeof(iv));
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
else
ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, iv);
#endif
if (!ctx)
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __func__);
return FALSE;
}
memset(ibuf, 0, sizeof(ibuf));
memcpy(ibuf, obuf, xlen);
memset(obuf, 0, sizeof(obuf));
ilen = xlen;
olen = 0;
xlen = 0;
if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_Final (decrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
(void)fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (decrypt)\n",
__func__, xlen, ilen);
goto out;
}
if (strcmp((const char*)obuf, plaintext) != 0)
{
(void)fprintf(stderr, "%s: error, decrypted data does not match plaintext\n", __func__);
goto out;
}
result = TRUE;
out:
winpr_Cipher_Free(ctx);
return result;
}
static const char TEST_RC4_KEY[] = "Key";
static const char TEST_RC4_PLAINTEXT[] = "Plaintext";
static const char TEST_RC4_CIPHERTEXT[] = "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3";
static BOOL test_crypto_cipher_rc4(void)
{
BOOL rc = FALSE;
WINPR_RC4_CTX* ctx = nullptr;
const size_t len = strnlen(TEST_RC4_PLAINTEXT, sizeof(TEST_RC4_PLAINTEXT));
BYTE* text = (BYTE*)calloc(1, len);
if (!text)
{
(void)fprintf(stderr, "%s: failed to allocate text buffer (len=%" PRIuz ")\n", __func__,
len);
goto out;
}
if ((ctx = winpr_RC4_New(TEST_RC4_KEY, strnlen(TEST_RC4_KEY, sizeof(TEST_RC4_KEY)))) == nullptr)
{
(void)fprintf(stderr, "%s: winpr_RC4_New failed\n", __func__);
goto out;
}
rc = winpr_RC4_Update(ctx, len, (const BYTE*)TEST_RC4_PLAINTEXT, text);
winpr_RC4_Free(ctx);
if (!rc)
{
(void)fprintf(stderr, "%s: winpr_RC4_Update failed\n", __func__);
goto out;
}
if (memcmp(text, TEST_RC4_CIPHERTEXT, len) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(text, len, FALSE);
expected = winpr_BinToHexString(TEST_RC4_CIPHERTEXT, len, FALSE);
(void)fprintf(stderr, "%s: unexpected RC4 ciphertext: Actual: %s Expected: %s\n", __func__,
actual, expected);
free(actual);
free(expected);
goto out;
}
rc = TRUE;
out:
free(text);
return rc;
}
static const BYTE* TEST_RAND_DATA =
(BYTE*)"\x1F\xC2\xEE\x4C\xA3\x66\x80\xA2\xCE\xFE\x56\xB4\x9E\x08\x30\x96"
"\x33\x6A\xA9\x6D\x36\xFD\x3C\xB7\x83\x04\x4E\x5E\xDC\x22\xCD\xF3"
"\x48\xDF\x3A\x2A\x61\xF1\xA8\xFA\x1F\xC6\xC7\x1B\x81\xB4\xE1\x0E"
"\xCB\xA2\xEF\xA1\x12\x4A\x83\xE5\x1D\x72\x1D\x2D\x26\xA8\x6B\xC0";
static const BYTE* TEST_CIPHER_KEY =
(BYTE*)"\x9D\x7C\xC0\xA1\x94\x3B\x07\x67\x2F\xD3\x83\x10\x51\x83\x38\x0E"
"\x1C\x74\x8C\x4E\x15\x79\xD6\xFF\xE2\xF0\x37\x7F\x8C\xD7\xD2\x13";
static const BYTE* TEST_CIPHER_IV =
(BYTE*)"\xFE\xE3\x9F\xF0\xD1\x5E\x37\x0C\xAB\xAB\x9B\x04\xF3\xDB\x99\x15";
static BOOL test_crypto_cipher_key(void)
{
int status = 0;
BYTE key[32] = WINPR_C_ARRAY_INIT;
BYTE iv[16] = WINPR_C_ARRAY_INIT;
BYTE salt[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
status = winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1, salt, TEST_RAND_DATA,
64, 4, key, iv);
if (status != 32 || memcmp(key, TEST_CIPHER_KEY, 32) != 0 ||
memcmp(iv, TEST_CIPHER_IV, 16) != 0)
{
char* akstr = nullptr;
char* ekstr = nullptr;
char* aivstr = nullptr;
char* eivstr = nullptr;
akstr = winpr_BinToHexString(key, 32, 0);
ekstr = winpr_BinToHexString(TEST_CIPHER_KEY, 32, 0);
aivstr = winpr_BinToHexString(iv, 16, 0);
eivstr = winpr_BinToHexString(TEST_CIPHER_IV, 16, 0);
(void)fprintf(stderr, "Unexpected EVP_BytesToKey Key: Actual: %s, Expected: %s\n", akstr,
ekstr);
(void)fprintf(stderr, "Unexpected EVP_BytesToKey IV : Actual: %s, Expected: %s\n", aivstr,
eivstr);
free(akstr);
free(ekstr);
free(aivstr);
free(eivstr);
}
return TRUE;
}
int TestCryptoCipher(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
if (!test_crypto_cipher_aes_128_cbc(TRUE))
return -1;
if (!test_crypto_cipher_aes_128_cbc(FALSE))
return -1;
if (!test_crypto_cipher_rc4())
return -1;
if (!test_crypto_cipher_key())
return -1;
return 0;
}

View File

@@ -0,0 +1,318 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
#include <winpr/ssl.h>
static const char TEST_MD5_DATA[] = "test";
static const BYTE TEST_MD5_HASH[] =
"\x09\x8f\x6b\xcd\x46\x21\xd3\x73\xca\xde\x4e\x83\x26\x27\xb4\xf6";
static BOOL test_crypto_hash_md5(void)
{
BOOL result = FALSE;
BYTE hash[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_MD5))
{
(void)fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
goto out;
}
if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_MD5_DATA,
strnlen(TEST_MD5_DATA, sizeof(TEST_MD5_DATA))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
(void)fprintf(stderr, "unexpected MD5 hash: Actual: %s Expected: %s\n", actual, expected);
free(actual);
free(expected);
goto out;
}
result = TRUE;
out:
winpr_Digest_Free(ctx);
return result;
}
static const char TEST_MD4_DATA[] = "test";
static const BYTE TEST_MD4_HASH[] =
"\xdb\x34\x6d\x69\x1d\x7a\xcc\x4d\xc2\x62\x5d\xb1\x9f\x9e\x3f\x52";
static BOOL test_crypto_hash_md4(void)
{
BOOL result = FALSE;
BYTE hash[WINPR_MD4_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_MD4))
{
(void)fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
goto out;
}
if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_MD4_DATA,
strnlen(TEST_MD4_DATA, sizeof(TEST_MD4_DATA))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD4_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH, FALSE);
(void)fprintf(stderr, "unexpected MD4 hash: Actual: %s Expected: %s\n", actual, expected);
free(actual);
free(expected);
goto out;
}
result = TRUE;
out:
winpr_Digest_Free(ctx);
return result;
}
static const char TEST_SHA1_DATA[] = "test";
static const BYTE TEST_SHA1_HASH[] =
"\xa9\x4a\x8f\xe5\xcc\xb1\x9b\xa6\x1c\x4c\x08\x73\xd3\x91\xe9\x87\x98\x2f\xbb\xd3";
static BOOL test_crypto_hash_sha1(void)
{
BOOL result = FALSE;
BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_SHA1))
{
(void)fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
goto out;
}
if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_SHA1_DATA,
strnlen(TEST_SHA1_DATA, sizeof(TEST_SHA1_DATA))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_SHA1_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
(void)fprintf(stderr, "unexpected SHA1 hash: Actual: %s Expected: %s\n", actual, expected);
free(actual);
free(expected);
goto out;
}
result = TRUE;
out:
winpr_Digest_Free(ctx);
return result;
}
static const char TEST_HMAC_MD5_DATA[] = "Hi There";
static const BYTE TEST_HMAC_MD5_KEY[] =
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
static const BYTE TEST_HMAC_MD5_HASH[] =
"\xb5\x79\x91\xa2\x20\x3d\x49\x2d\x73\xfb\x71\x43\xdf\xc5\x08\x28";
static BOOL test_crypto_hash_hmac_md5(void)
{
BYTE hash[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
WINPR_HMAC_CTX* ctx = nullptr;
BOOL result = FALSE;
if (!(ctx = winpr_HMAC_New()))
{
(void)fprintf(stderr, "%s: winpr_HMAC_New failed\n", __func__);
return FALSE;
}
if (!winpr_HMAC_Init(ctx, WINPR_MD_MD5, TEST_HMAC_MD5_KEY, WINPR_MD5_DIGEST_LENGTH))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Init failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA,
strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA,
strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
(void)fprintf(stderr, "unexpected HMAC-MD5 hash: Actual: %s Expected: %s\n", actual,
expected);
free(actual);
free(expected);
goto out;
}
result = TRUE;
out:
winpr_HMAC_Free(ctx);
return result;
}
static const char TEST_HMAC_SHA1_DATA[] = "Hi There";
static const BYTE TEST_HMAC_SHA1_KEY[] =
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
static const BYTE TEST_HMAC_SHA1_HASH[] =
"\xab\x23\x08\x2d\xca\x0c\x75\xea\xca\x60\x09\xc0\xb8\x8c\x2d\xf4\xf4\xbf\x88\xee";
static BOOL test_crypto_hash_hmac_sha1(void)
{
BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
WINPR_HMAC_CTX* ctx = nullptr;
BOOL result = FALSE;
if (!(ctx = winpr_HMAC_New()))
{
(void)fprintf(stderr, "%s: winpr_HMAC_New failed\n", __func__);
return FALSE;
}
if (!winpr_HMAC_Init(ctx, WINPR_MD_SHA1, TEST_HMAC_SHA1_KEY, WINPR_SHA1_DIGEST_LENGTH))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Init failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA,
strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA,
strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
(void)fprintf(stderr, "unexpected HMAC-SHA1 hash: Actual: %s Expected: %s\n", actual,
expected);
free(actual);
free(expected);
goto out;
}
result = TRUE;
out:
winpr_HMAC_Free(ctx);
return result;
}
int TestCryptoHash(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
if (!test_crypto_hash_md5())
return -1;
if (!test_crypto_hash_md4())
return -1;
if (!test_crypto_hash_sha1())
return -1;
if (!test_crypto_hash_hmac_md5())
return -1;
if (!test_crypto_hash_hmac_sha1())
return -1;
return 0;
}

View File

@@ -0,0 +1,10 @@
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/crypto.h>
int TestCryptoProtectData(int argc, char* argv[])
{
return 0;
}

View File

@@ -0,0 +1,55 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
#include <winpr/ssl.h>
#include <winpr/wlog.h>
static const char* SECRET_PASSWORD_TEST = "MySecretPassword123!";
int TestCryptoProtectMemory(int argc, char* argv[])
{
UINT32 cbPlainText = 0;
UINT32 cbCipherText = 0;
const char* pPlainText = nullptr;
BYTE* pCipherText = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
pPlainText = SECRET_PASSWORD_TEST;
cbPlainText = strlen(pPlainText) + 1;
cbCipherText = cbPlainText +
(CRYPTPROTECTMEMORY_BLOCK_SIZE - (cbPlainText % CRYPTPROTECTMEMORY_BLOCK_SIZE));
printf("cbPlainText: %" PRIu32 " cbCipherText: %" PRIu32 "\n", cbPlainText, cbCipherText);
pCipherText = (BYTE*)malloc(cbCipherText);
if (!pCipherText)
{
printf("Unable to allocate memory\n");
return -1;
}
CopyMemory(pCipherText, pPlainText, cbPlainText);
ZeroMemory(&pCipherText[cbPlainText], (cbCipherText - cbPlainText));
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
if (!CryptProtectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS))
{
printf("CryptProtectMemory failure\n");
return -1;
}
printf("PlainText: %s (cbPlainText = %" PRIu32 ", cbCipherText = %" PRIu32 ")\n", pPlainText,
cbPlainText, cbCipherText);
winpr_HexDump("crypto.test", WLOG_DEBUG, pCipherText, cbCipherText);
if (!CryptUnprotectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS))
{
printf("CryptUnprotectMemory failure\n");
return -1;
}
printf("Decrypted CipherText: %s\n", pCipherText);
SecureZeroMemory(pCipherText, cbCipherText);
free(pCipherText);
return 0;
}

View File

@@ -0,0 +1,27 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
int TestCryptoRand(int argc, char* argv[])
{
char* str = nullptr;
BYTE rnd[16] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (winpr_RAND(rnd, sizeof(rnd)) < 0)
return -1;
str = winpr_BinToHexString(rnd, sizeof(rnd), FALSE);
// (void)fprintf(stderr, "Rand: %s\n", str);
free(str);
if (memcmp(rnd, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0)
{
return -1;
}
return 0;
}

View File

@@ -0,0 +1,26 @@
# WinPR: Windows Portable Runtime
# libwinpr-dsparse cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(dsparse.c)
if(WIN32)
winpr_library_add_public(ntdsapi)
endif()
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "dsparse")
set(MINWIN_LONG_NAME "Domain Controller and Replication Management Functions")
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")

View File

@@ -0,0 +1,142 @@
/**
* WinPR: Windows Portable Runtime
* Active Directory Domain Services Parsing Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/dsparse.h>
#include <winpr/assert.h>
/**
* dsparse.dll:
*
* DsCrackSpnA
* DsCrackSpnW
* DsCrackUnquotedMangledRdnA
* DsCrackUnquotedMangledRdnW
* DsGetRdnW
* DsIsMangledDnA
* DsIsMangledDnW
* DsIsMangledRdnValueA
* DsIsMangledRdnValueW
* DsMakeSpnA
* DsMakeSpnW
* DsQuoteRdnValueA
* DsQuoteRdnValueW
* DsUnquoteRdnValueA
* DsUnquoteRdnValueW
*/
#if !defined(_WIN32) || defined(_UWP)
DWORD DsMakeSpnW(LPCWSTR ServiceClass, LPCWSTR ServiceName, LPCWSTR InstanceName,
USHORT InstancePort, LPCWSTR Referrer, DWORD* pcSpnLength, LPWSTR pszSpn)
{
DWORD res = ERROR_OUTOFMEMORY;
char* ServiceClassA = nullptr;
char* ServiceNameA = nullptr;
char* InstanceNameA = nullptr;
char* ReferrerA = nullptr;
char* pszSpnA = nullptr;
size_t length = 0;
WINPR_ASSERT(ServiceClass);
WINPR_ASSERT(ServiceName);
WINPR_ASSERT(pcSpnLength);
length = *pcSpnLength;
if ((length > 0) && pszSpn)
pszSpnA = calloc(length + 1, sizeof(char));
if (ServiceClass)
{
ServiceClassA = ConvertWCharToUtf8Alloc(ServiceClass, nullptr);
if (!ServiceClassA)
goto fail;
}
if (ServiceName)
{
ServiceNameA = ConvertWCharToUtf8Alloc(ServiceName, nullptr);
if (!ServiceNameA)
goto fail;
}
if (InstanceName)
{
InstanceNameA = ConvertWCharToUtf8Alloc(InstanceName, nullptr);
if (!InstanceNameA)
goto fail;
}
if (Referrer)
{
ReferrerA = ConvertWCharToUtf8Alloc(Referrer, nullptr);
if (!ReferrerA)
goto fail;
}
res = DsMakeSpnA(ServiceClassA, ServiceNameA, InstanceNameA, InstancePort, ReferrerA,
pcSpnLength, pszSpnA);
if (res == ERROR_SUCCESS)
{
if (ConvertUtf8NToWChar(pszSpnA, *pcSpnLength, pszSpn, length) < 0)
res = ERROR_OUTOFMEMORY;
}
fail:
free(ServiceClassA);
free(ServiceNameA);
free(InstanceNameA);
free(ReferrerA);
free(pszSpnA);
return res;
}
DWORD DsMakeSpnA(LPCSTR ServiceClass, LPCSTR ServiceName, LPCSTR InstanceName, USHORT InstancePort,
LPCSTR Referrer, DWORD* pcSpnLength, LPSTR pszSpn)
{
DWORD SpnLength = 0;
DWORD ServiceClassLength = 0;
DWORD ServiceNameLength = 0;
WINPR_ASSERT(ServiceClass);
WINPR_ASSERT(ServiceName);
WINPR_ASSERT(pcSpnLength);
WINPR_UNUSED(InstanceName);
WINPR_UNUSED(InstancePort);
WINPR_UNUSED(Referrer);
if ((*pcSpnLength != 0) && (pszSpn == nullptr))
return ERROR_INVALID_PARAMETER;
ServiceClassLength = (DWORD)strlen(ServiceClass);
ServiceNameLength = (DWORD)strlen(ServiceName);
SpnLength = ServiceClassLength + 1 + ServiceNameLength + 1;
if ((*pcSpnLength == 0) || (*pcSpnLength < SpnLength))
{
*pcSpnLength = SpnLength;
return ERROR_BUFFER_OVERFLOW;
}
(void)sprintf_s(pszSpn, *pcSpnLength, "%s/%s", ServiceClass, ServiceName);
return ERROR_SUCCESS;
}
#endif

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestDsParse")
set(MODULE_PREFIX "TEST_DSPARSE")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestDsMakeSpn.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,155 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/winpr.h>
#include <winpr/tchar.h>
#include <winpr/dsparse.h>
static BOOL test_DsMakeSpnA(void)
{
LPCSTR testServiceClass = "HTTP";
LPCSTR testServiceName = "LAB1-W2K8R2-GW.lab1.awake.local";
LPCSTR testSpn = "HTTP/LAB1-W2K8R2-GW.lab1.awake.local";
BOOL rc = FALSE;
CHAR Spn[100] = WINPR_C_ARRAY_INIT;
DWORD status = 0;
DWORD SpnLength = -1;
status =
DsMakeSpnA(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, nullptr);
if (status != ERROR_INVALID_PARAMETER)
{
printf("DsMakeSpnA: expected ERROR_INVALID_PARAMETER\n");
goto fail;
}
SpnLength = 0;
status =
DsMakeSpnA(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, nullptr);
if (status != ERROR_BUFFER_OVERFLOW)
{
printf("DsMakeSpnA: expected ERROR_BUFFER_OVERFLOW\n");
goto fail;
}
if (SpnLength != 37)
{
printf("DsMakeSpnA: SpnLength mismatch: Actual: %" PRIu32 ", Expected: 37\n", SpnLength);
goto fail;
}
status = DsMakeSpnA(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, Spn);
if (status != ERROR_SUCCESS)
{
printf("DsMakeSpnA: expected ERROR_SUCCESS\n");
goto fail;
}
if (strcmp(Spn, testSpn) != 0)
{
printf("DsMakeSpnA: SPN mismatch: Actual: %s, Expected: %s\n", Spn, testSpn);
goto fail;
}
printf("DsMakeSpnA: %s\n", Spn);
rc = TRUE;
fail:
return rc;
}
static BOOL test_DsMakeSpnW(void)
{
const CHAR ctestServiceClass[] = { 'H', 'T', 'T', 'P', '\0' };
const CHAR ctestServiceName[] = { 'L', 'A', 'B', '1', '-', 'W', '2', 'K', '8', 'R', '2',
'-', 'G', 'W', '.', 'l', 'a', 'b', '1', '.', 'a', 'w',
'a', 'k', 'e', '.', 'l', 'o', 'c', 'a', 'l', '\0' };
const CHAR ctestSpn[] = { 'H', 'T', 'T', 'P', '/', 'L', 'A', 'B', '1', '-', 'W', '2', 'K',
'8', 'R', '2', '-', 'G', 'W', '.', 'l', 'a', 'b', '1', '.', 'a',
'w', 'a', 'k', 'e', '.', 'l', 'o', 'c', 'a', 'l', '\0' };
WCHAR testServiceClass[ARRAYSIZE(ctestServiceClass)] = WINPR_C_ARRAY_INIT;
WCHAR testServiceName[ARRAYSIZE(ctestServiceName)] = WINPR_C_ARRAY_INIT;
WCHAR testSpn[ARRAYSIZE(ctestSpn)] = WINPR_C_ARRAY_INIT;
BOOL rc = FALSE;
WCHAR Spn[100] = WINPR_C_ARRAY_INIT;
DWORD status = 0;
DWORD SpnLength = -1;
(void)ConvertUtf8NToWChar(ctestServiceClass, ARRAYSIZE(ctestServiceClass), testServiceClass,
ARRAYSIZE(testServiceClass));
(void)ConvertUtf8NToWChar(ctestServiceName, ARRAYSIZE(ctestServiceName), testServiceName,
ARRAYSIZE(testServiceName));
(void)ConvertUtf8NToWChar(ctestSpn, ARRAYSIZE(ctestSpn), testSpn, ARRAYSIZE(testSpn));
status =
DsMakeSpnW(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, nullptr);
if (status != ERROR_INVALID_PARAMETER)
{
printf("DsMakeSpnW: expected ERROR_INVALID_PARAMETER\n");
goto fail;
}
SpnLength = 0;
status =
DsMakeSpnW(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, nullptr);
if (status != ERROR_BUFFER_OVERFLOW)
{
printf("DsMakeSpnW: expected ERROR_BUFFER_OVERFLOW\n");
goto fail;
}
if (SpnLength != 37)
{
printf("DsMakeSpnW: SpnLength mismatch: Actual: %" PRIu32 ", Expected: 37\n", SpnLength);
goto fail;
}
status = DsMakeSpnW(testServiceClass, testServiceName, nullptr, 0, nullptr, &SpnLength, Spn);
if (status != ERROR_SUCCESS)
{
printf("DsMakeSpnW: expected ERROR_SUCCESS\n");
goto fail;
}
if (_wcscmp(Spn, testSpn) != 0)
{
char buffer1[8192] = WINPR_C_ARRAY_INIT;
char buffer2[8192] = WINPR_C_ARRAY_INIT;
char* SpnA = buffer1;
char* testSpnA = buffer2;
(void)ConvertWCharToUtf8(Spn, SpnA, ARRAYSIZE(buffer1));
(void)ConvertWCharToUtf8(testSpn, testSpnA, ARRAYSIZE(buffer2));
printf("DsMakeSpnW: SPN mismatch: Actual: %s, Expected: %s\n", SpnA, testSpnA);
goto fail;
}
{
char buffer[8192] = WINPR_C_ARRAY_INIT;
char* SpnA = buffer;
(void)ConvertWCharToUtf8(Spn, SpnA, ARRAYSIZE(buffer));
printf("DsMakeSpnW: %s\n", SpnA);
}
rc = TRUE;
fail:
return rc;
}
int TestDsMakeSpn(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_DsMakeSpnA())
return -1;
if (!test_DsMakeSpnW())
return -2;
return 0;
}

View File

@@ -0,0 +1,5 @@
int winpr_dummy()
{
return 0;
}

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-environment cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(environment.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "2")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "processenvironment")
set(MINWIN_LONG_NAME "Process Environment Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

View File

@@ -0,0 +1,760 @@
/**
* WinPR: Windows Portable Runtime
* Process Environment Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2013 Thincast Technologies GmbH
* Copyright 2013 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/platform.h>
#include <winpr/error.h>
#include <winpr/file.h>
#include <winpr/string.h>
#include <winpr/wlog.h>
#include <winpr/environment.h>
#include "../log.h"
#define TAG WINPR_TAG("environment")
#ifndef _WIN32
#include <errno.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined(__IOS__)
#elif defined(__MACOSX__)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#endif
DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
{
size_t length = 0;
char* cwd = nullptr;
char* ccwd = nullptr;
do
{
length += MAX_PATH;
char* tmp = realloc(cwd, length);
if (!tmp)
{
free(cwd);
return 0;
}
cwd = tmp;
ccwd = getcwd(cwd, length);
} while (!ccwd && (errno == ERANGE));
if (!ccwd)
{
free(cwd);
return 0;
}
length = strnlen(cwd, length);
if ((nBufferLength == 0) && (lpBuffer == nullptr))
{
free(cwd);
return (DWORD)length;
}
else
{
if (lpBuffer == nullptr)
{
free(cwd);
return 0;
}
if ((length + 1) > nBufferLength)
{
free(cwd);
return (DWORD)(length + 1);
}
memcpy(lpBuffer, cwd, length + 1);
free(cwd);
return (DWORD)length;
}
}
DWORD GetCurrentDirectoryW(WINPR_ATTR_UNUSED DWORD nBufferLength, WINPR_ATTR_UNUSED LPWSTR lpBuffer)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
BOOL SetCurrentDirectoryA(WINPR_ATTR_UNUSED LPCSTR lpPathName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL SetCurrentDirectoryW(WINPR_ATTR_UNUSED LPCWSTR lpPathName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
DWORD SearchPathA(WINPR_ATTR_UNUSED LPCSTR lpPath, WINPR_ATTR_UNUSED LPCSTR lpFileName,
WINPR_ATTR_UNUSED LPCSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
WINPR_ATTR_UNUSED LPSTR lpBuffer, WINPR_ATTR_UNUSED LPSTR* lpFilePart)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
DWORD SearchPathW(WINPR_ATTR_UNUSED LPCWSTR lpPath, WINPR_ATTR_UNUSED LPCWSTR lpFileName,
WINPR_ATTR_UNUSED LPCWSTR lpExtension, WINPR_ATTR_UNUSED DWORD nBufferLength,
WINPR_ATTR_UNUSED LPWSTR lpBuffer, WINPR_ATTR_UNUSED LPWSTR* lpFilePart)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
LPSTR GetCommandLineA(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
LPWSTR GetCommandLineW(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
BOOL NeedCurrentDirectoryForExePathA(WINPR_ATTR_UNUSED LPCSTR ExeName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL NeedCurrentDirectoryForExePathW(WINPR_ATTR_UNUSED LPCWSTR ExeName)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
#endif
#if !defined(_WIN32) || defined(_UWP)
DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
{
#if !defined(_UWP)
size_t length = 0;
// NOLINTNEXTLINE(concurrency-mt-unsafe)
char* env = getenv(lpName);
if (!env)
{
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
}
length = strlen(env);
if ((length + 1 > nSize) || (!lpBuffer))
return (DWORD)length + 1;
CopyMemory(lpBuffer, env, length);
lpBuffer[length] = '\0';
return (DWORD)length;
#else
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
#endif
}
DWORD GetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPWSTR lpBuffer,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
SetLastError(ERROR_ENVVAR_NOT_FOUND);
return 0;
}
BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
{
#if !defined(_UWP)
if (!lpName)
return FALSE;
if (lpValue)
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (0 != setenv(lpName, lpValue, 1))
return FALSE;
}
else
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (0 != unsetenv(lpName))
return FALSE;
}
return TRUE;
#else
return FALSE;
#endif
}
BOOL SetEnvironmentVariableW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED LPCWSTR lpValue)
{
WLog_ERR(TAG, "TODO: not implemented");
return FALSE;
}
/**
* GetEnvironmentStrings function:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms683187/
*
* The GetEnvironmentStrings function returns a pointer to a block of memory
* that contains the environment variables of the calling process (both the
* system and the user environment variables). Each environment block contains
* the environment variables in the following format:
*
* Var1=Value1\0
* Var2=Value2\0
* Var3=Value3\0
* ...
* VarN=ValueN\0\0
*/
extern char** environ;
LPCH GetEnvironmentStringsA(VOID)
{
#if !defined(_UWP)
size_t offset = 0;
char** envp = environ;
const size_t blocksize = 128;
size_t cchEnvironmentBlock = blocksize;
LPCH lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
if (!lpszEnvironmentBlock)
return nullptr;
while (*envp)
{
const size_t length = strlen(*envp);
const size_t required = offset + length + 8ull;
if (required > UINT32_MAX)
{
WLog_ERR(TAG, "Environment block too large: %" PRIuz, required);
free(lpszEnvironmentBlock);
return nullptr;
}
if (required > cchEnvironmentBlock)
{
size_t new_size = cchEnvironmentBlock;
do
{
new_size += blocksize;
} while (new_size <= required);
LPCH new_blk = (LPCH)realloc(lpszEnvironmentBlock, new_size * sizeof(CHAR));
if (!new_blk)
{
free(lpszEnvironmentBlock);
return nullptr;
}
lpszEnvironmentBlock = new_blk;
cchEnvironmentBlock = new_size;
}
char* p = &(lpszEnvironmentBlock[offset]);
CopyMemory(p, *envp, length * sizeof(CHAR));
p[length] = '\0';
offset += (length + 1ull);
envp++;
}
lpszEnvironmentBlock[offset] = '\0';
return lpszEnvironmentBlock;
#else
return nullptr;
#endif
}
LPWCH GetEnvironmentStringsW(VOID)
{
WLog_ERR(TAG, "TODO: not implemented");
return nullptr;
}
BOOL SetEnvironmentStringsA(WINPR_ATTR_UNUSED LPCH NewEnvironment)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
BOOL SetEnvironmentStringsW(WINPR_ATTR_UNUSED LPWCH NewEnvironment)
{
WLog_ERR(TAG, "TODO: not implemented");
return TRUE;
}
DWORD ExpandEnvironmentStringsA(WINPR_ATTR_UNUSED LPCSTR lpSrc, WINPR_ATTR_UNUSED LPSTR lpDst,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
DWORD ExpandEnvironmentStringsW(WINPR_ATTR_UNUSED LPCWSTR lpSrc, WINPR_ATTR_UNUSED LPWSTR lpDst,
WINPR_ATTR_UNUSED DWORD nSize)
{
WLog_ERR(TAG, "TODO: not implemented");
return 0;
}
BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock)
{
free(lpszEnvironmentBlock);
return TRUE;
}
BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
{
free(lpszEnvironmentBlock);
return TRUE;
}
#endif
LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
{
const char* cp = nullptr;
char* p = nullptr;
size_t offset = 0;
size_t length = 0;
const char* envp = nullptr;
DWORD cchEnvironmentBlock = 0;
LPCH lpszEnvironmentBlock = nullptr;
const char** mergeStrings = nullptr;
size_t mergeStringLength = 0;
size_t mergeArraySize = 128;
size_t mergeLength = 0;
size_t foundMerge = 0;
char* foundEquals = nullptr;
mergeStrings = (LPCSTR*)calloc(mergeArraySize, sizeof(char*));
if (!mergeStrings)
return nullptr;
mergeStringLength = 0;
cp = merge;
while (*cp && *(cp + 1))
{
length = strlen(cp);
if (mergeStringLength == mergeArraySize)
{
const char** new_str = nullptr;
mergeArraySize += 128;
new_str = (const char**)realloc((void*)mergeStrings, mergeArraySize * sizeof(char*));
if (!new_str)
{
free((void*)mergeStrings);
return nullptr;
}
mergeStrings = new_str;
}
mergeStrings[mergeStringLength] = cp;
cp += length + 1;
mergeStringLength++;
}
offset = 0;
cchEnvironmentBlock = 128;
lpszEnvironmentBlock = (LPCH)calloc(cchEnvironmentBlock, sizeof(CHAR));
if (!lpszEnvironmentBlock)
{
free((void*)mergeStrings);
return nullptr;
}
envp = original;
while ((original != nullptr) && (*envp && *(envp + 1)))
{
size_t old_offset = offset;
length = strlen(envp);
while ((offset + length + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
}
p = &(lpszEnvironmentBlock[offset]);
// check if this value is in the mergeStrings
foundMerge = 0;
for (size_t run = 0; run < mergeStringLength; run++)
{
if (!mergeStrings[run])
continue;
mergeLength = strlen(mergeStrings[run]);
foundEquals = strstr(mergeStrings[run], "=");
if (!foundEquals)
continue;
const intptr_t len = foundEquals - mergeStrings[run] + 1;
if (strncmp(envp, mergeStrings[run], WINPR_ASSERTING_INT_CAST(size_t, len)) == 0)
{
// found variable in merge list ... use this ....
if (*(foundEquals + 1) == '\0')
{
// check if the argument is set ... if not remove variable ...
foundMerge = 1;
}
else
{
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp =
(LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
p = &(lpszEnvironmentBlock[old_offset]);
}
foundMerge = 1;
CopyMemory(p, mergeStrings[run], mergeLength);
mergeStrings[run] = nullptr;
p[mergeLength] = '\0';
offset += (mergeLength + 1);
}
}
}
if (foundMerge == 0)
{
CopyMemory(p, envp, length * sizeof(CHAR));
p[length] = '\0';
offset += (length + 1);
}
envp += (length + 1);
}
// now merge the not already merged env
for (size_t run = 0; run < mergeStringLength; run++)
{
if (!mergeStrings[run])
continue;
mergeLength = strlen(mergeStrings[run]);
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
{
cchEnvironmentBlock *= 2;
LPCH tmp = (LPCH)realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
if (!tmp)
{
free((void*)lpszEnvironmentBlock);
free((void*)mergeStrings);
return nullptr;
}
lpszEnvironmentBlock = tmp;
}
p = &(lpszEnvironmentBlock[offset]);
CopyMemory(p, mergeStrings[run], mergeLength);
mergeStrings[run] = nullptr;
p[mergeLength] = '\0';
offset += (mergeLength + 1);
}
lpszEnvironmentBlock[offset] = '\0';
free((void*)mergeStrings);
return lpszEnvironmentBlock;
}
DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
{
size_t vLength = 0;
char* env = nullptr;
char* foundEquals = nullptr;
const char* penvb = envBlock;
size_t nLength = 0;
size_t fLength = 0;
size_t lpNameLength = 0;
if (!lpName || nullptr == envBlock)
return 0;
lpNameLength = strlen(lpName);
if (lpNameLength < 1)
return 0;
while (*penvb && *(penvb + 1))
{
fLength = strlen(penvb);
foundEquals = strstr(penvb, "=");
if (!foundEquals)
{
/* if no = sign is found the envBlock is broken */
return 0;
}
nLength = WINPR_ASSERTING_INT_CAST(size_t, (foundEquals - penvb));
if (nLength != lpNameLength)
{
penvb += (fLength + 1);
continue;
}
if (strncmp(penvb, lpName, nLength) == 0)
{
env = foundEquals + 1;
break;
}
penvb += (fLength + 1);
}
if (!env)
return 0;
vLength = strlen(env);
if (vLength >= UINT32_MAX)
return 0;
if ((vLength + 1 > nSize) || (!lpBuffer))
return (DWORD)vLength + 1;
CopyMemory(lpBuffer, env, vLength + 1);
return (DWORD)vLength;
}
BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
{
size_t length = 0;
char* envstr = nullptr;
char* newEB = nullptr;
if (!lpName)
return FALSE;
if (lpValue)
{
length = (strlen(lpName) + strlen(lpValue) + 2); /* +2 because of = and \0 */
envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
if (!envstr)
return FALSE;
(void)sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
}
else
{
length = strlen(lpName) + 2; /* +2 because of = and \0 */
envstr = (char*)malloc(length + 1); /* +1 because of closing \0 */
if (!envstr)
return FALSE;
(void)sprintf_s(envstr, length, "%s=", lpName);
}
envstr[length] = '\0';
newEB = MergeEnvironmentStrings((LPCSTR)*envBlock, envstr);
free(envstr);
free(*envBlock);
*envBlock = newEB;
return TRUE;
}
char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
{
char* p = nullptr;
SSIZE_T index = 0;
size_t count = 0;
size_t length = 0;
char** envp = nullptr;
count = 0;
if (!lpszEnvironmentBlock)
return nullptr;
p = (char*)lpszEnvironmentBlock;
while (p[0] && p[1])
{
length = strlen(p);
p += (length + 1);
count++;
}
index = 0;
p = (char*)lpszEnvironmentBlock;
envp = (char**)calloc(count + 1, sizeof(char*));
if (!envp)
return nullptr;
envp[count] = nullptr;
while (p[0] && p[1])
{
length = strlen(p);
envp[index] = _strdup(p);
if (!envp[index])
{
for (index -= 1; index >= 0; --index)
{
free(envp[index]);
}
free((void*)envp);
return nullptr;
}
p += (length + 1);
index++;
}
return envp;
}
#ifdef _WIN32
// https://devblogs.microsoft.com/oldnewthing/20100203-00/?p=15083
#define WINPR_MAX_ENVIRONMENT_LENGTH 2048
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
DWORD result = 0;
DWORD nSizeW = 0;
LPWSTR lpNameW = nullptr;
LPWSTR lpBufferW = nullptr;
LPSTR lpBufferA = lpBuffer;
lpNameW = ConvertUtf8ToWCharAlloc(lpName, nullptr);
if (!lpNameW)
goto cleanup;
if (!lpBuffer)
{
char lpBufferMaxA[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
WCHAR lpBufferMaxW[WINPR_MAX_ENVIRONMENT_LENGTH] = WINPR_C_ARRAY_INIT;
LPSTR lpTmpBuffer = lpBufferMaxA;
nSizeW = ARRAYSIZE(lpBufferMaxW);
result = GetEnvironmentVariableW(lpNameW, lpBufferMaxW, nSizeW);
SSIZE_T rc =
ConvertWCharNToUtf8(lpBufferMaxW, nSizeW, lpTmpBuffer, ARRAYSIZE(lpBufferMaxA));
if ((rc < 0) || (rc >= UINT32_MAX))
goto cleanup;
result = (DWORD)rc + 1;
}
else
{
nSizeW = nSize;
lpBufferW = calloc(nSizeW + 1, sizeof(WCHAR));
if (!lpBufferW)
goto cleanup;
result = GetEnvironmentVariableW(lpNameW, lpBufferW, nSizeW);
if (result == 0)
goto cleanup;
SSIZE_T rc = ConvertWCharNToUtf8(lpBufferW, nSizeW, lpBufferA, nSize);
if ((rc < 0) || (rc > UINT32_MAX))
goto cleanup;
result = (DWORD)rc;
}
cleanup:
free(lpBufferW);
free(lpNameW);
return result;
}
#else
DWORD GetEnvironmentVariableX(const char* lpName, char* lpBuffer, DWORD nSize)
{
return GetEnvironmentVariableA(lpName, lpBuffer, nSize);
}
#endif

View File

@@ -0,0 +1,25 @@
set(MODULE_NAME "TestEnvironment")
set(MODULE_PREFIX "TEST_ENVIRONMENT")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestEnvironmentGetEnvironmentStrings.c TestEnvironmentSetEnvironmentVariable.c
TestEnvironmentMergeEnvironmentStrings.c TestEnvironmentGetSetEB.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,41 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
int TestEnvironmentGetEnvironmentStrings(int argc, char* argv[])
{
int r = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
LPTCH lpszEnvironmentBlock = GetEnvironmentStrings();
if (!lpszEnvironmentBlock)
goto fail;
TCHAR* p = lpszEnvironmentBlock;
while (p[0] && p[1])
{
const size_t max = _tcslen(p);
const int rc = _sntprintf(nullptr, 0, _T("%s\n"), p);
if (rc < 1)
{
_tprintf(_T("test failed: return %d\n"), rc);
goto fail;
}
if (max != (size_t)(rc - 1))
{
_tprintf(_T("test failed: length %") _T(PRIuz) _T(" != %d [%s]\n"), max, rc - 1, p);
goto fail;
}
p += (max + 1);
}
r = 0;
fail:
FreeEnvironmentStrings(lpszEnvironmentBlock);
return r;
}

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