Milestone 5: deliver embedded RDP sessions and lifecycle hardening
251
third_party/FreeRDP/winpr/libwinpr/utils/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-utils 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(CMakeDependentOption)
|
||||
|
||||
winpr_include_directory_add(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
option(WITH_DEBUG_UTILS_CMDLINE_DUMP "build with excessive command line parser logging" OFF)
|
||||
if(WITH_DEBUG_UTILS_CMDLINE_DUMP)
|
||||
winpr_definition_add(-DWITH_DEBUG_UTILS_CMDLINE_DUMP)
|
||||
endif()
|
||||
|
||||
option(WITH_STREAMPOOL_DEBUG "build with extensive streampool logging" OFF)
|
||||
if(WITH_STREAMPOOL_DEBUG)
|
||||
winpr_definition_add(-DWITH_STREAMPOOL_DEBUG)
|
||||
endif()
|
||||
|
||||
option(WITH_LODEPNG "build WinPR with PNG support" OFF)
|
||||
if(WITH_LODEPNG)
|
||||
find_package(lodepng REQUIRED)
|
||||
|
||||
winpr_definition_add(WITH_LODEPNG)
|
||||
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
|
||||
|
||||
winpr_system_include_directory_add(${lodepng_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${lodepng_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WINPR_UTILS_IMAGE_DIBv5 "[experimental] Add DIBv5 <--> BMP conversion support to clipboard" OFF)
|
||||
option(WINPR_UTILS_IMAGE_PNG "Add PNG <--> BMP conversion support to clipboard" OFF)
|
||||
if(WINPR_UTILS_IMAGE_PNG)
|
||||
find_package(PNG REQUIRED)
|
||||
winpr_pc_add_requires_private("libpng")
|
||||
|
||||
set(WINPR_WITH_PNG ON CACHE BOOL "build cache")
|
||||
winpr_system_include_directory_add(${PNG_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${PNG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WINPR_UTILS_IMAGE_WEBP "Add WebP <--> BMP conversion support to clipboard" OFF)
|
||||
if(WINPR_UTILS_IMAGE_WEBP)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(WEBP libwebp REQUIRED)
|
||||
winpr_pc_add_requires_private("libwebp")
|
||||
|
||||
winpr_system_include_directory_add(${WEBP_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${WEBP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WINPR_UTILS_IMAGE_JPEG "Add Jpeg <--> BMP conversion support to clipboard" OFF)
|
||||
if(WINPR_UTILS_IMAGE_JPEG)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(JPEG libjpeg REQUIRED)
|
||||
winpr_pc_add_requires_private("libjpeg")
|
||||
|
||||
winpr_system_include_directory_add(${JPEG_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${JPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set(COLLECTIONS_SRCS
|
||||
collections/Object.c
|
||||
collections/Queue.c
|
||||
collections/Stack.c
|
||||
collections/PubSub.c
|
||||
collections/BitStream.c
|
||||
collections/ArrayList.c
|
||||
collections/LinkedList.c
|
||||
collections/HashTable.c
|
||||
collections/ListDictionary.c
|
||||
collections/CountdownEvent.c
|
||||
collections/BufferPool.c
|
||||
collections/ObjectPool.c
|
||||
collections/StreamPool.c
|
||||
collections/MessageQueue.c
|
||||
collections/MessagePipe.c
|
||||
)
|
||||
|
||||
if(WINPR_HAVE_SYSLOG_H)
|
||||
set(SYSLOG_SRCS wlog/SyslogAppender.c wlog/SyslogAppender.h)
|
||||
endif()
|
||||
|
||||
find_package(libsystemd)
|
||||
option(WITH_SYSTEMD "allows to export wLog to systemd journal" ${libsystemd_FOUND})
|
||||
if(WITH_SYSTEMD)
|
||||
find_package(libsystemd REQUIRED)
|
||||
winpr_pc_add_requires_private("libsystemd")
|
||||
set(WINPR_HAVE_JOURNALD_H TRUE)
|
||||
set(JOURNALD_SRCS wlog/JournaldAppender.c wlog/JournaldAppender.h)
|
||||
winpr_system_include_directory_add(${LIBSYSTEMD_INCLUDE_DIR})
|
||||
winpr_library_add_private(${LIBSYSTEMD_LIBRARY})
|
||||
else()
|
||||
unset(WINPR_HAVE_JOURNALD_H)
|
||||
endif()
|
||||
|
||||
set(WLOG_SRCS
|
||||
wlog/wlog.c
|
||||
wlog/wlog.h
|
||||
wlog/Layout.c
|
||||
wlog/Layout.h
|
||||
wlog/Message.c
|
||||
wlog/Message.h
|
||||
wlog/DataMessage.c
|
||||
wlog/DataMessage.h
|
||||
wlog/ImageMessage.c
|
||||
wlog/ImageMessage.h
|
||||
wlog/PacketMessage.c
|
||||
wlog/PacketMessage.h
|
||||
wlog/Appender.c
|
||||
wlog/Appender.h
|
||||
wlog/FileAppender.c
|
||||
wlog/FileAppender.h
|
||||
wlog/BinaryAppender.c
|
||||
wlog/BinaryAppender.h
|
||||
wlog/CallbackAppender.c
|
||||
wlog/CallbackAppender.h
|
||||
wlog/ConsoleAppender.c
|
||||
wlog/ConsoleAppender.h
|
||||
wlog/UdpAppender.c
|
||||
wlog/UdpAppender.h
|
||||
${SYSLOG_SRCS}
|
||||
${JOURNALD_SRCS}
|
||||
)
|
||||
|
||||
set(ASN1_SRCS asn1/asn1.c)
|
||||
|
||||
set(SRCS
|
||||
ini.c
|
||||
sam.c
|
||||
ntlm.c
|
||||
image.c
|
||||
print.c
|
||||
stream.h
|
||||
stream.c
|
||||
strlst.c
|
||||
debug.c
|
||||
winpr.c
|
||||
cmdline.c
|
||||
ssl.c
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND SRCS android.h android.c)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
if(NOT WINPR_HAVE_UNWIND_H)
|
||||
message("[backtrace] android NDK without unwind.h, falling back to corkscrew")
|
||||
set(WINPR_HAVE_CORKSCREW 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WINPR_HAVE_CORKSCREW)
|
||||
list(APPEND SRCS corkscrew/debug.c corkscrew/debug.h)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SRCS windows/debug.c windows/debug.h)
|
||||
endif()
|
||||
|
||||
if(WINPR_HAVE_EXECINFO_H)
|
||||
option(USE_EXECINFO "Use execinfo.h to generate backtraces" ON)
|
||||
if(USE_EXECINFO)
|
||||
winpr_definition_add(USE_EXECINFO)
|
||||
list(APPEND SRCS execinfo/debug.c execinfo/debug.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WINPR_HAVE_UNWIND_H)
|
||||
option(USE_UNWIND "Use unwind.h to generate backtraces" ON)
|
||||
if(USE_UNWIND)
|
||||
winpr_definition_add(USE_UNWIND)
|
||||
list(APPEND SRCS unwind/debug.c unwind/debug.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT WITH_JSON_DISABLED)
|
||||
if(jansson_FOUND)
|
||||
winpr_library_add_private(jansson::jansson)
|
||||
winpr_pc_add_requires_private("jansson")
|
||||
winpr_definition_add(WITH_JANSSON)
|
||||
winpr_module_add(json/jansson.c)
|
||||
set(WITH_WINPR_JSON ON CACHE INTERNAL "internal")
|
||||
elseif(json-c_FOUND)
|
||||
winpr_library_add_private(json-c::json-c)
|
||||
winpr_pc_add_requires_private("json-c")
|
||||
winpr_definition_add(WITH_JSONC)
|
||||
winpr_module_add(json/json-c.c)
|
||||
set(WITH_WINPR_JSON ON CACHE INTERNAL "internal")
|
||||
elseif(cJSON_FOUND)
|
||||
winpr_library_add_private(cjson)
|
||||
winpr_pc_add_requires_private("libcjson")
|
||||
winpr_definition_add(WITH_CJSON)
|
||||
winpr_module_add(json/c-json.c)
|
||||
set(WITH_WINPR_JSON ON CACHE INTERNAL "internal")
|
||||
else()
|
||||
winpr_module_add(json/json-stub.c)
|
||||
endif()
|
||||
else()
|
||||
winpr_module_add(json/json-stub.c)
|
||||
endif()
|
||||
|
||||
winpr_module_add(json/json.c)
|
||||
|
||||
winpr_module_add(${SRCS} ${COLLECTIONS_SRCS} ${WLOG_SRCS} ${ASN1_SRCS})
|
||||
|
||||
winpr_include_directory_add(".")
|
||||
|
||||
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(UNIX)
|
||||
winpr_library_add_private(m)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES backtrace.h)
|
||||
check_function_exists(backtrace BACKTRACE)
|
||||
if(NOT BACKTRACE)
|
||||
set(CMAKE_REQUIRED_LIBRARIES execinfo)
|
||||
check_function_exists(backtrace EXECINFO)
|
||||
if(EXECINFO)
|
||||
winpr_library_add_private(execinfo)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
winpr_library_add_public(dbghelp)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
7
third_party/FreeRDP/winpr/libwinpr/utils/ModuleOptions.cmake
vendored
Normal 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 "utils")
|
||||
set(MINWIN_LONG_NAME "WinPR Utils")
|
||||
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")
|
||||
77
third_party/FreeRDP/winpr/libwinpr/utils/android.c
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Winpr android helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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 "android.h"
|
||||
#include <jni.h>
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#define TAG WINPR_TAG("android")
|
||||
|
||||
JavaVM* jniVm = nullptr;
|
||||
|
||||
WINPR_API jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
{
|
||||
WLog_INFO(TAG, "Setting up JNI environment...");
|
||||
|
||||
jniVm = vm;
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
WINPR_API void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
|
||||
{
|
||||
JNIEnv* env = nullptr;
|
||||
WLog_INFO(TAG, "Tearing down JNI environment...");
|
||||
|
||||
if ((*jniVm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
WLog_FATAL(TAG, "Failed to get the environment");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
jboolean winpr_jni_attach_thread(JNIEnv** env)
|
||||
{
|
||||
WINPR_ASSERT(jniVm);
|
||||
|
||||
if ((*jniVm)->GetEnv(jniVm, (void**)env, JNI_VERSION_1_4) != JNI_OK)
|
||||
{
|
||||
WLog_INFO(TAG, "android_java_callback: attaching current thread");
|
||||
(*jniVm)->AttachCurrentThread(jniVm, env, nullptr);
|
||||
|
||||
if ((*jniVm)->GetEnv(jniVm, (void**)env, JNI_VERSION_1_4) != JNI_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "android_java_callback: failed to obtain current JNI environment");
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/* attach current thread to JVM */
|
||||
void winpr_jni_detach_thread(void)
|
||||
{
|
||||
WINPR_ASSERT(jniVm);
|
||||
(*jniVm)->DetachCurrentThread(jniVm);
|
||||
}
|
||||
30
third_party/FreeRDP/winpr/libwinpr/utils/android.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Winpr android helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_UTILS_ANDROID_PRIV_H
|
||||
#define WINPR_UTILS_ANDROID_PRIV_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
extern JavaVM* jniVm;
|
||||
|
||||
jboolean winpr_jni_attach_thread(JNIEnv** env);
|
||||
void winpr_jni_detach_thread(void);
|
||||
|
||||
#endif /* WINPR_UTILS_ANDROID_PRIV_H */
|
||||
1505
third_party/FreeRDP/winpr/libwinpr/utils/asn1/asn1.c
vendored
Normal file
931
third_party/FreeRDP/winpr/libwinpr/utils/cmdline.c
vendored
Normal file
@@ -0,0 +1,931 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Command-Line Utils
|
||||
*
|
||||
* 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/assert.h>
|
||||
#include <winpr/cmdline.h>
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#define TAG WINPR_TAG("commandline")
|
||||
|
||||
/**
|
||||
* Command-line syntax: some basic concepts:
|
||||
* https://pythonconquerstheuniverse.wordpress.com/2010/07/25/command-line-syntax-some-basic-concepts/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Command-Line Syntax:
|
||||
*
|
||||
* <sigil><keyword><separator><value>
|
||||
*
|
||||
* <sigil>: '/' or '-' or ('+' | '-')
|
||||
*
|
||||
* <keyword>: option, named argument, flag
|
||||
*
|
||||
* <separator>: ':' or '='
|
||||
*
|
||||
* <value>: argument value
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(WITH_DEBUG_UTILS_CMDLINE_DUMP)
|
||||
static const char censoredmessage[] =
|
||||
"<censored: build with -DWITH_DEBUG_UTILS_CMDLINE_DUMP=ON for details>";
|
||||
#endif
|
||||
|
||||
#define log_error(flags, msg, index, arg) \
|
||||
log_error_((flags), (msg), (index), (arg), __FILE__, __func__, __LINE__)
|
||||
static void log_error_(DWORD flags, LPCSTR message, int index, WINPR_ATTR_UNUSED LPCSTR argv,
|
||||
const char* file, const char* fkt, size_t line)
|
||||
{
|
||||
if ((flags & COMMAND_LINE_SILENCE_PARSER) == 0)
|
||||
{
|
||||
const DWORD level = WLOG_ERROR;
|
||||
static wLog* log = nullptr;
|
||||
if (!log)
|
||||
log = WLog_Get(TAG);
|
||||
|
||||
if (!WLog_IsLevelActive(log, level))
|
||||
return;
|
||||
|
||||
WLog_PrintTextMessage(log, level, line, file, fkt, "Failed at index %d [%s]: %s", index,
|
||||
#if defined(WITH_DEBUG_UTILS_CMDLINE_DUMP)
|
||||
argv
|
||||
#else
|
||||
censoredmessage
|
||||
#endif
|
||||
,
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
#define log_comma_error(msg, arg) log_comma_error_((msg), (arg), __FILE__, __func__, __LINE__)
|
||||
static void log_comma_error_(const char* message, WINPR_ATTR_UNUSED const char* argument,
|
||||
const char* file, const char* fkt, size_t line)
|
||||
{
|
||||
const DWORD level = WLOG_ERROR;
|
||||
static wLog* log = nullptr;
|
||||
if (!log)
|
||||
log = WLog_Get(TAG);
|
||||
|
||||
if (!WLog_IsLevelActive(log, level))
|
||||
return;
|
||||
|
||||
WLog_PrintTextMessage(log, level, line, file, fkt, "%s [%s]", message,
|
||||
#if defined(WITH_DEBUG_UTILS_CMDLINE_DUMP)
|
||||
argument
|
||||
#else
|
||||
censoredmessage
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
int CommandLineParseArgumentsA(int argc, LPSTR* argv, COMMAND_LINE_ARGUMENT_A* options, DWORD flags,
|
||||
void* context, COMMAND_LINE_PRE_FILTER_FN_A preFilter,
|
||||
COMMAND_LINE_POST_FILTER_FN_A postFilter)
|
||||
{
|
||||
int status = 0;
|
||||
int count = 0;
|
||||
BOOL notescaped = FALSE;
|
||||
const char* sigil = nullptr;
|
||||
size_t sigil_length = 0;
|
||||
char* keyword = nullptr;
|
||||
size_t keyword_index = 0;
|
||||
char* separator = nullptr;
|
||||
char* value = nullptr;
|
||||
int toggle = 0;
|
||||
|
||||
if (!argv)
|
||||
return status;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
if (flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD)
|
||||
status = 0;
|
||||
else
|
||||
status = COMMAND_LINE_STATUS_PRINT_HELP;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
size_t keyword_length = 0;
|
||||
BOOL found = FALSE;
|
||||
BOOL escaped = TRUE;
|
||||
|
||||
if (preFilter)
|
||||
{
|
||||
count = preFilter(context, i, argc, argv);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
log_error(flags, "PreFilter rule could not be applied", i, argv[i]);
|
||||
status = COMMAND_LINE_ERROR;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
i += (count - 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sigil = argv[i];
|
||||
size_t length = strlen(argv[i]);
|
||||
|
||||
if ((sigil[0] == '/') && (flags & COMMAND_LINE_SIGIL_SLASH))
|
||||
{
|
||||
sigil_length = 1;
|
||||
}
|
||||
else if ((sigil[0] == '-') && (flags & COMMAND_LINE_SIGIL_DASH))
|
||||
{
|
||||
sigil_length = 1;
|
||||
|
||||
if (length > 2)
|
||||
{
|
||||
if ((sigil[1] == '-') && (flags & COMMAND_LINE_SIGIL_DOUBLE_DASH))
|
||||
sigil_length = 2;
|
||||
}
|
||||
}
|
||||
else if ((sigil[0] == '+') && (flags & COMMAND_LINE_SIGIL_PLUS_MINUS))
|
||||
{
|
||||
sigil_length = 1;
|
||||
}
|
||||
else if ((sigil[0] == '-') && (flags & COMMAND_LINE_SIGIL_PLUS_MINUS))
|
||||
{
|
||||
sigil_length = 1;
|
||||
}
|
||||
else if (flags & COMMAND_LINE_SIGIL_NONE)
|
||||
{
|
||||
sigil_length = 0;
|
||||
}
|
||||
else if (flags & COMMAND_LINE_SIGIL_NOT_ESCAPED)
|
||||
{
|
||||
if (notescaped)
|
||||
{
|
||||
log_error(flags, "Unescaped sigil", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR;
|
||||
}
|
||||
|
||||
sigil_length = 0;
|
||||
escaped = FALSE;
|
||||
notescaped = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error(flags, "Invalid sigil", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR;
|
||||
}
|
||||
|
||||
if ((sigil_length > 0) || (flags & COMMAND_LINE_SIGIL_NONE) ||
|
||||
(flags & COMMAND_LINE_SIGIL_NOT_ESCAPED))
|
||||
{
|
||||
if (length < (sigil_length + 1))
|
||||
{
|
||||
if ((flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD))
|
||||
continue;
|
||||
|
||||
log_error(flags, "Unexpected keyword", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR_NO_KEYWORD;
|
||||
}
|
||||
|
||||
keyword_index = sigil_length;
|
||||
keyword = &argv[i][keyword_index];
|
||||
toggle = -1;
|
||||
|
||||
if (flags & COMMAND_LINE_SIGIL_ENABLE_DISABLE)
|
||||
{
|
||||
if (strncmp(keyword, "enable-", 7) == 0)
|
||||
{
|
||||
toggle = TRUE;
|
||||
keyword_index += 7;
|
||||
keyword = &argv[i][keyword_index];
|
||||
}
|
||||
else if (strncmp(keyword, "disable-", 8) == 0)
|
||||
{
|
||||
toggle = FALSE;
|
||||
keyword_index += 8;
|
||||
keyword = &argv[i][keyword_index];
|
||||
}
|
||||
}
|
||||
|
||||
separator = nullptr;
|
||||
|
||||
if ((flags & COMMAND_LINE_SEPARATOR_COLON) && (!separator))
|
||||
separator = strchr(keyword, ':');
|
||||
|
||||
if ((flags & COMMAND_LINE_SEPARATOR_EQUAL) && (!separator))
|
||||
separator = strchr(keyword, '=');
|
||||
|
||||
if (separator)
|
||||
{
|
||||
SSIZE_T separator_index = (separator - argv[i]);
|
||||
SSIZE_T value_index = separator_index + 1;
|
||||
keyword_length = WINPR_ASSERTING_INT_CAST(size_t, (separator - keyword));
|
||||
value = &argv[i][value_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (length < keyword_index)
|
||||
{
|
||||
log_error(flags, "Argument required", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR;
|
||||
}
|
||||
|
||||
keyword_length = length - keyword_index;
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
if (!escaped)
|
||||
continue;
|
||||
|
||||
for (size_t j = 0; options[j].Name != nullptr; j++)
|
||||
{
|
||||
COMMAND_LINE_ARGUMENT_A* cur = &options[j];
|
||||
BOOL match = FALSE;
|
||||
|
||||
if (strncmp(cur->Name, keyword, keyword_length) == 0)
|
||||
{
|
||||
if (strlen(cur->Name) == keyword_length)
|
||||
match = TRUE;
|
||||
}
|
||||
|
||||
if ((!match) && (cur->Alias != nullptr))
|
||||
{
|
||||
if (strncmp(cur->Alias, keyword, keyword_length) == 0)
|
||||
{
|
||||
if (strlen(cur->Alias) == keyword_length)
|
||||
match = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
continue;
|
||||
|
||||
found = match;
|
||||
cur->Index = i;
|
||||
|
||||
if ((flags & COMMAND_LINE_SEPARATOR_SPACE) && ((i + 1) < argc))
|
||||
{
|
||||
BOOL argument = 0;
|
||||
int value_present = 1;
|
||||
|
||||
if (flags & COMMAND_LINE_SIGIL_DASH)
|
||||
{
|
||||
if (strncmp(argv[i + 1], "-", 1) == 0)
|
||||
value_present = 0;
|
||||
}
|
||||
|
||||
if (flags & COMMAND_LINE_SIGIL_DOUBLE_DASH)
|
||||
{
|
||||
if (strncmp(argv[i + 1], "--", 2) == 0)
|
||||
value_present = 0;
|
||||
}
|
||||
|
||||
if (flags & COMMAND_LINE_SIGIL_SLASH)
|
||||
{
|
||||
if (strncmp(argv[i + 1], "/", 1) == 0)
|
||||
value_present = 0;
|
||||
}
|
||||
|
||||
argument = (((cur->Flags & COMMAND_LINE_VALUE_REQUIRED) != 0) ||
|
||||
((cur->Flags & COMMAND_LINE_VALUE_OPTIONAL) != 0));
|
||||
|
||||
if (value_present && argument)
|
||||
{
|
||||
i++;
|
||||
value = argv[i];
|
||||
}
|
||||
else if (!value_present && (cur->Flags & COMMAND_LINE_VALUE_OPTIONAL))
|
||||
{
|
||||
value = nullptr;
|
||||
}
|
||||
else if (!value_present && argument)
|
||||
{
|
||||
log_error(flags, "Argument required", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & COMMAND_LINE_SEPARATOR_SPACE))
|
||||
{
|
||||
if (value && (cur->Flags & COMMAND_LINE_VALUE_FLAG))
|
||||
{
|
||||
log_error(flags, "Unexpected value", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value && (cur->Flags & COMMAND_LINE_VALUE_FLAG))
|
||||
{
|
||||
i--;
|
||||
value = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value && (cur->Flags & COMMAND_LINE_VALUE_REQUIRED))
|
||||
{
|
||||
log_error(flags, "Missing value", i, argv[i]);
|
||||
status = COMMAND_LINE_ERROR_MISSING_VALUE;
|
||||
return status;
|
||||
}
|
||||
|
||||
cur->Flags |= COMMAND_LINE_ARGUMENT_PRESENT;
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (!(cur->Flags & (COMMAND_LINE_VALUE_OPTIONAL | COMMAND_LINE_VALUE_REQUIRED)))
|
||||
{
|
||||
log_error(flags, "Unexpected value", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
|
||||
}
|
||||
|
||||
cur->Value = value;
|
||||
cur->Flags |= COMMAND_LINE_VALUE_PRESENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cur->Flags & COMMAND_LINE_VALUE_FLAG)
|
||||
{
|
||||
cur->Value = (LPSTR)1;
|
||||
cur->Flags |= COMMAND_LINE_VALUE_PRESENT;
|
||||
}
|
||||
else if (cur->Flags & COMMAND_LINE_VALUE_BOOL)
|
||||
{
|
||||
if (flags & COMMAND_LINE_SIGIL_ENABLE_DISABLE)
|
||||
{
|
||||
if (toggle == -1)
|
||||
cur->Value = BoolValueTrue;
|
||||
else if (!toggle)
|
||||
cur->Value = BoolValueFalse;
|
||||
else
|
||||
cur->Value = BoolValueTrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sigil[0] == '+')
|
||||
cur->Value = BoolValueTrue;
|
||||
else if (sigil[0] == '-')
|
||||
cur->Value = BoolValueFalse;
|
||||
else
|
||||
cur->Value = BoolValueTrue;
|
||||
}
|
||||
|
||||
cur->Flags |= COMMAND_LINE_VALUE_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (postFilter)
|
||||
{
|
||||
count = postFilter(context, &options[j]);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
log_error(flags, "PostFilter rule could not be applied", i, argv[i]);
|
||||
status = COMMAND_LINE_ERROR;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->Flags & COMMAND_LINE_PRINT)
|
||||
return COMMAND_LINE_STATUS_PRINT;
|
||||
else if (cur->Flags & COMMAND_LINE_PRINT_HELP)
|
||||
return COMMAND_LINE_STATUS_PRINT_HELP;
|
||||
else if (cur->Flags & COMMAND_LINE_PRINT_VERSION)
|
||||
return COMMAND_LINE_STATUS_PRINT_VERSION;
|
||||
else if (cur->Flags & COMMAND_LINE_PRINT_BUILDCONFIG)
|
||||
return COMMAND_LINE_STATUS_PRINT_BUILDCONFIG;
|
||||
}
|
||||
|
||||
if (!found && (flags & COMMAND_LINE_IGN_UNKNOWN_KEYWORD) == 0)
|
||||
{
|
||||
log_error(flags, "Unexpected keyword", i, argv[i]);
|
||||
return COMMAND_LINE_ERROR_NO_KEYWORD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int CommandLineParseArgumentsW(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED LPWSTR* argv,
|
||||
WINPR_ATTR_UNUSED COMMAND_LINE_ARGUMENT_W* options,
|
||||
WINPR_ATTR_UNUSED DWORD flags, WINPR_ATTR_UNUSED void* context,
|
||||
WINPR_ATTR_UNUSED COMMAND_LINE_PRE_FILTER_FN_W preFilter,
|
||||
WINPR_ATTR_UNUSED COMMAND_LINE_POST_FILTER_FN_W postFilter)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CommandLineClearArgumentsA(COMMAND_LINE_ARGUMENT_A* options)
|
||||
{
|
||||
for (size_t i = 0; options[i].Name != nullptr; i++)
|
||||
{
|
||||
options[i].Flags &= COMMAND_LINE_INPUT_FLAG_MASK;
|
||||
options[i].Value = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CommandLineClearArgumentsW(COMMAND_LINE_ARGUMENT_W* options)
|
||||
{
|
||||
for (int i = 0; options[i].Name != nullptr; i++)
|
||||
{
|
||||
options[i].Flags &= COMMAND_LINE_INPUT_FLAG_MASK;
|
||||
options[i].Value = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const COMMAND_LINE_ARGUMENT_A* CommandLineFindArgumentA(const COMMAND_LINE_ARGUMENT_A* options,
|
||||
LPCSTR Name)
|
||||
{
|
||||
WINPR_ASSERT(options);
|
||||
WINPR_ASSERT(Name);
|
||||
|
||||
for (size_t i = 0; options[i].Name != nullptr; i++)
|
||||
{
|
||||
if (strcmp(options[i].Name, Name) == 0)
|
||||
return &options[i];
|
||||
|
||||
if (options[i].Alias != nullptr)
|
||||
{
|
||||
if (strcmp(options[i].Alias, Name) == 0)
|
||||
return &options[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const COMMAND_LINE_ARGUMENT_W* CommandLineFindArgumentW(const COMMAND_LINE_ARGUMENT_W* options,
|
||||
LPCWSTR Name)
|
||||
{
|
||||
WINPR_ASSERT(options);
|
||||
WINPR_ASSERT(Name);
|
||||
|
||||
for (size_t i = 0; options[i].Name != nullptr; i++)
|
||||
{
|
||||
if (_wcscmp(options[i].Name, Name) == 0)
|
||||
return &options[i];
|
||||
|
||||
if (options[i].Alias != nullptr)
|
||||
{
|
||||
if (_wcscmp(options[i].Alias, Name) == 0)
|
||||
return &options[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const COMMAND_LINE_ARGUMENT_A* CommandLineFindNextArgumentA(const COMMAND_LINE_ARGUMENT_A* argument)
|
||||
{
|
||||
const COMMAND_LINE_ARGUMENT_A* nextArgument = nullptr;
|
||||
|
||||
if (!argument || !argument->Name)
|
||||
return nullptr;
|
||||
|
||||
nextArgument = &argument[1];
|
||||
|
||||
if (nextArgument->Name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return nextArgument;
|
||||
}
|
||||
|
||||
static int is_quoted(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
return 1;
|
||||
case '\'':
|
||||
return -1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_element_count(const char* list, BOOL* failed, BOOL fullquoted)
|
||||
{
|
||||
size_t count = 0;
|
||||
int quoted = 0;
|
||||
bool escaped = false;
|
||||
BOOL finished = FALSE;
|
||||
BOOL first = TRUE;
|
||||
const char* it = list;
|
||||
|
||||
if (!list)
|
||||
return 0;
|
||||
if (strlen(list) == 0)
|
||||
return 0;
|
||||
|
||||
while (!finished)
|
||||
{
|
||||
BOOL nextFirst = FALSE;
|
||||
|
||||
const char cur = *it++;
|
||||
|
||||
/* Ignore the symbol that was escaped. */
|
||||
if (escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cur)
|
||||
{
|
||||
case '\0':
|
||||
if (quoted != 0)
|
||||
{
|
||||
log_comma_error("Invalid argument (missing closing quote)", list);
|
||||
*failed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
finished = TRUE;
|
||||
break;
|
||||
case '\\':
|
||||
if (!escaped)
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
if (!fullquoted)
|
||||
{
|
||||
int now = is_quoted(cur) && !escaped;
|
||||
if (now == quoted)
|
||||
quoted = 0;
|
||||
else if (quoted == 0)
|
||||
quoted = now;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (first)
|
||||
{
|
||||
log_comma_error("Invalid argument (empty list elements)", list);
|
||||
*failed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
if (quoted == 0)
|
||||
{
|
||||
nextFirst = TRUE;
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
first = nextFirst;
|
||||
}
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
static char* get_next_comma(char* string, BOOL fullquoted)
|
||||
{
|
||||
const char* log = string;
|
||||
int quoted = 0;
|
||||
bool first = true;
|
||||
bool escaped = false;
|
||||
|
||||
WINPR_ASSERT(string);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
char* last = string;
|
||||
const char cur = *string++;
|
||||
if (escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cur)
|
||||
{
|
||||
case '\0':
|
||||
if (quoted != 0)
|
||||
log_comma_error("Invalid quoted argument", log);
|
||||
return nullptr;
|
||||
|
||||
case '\\':
|
||||
if (!escaped)
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
if (!fullquoted)
|
||||
{
|
||||
int now = is_quoted(cur);
|
||||
if ((quoted == 0) && !first)
|
||||
{
|
||||
log_comma_error("Invalid quoted argument", log);
|
||||
return nullptr;
|
||||
}
|
||||
if (now == quoted)
|
||||
quoted = 0;
|
||||
else if (quoted == 0)
|
||||
quoted = now;
|
||||
}
|
||||
break;
|
||||
|
||||
case ',':
|
||||
if (first)
|
||||
{
|
||||
log_comma_error("Invalid argument (empty list elements)", log);
|
||||
return nullptr;
|
||||
}
|
||||
if (quoted == 0)
|
||||
return last;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL is_valid_fullquoted(const char* string)
|
||||
{
|
||||
char cur = '\0';
|
||||
char last = '\0';
|
||||
const char quote = *string++;
|
||||
|
||||
/* We did not start with a quote. */
|
||||
if (is_quoted(quote) == 0)
|
||||
return FALSE;
|
||||
|
||||
while ((cur = *string++) != '\0')
|
||||
{
|
||||
/* A quote is found. */
|
||||
if (cur == quote)
|
||||
{
|
||||
/* If the quote was escaped, it is valid. */
|
||||
if (last != '\\')
|
||||
{
|
||||
/* Only allow unescaped quote as last character in string. */
|
||||
if (*string != '\0')
|
||||
return FALSE;
|
||||
}
|
||||
/* If the last quote in the string is escaped, it is wrong. */
|
||||
else if (*string != '\0')
|
||||
return FALSE;
|
||||
}
|
||||
last = cur;
|
||||
}
|
||||
|
||||
/* The string did not terminate with the same quote as it started. */
|
||||
return (last == quote);
|
||||
}
|
||||
|
||||
char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list, size_t* count)
|
||||
{
|
||||
char** p = nullptr;
|
||||
char* str = nullptr;
|
||||
size_t nArgs = 0;
|
||||
size_t prefix = 0;
|
||||
size_t len = 0;
|
||||
size_t namelen = 0;
|
||||
BOOL failed = FALSE;
|
||||
char* copy = nullptr;
|
||||
char* unquoted = nullptr;
|
||||
BOOL fullquoted = FALSE;
|
||||
|
||||
BOOL success = FALSE;
|
||||
if (count == nullptr)
|
||||
goto fail;
|
||||
|
||||
*count = 0;
|
||||
if (list)
|
||||
{
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
unquoted = copy = _strdup(list);
|
||||
if (!copy)
|
||||
goto fail;
|
||||
|
||||
len = strlen(unquoted);
|
||||
if (len > 0)
|
||||
{
|
||||
start = is_quoted(unquoted[0]);
|
||||
end = is_quoted(unquoted[len - 1]);
|
||||
|
||||
if ((start != 0) && (end != 0))
|
||||
{
|
||||
if (start != end)
|
||||
{
|
||||
log_comma_error("Invalid argument (quote mismatch)", list);
|
||||
goto fail;
|
||||
}
|
||||
if (!is_valid_fullquoted(unquoted))
|
||||
goto fail;
|
||||
unquoted[len - 1] = '\0';
|
||||
unquoted++;
|
||||
len -= 2;
|
||||
fullquoted = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*count = get_element_count(unquoted, &failed, fullquoted);
|
||||
if (failed)
|
||||
goto fail;
|
||||
|
||||
if (*count == 0)
|
||||
{
|
||||
if (!name)
|
||||
goto fail;
|
||||
else
|
||||
{
|
||||
size_t clen = strlen(name);
|
||||
p = (char**)calloc(2UL + clen, sizeof(char*));
|
||||
|
||||
if (p)
|
||||
{
|
||||
char* dst = (char*)&p[1];
|
||||
p[0] = dst;
|
||||
(void)sprintf_s(dst, clen + 1, "%s", name);
|
||||
*count = 1;
|
||||
success = TRUE;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nArgs = *count;
|
||||
|
||||
if (name)
|
||||
nArgs++;
|
||||
|
||||
prefix = (nArgs + 1UL) * sizeof(char*);
|
||||
if (name)
|
||||
namelen = strlen(name);
|
||||
p = (char**)calloc(len + prefix + 1 + namelen + 1, sizeof(char*));
|
||||
|
||||
if (!p)
|
||||
goto fail;
|
||||
|
||||
str = &((char*)p)[prefix];
|
||||
memcpy(str, unquoted, len);
|
||||
|
||||
if (name)
|
||||
{
|
||||
char* namestr = &((char*)p)[prefix + len + 1];
|
||||
memcpy(namestr, name, namelen);
|
||||
|
||||
p[0] = namestr;
|
||||
}
|
||||
|
||||
for (size_t index = name ? 1 : 0; index < nArgs; index++)
|
||||
{
|
||||
char* ptr = str;
|
||||
const int quote = is_quoted(*ptr);
|
||||
char* comma = get_next_comma(str, fullquoted);
|
||||
|
||||
if ((quote != 0) && !fullquoted)
|
||||
ptr++;
|
||||
|
||||
p[index] = ptr;
|
||||
|
||||
if (comma)
|
||||
{
|
||||
char* last = comma - 1;
|
||||
const int lastQuote = is_quoted(*last);
|
||||
|
||||
if (!fullquoted)
|
||||
{
|
||||
if (lastQuote != quote)
|
||||
{
|
||||
log_comma_error("Invalid argument (quote mismatch)", list);
|
||||
goto fail;
|
||||
}
|
||||
else if (lastQuote != 0)
|
||||
*last = '\0';
|
||||
}
|
||||
*comma = '\0';
|
||||
|
||||
str = comma + 1;
|
||||
}
|
||||
else if (quote)
|
||||
{
|
||||
char* end = strrchr(ptr, '"');
|
||||
if (!end)
|
||||
goto fail;
|
||||
*end = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
*count = nArgs;
|
||||
success = TRUE;
|
||||
fail:
|
||||
free(copy);
|
||||
if (!success)
|
||||
{
|
||||
if (count)
|
||||
*count = 0;
|
||||
free((void*)p);
|
||||
return nullptr;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char** CommandLineParseCommaSeparatedValues(const char* list, size_t* count)
|
||||
{
|
||||
return CommandLineParseCommaSeparatedValuesEx(nullptr, list, count);
|
||||
}
|
||||
|
||||
char* CommandLineToCommaSeparatedValues(int argc, char* argv[])
|
||||
{
|
||||
return CommandLineToCommaSeparatedValuesEx(argc, argv, nullptr, 0);
|
||||
}
|
||||
|
||||
static const char* filtered(const char* arg, const char* filters[], size_t number)
|
||||
{
|
||||
if (number == 0)
|
||||
return arg;
|
||||
for (size_t x = 0; x < number; x++)
|
||||
{
|
||||
const char* filter = filters[x];
|
||||
size_t len = strlen(filter);
|
||||
if (_strnicmp(arg, filter, len) == 0)
|
||||
return &arg[len];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* CommandLineToCommaSeparatedValuesEx(int argc, char* argv[], const char* filters[],
|
||||
size_t number)
|
||||
{
|
||||
char* str = nullptr;
|
||||
size_t offset = 0;
|
||||
size_t size = WINPR_ASSERTING_INT_CAST(size_t, argc) + 1;
|
||||
if ((argc <= 0) || !argv)
|
||||
return nullptr;
|
||||
|
||||
for (int x = 0; x < argc; x++)
|
||||
size += strlen(argv[x]);
|
||||
|
||||
str = calloc(size, sizeof(char));
|
||||
if (!str)
|
||||
return nullptr;
|
||||
for (int x = 0; x < argc; x++)
|
||||
{
|
||||
int rc = 0;
|
||||
const char* arg = filtered(argv[x], filters, number);
|
||||
if (!arg)
|
||||
continue;
|
||||
rc = _snprintf(&str[offset], size - offset, "%s,", arg);
|
||||
if (rc <= 0)
|
||||
{
|
||||
free(str);
|
||||
return nullptr;
|
||||
}
|
||||
offset += (size_t)rc;
|
||||
}
|
||||
if (offset > 0)
|
||||
str[offset - 1] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
void CommandLineParserFree(char** ptr)
|
||||
{
|
||||
union
|
||||
{
|
||||
char* p;
|
||||
char** pp;
|
||||
} uptr;
|
||||
uptr.pp = ptr;
|
||||
free(uptr.p);
|
||||
}
|
||||
614
third_party/FreeRDP/winpr/libwinpr/utils/collections/ArrayList.c
vendored
Normal file
@@ -0,0 +1,614 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.ArrayList
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#if defined(_WIN32) && (_MSC_VER < 1800) && !defined(__MINGW32__)
|
||||
#define va_copy(dest, src) (dest = src)
|
||||
#endif
|
||||
|
||||
struct s_wArrayList
|
||||
{
|
||||
size_t capacity;
|
||||
size_t growthFactor;
|
||||
BOOL synchronized;
|
||||
|
||||
size_t size;
|
||||
void** array;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
wObject object;
|
||||
};
|
||||
|
||||
/**
|
||||
* C equivalent of the C# ArrayList Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.arraylist.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets or sets the number of elements that the ArrayList can contain.
|
||||
*/
|
||||
|
||||
size_t ArrayList_Capacity(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return arrayList->capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of elements actually contained in the ArrayList.
|
||||
*/
|
||||
|
||||
size_t ArrayList_Count(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return arrayList->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal list of items contained in the ArrayList.
|
||||
*/
|
||||
|
||||
size_t ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
*ppItems = (ULONG_PTR*)arrayList->array;
|
||||
return arrayList->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the ArrayList has a fixed size.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_IsFixedSized(WINPR_ATTR_UNUSED wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the ArrayList is read-only.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_IsReadOnly(WINPR_ATTR_UNUSED wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether access to the ArrayList is synchronized (thread safe).
|
||||
*/
|
||||
|
||||
BOOL ArrayList_IsSynchronized(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return arrayList->synchronized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock access to the ArrayList
|
||||
*/
|
||||
|
||||
static void ArrayList_Lock_Conditional(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (arrayList->synchronized)
|
||||
EnterCriticalSection(&arrayList->lock);
|
||||
}
|
||||
|
||||
void ArrayList_Lock(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
EnterCriticalSection(&arrayList->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock access to the ArrayList
|
||||
*/
|
||||
|
||||
static void ArrayList_Unlock_Conditional(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (arrayList->synchronized)
|
||||
LeaveCriticalSection(&arrayList->lock);
|
||||
}
|
||||
|
||||
void ArrayList_Unlock(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
LeaveCriticalSection(&arrayList->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the element at the specified index.
|
||||
*/
|
||||
|
||||
void* ArrayList_GetItem(wArrayList* arrayList, size_t index)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (index < arrayList->size)
|
||||
{
|
||||
obj = arrayList->array[index];
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the element at the specified index.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_SetItem(wArrayList* arrayList, size_t index, const void* obj)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (index >= arrayList->size)
|
||||
return FALSE;
|
||||
|
||||
if (arrayList->object.fnObjectNew)
|
||||
{
|
||||
arrayList->array[index] = arrayList->object.fnObjectNew(obj);
|
||||
if (obj && !arrayList->array[index])
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.cpv = obj;
|
||||
arrayList->array[index] = cnv.pv;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
static BOOL ArrayList_EnsureCapacity(wArrayList* arrayList, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
WINPR_ASSERT(count > 0);
|
||||
|
||||
if (arrayList->size + count > arrayList->capacity)
|
||||
{
|
||||
void** newArray = nullptr;
|
||||
size_t newCapacity = arrayList->capacity * arrayList->growthFactor;
|
||||
if (newCapacity < arrayList->size + count)
|
||||
newCapacity = arrayList->size + count;
|
||||
|
||||
newArray = (void**)realloc((void*)arrayList->array, sizeof(void*) * newCapacity);
|
||||
|
||||
if (!newArray)
|
||||
return FALSE;
|
||||
|
||||
arrayList->array = newArray;
|
||||
arrayList->capacity = newCapacity;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/**
|
||||
* Shift a section of the list.
|
||||
*/
|
||||
|
||||
static BOOL ArrayList_Shift(wArrayList* arrayList, size_t index, SSIZE_T count)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (count > 0)
|
||||
{
|
||||
if (!ArrayList_EnsureCapacity(arrayList, (size_t)count))
|
||||
return FALSE;
|
||||
|
||||
MoveMemory((void*)&arrayList->array[index + (size_t)count], (void*)&arrayList->array[index],
|
||||
(arrayList->size - index) * sizeof(void*));
|
||||
arrayList->size += (size_t)count;
|
||||
}
|
||||
else if (count < 0)
|
||||
{
|
||||
const size_t scount = WINPR_ASSERTING_INT_CAST(size_t, -count);
|
||||
const size_t off = index + scount;
|
||||
if (off < arrayList->size)
|
||||
{
|
||||
const size_t chunk = arrayList->size - off;
|
||||
MoveMemory((void*)&arrayList->array[index], (void*)&arrayList->array[off],
|
||||
chunk * sizeof(void*));
|
||||
}
|
||||
|
||||
arrayList->size -= scount;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the ArrayList.
|
||||
*/
|
||||
|
||||
void ArrayList_Clear(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
for (size_t index = 0; index < arrayList->size; index++)
|
||||
{
|
||||
if (arrayList->object.fnObjectFree)
|
||||
arrayList->object.fnObjectFree(arrayList->array[index]);
|
||||
|
||||
arrayList->array[index] = nullptr;
|
||||
}
|
||||
|
||||
arrayList->size = 0;
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an element is in the ArrayList.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_Contains(wArrayList* arrayList, const void* obj)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
for (size_t index = 0; index < arrayList->size; index++)
|
||||
{
|
||||
rc = arrayList->object.fnObjectEquals(arrayList->array[index], obj);
|
||||
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(WITH_WINPR_DEPRECATED)
|
||||
int ArrayList_Add(wArrayList* arrayList, const void* obj)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
if (!ArrayList_Append(arrayList, obj))
|
||||
return -1;
|
||||
return (int)ArrayList_Count(arrayList) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds an object to the end of the ArrayList.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_Append(wArrayList* arrayList, const void* obj)
|
||||
{
|
||||
size_t index = 0;
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
if (!ArrayList_EnsureCapacity(arrayList, 1))
|
||||
goto out;
|
||||
|
||||
index = arrayList->size++;
|
||||
rc = ArrayList_SetItem(arrayList, index, obj);
|
||||
out:
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts an element into the ArrayList at the specified index.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_Insert(wArrayList* arrayList, size_t index, const void* obj)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
if (index < arrayList->size)
|
||||
{
|
||||
if (!ArrayList_Shift(arrayList, index, 1))
|
||||
{
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList_SetItem(arrayList, index, obj);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first occurrence of a specific object from the ArrayList.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_Remove(wArrayList* arrayList, const void* obj)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
size_t index = 0;
|
||||
for (; index < arrayList->size; index++)
|
||||
{
|
||||
if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (arrayList->object.fnObjectFree)
|
||||
arrayList->object.fnObjectFree(arrayList->array[index]);
|
||||
|
||||
ret = ArrayList_Shift(arrayList, index, -1);
|
||||
}
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specified index of the ArrayList.
|
||||
*/
|
||||
|
||||
BOOL ArrayList_RemoveAt(wArrayList* arrayList, size_t index)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
if (index < arrayList->size)
|
||||
{
|
||||
if (arrayList->object.fnObjectFree)
|
||||
arrayList->object.fnObjectFree(arrayList->array[index]);
|
||||
|
||||
ret = ArrayList_Shift(arrayList, index, -1);
|
||||
}
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the specified Object and returns the zero-based index of the first occurrence within
|
||||
* the entire ArrayList.
|
||||
*
|
||||
* Searches for the specified Object and returns the zero-based index of the last occurrence within
|
||||
* the range of elements in the ArrayList that extends from the first element to the specified
|
||||
* index.
|
||||
*
|
||||
* Searches for the specified Object and returns the zero-based index of the last occurrence within
|
||||
* the range of elements in the ArrayList that contains the specified number of elements and ends at
|
||||
* the specified index.
|
||||
*/
|
||||
|
||||
SSIZE_T ArrayList_IndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex, SSIZE_T count)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
SSIZE_T sindex = startIndex;
|
||||
if (startIndex < 0)
|
||||
sindex = 0;
|
||||
|
||||
SSIZE_T index = sindex;
|
||||
SSIZE_T cindex = count;
|
||||
if (count < 0)
|
||||
{
|
||||
if (arrayList->size > SSIZE_MAX)
|
||||
goto fail;
|
||||
cindex = (SSIZE_T)arrayList->size;
|
||||
}
|
||||
|
||||
for (; index < sindex + cindex; index++)
|
||||
{
|
||||
if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
if (!found)
|
||||
index = -1;
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the specified Object and returns the zero-based index of the last occurrence within
|
||||
* the entire ArrayList.
|
||||
*
|
||||
* Searches for the specified Object and returns the zero-based index of the last occurrence within
|
||||
* the range of elements in the ArrayList that extends from the first element to the specified
|
||||
* index.
|
||||
*
|
||||
* Searches for the specified Object and returns the zero-based index of the last occurrence within
|
||||
* the range of elements in the ArrayList that contains the specified number of elements and ends at
|
||||
* the specified index.
|
||||
*/
|
||||
|
||||
SSIZE_T ArrayList_LastIndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex,
|
||||
SSIZE_T count)
|
||||
{
|
||||
SSIZE_T sindex = 0;
|
||||
SSIZE_T cindex = 0;
|
||||
BOOL found = FALSE;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
|
||||
sindex = startIndex;
|
||||
if (startIndex < 0)
|
||||
sindex = 0;
|
||||
|
||||
cindex = count;
|
||||
if (count < 0)
|
||||
{
|
||||
WINPR_ASSERT(arrayList->size <= SSIZE_MAX);
|
||||
cindex = (SSIZE_T)arrayList->size;
|
||||
}
|
||||
|
||||
SSIZE_T index = sindex + cindex;
|
||||
for (; index > sindex; index--)
|
||||
{
|
||||
if (arrayList->object.fnObjectEquals(arrayList->array[index - 1], obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
index = -1;
|
||||
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static BOOL ArrayList_DefaultCompare(const void* objA, const void* objB)
|
||||
{
|
||||
return (objA == objB);
|
||||
}
|
||||
|
||||
wObject* ArrayList_Object(wArrayList* arrayList)
|
||||
{
|
||||
WINPR_ASSERT(arrayList);
|
||||
return &arrayList->object;
|
||||
}
|
||||
|
||||
BOOL ArrayList_ForEach(wArrayList* arrayList, ArrayList_ForEachFkt fkt, ...)
|
||||
{
|
||||
BOOL rc = 0;
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
va_start(ap, fkt);
|
||||
rc = ArrayList_ForEachAP(arrayList, fkt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL ArrayList_ForEachAP(wArrayList* arrayList, ArrayList_ForEachFkt fkt, va_list ap)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
va_list cap = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(arrayList);
|
||||
WINPR_ASSERT(fkt);
|
||||
|
||||
ArrayList_Lock_Conditional(arrayList);
|
||||
size_t count = ArrayList_Count(arrayList);
|
||||
for (size_t index = 0; index < count; index++)
|
||||
{
|
||||
BOOL rs = 0;
|
||||
void* obj = ArrayList_GetItem(arrayList, index);
|
||||
va_copy(cap, ap);
|
||||
rs = fkt(obj, index, cap);
|
||||
va_end(cap);
|
||||
if (!rs)
|
||||
goto fail;
|
||||
}
|
||||
rc = TRUE;
|
||||
fail:
|
||||
ArrayList_Unlock_Conditional(arrayList);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wArrayList* ArrayList_New(BOOL synchronized)
|
||||
{
|
||||
wObject* obj = nullptr;
|
||||
wArrayList* arrayList = nullptr;
|
||||
arrayList = (wArrayList*)calloc(1, sizeof(wArrayList));
|
||||
|
||||
if (!arrayList)
|
||||
return nullptr;
|
||||
|
||||
arrayList->synchronized = synchronized;
|
||||
arrayList->growthFactor = 2;
|
||||
obj = ArrayList_Object(arrayList);
|
||||
if (!obj)
|
||||
goto fail;
|
||||
obj->fnObjectEquals = ArrayList_DefaultCompare;
|
||||
if (!ArrayList_EnsureCapacity(arrayList, 32))
|
||||
goto fail;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000))
|
||||
goto fail;
|
||||
return arrayList;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
ArrayList_Free(arrayList);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ArrayList_Free(wArrayList* arrayList)
|
||||
{
|
||||
if (!arrayList)
|
||||
return;
|
||||
|
||||
ArrayList_Clear(arrayList);
|
||||
DeleteCriticalSection(&arrayList->lock);
|
||||
free((void*)arrayList->array);
|
||||
free(arrayList);
|
||||
}
|
||||
177
third_party/FreeRDP/winpr/libwinpr/utils/collections/BitStream.c
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* BitStream
|
||||
*
|
||||
* 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/assert.h>
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/bitstream.h>
|
||||
|
||||
static const char* BYTE_BIT_STRINGS_LSB[256] = {
|
||||
"00000000", "00000001", "00000010", "00000011", "00000100", "00000101", "00000110", "00000111",
|
||||
"00001000", "00001001", "00001010", "00001011", "00001100", "00001101", "00001110", "00001111",
|
||||
"00010000", "00010001", "00010010", "00010011", "00010100", "00010101", "00010110", "00010111",
|
||||
"00011000", "00011001", "00011010", "00011011", "00011100", "00011101", "00011110", "00011111",
|
||||
"00100000", "00100001", "00100010", "00100011", "00100100", "00100101", "00100110", "00100111",
|
||||
"00101000", "00101001", "00101010", "00101011", "00101100", "00101101", "00101110", "00101111",
|
||||
"00110000", "00110001", "00110010", "00110011", "00110100", "00110101", "00110110", "00110111",
|
||||
"00111000", "00111001", "00111010", "00111011", "00111100", "00111101", "00111110", "00111111",
|
||||
"01000000", "01000001", "01000010", "01000011", "01000100", "01000101", "01000110", "01000111",
|
||||
"01001000", "01001001", "01001010", "01001011", "01001100", "01001101", "01001110", "01001111",
|
||||
"01010000", "01010001", "01010010", "01010011", "01010100", "01010101", "01010110", "01010111",
|
||||
"01011000", "01011001", "01011010", "01011011", "01011100", "01011101", "01011110", "01011111",
|
||||
"01100000", "01100001", "01100010", "01100011", "01100100", "01100101", "01100110", "01100111",
|
||||
"01101000", "01101001", "01101010", "01101011", "01101100", "01101101", "01101110", "01101111",
|
||||
"01110000", "01110001", "01110010", "01110011", "01110100", "01110101", "01110110", "01110111",
|
||||
"01111000", "01111001", "01111010", "01111011", "01111100", "01111101", "01111110", "01111111",
|
||||
"10000000", "10000001", "10000010", "10000011", "10000100", "10000101", "10000110", "10000111",
|
||||
"10001000", "10001001", "10001010", "10001011", "10001100", "10001101", "10001110", "10001111",
|
||||
"10010000", "10010001", "10010010", "10010011", "10010100", "10010101", "10010110", "10010111",
|
||||
"10011000", "10011001", "10011010", "10011011", "10011100", "10011101", "10011110", "10011111",
|
||||
"10100000", "10100001", "10100010", "10100011", "10100100", "10100101", "10100110", "10100111",
|
||||
"10101000", "10101001", "10101010", "10101011", "10101100", "10101101", "10101110", "10101111",
|
||||
"10110000", "10110001", "10110010", "10110011", "10110100", "10110101", "10110110", "10110111",
|
||||
"10111000", "10111001", "10111010", "10111011", "10111100", "10111101", "10111110", "10111111",
|
||||
"11000000", "11000001", "11000010", "11000011", "11000100", "11000101", "11000110", "11000111",
|
||||
"11001000", "11001001", "11001010", "11001011", "11001100", "11001101", "11001110", "11001111",
|
||||
"11010000", "11010001", "11010010", "11010011", "11010100", "11010101", "11010110", "11010111",
|
||||
"11011000", "11011001", "11011010", "11011011", "11011100", "11011101", "11011110", "11011111",
|
||||
"11100000", "11100001", "11100010", "11100011", "11100100", "11100101", "11100110", "11100111",
|
||||
"11101000", "11101001", "11101010", "11101011", "11101100", "11101101", "11101110", "11101111",
|
||||
"11110000", "11110001", "11110010", "11110011", "11110100", "11110101", "11110110", "11110111",
|
||||
"11111000", "11111001", "11111010", "11111011", "11111100", "11111101", "11111110", "11111111"
|
||||
};
|
||||
|
||||
static const char* BYTE_BIT_STRINGS_MSB[256] = {
|
||||
"00000000", "10000000", "01000000", "11000000", "00100000", "10100000", "01100000", "11100000",
|
||||
"00010000", "10010000", "01010000", "11010000", "00110000", "10110000", "01110000", "11110000",
|
||||
"00001000", "10001000", "01001000", "11001000", "00101000", "10101000", "01101000", "11101000",
|
||||
"00011000", "10011000", "01011000", "11011000", "00111000", "10111000", "01111000", "11111000",
|
||||
"00000100", "10000100", "01000100", "11000100", "00100100", "10100100", "01100100", "11100100",
|
||||
"00010100", "10010100", "01010100", "11010100", "00110100", "10110100", "01110100", "11110100",
|
||||
"00001100", "10001100", "01001100", "11001100", "00101100", "10101100", "01101100", "11101100",
|
||||
"00011100", "10011100", "01011100", "11011100", "00111100", "10111100", "01111100", "11111100",
|
||||
"00000010", "10000010", "01000010", "11000010", "00100010", "10100010", "01100010", "11100010",
|
||||
"00010010", "10010010", "01010010", "11010010", "00110010", "10110010", "01110010", "11110010",
|
||||
"00001010", "10001010", "01001010", "11001010", "00101010", "10101010", "01101010", "11101010",
|
||||
"00011010", "10011010", "01011010", "11011010", "00111010", "10111010", "01111010", "11111010",
|
||||
"00000110", "10000110", "01000110", "11000110", "00100110", "10100110", "01100110", "11100110",
|
||||
"00010110", "10010110", "01010110", "11010110", "00110110", "10110110", "01110110", "11110110",
|
||||
"00001110", "10001110", "01001110", "11001110", "00101110", "10101110", "01101110", "11101110",
|
||||
"00011110", "10011110", "01011110", "11011110", "00111110", "10111110", "01111110", "11111110",
|
||||
"00000001", "10000001", "01000001", "11000001", "00100001", "10100001", "01100001", "11100001",
|
||||
"00010001", "10010001", "01010001", "11010001", "00110001", "10110001", "01110001", "11110001",
|
||||
"00001001", "10001001", "01001001", "11001001", "00101001", "10101001", "01101001", "11101001",
|
||||
"00011001", "10011001", "01011001", "11011001", "00111001", "10111001", "01111001", "11111001",
|
||||
"00000101", "10000101", "01000101", "11000101", "00100101", "10100101", "01100101", "11100101",
|
||||
"00010101", "10010101", "01010101", "11010101", "00110101", "10110101", "01110101", "11110101",
|
||||
"00001101", "10001101", "01001101", "11001101", "00101101", "10101101", "01101101", "11101101",
|
||||
"00011101", "10011101", "01011101", "11011101", "00111101", "10111101", "01111101", "11111101",
|
||||
"00000011", "10000011", "01000011", "11000011", "00100011", "10100011", "01100011", "11100011",
|
||||
"00010011", "10010011", "01010011", "11010011", "00110011", "10110011", "01110011", "11110011",
|
||||
"00001011", "10001011", "01001011", "11001011", "00101011", "10101011", "01101011", "11101011",
|
||||
"00011011", "10011011", "01011011", "11011011", "00111011", "10111011", "01111011", "11111011",
|
||||
"00000111", "10000111", "01000111", "11000111", "00100111", "10100111", "01100111", "11100111",
|
||||
"00010111", "10010111", "01010111", "11010111", "00110111", "10110111", "01110111", "11110111",
|
||||
"00001111", "10001111", "01001111", "11001111", "00101111", "10101111", "01101111", "11101111",
|
||||
"00011111", "10011111", "01011111", "11011111", "00111111", "10111111", "01111111", "11111111"
|
||||
};
|
||||
|
||||
void BitDump(const char* tag, UINT32 level, const BYTE* buffer, UINT32 length, UINT32 flags)
|
||||
{
|
||||
const char** strs = (flags & BITDUMP_MSB_FIRST) ? BYTE_BIT_STRINGS_MSB : BYTE_BIT_STRINGS_LSB;
|
||||
char pbuffer[64 * 8 + 1] = WINPR_C_ARRAY_INIT;
|
||||
size_t pos = 0;
|
||||
|
||||
WINPR_ASSERT(tag);
|
||||
WINPR_ASSERT(buffer || (length == 0));
|
||||
|
||||
DWORD i = 0;
|
||||
for (; i < length; i += 8)
|
||||
{
|
||||
const char* str = strs[buffer[i / 8]];
|
||||
const DWORD nbits = (length - i) > 8 ? 8 : (length - i);
|
||||
WINPR_ASSERT(nbits <= INT32_MAX);
|
||||
const int rc = _snprintf(&pbuffer[pos], length - pos, "%.*s ", (int)nbits, str);
|
||||
if (rc < 0)
|
||||
return;
|
||||
|
||||
pos += (size_t)rc;
|
||||
if ((i % 64) == 0)
|
||||
{
|
||||
pos = 0;
|
||||
WLog_LVL(tag, level, "%s", pbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
WLog_LVL(tag, level, "%s ", pbuffer);
|
||||
}
|
||||
|
||||
UINT32 ReverseBits32(UINT32 bits, UINT32 nbits)
|
||||
{
|
||||
UINT32 rbits = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rbits = (rbits | (bits & 1)) << 1;
|
||||
bits >>= 1;
|
||||
nbits--;
|
||||
} while (nbits > 0);
|
||||
|
||||
rbits >>= 1;
|
||||
return rbits;
|
||||
}
|
||||
|
||||
void BitStream_Attach(wBitStream* bs, const BYTE* buffer, UINT32 capacity)
|
||||
{
|
||||
union
|
||||
{
|
||||
const BYTE* cpv;
|
||||
BYTE* pv;
|
||||
} cnv;
|
||||
|
||||
WINPR_ASSERT(bs);
|
||||
WINPR_ASSERT(buffer);
|
||||
|
||||
cnv.cpv = buffer;
|
||||
|
||||
bs->position = 0;
|
||||
bs->buffer = cnv.pv;
|
||||
bs->offset = 0;
|
||||
bs->accumulator = 0;
|
||||
bs->pointer = cnv.pv;
|
||||
bs->capacity = capacity;
|
||||
bs->length = bs->capacity * 8;
|
||||
}
|
||||
|
||||
wBitStream* BitStream_New(void)
|
||||
{
|
||||
wBitStream* bs = (wBitStream*)calloc(1, sizeof(wBitStream));
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
void BitStream_Free(wBitStream* bs)
|
||||
{
|
||||
if (!bs)
|
||||
return;
|
||||
|
||||
free(bs);
|
||||
}
|
||||
597
third_party/FreeRDP/winpr/libwinpr/utils/collections/BufferPool.c
vendored
Normal file
@@ -0,0 +1,597 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Buffer Pool
|
||||
*
|
||||
* 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/collections.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b)) ? (a) : (b)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SSIZE_T size;
|
||||
void* buffer;
|
||||
} wBufferPoolItem;
|
||||
|
||||
struct s_wBufferPool
|
||||
{
|
||||
SSIZE_T fixedSize;
|
||||
DWORD alignment;
|
||||
BOOL synchronized;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
SSIZE_T size;
|
||||
SSIZE_T capacity;
|
||||
void** array;
|
||||
|
||||
SSIZE_T aSize;
|
||||
SSIZE_T aCapacity;
|
||||
wBufferPoolItem* aArray;
|
||||
|
||||
SSIZE_T uSize;
|
||||
SSIZE_T uCapacity;
|
||||
wBufferPoolItem* uArray;
|
||||
};
|
||||
|
||||
static BOOL BufferPool_Lock(wBufferPool* pool)
|
||||
{
|
||||
if (!pool)
|
||||
return FALSE;
|
||||
|
||||
if (pool->synchronized)
|
||||
EnterCriticalSection(&pool->lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL BufferPool_Unlock(wBufferPool* pool)
|
||||
{
|
||||
if (!pool)
|
||||
return FALSE;
|
||||
|
||||
if (pool->synchronized)
|
||||
LeaveCriticalSection(&pool->lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* C equivalent of the C# BufferManager Class:
|
||||
* http://msdn.microsoft.com/en-us/library/ms405814.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
static BOOL BufferPool_ShiftAvailable(wBufferPool* pool, size_t index, int count)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
if (pool->aSize + count > pool->aCapacity)
|
||||
{
|
||||
wBufferPoolItem* newArray = nullptr;
|
||||
SSIZE_T newCapacity = pool->aSize + count;
|
||||
newCapacity += (newCapacity + 2) / 2;
|
||||
|
||||
WINPR_ASSERT(newCapacity > 0);
|
||||
if (pool->alignment > 0)
|
||||
newArray = (wBufferPoolItem*)winpr_aligned_realloc(
|
||||
pool->aArray,
|
||||
sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity),
|
||||
pool->alignment);
|
||||
else
|
||||
newArray = (wBufferPoolItem*)realloc(
|
||||
pool->aArray,
|
||||
sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
|
||||
if (!newArray)
|
||||
return FALSE;
|
||||
pool->aArray = newArray;
|
||||
pool->aCapacity = newCapacity;
|
||||
}
|
||||
|
||||
MoveMemory(
|
||||
&pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, count)], &pool->aArray[index],
|
||||
(WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
|
||||
pool->aSize += count;
|
||||
}
|
||||
else if (count < 0)
|
||||
{
|
||||
MoveMemory(
|
||||
&pool->aArray[index], &pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, -count)],
|
||||
(WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
|
||||
pool->aSize += count;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL BufferPool_ShiftUsed(wBufferPool* pool, SSIZE_T index, SSIZE_T count)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
const SSIZE_T required = pool->uSize + count;
|
||||
// check for overflow
|
||||
if ((required < count) || (required < pool->uSize))
|
||||
return FALSE;
|
||||
|
||||
if (required > pool->uCapacity)
|
||||
{
|
||||
SSIZE_T newUCapacity = pool->uCapacity;
|
||||
do
|
||||
{
|
||||
if (newUCapacity > SSIZE_MAX - 128ll)
|
||||
return FALSE;
|
||||
newUCapacity += 128ll;
|
||||
} while (newUCapacity <= required);
|
||||
wBufferPoolItem* newUArray = nullptr;
|
||||
if (pool->alignment > 0)
|
||||
newUArray = (wBufferPoolItem*)winpr_aligned_realloc(
|
||||
pool->uArray,
|
||||
sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity),
|
||||
pool->alignment);
|
||||
else
|
||||
newUArray = (wBufferPoolItem*)realloc(
|
||||
pool->uArray,
|
||||
sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity));
|
||||
if (!newUArray)
|
||||
return FALSE;
|
||||
pool->uCapacity = newUCapacity;
|
||||
pool->uArray = newUArray;
|
||||
}
|
||||
|
||||
MoveMemory(&pool->uArray[index + count], &pool->uArray[index],
|
||||
WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
|
||||
pool->uSize += count;
|
||||
}
|
||||
else if (count < 0)
|
||||
{
|
||||
MoveMemory(&pool->uArray[index], &pool->uArray[index - count],
|
||||
WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
|
||||
pool->uSize += count;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the buffer pool size
|
||||
*/
|
||||
|
||||
SSIZE_T BufferPool_GetPoolSize(wBufferPool* pool)
|
||||
{
|
||||
SSIZE_T size = 0;
|
||||
|
||||
BufferPool_Lock(pool);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
size = pool->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
size = pool->uSize;
|
||||
}
|
||||
|
||||
BufferPool_Unlock(pool);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of a pooled buffer
|
||||
*/
|
||||
|
||||
SSIZE_T BufferPool_GetBufferSize(wBufferPool* pool, const void* buffer)
|
||||
{
|
||||
SSIZE_T size = 0;
|
||||
BOOL found = FALSE;
|
||||
|
||||
BufferPool_Lock(pool);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
size = pool->fixedSize;
|
||||
found = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
for (SSIZE_T index = 0; index < pool->uSize; index++)
|
||||
{
|
||||
if (pool->uArray[index].buffer == buffer)
|
||||
{
|
||||
size = pool->uArray[index].size;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BufferPool_Unlock(pool);
|
||||
|
||||
return (found) ? size : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffer of at least the specified size from the pool.
|
||||
*/
|
||||
|
||||
void* BufferPool_Take(wBufferPool* pool, SSIZE_T size)
|
||||
{
|
||||
SSIZE_T maxSize = 0;
|
||||
SSIZE_T maxIndex = 0;
|
||||
SSIZE_T foundIndex = -1;
|
||||
BOOL found = FALSE;
|
||||
void* buffer = nullptr;
|
||||
|
||||
BufferPool_Lock(pool);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
|
||||
if (pool->size > 0)
|
||||
buffer = pool->array[--(pool->size)];
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
if (pool->alignment)
|
||||
buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize),
|
||||
pool->alignment);
|
||||
else
|
||||
buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize));
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
goto out_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
maxSize = 0;
|
||||
maxIndex = 0;
|
||||
|
||||
if (size < 1)
|
||||
size = pool->fixedSize;
|
||||
|
||||
for (SSIZE_T index = 0; index < pool->aSize; index++)
|
||||
{
|
||||
if (pool->aArray[index].size > maxSize)
|
||||
{
|
||||
maxIndex = index;
|
||||
maxSize = pool->aArray[index].size;
|
||||
}
|
||||
|
||||
if (pool->aArray[index].size >= size)
|
||||
{
|
||||
foundIndex = index;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && maxSize)
|
||||
{
|
||||
foundIndex = maxIndex;
|
||||
found = TRUE;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (!size)
|
||||
buffer = nullptr;
|
||||
else
|
||||
{
|
||||
if (pool->alignment)
|
||||
buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, size),
|
||||
pool->alignment);
|
||||
else
|
||||
buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, size));
|
||||
|
||||
if (!buffer)
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = pool->aArray[foundIndex].buffer;
|
||||
|
||||
if (maxSize < size)
|
||||
{
|
||||
void* newBuffer = nullptr;
|
||||
if (pool->alignment)
|
||||
newBuffer = winpr_aligned_realloc(
|
||||
buffer, WINPR_ASSERTING_INT_CAST(size_t, size), pool->alignment);
|
||||
else
|
||||
newBuffer = realloc(buffer, WINPR_ASSERTING_INT_CAST(size_t, size));
|
||||
|
||||
if (!newBuffer)
|
||||
goto out_error_no_free;
|
||||
|
||||
buffer = newBuffer;
|
||||
}
|
||||
|
||||
if (!BufferPool_ShiftAvailable(pool, WINPR_ASSERTING_INT_CAST(size_t, foundIndex), -1))
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
goto out_error;
|
||||
|
||||
if (pool->uSize + 1 > pool->uCapacity)
|
||||
{
|
||||
size_t newUCapacity = WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity);
|
||||
newUCapacity += (newUCapacity + 2) / 2;
|
||||
if (newUCapacity > SSIZE_MAX)
|
||||
goto out_error;
|
||||
wBufferPoolItem* newUArray =
|
||||
(wBufferPoolItem*)realloc(pool->uArray, sizeof(wBufferPoolItem) * newUCapacity);
|
||||
if (!newUArray)
|
||||
goto out_error;
|
||||
|
||||
pool->uCapacity = (SSIZE_T)newUCapacity;
|
||||
pool->uArray = newUArray;
|
||||
}
|
||||
|
||||
pool->uArray[pool->uSize].buffer = buffer;
|
||||
pool->uArray[pool->uSize].size = size;
|
||||
(pool->uSize)++;
|
||||
}
|
||||
|
||||
BufferPool_Unlock(pool);
|
||||
|
||||
return buffer;
|
||||
|
||||
out_error:
|
||||
if (pool->alignment)
|
||||
winpr_aligned_free(buffer);
|
||||
else
|
||||
free(buffer);
|
||||
out_error_no_free:
|
||||
BufferPool_Unlock(pool);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a buffer to the pool.
|
||||
*/
|
||||
|
||||
BOOL BufferPool_Return(wBufferPool* pool, void* buffer)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
SSIZE_T size = 0;
|
||||
BOOL found = FALSE;
|
||||
|
||||
BufferPool_Lock(pool);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
|
||||
if ((pool->size + 1) >= pool->capacity)
|
||||
{
|
||||
SSIZE_T newCapacity = MAX(2, pool->size + (pool->size + 2) / 2 + 1);
|
||||
void** newArray = (void**)realloc(
|
||||
(void*)pool->array, sizeof(void*) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
|
||||
if (!newArray)
|
||||
goto out_error;
|
||||
|
||||
pool->capacity = newCapacity;
|
||||
pool->array = newArray;
|
||||
}
|
||||
|
||||
pool->array[(pool->size)++] = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
SSIZE_T index = 0;
|
||||
for (; index < pool->uSize; index++)
|
||||
{
|
||||
if (pool->uArray[index].buffer == buffer)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
size = pool->uArray[index].size;
|
||||
if (!BufferPool_ShiftUsed(pool, index, -1))
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (size)
|
||||
{
|
||||
if ((pool->aSize + 1) >= pool->aCapacity)
|
||||
{
|
||||
SSIZE_T newCapacity = MAX(2, pool->aSize + (pool->aSize + 2) / 2 + 1);
|
||||
wBufferPoolItem* newArray = (wBufferPoolItem*)realloc(
|
||||
pool->aArray,
|
||||
sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
|
||||
if (!newArray)
|
||||
goto out_error;
|
||||
|
||||
pool->aCapacity = newCapacity;
|
||||
pool->aArray = newArray;
|
||||
}
|
||||
|
||||
pool->aArray[pool->aSize].buffer = buffer;
|
||||
pool->aArray[pool->aSize].size = size;
|
||||
(pool->aSize)++;
|
||||
}
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
out_error:
|
||||
BufferPool_Unlock(pool);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the buffers currently cached in the pool.
|
||||
*/
|
||||
|
||||
void BufferPool_Clear(wBufferPool* pool)
|
||||
{
|
||||
BufferPool_Lock(pool);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
|
||||
while (pool->size > 0)
|
||||
{
|
||||
(pool->size)--;
|
||||
|
||||
if (pool->alignment)
|
||||
winpr_aligned_free(pool->array[pool->size]);
|
||||
else
|
||||
free(pool->array[pool->size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
while (pool->aSize > 0)
|
||||
{
|
||||
(pool->aSize)--;
|
||||
|
||||
if (pool->alignment)
|
||||
winpr_aligned_free(pool->aArray[pool->aSize].buffer);
|
||||
else
|
||||
free(pool->aArray[pool->aSize].buffer);
|
||||
}
|
||||
|
||||
while (pool->uSize > 0)
|
||||
{
|
||||
(pool->uSize)--;
|
||||
|
||||
if (pool->alignment)
|
||||
winpr_aligned_free(pool->uArray[pool->uSize].buffer);
|
||||
else
|
||||
free(pool->uArray[pool->uSize].buffer);
|
||||
}
|
||||
}
|
||||
|
||||
BufferPool_Unlock(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wBufferPool* BufferPool_New(BOOL synchronized, SSIZE_T fixedSize, DWORD alignment)
|
||||
{
|
||||
wBufferPool* pool = nullptr;
|
||||
|
||||
pool = (wBufferPool*)calloc(1, sizeof(wBufferPool));
|
||||
|
||||
if (pool)
|
||||
{
|
||||
pool->fixedSize = fixedSize;
|
||||
|
||||
if (pool->fixedSize < 0)
|
||||
pool->fixedSize = 0;
|
||||
|
||||
pool->alignment = alignment;
|
||||
pool->synchronized = synchronized;
|
||||
|
||||
if (pool->synchronized)
|
||||
{
|
||||
if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
|
||||
pool->size = 0;
|
||||
pool->capacity = 32;
|
||||
pool->array =
|
||||
(void**)calloc(WINPR_ASSERTING_INT_CAST(size_t, pool->capacity), sizeof(void*));
|
||||
if (!pool->array)
|
||||
goto out_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
pool->aSize = 0;
|
||||
pool->aCapacity = 32;
|
||||
pool->aArray = (wBufferPoolItem*)calloc(
|
||||
WINPR_ASSERTING_INT_CAST(size_t, pool->aCapacity), sizeof(wBufferPoolItem));
|
||||
if (!pool->aArray)
|
||||
goto out_error;
|
||||
|
||||
pool->uSize = 0;
|
||||
pool->uCapacity = 32;
|
||||
pool->uArray = (wBufferPoolItem*)calloc(
|
||||
WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity), sizeof(wBufferPoolItem));
|
||||
if (!pool->uArray)
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
|
||||
return pool;
|
||||
|
||||
out_error:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
BufferPool_Free(pool);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BufferPool_Free(wBufferPool* pool)
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
BufferPool_Clear(pool);
|
||||
|
||||
if (pool->synchronized)
|
||||
DeleteCriticalSection(&pool->lock);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
/* fixed size buffers */
|
||||
|
||||
free((void*)pool->array);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* variable size buffers */
|
||||
|
||||
free(pool->aArray);
|
||||
free(pool->uArray);
|
||||
}
|
||||
|
||||
free(pool);
|
||||
}
|
||||
}
|
||||
210
third_party/FreeRDP/winpr/libwinpr/utils/collections/CountdownEvent.c
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Countdown Event
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
struct CountdownEvent
|
||||
{
|
||||
size_t count;
|
||||
CRITICAL_SECTION lock;
|
||||
HANDLE event;
|
||||
size_t initialCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* C equivalent of the C# CountdownEvent Class
|
||||
* http://msdn.microsoft.com/en-us/library/dd235708/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of remaining signals required to set the event.
|
||||
*/
|
||||
|
||||
size_t CountdownEvent_CurrentCount(wCountdownEvent* countdown)
|
||||
{
|
||||
WINPR_ASSERT(countdown);
|
||||
EnterCriticalSection(&countdown->lock);
|
||||
const size_t rc = countdown->count;
|
||||
LeaveCriticalSection(&countdown->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numbers of signals initially required to set the event.
|
||||
*/
|
||||
|
||||
size_t CountdownEvent_InitialCount(wCountdownEvent* countdown)
|
||||
{
|
||||
WINPR_ASSERT(countdown);
|
||||
EnterCriticalSection(&countdown->lock);
|
||||
const size_t rc = countdown->initialCount;
|
||||
LeaveCriticalSection(&countdown->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the event is set.
|
||||
*/
|
||||
|
||||
BOOL CountdownEvent_IsSet(wCountdownEvent* countdown)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
|
||||
WINPR_ASSERT(countdown);
|
||||
if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
|
||||
status = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a WaitHandle that is used to wait for the event to be set.
|
||||
*/
|
||||
|
||||
HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown)
|
||||
{
|
||||
WINPR_ASSERT(countdown);
|
||||
return countdown->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Increments the CountdownEvent's current count by a specified value.
|
||||
*/
|
||||
|
||||
void CountdownEvent_AddCount(wCountdownEvent* countdown, size_t signalCount)
|
||||
{
|
||||
WINPR_ASSERT(countdown);
|
||||
EnterCriticalSection(&countdown->lock);
|
||||
|
||||
const BOOL signalSet = countdown->count == 0;
|
||||
countdown->count += signalCount;
|
||||
|
||||
if (signalSet)
|
||||
(void)ResetEvent(countdown->event);
|
||||
|
||||
LeaveCriticalSection(&countdown->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the
|
||||
* specified amount.
|
||||
*/
|
||||
|
||||
BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
BOOL newStatus = FALSE;
|
||||
BOOL oldStatus = FALSE;
|
||||
|
||||
WINPR_ASSERT(countdown);
|
||||
|
||||
EnterCriticalSection(&countdown->lock);
|
||||
|
||||
if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
|
||||
oldStatus = TRUE;
|
||||
|
||||
if (signalCount <= countdown->count)
|
||||
countdown->count -= signalCount;
|
||||
else
|
||||
countdown->count = 0;
|
||||
|
||||
if (countdown->count == 0)
|
||||
newStatus = TRUE;
|
||||
|
||||
if (newStatus && (!oldStatus))
|
||||
{
|
||||
(void)SetEvent(countdown->event);
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&countdown->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the InitialCount property to a specified value.
|
||||
*/
|
||||
|
||||
void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(countdown);
|
||||
countdown->initialCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wCountdownEvent* CountdownEvent_New(size_t initialCount)
|
||||
{
|
||||
wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent));
|
||||
|
||||
if (!countdown)
|
||||
return nullptr;
|
||||
|
||||
countdown->count = initialCount;
|
||||
countdown->initialCount = initialCount;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000))
|
||||
goto fail;
|
||||
|
||||
countdown->event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!countdown->event)
|
||||
goto fail;
|
||||
|
||||
if (countdown->count == 0)
|
||||
{
|
||||
if (!SetEvent(countdown->event))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return countdown;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
CountdownEvent_Free(countdown);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CountdownEvent_Free(wCountdownEvent* countdown)
|
||||
{
|
||||
if (!countdown)
|
||||
return;
|
||||
|
||||
DeleteCriticalSection(&countdown->lock);
|
||||
(void)CloseHandle(countdown->event);
|
||||
|
||||
free(countdown);
|
||||
}
|
||||
873
third_party/FreeRDP/winpr/libwinpr/utils/collections/HashTable.c
vendored
Normal file
@@ -0,0 +1,873 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.Hashtable
|
||||
*
|
||||
* 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/assert.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
/**
|
||||
* This implementation is based on the public domain
|
||||
* hash table implementation made by Keith Pomakis:
|
||||
*
|
||||
* http://www.pomakis.com/hashtable/hashtable.c
|
||||
* http://www.pomakis.com/hashtable/hashtable.h
|
||||
*/
|
||||
|
||||
typedef struct s_wKeyValuePair wKeyValuePair;
|
||||
|
||||
struct s_wKeyValuePair
|
||||
{
|
||||
void* key;
|
||||
void* value;
|
||||
|
||||
wKeyValuePair* next;
|
||||
BOOL markedForRemove;
|
||||
};
|
||||
|
||||
struct s_wHashTable
|
||||
{
|
||||
BOOL synchronized;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
size_t numOfBuckets;
|
||||
size_t numOfElements;
|
||||
float idealRatio;
|
||||
float lowerRehashThreshold;
|
||||
float upperRehashThreshold;
|
||||
wKeyValuePair** bucketArray;
|
||||
|
||||
HASH_TABLE_HASH_FN hash;
|
||||
wObject key;
|
||||
wObject value;
|
||||
|
||||
DWORD foreachRecursionLevel;
|
||||
DWORD pendingRemoves;
|
||||
};
|
||||
|
||||
BOOL HashTable_PointerCompare(const void* pointer1, const void* pointer2)
|
||||
{
|
||||
return (pointer1 == pointer2);
|
||||
}
|
||||
|
||||
UINT32 HashTable_PointerHash(const void* pointer)
|
||||
{
|
||||
return ((UINT32)(UINT_PTR)pointer) >> 4;
|
||||
}
|
||||
|
||||
BOOL HashTable_StringCompare(const void* string1, const void* string2)
|
||||
{
|
||||
if (!string1 || !string2)
|
||||
return (string1 == string2);
|
||||
|
||||
return (strcmp((const char*)string1, (const char*)string2) == 0);
|
||||
}
|
||||
|
||||
UINT32 HashTable_StringHash(const void* key)
|
||||
{
|
||||
UINT32 c = 0;
|
||||
UINT32 hash = 5381;
|
||||
const BYTE* str = (const BYTE*)key;
|
||||
|
||||
/* djb2 algorithm */
|
||||
while ((c = *str++) != '\0')
|
||||
hash = (hash * 33) + c;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void* HashTable_StringClone(const void* str)
|
||||
{
|
||||
return winpr_ObjectStringClone(str);
|
||||
}
|
||||
|
||||
void HashTable_StringFree(void* str)
|
||||
{
|
||||
winpr_ObjectStringFree(str);
|
||||
}
|
||||
|
||||
static inline BOOL HashTable_IsProbablePrime(size_t oddNumber)
|
||||
{
|
||||
for (size_t i = 3; i < 51; i += 2)
|
||||
{
|
||||
if (oddNumber == i)
|
||||
return TRUE;
|
||||
else if (oddNumber % i == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE; /* maybe */
|
||||
}
|
||||
|
||||
static inline size_t HashTable_CalculateIdealNumOfBuckets(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
|
||||
const float numOfElements = (float)table->numOfElements;
|
||||
const float tmp = (numOfElements / table->idealRatio);
|
||||
size_t idealNumOfBuckets = (size_t)tmp;
|
||||
|
||||
if (idealNumOfBuckets < 5)
|
||||
idealNumOfBuckets = 5;
|
||||
else
|
||||
idealNumOfBuckets |= 0x01;
|
||||
|
||||
while (!HashTable_IsProbablePrime(idealNumOfBuckets))
|
||||
idealNumOfBuckets += 2;
|
||||
|
||||
return idealNumOfBuckets;
|
||||
}
|
||||
|
||||
static inline void HashTable_Rehash(wHashTable* table, size_t numOfBuckets)
|
||||
{
|
||||
UINT32 hashValue = 0;
|
||||
wKeyValuePair* nextPair = nullptr;
|
||||
wKeyValuePair** newBucketArray = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (numOfBuckets == 0)
|
||||
numOfBuckets = HashTable_CalculateIdealNumOfBuckets(table);
|
||||
|
||||
if (numOfBuckets == table->numOfBuckets)
|
||||
return; /* already the right size! */
|
||||
|
||||
newBucketArray = (wKeyValuePair**)calloc(numOfBuckets, sizeof(wKeyValuePair*));
|
||||
|
||||
if (!newBucketArray)
|
||||
{
|
||||
/*
|
||||
* Couldn't allocate memory for the new array.
|
||||
* This isn't a fatal error; we just can't perform the rehash.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
wKeyValuePair* pair = table->bucketArray[index];
|
||||
|
||||
while (pair)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
hashValue = table->hash(pair->key) % numOfBuckets;
|
||||
pair->next = newBucketArray[hashValue];
|
||||
newBucketArray[hashValue] = pair;
|
||||
pair = nextPair;
|
||||
}
|
||||
}
|
||||
|
||||
free((void*)table->bucketArray);
|
||||
table->bucketArray = newBucketArray;
|
||||
table->numOfBuckets = numOfBuckets;
|
||||
}
|
||||
|
||||
static inline BOOL HashTable_Equals(wHashTable* table, const wKeyValuePair* pair, const void* key)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
WINPR_ASSERT(pair);
|
||||
WINPR_ASSERT(key);
|
||||
return table->key.fnObjectEquals(key, pair->key);
|
||||
}
|
||||
|
||||
static inline wKeyValuePair* HashTable_Get(wHashTable* table, const void* key)
|
||||
{
|
||||
UINT32 hashValue = 0;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair && !HashTable_Equals(table, pair, key))
|
||||
pair = pair->next;
|
||||
|
||||
return pair;
|
||||
}
|
||||
|
||||
static inline void disposeKey(wHashTable* table, void* key)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
if (table->key.fnObjectFree)
|
||||
table->key.fnObjectFree(key);
|
||||
}
|
||||
|
||||
static inline void disposeValue(wHashTable* table, void* value)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
if (table->value.fnObjectFree)
|
||||
table->value.fnObjectFree(value);
|
||||
}
|
||||
|
||||
static inline void disposePair(wHashTable* table, wKeyValuePair* pair)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
if (!pair)
|
||||
return;
|
||||
disposeKey(table, pair->key);
|
||||
disposeValue(table, pair->value);
|
||||
free(pair);
|
||||
}
|
||||
|
||||
static inline void setKey(wHashTable* table, wKeyValuePair* pair, const void* key)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
if (!pair)
|
||||
return;
|
||||
disposeKey(table, pair->key);
|
||||
if (table->key.fnObjectNew)
|
||||
pair->key = table->key.fnObjectNew(key);
|
||||
else
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.cpv = key;
|
||||
pair->key = cnv.pv;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setValue(wHashTable* table, wKeyValuePair* pair, const void* value)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
if (!pair)
|
||||
return;
|
||||
disposeValue(table, pair->value);
|
||||
if (table->value.fnObjectNew)
|
||||
pair->value = table->value.fnObjectNew(value);
|
||||
else
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.cpv = value;
|
||||
pair->value = cnv.pv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* C equivalent of the C# Hashtable Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of key/value pairs contained in the HashTable.
|
||||
*/
|
||||
|
||||
size_t HashTable_Count(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
return table->numOfElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds an element with the specified key and value into the HashTable.
|
||||
*/
|
||||
#if defined(WITH_WINPR_DEPRECATED)
|
||||
int HashTable_Add(wHashTable* table, const void* key, const void* value)
|
||||
{
|
||||
if (!HashTable_Insert(table, key, value))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL HashTable_Insert(wHashTable* table, const void* key, const void* value)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
UINT32 hashValue = 0;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
wKeyValuePair* newPair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key || !value)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair && !HashTable_Equals(table, pair, key))
|
||||
pair = pair->next;
|
||||
|
||||
if (pair)
|
||||
{
|
||||
if (pair->markedForRemove)
|
||||
{
|
||||
/* this entry was set to be removed but will be recycled instead */
|
||||
table->pendingRemoves--;
|
||||
pair->markedForRemove = FALSE;
|
||||
table->numOfElements++;
|
||||
}
|
||||
|
||||
if (pair->key != key)
|
||||
{
|
||||
setKey(table, pair, key);
|
||||
}
|
||||
|
||||
if (pair->value != value)
|
||||
{
|
||||
setValue(table, pair, value);
|
||||
}
|
||||
rc = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPair = (wKeyValuePair*)calloc(1, sizeof(wKeyValuePair));
|
||||
|
||||
if (newPair)
|
||||
{
|
||||
setKey(table, newPair, key);
|
||||
setValue(table, newPair, value);
|
||||
newPair->next = table->bucketArray[hashValue];
|
||||
newPair->markedForRemove = FALSE;
|
||||
table->bucketArray[hashValue] = newPair;
|
||||
table->numOfElements++;
|
||||
|
||||
if (!table->foreachRecursionLevel && table->upperRehashThreshold > table->idealRatio)
|
||||
{
|
||||
float elementToBucketRatio =
|
||||
(float)table->numOfElements / (float)table->numOfBuckets;
|
||||
|
||||
if (elementToBucketRatio > table->upperRehashThreshold)
|
||||
HashTable_Rehash(table, 0);
|
||||
}
|
||||
rc = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element with the specified key from the HashTable.
|
||||
*/
|
||||
|
||||
BOOL HashTable_Remove(wHashTable* table, const void* key)
|
||||
{
|
||||
UINT32 hashValue = 0;
|
||||
BOOL status = TRUE;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
wKeyValuePair* previousPair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair && !HashTable_Equals(table, pair, key))
|
||||
{
|
||||
previousPair = pair;
|
||||
pair = pair->next;
|
||||
}
|
||||
|
||||
if (!pair)
|
||||
{
|
||||
status = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (table->foreachRecursionLevel)
|
||||
{
|
||||
/* if we are running a HashTable_Foreach, just mark the entry for removal */
|
||||
pair->markedForRemove = TRUE;
|
||||
table->pendingRemoves++;
|
||||
table->numOfElements--;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (previousPair)
|
||||
previousPair->next = pair->next;
|
||||
else
|
||||
table->bucketArray[hashValue] = pair->next;
|
||||
|
||||
disposePair(table, pair);
|
||||
table->numOfElements--;
|
||||
|
||||
if (!table->foreachRecursionLevel && table->lowerRehashThreshold > 0.0f)
|
||||
{
|
||||
float elementToBucketRatio = (float)table->numOfElements / (float)table->numOfBuckets;
|
||||
|
||||
if (elementToBucketRatio < table->lowerRehashThreshold)
|
||||
HashTable_Rehash(table, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item value using key
|
||||
*/
|
||||
|
||||
void* HashTable_GetItemValue(wHashTable* table, const void* key)
|
||||
{
|
||||
void* value = nullptr;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
pair = HashTable_Get(table, key);
|
||||
|
||||
if (pair && !pair->markedForRemove)
|
||||
value = pair->value;
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an item value using key
|
||||
*/
|
||||
|
||||
BOOL HashTable_SetItemValue(wHashTable* table, const void* key, const void* value)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
pair = HashTable_Get(table, key);
|
||||
|
||||
if (!pair || pair->markedForRemove)
|
||||
status = FALSE;
|
||||
else
|
||||
{
|
||||
setValue(table, pair, value);
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from the HashTable.
|
||||
*/
|
||||
|
||||
void HashTable_Clear(wHashTable* table)
|
||||
{
|
||||
wKeyValuePair* nextPair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
wKeyValuePair* pair = table->bucketArray[index];
|
||||
|
||||
while (pair)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
|
||||
if (table->foreachRecursionLevel)
|
||||
{
|
||||
/* if we're in a foreach we just mark the entry for removal */
|
||||
pair->markedForRemove = TRUE;
|
||||
table->pendingRemoves++;
|
||||
}
|
||||
else
|
||||
{
|
||||
disposePair(table, pair);
|
||||
pair = nextPair;
|
||||
}
|
||||
}
|
||||
|
||||
table->bucketArray[index] = nullptr;
|
||||
}
|
||||
|
||||
table->numOfElements = 0;
|
||||
if (table->foreachRecursionLevel == 0)
|
||||
HashTable_Rehash(table, 5);
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of keys as an array
|
||||
*/
|
||||
|
||||
size_t HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys)
|
||||
{
|
||||
size_t iKey = 0;
|
||||
size_t count = 0;
|
||||
ULONG_PTR* pKeys = nullptr;
|
||||
wKeyValuePair* nextPair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
iKey = 0;
|
||||
count = table->numOfElements;
|
||||
if (ppKeys)
|
||||
*ppKeys = nullptr;
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pKeys = (ULONG_PTR*)calloc(count, sizeof(ULONG_PTR));
|
||||
|
||||
if (!pKeys)
|
||||
{
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
wKeyValuePair* pair = table->bucketArray[index];
|
||||
|
||||
while (pair)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
if (!pair->markedForRemove)
|
||||
pKeys[iKey++] = (ULONG_PTR)pair->key;
|
||||
pair = nextPair;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
if (ppKeys)
|
||||
*ppKeys = pKeys;
|
||||
else
|
||||
free(pKeys);
|
||||
return count;
|
||||
}
|
||||
|
||||
BOOL HashTable_Foreach(wHashTable* table, HASH_TABLE_FOREACH_FN fn, VOID* arg)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
WINPR_ASSERT(fn);
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
table->foreachRecursionLevel++;
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
for (wKeyValuePair* pair = table->bucketArray[index]; pair; pair = pair->next)
|
||||
{
|
||||
if (!pair->markedForRemove && !fn(pair->key, pair->value, arg))
|
||||
{
|
||||
ret = FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
table->foreachRecursionLevel--;
|
||||
|
||||
if (!table->foreachRecursionLevel && table->pendingRemoves)
|
||||
{
|
||||
/* if we're the last recursive foreach call, let's do the cleanup if needed */
|
||||
wKeyValuePair** prevPtr = nullptr;
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
wKeyValuePair* nextPair = nullptr;
|
||||
prevPtr = &table->bucketArray[index];
|
||||
for (wKeyValuePair* pair = table->bucketArray[index]; pair;)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
|
||||
if (pair->markedForRemove)
|
||||
{
|
||||
disposePair(table, pair);
|
||||
*prevPtr = nextPair;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevPtr = &pair->next;
|
||||
}
|
||||
pair = nextPair;
|
||||
}
|
||||
}
|
||||
table->pendingRemoves = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the HashTable contains a specific key.
|
||||
*/
|
||||
|
||||
BOOL HashTable_Contains(wHashTable* table, const void* key)
|
||||
{
|
||||
BOOL status = 0;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
pair = HashTable_Get(table, key);
|
||||
status = (pair && !pair->markedForRemove);
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the HashTable contains a specific key.
|
||||
*/
|
||||
|
||||
BOOL HashTable_ContainsKey(wHashTable* table, const void* key)
|
||||
{
|
||||
BOOL status = 0;
|
||||
wKeyValuePair* pair = nullptr;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
pair = HashTable_Get(table, key);
|
||||
status = (pair && !pair->markedForRemove);
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the HashTable contains a specific value.
|
||||
*/
|
||||
|
||||
BOOL HashTable_ContainsValue(wHashTable* table, const void* value)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
|
||||
WINPR_ASSERT(table);
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
wKeyValuePair* pair = table->bucketArray[index];
|
||||
|
||||
while (pair)
|
||||
{
|
||||
if (!pair->markedForRemove && HashTable_Equals(table, pair, value))
|
||||
{
|
||||
status = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
pair = pair->next;
|
||||
}
|
||||
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wHashTable* HashTable_New(BOOL synchronized)
|
||||
{
|
||||
wHashTable* table = (wHashTable*)calloc(1, sizeof(wHashTable));
|
||||
|
||||
if (!table)
|
||||
goto fail;
|
||||
|
||||
table->synchronized = synchronized;
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(table->lock), 4000))
|
||||
goto fail;
|
||||
table->numOfBuckets = 64;
|
||||
table->numOfElements = 0;
|
||||
table->bucketArray = (wKeyValuePair**)calloc(table->numOfBuckets, sizeof(wKeyValuePair*));
|
||||
|
||||
if (!table->bucketArray)
|
||||
goto fail;
|
||||
|
||||
table->idealRatio = 3.0f;
|
||||
table->lowerRehashThreshold = 0.0f;
|
||||
table->upperRehashThreshold = 15.0f;
|
||||
table->hash = HashTable_PointerHash;
|
||||
table->key.fnObjectEquals = HashTable_PointerCompare;
|
||||
table->value.fnObjectEquals = HashTable_PointerCompare;
|
||||
|
||||
return table;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
HashTable_Free(table);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HashTable_Free(wHashTable* table)
|
||||
{
|
||||
wKeyValuePair* pair = nullptr;
|
||||
wKeyValuePair* nextPair = nullptr;
|
||||
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (table->bucketArray)
|
||||
{
|
||||
for (size_t index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
pair = table->bucketArray[index];
|
||||
|
||||
while (pair)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
|
||||
disposePair(table, pair);
|
||||
pair = nextPair;
|
||||
}
|
||||
}
|
||||
free((void*)table->bucketArray);
|
||||
}
|
||||
DeleteCriticalSection(&(table->lock));
|
||||
|
||||
free(table);
|
||||
}
|
||||
|
||||
void HashTable_Lock(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
EnterCriticalSection(&table->lock);
|
||||
}
|
||||
|
||||
void HashTable_Unlock(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
LeaveCriticalSection(&table->lock);
|
||||
}
|
||||
|
||||
wObject* HashTable_KeyObject(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
return &table->key;
|
||||
}
|
||||
|
||||
wObject* HashTable_ValueObject(wHashTable* table)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
return &table->value;
|
||||
}
|
||||
|
||||
BOOL HashTable_SetHashFunction(wHashTable* table, HASH_TABLE_HASH_FN fn)
|
||||
{
|
||||
WINPR_ASSERT(table);
|
||||
table->hash = fn;
|
||||
return fn != nullptr;
|
||||
}
|
||||
|
||||
BOOL HashTable_SetupForStringData(wHashTable* table, BOOL stringValues)
|
||||
{
|
||||
wObject* obj = nullptr;
|
||||
|
||||
if (!HashTable_SetHashFunction(table, HashTable_StringHash))
|
||||
return FALSE;
|
||||
|
||||
obj = HashTable_KeyObject(table);
|
||||
obj->fnObjectEquals = HashTable_StringCompare;
|
||||
obj->fnObjectNew = HashTable_StringClone;
|
||||
obj->fnObjectFree = HashTable_StringFree;
|
||||
|
||||
if (stringValues)
|
||||
{
|
||||
obj = HashTable_ValueObject(table);
|
||||
obj->fnObjectEquals = HashTable_StringCompare;
|
||||
obj->fnObjectNew = HashTable_StringClone;
|
||||
obj->fnObjectFree = HashTable_StringFree;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
385
third_party/FreeRDP/winpr/libwinpr/utils/collections/LinkedList.c
vendored
Normal file
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.Generic.LinkedList<T>
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
typedef struct s_wLinkedListItem wLinkedListNode;
|
||||
|
||||
struct s_wLinkedListItem
|
||||
{
|
||||
void* value;
|
||||
wLinkedListNode* prev;
|
||||
wLinkedListNode* next;
|
||||
};
|
||||
|
||||
struct s_wLinkedList
|
||||
{
|
||||
size_t count;
|
||||
int initial;
|
||||
wLinkedListNode* head;
|
||||
wLinkedListNode* tail;
|
||||
wLinkedListNode* current;
|
||||
wObject object;
|
||||
};
|
||||
|
||||
/**
|
||||
* C equivalent of the C# LinkedList<T> Class:
|
||||
* http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx
|
||||
*
|
||||
* Internal implementation uses a doubly-linked list
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of nodes actually contained in the LinkedList.
|
||||
*/
|
||||
|
||||
size_t LinkedList_Count(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
return list->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first node of the LinkedList.
|
||||
*/
|
||||
|
||||
void* LinkedList_First(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->head)
|
||||
return list->head->value;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last node of the LinkedList.
|
||||
*/
|
||||
|
||||
void* LinkedList_Last(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->tail)
|
||||
return list->tail->value;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines whether the LinkedList contains a specific value.
|
||||
*/
|
||||
|
||||
BOOL LinkedList_Contains(wLinkedList* list, const void* value)
|
||||
{
|
||||
wLinkedListNode* item = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
|
||||
WINPR_ASSERT(list);
|
||||
if (!list->head)
|
||||
return FALSE;
|
||||
|
||||
item = list->head;
|
||||
keyEquals = list->object.fnObjectEquals;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (keyEquals(item->value, value))
|
||||
break;
|
||||
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return (item != nullptr);
|
||||
}
|
||||
|
||||
static wLinkedListNode* LinkedList_FreeNode(wLinkedList* list, wLinkedListNode* node)
|
||||
{
|
||||
wLinkedListNode* next = nullptr;
|
||||
wLinkedListNode* prev = nullptr;
|
||||
|
||||
WINPR_ASSERT(list);
|
||||
WINPR_ASSERT(node);
|
||||
|
||||
next = node->next;
|
||||
prev = node->prev;
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
|
||||
if (node == list->head)
|
||||
list->head = node->next;
|
||||
|
||||
if (node == list->tail)
|
||||
list->tail = node->prev;
|
||||
|
||||
if (list->object.fnObjectUninit)
|
||||
list->object.fnObjectUninit(node);
|
||||
|
||||
if (list->object.fnObjectFree)
|
||||
list->object.fnObjectFree(node);
|
||||
|
||||
free(node);
|
||||
list->count--;
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries from the LinkedList.
|
||||
*/
|
||||
|
||||
void LinkedList_Clear(wLinkedList* list)
|
||||
{
|
||||
wLinkedListNode* node = nullptr;
|
||||
WINPR_ASSERT(list);
|
||||
if (!list->head)
|
||||
return;
|
||||
|
||||
node = list->head;
|
||||
|
||||
while (node)
|
||||
node = LinkedList_FreeNode(list, node);
|
||||
|
||||
list->head = list->tail = nullptr;
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
static wLinkedListNode* LinkedList_Create(wLinkedList* list, const void* value)
|
||||
{
|
||||
wLinkedListNode* node = nullptr;
|
||||
|
||||
WINPR_ASSERT(list);
|
||||
node = (wLinkedListNode*)calloc(1, sizeof(wLinkedListNode));
|
||||
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
if (list->object.fnObjectNew)
|
||||
node->value = list->object.fnObjectNew(value);
|
||||
else
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.cpv = value;
|
||||
node->value = cnv.pv;
|
||||
}
|
||||
|
||||
if (list->object.fnObjectInit)
|
||||
list->object.fnObjectInit(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
/**
|
||||
* Adds a new node containing the specified value at the start of the LinkedList.
|
||||
*/
|
||||
|
||||
BOOL LinkedList_AddFirst(wLinkedList* list, const void* value)
|
||||
{
|
||||
wLinkedListNode* node = LinkedList_Create(list, value);
|
||||
|
||||
if (!node)
|
||||
return FALSE;
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->tail = list->head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->head->prev = node;
|
||||
node->next = list->head;
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new node containing the specified value at the end of the LinkedList.
|
||||
*/
|
||||
|
||||
BOOL LinkedList_AddLast(wLinkedList* list, const void* value)
|
||||
{
|
||||
wLinkedListNode* node = LinkedList_Create(list, value);
|
||||
|
||||
if (!node)
|
||||
return FALSE;
|
||||
|
||||
if (!list->tail)
|
||||
{
|
||||
list->head = list->tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->tail->next = node;
|
||||
node->prev = list->tail;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first occurrence of the specified value from the LinkedList.
|
||||
*/
|
||||
|
||||
BOOL LinkedList_Remove(wLinkedList* list, const void* value)
|
||||
{
|
||||
wLinkedListNode* node = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
WINPR_ASSERT(list);
|
||||
|
||||
keyEquals = list->object.fnObjectEquals;
|
||||
node = list->head;
|
||||
|
||||
while (node)
|
||||
{
|
||||
if (keyEquals(node->value, value))
|
||||
{
|
||||
LinkedList_FreeNode(list, node);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the node at the start of the LinkedList.
|
||||
*/
|
||||
|
||||
void LinkedList_RemoveFirst(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->head)
|
||||
LinkedList_FreeNode(list, list->head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the node at the end of the LinkedList.
|
||||
*/
|
||||
|
||||
void LinkedList_RemoveLast(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->tail)
|
||||
LinkedList_FreeNode(list, list->tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enumerator to its initial position, which is before the first element in the collection.
|
||||
*/
|
||||
|
||||
void LinkedList_Enumerator_Reset(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
list->initial = 1;
|
||||
list->current = list->head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the element at the current position of the enumerator.
|
||||
*/
|
||||
|
||||
void* LinkedList_Enumerator_Current(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->initial)
|
||||
return nullptr;
|
||||
|
||||
if (list->current)
|
||||
return list->current->value;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advances the enumerator to the next element of the LinkedList.
|
||||
*/
|
||||
|
||||
BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
if (list->initial)
|
||||
list->initial = 0;
|
||||
else if (list->current)
|
||||
list->current = list->current->next;
|
||||
|
||||
if (!list->current)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL default_equal_function(const void* objA, const void* objB)
|
||||
{
|
||||
return objA == objB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wLinkedList* LinkedList_New(void)
|
||||
{
|
||||
wLinkedList* list = nullptr;
|
||||
list = (wLinkedList*)calloc(1, sizeof(wLinkedList));
|
||||
|
||||
if (list)
|
||||
{
|
||||
list->object.fnObjectEquals = default_equal_function;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void LinkedList_Free(wLinkedList* list)
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
LinkedList_Clear(list);
|
||||
free(list);
|
||||
}
|
||||
}
|
||||
|
||||
wObject* LinkedList_Object(wLinkedList* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
|
||||
return &list->object;
|
||||
}
|
||||
562
third_party/FreeRDP/winpr/libwinpr/utils/collections/ListDictionary.c
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.Specialized.ListDictionary
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
typedef struct s_wListDictionaryItem wListDictionaryItem;
|
||||
|
||||
struct s_wListDictionaryItem
|
||||
{
|
||||
void* key;
|
||||
void* value;
|
||||
|
||||
wListDictionaryItem* next;
|
||||
};
|
||||
|
||||
struct s_wListDictionary
|
||||
{
|
||||
BOOL synchronized;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
wListDictionaryItem* head;
|
||||
wObject objectKey;
|
||||
wObject objectValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* C equivalent of the C# ListDictionary Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.specialized.listdictionary.aspx
|
||||
*
|
||||
* Internal implementation uses a singly-linked list
|
||||
*/
|
||||
|
||||
WINPR_API wObject* ListDictionary_KeyObject(wListDictionary* listDictionary)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
return &listDictionary->objectKey;
|
||||
}
|
||||
|
||||
WINPR_API wObject* ListDictionary_ValueObject(wListDictionary* listDictionary)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
return &listDictionary->objectValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of key/value pairs contained in the ListDictionary.
|
||||
*/
|
||||
|
||||
size_t ListDictionary_Count(wListDictionary* listDictionary)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
wListDictionaryItem* item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
count++;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock access to the ListDictionary
|
||||
*/
|
||||
|
||||
void ListDictionary_Lock(wListDictionary* listDictionary)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
EnterCriticalSection(&listDictionary->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock access to the ListDictionary
|
||||
*/
|
||||
|
||||
void ListDictionary_Unlock(wListDictionary* listDictionary)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
LeaveCriticalSection(&listDictionary->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the list of keys as an array
|
||||
*/
|
||||
|
||||
size_t ListDictionary_GetKeys(wListDictionary* listDictionary, ULONG_PTR** ppKeys)
|
||||
{
|
||||
ULONG_PTR* pKeys = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
if (!ppKeys)
|
||||
return 0;
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
wListDictionaryItem* item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
count++;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
pKeys = (ULONG_PTR*)calloc(count, sizeof(ULONG_PTR));
|
||||
|
||||
if (!pKeys)
|
||||
{
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
wListDictionaryItem* item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
pKeys[index++] = (ULONG_PTR)item->key;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
*ppKeys = pKeys;
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void item_free(wListDictionary* listDictionary, wListDictionaryItem* item)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (item)
|
||||
{
|
||||
if (listDictionary->objectKey.fnObjectFree)
|
||||
listDictionary->objectKey.fnObjectFree(item->key);
|
||||
if (listDictionary->objectValue.fnObjectFree)
|
||||
listDictionary->objectValue.fnObjectFree(item->value);
|
||||
}
|
||||
free(item);
|
||||
}
|
||||
|
||||
static void item_set(wListDictionary* listDictionary, wListDictionaryItem* item, const void* value)
|
||||
{
|
||||
WINPR_ASSERT(listDictionary);
|
||||
WINPR_ASSERT(item);
|
||||
|
||||
if (listDictionary->objectValue.fnObjectFree)
|
||||
listDictionary->objectValue.fnObjectFree(item->value);
|
||||
|
||||
if (listDictionary->objectValue.fnObjectNew)
|
||||
item->value = listDictionary->objectValue.fnObjectNew(value);
|
||||
else
|
||||
item->value = (void*)(uintptr_t)value;
|
||||
}
|
||||
|
||||
static wListDictionaryItem* new_item(wListDictionary* listDictionary, const void* key,
|
||||
const void* value)
|
||||
{
|
||||
wListDictionaryItem* item = (wListDictionaryItem*)calloc(1, sizeof(wListDictionaryItem));
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
if (listDictionary->objectKey.fnObjectNew)
|
||||
item->key = listDictionary->objectKey.fnObjectNew(key);
|
||||
else
|
||||
item->key = (void*)(uintptr_t)key;
|
||||
if (!item->key)
|
||||
goto fail;
|
||||
|
||||
item_set(listDictionary, item, value);
|
||||
if (value && !item->value)
|
||||
goto fail;
|
||||
|
||||
return item;
|
||||
|
||||
fail:
|
||||
item_free(listDictionary, item);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry with the specified key and value into the ListDictionary.
|
||||
*/
|
||||
|
||||
BOOL ListDictionary_Add(wListDictionary* listDictionary, const void* key, const void* value)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
wListDictionaryItem* item = new_item(listDictionary, key, value);
|
||||
|
||||
if (!item)
|
||||
goto out_error;
|
||||
|
||||
if (!listDictionary->head)
|
||||
{
|
||||
listDictionary->head = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
wListDictionaryItem* lastItem = listDictionary->head;
|
||||
|
||||
while (lastItem->next)
|
||||
lastItem = lastItem->next;
|
||||
|
||||
lastItem->next = item;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out_error:
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries from the ListDictionary.
|
||||
*/
|
||||
|
||||
void ListDictionary_Clear(wListDictionary* listDictionary)
|
||||
{
|
||||
wListDictionaryItem* item = nullptr;
|
||||
wListDictionaryItem* nextItem = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
nextItem = item->next;
|
||||
|
||||
item_free(listDictionary, item);
|
||||
item = nextItem;
|
||||
}
|
||||
|
||||
listDictionary->head = nullptr;
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the ListDictionary contains a specific key.
|
||||
*/
|
||||
|
||||
BOOL ListDictionary_Contains(wListDictionary* listDictionary, const void* key)
|
||||
{
|
||||
wListDictionaryItem* item = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
keyEquals = listDictionary->objectKey.fnObjectEquals;
|
||||
item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (keyEquals(item->key, key))
|
||||
break;
|
||||
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return (item != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the entry with the specified key from the ListDictionary.
|
||||
*/
|
||||
|
||||
static void* ListDictionary_RemoveOrTake(wListDictionary* listDictionary, const void* key,
|
||||
BOOL take)
|
||||
{
|
||||
void* value = nullptr;
|
||||
wListDictionaryItem* item = nullptr;
|
||||
wListDictionaryItem* prevItem = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
keyEquals = listDictionary->objectKey.fnObjectEquals;
|
||||
item = listDictionary->head;
|
||||
prevItem = nullptr;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (keyEquals(item->key, key))
|
||||
{
|
||||
if (!prevItem)
|
||||
listDictionary->head = item->next;
|
||||
else
|
||||
prevItem->next = item->next;
|
||||
|
||||
if (take)
|
||||
{
|
||||
value = item->value;
|
||||
item->value = nullptr;
|
||||
}
|
||||
item_free(listDictionary, item);
|
||||
break;
|
||||
}
|
||||
|
||||
prevItem = item;
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ListDictionary_Remove(wListDictionary* listDictionary, const void* key)
|
||||
{
|
||||
ListDictionary_RemoveOrTake(listDictionary, key, FALSE);
|
||||
}
|
||||
|
||||
void* ListDictionary_Take(wListDictionary* listDictionary, const void* key)
|
||||
{
|
||||
return ListDictionary_RemoveOrTake(listDictionary, key, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first (head) entry from the list
|
||||
*/
|
||||
|
||||
static void* ListDictionary_Remove_Or_Take_Head(wListDictionary* listDictionary, BOOL take)
|
||||
{
|
||||
wListDictionaryItem* item = nullptr;
|
||||
void* value = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
item = listDictionary->head;
|
||||
listDictionary->head = listDictionary->head->next;
|
||||
if (take)
|
||||
{
|
||||
value = item->value;
|
||||
item->value = nullptr;
|
||||
}
|
||||
item_free(listDictionary, item);
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ListDictionary_Remove_Head(wListDictionary* listDictionary)
|
||||
{
|
||||
ListDictionary_Remove_Or_Take_Head(listDictionary, FALSE);
|
||||
}
|
||||
|
||||
void* ListDictionary_Take_Head(wListDictionary* listDictionary)
|
||||
{
|
||||
return ListDictionary_Remove_Or_Take_Head(listDictionary, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item value using key
|
||||
*/
|
||||
|
||||
void* ListDictionary_GetItemValue(wListDictionary* listDictionary, const void* key)
|
||||
{
|
||||
void* value = nullptr;
|
||||
wListDictionaryItem* item = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
keyEquals = listDictionary->objectKey.fnObjectEquals;
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (keyEquals(item->key, key))
|
||||
break;
|
||||
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
value = (item) ? item->value : nullptr;
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an item value using key
|
||||
*/
|
||||
|
||||
BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, const void* key,
|
||||
const void* value)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
wListDictionaryItem* item = nullptr;
|
||||
OBJECT_EQUALS_FN keyEquals = nullptr;
|
||||
|
||||
WINPR_ASSERT(listDictionary);
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Lock(listDictionary);
|
||||
|
||||
keyEquals = listDictionary->objectKey.fnObjectEquals;
|
||||
|
||||
if (listDictionary->head)
|
||||
{
|
||||
item = listDictionary->head;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (keyEquals(item->key, key))
|
||||
break;
|
||||
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
if (item)
|
||||
item_set(listDictionary, item, value);
|
||||
|
||||
status = (item != nullptr);
|
||||
}
|
||||
|
||||
if (listDictionary->synchronized)
|
||||
ListDictionary_Unlock(listDictionary);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL default_equal_function(const void* obj1, const void* obj2)
|
||||
{
|
||||
return (obj1 == obj2);
|
||||
}
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wListDictionary* ListDictionary_New(BOOL synchronized)
|
||||
{
|
||||
wListDictionary* listDictionary = (wListDictionary*)calloc(1, sizeof(wListDictionary));
|
||||
|
||||
if (!listDictionary)
|
||||
return nullptr;
|
||||
|
||||
listDictionary->synchronized = synchronized;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(listDictionary->lock), 4000))
|
||||
{
|
||||
free(listDictionary);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
listDictionary->objectKey.fnObjectEquals = default_equal_function;
|
||||
listDictionary->objectValue.fnObjectEquals = default_equal_function;
|
||||
return listDictionary;
|
||||
}
|
||||
|
||||
void ListDictionary_Free(wListDictionary* listDictionary)
|
||||
{
|
||||
if (listDictionary)
|
||||
{
|
||||
ListDictionary_Clear(listDictionary);
|
||||
DeleteCriticalSection(&listDictionary->lock);
|
||||
free(listDictionary);
|
||||
}
|
||||
}
|
||||
80
third_party/FreeRDP/winpr/libwinpr/utils/collections/MessagePipe.c
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Message Pipe
|
||||
*
|
||||
* 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/sysinfo.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
void MessagePipe_PostQuit(wMessagePipe* pipe, int nExitCode)
|
||||
{
|
||||
MessageQueue_PostQuit(pipe->In, nExitCode);
|
||||
MessageQueue_PostQuit(pipe->Out, nExitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wMessagePipe* MessagePipe_New(void)
|
||||
{
|
||||
wMessagePipe* pipe = nullptr;
|
||||
|
||||
pipe = (wMessagePipe*)malloc(sizeof(wMessagePipe));
|
||||
|
||||
if (!pipe)
|
||||
return nullptr;
|
||||
|
||||
pipe->In = MessageQueue_New(nullptr);
|
||||
if (!pipe->In)
|
||||
goto error_in;
|
||||
|
||||
pipe->Out = MessageQueue_New(nullptr);
|
||||
if (!pipe->Out)
|
||||
goto error_out;
|
||||
|
||||
return pipe;
|
||||
|
||||
error_out:
|
||||
MessageQueue_Free(pipe->In);
|
||||
error_in:
|
||||
free(pipe);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MessagePipe_Free(wMessagePipe* pipe)
|
||||
{
|
||||
if (pipe)
|
||||
{
|
||||
MessageQueue_Free(pipe->In);
|
||||
MessageQueue_Free(pipe->Out);
|
||||
|
||||
free(pipe);
|
||||
}
|
||||
}
|
||||
354
third_party/FreeRDP/winpr/libwinpr/utils/collections/MessageQueue.c
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Message Queue
|
||||
*
|
||||
* 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/sysinfo.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
struct s_wMessageQueue
|
||||
{
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
BOOL closed;
|
||||
wMessage* array;
|
||||
CRITICAL_SECTION lock;
|
||||
HANDLE event;
|
||||
|
||||
wObject object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Message Queue inspired from Windows:
|
||||
* http://msdn.microsoft.com/en-us/library/ms632590/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
wObject* MessageQueue_Object(wMessageQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
return &queue->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an event which is set when the queue is non-empty
|
||||
*/
|
||||
|
||||
HANDLE MessageQueue_Event(wMessageQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
return queue->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queue size
|
||||
*/
|
||||
|
||||
size_t MessageQueue_Size(wMessageQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
EnterCriticalSection(&queue->lock);
|
||||
const size_t ret = queue->size;
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t MessageQueue_Capacity(wMessageQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
EnterCriticalSection(&queue->lock);
|
||||
const size_t ret = queue->capacity;
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
BOOL MessageQueue_Wait(wMessageQueue* queue)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
|
||||
WINPR_ASSERT(queue);
|
||||
if (WaitForSingleObject(queue->event, INFINITE) == WAIT_OBJECT_0)
|
||||
status = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL MessageQueue_EnsureCapacity(wMessageQueue* queue, size_t count)
|
||||
{
|
||||
const size_t increment = 128;
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
const size_t required = queue->size + count;
|
||||
// check for overflow
|
||||
if ((required < queue->size) || (required < count) ||
|
||||
(required > (SIZE_MAX - increment) / sizeof(wMessage)))
|
||||
return FALSE;
|
||||
|
||||
if (required > queue->capacity)
|
||||
{
|
||||
const size_t old_capacity = queue->capacity;
|
||||
const size_t new_capacity = required + increment;
|
||||
|
||||
wMessage* new_arr = (wMessage*)realloc(queue->array, sizeof(wMessage) * new_capacity);
|
||||
if (!new_arr)
|
||||
return FALSE;
|
||||
queue->array = new_arr;
|
||||
queue->capacity = new_capacity;
|
||||
ZeroMemory(&(queue->array[old_capacity]), (new_capacity - old_capacity) * sizeof(wMessage));
|
||||
|
||||
/* rearrange wrapped entries:
|
||||
* fill up the newly available space and move tail
|
||||
* back by the amount of elements that have been moved to the newly
|
||||
* allocated space.
|
||||
*/
|
||||
if (queue->tail <= queue->head)
|
||||
{
|
||||
size_t tocopy = queue->tail;
|
||||
size_t slots = new_capacity - old_capacity;
|
||||
const size_t batch = (tocopy < slots) ? tocopy : slots;
|
||||
CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(wMessage));
|
||||
|
||||
/* Tail is decremented. if the whole thing is appended
|
||||
* just move the existing tail by old_capacity */
|
||||
if (tocopy < slots)
|
||||
{
|
||||
ZeroMemory(queue->array, batch * sizeof(wMessage));
|
||||
queue->tail += old_capacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t remain = queue->tail - batch;
|
||||
const size_t movesize = remain * sizeof(wMessage);
|
||||
memmove_s(queue->array, queue->tail * sizeof(wMessage), &queue->array[batch],
|
||||
movesize);
|
||||
|
||||
const size_t zerooffset = remain;
|
||||
const size_t zerosize = (queue->tail - remain) * sizeof(wMessage);
|
||||
ZeroMemory(&queue->array[zerooffset], zerosize);
|
||||
queue->tail -= batch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MessageQueue_Dispatch(wMessageQueue* queue, const wMessage* message)
|
||||
{
|
||||
wMessage* dst = nullptr;
|
||||
BOOL ret = FALSE;
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
if (!message)
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(queue);
|
||||
EnterCriticalSection(&queue->lock);
|
||||
|
||||
if (queue->closed)
|
||||
goto out;
|
||||
|
||||
if (!MessageQueue_EnsureCapacity(queue, 1))
|
||||
goto out;
|
||||
|
||||
dst = &(queue->array[queue->tail]);
|
||||
*dst = *message;
|
||||
dst->time = GetTickCount64();
|
||||
|
||||
queue->tail = (queue->tail + 1) % queue->capacity;
|
||||
queue->size++;
|
||||
|
||||
if (queue->size > 0)
|
||||
(void)SetEvent(queue->event);
|
||||
|
||||
if (message->id == WMQ_QUIT)
|
||||
queue->closed = TRUE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* wParam, void* lParam)
|
||||
{
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
|
||||
message.context = context;
|
||||
message.id = type;
|
||||
message.wParam = wParam;
|
||||
message.lParam = lParam;
|
||||
message.Free = nullptr;
|
||||
|
||||
return MessageQueue_Dispatch(queue, &message);
|
||||
}
|
||||
|
||||
BOOL MessageQueue_PostQuit(wMessageQueue* queue, int nExitCode)
|
||||
{
|
||||
return MessageQueue_Post(queue, nullptr, WMQ_QUIT, (void*)(size_t)nExitCode, nullptr);
|
||||
}
|
||||
|
||||
int MessageQueue_Get(wMessageQueue* queue, wMessage* message)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
if (!MessageQueue_Wait(queue))
|
||||
return status;
|
||||
|
||||
EnterCriticalSection(&queue->lock);
|
||||
|
||||
if (queue->size > 0)
|
||||
{
|
||||
CopyMemory(message, &(queue->array[queue->head]), sizeof(wMessage));
|
||||
ZeroMemory(&(queue->array[queue->head]), sizeof(wMessage));
|
||||
queue->head = (queue->head + 1) % queue->capacity;
|
||||
queue->size--;
|
||||
|
||||
if (queue->size < 1)
|
||||
(void)ResetEvent(queue->event);
|
||||
|
||||
status = (message->id != WMQ_QUIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
WINPR_ASSERT(queue);
|
||||
EnterCriticalSection(&queue->lock);
|
||||
|
||||
if (queue->size > 0)
|
||||
{
|
||||
CopyMemory(message, &(queue->array[queue->head]), sizeof(wMessage));
|
||||
status = 1;
|
||||
|
||||
if (remove)
|
||||
{
|
||||
ZeroMemory(&(queue->array[queue->head]), sizeof(wMessage));
|
||||
queue->head = (queue->head + 1) % queue->capacity;
|
||||
queue->size--;
|
||||
|
||||
if (queue->size < 1)
|
||||
(void)ResetEvent(queue->event);
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wMessageQueue* MessageQueue_New(const wObject* callback)
|
||||
{
|
||||
wMessageQueue* queue = nullptr;
|
||||
|
||||
queue = (wMessageQueue*)calloc(1, sizeof(wMessageQueue));
|
||||
if (!queue)
|
||||
return nullptr;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
|
||||
goto fail;
|
||||
|
||||
if (!MessageQueue_EnsureCapacity(queue, 32))
|
||||
goto fail;
|
||||
|
||||
queue->event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!queue->event)
|
||||
goto fail;
|
||||
|
||||
if (callback)
|
||||
queue->object = *callback;
|
||||
|
||||
return queue;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
MessageQueue_Free(queue);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MessageQueue_Free(wMessageQueue* queue)
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
|
||||
if (queue->event)
|
||||
MessageQueue_Clear(queue);
|
||||
|
||||
(void)CloseHandle(queue->event);
|
||||
DeleteCriticalSection(&queue->lock);
|
||||
|
||||
free(queue->array);
|
||||
free(queue);
|
||||
}
|
||||
|
||||
int MessageQueue_Clear(wMessageQueue* queue)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
WINPR_ASSERT(queue);
|
||||
WINPR_ASSERT(queue->event);
|
||||
|
||||
EnterCriticalSection(&queue->lock);
|
||||
|
||||
while (queue->size > 0)
|
||||
{
|
||||
wMessage* msg = &(queue->array[queue->head]);
|
||||
|
||||
/* Free resources of message. */
|
||||
if (queue->object.fnObjectUninit)
|
||||
queue->object.fnObjectUninit(msg);
|
||||
if (queue->object.fnObjectFree)
|
||||
queue->object.fnObjectFree(msg);
|
||||
|
||||
ZeroMemory(msg, sizeof(wMessage));
|
||||
|
||||
queue->head = (queue->head + 1) % queue->capacity;
|
||||
queue->size--;
|
||||
}
|
||||
(void)ResetEvent(queue->event);
|
||||
queue->closed = FALSE;
|
||||
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
42
third_party/FreeRDP/winpr/libwinpr/utils/collections/Object.c
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Collections
|
||||
*
|
||||
* 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/string.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
void* winpr_ObjectStringClone(const void* pvstr)
|
||||
{
|
||||
const char* str = pvstr;
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return _strdup(str);
|
||||
}
|
||||
|
||||
void* winpr_ObjectWStringClone(const void* pvstr)
|
||||
{
|
||||
const WCHAR* str = pvstr;
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return _wcsdup(str);
|
||||
}
|
||||
|
||||
void winpr_ObjectStringFree(void* pvstr)
|
||||
{
|
||||
free(pvstr);
|
||||
}
|
||||
194
third_party/FreeRDP/winpr/libwinpr/utils/collections/ObjectPool.c
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Object Pool
|
||||
*
|
||||
* 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/assert.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
struct s_wObjectPool
|
||||
{
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
void** array;
|
||||
CRITICAL_SECTION lock;
|
||||
wObject object;
|
||||
BOOL synchronized;
|
||||
};
|
||||
|
||||
/**
|
||||
* C Object Pool similar to C# BufferManager Class:
|
||||
* http://msdn.microsoft.com/en-us/library/ms405814.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
static void ObjectPool_Lock(wObjectPool* pool)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
if (pool->synchronized)
|
||||
EnterCriticalSection(&pool->lock);
|
||||
}
|
||||
|
||||
static void ObjectPool_Unlock(wObjectPool* pool)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
if (pool->synchronized)
|
||||
LeaveCriticalSection(&pool->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an object from the pool.
|
||||
*/
|
||||
|
||||
void* ObjectPool_Take(wObjectPool* pool)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
ObjectPool_Lock(pool);
|
||||
|
||||
if (pool->size > 0)
|
||||
obj = pool->array[--(pool->size)];
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
if (pool->object.fnObjectNew)
|
||||
obj = pool->object.fnObjectNew(nullptr);
|
||||
}
|
||||
|
||||
if (pool->object.fnObjectInit)
|
||||
pool->object.fnObjectInit(obj);
|
||||
|
||||
ObjectPool_Unlock(pool);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static BOOL ObjectPool_EnsureCapacity(wObjectPool* pool, size_t add)
|
||||
{
|
||||
WINPR_ASSERT(pool->size < SIZE_MAX - add);
|
||||
|
||||
const size_t blocksize = 128ull;
|
||||
const size_t required = pool->size + add;
|
||||
if (required >= pool->capacity)
|
||||
{
|
||||
const size_t new_cap = required + blocksize - required % blocksize;
|
||||
|
||||
void** new_arr = (void**)realloc((void*)pool->array, sizeof(void*) * new_cap);
|
||||
if (!new_arr)
|
||||
return FALSE;
|
||||
|
||||
pool->array = new_arr;
|
||||
pool->capacity = new_cap;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object to the pool.
|
||||
*/
|
||||
|
||||
void ObjectPool_Return(wObjectPool* pool, void* obj)
|
||||
{
|
||||
ObjectPool_Lock(pool);
|
||||
|
||||
if (!ObjectPool_EnsureCapacity(pool, 1))
|
||||
goto out;
|
||||
|
||||
pool->array[(pool->size)++] = obj;
|
||||
|
||||
if (pool->object.fnObjectUninit)
|
||||
pool->object.fnObjectUninit(obj);
|
||||
|
||||
out:
|
||||
ObjectPool_Unlock(pool);
|
||||
}
|
||||
|
||||
wObject* ObjectPool_Object(wObjectPool* pool)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
return &pool->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the buffers currently cached in the pool.
|
||||
*/
|
||||
|
||||
void ObjectPool_Clear(wObjectPool* pool)
|
||||
{
|
||||
ObjectPool_Lock(pool);
|
||||
|
||||
while (pool->size > 0)
|
||||
{
|
||||
(pool->size)--;
|
||||
|
||||
if (pool->object.fnObjectFree)
|
||||
pool->object.fnObjectFree(pool->array[pool->size]);
|
||||
}
|
||||
|
||||
ObjectPool_Unlock(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wObjectPool* ObjectPool_New(BOOL synchronized)
|
||||
{
|
||||
wObjectPool* pool = (wObjectPool*)calloc(1, sizeof(wObjectPool));
|
||||
|
||||
if (!pool)
|
||||
goto fail;
|
||||
|
||||
pool->synchronized = synchronized;
|
||||
|
||||
if (pool->synchronized)
|
||||
{
|
||||
if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!ObjectPool_EnsureCapacity(pool, 32))
|
||||
goto fail;
|
||||
|
||||
return pool;
|
||||
|
||||
fail:
|
||||
ObjectPool_Free(pool);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ObjectPool_Free(wObjectPool* pool)
|
||||
{
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
ObjectPool_Clear(pool);
|
||||
|
||||
if (pool->synchronized)
|
||||
DeleteCriticalSection(&pool->lock);
|
||||
|
||||
free((void*)pool->array);
|
||||
|
||||
free(pool);
|
||||
}
|
||||
273
third_party/FreeRDP/winpr/libwinpr/utils/collections/PubSub.c
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Publisher/Subscriber Pattern
|
||||
*
|
||||
* 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/collections.h>
|
||||
|
||||
/**
|
||||
* Events (C# Programming Guide)
|
||||
* http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
|
||||
*/
|
||||
|
||||
struct s_wPubSub
|
||||
{
|
||||
CRITICAL_SECTION lock;
|
||||
BOOL synchronized;
|
||||
|
||||
size_t size;
|
||||
size_t count;
|
||||
wEventType* events;
|
||||
};
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
wEventType* PubSub_GetEventTypes(wPubSub* pubSub, size_t* count)
|
||||
{
|
||||
WINPR_ASSERT(pubSub);
|
||||
if (count)
|
||||
*count = pubSub->count;
|
||||
|
||||
return pubSub->events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
void PubSub_Lock(wPubSub* pubSub)
|
||||
{
|
||||
WINPR_ASSERT(pubSub);
|
||||
if (pubSub->synchronized)
|
||||
EnterCriticalSection(&pubSub->lock);
|
||||
}
|
||||
|
||||
void PubSub_Unlock(wPubSub* pubSub)
|
||||
{
|
||||
WINPR_ASSERT(pubSub);
|
||||
if (pubSub->synchronized)
|
||||
LeaveCriticalSection(&pubSub->lock);
|
||||
}
|
||||
|
||||
wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
|
||||
{
|
||||
wEventType* event = nullptr;
|
||||
|
||||
WINPR_ASSERT(pubSub);
|
||||
WINPR_ASSERT(EventName);
|
||||
for (size_t index = 0; index < pubSub->count; index++)
|
||||
{
|
||||
if (strcmp(pubSub->events[index].EventName, EventName) == 0)
|
||||
{
|
||||
event = &(pubSub->events[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(pubSub);
|
||||
WINPR_ASSERT(events || (count == 0));
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Lock(pubSub);
|
||||
|
||||
const size_t required = pubSub->count + count;
|
||||
WINPR_ASSERT((required >= pubSub->count) && (required >= count));
|
||||
|
||||
if (required >= pubSub->size)
|
||||
{
|
||||
size_t new_size = pubSub->size;
|
||||
do
|
||||
{
|
||||
WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
|
||||
new_size += 128ull;
|
||||
} while (new_size <= required);
|
||||
|
||||
wEventType* new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
|
||||
if (!new_event)
|
||||
goto fail;
|
||||
pubSub->size = new_size;
|
||||
pubSub->events = new_event;
|
||||
}
|
||||
|
||||
CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
|
||||
pubSub->count += count;
|
||||
|
||||
fail:
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Unlock(pubSub);
|
||||
}
|
||||
|
||||
int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, ...)
|
||||
{
|
||||
wEventType* event = nullptr;
|
||||
int status = -1;
|
||||
WINPR_ASSERT(pubSub);
|
||||
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
va_start(ap, EventName);
|
||||
pEventHandler EventHandler = va_arg(ap, pEventHandler);
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Lock(pubSub);
|
||||
|
||||
event = PubSub_FindEventType(pubSub, EventName);
|
||||
|
||||
if (event)
|
||||
{
|
||||
status = 0;
|
||||
|
||||
if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
|
||||
event->EventHandlers[event->EventHandlerCount++] = EventHandler;
|
||||
else
|
||||
status = -1;
|
||||
}
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Unlock(pubSub);
|
||||
|
||||
va_end(ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, ...)
|
||||
{
|
||||
wEventType* event = nullptr;
|
||||
int status = -1;
|
||||
WINPR_ASSERT(pubSub);
|
||||
WINPR_ASSERT(EventName);
|
||||
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
va_start(ap, EventName);
|
||||
pEventHandler EventHandler = va_arg(ap, pEventHandler);
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Lock(pubSub);
|
||||
|
||||
event = PubSub_FindEventType(pubSub, EventName);
|
||||
|
||||
if (event)
|
||||
{
|
||||
status = 0;
|
||||
|
||||
for (size_t index = 0; index < event->EventHandlerCount; index++)
|
||||
{
|
||||
if (event->EventHandlers[index] == EventHandler)
|
||||
{
|
||||
event->EventHandlers[index] = nullptr;
|
||||
event->EventHandlerCount--;
|
||||
MoveMemory((void*)&event->EventHandlers[index],
|
||||
(void*)&event->EventHandlers[index + 1],
|
||||
(MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Unlock(pubSub);
|
||||
|
||||
va_end(ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
|
||||
{
|
||||
wEventType* event = nullptr;
|
||||
int status = -1;
|
||||
|
||||
if (!pubSub)
|
||||
return -1;
|
||||
WINPR_ASSERT(e);
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Lock(pubSub);
|
||||
|
||||
event = PubSub_FindEventType(pubSub, EventName);
|
||||
|
||||
if (pubSub->synchronized)
|
||||
PubSub_Unlock(pubSub);
|
||||
|
||||
if (event)
|
||||
{
|
||||
status = 0;
|
||||
|
||||
for (size_t index = 0; index < event->EventHandlerCount; index++)
|
||||
{
|
||||
if (event->EventHandlers[index])
|
||||
{
|
||||
event->EventHandlers[index](context, e);
|
||||
status++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wPubSub* PubSub_New(BOOL synchronized)
|
||||
{
|
||||
wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
|
||||
|
||||
if (!pubSub)
|
||||
return nullptr;
|
||||
|
||||
pubSub->synchronized = synchronized;
|
||||
|
||||
if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
|
||||
goto fail;
|
||||
|
||||
pubSub->count = 0;
|
||||
pubSub->size = 64;
|
||||
|
||||
pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
|
||||
if (!pubSub->events)
|
||||
goto fail;
|
||||
|
||||
return pubSub;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
PubSub_Free(pubSub);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PubSub_Free(wPubSub* pubSub)
|
||||
{
|
||||
if (pubSub)
|
||||
{
|
||||
if (pubSub->synchronized)
|
||||
DeleteCriticalSection(&pubSub->lock);
|
||||
|
||||
free(pubSub->events);
|
||||
free(pubSub);
|
||||
}
|
||||
}
|
||||
405
third_party/FreeRDP/winpr/libwinpr/utils/collections/Queue.c
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.Queue
|
||||
*
|
||||
* 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/assert.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
struct s_wQueue
|
||||
{
|
||||
size_t capacity;
|
||||
size_t growthFactor;
|
||||
BOOL synchronized;
|
||||
|
||||
BYTE padding[4];
|
||||
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t size;
|
||||
uintptr_t* array;
|
||||
CRITICAL_SECTION lock;
|
||||
HANDLE event;
|
||||
|
||||
wObject object;
|
||||
BOOL haveLock;
|
||||
|
||||
BYTE padding2[4];
|
||||
};
|
||||
|
||||
static inline void* uptr2void(uintptr_t ptr)
|
||||
{
|
||||
return (void*)ptr;
|
||||
}
|
||||
|
||||
static inline uintptr_t void2uptr(const void* ptr)
|
||||
{
|
||||
return (uintptr_t)ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* C equivalent of the C# Queue Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.queue.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of elements contained in the Queue.
|
||||
*/
|
||||
|
||||
size_t Queue_Count(wQueue* queue)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
ret = queue->size;
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t Queue_Capacity(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
const size_t ret = queue->capacity;
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock access to the ArrayList
|
||||
*/
|
||||
|
||||
void Queue_Lock(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
if (queue->synchronized)
|
||||
EnterCriticalSection(&queue->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock access to the ArrayList
|
||||
*/
|
||||
|
||||
void Queue_Unlock(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
if (queue->synchronized)
|
||||
LeaveCriticalSection(&queue->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an event which is set when the queue is non-empty
|
||||
*/
|
||||
|
||||
HANDLE Queue_Event(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
return queue->event;
|
||||
}
|
||||
|
||||
wObject* Queue_Object(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
return &queue->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes all objects from the Queue.
|
||||
*/
|
||||
|
||||
void Queue_Clear(wQueue* queue)
|
||||
{
|
||||
Queue_Lock(queue);
|
||||
|
||||
for (size_t index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity)
|
||||
{
|
||||
if (queue->object.fnObjectFree)
|
||||
{
|
||||
void* obj = uptr2void(queue->array[index]);
|
||||
queue->object.fnObjectFree(obj);
|
||||
}
|
||||
|
||||
queue->array[index] = 0;
|
||||
}
|
||||
|
||||
queue->size = 0;
|
||||
queue->head = queue->tail = 0;
|
||||
(void)ResetEvent(queue->event);
|
||||
Queue_Unlock(queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an element is in the Queue.
|
||||
*/
|
||||
|
||||
BOOL Queue_Contains(wQueue* queue, const void* obj)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
for (size_t index = 0; index < queue->tail; index++)
|
||||
{
|
||||
void* ptr = uptr2void(queue->array[index]);
|
||||
if (queue->object.fnObjectEquals(ptr, obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count)
|
||||
{
|
||||
const size_t blocksize = 32ull;
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
if (queue->growthFactor > SIZE_MAX / blocksize)
|
||||
return FALSE;
|
||||
|
||||
const size_t increment = blocksize * queue->growthFactor;
|
||||
if (queue->size > SIZE_MAX - count)
|
||||
return FALSE;
|
||||
|
||||
const size_t required = queue->size + count;
|
||||
if (required > queue->capacity)
|
||||
{
|
||||
const size_t old_capacity = queue->capacity;
|
||||
if (required > SIZE_MAX - increment)
|
||||
return FALSE;
|
||||
|
||||
const size_t new_capacity = required + increment - required % increment;
|
||||
if (new_capacity > SIZE_MAX / sizeof(BYTE*))
|
||||
return FALSE;
|
||||
|
||||
uintptr_t* newArray = (uintptr_t*)realloc(queue->array, sizeof(uintptr_t) * new_capacity);
|
||||
|
||||
if (!newArray)
|
||||
return FALSE;
|
||||
|
||||
queue->capacity = new_capacity;
|
||||
queue->array = newArray;
|
||||
ZeroMemory(&(queue->array[old_capacity]),
|
||||
(new_capacity - old_capacity) * sizeof(uintptr_t));
|
||||
|
||||
/* rearrange wrapped entries */
|
||||
if (queue->tail <= queue->head)
|
||||
{
|
||||
const size_t tocopy = queue->tail;
|
||||
const size_t slots = new_capacity - old_capacity;
|
||||
const size_t batch = (tocopy < slots) ? tocopy : slots;
|
||||
|
||||
CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(uintptr_t));
|
||||
|
||||
/* Tail is decremented. if the whole thing is appended
|
||||
* just move the existing tail by old_capacity */
|
||||
if (tocopy < slots)
|
||||
{
|
||||
ZeroMemory(queue->array, batch * sizeof(uintptr_t));
|
||||
queue->tail += old_capacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t remain = queue->tail - batch;
|
||||
const size_t movesize = remain * sizeof(uintptr_t);
|
||||
memmove_s(queue->array, queue->tail * sizeof(uintptr_t), &queue->array[batch],
|
||||
movesize);
|
||||
|
||||
const size_t zerooffset = remain;
|
||||
const size_t zerosize = (queue->tail - remain) * sizeof(uintptr_t);
|
||||
ZeroMemory(&queue->array[zerooffset], zerosize);
|
||||
queue->tail -= batch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to the end of the Queue.
|
||||
*/
|
||||
|
||||
BOOL Queue_Enqueue(wQueue* queue, const void* obj)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
if (!Queue_EnsureCapacity(queue, 1))
|
||||
goto out;
|
||||
|
||||
if (queue->object.fnObjectNew)
|
||||
queue->array[queue->tail] = void2uptr(queue->object.fnObjectNew(obj));
|
||||
else
|
||||
queue->array[queue->tail] = void2uptr(obj);
|
||||
|
||||
queue->tail = (queue->tail + 1) % queue->capacity;
|
||||
|
||||
{
|
||||
const BOOL signalSet = queue->size == 0;
|
||||
queue->size++;
|
||||
|
||||
if (signalSet)
|
||||
(void)SetEvent(queue->event);
|
||||
}
|
||||
out:
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the object at the beginning of the Queue.
|
||||
*/
|
||||
|
||||
void* Queue_Dequeue(wQueue* queue)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
if (queue->size > 0)
|
||||
{
|
||||
obj = uptr2void(queue->array[queue->head]);
|
||||
queue->array[queue->head] = 0;
|
||||
queue->head = (queue->head + 1) % queue->capacity;
|
||||
queue->size--;
|
||||
}
|
||||
|
||||
if (queue->size < 1)
|
||||
(void)ResetEvent(queue->event);
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object at the beginning of the Queue without removing it.
|
||||
*/
|
||||
|
||||
void* Queue_Peek(wQueue* queue)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
Queue_Lock(queue);
|
||||
|
||||
if (queue->size > 0)
|
||||
obj = uptr2void(queue->array[queue->head]);
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Queue_Discard(wQueue* queue)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
Queue_Lock(queue);
|
||||
obj = Queue_Dequeue(queue);
|
||||
|
||||
if (queue->object.fnObjectFree)
|
||||
queue->object.fnObjectFree(obj);
|
||||
Queue_Unlock(queue);
|
||||
}
|
||||
|
||||
static BOOL default_queue_equals(const void* obj1, const void* obj2)
|
||||
{
|
||||
return (obj1 == obj2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wQueue* Queue_New(BOOL synchronized, SSIZE_T capacity, SSIZE_T growthFactor)
|
||||
{
|
||||
wQueue* queue = (wQueue*)calloc(1, sizeof(wQueue));
|
||||
|
||||
if (!queue)
|
||||
return nullptr;
|
||||
|
||||
queue->synchronized = synchronized;
|
||||
|
||||
queue->growthFactor = 2;
|
||||
if (growthFactor > 0)
|
||||
queue->growthFactor = (size_t)growthFactor;
|
||||
|
||||
if (capacity <= 0)
|
||||
capacity = 32;
|
||||
if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
|
||||
goto fail;
|
||||
queue->haveLock = TRUE;
|
||||
if (!Queue_EnsureCapacity(queue, (size_t)capacity))
|
||||
goto fail;
|
||||
|
||||
queue->event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
if (!queue->event)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
wObject* obj = Queue_Object(queue);
|
||||
obj->fnObjectEquals = default_queue_equals;
|
||||
}
|
||||
return queue;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
Queue_Free(queue);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Queue_Free(wQueue* queue)
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
|
||||
if (queue->haveLock)
|
||||
{
|
||||
Queue_Clear(queue);
|
||||
DeleteCriticalSection(&queue->lock);
|
||||
}
|
||||
(void)CloseHandle(queue->event);
|
||||
free(queue->array);
|
||||
free(queue);
|
||||
}
|
||||
258
third_party/FreeRDP/winpr/libwinpr/utils/collections/Stack.c
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System.Collections.Stack
|
||||
*
|
||||
* 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/collections.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
struct s_wStack
|
||||
{
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
void** array;
|
||||
CRITICAL_SECTION lock;
|
||||
BOOL synchronized;
|
||||
wObject object;
|
||||
};
|
||||
|
||||
/**
|
||||
* C equivalent of the C# Stack Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of elements contained in the Stack.
|
||||
*/
|
||||
|
||||
size_t Stack_Count(wStack* stack)
|
||||
{
|
||||
size_t ret = 0;
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
ret = stack->size;
|
||||
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether access to the Stack is synchronized (thread safe).
|
||||
*/
|
||||
|
||||
BOOL Stack_IsSynchronized(wStack* stack)
|
||||
{
|
||||
WINPR_ASSERT(stack);
|
||||
return stack->synchronized;
|
||||
}
|
||||
|
||||
wObject* Stack_Object(wStack* stack)
|
||||
{
|
||||
WINPR_ASSERT(stack);
|
||||
return &stack->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes all objects from the Stack.
|
||||
*/
|
||||
|
||||
void Stack_Clear(wStack* stack)
|
||||
{
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
for (size_t index = 0; index < stack->size; index++)
|
||||
{
|
||||
if (stack->object.fnObjectFree)
|
||||
stack->object.fnObjectFree(stack->array[index]);
|
||||
|
||||
stack->array[index] = nullptr;
|
||||
}
|
||||
|
||||
stack->size = 0;
|
||||
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an element is in the Stack.
|
||||
*/
|
||||
|
||||
BOOL Stack_Contains(wStack* stack, const void* obj)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
for (size_t i = 0; i < stack->size; i++)
|
||||
{
|
||||
if (stack->object.fnObjectEquals(stack->array[i], obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an object at the top of the Stack.
|
||||
*/
|
||||
|
||||
void Stack_Push(wStack* stack, void* obj)
|
||||
{
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
WINPR_ASSERT(stack->size < SIZE_MAX);
|
||||
if ((stack->size + 1ull) >= stack->capacity)
|
||||
{
|
||||
size_t new_cap = stack->capacity;
|
||||
do
|
||||
{
|
||||
WINPR_ASSERT(new_cap <= SIZE_MAX - 128ull);
|
||||
new_cap += 128ull;
|
||||
} while (new_cap <= stack->size + 1ull);
|
||||
void** new_arr = (void**)realloc((void*)stack->array, sizeof(void*) * new_cap);
|
||||
|
||||
if (!new_arr)
|
||||
goto end;
|
||||
|
||||
stack->array = new_arr;
|
||||
stack->capacity = new_cap;
|
||||
}
|
||||
|
||||
stack->array[(stack->size)++] = obj;
|
||||
|
||||
end:
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the object at the top of the Stack.
|
||||
*/
|
||||
|
||||
void* Stack_Pop(wStack* stack)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
if (stack->size > 0)
|
||||
obj = stack->array[--(stack->size)];
|
||||
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object at the top of the Stack without removing it.
|
||||
*/
|
||||
|
||||
void* Stack_Peek(wStack* stack)
|
||||
{
|
||||
void* obj = nullptr;
|
||||
|
||||
WINPR_ASSERT(stack);
|
||||
if (stack->synchronized)
|
||||
EnterCriticalSection(&stack->lock);
|
||||
|
||||
if (stack->size > 0)
|
||||
obj = stack->array[stack->size - 1];
|
||||
|
||||
if (stack->synchronized)
|
||||
LeaveCriticalSection(&stack->lock);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static BOOL default_stack_equals(const void* obj1, const void* obj2)
|
||||
{
|
||||
return (obj1 == obj2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wStack* Stack_New(BOOL synchronized)
|
||||
{
|
||||
wStack* stack = nullptr;
|
||||
stack = (wStack*)calloc(1, sizeof(wStack));
|
||||
|
||||
if (!stack)
|
||||
return nullptr;
|
||||
|
||||
stack->object.fnObjectEquals = default_stack_equals;
|
||||
stack->synchronized = synchronized;
|
||||
stack->capacity = 32;
|
||||
stack->array = (void**)calloc(stack->capacity, sizeof(void*));
|
||||
|
||||
if (!stack->array)
|
||||
goto out_free;
|
||||
|
||||
if (stack->synchronized && !InitializeCriticalSectionAndSpinCount(&stack->lock, 4000))
|
||||
goto out_free;
|
||||
|
||||
return stack;
|
||||
out_free:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
Stack_Free(stack);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Stack_Free(wStack* stack)
|
||||
{
|
||||
if (stack)
|
||||
{
|
||||
if (stack->synchronized)
|
||||
DeleteCriticalSection(&stack->lock);
|
||||
|
||||
free((void*)stack->array);
|
||||
free(stack);
|
||||
}
|
||||
}
|
||||
531
third_party/FreeRDP/winpr/libwinpr/utils/collections/StreamPool.c
vendored
Normal file
@@ -0,0 +1,531 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Object Pool
|
||||
*
|
||||
* 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/wlog.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include "../stream.h"
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("utils.streampool")
|
||||
|
||||
struct s_StreamPoolEntry
|
||||
{
|
||||
#if defined(WITH_STREAMPOOL_DEBUG)
|
||||
char** msg;
|
||||
size_t lines;
|
||||
#endif
|
||||
wStream* s;
|
||||
};
|
||||
|
||||
struct s_wStreamPool
|
||||
{
|
||||
size_t aSize;
|
||||
size_t aCapacity;
|
||||
struct s_StreamPoolEntry* aArray;
|
||||
|
||||
size_t uSize;
|
||||
size_t uCapacity;
|
||||
struct s_StreamPoolEntry* uArray;
|
||||
|
||||
CRITICAL_SECTION lock;
|
||||
BOOL synchronized;
|
||||
size_t defaultSize;
|
||||
};
|
||||
|
||||
static void discard_entry(struct s_StreamPoolEntry* entry, BOOL discardStream)
|
||||
{
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
#if defined(WITH_STREAMPOOL_DEBUG)
|
||||
free((void*)entry->msg);
|
||||
#endif
|
||||
|
||||
if (discardStream && entry->s)
|
||||
Stream_Free(entry->s, entry->s->isAllocatedStream);
|
||||
|
||||
const struct s_StreamPoolEntry empty = WINPR_C_ARRAY_INIT;
|
||||
*entry = empty;
|
||||
}
|
||||
|
||||
static struct s_StreamPoolEntry add_entry(wStream* s)
|
||||
{
|
||||
struct s_StreamPoolEntry entry = WINPR_C_ARRAY_INIT;
|
||||
|
||||
#if defined(WITH_STREAMPOOL_DEBUG)
|
||||
void* stack = winpr_backtrace(20);
|
||||
if (stack)
|
||||
entry.msg = winpr_backtrace_symbols(stack, &entry.lines);
|
||||
winpr_backtrace_free(stack);
|
||||
#endif
|
||||
|
||||
entry.s = s;
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the stream pool
|
||||
*/
|
||||
|
||||
static inline void StreamPool_Lock(wStreamPool* pool)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
if (pool->synchronized)
|
||||
EnterCriticalSection(&pool->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the stream pool
|
||||
*/
|
||||
|
||||
static inline void StreamPool_Unlock(wStreamPool* pool)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
if (pool->synchronized)
|
||||
LeaveCriticalSection(&pool->lock);
|
||||
}
|
||||
|
||||
static BOOL StreamPool_EnsureCapacity(wStreamPool* pool, size_t count, BOOL usedOrAvailable)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
|
||||
size_t* cap = (usedOrAvailable) ? &pool->uCapacity : &pool->aCapacity;
|
||||
size_t* size = (usedOrAvailable) ? &pool->uSize : &pool->aSize;
|
||||
struct s_StreamPoolEntry** array = (usedOrAvailable) ? &pool->uArray : &pool->aArray;
|
||||
|
||||
size_t new_cap = 0;
|
||||
if (*cap == 0)
|
||||
new_cap = *size + count;
|
||||
else if (*size + count > *cap)
|
||||
new_cap = (*size + count + 2) / 2 * 3;
|
||||
else if ((*size + count) < *cap / 3)
|
||||
new_cap = *cap / 2;
|
||||
|
||||
if (new_cap > 0)
|
||||
{
|
||||
struct s_StreamPoolEntry* new_arr = nullptr;
|
||||
|
||||
if (*cap < *size + count)
|
||||
*cap += count;
|
||||
|
||||
new_arr =
|
||||
(struct s_StreamPoolEntry*)realloc(*array, sizeof(struct s_StreamPoolEntry) * new_cap);
|
||||
if (!new_arr)
|
||||
return FALSE;
|
||||
*cap = new_cap;
|
||||
*array = new_arr;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
static void StreamPool_ShiftUsed(wStreamPool* pool, size_t index)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
|
||||
const size_t pcount = 1;
|
||||
const size_t off = index + pcount;
|
||||
if (pool->uSize >= off)
|
||||
{
|
||||
for (size_t x = 0; x < pcount; x++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->uArray[index + x];
|
||||
discard_entry(cur, FALSE);
|
||||
}
|
||||
MoveMemory(&pool->uArray[index], &pool->uArray[index + pcount],
|
||||
(pool->uSize - index - pcount) * sizeof(struct s_StreamPoolEntry));
|
||||
pool->uSize -= pcount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a used stream to the pool.
|
||||
*/
|
||||
|
||||
static void StreamPool_AddUsed(wStreamPool* pool, wStream* s)
|
||||
{
|
||||
StreamPool_EnsureCapacity(pool, 1, TRUE);
|
||||
pool->uArray[pool->uSize] = add_entry(s);
|
||||
pool->uSize++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a used stream from the pool.
|
||||
*/
|
||||
|
||||
static void StreamPool_RemoveUsed(wStreamPool* pool, wStream* s)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
for (size_t index = 0; index < pool->uSize; index++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->uArray[index];
|
||||
if (cur->s == s)
|
||||
{
|
||||
StreamPool_ShiftUsed(pool, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void StreamPool_ShiftAvailable(wStreamPool* pool, size_t index)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
|
||||
const size_t pcount = 1;
|
||||
const size_t off = index + pcount;
|
||||
if (pool->aSize >= off)
|
||||
{
|
||||
for (size_t x = 0; x < pcount; x++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->aArray[index + x];
|
||||
discard_entry(cur, FALSE);
|
||||
}
|
||||
|
||||
MoveMemory(&pool->aArray[index], &pool->aArray[index + pcount],
|
||||
(pool->aSize - index - pcount) * sizeof(struct s_StreamPoolEntry));
|
||||
pool->aSize -= pcount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a stream from the pool.
|
||||
*/
|
||||
|
||||
wStream* StreamPool_Take(wStreamPool* pool, size_t size)
|
||||
{
|
||||
BOOL found = FALSE;
|
||||
size_t foundIndex = 0;
|
||||
wStream* s = nullptr;
|
||||
|
||||
StreamPool_Lock(pool);
|
||||
|
||||
if (size == 0)
|
||||
size = pool->defaultSize;
|
||||
|
||||
for (size_t index = 0; index < pool->aSize; index++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->aArray[index];
|
||||
s = cur->s;
|
||||
|
||||
if (Stream_Capacity(s) >= size)
|
||||
{
|
||||
found = TRUE;
|
||||
foundIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
s = Stream_New(nullptr, size);
|
||||
if (!s)
|
||||
goto out_fail;
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
Stream_ResetPosition(s);
|
||||
Stream_SetLength(s, Stream_Capacity(s));
|
||||
StreamPool_ShiftAvailable(pool, foundIndex);
|
||||
}
|
||||
|
||||
if (s)
|
||||
{
|
||||
s->pool = pool;
|
||||
s->count = 1;
|
||||
StreamPool_AddUsed(pool, s);
|
||||
}
|
||||
|
||||
out_fail:
|
||||
StreamPool_Unlock(pool);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object to the pool.
|
||||
*/
|
||||
|
||||
static void StreamPool_Remove(wStreamPool* pool, wStream* s)
|
||||
{
|
||||
StreamPool_EnsureCapacity(pool, 1, FALSE);
|
||||
Stream_EnsureValidity(s);
|
||||
for (size_t x = 0; x < pool->aSize; x++)
|
||||
{
|
||||
wStream* cs = pool->aArray[x].s;
|
||||
if (cs == s)
|
||||
return;
|
||||
}
|
||||
pool->aArray[(pool->aSize)++] = add_entry(s);
|
||||
StreamPool_RemoveUsed(pool, s);
|
||||
}
|
||||
|
||||
static void StreamPool_ReleaseOrReturn(wStreamPool* pool, wStream* s)
|
||||
{
|
||||
StreamPool_Lock(pool);
|
||||
StreamPool_Remove(pool, s);
|
||||
StreamPool_Unlock(pool);
|
||||
}
|
||||
|
||||
void StreamPool_Return(wStreamPool* pool, wStream* s)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
StreamPool_Lock(pool);
|
||||
StreamPool_Remove(pool, s);
|
||||
StreamPool_Unlock(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment stream reference count
|
||||
*/
|
||||
|
||||
void Stream_AddRef(wStream* s)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
s->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement stream reference count
|
||||
*/
|
||||
|
||||
void Stream_Release(wStream* s)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (s->count > 0)
|
||||
s->count--;
|
||||
if (s->count == 0)
|
||||
{
|
||||
if (s->pool)
|
||||
StreamPool_ReleaseOrReturn(s->pool, s);
|
||||
else
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find stream in pool using pointer inside buffer
|
||||
*/
|
||||
|
||||
wStream* StreamPool_Find(wStreamPool* pool, const BYTE* ptr)
|
||||
{
|
||||
wStream* s = nullptr;
|
||||
|
||||
StreamPool_Lock(pool);
|
||||
|
||||
for (size_t index = 0; index < pool->uSize; index++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->uArray[index];
|
||||
|
||||
if ((ptr >= Stream_Buffer(cur->s)) &&
|
||||
(ptr < (Stream_Buffer(cur->s) + Stream_Capacity(cur->s))))
|
||||
{
|
||||
s = cur->s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StreamPool_Unlock(pool);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the streams currently cached in the pool.
|
||||
*/
|
||||
|
||||
void StreamPool_Clear(wStreamPool* pool)
|
||||
{
|
||||
StreamPool_Lock(pool);
|
||||
|
||||
for (size_t x = 0; x < pool->aSize; x++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->aArray[x];
|
||||
discard_entry(cur, TRUE);
|
||||
}
|
||||
pool->aSize = 0;
|
||||
|
||||
if (pool->uSize > 0)
|
||||
{
|
||||
WLog_WARN(TAG, "Clearing StreamPool, but there are %" PRIuz " streams currently in use",
|
||||
pool->uSize);
|
||||
for (size_t x = 0; x < pool->uSize; x++)
|
||||
{
|
||||
struct s_StreamPoolEntry* cur = &pool->uArray[x];
|
||||
discard_entry(cur, TRUE);
|
||||
}
|
||||
pool->uSize = 0;
|
||||
}
|
||||
|
||||
StreamPool_Unlock(pool);
|
||||
}
|
||||
|
||||
size_t StreamPool_UsedCount(wStreamPool* pool)
|
||||
{
|
||||
StreamPool_Lock(pool);
|
||||
size_t usize = pool->uSize;
|
||||
StreamPool_Unlock(pool);
|
||||
return usize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize)
|
||||
{
|
||||
wStreamPool* pool = nullptr;
|
||||
|
||||
pool = (wStreamPool*)calloc(1, sizeof(wStreamPool));
|
||||
|
||||
if (pool)
|
||||
{
|
||||
pool->synchronized = synchronized;
|
||||
pool->defaultSize = defaultSize;
|
||||
|
||||
if (!StreamPool_EnsureCapacity(pool, 32, FALSE))
|
||||
goto fail;
|
||||
if (!StreamPool_EnsureCapacity(pool, 32, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return pool;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
StreamPool_Free(pool);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StreamPool_Free(wStreamPool* pool)
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
StreamPool_Clear(pool);
|
||||
|
||||
DeleteCriticalSection(&pool->lock);
|
||||
|
||||
free(pool->aArray);
|
||||
free(pool->uArray);
|
||||
|
||||
free(pool);
|
||||
}
|
||||
}
|
||||
|
||||
char* StreamPool_GetStatistics(wStreamPool* pool, char* buffer, size_t size)
|
||||
{
|
||||
WINPR_ASSERT(pool);
|
||||
|
||||
if (!buffer || (size < 1))
|
||||
return nullptr;
|
||||
|
||||
size_t used = 0;
|
||||
int offset = _snprintf(buffer, size - 1,
|
||||
"aSize =%" PRIuz ", uSize =%" PRIuz ", aCapacity=%" PRIuz
|
||||
", uCapacity=%" PRIuz,
|
||||
pool->aSize, pool->uSize, pool->aCapacity, pool->uCapacity);
|
||||
if ((offset > 0) && ((size_t)offset < size))
|
||||
used += (size_t)offset;
|
||||
|
||||
#if defined(WITH_STREAMPOOL_DEBUG)
|
||||
StreamPool_Lock(pool);
|
||||
|
||||
offset = _snprintf(&buffer[used], size - 1 - used, "\n-- dump used array take locations --\n");
|
||||
if ((offset > 0) && ((size_t)offset < size - used))
|
||||
used += (size_t)offset;
|
||||
for (size_t x = 0; x < pool->uSize; x++)
|
||||
{
|
||||
const struct s_StreamPoolEntry* cur = &pool->uArray[x];
|
||||
WINPR_ASSERT(cur->msg || (cur->lines == 0));
|
||||
|
||||
for (size_t y = 0; y < cur->lines; y++)
|
||||
{
|
||||
offset = _snprintf(&buffer[used], size - 1 - used, "[%" PRIuz " | %" PRIuz "]: %s\n", x,
|
||||
y, cur->msg[y]);
|
||||
if ((offset > 0) && ((size_t)offset < size - used))
|
||||
used += (size_t)offset;
|
||||
}
|
||||
}
|
||||
|
||||
offset = _snprintf(&buffer[used], size - 1 - used, "\n-- statistics called from --\n");
|
||||
if ((offset > 0) && ((size_t)offset < size - used))
|
||||
used += (size_t)offset;
|
||||
|
||||
struct s_StreamPoolEntry entry = WINPR_C_ARRAY_INIT;
|
||||
void* stack = winpr_backtrace(20);
|
||||
if (stack)
|
||||
entry.msg = winpr_backtrace_symbols(stack, &entry.lines);
|
||||
winpr_backtrace_free(stack);
|
||||
|
||||
for (size_t x = 0; x < entry.lines; x++)
|
||||
{
|
||||
const char* msg = entry.msg[x];
|
||||
offset = _snprintf(&buffer[used], size - 1 - used, "[%" PRIuz "]: %s\n", x, msg);
|
||||
if ((offset > 0) && ((size_t)offset < size - used))
|
||||
used += (size_t)offset;
|
||||
}
|
||||
free((void*)entry.msg);
|
||||
StreamPool_Unlock(pool);
|
||||
#endif
|
||||
buffer[used] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
BOOL StreamPool_WaitForReturn(wStreamPool* pool, UINT32 timeoutMS)
|
||||
{
|
||||
wLog* log = WLog_Get(TAG);
|
||||
|
||||
/* HACK: We disconnected the transport above, now wait without a read or write lock until all
|
||||
* streams in use have been returned to the pool. */
|
||||
while (timeoutMS > 0)
|
||||
{
|
||||
const size_t used = StreamPool_UsedCount(pool);
|
||||
if (used == 0)
|
||||
return TRUE;
|
||||
WLog_Print(log, WLOG_DEBUG, "%" PRIuz " streams still in use, sleeping...", used);
|
||||
|
||||
char buffer[4096] = WINPR_C_ARRAY_INIT;
|
||||
StreamPool_GetStatistics(pool, buffer, sizeof(buffer));
|
||||
WLog_Print(log, WLOG_TRACE, "Pool statistics: %s", buffer);
|
||||
|
||||
UINT32 diff = 10;
|
||||
if (timeoutMS != INFINITE)
|
||||
{
|
||||
diff = timeoutMS > 10 ? 10 : timeoutMS;
|
||||
timeoutMS -= diff;
|
||||
}
|
||||
Sleep(diff);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
120
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/backtrace.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* A stack unwinder. */
|
||||
|
||||
#ifndef _CORKSCREW_BACKTRACE_H
|
||||
#define _CORKSCREW_BACKTRACE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <corkscrew/ptrace.h>
|
||||
#include <corkscrew/map_info.h>
|
||||
#include <corkscrew/symbol_table.h>
|
||||
|
||||
/*
|
||||
* Describes a single frame of a backtrace.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uintptr_t absolute_pc; /* absolute PC offset */
|
||||
uintptr_t stack_top; /* top of stack for this frame */
|
||||
size_t stack_size; /* size of this stack frame */
|
||||
} backtrace_frame_t;
|
||||
|
||||
/*
|
||||
* Describes the symbols associated with a backtrace frame.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uintptr_t relative_pc; /* relative frame PC offset from the start of the library,
|
||||
or the absolute PC if the library is unknown */
|
||||
uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the
|
||||
library or 0 if the library is unknown */
|
||||
char* map_name; /* executable or library name, or nullptr if unknown */
|
||||
char* symbol_name; /* symbol name, or nullptr if unknown */
|
||||
char* demangled_name; /* demangled symbol name, or nullptr if unknown */
|
||||
} backtrace_symbol_t;
|
||||
|
||||
/*
|
||||
* Unwinds the call stack for the current thread of execution.
|
||||
* Populates the backtrace array with the program counters from the call stack.
|
||||
* Returns the number of frames collected, or -1 if an error occurred.
|
||||
*/
|
||||
ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
|
||||
|
||||
/*
|
||||
* Unwinds the call stack for a thread within this process.
|
||||
* Populates the backtrace array with the program counters from the call stack.
|
||||
* Returns the number of frames collected, or -1 if an error occurred.
|
||||
*
|
||||
* The task is briefly suspended while the backtrace is being collected.
|
||||
*/
|
||||
ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth,
|
||||
size_t max_depth);
|
||||
|
||||
/*
|
||||
* Unwinds the call stack of a task within a remote process using ptrace().
|
||||
* Populates the backtrace array with the program counters from the call stack.
|
||||
* Returns the number of frames collected, or -1 if an error occurred.
|
||||
*/
|
||||
ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
|
||||
backtrace_frame_t* backtrace, size_t ignore_depth,
|
||||
size_t max_depth);
|
||||
|
||||
/*
|
||||
* Gets the symbols for each frame of a backtrace.
|
||||
* The symbols array must be big enough to hold one symbol record per frame.
|
||||
* The symbols must later be freed using free_backtrace_symbols.
|
||||
*/
|
||||
void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
|
||||
backtrace_symbol_t* backtrace_symbols);
|
||||
|
||||
/*
|
||||
* Gets the symbols for each frame of a backtrace from a remote process.
|
||||
* The symbols array must be big enough to hold one symbol record per frame.
|
||||
* The symbols must later be freed using free_backtrace_symbols.
|
||||
*/
|
||||
void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
|
||||
const backtrace_frame_t* backtrace, size_t frames,
|
||||
backtrace_symbol_t* backtrace_symbols);
|
||||
|
||||
/*
|
||||
* Frees the storage associated with backtrace symbols.
|
||||
*/
|
||||
void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames);
|
||||
|
||||
enum
|
||||
{
|
||||
// A hint for how big to make the line buffer for format_backtrace_line
|
||||
MAX_BACKTRACE_LINE_LENGTH = 800,
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a line from a backtrace as a zero-terminated string into the specified buffer.
|
||||
*/
|
||||
void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame,
|
||||
const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CORKSCREW_BACKTRACE_H
|
||||
260
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/debug.c
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Debugging Utils
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#include <corkscrew/backtrace.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define TAG "com.winpr.utils.debug"
|
||||
#define LOGT(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOGD(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOGI(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOGW(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOGE(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOGF(...) \
|
||||
do \
|
||||
{ \
|
||||
WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
backtrace_frame_t* buffer;
|
||||
size_t max;
|
||||
size_t used;
|
||||
} t_corkscrew_data;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* hdl;
|
||||
ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth,
|
||||
size_t max_depth);
|
||||
ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth,
|
||||
size_t max_depth);
|
||||
ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context,
|
||||
backtrace_frame_t* backtrace, size_t ignore_depth,
|
||||
size_t max_depth);
|
||||
void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames,
|
||||
backtrace_symbol_t* backtrace_symbols);
|
||||
void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context,
|
||||
const backtrace_frame_t* backtrace, size_t frames,
|
||||
backtrace_symbol_t* backtrace_symbols);
|
||||
void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames);
|
||||
void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame,
|
||||
const backtrace_symbol_t* symbol, char* buffer,
|
||||
size_t bufferSize);
|
||||
} t_corkscrew;
|
||||
|
||||
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
|
||||
static t_corkscrew* fkt = nullptr;
|
||||
|
||||
void load_library(void)
|
||||
{
|
||||
static t_corkscrew lib;
|
||||
{
|
||||
lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY);
|
||||
|
||||
if (!lib.hdl)
|
||||
{
|
||||
LOGF("dlopen error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace");
|
||||
|
||||
if (!lib.unwind_backtrace)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread");
|
||||
|
||||
if (!lib.unwind_backtrace_thread)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace");
|
||||
|
||||
if (!lib.unwind_backtrace_ptrace)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols");
|
||||
|
||||
if (!lib.get_backtrace_symbols)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace");
|
||||
|
||||
if (!lib.get_backtrace_symbols_ptrace)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols");
|
||||
|
||||
if (!lib.free_backtrace_symbols)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line");
|
||||
|
||||
if (!lib.format_backtrace_line)
|
||||
{
|
||||
LOGF("dlsym error %s", dlerror());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fkt = &lib;
|
||||
return;
|
||||
}
|
||||
fail:
|
||||
{
|
||||
if (lib.hdl)
|
||||
dlclose(lib.hdl);
|
||||
|
||||
fkt = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void winpr_corkscrew_backtrace_free(void* buffer)
|
||||
{
|
||||
t_corkscrew_data* data = (t_corkscrew_data*)buffer;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
free(data->buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void* winpr_corkscrew_backtrace(DWORD size)
|
||||
{
|
||||
t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data));
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
data->buffer = calloc(size, sizeof(backtrace_frame_t));
|
||||
|
||||
if (!data->buffer)
|
||||
{
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pthread_once(&initialized, load_library);
|
||||
data->max = size;
|
||||
data->used = fkt->unwind_backtrace(data->buffer, 0, size);
|
||||
return data;
|
||||
}
|
||||
|
||||
char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used)
|
||||
{
|
||||
t_corkscrew_data* data = (t_corkscrew_data*)buffer;
|
||||
if (used)
|
||||
*used = 0;
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
pthread_once(&initialized, load_library);
|
||||
|
||||
if (!fkt)
|
||||
{
|
||||
LOGF(support_msg);
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t line_len = (data->max > 1024) ? data->max : 1024;
|
||||
size_t array_size = data->used * sizeof(char*);
|
||||
size_t lines_size = data->used * line_len;
|
||||
char** vlines = calloc(1, array_size + lines_size);
|
||||
backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t));
|
||||
|
||||
if (!vlines || !symbols)
|
||||
{
|
||||
free(vlines);
|
||||
free(symbols);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Set the pointers in the allocated buffer's initial array section */
|
||||
for (size_t i = 0; i < data->used; i++)
|
||||
vlines[i] = (char*)vlines + array_size + i * line_len;
|
||||
|
||||
fkt->get_backtrace_symbols(data->buffer, data->used, symbols);
|
||||
|
||||
for (size_t i = 0; i < data->used; i++)
|
||||
fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len);
|
||||
|
||||
fkt->free_backtrace_symbols(symbols, data->used);
|
||||
free(symbols);
|
||||
|
||||
if (used)
|
||||
*used = data->used;
|
||||
|
||||
return vlines;
|
||||
}
|
||||
}
|
||||
40
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/debug.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Debugging helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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_DEBUG_CORKSCREW_H
|
||||
#define WINPR_DEBUG_CORKSCREW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
void* winpr_corkscrew_backtrace(DWORD size);
|
||||
void winpr_corkscrew_backtrace_free(void* buffer);
|
||||
char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used);
|
||||
void winpr_corkscrew_backtrace_symbols_fd(void* buffer, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_DEBUG_CORKSCREW_H */
|
||||
43
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/demangle.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* C++ symbol name demangling. */
|
||||
|
||||
#ifndef _CORKSCREW_DEMANGLE_H
|
||||
#define _CORKSCREW_DEMANGLE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Demangles a C++ symbol name.
|
||||
* If name is nullptr or if the name cannot be demangled, returns nullptr.
|
||||
* Otherwise, returns a newly allocated string that contains the demangled name.
|
||||
*
|
||||
* The caller must free the returned string using free().
|
||||
*/
|
||||
char* demangle_symbol_name(const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CORKSCREW_DEMANGLE_H
|
||||
76
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/map_info.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Process memory map. */
|
||||
|
||||
#ifndef _CORKSCREW_MAP_INFO_H
|
||||
#define _CORKSCREW_MAP_INFO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct map_info* next;
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
bool is_readable;
|
||||
bool is_writable;
|
||||
bool is_executable;
|
||||
void* data; // arbitrary data associated with the map by the user, initially nullptr
|
||||
char name[];
|
||||
} map_info_t;
|
||||
|
||||
/* Loads memory map from /proc/<tid>/maps. */
|
||||
map_info_t* load_map_info_list(pid_t tid);
|
||||
|
||||
/* Frees memory map. */
|
||||
void free_map_info_list(map_info_t* milist);
|
||||
|
||||
/* Finds the memory map that contains the specified address. */
|
||||
const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr);
|
||||
|
||||
/* Returns true if the addr is in a readable map. */
|
||||
bool is_readable_map(const map_info_t* milist, uintptr_t addr);
|
||||
/* Returns true if the addr is in a writable map. */
|
||||
bool is_writable_map(const map_info_t* milist, uintptr_t addr);
|
||||
/* Returns true if the addr is in an executable map. */
|
||||
bool is_executable_map(const map_info_t* milist, uintptr_t addr);
|
||||
|
||||
/* Acquires a reference to the memory map for this process.
|
||||
* The result is cached and refreshed automatically.
|
||||
* Make sure to release the map info when done. */
|
||||
map_info_t* acquire_my_map_info_list();
|
||||
|
||||
/* Releases a reference to the map info for this process that was
|
||||
* previous acquired using acquire_my_map_info_list(). */
|
||||
void release_my_map_info_list(map_info_t* milist);
|
||||
|
||||
/* Flushes the cached memory map so the next call to
|
||||
* acquire_my_map_info_list() gets fresh data. */
|
||||
void flush_my_map_info_list();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CORKSCREW_MAP_INFO_H
|
||||
139
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/ptrace.h
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Useful ptrace() utility functions. */
|
||||
|
||||
#ifndef _CORKSCREW_PTRACE_H
|
||||
#define _CORKSCREW_PTRACE_H
|
||||
|
||||
#include <corkscrew/map_info.h>
|
||||
#include <corkscrew/symbol_table.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Stores information about a process that is used for several different
|
||||
* ptrace() based operations. */
|
||||
typedef struct
|
||||
{
|
||||
map_info_t* map_info_list;
|
||||
} ptrace_context_t;
|
||||
|
||||
/* Describes how to access memory from a process. */
|
||||
typedef struct
|
||||
{
|
||||
pid_t tid;
|
||||
const map_info_t* map_info_list;
|
||||
} memory_t;
|
||||
|
||||
#ifdef __i386__
|
||||
/* ptrace() register context. */
|
||||
typedef struct pt_regs_x86
|
||||
{
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t ebp;
|
||||
uint32_t eax;
|
||||
uint32_t xds;
|
||||
uint32_t xes;
|
||||
uint32_t xfs;
|
||||
uint32_t xgs;
|
||||
uint32_t orig_eax;
|
||||
uint32_t eip;
|
||||
uint32_t xcs;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint32_t xss;
|
||||
} pt_regs_x86_t;
|
||||
#endif
|
||||
|
||||
#ifdef __mips__
|
||||
/* ptrace() GET_REGS context. */
|
||||
typedef struct pt_regs_mips
|
||||
{
|
||||
uint64_t regs[32];
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
uint64_t cp0_epc;
|
||||
uint64_t cp0_badvaddr;
|
||||
uint64_t cp0_status;
|
||||
uint64_t cp0_cause;
|
||||
} pt_regs_mips_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initializes a memory structure for accessing memory from this process.
|
||||
*/
|
||||
void init_memory(memory_t* memory, const map_info_t* map_info_list);
|
||||
|
||||
/*
|
||||
* Initializes a memory structure for accessing memory from another process
|
||||
* using ptrace().
|
||||
*/
|
||||
void init_memory_ptrace(memory_t* memory, pid_t tid);
|
||||
|
||||
/*
|
||||
* Reads a word of memory safely.
|
||||
* If the memory is local, ensures that the address is readable before dereferencing it.
|
||||
* Returns false and a value of 0xffffffff if the word could not be read.
|
||||
*/
|
||||
bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value);
|
||||
|
||||
/*
|
||||
* Reads a word of memory safely using ptrace().
|
||||
* Returns false and a value of 0xffffffff if the word could not be read.
|
||||
*/
|
||||
bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value);
|
||||
|
||||
/*
|
||||
* Loads information needed for examining a remote process using ptrace().
|
||||
* The caller must already have successfully attached to the process
|
||||
* using ptrace().
|
||||
*
|
||||
* The context can be used for any threads belonging to that process
|
||||
* assuming ptrace() is attached to them before performing the actual
|
||||
* unwinding. The context can continue to be used to decode backtraces
|
||||
* even after ptrace() has been detached from the process.
|
||||
*/
|
||||
ptrace_context_t* load_ptrace_context(pid_t pid);
|
||||
|
||||
/*
|
||||
* Frees a ptrace context.
|
||||
*/
|
||||
void free_ptrace_context(ptrace_context_t* context);
|
||||
|
||||
/*
|
||||
* Finds a symbol using ptrace.
|
||||
* Returns the containing map and information about the symbol, or
|
||||
* nullptr if one or the other is not available.
|
||||
*/
|
||||
void find_symbol_ptrace(const ptrace_context_t* context, uintptr_t addr,
|
||||
const map_info_t** out_map_info, const symbol_t** out_symbol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CORKSCREW_PTRACE_H
|
||||
62
third_party/FreeRDP/winpr/libwinpr/utils/corkscrew/symbol_table.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CORKSCREW_SYMBOL_TABLE_H
|
||||
#define _CORKSCREW_SYMBOL_TABLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
char* name;
|
||||
} symbol_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
symbol_t* symbols;
|
||||
size_t num_symbols;
|
||||
} symbol_table_t;
|
||||
|
||||
/*
|
||||
* Loads a symbol table from a given file.
|
||||
* Returns nullptr on error.
|
||||
*/
|
||||
symbol_table_t* load_symbol_table(const char* filename);
|
||||
|
||||
/*
|
||||
* Frees a symbol table.
|
||||
*/
|
||||
void free_symbol_table(symbol_table_t* table);
|
||||
|
||||
/*
|
||||
* Finds a symbol associated with an address in the symbol table.
|
||||
* Returns nullptr if not found.
|
||||
*/
|
||||
const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CORKSCREW_SYMBOL_TABLE_H
|
||||
211
third_party/FreeRDP/winpr/libwinpr/utils/debug.c
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Debugging Utils
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
#include <winpr/platform.h>
|
||||
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
|
||||
WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
|
||||
|
||||
#define __STDC_WANT_LIB_EXT1__ 1 // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
|
||||
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#if defined(USE_EXECINFO)
|
||||
#include <execinfo/debug.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_UNWIND)
|
||||
#include <unwind/debug.h>
|
||||
#endif
|
||||
|
||||
#if defined(WINPR_HAVE_CORKSCREW)
|
||||
#include <corkscrew/debug.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <io.h>
|
||||
#include <windows/debug.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/debug.h>
|
||||
|
||||
#define TAG "com.winpr.utils.debug"
|
||||
|
||||
#define LINE_LENGTH_MAX 2048
|
||||
|
||||
static const char support_msg[] = "Invalid stacktrace buffer! check if platform is supported!";
|
||||
|
||||
void winpr_backtrace_free(void* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
#if defined(USE_UNWIND)
|
||||
winpr_unwind_backtrace_free(buffer);
|
||||
#elif defined(USE_EXECINFO)
|
||||
winpr_execinfo_backtrace_free(buffer);
|
||||
#elif defined(WINPR_HAVE_CORKSCREW)
|
||||
winpr_corkscrew_backtrace_free(buffer);
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
winpr_win_backtrace_free(buffer);
|
||||
#else
|
||||
free(buffer);
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* winpr_backtrace(DWORD size)
|
||||
{
|
||||
#if defined(USE_UNWIND)
|
||||
return winpr_unwind_backtrace(size);
|
||||
#elif defined(USE_EXECINFO)
|
||||
return winpr_execinfo_backtrace(size);
|
||||
#elif defined(WINPR_HAVE_CORKSCREW)
|
||||
return winpr_corkscrew_backtrace(size);
|
||||
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
|
||||
return winpr_win_backtrace(size);
|
||||
#else
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
/* return a non nullptr buffer to allow the backtrace function family to succeed without failing
|
||||
*/
|
||||
return strndup(support_msg, sizeof(support_msg));
|
||||
#endif
|
||||
}
|
||||
|
||||
char** winpr_backtrace_symbols(void* buffer, size_t* used)
|
||||
{
|
||||
if (used)
|
||||
*used = 0;
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(USE_UNWIND)
|
||||
return winpr_unwind_backtrace_symbols(buffer, used);
|
||||
#elif defined(USE_EXECINFO)
|
||||
return winpr_execinfo_backtrace_symbols(buffer, used);
|
||||
#elif defined(WINPR_HAVE_CORKSCREW)
|
||||
return winpr_corkscrew_backtrace_symbols(buffer, used);
|
||||
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
|
||||
return winpr_win_backtrace_symbols(buffer, used);
|
||||
#else
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
|
||||
/* We return a char** on heap that is compatible with free:
|
||||
*
|
||||
* 1. We allocate sizeof(char*) + strlen + 1 bytes.
|
||||
* 2. The first sizeof(char*) bytes contain the pointer to the string following the pointer.
|
||||
* 3. The at data + sizeof(char*) contains the actual string
|
||||
*/
|
||||
size_t len = strnlen(support_msg, sizeof(support_msg));
|
||||
char* ppmsg = calloc(sizeof(char*) + len + 1, sizeof(char));
|
||||
if (!ppmsg)
|
||||
return nullptr;
|
||||
char** msgptr = (char**)ppmsg;
|
||||
char* msg = &ppmsg[sizeof(char*)];
|
||||
|
||||
*msgptr = msg;
|
||||
strncpy(msg, support_msg, len);
|
||||
*used = 1;
|
||||
return msgptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void winpr_backtrace_symbols_fd(void* buffer, int fd)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(USE_EXECINFO) && !defined(USE_UNWIND)
|
||||
winpr_execinfo_backtrace_symbols_fd(buffer, fd);
|
||||
#elif !defined(ANDROID)
|
||||
{
|
||||
size_t used = 0;
|
||||
char** lines = winpr_backtrace_symbols(buffer, &used);
|
||||
|
||||
if (!lines)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < used; i++)
|
||||
(void)_write(fd, lines[i], (unsigned)strnlen(lines[i], LINE_LENGTH_MAX));
|
||||
free((void*)lines);
|
||||
}
|
||||
#else
|
||||
WLog_FATAL(TAG, "%s", support_msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
|
||||
{
|
||||
winpr_log_backtrace_ex(WLog_Get(tag), level, size);
|
||||
}
|
||||
|
||||
void winpr_log_backtrace_ex(wLog* log, DWORD level, WINPR_ATTR_UNUSED DWORD size)
|
||||
{
|
||||
size_t used = 0;
|
||||
char** msg = nullptr;
|
||||
void* stack = winpr_backtrace(20);
|
||||
|
||||
if (!stack)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msg = winpr_backtrace_symbols(stack, &used);
|
||||
|
||||
if (msg)
|
||||
{
|
||||
for (size_t x = 0; x < used; x++)
|
||||
WLog_Print(log, level, "%" PRIuz ": %s", x, msg[x]);
|
||||
}
|
||||
free((void*)msg);
|
||||
|
||||
fail:
|
||||
winpr_backtrace_free(stack);
|
||||
}
|
||||
|
||||
char* winpr_strerror(INT32 dw, char* dmsg, size_t size)
|
||||
{
|
||||
#ifdef __STDC_LIB_EXT1__
|
||||
(void)strerror_s(dw, dmsg, size);
|
||||
#elif defined(WINPR_HAVE_STRERROR_R)
|
||||
(void)strerror_r(dw, dmsg, size);
|
||||
#else
|
||||
(void)_snprintf(dmsg, size, "%s", strerror(dw));
|
||||
#endif
|
||||
return dmsg;
|
||||
}
|
||||
98
third_party/FreeRDP/winpr/libwinpr/utils/execinfo/debug.c
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Debugging Utils
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <execinfo.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void** buffer;
|
||||
size_t max;
|
||||
size_t used;
|
||||
} t_execinfo;
|
||||
|
||||
void winpr_execinfo_backtrace_free(void* buffer)
|
||||
{
|
||||
t_execinfo* data = (t_execinfo*)buffer;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
free((void*)data->buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void* winpr_execinfo_backtrace(DWORD size)
|
||||
{
|
||||
t_execinfo* data = calloc(1, sizeof(t_execinfo));
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
data->buffer = (void**)calloc(size, sizeof(void*));
|
||||
|
||||
if (!data->buffer)
|
||||
{
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(size <= INT32_MAX);
|
||||
const int rc = backtrace(data->buffer, (int)size);
|
||||
if (rc < 0)
|
||||
{
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
data->max = size;
|
||||
data->used = (size_t)rc;
|
||||
return data;
|
||||
}
|
||||
|
||||
char** winpr_execinfo_backtrace_symbols(void* buffer, size_t* used)
|
||||
{
|
||||
t_execinfo* data = (t_execinfo*)buffer;
|
||||
if (used)
|
||||
*used = 0;
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
if (used)
|
||||
*used = data->used;
|
||||
|
||||
assert(data->used < INT32_MAX);
|
||||
return backtrace_symbols(data->buffer, (int)data->used);
|
||||
}
|
||||
|
||||
void winpr_execinfo_backtrace_symbols_fd(void* buffer, int fd)
|
||||
{
|
||||
t_execinfo* data = (t_execinfo*)buffer;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
assert(data->used <= INT32_MAX);
|
||||
backtrace_symbols_fd(data->buffer, (int)data->used, fd);
|
||||
}
|
||||
40
third_party/FreeRDP/winpr/libwinpr/utils/execinfo/debug.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Debugging helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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_DEBUG_EXECINFO_H
|
||||
#define WINPR_DEBUG_EXECINFO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
void* winpr_execinfo_backtrace(DWORD size);
|
||||
void winpr_execinfo_backtrace_free(void* buffer);
|
||||
char** winpr_execinfo_backtrace_symbols(void* buffer, size_t* used);
|
||||
void winpr_execinfo_backtrace_symbols_fd(void* buffer, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_DEBUG_EXECINFO_H */
|
||||
1390
third_party/FreeRDP/winpr/libwinpr/utils/image.c
vendored
Normal file
34
third_party/FreeRDP/winpr/libwinpr/utils/image.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Image Utils
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LIBWINPR_UTILS_IMAGE_H
|
||||
#define LIBWINPR_UTILS_IMAGE_H
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/image.h>
|
||||
|
||||
BOOL readBitmapFileHeader(wStream* s, WINPR_BITMAP_FILE_HEADER* bf);
|
||||
BOOL writeBitmapFileHeader(wStream* s, const WINPR_BITMAP_FILE_HEADER* bf);
|
||||
|
||||
BOOL readBitmapInfoHeader(wStream* s, WINPR_BITMAP_INFO_HEADER* bi, size_t* poffset);
|
||||
BOOL writeBitmapInfoHeader(wStream* s, const WINPR_BITMAP_INFO_HEADER* bi);
|
||||
|
||||
#endif /* LIBWINPR_UTILS_IMAGE_H */
|
||||
887
third_party/FreeRDP/winpr/libwinpr/utils/ini.c
vendored
Normal file
@@ -0,0 +1,887 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* .ini config file
|
||||
*
|
||||
* 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/assert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
|
||||
#include <winpr/ini.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
char* value;
|
||||
} wIniFileKey;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
size_t nKeys;
|
||||
size_t cKeys;
|
||||
wIniFileKey** keys;
|
||||
} wIniFileSection;
|
||||
|
||||
struct s_wIniFile
|
||||
{
|
||||
char* line;
|
||||
char* nextLine;
|
||||
size_t lineLength;
|
||||
char* tokctx;
|
||||
char* buffer;
|
||||
size_t buffersize;
|
||||
char* filename;
|
||||
BOOL readOnly;
|
||||
size_t nSections;
|
||||
size_t cSections;
|
||||
wIniFileSection** sections;
|
||||
};
|
||||
|
||||
static BOOL IniFile_Load_NextLine(wIniFile* ini, char* str)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
ini->nextLine = strtok_s(str, "\n", &ini->tokctx);
|
||||
|
||||
if (ini->nextLine)
|
||||
length = strlen(ini->nextLine);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (ini->nextLine[length - 1] == '\r')
|
||||
{
|
||||
ini->nextLine[length - 1] = '\0';
|
||||
length--;
|
||||
}
|
||||
|
||||
if (length < 1)
|
||||
ini->nextLine = nullptr;
|
||||
}
|
||||
|
||||
return (ini->nextLine != nullptr);
|
||||
}
|
||||
|
||||
static BOOL IniFile_BufferResize(wIniFile* ini, size_t size)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
if (size > ini->buffersize)
|
||||
{
|
||||
const size_t diff = size - ini->buffersize;
|
||||
char* tmp = realloc(ini->buffer, size);
|
||||
if (!tmp)
|
||||
return FALSE;
|
||||
|
||||
memset(&tmp[ini->buffersize], 0, diff * sizeof(char));
|
||||
ini->buffer = tmp;
|
||||
ini->buffersize = size;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL IniFile_Load_String(wIniFile* ini, const char* iniString)
|
||||
{
|
||||
size_t fileSize = 0;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!iniString)
|
||||
return FALSE;
|
||||
|
||||
ini->line = nullptr;
|
||||
ini->nextLine = nullptr;
|
||||
fileSize = strlen(iniString);
|
||||
|
||||
if (fileSize < 1)
|
||||
return FALSE;
|
||||
|
||||
if (!IniFile_BufferResize(ini, fileSize + 2))
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(ini->buffer, iniString, fileSize);
|
||||
ini->buffer[fileSize] = '\n';
|
||||
IniFile_Load_NextLine(ini, ini->buffer);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void IniFile_Close_File(FILE* fp)
|
||||
{
|
||||
if (fp)
|
||||
(void)fclose(fp);
|
||||
}
|
||||
|
||||
static FILE* IniFile_Open_File(wIniFile* ini, const char* filename)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!filename)
|
||||
return nullptr;
|
||||
|
||||
if (ini->readOnly)
|
||||
return winpr_fopen(filename, "rb");
|
||||
else
|
||||
return winpr_fopen(filename, "w+b");
|
||||
}
|
||||
|
||||
static BOOL IniFile_Load_File(wIniFile* ini, const char* filename)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
FILE* fp = IniFile_Open_File(ini, filename);
|
||||
if (!fp)
|
||||
return FALSE;
|
||||
|
||||
if (_fseeki64(fp, 0, SEEK_END) < 0)
|
||||
goto out_file;
|
||||
|
||||
{
|
||||
const INT64 fileSize = _ftelli64(fp);
|
||||
if (fileSize < 0)
|
||||
goto out_file;
|
||||
|
||||
if (_fseeki64(fp, 0, SEEK_SET) < 0)
|
||||
goto out_file;
|
||||
|
||||
ini->line = nullptr;
|
||||
ini->nextLine = nullptr;
|
||||
|
||||
if (fileSize < 1)
|
||||
goto out_file;
|
||||
|
||||
if (!IniFile_BufferResize(ini, (size_t)fileSize + 2))
|
||||
goto out_file;
|
||||
|
||||
if (fread(ini->buffer, (size_t)fileSize, 1ul, fp) != 1)
|
||||
goto out_file;
|
||||
|
||||
ini->buffer[fileSize] = '\n';
|
||||
ini->buffer[fileSize + 1] = '\0';
|
||||
}
|
||||
IniFile_Load_NextLine(ini, ini->buffer);
|
||||
rc = TRUE;
|
||||
|
||||
out_file:
|
||||
IniFile_Close_File(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
return (ini->nextLine != nullptr);
|
||||
}
|
||||
|
||||
static char* IniFile_Load_GetNextLine(wIniFile* ini)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
ini->line = ini->nextLine;
|
||||
ini->lineLength = strlen(ini->line);
|
||||
IniFile_Load_NextLine(ini, nullptr);
|
||||
return ini->line;
|
||||
}
|
||||
|
||||
static void IniFile_Key_Free(wIniFileKey* key)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
free(key->name);
|
||||
free(key->value);
|
||||
free(key);
|
||||
}
|
||||
|
||||
static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
|
||||
{
|
||||
if (!name || !value)
|
||||
return nullptr;
|
||||
|
||||
wIniFileKey* key = calloc(1, sizeof(wIniFileKey));
|
||||
|
||||
if (key)
|
||||
{
|
||||
key->name = _strdup(name);
|
||||
key->value = _strdup(value);
|
||||
|
||||
if (!key->name || !key->value)
|
||||
{
|
||||
IniFile_Key_Free(key);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void IniFile_Section_Free(wIniFileSection* section)
|
||||
{
|
||||
if (!section)
|
||||
return;
|
||||
|
||||
free(section->name);
|
||||
|
||||
for (size_t index = 0; index < section->nKeys; index++)
|
||||
{
|
||||
IniFile_Key_Free(section->keys[index]);
|
||||
}
|
||||
|
||||
free((void*)section->keys);
|
||||
free(section);
|
||||
}
|
||||
|
||||
static BOOL IniFile_SectionKeysResize(wIniFileSection* section, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(section);
|
||||
|
||||
if (section->nKeys + count >= section->cKeys)
|
||||
{
|
||||
const size_t new_size = section->cKeys + count + 1024;
|
||||
const size_t diff = new_size - section->cKeys;
|
||||
wIniFileKey** new_keys =
|
||||
(wIniFileKey**)realloc((void*)section->keys, sizeof(wIniFileKey*) * new_size);
|
||||
|
||||
if (!new_keys)
|
||||
return FALSE;
|
||||
|
||||
memset((void*)&new_keys[section->cKeys], 0, diff * sizeof(wIniFileKey*));
|
||||
section->cKeys = new_size;
|
||||
section->keys = new_keys;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static wIniFileSection* IniFile_Section_New(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
wIniFileSection* section = calloc(1, sizeof(wIniFileSection));
|
||||
|
||||
if (!section)
|
||||
goto fail;
|
||||
|
||||
section->name = _strdup(name);
|
||||
|
||||
if (!section->name)
|
||||
goto fail;
|
||||
|
||||
if (!IniFile_SectionKeysResize(section, 64))
|
||||
goto fail;
|
||||
|
||||
return section;
|
||||
|
||||
fail:
|
||||
IniFile_Section_Free(section);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
wIniFileSection* section = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
for (size_t index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
if (_stricmp(name, ini->sections[index]->name) == 0)
|
||||
{
|
||||
section = ini->sections[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
static BOOL IniFile_SectionResize(wIniFile* ini, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (ini->nSections + count >= ini->cSections)
|
||||
{
|
||||
const size_t new_size = ini->cSections + count + 1024;
|
||||
const size_t diff = new_size - ini->cSections;
|
||||
wIniFileSection** new_sect =
|
||||
(wIniFileSection**)realloc((void*)ini->sections, sizeof(wIniFileSection*) * new_size);
|
||||
|
||||
if (!new_sect)
|
||||
return FALSE;
|
||||
|
||||
memset((void*)&new_sect[ini->cSections], 0, diff * sizeof(wIniFileSection*));
|
||||
ini->cSections = new_size;
|
||||
ini->sections = new_sect;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static wIniFileSection* IniFile_AddToSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
wIniFileSection* section = IniFile_GetSection(ini, name);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
if (!IniFile_SectionResize(ini, 1))
|
||||
return nullptr;
|
||||
|
||||
section = IniFile_Section_New(name);
|
||||
if (!section)
|
||||
return nullptr;
|
||||
ini->sections[ini->nSections++] = section;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
static wIniFileKey* IniFile_GetKey(wIniFileSection* section, const char* name)
|
||||
{
|
||||
wIniFileKey* key = nullptr;
|
||||
|
||||
WINPR_ASSERT(section);
|
||||
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
for (size_t index = 0; index < section->nKeys; index++)
|
||||
{
|
||||
if (_stricmp(name, section->keys[index]->name) == 0)
|
||||
{
|
||||
key = section->keys[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static wIniFileKey* IniFile_AddKey(wIniFileSection* section, const char* name, const char* value)
|
||||
{
|
||||
WINPR_ASSERT(section);
|
||||
|
||||
if (!name || !value)
|
||||
return nullptr;
|
||||
|
||||
wIniFileKey* key = IniFile_GetKey(section, name);
|
||||
|
||||
if (!key)
|
||||
{
|
||||
if (!IniFile_SectionKeysResize(section, 1))
|
||||
return nullptr;
|
||||
|
||||
key = IniFile_Key_New(name, value);
|
||||
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
section->keys[section->nKeys++] = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(key->value);
|
||||
key->value = _strdup(value);
|
||||
|
||||
if (!key->value)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static int IniFile_Load(wIniFile* ini)
|
||||
{
|
||||
char* name = nullptr;
|
||||
char* value = nullptr;
|
||||
char* separator = nullptr;
|
||||
char* beg = nullptr;
|
||||
char* end = nullptr;
|
||||
wIniFileSection* section = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
while (IniFile_Load_HasNextLine(ini))
|
||||
{
|
||||
char* line = IniFile_Load_GetNextLine(ini);
|
||||
|
||||
if (line[0] == ';')
|
||||
continue;
|
||||
|
||||
if (line[0] == '[')
|
||||
{
|
||||
beg = &line[1];
|
||||
end = strchr(line, ']');
|
||||
|
||||
if (!end)
|
||||
return -1;
|
||||
|
||||
*end = '\0';
|
||||
IniFile_AddToSection(ini, beg);
|
||||
section = ini->sections[ini->nSections - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
separator = strchr(line, '=');
|
||||
|
||||
if (separator == nullptr)
|
||||
return -1;
|
||||
|
||||
end = separator;
|
||||
|
||||
while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
|
||||
end--;
|
||||
|
||||
*end = '\0';
|
||||
name = line;
|
||||
beg = separator + 1;
|
||||
|
||||
while (*beg && ((*beg == ' ') || (*beg == '\t')))
|
||||
beg++;
|
||||
|
||||
if (*beg == '"')
|
||||
beg++;
|
||||
|
||||
end = &line[ini->lineLength];
|
||||
|
||||
while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
|
||||
end--;
|
||||
|
||||
if (end[-1] == '"')
|
||||
end[-1] = '\0';
|
||||
|
||||
value = beg;
|
||||
|
||||
if (!IniFile_AddKey(section, name, value))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL IniFile_SetFilename(wIniFile* ini, const char* name)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
free(ini->filename);
|
||||
ini->filename = nullptr;
|
||||
|
||||
if (!name)
|
||||
return TRUE;
|
||||
ini->filename = _strdup(name);
|
||||
return ini->filename != nullptr;
|
||||
}
|
||||
|
||||
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
|
||||
{
|
||||
BOOL status = 0;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
ini->readOnly = TRUE;
|
||||
status = IniFile_Load_String(ini, buffer);
|
||||
|
||||
if (!status)
|
||||
return -1;
|
||||
|
||||
return IniFile_Load(ini);
|
||||
}
|
||||
|
||||
int IniFile_ReadFile(wIniFile* ini, const char* filename)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
ini->readOnly = TRUE;
|
||||
if (!IniFile_SetFilename(ini, filename))
|
||||
return -1;
|
||||
if (!ini->filename)
|
||||
return -1;
|
||||
|
||||
if (!IniFile_Load_File(ini, filename))
|
||||
return -1;
|
||||
|
||||
return IniFile_Load(ini);
|
||||
}
|
||||
|
||||
char** IniFile_GetSectionNames(wIniFile* ini, size_t* count)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!count)
|
||||
return nullptr;
|
||||
|
||||
if (ini->nSections > INT_MAX)
|
||||
return nullptr;
|
||||
|
||||
size_t length = (sizeof(char*) * ini->nSections) + sizeof(char);
|
||||
|
||||
for (size_t index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
wIniFileSection* section = ini->sections[index];
|
||||
const size_t nameLength = strlen(section->name);
|
||||
length += (nameLength + 1);
|
||||
}
|
||||
|
||||
char** sectionNames = (char**)calloc(length, sizeof(char*));
|
||||
|
||||
if (!sectionNames)
|
||||
return nullptr;
|
||||
|
||||
char* p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
|
||||
|
||||
for (size_t index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
sectionNames[index] = p;
|
||||
wIniFileSection* section = ini->sections[index];
|
||||
const size_t nameLength = strlen(section->name);
|
||||
CopyMemory(p, section->name, nameLength + 1);
|
||||
p += (nameLength + 1);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
*count = ini->nSections;
|
||||
return sectionNames;
|
||||
}
|
||||
|
||||
char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, size_t* count)
|
||||
{
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
if (!section || !count)
|
||||
return nullptr;
|
||||
|
||||
wIniFileSection* pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return nullptr;
|
||||
|
||||
if (pSection->nKeys > INT_MAX)
|
||||
return nullptr;
|
||||
|
||||
size_t length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
|
||||
|
||||
for (size_t index = 0; index < pSection->nKeys; index++)
|
||||
{
|
||||
wIniFileKey* pKey = pSection->keys[index];
|
||||
const size_t nameLength = strlen(pKey->name);
|
||||
length += (nameLength + 1);
|
||||
}
|
||||
|
||||
char** keyNames = (char**)calloc(length, sizeof(char*));
|
||||
|
||||
if (!keyNames)
|
||||
return nullptr;
|
||||
|
||||
char* p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
|
||||
|
||||
for (size_t index = 0; index < pSection->nKeys; index++)
|
||||
{
|
||||
keyNames[index] = p;
|
||||
wIniFileKey* pKey = pSection->keys[index];
|
||||
const size_t nameLength = strlen(pKey->name);
|
||||
CopyMemory(p, pKey->name, nameLength + 1);
|
||||
p += (nameLength + 1);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
*count = pSection->nKeys;
|
||||
return keyNames;
|
||||
}
|
||||
|
||||
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
|
||||
{
|
||||
const char* value = nullptr;
|
||||
wIniFileKey* pKey = nullptr;
|
||||
wIniFileSection* pSection = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return nullptr;
|
||||
|
||||
pKey = IniFile_GetKey(pSection, key);
|
||||
|
||||
if (!pKey)
|
||||
return nullptr;
|
||||
|
||||
value = (const char*)pKey->value;
|
||||
return value;
|
||||
}
|
||||
|
||||
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
|
||||
{
|
||||
int err = 0;
|
||||
long value = 0;
|
||||
wIniFileKey* pKey = nullptr;
|
||||
wIniFileSection* pSection = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return 0;
|
||||
|
||||
pKey = IniFile_GetKey(pSection, key);
|
||||
|
||||
if (!pKey)
|
||||
return 0;
|
||||
|
||||
err = errno;
|
||||
errno = 0;
|
||||
value = strtol(pKey->value, nullptr, 0);
|
||||
if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
|
||||
{
|
||||
errno = err;
|
||||
return 0;
|
||||
}
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
|
||||
const char* value)
|
||||
{
|
||||
wIniFileKey* pKey = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
wIniFileSection* pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
pSection = IniFile_AddToSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return -1;
|
||||
|
||||
pKey = IniFile_AddKey(pSection, key, value);
|
||||
|
||||
if (!pKey)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
|
||||
{
|
||||
char strVal[128] = WINPR_C_ARRAY_INIT;
|
||||
wIniFileKey* pKey = nullptr;
|
||||
wIniFileSection* pSection = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
(void)sprintf_s(strVal, sizeof(strVal), "%d", value);
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
pSection = IniFile_AddToSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return -1;
|
||||
|
||||
pKey = IniFile_AddKey(pSection, key, strVal);
|
||||
|
||||
if (!pKey)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* IniFile_WriteBuffer(wIniFile* ini)
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t size = 0;
|
||||
char* buffer = nullptr;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
for (size_t i = 0; i < ini->nSections; i++)
|
||||
{
|
||||
wIniFileSection* section = ini->sections[i];
|
||||
size += (strlen(section->name) + 3);
|
||||
|
||||
for (size_t j = 0; j < section->nKeys; j++)
|
||||
{
|
||||
wIniFileKey* key = section->keys[j];
|
||||
size += (strlen(key->name) + strlen(key->value) + 2);
|
||||
}
|
||||
|
||||
size += 1;
|
||||
}
|
||||
|
||||
size += 1;
|
||||
buffer = calloc(size + 1, sizeof(char));
|
||||
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
|
||||
offset = 0;
|
||||
|
||||
for (size_t i = 0; i < ini->nSections; i++)
|
||||
{
|
||||
wIniFileSection* section = ini->sections[i];
|
||||
(void)sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
|
||||
offset += (strlen(section->name) + 3);
|
||||
|
||||
for (size_t j = 0; j < section->nKeys; j++)
|
||||
{
|
||||
wIniFileKey* key = section->keys[j];
|
||||
(void)sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
|
||||
offset += (strlen(key->name) + strlen(key->value) + 2);
|
||||
}
|
||||
|
||||
(void)sprintf_s(&buffer[offset], size - offset, "\n");
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int IniFile_WriteFile(wIniFile* ini, const char* filename)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
WINPR_ASSERT(ini);
|
||||
|
||||
char* buffer = IniFile_WriteBuffer(ini);
|
||||
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
const size_t length = strlen(buffer);
|
||||
ini->readOnly = FALSE;
|
||||
|
||||
if (!filename)
|
||||
filename = ini->filename;
|
||||
|
||||
FILE* fp = IniFile_Open_File(ini, filename);
|
||||
if (!fp)
|
||||
goto fail;
|
||||
|
||||
if (fwrite((void*)buffer, length, 1, fp) != 1)
|
||||
goto fail;
|
||||
|
||||
ret = 1;
|
||||
|
||||
fail:
|
||||
IniFile_Close_File(fp);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void IniFile_Free(wIniFile* ini)
|
||||
{
|
||||
if (!ini)
|
||||
return;
|
||||
|
||||
IniFile_SetFilename(ini, nullptr);
|
||||
|
||||
for (size_t index = 0; index < ini->nSections; index++)
|
||||
IniFile_Section_Free(ini->sections[index]);
|
||||
|
||||
free((void*)ini->sections);
|
||||
free(ini->buffer);
|
||||
free(ini);
|
||||
}
|
||||
|
||||
wIniFile* IniFile_New(void)
|
||||
{
|
||||
wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
|
||||
|
||||
if (!ini)
|
||||
goto fail;
|
||||
|
||||
if (!IniFile_SectionResize(ini, 64))
|
||||
goto fail;
|
||||
|
||||
return ini;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
IniFile_Free(ini);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wIniFile* IniFile_Clone(const wIniFile* ini)
|
||||
{
|
||||
if (!ini)
|
||||
return nullptr;
|
||||
|
||||
wIniFile* copy = IniFile_New();
|
||||
if (!copy)
|
||||
goto fail;
|
||||
|
||||
copy->lineLength = ini->lineLength;
|
||||
if (!IniFile_SetFilename(copy, ini->filename))
|
||||
goto fail;
|
||||
|
||||
if (ini->buffersize > 0)
|
||||
{
|
||||
if (!IniFile_BufferResize(copy, ini->buffersize))
|
||||
goto fail;
|
||||
memcpy(copy->buffer, ini->buffer, copy->buffersize);
|
||||
}
|
||||
|
||||
copy->readOnly = ini->readOnly;
|
||||
|
||||
for (size_t x = 0; x < ini->nSections; x++)
|
||||
{
|
||||
const wIniFileSection* cur = ini->sections[x];
|
||||
if (!cur)
|
||||
goto fail;
|
||||
|
||||
wIniFileSection* scopy = IniFile_AddToSection(copy, cur->name);
|
||||
if (!scopy)
|
||||
goto fail;
|
||||
|
||||
for (size_t y = 0; y < cur->nKeys; y++)
|
||||
{
|
||||
const wIniFileKey* key = cur->keys[y];
|
||||
if (!key)
|
||||
goto fail;
|
||||
|
||||
IniFile_AddKey(scopy, key->name, key->value);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
|
||||
fail:
|
||||
IniFile_Free(copy);
|
||||
return nullptr;
|
||||
}
|
||||
304
third_party/FreeRDP/winpr/libwinpr/utils/json/c-json.c
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* JSON parser wrapper
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/json.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#if !defined(WITH_CJSON)
|
||||
#error "This file must only be compiled when cJSON is enabled"
|
||||
#endif
|
||||
#include <cjson/cJSON.h>
|
||||
|
||||
#if defined(WITH_CJSON)
|
||||
#if CJSON_VERSION_MAJOR == 1
|
||||
#if (CJSON_VERSION_MINOR < 7) || ((CJSON_VERSION_MINOR == 7) && (CJSON_VERSION_PATCH < 13))
|
||||
#define USE_CJSON_COMPAT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_CJSON_COMPAT)
|
||||
static double cJSON_GetNumberValue(const cJSON* prop)
|
||||
{
|
||||
#ifndef NAN
|
||||
#ifdef _WIN32
|
||||
#define NAN sqrt(-1.0)
|
||||
#define COMPAT_NAN_UNDEF
|
||||
#else
|
||||
#define NAN 0.0 / 0.0
|
||||
#define COMPAT_NAN_UNDEF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!cJSON_IsNumber(prop))
|
||||
return NAN;
|
||||
char* val = cJSON_GetStringValue(prop);
|
||||
if (!val)
|
||||
return NAN;
|
||||
|
||||
errno = 0;
|
||||
char* endptr = nullptr;
|
||||
double dval = strtod(val, &endptr);
|
||||
if (val == endptr)
|
||||
return NAN;
|
||||
if (endptr != nullptr)
|
||||
return NAN;
|
||||
if (errno != 0)
|
||||
return NAN;
|
||||
return dval;
|
||||
|
||||
#ifdef COMPAT_NAN_UNDEF
|
||||
#undef NAN
|
||||
#endif
|
||||
}
|
||||
|
||||
static cJSON* cJSON_ParseWithLength(const char* value, size_t buffer_length)
|
||||
{
|
||||
// Check for string '\0' termination.
|
||||
const size_t slen = strnlen(value, buffer_length);
|
||||
if (slen >= buffer_length)
|
||||
{
|
||||
if (value[buffer_length] != '\0')
|
||||
return nullptr;
|
||||
}
|
||||
return cJSON_Parse(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
int WINPR_JSON_version(char* buffer, size_t len)
|
||||
{
|
||||
return _snprintf(buffer, len, "cJSON %s", cJSON_Version());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_Parse(const char* value)
|
||||
{
|
||||
return cJSON_Parse(value);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length)
|
||||
{
|
||||
return cJSON_ParseWithLength(value, buffer_length);
|
||||
}
|
||||
|
||||
void WINPR_JSON_Delete(WINPR_JSON* item)
|
||||
{
|
||||
cJSON_Delete((cJSON*)item);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index)
|
||||
{
|
||||
WINPR_ASSERT(index <= INT_MAX);
|
||||
return cJSON_GetArrayItem((const cJSON*)array, (INT)index);
|
||||
}
|
||||
|
||||
size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array)
|
||||
{
|
||||
const int rc = cJSON_GetArraySize((const cJSON*)array);
|
||||
if (rc <= 0)
|
||||
return 0;
|
||||
return (size_t)rc;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return cJSON_GetObjectItem((const cJSON*)object, string);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return cJSON_GetObjectItemCaseSensitive((const cJSON*)object, string);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return cJSON_HasObjectItem((const cJSON*)object, string);
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetErrorPtr(void)
|
||||
{
|
||||
return cJSON_GetErrorPtr();
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetStringValue(WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_GetStringValue((cJSON*)item);
|
||||
}
|
||||
|
||||
double WINPR_JSON_GetNumberValue(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_GetNumberValue((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsInvalid((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsFalse(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsFalse((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsTrue(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsTrue((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsBool(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsBool((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNull(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsNull((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNumber(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsNumber((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsString(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsString((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsArray(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsArray((const cJSON*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsObject(const WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_IsObject((const cJSON*)item);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNull(void)
|
||||
{
|
||||
return cJSON_CreateNull();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateTrue(void)
|
||||
{
|
||||
return cJSON_CreateTrue();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateFalse(void)
|
||||
{
|
||||
return cJSON_CreateFalse();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean)
|
||||
{
|
||||
return cJSON_CreateBool(boolean);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNumber(double num)
|
||||
{
|
||||
return cJSON_CreateNumber(num);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateString(const char* string)
|
||||
{
|
||||
return cJSON_CreateString(string);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateArray(void)
|
||||
{
|
||||
return cJSON_CreateArray();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateObject(void)
|
||||
{
|
||||
return cJSON_CreateObject();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
return cJSON_AddNullToObject((cJSON*)object, name);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
return cJSON_AddTrueToObject((cJSON*)object, name);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
return cJSON_AddFalseToObject((cJSON*)object, name);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* object, const char* name, BOOL boolean)
|
||||
{
|
||||
return cJSON_AddBoolToObject((cJSON*)object, name, boolean);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* object, const char* name, double number)
|
||||
{
|
||||
return cJSON_AddNumberToObject((cJSON*)object, name, number);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddIntegerToObject(WINPR_JSON* object, const char* name, int64_t number)
|
||||
{
|
||||
char str[64] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(str, sizeof(str), "%" PRId64, number);
|
||||
return cJSON_AddRawToObject((cJSON*)object, name, str);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* object, const char* name, const char* string)
|
||||
{
|
||||
return cJSON_AddStringToObject((cJSON*)object, name, string);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
return cJSON_AddObjectToObject((cJSON*)object, name);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_AddItemToArray(WINPR_JSON* array, WINPR_JSON* item)
|
||||
{
|
||||
#if defined(USE_CJSON_COMPAT)
|
||||
if ((array == nullptr) || (item == nullptr))
|
||||
return FALSE;
|
||||
cJSON_AddItemToArray((cJSON*)array, (cJSON*)item);
|
||||
return TRUE;
|
||||
#else
|
||||
return cJSON_AddItemToArray((cJSON*)array, (cJSON*)item);
|
||||
#endif
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
return cJSON_AddArrayToObject((cJSON*)object, name);
|
||||
}
|
||||
|
||||
char* WINPR_JSON_Print(WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_Print((const cJSON*)item);
|
||||
}
|
||||
|
||||
char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item)
|
||||
{
|
||||
return cJSON_PrintUnformatted((const cJSON*)item);
|
||||
}
|
||||
355
third_party/FreeRDP/winpr/libwinpr/utils/json/jansson.c
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* JSON parser wrapper
|
||||
*
|
||||
* Copyright 2025 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2025 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/file.h>
|
||||
#include <winpr/json.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#if !defined(WITH_JANSSON)
|
||||
#error "This file must only be compiled if jansson library is linked in"
|
||||
#endif
|
||||
#include <jansson.h>
|
||||
|
||||
#if !defined(JANSSON_VERSION_HEX) || (JANSSON_VERSION_HEX < 0x020d00)
|
||||
#error "The library detected is too old, need >= 2.13.0"
|
||||
#endif
|
||||
|
||||
static WINPR_TLS char lasterror[256] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
#if defined(WITH_DEBUG_JANSSON)
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("jansson")
|
||||
|
||||
#define ccast(json) ccast_((json), __func__)
|
||||
static const json_t* ccast_(const WINPR_JSON* json, const char* fkt)
|
||||
{
|
||||
const json_t* jansson = (const json_t*)json;
|
||||
if (!jansson)
|
||||
WLog_DBG(TAG, "%s: nullptr", fkt);
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "%s: %" PRIuz, fkt, jansson->refcount);
|
||||
}
|
||||
return jansson;
|
||||
}
|
||||
|
||||
#define cast(json) cast_((json), __func__)
|
||||
static json_t* cast_(WINPR_JSON* json, const char* fkt)
|
||||
{
|
||||
json_t* jansson = (json_t*)json;
|
||||
if (!jansson)
|
||||
WLog_DBG(TAG, "%s: nullptr", fkt);
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "%s: %" PRIuz, fkt, jansson->refcount);
|
||||
}
|
||||
return jansson;
|
||||
}
|
||||
|
||||
#define revcast(json) revcast_((json), __func__)
|
||||
static WINPR_JSON* revcast_(json_t* json, const char* fkt)
|
||||
{
|
||||
json_t* jansson = (json_t*)json;
|
||||
if (!jansson)
|
||||
WLog_DBG(TAG, "%s: nullptr", fkt);
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "%s: %" PRIuz, fkt, jansson->refcount);
|
||||
}
|
||||
return jansson;
|
||||
}
|
||||
#else
|
||||
static inline const json_t* ccast(const WINPR_JSON* json)
|
||||
{
|
||||
return WINPR_CXX_COMPAT_CAST(const json_t*, json);
|
||||
}
|
||||
|
||||
static inline json_t* cast(WINPR_JSON* json)
|
||||
{
|
||||
return WINPR_CXX_COMPAT_CAST(json_t*, json);
|
||||
}
|
||||
|
||||
static inline WINPR_JSON* revcast(json_t* json)
|
||||
{
|
||||
return WINPR_CXX_COMPAT_CAST(WINPR_JSON*, json);
|
||||
}
|
||||
#endif
|
||||
|
||||
int WINPR_JSON_version(char* buffer, size_t len)
|
||||
{
|
||||
return _snprintf(buffer, len, "jansson %s", jansson_version_str());
|
||||
}
|
||||
|
||||
static WINPR_JSON* updateError(WINPR_JSON* json, const json_error_t* error)
|
||||
{
|
||||
lasterror[0] = '\0';
|
||||
if (!json)
|
||||
(void)_snprintf(lasterror, sizeof(lasterror), "[%d:%d:%d] %s [%s]", error->line,
|
||||
error->column, error->position, error->text, error->source);
|
||||
return json;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_Parse(const char* value)
|
||||
{
|
||||
json_error_t error = WINPR_C_ARRAY_INIT;
|
||||
WINPR_JSON* json = revcast(json_loads(value, JSON_DECODE_ANY, &error));
|
||||
return updateError(json, &error);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length)
|
||||
{
|
||||
if (!value || (buffer_length == 0))
|
||||
return nullptr;
|
||||
|
||||
json_error_t error = WINPR_C_ARRAY_INIT;
|
||||
const size_t slen = strnlen(value, buffer_length);
|
||||
WINPR_JSON* json = revcast(json_loadb(value, slen, JSON_DECODE_ANY, &error));
|
||||
return updateError(json, &error);
|
||||
}
|
||||
|
||||
void WINPR_JSON_Delete(WINPR_JSON* item)
|
||||
{
|
||||
json_delete(cast(item));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index)
|
||||
{
|
||||
return revcast(json_array_get(ccast(array), index));
|
||||
}
|
||||
|
||||
size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array)
|
||||
{
|
||||
return json_array_size(ccast(array));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
json_t* json = cast(WINPR_CAST_CONST_PTR_AWAY(object, WINPR_JSON*));
|
||||
void* it = json_object_iter(json);
|
||||
while (it)
|
||||
{
|
||||
const char* name = json_object_iter_key(it);
|
||||
if (_stricmp(name, string) == 0)
|
||||
return revcast(json_object_iter_value(it));
|
||||
it = json_object_iter_next(json, it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return revcast(json_object_get(ccast(object), string));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return json_object_get(ccast(object), string) != nullptr;
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetErrorPtr(void)
|
||||
{
|
||||
return lasterror;
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetStringValue(WINPR_JSON* item)
|
||||
{
|
||||
return json_string_value(cast(item));
|
||||
}
|
||||
|
||||
double WINPR_JSON_GetNumberValue(const WINPR_JSON* item)
|
||||
{
|
||||
return json_number_value(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* item)
|
||||
{
|
||||
const json_t* jitem = ccast(item);
|
||||
if (WINPR_JSON_IsArray(jitem))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsObject(jitem))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsNull(jitem))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsNumber(jitem))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsBool(jitem))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsString(jitem))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsFalse(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_false(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsTrue(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_true(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsBool(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_boolean(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNull(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_null(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNumber(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_number(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsString(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_string(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsArray(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_array(ccast(item));
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsObject(const WINPR_JSON* item)
|
||||
{
|
||||
return json_is_object(ccast(item));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNull(void)
|
||||
{
|
||||
return revcast(json_null());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateTrue(void)
|
||||
{
|
||||
return revcast(json_true());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateFalse(void)
|
||||
{
|
||||
return revcast(json_false());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean)
|
||||
{
|
||||
return revcast(json_boolean(boolean));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNumber(double num)
|
||||
{
|
||||
return revcast(json_real(num));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateString(const char* string)
|
||||
{
|
||||
return revcast(json_string(string));
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateArray(void)
|
||||
{
|
||||
return revcast(json_array());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateObject(void)
|
||||
{
|
||||
return revcast(json_object());
|
||||
}
|
||||
|
||||
static WINPR_JSON* add_to_object(WINPR_JSON* object, const char* name, json_t* obj)
|
||||
{
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
const int rc = json_object_set_new(cast(object), name, obj);
|
||||
if (rc != 0)
|
||||
return nullptr;
|
||||
return revcast(obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
json_t* obj = json_null();
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
json_t* obj = json_true();
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
json_t* obj = json_false();
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* object, const char* name, BOOL boolean)
|
||||
{
|
||||
json_t* obj = json_boolean(boolean);
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* object, const char* name, double number)
|
||||
{
|
||||
json_t* obj = json_real(number);
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddIntegerToObject(WINPR_JSON* object, const char* name, int64_t number)
|
||||
{
|
||||
json_t* obj = json_integer(number);
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* object, const char* name, const char* string)
|
||||
{
|
||||
json_t* obj = json_string(string);
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
json_t* obj = json_object();
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_AddItemToArray(WINPR_JSON* array, WINPR_JSON* item)
|
||||
{
|
||||
return json_array_append_new(cast(array), item) == 0;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
json_t* obj = json_array();
|
||||
return add_to_object(object, name, obj);
|
||||
}
|
||||
|
||||
char* WINPR_JSON_Print(WINPR_JSON* item)
|
||||
{
|
||||
return json_dumps(cast(item), JSON_INDENT(2) | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
|
||||
}
|
||||
|
||||
char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item)
|
||||
{
|
||||
return json_dumps(cast(item), JSON_COMPACT | JSON_ENSURE_ASCII | JSON_SORT_KEYS);
|
||||
}
|
||||
343
third_party/FreeRDP/winpr/libwinpr/utils/json/json-c.c
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* JSON parser wrapper
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/json.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#if !defined(WITH_JSONC)
|
||||
#error "This file must only be compiled when json-c is enabled"
|
||||
#endif
|
||||
#include <json.h>
|
||||
|
||||
#if JSON_C_MAJOR_VERSION == 0
|
||||
#if JSON_C_MINOR_VERSION < 14
|
||||
static struct json_object* json_object_new_null(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int WINPR_JSON_version(char* buffer, size_t len)
|
||||
{
|
||||
return _snprintf(buffer, len, "json-c %s", json_c_version());
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_Parse(const char* value)
|
||||
{
|
||||
return json_tokener_parse(value);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length)
|
||||
{
|
||||
WINPR_ASSERT(buffer_length <= INT_MAX);
|
||||
json_tokener* tok = json_tokener_new();
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
json_object* obj = json_tokener_parse_ex(tok, value, (int)buffer_length);
|
||||
json_tokener_free(tok);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void WINPR_JSON_Delete(WINPR_JSON* item)
|
||||
{
|
||||
json_object_put((json_object*)item);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index)
|
||||
{
|
||||
return json_object_array_get_idx((const json_object*)array, index);
|
||||
}
|
||||
|
||||
size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array)
|
||||
{
|
||||
return json_object_array_length((const json_object*)array);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
struct json_object_iterator it = json_object_iter_begin((const json_object*)object);
|
||||
struct json_object_iterator itEnd = json_object_iter_end((const json_object*)object);
|
||||
while (!json_object_iter_equal(&it, &itEnd))
|
||||
{
|
||||
const char* key = json_object_iter_peek_name(&it);
|
||||
if (_stricmp(key, string) == 0)
|
||||
{
|
||||
return json_object_iter_peek_value(&it);
|
||||
}
|
||||
json_object_iter_next(&it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return json_object_object_get((const json_object*)object, string);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
return json_object_object_get_ex((const json_object*)object, string, nullptr);
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetErrorPtr(void)
|
||||
{
|
||||
return json_util_get_last_err();
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetStringValue(WINPR_JSON* item)
|
||||
{
|
||||
return json_object_get_string((json_object*)item);
|
||||
}
|
||||
|
||||
double WINPR_JSON_GetNumberValue(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_get_double((const json_object*)item);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* item)
|
||||
{
|
||||
if (WINPR_JSON_IsArray(item))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsObject(item))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsNull(item))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsNumber(item))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsBool(item))
|
||||
return FALSE;
|
||||
if (WINPR_JSON_IsString(item))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsFalse(const WINPR_JSON* item)
|
||||
{
|
||||
if (!json_object_is_type((const json_object*)item, json_type_boolean))
|
||||
return FALSE;
|
||||
json_bool val = json_object_get_boolean((const json_object*)item);
|
||||
return val == 0;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsTrue(const WINPR_JSON* item)
|
||||
{
|
||||
if (!json_object_is_type((const json_object*)item, json_type_boolean))
|
||||
return FALSE;
|
||||
json_bool val = json_object_get_boolean((const json_object*)item);
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsBool(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_boolean);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNull(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_null);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNumber(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_int) ||
|
||||
json_object_is_type((const json_object*)item, json_type_double);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsString(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_string);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsArray(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_array);
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsObject(const WINPR_JSON* item)
|
||||
{
|
||||
return json_object_is_type((const json_object*)item, json_type_object);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNull(void)
|
||||
{
|
||||
return json_object_new_null();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateTrue(void)
|
||||
{
|
||||
return json_object_new_boolean(TRUE);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateFalse(void)
|
||||
{
|
||||
return json_object_new_boolean(FALSE);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean)
|
||||
{
|
||||
return json_object_new_boolean(boolean);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNumber(double num)
|
||||
{
|
||||
return json_object_new_double(num);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateString(const char* string)
|
||||
{
|
||||
return json_object_new_string(string);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateArray(void)
|
||||
{
|
||||
return json_object_new_array();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateObject(void)
|
||||
{
|
||||
return json_object_new_object();
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
struct json_object* obj = json_object_new_null();
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
struct json_object* obj = json_object_new_boolean(TRUE);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
struct json_object* obj = json_object_new_boolean(FALSE);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* object, const char* name, BOOL boolean)
|
||||
{
|
||||
struct json_object* obj = json_object_new_boolean(boolean);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* object, const char* name, double number)
|
||||
{
|
||||
struct json_object* obj = json_object_new_double(number);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddIntegerToObject(WINPR_JSON* object, const char* name, int64_t number)
|
||||
{
|
||||
struct json_object* obj = json_object_new_int64(number);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* object, const char* name, const char* string)
|
||||
{
|
||||
struct json_object* obj = json_object_new_string(string);
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
struct json_object* obj = json_object_new_object();
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_AddItemToArray(WINPR_JSON* array, WINPR_JSON* item)
|
||||
{
|
||||
const int rc = json_object_array_add((json_object*)array, (json_object*)item);
|
||||
if (rc != 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
struct json_object* obj = json_object_new_array();
|
||||
if (json_object_object_add((json_object*)object, name, obj) != 0)
|
||||
{
|
||||
json_object_put(obj);
|
||||
return nullptr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
char* WINPR_JSON_Print(WINPR_JSON* item)
|
||||
{
|
||||
const char* str = json_object_to_json_string_ext((json_object*)item, JSON_C_TO_STRING_PRETTY);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return _strdup(str);
|
||||
}
|
||||
|
||||
char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item)
|
||||
{
|
||||
const char* str = json_object_to_json_string_ext((json_object*)item, JSON_C_TO_STRING_PLAIN);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
return _strdup(str);
|
||||
}
|
||||
275
third_party/FreeRDP/winpr/libwinpr/utils/json/json-stub.c
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* JSON parser wrapper
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/json.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
int WINPR_JSON_version(char* buffer, size_t len)
|
||||
{
|
||||
(void)_snprintf(buffer, len, "JSON support not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_Parse(const char* value)
|
||||
{
|
||||
WINPR_UNUSED(value);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseWithLength(const char* value, size_t buffer_length)
|
||||
{
|
||||
WINPR_UNUSED(value);
|
||||
WINPR_UNUSED(buffer_length);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void WINPR_JSON_Delete(WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetArrayItem(const WINPR_JSON* array, size_t index)
|
||||
{
|
||||
WINPR_UNUSED(array);
|
||||
WINPR_UNUSED(index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t WINPR_JSON_GetArraySize(const WINPR_JSON* array)
|
||||
{
|
||||
WINPR_UNUSED(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(string);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(string);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON* object, const char* string)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(string);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetErrorPtr(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* WINPR_JSON_GetStringValue(WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
double WINPR_JSON_GetNumberValue(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return nan("");
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsInvalid(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsFalse(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsTrue(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsBool(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNull(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsNumber(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsString(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsArray(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_IsObject(const WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNull(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateTrue(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateFalse(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateBool(BOOL boolean)
|
||||
{
|
||||
WINPR_UNUSED(boolean);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateNumber(double num)
|
||||
{
|
||||
WINPR_UNUSED(num);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateString(const char* string)
|
||||
{
|
||||
WINPR_UNUSED(string);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateArray(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_CreateObject(void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNullToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddTrueToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddFalseToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddBoolToObject(WINPR_JSON* object, const char* name, BOOL boolean)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
WINPR_UNUSED(boolean);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddNumberToObject(WINPR_JSON* object, const char* name, double number)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
WINPR_UNUSED(number);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddStringToObject(WINPR_JSON* object, const char* name, const char* string)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
WINPR_UNUSED(string);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddObjectToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOL WINPR_JSON_AddItemToArray(WINPR_JSON* array, WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(array);
|
||||
WINPR_UNUSED(item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_AddArrayToObject(WINPR_JSON* object, const char* name)
|
||||
{
|
||||
WINPR_UNUSED(object);
|
||||
WINPR_UNUSED(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* WINPR_JSON_Print(WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* WINPR_JSON_PrintUnformatted(WINPR_JSON* item)
|
||||
{
|
||||
WINPR_UNUSED(item);
|
||||
return nullptr;
|
||||
}
|
||||
63
third_party/FreeRDP/winpr/libwinpr/utils/json/json.c
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* JSON parser wrapper
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/json.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseFromFile(const char* filename)
|
||||
{
|
||||
FILE* fp = winpr_fopen(filename, "r");
|
||||
if (!fp)
|
||||
return nullptr;
|
||||
WINPR_JSON* json = WINPR_JSON_ParseFromFileFP(fp);
|
||||
(void)fclose(fp);
|
||||
return json;
|
||||
}
|
||||
|
||||
WINPR_JSON* WINPR_JSON_ParseFromFileFP(FILE* fp)
|
||||
{
|
||||
if (!fp)
|
||||
return nullptr;
|
||||
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
return nullptr;
|
||||
|
||||
const INT64 size = _ftelli64(fp);
|
||||
if (size < 0)
|
||||
return nullptr;
|
||||
|
||||
if (fseek(fp, 0, SEEK_SET) != 0)
|
||||
return nullptr;
|
||||
|
||||
const size_t usize = WINPR_ASSERTING_INT_CAST(size_t, size);
|
||||
char* str = calloc(usize + 1, sizeof(char));
|
||||
if (!str)
|
||||
return nullptr;
|
||||
|
||||
WINPR_JSON* json = nullptr;
|
||||
const size_t s = fread(str, sizeof(char), usize, fp);
|
||||
if (s == usize)
|
||||
json = WINPR_JSON_ParseWithLength(str, usize);
|
||||
free(str);
|
||||
return json;
|
||||
}
|
||||
182
third_party/FreeRDP/winpr/libwinpr/utils/ntlm.c
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Utils
|
||||
*
|
||||
* 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/ntlm.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
/**
|
||||
* Define NTOWFv1(Password, User, Domain) as
|
||||
* MD4(UNICODE(Password))
|
||||
* EndDefine
|
||||
*/
|
||||
|
||||
BOOL NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash)
|
||||
{
|
||||
if (!Password || !NtHash)
|
||||
return FALSE;
|
||||
|
||||
if (!winpr_Digest(WINPR_MD_MD4, (BYTE*)Password, (size_t)PasswordLength, NtHash,
|
||||
WINPR_MD4_DIGEST_LENGTH))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash)
|
||||
{
|
||||
LPWSTR PasswordW = nullptr;
|
||||
BOOL result = FALSE;
|
||||
size_t pwdCharLength = 0;
|
||||
|
||||
if (!NtHash)
|
||||
return FALSE;
|
||||
|
||||
PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLength, &pwdCharLength);
|
||||
if (!PasswordW)
|
||||
return FALSE;
|
||||
|
||||
if (!NTOWFv1W(PasswordW, (UINT32)pwdCharLength * sizeof(WCHAR), NtHash))
|
||||
goto out_fail;
|
||||
|
||||
result = TRUE;
|
||||
out_fail:
|
||||
free(PasswordW);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define NTOWFv2(Password, User, Domain) as
|
||||
* HMAC_MD5(MD4(UNICODE(Password)),
|
||||
* UNICODE(ConcatenationOf(UpperCase(User), Domain)))
|
||||
* EndDefine
|
||||
*/
|
||||
|
||||
BOOL NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, UINT32 UserLength, LPWSTR Domain,
|
||||
UINT32 DomainLength, BYTE* NtHash)
|
||||
{
|
||||
BYTE NtHashV1[WINPR_MD5_DIGEST_LENGTH];
|
||||
|
||||
if ((!User) || (!Password) || (!NtHash))
|
||||
return FALSE;
|
||||
|
||||
if (!NTOWFv1W(Password, PasswordLength, NtHashV1))
|
||||
return FALSE;
|
||||
|
||||
return NTOWFv2FromHashW(NtHashV1, User, UserLength, Domain, DomainLength, NtHash);
|
||||
}
|
||||
|
||||
BOOL NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, UINT32 UserLength, LPSTR Domain,
|
||||
UINT32 DomainLength, BYTE* NtHash)
|
||||
{
|
||||
LPWSTR UserW = nullptr;
|
||||
LPWSTR DomainW = nullptr;
|
||||
LPWSTR PasswordW = nullptr;
|
||||
BOOL result = FALSE;
|
||||
size_t userCharLength = 0;
|
||||
size_t domainCharLength = 0;
|
||||
size_t pwdCharLength = 0;
|
||||
|
||||
if (!NtHash)
|
||||
return FALSE;
|
||||
|
||||
UserW = ConvertUtf8NToWCharAlloc(User, UserLength, &userCharLength);
|
||||
DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLength, &domainCharLength);
|
||||
PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLength, &pwdCharLength);
|
||||
|
||||
if (!UserW || !DomainW || !PasswordW)
|
||||
goto out_fail;
|
||||
|
||||
if (!NTOWFv2W(PasswordW, (UINT32)pwdCharLength * sizeof(WCHAR), UserW,
|
||||
(UINT32)userCharLength * sizeof(WCHAR), DomainW,
|
||||
(UINT32)domainCharLength * sizeof(WCHAR), NtHash))
|
||||
goto out_fail;
|
||||
|
||||
result = TRUE;
|
||||
out_fail:
|
||||
free(UserW);
|
||||
free(DomainW);
|
||||
free(PasswordW);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength, LPWSTR Domain,
|
||||
UINT32 DomainLength, BYTE* NtHash)
|
||||
{
|
||||
BYTE* buffer = nullptr;
|
||||
BYTE result = FALSE;
|
||||
|
||||
if (!User || !NtHash)
|
||||
return FALSE;
|
||||
|
||||
if (!(buffer = (BYTE*)malloc(UserLength + DomainLength)))
|
||||
return FALSE;
|
||||
|
||||
/* Concatenate(UpperCase(User), Domain) */
|
||||
CopyMemory(buffer, User, UserLength);
|
||||
CharUpperBuffW((LPWSTR)buffer, UserLength / 2);
|
||||
|
||||
if (DomainLength > 0)
|
||||
{
|
||||
CopyMemory(&buffer[UserLength], Domain, DomainLength);
|
||||
}
|
||||
|
||||
/* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is
|
||||
* the NTLMv2 hash */
|
||||
if (!winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash,
|
||||
WINPR_MD5_DIGEST_LENGTH))
|
||||
goto out_fail;
|
||||
|
||||
result = TRUE;
|
||||
out_fail:
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength, LPSTR Domain,
|
||||
UINT32 DomainLength, BYTE* NtHash)
|
||||
{
|
||||
LPWSTR UserW = nullptr;
|
||||
LPWSTR DomainW = nullptr;
|
||||
BOOL result = FALSE;
|
||||
size_t userCharLength = 0;
|
||||
size_t domainCharLength = 0;
|
||||
if (!NtHash)
|
||||
return FALSE;
|
||||
|
||||
UserW = ConvertUtf8NToWCharAlloc(User, UserLength, &userCharLength);
|
||||
DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLength, &domainCharLength);
|
||||
|
||||
if (!UserW || !DomainW)
|
||||
goto out_fail;
|
||||
|
||||
if (!NTOWFv2FromHashW(NtHashV1, UserW, (UINT32)userCharLength * sizeof(WCHAR), DomainW,
|
||||
(UINT32)domainCharLength * sizeof(WCHAR), NtHash))
|
||||
goto out_fail;
|
||||
|
||||
result = TRUE;
|
||||
out_fail:
|
||||
free(UserW);
|
||||
free(DomainW);
|
||||
return result;
|
||||
}
|
||||
262
third_party/FreeRDP/winpr/libwinpr/utils/print.c
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Print Utils
|
||||
*
|
||||
* 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/debug.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (a) < (b) ? (a) : (b)
|
||||
#endif
|
||||
|
||||
void winpr_HexDump(const char* tag, UINT32 level, const void* data, size_t length)
|
||||
{
|
||||
wLog* log = WLog_Get(tag);
|
||||
winpr_HexLogDump(log, level, data, length);
|
||||
}
|
||||
|
||||
void winpr_HexLogDump(wLog* log, UINT32 level, const void* data, size_t length)
|
||||
{
|
||||
const BYTE* p = data;
|
||||
size_t line = 0;
|
||||
size_t offset = 0;
|
||||
const size_t maxlen = 20; /* 64bit SIZE_MAX as decimal */
|
||||
/* String line length:
|
||||
* prefix '[1234] '
|
||||
* hexdump '01 02 03 04'
|
||||
* separator ' '
|
||||
* ASIC line 'ab..cd'
|
||||
* zero terminator '\0'
|
||||
*/
|
||||
const size_t blen = (maxlen + 3ULL) + (WINPR_HEXDUMP_LINE_LENGTH * 3ULL) + 3ULL +
|
||||
WINPR_HEXDUMP_LINE_LENGTH + 1ULL;
|
||||
size_t pos = 0;
|
||||
|
||||
char* buffer = nullptr;
|
||||
|
||||
if (!WLog_IsLevelActive(log, level))
|
||||
return;
|
||||
|
||||
if (!log)
|
||||
return;
|
||||
|
||||
buffer = malloc(blen);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Print(log, WLOG_ERROR, "malloc(%" PRIuz ") failed with [%d] %s", blen, errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
return;
|
||||
}
|
||||
|
||||
while (offset < length)
|
||||
{
|
||||
int rc = _snprintf(&buffer[pos], blen - pos, "%04" PRIuz " ", offset);
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
pos += (size_t)rc;
|
||||
line = length - offset;
|
||||
|
||||
if (line > WINPR_HEXDUMP_LINE_LENGTH)
|
||||
line = WINPR_HEXDUMP_LINE_LENGTH;
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < line; i++)
|
||||
{
|
||||
rc = _snprintf(&buffer[pos], blen - pos, "%02" PRIx8 " ", p[i]);
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
pos += (size_t)rc;
|
||||
}
|
||||
|
||||
for (; i < WINPR_HEXDUMP_LINE_LENGTH; i++)
|
||||
{
|
||||
rc = _snprintf(&buffer[pos], blen - pos, " ");
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
pos += (size_t)rc;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < line; j++)
|
||||
{
|
||||
rc = _snprintf(&buffer[pos], blen - pos, "%c",
|
||||
(p[j] >= 0x20 && p[j] < 0x7F) ? (char)p[j] : '.');
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
pos += (size_t)rc;
|
||||
}
|
||||
|
||||
WLog_Print(log, level, "%s", buffer);
|
||||
offset += line;
|
||||
p += line;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
WLog_Print(log, level, "[length=%" PRIuz "] ", length);
|
||||
fail:
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void winpr_CArrayDump(const char* tag, UINT32 level, const void* data, size_t length, size_t width)
|
||||
{
|
||||
const BYTE* p = data;
|
||||
size_t offset = 0;
|
||||
const size_t llen = ((length > width) ? width : length) * 4ull + 1ull;
|
||||
size_t pos = 0;
|
||||
char* buffer = malloc(llen);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(tag, "malloc(%" PRIuz ") failed with [%d] %s", llen, errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
return;
|
||||
}
|
||||
|
||||
while (offset < length)
|
||||
{
|
||||
size_t line = length - offset;
|
||||
|
||||
if (line > width)
|
||||
line = width;
|
||||
|
||||
pos = 0;
|
||||
|
||||
for (size_t i = 0; i < line; i++)
|
||||
{
|
||||
const int rc = _snprintf(&buffer[pos], llen - pos, "\\x%02" PRIX8 "", p[i]);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
pos += (size_t)rc;
|
||||
}
|
||||
|
||||
WLog_LVL(tag, level, "%s", buffer);
|
||||
offset += line;
|
||||
p += line;
|
||||
}
|
||||
|
||||
fail:
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static BYTE value(char c)
|
||||
{
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return (c - '0') & 0xFF;
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return (10 + c - 'A') & 0xFF;
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return (10 + c - 'a') & 0xFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t winpr_HexStringToBinBuffer(const char* str, size_t strLength, BYTE* data, size_t dataLength)
|
||||
{
|
||||
size_t y = 0;
|
||||
size_t maxStrLen = 0;
|
||||
if (!str || !data || (strLength == 0) || (dataLength == 0))
|
||||
return 0;
|
||||
|
||||
maxStrLen = strnlen(str, strLength);
|
||||
for (size_t x = 0; x < maxStrLen;)
|
||||
{
|
||||
BYTE val = value(str[x++]);
|
||||
if (x < maxStrLen)
|
||||
val = (BYTE)(val << 4) | (value(str[x++]));
|
||||
if (x < maxStrLen)
|
||||
{
|
||||
if (str[x] == ' ')
|
||||
x++;
|
||||
}
|
||||
data[y++] = val;
|
||||
if (y >= dataLength)
|
||||
return y;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
size_t winpr_BinToHexStringBuffer(const BYTE* data, size_t length, char* dstStr, size_t dstSize,
|
||||
BOOL space)
|
||||
{
|
||||
const size_t n = space ? 3 : 2;
|
||||
const char bin2hex[] = "0123456789ABCDEF";
|
||||
const size_t maxLength = MIN(length, dstSize / n);
|
||||
|
||||
if (!data || !dstStr || (length == 0) || (dstSize == 0))
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0; i < maxLength; i++)
|
||||
{
|
||||
const int ln = data[i] & 0xF;
|
||||
const int hn = (data[i] >> 4) & 0xF;
|
||||
char* dst = &dstStr[i * n];
|
||||
|
||||
dst[0] = bin2hex[hn];
|
||||
dst[1] = bin2hex[ln];
|
||||
|
||||
if (space)
|
||||
dst[2] = ' ';
|
||||
}
|
||||
|
||||
if (space && (maxLength > 0))
|
||||
{
|
||||
dstStr[maxLength * n - 1] = '\0';
|
||||
return maxLength * n - 1;
|
||||
}
|
||||
dstStr[maxLength * n] = '\0';
|
||||
return maxLength * n;
|
||||
}
|
||||
|
||||
char* winpr_BinToHexString(const BYTE* data, size_t length, BOOL space)
|
||||
{
|
||||
size_t rc = 0;
|
||||
const size_t n = space ? 3 : 2;
|
||||
const size_t size = (length + 1ULL) * n;
|
||||
char* p = (char*)malloc(size);
|
||||
|
||||
if (!p)
|
||||
return nullptr;
|
||||
|
||||
rc = winpr_BinToHexStringBuffer(data, length, p, size, space);
|
||||
if (rc == 0)
|
||||
{
|
||||
free(p);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
385
third_party/FreeRDP/winpr/libwinpr/utils/sam.c
vendored
Normal file
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Accounts Manager (SAM)
|
||||
*
|
||||
* 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/path.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sam.h>
|
||||
#include <winpr/cast.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/file.h>
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#ifdef WINPR_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define TAG WINPR_TAG("utils")
|
||||
|
||||
struct winpr_sam
|
||||
{
|
||||
FILE* fp;
|
||||
char* line;
|
||||
char* buffer;
|
||||
char* context;
|
||||
BOOL readOnly;
|
||||
};
|
||||
|
||||
static WINPR_SAM_ENTRY* SamEntryFromDataA(LPCSTR User, DWORD UserLength, LPCSTR Domain,
|
||||
DWORD DomainLength)
|
||||
{
|
||||
WINPR_SAM_ENTRY* entry = calloc(1, sizeof(WINPR_SAM_ENTRY));
|
||||
if (!entry)
|
||||
return nullptr;
|
||||
if (User && (UserLength > 0))
|
||||
entry->User = _strdup(User);
|
||||
entry->UserLength = UserLength;
|
||||
if (Domain && (DomainLength > 0))
|
||||
entry->Domain = _strdup(Domain);
|
||||
entry->DomainLength = DomainLength;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static BOOL SamAreEntriesEqual(const WINPR_SAM_ENTRY* a, const WINPR_SAM_ENTRY* b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return FALSE;
|
||||
if (a->UserLength != b->UserLength)
|
||||
return FALSE;
|
||||
if (a->DomainLength != b->DomainLength)
|
||||
return FALSE;
|
||||
if (a->UserLength > 0)
|
||||
{
|
||||
if (!a->User || !b->User)
|
||||
return FALSE;
|
||||
if (strncmp(a->User, b->User, a->UserLength) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
if (a->DomainLength > 0)
|
||||
{
|
||||
if (!a->Domain || !b->Domain)
|
||||
return FALSE;
|
||||
if (strncmp(a->Domain, b->Domain, a->DomainLength) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_SAM* SamOpen(const char* filename, BOOL readOnly)
|
||||
{
|
||||
FILE* fp = nullptr;
|
||||
WINPR_SAM* sam = nullptr;
|
||||
char* allocatedFileName = nullptr;
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
allocatedFileName = winpr_GetConfigFilePath(TRUE, "SAM");
|
||||
filename = allocatedFileName;
|
||||
}
|
||||
|
||||
if (readOnly)
|
||||
fp = winpr_fopen(filename, "r");
|
||||
else
|
||||
{
|
||||
fp = winpr_fopen(filename, "r+");
|
||||
|
||||
if (!fp)
|
||||
fp = winpr_fopen(filename, "w+");
|
||||
}
|
||||
free(allocatedFileName);
|
||||
|
||||
if (fp)
|
||||
{
|
||||
sam = (WINPR_SAM*)calloc(1, sizeof(WINPR_SAM));
|
||||
|
||||
if (!sam)
|
||||
{
|
||||
(void)fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sam->readOnly = readOnly;
|
||||
sam->fp = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "Could not open SAM file!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sam;
|
||||
}
|
||||
|
||||
static BOOL SamLookupStart(WINPR_SAM* sam)
|
||||
{
|
||||
size_t readSize = 0;
|
||||
INT64 fileSize = 0;
|
||||
|
||||
if (!sam || !sam->fp)
|
||||
return FALSE;
|
||||
|
||||
if (_fseeki64(sam->fp, 0, SEEK_END) != 0)
|
||||
return FALSE;
|
||||
fileSize = _ftelli64(sam->fp);
|
||||
if (_fseeki64(sam->fp, 0, SEEK_SET) != 0)
|
||||
return FALSE;
|
||||
|
||||
if (fileSize < 1)
|
||||
return FALSE;
|
||||
|
||||
sam->context = nullptr;
|
||||
sam->buffer = (char*)calloc((size_t)fileSize + 2, 1);
|
||||
|
||||
if (!sam->buffer)
|
||||
return FALSE;
|
||||
|
||||
readSize = fread(sam->buffer, (size_t)fileSize, 1, sam->fp);
|
||||
|
||||
if (!readSize)
|
||||
{
|
||||
if (!ferror(sam->fp))
|
||||
readSize = (size_t)fileSize;
|
||||
}
|
||||
|
||||
if (readSize < 1)
|
||||
{
|
||||
free(sam->buffer);
|
||||
sam->buffer = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sam->buffer[fileSize] = '\n';
|
||||
sam->buffer[fileSize + 1] = '\0';
|
||||
sam->line = strtok_s(sam->buffer, "\n", &sam->context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SamLookupFinish(WINPR_SAM* sam)
|
||||
{
|
||||
free(sam->buffer);
|
||||
sam->buffer = nullptr;
|
||||
sam->line = nullptr;
|
||||
}
|
||||
|
||||
static BOOL SamReadEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
|
||||
{
|
||||
char* p[5] = WINPR_C_ARRAY_INIT;
|
||||
size_t count = 0;
|
||||
|
||||
if (!sam || !entry || !sam->line)
|
||||
return FALSE;
|
||||
|
||||
char* cur = sam->line;
|
||||
|
||||
while ((cur = strchr(cur, ':')) != nullptr)
|
||||
{
|
||||
count++;
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (count < 4)
|
||||
return FALSE;
|
||||
|
||||
p[0] = sam->line;
|
||||
p[1] = strchr(p[0], ':') + 1;
|
||||
p[2] = strchr(p[1], ':') + 1;
|
||||
p[3] = strchr(p[2], ':') + 1;
|
||||
p[4] = strchr(p[3], ':') + 1;
|
||||
const size_t LmHashLength = WINPR_ASSERTING_INT_CAST(size_t, (p[3] - p[2] - 1));
|
||||
const size_t NtHashLength = WINPR_ASSERTING_INT_CAST(size_t, (p[4] - p[3] - 1));
|
||||
|
||||
if ((LmHashLength != 0) && (LmHashLength != 32))
|
||||
return FALSE;
|
||||
|
||||
if ((NtHashLength != 0) && (NtHashLength != 32))
|
||||
return FALSE;
|
||||
|
||||
entry->UserLength = (UINT32)(p[1] - p[0] - 1);
|
||||
entry->User = (LPSTR)malloc(entry->UserLength + 1);
|
||||
|
||||
if (!entry->User)
|
||||
return FALSE;
|
||||
|
||||
entry->User[entry->UserLength] = '\0';
|
||||
entry->DomainLength = (UINT32)(p[2] - p[1] - 1);
|
||||
memcpy(entry->User, p[0], entry->UserLength);
|
||||
|
||||
if (entry->DomainLength > 0)
|
||||
{
|
||||
entry->Domain = (LPSTR)malloc(entry->DomainLength + 1);
|
||||
|
||||
if (!entry->Domain)
|
||||
{
|
||||
free(entry->User);
|
||||
entry->User = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(entry->Domain, p[1], entry->DomainLength);
|
||||
entry->Domain[entry->DomainLength] = '\0';
|
||||
}
|
||||
else
|
||||
entry->Domain = nullptr;
|
||||
|
||||
if (LmHashLength == 32)
|
||||
{
|
||||
if (winpr_HexStringToBinBuffer(p[2], LmHashLength, entry->LmHash, sizeof(entry->LmHash)) !=
|
||||
32)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (NtHashLength == 32)
|
||||
{
|
||||
if (winpr_HexStringToBinBuffer(p[3], NtHashLength, (BYTE*)entry->NtHash,
|
||||
sizeof(entry->NtHash)) != 32)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void SamFreeEntry(WINPR_ATTR_UNUSED WINPR_SAM* sam, WINPR_SAM_ENTRY* entry)
|
||||
{
|
||||
if (entry)
|
||||
{
|
||||
if (entry->UserLength > 0)
|
||||
free(entry->User);
|
||||
|
||||
if (entry->DomainLength > 0)
|
||||
free(entry->Domain);
|
||||
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void SamResetEntry(WINPR_SAM_ENTRY* entry)
|
||||
{
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
if (entry->UserLength)
|
||||
{
|
||||
free(entry->User);
|
||||
entry->User = nullptr;
|
||||
}
|
||||
|
||||
if (entry->DomainLength)
|
||||
{
|
||||
free(entry->Domain);
|
||||
entry->Domain = nullptr;
|
||||
}
|
||||
|
||||
ZeroMemory(entry->LmHash, sizeof(entry->LmHash));
|
||||
ZeroMemory(entry->NtHash, sizeof(entry->NtHash));
|
||||
}
|
||||
|
||||
WINPR_SAM_ENTRY* SamLookupUserA(WINPR_SAM* sam, LPCSTR User, UINT32 UserLength, LPCSTR Domain,
|
||||
UINT32 DomainLength)
|
||||
{
|
||||
size_t length = 0;
|
||||
BOOL found = FALSE;
|
||||
WINPR_SAM_ENTRY* search = SamEntryFromDataA(User, UserLength, Domain, DomainLength);
|
||||
WINPR_SAM_ENTRY* entry = (WINPR_SAM_ENTRY*)calloc(1, sizeof(WINPR_SAM_ENTRY));
|
||||
|
||||
if (!entry || !search)
|
||||
goto fail;
|
||||
|
||||
if (!SamLookupStart(sam))
|
||||
goto fail;
|
||||
|
||||
while (sam->line != nullptr)
|
||||
{
|
||||
length = strlen(sam->line);
|
||||
|
||||
if (length > 1)
|
||||
{
|
||||
if (sam->line[0] != '#')
|
||||
{
|
||||
if (!SamReadEntry(sam, entry))
|
||||
{
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if (SamAreEntriesEqual(entry, search))
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SamResetEntry(entry);
|
||||
sam->line = strtok_s(nullptr, "\n", &sam->context);
|
||||
}
|
||||
|
||||
out_fail:
|
||||
SamLookupFinish(sam);
|
||||
fail:
|
||||
SamFreeEntry(sam, search);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
SamFreeEntry(sam, entry);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPCWSTR User, UINT32 UserLength, LPCWSTR Domain,
|
||||
UINT32 DomainLength)
|
||||
{
|
||||
WINPR_SAM_ENTRY* entry = nullptr;
|
||||
char* utfUser = nullptr;
|
||||
char* utfDomain = nullptr;
|
||||
size_t userCharLen = 0;
|
||||
size_t domainCharLen = 0;
|
||||
|
||||
utfUser = ConvertWCharNToUtf8Alloc(User, UserLength / sizeof(WCHAR), &userCharLen);
|
||||
if (!utfUser)
|
||||
goto fail;
|
||||
if (DomainLength > 0)
|
||||
{
|
||||
utfDomain = ConvertWCharNToUtf8Alloc(Domain, DomainLength / sizeof(WCHAR), &domainCharLen);
|
||||
if (!utfDomain)
|
||||
goto fail;
|
||||
}
|
||||
entry = SamLookupUserA(sam, utfUser, (UINT32)userCharLen, utfDomain, (UINT32)domainCharLen);
|
||||
fail:
|
||||
free(utfUser);
|
||||
free(utfDomain);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void SamClose(WINPR_SAM* sam)
|
||||
{
|
||||
if (sam != nullptr)
|
||||
{
|
||||
if (sam->fp)
|
||||
(void)fclose(sam->fp);
|
||||
free(sam);
|
||||
}
|
||||
}
|
||||
448
third_party/FreeRDP/winpr/libwinpr/utils/ssl.c
vendored
Normal file
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* OpenSSL Library Initialization
|
||||
*
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
* Copyright 2014 Norbert Federa <norbert.federa@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/synch.h>
|
||||
#include <winpr/ssl.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
#include <openssl/provider.h>
|
||||
#endif
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("utils.ssl")
|
||||
|
||||
static BOOL g_winpr_openssl_initialized_by_winpr = FALSE;
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
static OSSL_PROVIDER* s_winpr_openssl_provider_fips = nullptr;
|
||||
static OSSL_PROVIDER* s_winpr_openssl_provider_legacy = nullptr;
|
||||
static OSSL_PROVIDER* s_winpr_openssl_provider_default = nullptr;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Note from OpenSSL 1.1.0 "CHANGES":
|
||||
* OpenSSL now uses a new threading API. It is no longer necessary to
|
||||
* set locking callbacks to use OpenSSL in a multi-threaded environment.
|
||||
*/
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
#define WINPR_OPENSSL_LOCKING_REQUIRED 1
|
||||
|
||||
static int g_winpr_openssl_num_locks = 0;
|
||||
static HANDLE* g_winpr_openssl_locks = nullptr;
|
||||
|
||||
struct CRYPTO_dynlock_value
|
||||
{
|
||||
HANDLE mutex;
|
||||
};
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
static unsigned long _winpr_openssl_id(void)
|
||||
{
|
||||
return (unsigned long)GetCurrentThreadId();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _winpr_openssl_locking(int mode, int type, const char* file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
{
|
||||
(void)WaitForSingleObject(g_winpr_openssl_locks[type], INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)ReleaseMutex(g_winpr_openssl_locks[type]);
|
||||
}
|
||||
}
|
||||
|
||||
static struct CRYPTO_dynlock_value* _winpr_openssl_dynlock_create(const char* file, int line)
|
||||
{
|
||||
struct CRYPTO_dynlock_value* dynlock;
|
||||
|
||||
if (!(dynlock = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value))))
|
||||
return nullptr;
|
||||
|
||||
if (!(dynlock->mutex = CreateMutex(nullptr, FALSE, nullptr)))
|
||||
{
|
||||
free(dynlock);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dynlock;
|
||||
}
|
||||
|
||||
static void _winpr_openssl_dynlock_lock(int mode, struct CRYPTO_dynlock_value* dynlock,
|
||||
const char* file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
{
|
||||
(void)WaitForSingleObject(dynlock->mutex, INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)ReleaseMutex(dynlock->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void _winpr_openssl_dynlock_destroy(struct CRYPTO_dynlock_value* dynlock, const char* file,
|
||||
int line)
|
||||
{
|
||||
(void)CloseHandle(dynlock->mutex);
|
||||
free(dynlock);
|
||||
}
|
||||
|
||||
static BOOL _winpr_openssl_initialize_locking(void)
|
||||
{
|
||||
int count;
|
||||
|
||||
/* OpenSSL static locking */
|
||||
|
||||
if (CRYPTO_get_locking_callback())
|
||||
{
|
||||
WLog_WARN(TAG, "OpenSSL static locking callback is already set");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((count = CRYPTO_num_locks()) > 0)
|
||||
{
|
||||
HANDLE* locks;
|
||||
|
||||
if (!(locks = calloc(count, sizeof(HANDLE))))
|
||||
{
|
||||
WLog_ERR(TAG, "error allocating lock table");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (!(locks[i] = CreateMutex(nullptr, FALSE, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "error creating lock #%d", i);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
if (locks[i])
|
||||
(void)CloseHandle(locks[i]);
|
||||
}
|
||||
|
||||
free(locks);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_winpr_openssl_locks = locks;
|
||||
g_winpr_openssl_num_locks = count;
|
||||
CRYPTO_set_locking_callback(_winpr_openssl_locking);
|
||||
}
|
||||
}
|
||||
|
||||
/* OpenSSL dynamic locking */
|
||||
|
||||
if (CRYPTO_get_dynlock_create_callback() || CRYPTO_get_dynlock_lock_callback() ||
|
||||
CRYPTO_get_dynlock_destroy_callback())
|
||||
{
|
||||
WLog_WARN(TAG, "dynamic locking callbacks are already set");
|
||||
}
|
||||
else
|
||||
{
|
||||
CRYPTO_set_dynlock_create_callback(_winpr_openssl_dynlock_create);
|
||||
CRYPTO_set_dynlock_lock_callback(_winpr_openssl_dynlock_lock);
|
||||
CRYPTO_set_dynlock_destroy_callback(_winpr_openssl_dynlock_destroy);
|
||||
}
|
||||
|
||||
/* Use the deprecated CRYPTO_get_id_callback() if building against OpenSSL < 1.0.0 */
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
if (CRYPTO_get_id_callback())
|
||||
{
|
||||
WLog_WARN(TAG, "OpenSSL id_callback is already set");
|
||||
}
|
||||
else
|
||||
{
|
||||
CRYPTO_set_id_callback(_winpr_openssl_id);
|
||||
}
|
||||
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _winpr_openssl_cleanup_locking(void)
|
||||
{
|
||||
/* undo our static locking modifications */
|
||||
if (CRYPTO_get_locking_callback() == _winpr_openssl_locking)
|
||||
{
|
||||
CRYPTO_set_locking_callback(nullptr);
|
||||
|
||||
for (int i = 0; i < g_winpr_openssl_num_locks; i++)
|
||||
{
|
||||
(void)CloseHandle(g_winpr_openssl_locks[i]);
|
||||
}
|
||||
|
||||
g_winpr_openssl_num_locks = 0;
|
||||
free(g_winpr_openssl_locks);
|
||||
g_winpr_openssl_locks = nullptr;
|
||||
}
|
||||
|
||||
/* unset our dynamic locking callbacks */
|
||||
|
||||
if (CRYPTO_get_dynlock_create_callback() == _winpr_openssl_dynlock_create)
|
||||
{
|
||||
CRYPTO_set_dynlock_create_callback(nullptr);
|
||||
}
|
||||
|
||||
if (CRYPTO_get_dynlock_lock_callback() == _winpr_openssl_dynlock_lock)
|
||||
{
|
||||
CRYPTO_set_dynlock_lock_callback(nullptr);
|
||||
}
|
||||
|
||||
if (CRYPTO_get_dynlock_destroy_callback() == _winpr_openssl_dynlock_destroy)
|
||||
{
|
||||
CRYPTO_set_dynlock_destroy_callback(nullptr);
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
if (CRYPTO_get_id_callback() == _winpr_openssl_id)
|
||||
{
|
||||
CRYPTO_set_id_callback(nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* OpenSSL < 1.1.0 */
|
||||
|
||||
static BOOL winpr_enable_fips(DWORD flags)
|
||||
{
|
||||
if (flags & WINPR_SSL_INIT_ENABLE_FIPS)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
WLog_ERR(TAG, "Openssl fips mode not available on openssl versions less than 1.0.1!");
|
||||
return FALSE;
|
||||
#else
|
||||
WLog_DBG(TAG, "Ensuring openssl fips mode is enabled");
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
s_winpr_openssl_provider_fips = OSSL_PROVIDER_load(nullptr, "fips");
|
||||
if (s_winpr_openssl_provider_fips == nullptr)
|
||||
{
|
||||
WLog_WARN(TAG, "OpenSSL FIPS provider failed to load");
|
||||
}
|
||||
if (!EVP_default_properties_is_fips_enabled(nullptr))
|
||||
#else
|
||||
if (FIPS_mode() != 1)
|
||||
#endif
|
||||
{
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
if (EVP_set_default_properties(nullptr, "fips=yes"))
|
||||
#else
|
||||
if (FIPS_mode_set(1))
|
||||
#endif
|
||||
WLog_INFO(TAG, "Openssl fips mode enabled!");
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Openssl fips mode enable failed!");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void winpr_openssl_cleanup(void)
|
||||
{
|
||||
winpr_CleanupSSL(WINPR_SSL_INIT_DEFAULT);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK winpr_openssl_initialize(WINPR_ATTR_UNUSED PINIT_ONCE once, PVOID param,
|
||||
WINPR_ATTR_UNUSED PVOID* context)
|
||||
{
|
||||
DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT;
|
||||
|
||||
if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
|
||||
|
||||
if (flags & WINPR_SSL_INIT_ENABLE_LOCKING)
|
||||
{
|
||||
if (!_winpr_openssl_initialize_locking())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/* SSL_load_error_strings() is void */
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
SSL_load_error_strings();
|
||||
/* SSL_library_init() always returns "1" */
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_digests();
|
||||
OpenSSL_add_all_ciphers();
|
||||
#else
|
||||
|
||||
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
|
||||
OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
|
||||
OPENSSL_INIT_ENGINE_ALL_BUILTIN,
|
||||
nullptr) != 1)
|
||||
return FALSE;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
/* The legacy provider is needed for MD4. */
|
||||
s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(nullptr, "legacy");
|
||||
if (s_winpr_openssl_provider_legacy == nullptr)
|
||||
{
|
||||
WLog_WARN(TAG, "OpenSSL LEGACY provider failed to load, no md4 support available!");
|
||||
}
|
||||
s_winpr_openssl_provider_default = OSSL_PROVIDER_load(nullptr, "default");
|
||||
if (s_winpr_openssl_provider_default == nullptr)
|
||||
{
|
||||
WLog_WARN(TAG, "OpenSSL DEFAULT provider failed to load");
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)atexit(winpr_openssl_cleanup);
|
||||
g_winpr_openssl_initialized_by_winpr = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* exported functions */
|
||||
|
||||
BOOL winpr_InitializeSSL(DWORD flags)
|
||||
{
|
||||
static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
|
||||
|
||||
if (!InitOnceExecuteOnce(&once, winpr_openssl_initialize, &flags, nullptr))
|
||||
return FALSE;
|
||||
|
||||
return winpr_enable_fips(flags);
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
static int unload(OSSL_PROVIDER* provider, WINPR_ATTR_UNUSED void* data)
|
||||
{
|
||||
if (!provider)
|
||||
return 1;
|
||||
const char* name = OSSL_PROVIDER_get0_name(provider);
|
||||
if (!name)
|
||||
return 1;
|
||||
|
||||
OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
|
||||
const int rc = OSSL_PROVIDER_available(ctx, name);
|
||||
if (rc < 1)
|
||||
return 1;
|
||||
OSSL_PROVIDER_unload(provider);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL winpr_CleanupSSL(DWORD flags)
|
||||
{
|
||||
if (flags & WINPR_SSL_CLEANUP_GLOBAL)
|
||||
{
|
||||
if (!g_winpr_openssl_initialized_by_winpr)
|
||||
{
|
||||
WLog_WARN(TAG, "ssl was not initialized by winpr");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_winpr_openssl_initialized_by_winpr = FALSE;
|
||||
#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
|
||||
_winpr_openssl_cleanup_locking();
|
||||
#endif
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
#endif
|
||||
#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
|
||||
flags |= WINPR_SSL_CLEANUP_THREAD;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
|
||||
|
||||
if (flags & WINPR_SSL_CLEANUP_THREAD)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
ERR_remove_state(0);
|
||||
#else
|
||||
ERR_remove_thread_state(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
|
||||
OSSL_PROVIDER_do_all(ctx, unload, nullptr);
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL winpr_FIPSMode(void)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
return FALSE;
|
||||
#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
return (EVP_default_properties_is_fips_enabled(nullptr) == 1);
|
||||
#else
|
||||
return (FIPS_mode() == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
BOOL winpr_InitializeSSL(DWORD flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL winpr_CleanupSSL(DWORD flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL winpr_FIPSMode(void)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
516
third_party/FreeRDP/winpr/libwinpr/utils/stream.c
vendored
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Stream Utils
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
* 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 <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "stream.h"
|
||||
#include "../log.h"
|
||||
|
||||
#define STREAM_TAG WINPR_TAG("wStream")
|
||||
|
||||
#define STREAM_ASSERT(cond) \
|
||||
do \
|
||||
{ \
|
||||
if (!(cond)) \
|
||||
{ \
|
||||
WLog_FATAL(STREAM_TAG, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __func__, \
|
||||
(size_t)__LINE__); \
|
||||
winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
BOOL Stream_EnsureCapacity(wStream* s, size_t size)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
if (s->capacity >= size)
|
||||
return TRUE;
|
||||
|
||||
const size_t increment = 128ull;
|
||||
const size_t old_capacity = s->capacity;
|
||||
const size_t new_capacity = size + increment - size % increment;
|
||||
const size_t position = Stream_GetPosition(s);
|
||||
|
||||
BYTE* new_buf = nullptr;
|
||||
if (!s->isOwner)
|
||||
{
|
||||
new_buf = (BYTE*)malloc(new_capacity);
|
||||
if (!new_buf)
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(new_buf, s->buffer, s->capacity);
|
||||
s->isOwner = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_buf = (BYTE*)realloc(s->buffer, new_capacity);
|
||||
if (!new_buf)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s->buffer = new_buf;
|
||||
s->capacity = new_capacity;
|
||||
s->length = new_capacity;
|
||||
ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity);
|
||||
|
||||
return Stream_SetPosition(s, position);
|
||||
}
|
||||
|
||||
BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size)
|
||||
{
|
||||
if (Stream_GetPosition(s) + size > Stream_Capacity(s))
|
||||
return Stream_EnsureCapacity(s, Stream_Capacity(s) + size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wStream* Stream_New(BYTE* buffer, size_t size)
|
||||
{
|
||||
wStream* s = nullptr;
|
||||
|
||||
if (!buffer && !size)
|
||||
return nullptr;
|
||||
|
||||
s = calloc(1, sizeof(wStream));
|
||||
if (!s)
|
||||
return nullptr;
|
||||
|
||||
if (buffer)
|
||||
s->buffer = buffer;
|
||||
else
|
||||
s->buffer = (BYTE*)malloc(size);
|
||||
|
||||
if (!s->buffer)
|
||||
{
|
||||
free(s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
s->pointer = s->buffer;
|
||||
s->capacity = size;
|
||||
s->length = size;
|
||||
|
||||
s->pool = nullptr;
|
||||
s->count = 1;
|
||||
s->isAllocatedStream = TRUE;
|
||||
s->isOwner = TRUE;
|
||||
return s;
|
||||
}
|
||||
|
||||
wStream* Stream_StaticConstInit(wStream* s, const BYTE* buffer, size_t size)
|
||||
{
|
||||
union
|
||||
{
|
||||
BYTE* b;
|
||||
const BYTE* cb;
|
||||
} cnv;
|
||||
|
||||
cnv.cb = buffer;
|
||||
return Stream_StaticInit(s, cnv.b, size);
|
||||
}
|
||||
|
||||
wStream* Stream_StaticInit(wStream* s, BYTE* buffer, size_t size)
|
||||
{
|
||||
const wStream empty = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(buffer);
|
||||
|
||||
*s = empty;
|
||||
s->buffer = s->pointer = buffer;
|
||||
s->capacity = s->length = size;
|
||||
s->pool = nullptr;
|
||||
s->count = 1;
|
||||
s->isAllocatedStream = FALSE;
|
||||
s->isOwner = FALSE;
|
||||
return s;
|
||||
}
|
||||
|
||||
void Stream_EnsureValidity(wStream* s)
|
||||
{
|
||||
size_t cur = 0;
|
||||
|
||||
STREAM_ASSERT(s);
|
||||
STREAM_ASSERT(s->pointer >= s->buffer);
|
||||
|
||||
cur = (size_t)(s->pointer - s->buffer);
|
||||
STREAM_ASSERT(cur <= s->capacity);
|
||||
STREAM_ASSERT(s->length <= s->capacity);
|
||||
}
|
||||
|
||||
void Stream_Free(wStream* s, BOOL bFreeBuffer)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
Stream_EnsureValidity(s);
|
||||
if (bFreeBuffer && s->isOwner)
|
||||
free(s->buffer);
|
||||
|
||||
if (s->isAllocatedStream)
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Stream_SetLength(wStream* _s, size_t _l)
|
||||
{
|
||||
if ((_l) > Stream_Capacity(_s))
|
||||
{
|
||||
_s->length = 0;
|
||||
return FALSE;
|
||||
}
|
||||
_s->length = _l;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_SetPosition(wStream* _s, size_t _p)
|
||||
{
|
||||
if ((_p) > Stream_Capacity(_s))
|
||||
{
|
||||
_s->pointer = _s->buffer;
|
||||
return FALSE;
|
||||
}
|
||||
_s->pointer = _s->buffer + (_p);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void Stream_SealLength(wStream* _s)
|
||||
{
|
||||
size_t cur = 0;
|
||||
WINPR_ASSERT(_s);
|
||||
WINPR_ASSERT(_s->buffer <= _s->pointer);
|
||||
cur = (size_t)(_s->pointer - _s->buffer);
|
||||
WINPR_ASSERT(cur <= _s->capacity);
|
||||
if (cur <= _s->capacity)
|
||||
_s->length = cur;
|
||||
else
|
||||
{
|
||||
WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was written out of bounds");
|
||||
winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
|
||||
_s->length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_WINPR_DEPRECATED)
|
||||
BOOL Stream_SetPointer(wStream* _s, BYTE* _p)
|
||||
{
|
||||
WINPR_ASSERT(_s);
|
||||
if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p))
|
||||
{
|
||||
_s->pointer = _s->buffer;
|
||||
return FALSE;
|
||||
}
|
||||
_s->pointer = _p;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_SetBuffer(wStream* _s, BYTE* _b)
|
||||
{
|
||||
WINPR_ASSERT(_s);
|
||||
WINPR_ASSERT(_b);
|
||||
|
||||
_s->buffer = _b;
|
||||
_s->pointer = _b;
|
||||
return _s->buffer != nullptr;
|
||||
}
|
||||
|
||||
void Stream_SetCapacity(wStream* _s, size_t _c)
|
||||
{
|
||||
WINPR_ASSERT(_s);
|
||||
_s->capacity = _c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
size_t Stream_GetRemainingCapacity(const wStream* _s)
|
||||
{
|
||||
size_t cur = 0;
|
||||
WINPR_ASSERT(_s);
|
||||
WINPR_ASSERT(_s->buffer <= _s->pointer);
|
||||
cur = (size_t)(_s->pointer - _s->buffer);
|
||||
WINPR_ASSERT(cur <= _s->capacity);
|
||||
if (cur > _s->capacity)
|
||||
{
|
||||
WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was written out of bounds");
|
||||
winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
|
||||
return 0;
|
||||
}
|
||||
return (_s->capacity - cur);
|
||||
}
|
||||
|
||||
size_t Stream_GetRemainingLength(const wStream* _s)
|
||||
{
|
||||
size_t cur = 0;
|
||||
WINPR_ASSERT(_s);
|
||||
WINPR_ASSERT(_s->buffer <= _s->pointer);
|
||||
WINPR_ASSERT(_s->length <= _s->capacity);
|
||||
cur = (size_t)(_s->pointer - _s->buffer);
|
||||
WINPR_ASSERT(cur <= _s->length);
|
||||
if (cur > _s->length)
|
||||
{
|
||||
WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was read out of bounds");
|
||||
winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
|
||||
return 0;
|
||||
}
|
||||
return (_s->length - cur);
|
||||
}
|
||||
|
||||
BOOL Stream_Write_UTF16_String(wStream* s, const WCHAR* src, size_t length)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(src || (length == 0));
|
||||
if (!s || !src)
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, (s), length, sizeof(WCHAR)))
|
||||
return FALSE;
|
||||
|
||||
for (size_t x = 0; x < length; x++)
|
||||
Stream_Write_UINT16(s, src[x]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_Read_UTF16_String(wStream* s, WCHAR* dst, size_t length)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(dst);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSize(STREAM_TAG, s, length, sizeof(WCHAR)))
|
||||
return FALSE;
|
||||
|
||||
for (size_t x = 0; x < length; x++)
|
||||
Stream_Read_UINT16(s, dst[x]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_CheckAndLogRequiredCapacityEx(const char* tag, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, const char* fmt, ...)
|
||||
{
|
||||
WINPR_ASSERT(size != 0);
|
||||
const size_t actual = Stream_GetRemainingCapacity(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
va_list args = WINPR_C_ARRAY_INIT;
|
||||
|
||||
va_start(args, fmt);
|
||||
const BOOL rc =
|
||||
Stream_CheckAndLogRequiredCapacityExVa(tag, level, s, nmemb, size, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_CheckAndLogRequiredCapacityExVa(const char* tag, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, const char* fmt, va_list args)
|
||||
{
|
||||
WINPR_ASSERT(size != 0);
|
||||
const size_t actual = Stream_GetRemainingCapacity(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
return Stream_CheckAndLogRequiredCapacityWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
|
||||
args);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(6, 0)
|
||||
BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, WINPR_FORMAT_ARG const char* fmt,
|
||||
va_list args)
|
||||
{
|
||||
|
||||
WINPR_ASSERT(size != 0);
|
||||
const size_t actual = Stream_GetRemainingCapacity(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
char prefix[1024] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
(void)vsnprintf(prefix, sizeof(prefix), fmt, args);
|
||||
|
||||
WLog_Print(log, level,
|
||||
"[%s] invalid remaining capacity, got %" PRIuz ", require at least %" PRIuz
|
||||
" [element size=%" PRIuz "]",
|
||||
prefix, actual, nmemb, size);
|
||||
winpr_log_backtrace_ex(log, level, 20);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(6, 7)
|
||||
BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, WINPR_FORMAT_ARG const char* fmt, ...)
|
||||
{
|
||||
|
||||
WINPR_ASSERT(size != 0);
|
||||
const size_t actual = Stream_GetRemainingCapacity(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
va_list args = WINPR_C_ARRAY_INIT;
|
||||
|
||||
va_start(args, fmt);
|
||||
const BOOL rc =
|
||||
Stream_CheckAndLogRequiredCapacityWLogExVa(log, level, s, nmemb, size, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(6, 7)
|
||||
BOOL Stream_CheckAndLogRequiredLengthEx(const char* tag, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, WINPR_FORMAT_ARG const char* fmt, ...)
|
||||
{
|
||||
WINPR_ASSERT(size > 0);
|
||||
const size_t actual = Stream_GetRemainingLength(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
va_list args = WINPR_C_ARRAY_INIT;
|
||||
|
||||
va_start(args, fmt);
|
||||
const BOOL rc = Stream_CheckAndLogRequiredLengthExVa(tag, level, s, nmemb, size, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_CheckAndLogRequiredLengthExVa(const char* tag, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, const char* fmt, va_list args)
|
||||
{
|
||||
WINPR_ASSERT(size > 0);
|
||||
const size_t actual = Stream_GetRemainingLength(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
|
||||
args);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, const char* fmt, ...)
|
||||
{
|
||||
WINPR_ASSERT(size > 0);
|
||||
const size_t actual = Stream_GetRemainingLength(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
va_list args = WINPR_C_ARRAY_INIT;
|
||||
|
||||
va_start(args, fmt);
|
||||
const BOOL rc =
|
||||
Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, nmemb, size, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(6, 0)
|
||||
BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level, wStream* s, size_t nmemb,
|
||||
size_t size, WINPR_FORMAT_ARG const char* fmt,
|
||||
va_list args)
|
||||
{
|
||||
WINPR_ASSERT(size > 0);
|
||||
const size_t actual = Stream_GetRemainingLength(s) / size;
|
||||
|
||||
if (actual < nmemb)
|
||||
{
|
||||
char prefix[1024] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
(void)vsnprintf(prefix, sizeof(prefix), fmt, args);
|
||||
|
||||
WLog_Print(log, level,
|
||||
"[%s] invalid length, got %" PRIuz ", require at least %" PRIuz
|
||||
" [element size=%" PRIuz "]",
|
||||
prefix, actual, nmemb, size);
|
||||
winpr_log_backtrace_ex(log, level, 20);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SSIZE_T Stream_Write_UTF16_String_From_UTF8(wStream* s, size_t wcharLength, const char* src,
|
||||
size_t length, BOOL fill)
|
||||
{
|
||||
SSIZE_T rc = 0;
|
||||
WCHAR* str = Stream_PointerAs(s, WCHAR);
|
||||
|
||||
if (length != 0)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, s, wcharLength, sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
rc = ConvertUtf8NToWChar(src, length, str, wcharLength);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
Stream_Seek(s, (size_t)rc * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
if (fill)
|
||||
Stream_Zero(s, (wcharLength - (size_t)rc) * sizeof(WCHAR));
|
||||
return rc;
|
||||
}
|
||||
|
||||
char* Stream_Read_UTF16_String_As_UTF8(wStream* s, size_t wcharLength, size_t* pUtfCharLength)
|
||||
{
|
||||
const WCHAR* str = Stream_ConstPointer(s);
|
||||
if (wcharLength > SIZE_MAX / sizeof(WCHAR))
|
||||
return nullptr;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength * sizeof(WCHAR)))
|
||||
return nullptr;
|
||||
|
||||
Stream_Seek(s, wcharLength * sizeof(WCHAR));
|
||||
return ConvertWCharNToUtf8Alloc(str, wcharLength, pUtfCharLength);
|
||||
}
|
||||
|
||||
SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(wStream* s, size_t wcharLength, char* utfBuffer,
|
||||
size_t utfBufferCharLength)
|
||||
{
|
||||
const WCHAR* ptr = Stream_ConstPointer(s);
|
||||
if (wcharLength > SIZE_MAX / sizeof(WCHAR))
|
||||
return -1;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength * sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
Stream_Seek(s, wcharLength * sizeof(WCHAR));
|
||||
return ConvertWCharNToUtf8(ptr, wcharLength, utfBuffer, utfBufferCharLength);
|
||||
}
|
||||
|
||||
BOOL Stream_SafeSeekEx(wStream* s, size_t size, const char* file, size_t line, const char* fkt)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLengthEx(STREAM_TAG, WLOG_WARN, s, size, 1, "%s(%s:%" PRIuz ")",
|
||||
fkt, file, line))
|
||||
return FALSE;
|
||||
|
||||
Stream_Seek(s, size);
|
||||
return TRUE;
|
||||
}
|
||||
28
third_party/FreeRDP/winpr/libwinpr/utils/stream.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Stream Utils
|
||||
*
|
||||
* Copyright 2021 Armin Novak <anovak@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.
|
||||
*/
|
||||
|
||||
#ifndef LIBWINPR_UTILS_STREAM_H
|
||||
#define LIBWINPR_UTILS_STREAM_H
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
void Stream_EnsureValidity(wStream* s);
|
||||
|
||||
#endif /* LIBWINPR_UTILS_STREAM_H */
|
||||
74
third_party/FreeRDP/winpr/libwinpr/utils/strlst.c
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* String List Utils
|
||||
*
|
||||
* Copyright 2018 Pascal Bourguignon <pjb@informatimago.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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/strlst.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
void string_list_free(char** string_list)
|
||||
{
|
||||
for (size_t i = 0; string_list[i]; i++)
|
||||
{
|
||||
free(string_list[i]);
|
||||
}
|
||||
|
||||
free((void*)string_list);
|
||||
}
|
||||
|
||||
int string_list_length(const char* const* string_list)
|
||||
{
|
||||
int i = 0;
|
||||
for (; string_list[i]; i++)
|
||||
;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
char** string_list_copy(const char* const* string_list)
|
||||
{
|
||||
int length = string_list_length(string_list);
|
||||
char** copy = (char**)calloc(WINPR_ASSERTING_INT_CAST(size_t, length) + 1, sizeof(char*));
|
||||
|
||||
if (!copy)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
copy[i] = _strdup(string_list[i]);
|
||||
}
|
||||
|
||||
copy[length] = nullptr;
|
||||
return copy;
|
||||
}
|
||||
|
||||
void string_list_print(FILE* out, const char* const* string_list)
|
||||
{
|
||||
for (int j = 0; string_list[j]; j++)
|
||||
{
|
||||
(void)fprintf(out, "[%2d]: %s\n", j, string_list[j]);
|
||||
}
|
||||
|
||||
(void)fflush(out);
|
||||
}
|
||||
55
third_party/FreeRDP/winpr/libwinpr/utils/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
set(MODULE_NAME "TestWinPRUtils")
|
||||
set(MODULE_PREFIX "TEST_WINPR_UTILS")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestIni.c
|
||||
TestVersion.c
|
||||
TestImage.c
|
||||
TestBacktrace.c
|
||||
TestQueue.c
|
||||
TestPrint.c
|
||||
TestPubSub.c
|
||||
TestStream.c
|
||||
TestBitStream.c
|
||||
TestArrayList.c
|
||||
TestLinkedList.c
|
||||
TestListDictionary.c
|
||||
TestCmdLine.c
|
||||
TestASN1.c
|
||||
TestWLog.c
|
||||
TestWLogCallback.c
|
||||
TestHashTable.c
|
||||
TestBufferPool.c
|
||||
TestStreamPool.c
|
||||
TestMessageQueue.c
|
||||
TestMessagePipe.c
|
||||
)
|
||||
|
||||
if(WITH_LODEPNG)
|
||||
list(APPEND ${MODULES_PREFIX}_TESTS TestImage.c)
|
||||
endif()
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_compile_definitions(TEST_SOURCE_PATH="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
add_compile_definitions(TEST_BINARY_PATH="${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
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")
|
||||
|
||||
add_executable(img-cnv img-cnv.c)
|
||||
target_link_libraries(img-cnv winpr)
|
||||
347
third_party/FreeRDP/winpr/libwinpr/utils/test/TestASN1.c
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
#include <winpr/asn1.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
static const BYTE boolContent[] = { 0x01, 0x01, 0xFF };
|
||||
static const BYTE badBoolContent[] = { 0x01, 0x04, 0xFF };
|
||||
|
||||
static const BYTE integerContent[] = { 0x02, 0x01, 0x02 };
|
||||
static const BYTE badIntegerContent[] = { 0x02, 0x04, 0x02 };
|
||||
static const BYTE positiveIntegerContent[] = { 0x02, 0x02, 0x00, 0xff };
|
||||
static const BYTE negativeIntegerContent[] = { 0x02, 0x01, 0xff };
|
||||
|
||||
static const BYTE seqContent[] = { 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1B, 0x44,
|
||||
0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x53, 0x69, 0x67,
|
||||
0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75,
|
||||
0x73, 0x74, 0x20, 0x43, 0x6F, 0x2E, 0x31 };
|
||||
|
||||
static const BYTE contextualInteger[] = { 0xA0, 0x03, 0x02, 0x01, 0x02 };
|
||||
|
||||
static const BYTE oidContent[] = { 0x06, 0x03, 0x55, 0x04, 0x0A };
|
||||
static const BYTE badOidContent[] = { 0x06, 0x89, 0x55, 0x04, 0x0A };
|
||||
static const BYTE oidValue[] = { 0x55, 0x04, 0x0A };
|
||||
|
||||
static const BYTE ia5stringContent[] = { 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
|
||||
0x63, 0x70, 0x73, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D,
|
||||
0x78, 0x31, 0x2E, 0x6C, 0x65, 0x74, 0x73, 0x65, 0x6E,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72, 0x67 };
|
||||
|
||||
static const BYTE utctimeContent[] = { 0x17, 0x0D, 0x32, 0x31, 0x30, 0x33, 0x31, 0x37,
|
||||
0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5A };
|
||||
|
||||
int TestASN1Read(int argc, char* argv[])
|
||||
{
|
||||
WinPrAsn1Decoder decoder = WinPrAsn1Decoder_init();
|
||||
WinPrAsn1Decoder seqDecoder = WinPrAsn1Decoder_init();
|
||||
wStream staticS = WINPR_C_ARRAY_INIT;
|
||||
WinPrAsn1_BOOL boolV = 0;
|
||||
WinPrAsn1_INTEGER integerV = 0;
|
||||
WinPrAsn1_OID oidV = WINPR_C_ARRAY_INIT;
|
||||
WinPrAsn1_IA5STRING ia5stringV = nullptr;
|
||||
WinPrAsn1_UTCTIME utctimeV = WINPR_C_ARRAY_INIT;
|
||||
WinPrAsn1_tag tag = 0;
|
||||
size_t len = 0;
|
||||
BOOL error = 0;
|
||||
|
||||
/* ============== Test INTEGERs ================ */
|
||||
Stream_StaticConstInit(&staticS, integerContent, sizeof(integerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadInteger(&decoder, &integerV))
|
||||
return -1;
|
||||
|
||||
Stream_StaticConstInit(&staticS, positiveIntegerContent, sizeof(positiveIntegerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadInteger(&decoder, &integerV) && integerV != 0xff)
|
||||
return -1;
|
||||
|
||||
Stream_StaticConstInit(&staticS, negativeIntegerContent, sizeof(negativeIntegerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadInteger(&decoder, &integerV) && integerV != -1)
|
||||
return -1;
|
||||
|
||||
Stream_StaticConstInit(&staticS, badIntegerContent, sizeof(badIntegerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadInteger(&decoder, &integerV))
|
||||
return -1;
|
||||
|
||||
/* ================ Test BOOL ================*/
|
||||
Stream_StaticConstInit(&staticS, boolContent, sizeof(boolContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadBoolean(&decoder, &boolV))
|
||||
return -10;
|
||||
|
||||
Stream_StaticConstInit(&staticS, badBoolContent, sizeof(badBoolContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadBoolean(&decoder, &boolV))
|
||||
return -11;
|
||||
|
||||
/* ================ Test OID ================*/
|
||||
Stream_StaticConstInit(&staticS, oidContent, sizeof(oidContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadOID(&decoder, &oidV, TRUE) || oidV.len != 3 ||
|
||||
(memcmp(oidV.data, oidValue, oidV.len) != 0))
|
||||
return -15;
|
||||
WinPrAsn1FreeOID(&oidV);
|
||||
|
||||
Stream_StaticConstInit(&staticS, badOidContent, sizeof(badOidContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadOID(&decoder, &oidV, TRUE))
|
||||
return -15;
|
||||
WinPrAsn1FreeOID(&oidV);
|
||||
|
||||
Stream_StaticConstInit(&staticS, ia5stringContent, sizeof(ia5stringContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadIA5String(&decoder, &ia5stringV) ||
|
||||
(strcmp(ia5stringV, "http://cps.root-x1.letsencrypt.org") != 0))
|
||||
return -16;
|
||||
free(ia5stringV);
|
||||
|
||||
/* ================ Test utc time ================*/
|
||||
Stream_StaticConstInit(&staticS, utctimeContent, sizeof(utctimeContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadUtcTime(&decoder, &utctimeV) || utctimeV.year != 2021 ||
|
||||
utctimeV.month != 3 || utctimeV.day != 17 || utctimeV.minute != 40 || utctimeV.tz != 'Z')
|
||||
return -17;
|
||||
|
||||
/* ================ Test sequence ================*/
|
||||
Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadSequence(&decoder, &seqDecoder))
|
||||
return -20;
|
||||
|
||||
Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadTagLenValue(&decoder, &tag, &len, &seqDecoder))
|
||||
return -21;
|
||||
|
||||
if (tag != ER_TAG_SEQUENCE)
|
||||
return -22;
|
||||
|
||||
if (!WinPrAsn1DecPeekTag(&seqDecoder, &tag) || tag != ER_TAG_OBJECT_IDENTIFIER)
|
||||
return -23;
|
||||
|
||||
/* ================ Test contextual ================*/
|
||||
Stream_StaticConstInit(&staticS, contextualInteger, sizeof(contextualInteger));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
error = TRUE;
|
||||
if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV) || error)
|
||||
return -25;
|
||||
|
||||
/* test reading a contextual integer that is not there (index 1).
|
||||
* that should not touch the decoder read head and we shall be able to extract contextual tag 0
|
||||
* after that
|
||||
*/
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
error = FALSE;
|
||||
if (WinPrAsn1DecReadContextualInteger(&decoder, 1, &error, &integerV) || error)
|
||||
return -26;
|
||||
|
||||
error = FALSE;
|
||||
if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV) || error)
|
||||
return -27;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BYTE oid1_val[] = { 1 };
|
||||
static const WinPrAsn1_OID oid1 = { sizeof(oid1_val), oid1_val };
|
||||
static BYTE oid2_val[] = { 2, 2 };
|
||||
static WinPrAsn1_OID oid2 = { sizeof(oid2_val), oid2_val };
|
||||
static BYTE oid3_val[] = { 3, 3, 3 };
|
||||
static WinPrAsn1_OID oid3 = { sizeof(oid3_val), oid3_val };
|
||||
static BYTE oid4_val[] = { 4, 4, 4, 4 };
|
||||
static WinPrAsn1_OID oid4 = { sizeof(oid4_val), oid4_val };
|
||||
|
||||
int TestASN1Write(int argc, char* argv[])
|
||||
{
|
||||
wStream* s = nullptr;
|
||||
size_t expectedOuputSz = 0;
|
||||
int retCode = 100;
|
||||
WinPrAsn1_UTCTIME utcTime;
|
||||
WinPrAsn1_IA5STRING ia5string = nullptr;
|
||||
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
goto out;
|
||||
|
||||
/* Let's encode something like:
|
||||
* APP(3)
|
||||
* SEQ2
|
||||
* OID1
|
||||
* OID2
|
||||
* SEQ3
|
||||
* OID3
|
||||
* OID4
|
||||
*
|
||||
* [5] integer(200)
|
||||
* [6] SEQ (empty)
|
||||
* [7] UTC time (2016-03-17 16:40:41 UTC)
|
||||
* [8] IA5String(test)
|
||||
* [9] OctetString
|
||||
* SEQ(empty)
|
||||
*
|
||||
*/
|
||||
|
||||
/* APP(3) */
|
||||
retCode = 101;
|
||||
if (!WinPrAsn1EncAppContainer(enc, 3))
|
||||
goto out;
|
||||
|
||||
/* SEQ2 */
|
||||
retCode = 102;
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
retCode = 103;
|
||||
if (WinPrAsn1EncOID(enc, &oid1) != 3)
|
||||
goto out;
|
||||
|
||||
retCode = 104;
|
||||
if (WinPrAsn1EncOID(enc, &oid2) != 4)
|
||||
goto out;
|
||||
|
||||
retCode = 105;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 9)
|
||||
goto out;
|
||||
|
||||
/* SEQ3 */
|
||||
retCode = 110;
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
retCode = 111;
|
||||
if (WinPrAsn1EncOID(enc, &oid3) != 5)
|
||||
goto out;
|
||||
|
||||
retCode = 112;
|
||||
if (WinPrAsn1EncOID(enc, &oid4) != 6)
|
||||
goto out;
|
||||
|
||||
retCode = 113;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 13)
|
||||
goto out;
|
||||
|
||||
/* [5] integer(200) */
|
||||
retCode = 114;
|
||||
if (WinPrAsn1EncContextualInteger(enc, 5, 200) != 6)
|
||||
goto out;
|
||||
|
||||
/* [6] SEQ (empty) */
|
||||
retCode = 115;
|
||||
if (!WinPrAsn1EncContextualSeqContainer(enc, 6))
|
||||
goto out;
|
||||
|
||||
retCode = 116;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 4)
|
||||
goto out;
|
||||
|
||||
/* [7] UTC time (2016-03-17 16:40:41 UTC) */
|
||||
retCode = 117;
|
||||
utcTime.year = 2016;
|
||||
utcTime.month = 3;
|
||||
utcTime.day = 17;
|
||||
utcTime.hour = 16;
|
||||
utcTime.minute = 40;
|
||||
utcTime.second = 41;
|
||||
utcTime.tz = 'Z';
|
||||
if (WinPrAsn1EncContextualUtcTime(enc, 7, &utcTime) != 17)
|
||||
goto out;
|
||||
|
||||
/* [8] IA5String(test) */
|
||||
retCode = 118;
|
||||
ia5string = "test";
|
||||
if (!WinPrAsn1EncContextualContainer(enc, 8))
|
||||
goto out;
|
||||
|
||||
retCode = 119;
|
||||
if (WinPrAsn1EncIA5String(enc, ia5string) != 6)
|
||||
goto out;
|
||||
|
||||
retCode = 120;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 8)
|
||||
goto out;
|
||||
|
||||
/* [9] OctetString
|
||||
* SEQ(empty)
|
||||
*/
|
||||
retCode = 121;
|
||||
if (!WinPrAsn1EncContextualOctetStringContainer(enc, 9))
|
||||
goto out;
|
||||
|
||||
retCode = 122;
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
retCode = 123;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 2)
|
||||
goto out;
|
||||
|
||||
retCode = 124;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 6)
|
||||
goto out;
|
||||
|
||||
/* close APP */
|
||||
expectedOuputSz = 24 + 6 + 4 + 17 + 8 + 6;
|
||||
retCode = 200;
|
||||
if (WinPrAsn1EncEndContainer(enc) != expectedOuputSz)
|
||||
goto out;
|
||||
|
||||
/* let's output the result */
|
||||
retCode = 201;
|
||||
s = Stream_New(nullptr, 1024);
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
retCode = 202;
|
||||
if (!WinPrAsn1EncToStream(enc, s) || Stream_GetPosition(s) != expectedOuputSz)
|
||||
goto out;
|
||||
/* winpr_HexDump("", WLOG_ERROR, Stream_Buffer(s), Stream_GetPosition(s));*/
|
||||
|
||||
/*
|
||||
* let's perform a mini-performance test, where we encode an ASN1 message with a big depth,
|
||||
* so that we trigger reallocation routines in the encoder. We're gonna encode something like
|
||||
* SEQ1
|
||||
* SEQ2
|
||||
* SEQ3
|
||||
* ...
|
||||
* SEQ1000
|
||||
* INTEGER(2)
|
||||
*
|
||||
* As static chunks and containers are 50, a depth of 1000 should be enough
|
||||
*
|
||||
*/
|
||||
WinPrAsn1Encoder_Reset(enc);
|
||||
|
||||
retCode = 203;
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
}
|
||||
|
||||
retCode = 204;
|
||||
if (WinPrAsn1EncInteger(enc, 2) != 3)
|
||||
goto out;
|
||||
|
||||
retCode = 205;
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
if (!WinPrAsn1EncEndContainer(enc))
|
||||
goto out;
|
||||
}
|
||||
|
||||
retCode = 0;
|
||||
|
||||
out:
|
||||
if (s)
|
||||
Stream_Free(s, TRUE);
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return retCode;
|
||||
}
|
||||
|
||||
int TestASN1(int argc, char* argv[])
|
||||
{
|
||||
int ret = TestASN1Read(argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return TestASN1Write(argc, argv);
|
||||
}
|
||||
84
third_party/FreeRDP/winpr/libwinpr/utils/test/TestArrayList.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
int TestArrayList(int argc, char* argv[])
|
||||
{
|
||||
int res = -1;
|
||||
SSIZE_T rc = 0;
|
||||
size_t val = 0;
|
||||
const size_t elemsToInsert = 10;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
wArrayList* arrayList = ArrayList_New(TRUE);
|
||||
if (!arrayList)
|
||||
return -1;
|
||||
|
||||
for (size_t index = 0; index < elemsToInsert; index++)
|
||||
{
|
||||
if (!ArrayList_Append(arrayList, (void*)index))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size_t count = ArrayList_Count(arrayList);
|
||||
|
||||
printf("ArrayList count: %" PRIuz "\n", count);
|
||||
|
||||
SSIZE_T index = ArrayList_IndexOf(arrayList, (void*)(size_t)6, -1, -1);
|
||||
|
||||
printf("ArrayList index: %" PRIdz "\n", index);
|
||||
|
||||
if (index != 6)
|
||||
goto fail;
|
||||
|
||||
ArrayList_Insert(arrayList, 5, (void*)(size_t)100);
|
||||
|
||||
index = ArrayList_IndexOf(arrayList, (void*)(size_t)6, -1, -1);
|
||||
printf("ArrayList index: %" PRIdz "\n", index);
|
||||
|
||||
if (index != 7)
|
||||
goto fail;
|
||||
|
||||
ArrayList_Remove(arrayList, (void*)(size_t)100);
|
||||
|
||||
rc = ArrayList_IndexOf(arrayList, (void*)(size_t)6, -1, -1);
|
||||
printf("ArrayList index: %" PRIdz "\n", rc);
|
||||
|
||||
if (rc != 6)
|
||||
goto fail;
|
||||
|
||||
for (size_t index = 0; index < elemsToInsert; index++)
|
||||
{
|
||||
val = (size_t)ArrayList_GetItem(arrayList, 0);
|
||||
if (!ArrayList_RemoveAt(arrayList, 0))
|
||||
goto fail;
|
||||
|
||||
if (val != index)
|
||||
{
|
||||
printf("ArrayList: shifted %" PRIdz " entries, expected value %" PRIdz ", got %" PRIdz
|
||||
"\n",
|
||||
index, index, val);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ArrayList_IndexOf(arrayList, (void*)elemsToInsert, -1, -1);
|
||||
printf("ArrayList index: %" PRIdz "\n", rc);
|
||||
if (rc != -1)
|
||||
goto fail;
|
||||
|
||||
count = ArrayList_Count(arrayList);
|
||||
printf("ArrayList count: %" PRIuz "\n", count);
|
||||
if (count != 0)
|
||||
goto fail;
|
||||
|
||||
ArrayList_Clear(arrayList);
|
||||
res = 0;
|
||||
fail:
|
||||
ArrayList_Free(arrayList);
|
||||
|
||||
return res;
|
||||
}
|
||||
34
third_party/FreeRDP/winpr/libwinpr/utils/test/TestBacktrace.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <winpr/debug.h>
|
||||
|
||||
int TestBacktrace(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
size_t used = 0;
|
||||
char** msg = nullptr;
|
||||
void* stack = winpr_backtrace(20);
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!stack)
|
||||
{
|
||||
(void)fprintf(stderr, "winpr_backtrace failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = winpr_backtrace_symbols(stack, &used);
|
||||
|
||||
if (msg)
|
||||
{
|
||||
for (size_t x = 0; x < used; x++)
|
||||
printf("%" PRIuz ": %s\n", x, msg[x]);
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
winpr_backtrace_symbols_fd(stack, fileno(stdout));
|
||||
winpr_backtrace_free(stack);
|
||||
free((void*)msg);
|
||||
return rc;
|
||||
}
|
||||
86
third_party/FreeRDP/winpr/libwinpr/utils/test/TestBitStream.c
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/bitstream.h>
|
||||
|
||||
static void BitStrGen(void)
|
||||
{
|
||||
char str[64] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
for (DWORD i = 0; i < 256;)
|
||||
{
|
||||
printf("\t");
|
||||
|
||||
for (DWORD j = 0; j < 4; j++)
|
||||
{
|
||||
if (0)
|
||||
{
|
||||
/* Least Significant Bit First */
|
||||
str[0] = (i & (1 << 7)) ? '1' : '0';
|
||||
str[1] = (i & (1 << 6)) ? '1' : '0';
|
||||
str[2] = (i & (1 << 5)) ? '1' : '0';
|
||||
str[3] = (i & (1 << 4)) ? '1' : '0';
|
||||
str[4] = (i & (1 << 3)) ? '1' : '0';
|
||||
str[5] = (i & (1 << 2)) ? '1' : '0';
|
||||
str[6] = (i & (1 << 1)) ? '1' : '0';
|
||||
str[7] = (i & (1 << 0)) ? '1' : '0';
|
||||
str[8] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Most Significant Bit First */
|
||||
str[7] = (i & (1 << 7)) ? '1' : '0';
|
||||
str[6] = (i & (1 << 6)) ? '1' : '0';
|
||||
str[5] = (i & (1 << 5)) ? '1' : '0';
|
||||
str[4] = (i & (1 << 4)) ? '1' : '0';
|
||||
str[3] = (i & (1 << 3)) ? '1' : '0';
|
||||
str[2] = (i & (1 << 2)) ? '1' : '0';
|
||||
str[1] = (i & (1 << 1)) ? '1' : '0';
|
||||
str[0] = (i & (1 << 0)) ? '1' : '0';
|
||||
str[8] = '\0';
|
||||
}
|
||||
|
||||
printf("\"%s\",%s", str, j == 3 ? "" : " ");
|
||||
i++;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int TestBitStream(int argc, char* argv[])
|
||||
{
|
||||
wBitStream* bs = nullptr;
|
||||
BYTE buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
bs = BitStream_New();
|
||||
if (!bs)
|
||||
return 1;
|
||||
BitStream_Attach(bs, buffer, sizeof(buffer));
|
||||
BitStream_Write_Bits(bs, 0xAF, 8); /* 11110101 */
|
||||
BitStream_Write_Bits(bs, 0xF, 4); /* 1111 */
|
||||
BitStream_Write_Bits(bs, 0xA, 4); /* 0101 */
|
||||
BitStream_Flush(bs);
|
||||
BitDump(__func__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST);
|
||||
BitStream_Write_Bits(bs, 3, 2); /* 11 */
|
||||
BitStream_Write_Bits(bs, 0, 3); /* 000 */
|
||||
BitStream_Write_Bits(bs, 0x2D, 6); /* 101101 */
|
||||
BitStream_Write_Bits(bs, 0x19, 5); /* 11001 */
|
||||
// BitStream_Flush(bs); /* flush should be done automatically here (32 bits written) */
|
||||
BitDump(__func__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST);
|
||||
BitStream_Write_Bits(bs, 3, 2); /* 11 */
|
||||
BitStream_Flush(bs);
|
||||
BitDump(__func__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST);
|
||||
BitStream_Write_Bits(bs, 00, 2); /* 00 */
|
||||
BitStream_Write_Bits(bs, 0xF, 4); /* 1111 */
|
||||
BitStream_Write_Bits(bs, 0, 20);
|
||||
BitStream_Write_Bits(bs, 0xAFF, 12); /* 111111110101 */
|
||||
BitStream_Flush(bs);
|
||||
BitDump(__func__, WLOG_INFO, buffer, bs->position, BITDUMP_MSB_FIRST);
|
||||
BitStream_Free(bs);
|
||||
return 0;
|
||||
}
|
||||
68
third_party/FreeRDP/winpr/libwinpr/utils/test/TestBufferPool.c
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
int TestBufferPool(int argc, char* argv[])
|
||||
{
|
||||
DWORD PoolSize = 0;
|
||||
SSIZE_T BufferSize = 0;
|
||||
wBufferPool* pool = nullptr;
|
||||
BYTE* Buffers[10] = WINPR_C_ARRAY_INIT;
|
||||
int DefaultSize = 1234;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
pool = BufferPool_New(TRUE, -1, 16);
|
||||
if (!pool)
|
||||
return -1;
|
||||
|
||||
Buffers[0] = BufferPool_Take(pool, DefaultSize);
|
||||
Buffers[1] = BufferPool_Take(pool, DefaultSize);
|
||||
Buffers[2] = BufferPool_Take(pool, 2048);
|
||||
if (!Buffers[0] || !Buffers[1] || !Buffers[2])
|
||||
return -1;
|
||||
|
||||
BufferSize = BufferPool_GetBufferSize(pool, Buffers[0]);
|
||||
|
||||
if (BufferSize != DefaultSize)
|
||||
{
|
||||
printf("BufferPool_GetBufferSize failure: Actual: %" PRIdz " Expected: %" PRIu32 "\n",
|
||||
BufferSize, DefaultSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BufferSize = BufferPool_GetBufferSize(pool, Buffers[1]);
|
||||
|
||||
if (BufferSize != DefaultSize)
|
||||
{
|
||||
printf("BufferPool_GetBufferSize failure: Actual: %" PRIdz " Expected: %" PRIu32 "\n",
|
||||
BufferSize, DefaultSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BufferSize = BufferPool_GetBufferSize(pool, Buffers[2]);
|
||||
|
||||
if (BufferSize != 2048)
|
||||
{
|
||||
printf("BufferPool_GetBufferSize failure: Actual: %" PRIdz " Expected: 2048\n", BufferSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BufferPool_Return(pool, Buffers[1]);
|
||||
|
||||
PoolSize = BufferPool_GetPoolSize(pool);
|
||||
|
||||
if (PoolSize != 2)
|
||||
{
|
||||
printf("BufferPool_GetPoolSize failure: Actual: %" PRIu32 " Expected: 2\n", PoolSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BufferPool_Clear(pool);
|
||||
|
||||
BufferPool_Free(pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
379
third_party/FreeRDP/winpr/libwinpr/utils/test/TestCmdLine.c
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
#include <errno.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/strlst.h>
|
||||
|
||||
static const char* testArgv[] = { "mstsc.exe",
|
||||
"+z",
|
||||
"/w:1024",
|
||||
"/h:768",
|
||||
"/bpp:32",
|
||||
"/admin",
|
||||
"/multimon",
|
||||
"+fonts",
|
||||
"-wallpaper",
|
||||
"/v:localhost:3389",
|
||||
"/valuelist:value1,value2",
|
||||
"/valuelist-empty:",
|
||||
nullptr };
|
||||
|
||||
static const char testListAppName[] = "test app name";
|
||||
static const char* testListArgs[] = {
|
||||
"g:some.gateway.server,u:some\\\"user,p:some\\\"password,d:some\\\"domain,type:auto",
|
||||
"a,b,c,d",
|
||||
"a:,\"b:xxx, yyy\",c",
|
||||
"a:,,,b",
|
||||
"a:,\",b",
|
||||
"\"a,b,c,d d d,fff\"",
|
||||
"",
|
||||
nullptr,
|
||||
"'a,b,\",c'",
|
||||
"\"a,b,',c\"",
|
||||
"', a, ', b,c'",
|
||||
"\"a,b,\",c\"",
|
||||
|
||||
};
|
||||
|
||||
static const char* testListArgs1[] = { testListAppName, "a", "b", "c", "d" };
|
||||
static const char* testListArgs2[] = { testListAppName, "a:", "b:xxx, yyy", "c" };
|
||||
// static const char* testListArgs3[] = {};
|
||||
// static const char* testListArgs4[] = {};
|
||||
static const char* testListArgs5[] = { testListAppName, "a", "b", "c", "d d d", "fff" };
|
||||
static const char* testListArgs6[] = { testListAppName };
|
||||
static const char* testListArgs7[] = { testListAppName };
|
||||
static const char* testListArgs8[] = { testListAppName, "a", "b", "\"", "c" };
|
||||
static const char* testListArgs9[] = { testListAppName, "a", "b", "'", "c" };
|
||||
// static const char* testListArgs10[] = {};
|
||||
// static const char* testListArgs11[] = {};
|
||||
static const char* testListArgs12[] = { testListAppName, "g:some.gateway.server",
|
||||
"u:some\\\"user", "p:some\\\"password",
|
||||
"d:some\\\"domain", "type:auto" };
|
||||
|
||||
static const char** testListArgsResult[] = {
|
||||
testListArgs12,
|
||||
testListArgs1,
|
||||
testListArgs2,
|
||||
nullptr /* testListArgs3 */,
|
||||
nullptr /* testListArgs4 */,
|
||||
testListArgs5,
|
||||
testListArgs6,
|
||||
testListArgs7,
|
||||
testListArgs8,
|
||||
testListArgs9,
|
||||
nullptr /* testListArgs10 */,
|
||||
nullptr /* testListArgs11 */
|
||||
};
|
||||
static const size_t testListArgsCount[] = {
|
||||
ARRAYSIZE(testListArgs12), ARRAYSIZE(testListArgs1),
|
||||
ARRAYSIZE(testListArgs2), 0 /* ARRAYSIZE(testListArgs3) */,
|
||||
0 /* ARRAYSIZE(testListArgs4) */, ARRAYSIZE(testListArgs5),
|
||||
ARRAYSIZE(testListArgs6), ARRAYSIZE(testListArgs7),
|
||||
ARRAYSIZE(testListArgs8), ARRAYSIZE(testListArgs9),
|
||||
0 /* ARRAYSIZE(testListArgs10) */, 0 /* ARRAYSIZE(testListArgs11) */
|
||||
|
||||
};
|
||||
|
||||
static BOOL checkResult(size_t index, char** actual, size_t actualCount)
|
||||
{
|
||||
const char** result = testListArgsResult[index];
|
||||
const size_t resultCount = testListArgsCount[index];
|
||||
|
||||
if (resultCount != actualCount)
|
||||
return FALSE;
|
||||
|
||||
if (actualCount == 0)
|
||||
{
|
||||
return (actual == nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!actual)
|
||||
return FALSE;
|
||||
|
||||
for (size_t x = 0; x < actualCount; x++)
|
||||
{
|
||||
const char* a = result[x];
|
||||
const char* b = actual[x];
|
||||
|
||||
if (strcmp(a, b) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL TestCommandLineParseCommaSeparatedValuesEx(void)
|
||||
{
|
||||
WINPR_ASSERT(ARRAYSIZE(testListArgs) == ARRAYSIZE(testListArgsResult));
|
||||
WINPR_ASSERT(ARRAYSIZE(testListArgs) == ARRAYSIZE(testListArgsCount));
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(testListArgs); x++)
|
||||
{
|
||||
union
|
||||
{
|
||||
char* p;
|
||||
char** pp;
|
||||
const char** ppc;
|
||||
} ptr;
|
||||
const char* list = testListArgs[x];
|
||||
size_t count = 42;
|
||||
ptr.pp = CommandLineParseCommaSeparatedValuesEx(testListAppName, list, &count);
|
||||
BOOL valid = checkResult(x, ptr.pp, count);
|
||||
free(ptr.p);
|
||||
if (!valid)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestCmdLine(int argc, char* argv[])
|
||||
{
|
||||
int status = 0;
|
||||
int ret = -1;
|
||||
DWORD flags = 0;
|
||||
long width = 0;
|
||||
long height = 0;
|
||||
const COMMAND_LINE_ARGUMENT_A* arg = nullptr;
|
||||
int testArgc = 0;
|
||||
char** command_line = nullptr;
|
||||
COMMAND_LINE_ARGUMENT_A args[] = {
|
||||
{ "v", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"destination server" },
|
||||
{ "port", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"server port" },
|
||||
{ "w", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "width" },
|
||||
{ "h", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "height" },
|
||||
{ "f", COMMAND_LINE_VALUE_FLAG, nullptr, nullptr, nullptr, -1, nullptr, "fullscreen" },
|
||||
{ "bpp", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"session bpp (color depth)" },
|
||||
{ "admin", COMMAND_LINE_VALUE_FLAG, nullptr, nullptr, nullptr, -1, "console",
|
||||
"admin (or console) session" },
|
||||
{ "multimon", COMMAND_LINE_VALUE_FLAG, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"multi-monitor" },
|
||||
{ "a", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, "addin", "addin" },
|
||||
{ "u", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "username" },
|
||||
{ "p", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "password" },
|
||||
{ "d", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "domain" },
|
||||
{ "z", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"compression" },
|
||||
{ "audio", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"audio output mode" },
|
||||
{ "mic", COMMAND_LINE_VALUE_FLAG, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"audio input (microphone)" },
|
||||
{ "fonts", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"smooth fonts (cleartype)" },
|
||||
{ "aero", COMMAND_LINE_VALUE_BOOL, nullptr, nullptr, BoolValueFalse, -1, nullptr,
|
||||
"desktop composition" },
|
||||
{ "window-drag", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"full window drag" },
|
||||
{ "menu-anims", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"menu animations" },
|
||||
{ "themes", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"themes" },
|
||||
{ "wallpaper", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"wallpaper" },
|
||||
{ "codec", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr, "codec" },
|
||||
{ "nego", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"protocol security negotiation" },
|
||||
{ "sec", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"force specific protocol security" },
|
||||
#if defined(WITH_FREERDP_DEPRECATED)
|
||||
{ "sec-rdp", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"rdp protocol security" },
|
||||
{ "sec-tls", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"tls protocol security" },
|
||||
{ "sec-nla", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"nla protocol security" },
|
||||
{ "sec-ext", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"nla extended protocol security" },
|
||||
{ "cert-name", COMMAND_LINE_VALUE_REQUIRED, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"certificate name" },
|
||||
{ "cert-ignore", COMMAND_LINE_VALUE_FLAG, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"ignore certificate" },
|
||||
#endif
|
||||
{ "valuelist", COMMAND_LINE_VALUE_REQUIRED, "<val1>,<val2>", nullptr, nullptr, -1, nullptr,
|
||||
"List of comma separated values." },
|
||||
{ "valuelist-empty", COMMAND_LINE_VALUE_REQUIRED, "<val1>,<val2>", nullptr, nullptr, -1,
|
||||
nullptr,
|
||||
"List of comma separated values. Used to test correct behavior if an empty list was "
|
||||
"passed." },
|
||||
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, nullptr, nullptr,
|
||||
nullptr, -1, nullptr, "print version" },
|
||||
{ "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, nullptr, nullptr, nullptr, -1,
|
||||
"?", "print help" },
|
||||
{ nullptr, 0, nullptr, nullptr, nullptr, -1, nullptr, nullptr }
|
||||
};
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
flags = COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_SIGIL_PLUS_MINUS;
|
||||
testArgc = string_list_length(testArgv);
|
||||
command_line = string_list_copy(testArgv);
|
||||
|
||||
if (!command_line)
|
||||
{
|
||||
printf("Argument duplication failed (not enough memory?)\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
status =
|
||||
CommandLineParseArgumentsA(testArgc, command_line, args, flags, nullptr, nullptr, nullptr);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
printf("CommandLineParseArgumentsA failure: %d\n", status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "w");
|
||||
|
||||
if (strcmp("1024", arg->Value) != 0)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value %s\n", arg->Name, arg->Value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "h");
|
||||
|
||||
if (strcmp("768", arg->Value) != 0)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value %s\n", arg->Name, arg->Value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "f");
|
||||
|
||||
if (arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "admin");
|
||||
|
||||
if (!arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "multimon");
|
||||
|
||||
if (!arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "v");
|
||||
|
||||
if (strcmp("localhost:3389", arg->Value) != 0)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value %s\n", arg->Name, arg->Value);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "fonts");
|
||||
|
||||
if (!arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "wallpaper");
|
||||
|
||||
if (arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = CommandLineFindArgumentA(args, "help");
|
||||
|
||||
if (arg->Value)
|
||||
{
|
||||
printf("CommandLineFindArgumentA: unexpected %s value\n", arg->Name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arg = args;
|
||||
errno = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
continue;
|
||||
|
||||
printf("Argument: %s\n", arg->Name);
|
||||
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "v")
|
||||
{
|
||||
}
|
||||
CommandLineSwitchCase(arg, "w")
|
||||
{
|
||||
width = strtol(arg->Value, nullptr, 0);
|
||||
|
||||
if (errno != 0)
|
||||
goto out;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "h")
|
||||
{
|
||||
height = strtol(arg->Value, nullptr, 0);
|
||||
|
||||
if (errno != 0)
|
||||
goto out;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "valuelist")
|
||||
{
|
||||
size_t count = 0;
|
||||
char** p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
|
||||
free((void*)p);
|
||||
|
||||
if (!p || count != 3)
|
||||
{
|
||||
printf("CommandLineParseCommaSeparatedValuesEx: invalid p or count (%" PRIuz
|
||||
"!=3)\n",
|
||||
count);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "valuelist-empty")
|
||||
{
|
||||
size_t count = 0;
|
||||
char** p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
|
||||
free((void*)p);
|
||||
|
||||
if (!p || count != 1)
|
||||
{
|
||||
printf("CommandLineParseCommaSeparatedValuesEx: invalid p or count (%" PRIuz
|
||||
"!=1)\n",
|
||||
count);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
}
|
||||
CommandLineSwitchEnd(arg)
|
||||
} while ((arg = CommandLineFindNextArgumentA(arg)) != nullptr);
|
||||
|
||||
if ((width != 1024) || (height != 768))
|
||||
{
|
||||
printf("Unexpected width and height: Actual: (%ldx%ld), Expected: (1024x768)\n", width,
|
||||
height);
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
string_list_free(command_line);
|
||||
|
||||
if (!TestCommandLineParseCommaSeparatedValuesEx())
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
446
third_party/FreeRDP/winpr/libwinpr/utils/test/TestHashTable.c
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
static char* key1 = "key1";
|
||||
static char* key2 = "key2";
|
||||
static char* key3 = "key3";
|
||||
|
||||
static char* val1 = "val1";
|
||||
static char* val2 = "val2";
|
||||
static char* val3 = "val3";
|
||||
|
||||
static int test_hash_table_pointer(void)
|
||||
{
|
||||
int rc = -1;
|
||||
size_t count = 0;
|
||||
char* value = nullptr;
|
||||
wHashTable* table = nullptr;
|
||||
table = HashTable_New(TRUE);
|
||||
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (!HashTable_Insert(table, key1, val1))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key2, val2))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key3, val3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key2))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 2, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 1, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key1))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Insert(table, key1, val1))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key2, val2))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key3, val3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key1);
|
||||
|
||||
if (strcmp(value, val1) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val1, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, val2) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val2, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key3);
|
||||
|
||||
if (strcmp(value, val3) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val3, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_SetItemValue(table, key2, "apple"))
|
||||
goto fail;
|
||||
value = (char*)HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, "apple") != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", "apple", value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Contains(table, key2))
|
||||
{
|
||||
printf("HashTable_Contains: Expected : TRUE, Actual: FALSE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : TRUE, Actual: FALSE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : FALSE, Actual: TRUE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HashTable_Clear(table);
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
fail:
|
||||
HashTable_Free(table);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int test_hash_table_string(void)
|
||||
{
|
||||
int rc = -1;
|
||||
size_t count = 0;
|
||||
char* value = nullptr;
|
||||
wHashTable* table = HashTable_New(TRUE);
|
||||
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (!HashTable_SetupForStringData(table, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!HashTable_Insert(table, key1, val1))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key2, val2))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key3, val3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key2))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 1, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key1))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Insert(table, key1, val1))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key2, val2))
|
||||
goto fail;
|
||||
if (!HashTable_Insert(table, key3, val3))
|
||||
goto fail;
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key1);
|
||||
|
||||
if (strcmp(value, val1) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val1, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, val2) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val2, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
value = (char*)HashTable_GetItemValue(table, key3);
|
||||
|
||||
if (strcmp(value, val3) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val3, value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_SetItemValue(table, key2, "apple"))
|
||||
goto fail;
|
||||
value = (char*)HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, "apple") != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", "apple", value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Contains(table, key2))
|
||||
{
|
||||
printf("HashTable_Contains: Expected : TRUE, Actual: FALSE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : TRUE, Actual: FALSE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : FALSE, Actual: TRUE\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HashTable_Clear(table);
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
fail:
|
||||
HashTable_Free(table);
|
||||
return rc;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
wHashTable* table;
|
||||
size_t strlenCounter;
|
||||
size_t foreachCalls;
|
||||
|
||||
BOOL test3error;
|
||||
} ForeachData;
|
||||
|
||||
static BOOL foreachFn1(const void* key, void* value, void* arg)
|
||||
{
|
||||
ForeachData* d = (ForeachData*)arg;
|
||||
WINPR_UNUSED(key);
|
||||
d->strlenCounter += strlen((const char*)value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL foreachFn2(const void* key, void* value, void* arg)
|
||||
{
|
||||
ForeachData* d = (ForeachData*)arg;
|
||||
WINPR_UNUSED(key);
|
||||
WINPR_UNUSED(value);
|
||||
d->foreachCalls++;
|
||||
|
||||
return (d->foreachCalls != 2);
|
||||
}
|
||||
|
||||
static BOOL foreachFn3(const void* key, void* value, void* arg)
|
||||
{
|
||||
const char* keyStr = (const char*)key;
|
||||
|
||||
ForeachData* d = (ForeachData*)arg;
|
||||
ForeachData d2;
|
||||
|
||||
WINPR_UNUSED(value);
|
||||
WINPR_ASSERT(keyStr);
|
||||
|
||||
if (strcmp(keyStr, "key1") == 0)
|
||||
{
|
||||
/* when we pass on key1, let's remove key2 and check that the value is not
|
||||
* visible anymore (even if has just been marked for removal)*/
|
||||
HashTable_Remove(d->table, "key2");
|
||||
|
||||
if (HashTable_Contains(d->table, "key2"))
|
||||
{
|
||||
d->test3error = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (HashTable_ContainsValue(d->table, "value2"))
|
||||
{
|
||||
d->test3error = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* number of elements of the table shall be correct too */
|
||||
if (HashTable_Count(d->table) != 2)
|
||||
{
|
||||
d->test3error = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* we try recursive HashTable_Foreach */
|
||||
d2.table = d->table;
|
||||
d2.strlenCounter = 0;
|
||||
|
||||
if (!HashTable_Foreach(d->table, foreachFn1, &d2))
|
||||
{
|
||||
d->test3error = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
if (d2.strlenCounter != 8)
|
||||
{
|
||||
d->test3error = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int test_hash_foreach(void)
|
||||
{
|
||||
ForeachData foreachData;
|
||||
wHashTable* table = nullptr;
|
||||
int retCode = 0;
|
||||
|
||||
foreachData.table = table = HashTable_New(TRUE);
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (!HashTable_SetupForStringData(table, TRUE))
|
||||
goto out;
|
||||
|
||||
if (HashTable_Insert(table, key1, val1) < 0 || HashTable_Insert(table, key2, val2) < 0 ||
|
||||
HashTable_Insert(table, key3, val3) < 0)
|
||||
{
|
||||
retCode = -2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* let's try a first trivial foreach */
|
||||
foreachData.strlenCounter = 0;
|
||||
if (!HashTable_Foreach(table, foreachFn1, &foreachData))
|
||||
{
|
||||
retCode = -10;
|
||||
goto out;
|
||||
}
|
||||
if (foreachData.strlenCounter != 12)
|
||||
{
|
||||
retCode = -11;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* interrupted foreach */
|
||||
foreachData.foreachCalls = 0;
|
||||
if (HashTable_Foreach(table, foreachFn2, &foreachData))
|
||||
{
|
||||
retCode = -20;
|
||||
goto out;
|
||||
}
|
||||
if (foreachData.foreachCalls != 2)
|
||||
{
|
||||
retCode = -21;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* let's try a foreach() call that will remove a value from the table in the callback */
|
||||
foreachData.test3error = FALSE;
|
||||
if (!HashTable_Foreach(table, foreachFn3, &foreachData))
|
||||
{
|
||||
retCode = -30;
|
||||
goto out;
|
||||
}
|
||||
if (foreachData.test3error)
|
||||
{
|
||||
retCode = -31;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
HashTable_Free(table);
|
||||
return retCode;
|
||||
}
|
||||
|
||||
int TestHashTable(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (test_hash_table_pointer() < 0)
|
||||
return 1;
|
||||
|
||||
if (test_hash_table_string() < 0)
|
||||
return 2;
|
||||
|
||||
if (test_hash_foreach() < 0)
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
232
third_party/FreeRDP/winpr/libwinpr/utils/test/TestImage.c
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
#include <stdio.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/image.h>
|
||||
|
||||
static const char test_src_filename[] = TEST_SOURCE_PATH "/rgb";
|
||||
static const char test_bin_filename[] = TEST_BINARY_PATH "/rgb";
|
||||
|
||||
static BOOL test_image_equal(const wImage* imageA, const wImage* imageB)
|
||||
{
|
||||
return winpr_image_equal(imageA, imageB,
|
||||
WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
|
||||
WINPR_IMAGE_CMP_FUZZY);
|
||||
}
|
||||
|
||||
static BOOL test_equal_to(const wImage* bmp, const char* name, UINT32 format)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wImage* cmp = winpr_image_new();
|
||||
if (!cmp)
|
||||
goto fail;
|
||||
|
||||
char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(path, sizeof(path), "%s.%s", name, winpr_image_format_extension(format));
|
||||
const int cmpSize = winpr_image_read(cmp, path);
|
||||
if (cmpSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = test_image_equal(bmp, cmp);
|
||||
if (!rc)
|
||||
(void)fprintf(stderr, "[%s] winpr_image_eqal failed", __func__);
|
||||
|
||||
fail:
|
||||
winpr_image_free(cmp, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_equal(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wImage* bmp = winpr_image_new();
|
||||
|
||||
if (!bmp)
|
||||
goto fail;
|
||||
|
||||
char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(path, sizeof(path), "%s.bmp", test_src_filename);
|
||||
PathCchConvertStyleA(path, sizeof(path), PATH_STYLE_NATIVE);
|
||||
|
||||
const int bmpSize = winpr_image_read(bmp, path);
|
||||
if (bmpSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (UINT32 x = 0; x < UINT8_MAX; x++)
|
||||
{
|
||||
if (!winpr_image_format_is_supported(x))
|
||||
continue;
|
||||
if (!test_equal_to(bmp, test_src_filename, x))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
winpr_image_free(bmp, TRUE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_read_write_compare(const char* tname, const char* tdst, UINT32 format)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wImage* bmp1 = winpr_image_new();
|
||||
wImage* bmp2 = winpr_image_new();
|
||||
wImage* bmp3 = winpr_image_new();
|
||||
if (!bmp1 || !bmp2 || !bmp3)
|
||||
goto fail;
|
||||
|
||||
char spath[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
char dpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
char bpath1[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
char bpath2[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
(void)_snprintf(spath, sizeof(spath), "%s.%s", tname, winpr_image_format_extension(format));
|
||||
(void)_snprintf(dpath, sizeof(dpath), "%s.%s", tdst, winpr_image_format_extension(format));
|
||||
(void)_snprintf(bpath1, sizeof(bpath1), "%s.src.%s", dpath,
|
||||
winpr_image_format_extension(WINPR_IMAGE_BITMAP));
|
||||
(void)_snprintf(bpath2, sizeof(bpath2), "%s.bin.%s", dpath,
|
||||
winpr_image_format_extension(WINPR_IMAGE_BITMAP));
|
||||
PathCchConvertStyleA(spath, sizeof(spath), PATH_STYLE_NATIVE);
|
||||
PathCchConvertStyleA(dpath, sizeof(dpath), PATH_STYLE_NATIVE);
|
||||
PathCchConvertStyleA(bpath1, sizeof(bpath1), PATH_STYLE_NATIVE);
|
||||
PathCchConvertStyleA(bpath2, sizeof(bpath2), PATH_STYLE_NATIVE);
|
||||
|
||||
const int bmpRSize = winpr_image_read(bmp1, spath);
|
||||
if (bmpRSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, spath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int bmpWSize = winpr_image_write(bmp1, dpath);
|
||||
if (bmpWSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_write failed for %s", __func__, dpath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int bmp2RSize = winpr_image_read(bmp2, dpath);
|
||||
if (bmp2RSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, dpath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int bmpSrcWSize = winpr_image_write_ex(bmp1, WINPR_IMAGE_BITMAP, bpath1);
|
||||
if (bmpSrcWSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_write_ex failed for %s", __func__, bpath1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* write a bitmap and read it back.
|
||||
* this tests if we have the proper internal format */
|
||||
const int bmpBinWSize = winpr_image_write_ex(bmp2, WINPR_IMAGE_BITMAP, bpath2);
|
||||
if (bmpBinWSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_write_ex failed for %s", __func__, bpath2);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int bmp3RSize = winpr_image_read(bmp3, bpath2);
|
||||
if (bmp3RSize <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, bpath2);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!winpr_image_equal(bmp1, bmp2,
|
||||
WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
|
||||
WINPR_IMAGE_CMP_FUZZY))
|
||||
{
|
||||
(void)fprintf(stderr, "[%s] winpr_image_eqal failed bmp1 bmp2", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = winpr_image_equal(bmp3, bmp2,
|
||||
WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
|
||||
WINPR_IMAGE_CMP_FUZZY);
|
||||
if (!rc)
|
||||
(void)fprintf(stderr, "[%s] winpr_image_eqal failed bmp3 bmp2", __func__);
|
||||
fail:
|
||||
winpr_image_free(bmp1, TRUE);
|
||||
winpr_image_free(bmp2, TRUE);
|
||||
winpr_image_free(bmp3, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_read_write(void)
|
||||
{
|
||||
BOOL rc = TRUE;
|
||||
for (UINT32 x = 0; x < UINT8_MAX; x++)
|
||||
{
|
||||
if (!winpr_image_format_is_supported(x))
|
||||
continue;
|
||||
if (!test_read_write_compare(test_src_filename, test_bin_filename, x))
|
||||
rc = FALSE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_load_file(const char* name)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wImage* image = winpr_image_new();
|
||||
if (!image || !name)
|
||||
goto fail;
|
||||
|
||||
const int res = winpr_image_read(image, name);
|
||||
rc = (res > 0);
|
||||
|
||||
fail:
|
||||
winpr_image_free(image, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_load(void)
|
||||
{
|
||||
const char* names[] = {
|
||||
"rgb.16a.bmp", "rgb.16a.nocolor.bmp", "rgb.16.bmp", "rgb.16.nocolor.bmp",
|
||||
"rgb.16x.bmp", "rgb.16x.nocolor.bmp", "rgb.24.bmp", "rgb.24.nocolor.bmp",
|
||||
"rgb.32.bmp", "rgb.32.nocolor.bmp", "rgb.32x.bmp", "rgb.32x.nocolor.bmp",
|
||||
"rgb.bmp"
|
||||
};
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(names); x++)
|
||||
{
|
||||
const char* name = names[x];
|
||||
char* fname = GetCombinedPath(TEST_SOURCE_PATH, name);
|
||||
const BOOL res = test_load_file(fname);
|
||||
free(fname);
|
||||
if (!res)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestImage(int argc, char* argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_equal())
|
||||
rc -= 1;
|
||||
|
||||
if (!test_read_write())
|
||||
rc -= 2;
|
||||
|
||||
if (!test_load())
|
||||
rc -= 4;
|
||||
|
||||
return rc;
|
||||
}
|
||||
160
third_party/FreeRDP/winpr/libwinpr/utils/test/TestIni.c
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/ini.h>
|
||||
|
||||
static const char TEST_INI_01[] = "; This is a sample .ini config file\n"
|
||||
"\n"
|
||||
"[first_section]\n"
|
||||
"one = 1\n"
|
||||
"five = 5\n"
|
||||
"animal = BIRD\n"
|
||||
"\n"
|
||||
"[second_section]\n"
|
||||
"path = \"/usr/local/bin\"\n"
|
||||
"URL = \"http://www.example.com/~username\"\n"
|
||||
"\n";
|
||||
|
||||
static const char TEST_INI_02[] = "[FreeRDS]\n"
|
||||
"prefix=\"/usr/local\"\n"
|
||||
"bindir=\"bin\"\n"
|
||||
"sbindir=\"sbin\"\n"
|
||||
"libdir=\"lib\"\n"
|
||||
"datarootdir=\"share\"\n"
|
||||
"localstatedir=\"var\"\n"
|
||||
"sysconfdir=\"etc\"\n"
|
||||
"\n";
|
||||
|
||||
static const char TEST_INI_03[] = "[FreeRDS]\n"
|
||||
"prefix=\"/usr/local\"\n"
|
||||
"bindir=\"bin\"\n"
|
||||
"# some illegal string\n"
|
||||
"sbindir=\"sbin\"\n"
|
||||
"libdir=\"lib\"\n"
|
||||
"invalid key-value pair\n"
|
||||
"datarootdir=\"share\"\n"
|
||||
"localstatedir=\"var\"\n"
|
||||
"sysconfdir=\"etc\"\n"
|
||||
"\n";
|
||||
|
||||
int TestIni(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
size_t nKeys = 0;
|
||||
size_t nSections = 0;
|
||||
UINT32 iValue = 0;
|
||||
wIniFile* ini = nullptr;
|
||||
const char* sValue = nullptr;
|
||||
char** keyNames = nullptr;
|
||||
char** sectionNames = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
/* First Sample */
|
||||
ini = IniFile_New();
|
||||
if (!ini)
|
||||
goto fail;
|
||||
|
||||
if (IniFile_ReadBuffer(ini, TEST_INI_01) < 0)
|
||||
goto fail;
|
||||
|
||||
free((void*)sectionNames);
|
||||
sectionNames = IniFile_GetSectionNames(ini, &nSections);
|
||||
if (!sectionNames && (nSections > 0))
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < nSections; i++)
|
||||
{
|
||||
free((void*)keyNames);
|
||||
keyNames = IniFile_GetSectionKeyNames(ini, sectionNames[i], &nKeys);
|
||||
printf("[%s]\n", sectionNames[i]);
|
||||
if (!keyNames && (nKeys > 0))
|
||||
goto fail;
|
||||
for (size_t j = 0; j < nKeys; j++)
|
||||
{
|
||||
sValue = IniFile_GetKeyValueString(ini, sectionNames[i], keyNames[j]);
|
||||
printf("%s = %s\n", keyNames[j], sValue);
|
||||
}
|
||||
}
|
||||
|
||||
iValue = IniFile_GetKeyValueInt(ini, "first_section", "one");
|
||||
|
||||
if (iValue != 1)
|
||||
{
|
||||
printf("IniFile_GetKeyValueInt failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iValue = IniFile_GetKeyValueInt(ini, "first_section", "five");
|
||||
|
||||
if (iValue != 5)
|
||||
{
|
||||
printf("IniFile_GetKeyValueInt failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sValue = IniFile_GetKeyValueString(ini, "first_section", "animal");
|
||||
|
||||
if (strcmp(sValue, "BIRD") != 0)
|
||||
{
|
||||
printf("IniFile_GetKeyValueString failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sValue = IniFile_GetKeyValueString(ini, "second_section", "path");
|
||||
|
||||
if (strcmp(sValue, "/usr/local/bin") != 0)
|
||||
{
|
||||
printf("IniFile_GetKeyValueString failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sValue = IniFile_GetKeyValueString(ini, "second_section", "URL");
|
||||
|
||||
if (strcmp(sValue, "http://www.example.com/~username") != 0)
|
||||
{
|
||||
printf("IniFile_GetKeyValueString failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
IniFile_Free(ini);
|
||||
/* Second Sample */
|
||||
ini = IniFile_New();
|
||||
if (!ini)
|
||||
goto fail;
|
||||
if (IniFile_ReadBuffer(ini, TEST_INI_02) < 0)
|
||||
goto fail;
|
||||
free((void*)sectionNames);
|
||||
sectionNames = IniFile_GetSectionNames(ini, &nSections);
|
||||
if (!sectionNames && (nSections > 0))
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < nSections; i++)
|
||||
{
|
||||
free((void*)keyNames);
|
||||
keyNames = IniFile_GetSectionKeyNames(ini, sectionNames[i], &nKeys);
|
||||
printf("[%s]\n", sectionNames[i]);
|
||||
|
||||
if (!keyNames && (nKeys > 0))
|
||||
goto fail;
|
||||
for (size_t j = 0; j < nKeys; j++)
|
||||
{
|
||||
sValue = IniFile_GetKeyValueString(ini, sectionNames[i], keyNames[j]);
|
||||
printf("%s = %s\n", keyNames[j], sValue);
|
||||
}
|
||||
}
|
||||
|
||||
IniFile_Free(ini);
|
||||
/* Third sample - invalid input */
|
||||
ini = IniFile_New();
|
||||
|
||||
if (IniFile_ReadBuffer(ini, TEST_INI_03) != -1)
|
||||
goto fail;
|
||||
|
||||
rc = 0;
|
||||
fail:
|
||||
free((void*)keyNames);
|
||||
free((void*)sectionNames);
|
||||
IniFile_Free(ini);
|
||||
return rc;
|
||||
}
|
||||
135
third_party/FreeRDP/winpr/libwinpr/utils/test/TestLinkedList.c
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
int TestLinkedList(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
wLinkedList* list = LinkedList_New();
|
||||
if (!list)
|
||||
return -1;
|
||||
|
||||
if (!LinkedList_AddFirst(list, (void*)(size_t)1))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)2))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)3))
|
||||
return -1;
|
||||
size_t count = LinkedList_Count(list);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("LinkedList_Count: expected 3, actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LinkedList_Enumerator_Reset(list);
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\t%p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("LinkedList First: %p Last: %p\n", LinkedList_First(list), LinkedList_Last(list));
|
||||
LinkedList_RemoveFirst(list);
|
||||
LinkedList_RemoveLast(list);
|
||||
count = LinkedList_Count(list);
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
printf("LinkedList_Count: expected 1, actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LinkedList_Enumerator_Reset(list);
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\t%p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("LinkedList First: %p Last: %p\n", LinkedList_First(list), LinkedList_Last(list));
|
||||
LinkedList_RemoveFirst(list);
|
||||
LinkedList_RemoveLast(list);
|
||||
count = LinkedList_Count(list);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("LinkedList_Count: expected 0, actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!LinkedList_AddFirst(list, (void*)(size_t)4))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)5))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)6))
|
||||
return -1;
|
||||
count = LinkedList_Count(list);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("LinkedList_Count: expected 3, actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LinkedList_Enumerator_Reset(list);
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\t%p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("LinkedList First: %p Last: %p\n", LinkedList_First(list), LinkedList_Last(list));
|
||||
if (!LinkedList_Remove(list, (void*)(size_t)5))
|
||||
return -1;
|
||||
LinkedList_Enumerator_Reset(list);
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\t%p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("LinkedList First: %p Last: %p\n", LinkedList_First(list), LinkedList_Last(list));
|
||||
LinkedList_Free(list);
|
||||
/* Test enumerator robustness */
|
||||
/* enumerator on an empty list */
|
||||
list = LinkedList_New();
|
||||
if (!list)
|
||||
return -1;
|
||||
LinkedList_Enumerator_Reset(list);
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\terror: %p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
LinkedList_Free(list);
|
||||
/* Use an enumerator without reset */
|
||||
list = LinkedList_New();
|
||||
if (!list)
|
||||
return -1;
|
||||
if (!LinkedList_AddFirst(list, (void*)(size_t)4))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)5))
|
||||
return -1;
|
||||
if (!LinkedList_AddLast(list, (void*)(size_t)6))
|
||||
return -1;
|
||||
|
||||
while (LinkedList_Enumerator_MoveNext(list))
|
||||
{
|
||||
printf("\t%p\n", LinkedList_Enumerator_Current(list));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
LinkedList_Free(list);
|
||||
return 0;
|
||||
}
|
||||
178
third_party/FreeRDP/winpr/libwinpr/utils/test/TestListDictionary.c
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
static char* key1 = "key1";
|
||||
static char* key2 = "key2";
|
||||
static char* key3 = "key3";
|
||||
|
||||
static char* val1 = "val1";
|
||||
static char* val2 = "val2";
|
||||
static char* val3 = "val3";
|
||||
|
||||
int TestListDictionary(int argc, char* argv[])
|
||||
{
|
||||
size_t count = 0;
|
||||
char* value = nullptr;
|
||||
wListDictionary* list = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
list = ListDictionary_New(TRUE);
|
||||
if (!list)
|
||||
return -1;
|
||||
|
||||
if (!ListDictionary_Add(list, key1, val1) || !ListDictionary_Add(list, key2, val2) ||
|
||||
!ListDictionary_Add(list, key3, val3))
|
||||
return -1;
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListDictionary_Remove(list, key2);
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 2, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListDictionary_Remove(list, key3);
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 1, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListDictionary_Remove(list, key1);
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ListDictionary_Add(list, key1, val1) || !ListDictionary_Add(list, key2, val2) ||
|
||||
!ListDictionary_Add(list, key3, val3))
|
||||
return -1;
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 3, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*)ListDictionary_GetItemValue(list, key1);
|
||||
|
||||
if (strcmp(value, val1) != 0)
|
||||
{
|
||||
printf("ListDictionary_GetItemValue: Expected : %" PRIuz ", Actual: %" PRIuz "\n",
|
||||
(size_t)val1, (size_t)value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*)ListDictionary_GetItemValue(list, key2);
|
||||
|
||||
if (strcmp(value, val2) != 0)
|
||||
{
|
||||
printf("ListDictionary_GetItemValue: Expected : %" PRIuz ", Actual: %" PRIuz "\n",
|
||||
(size_t)val2, (size_t)value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*)ListDictionary_GetItemValue(list, key3);
|
||||
|
||||
if (strcmp(value, val3) != 0)
|
||||
{
|
||||
printf("ListDictionary_GetItemValue: Expected : %" PRIuz ", Actual: %" PRIuz "\n",
|
||||
(size_t)val3, (size_t)value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListDictionary_SetItemValue(list, key2, "apple");
|
||||
|
||||
value = (char*)ListDictionary_GetItemValue(list, key2);
|
||||
|
||||
if (strcmp(value, "apple") != 0)
|
||||
{
|
||||
printf("ListDictionary_GetItemValue: Expected : %s, Actual: %s\n", "apple", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ListDictionary_Contains(list, key2))
|
||||
{
|
||||
printf("ListDictionary_Contains: Expected : TRUE, Actual: FALSE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ListDictionary_Take(list, key2))
|
||||
{
|
||||
printf("ListDictionary_Remove: Expected : TRUE, Actual: FALSE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ListDictionary_Take(list, key2))
|
||||
{
|
||||
printf("ListDictionary_Remove: Expected : FALSE, Actual: TRUE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = ListDictionary_Take_Head(list);
|
||||
count = ListDictionary_Count(list);
|
||||
if ((strncmp(value, val1, 4) != 0) || (count != 1))
|
||||
{
|
||||
printf("ListDictionary_Remove_Head: Expected : %s, Actual: %s Count: %" PRIuz "\n", val1,
|
||||
value, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = ListDictionary_Take_Head(list);
|
||||
count = ListDictionary_Count(list);
|
||||
if ((strncmp(value, val3, 4) != 0) || (count != 0))
|
||||
{
|
||||
printf("ListDictionary_Remove_Head: Expected : %s, Actual: %s Count: %" PRIuz "\n", val3,
|
||||
value, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = ListDictionary_Take_Head(list);
|
||||
if (value)
|
||||
{
|
||||
printf("ListDictionary_Remove_Head: Expected : (null), Actual: %s\n", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ListDictionary_Add(list, key1, val1) || !ListDictionary_Add(list, key2, val2) ||
|
||||
!ListDictionary_Add(list, key3, val3))
|
||||
return -1;
|
||||
|
||||
ListDictionary_Clear(list);
|
||||
|
||||
count = ListDictionary_Count(list);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("ListDictionary_Count: Expected : 0, Actual: %" PRIuz "\n", count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListDictionary_Free(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
105
third_party/FreeRDP/winpr/libwinpr/utils/test/TestMessagePipe.c
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
static DWORD WINAPI message_echo_pipe_client_thread(LPVOID arg)
|
||||
{
|
||||
int index = 0;
|
||||
wMessagePipe* pipe = (wMessagePipe*)arg;
|
||||
|
||||
while (index < 100)
|
||||
{
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
int count = -1;
|
||||
|
||||
if (!MessageQueue_Post(pipe->In, nullptr, 0, (void*)(size_t)index, nullptr))
|
||||
break;
|
||||
|
||||
if (!MessageQueue_Wait(pipe->Out))
|
||||
break;
|
||||
|
||||
if (!MessageQueue_Peek(pipe->Out, &message, TRUE))
|
||||
break;
|
||||
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
count = (int)(size_t)message.wParam;
|
||||
|
||||
if (count != index)
|
||||
printf("Echo count mismatch: Actual: %d, Expected: %d\n", count, index);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
MessageQueue_PostQuit(pipe->In, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI message_echo_pipe_server_thread(LPVOID arg)
|
||||
{
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
wMessagePipe* pipe = (wMessagePipe*)arg;
|
||||
|
||||
while (MessageQueue_Wait(pipe->In))
|
||||
{
|
||||
if (MessageQueue_Peek(pipe->In, &message, TRUE))
|
||||
{
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
if (!MessageQueue_Dispatch(pipe->Out, &message))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TestMessagePipe(int argc, char* argv[])
|
||||
{
|
||||
HANDLE ClientThread = nullptr;
|
||||
HANDLE ServerThread = nullptr;
|
||||
wMessagePipe* EchoPipe = nullptr;
|
||||
int ret = 1;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!(EchoPipe = MessagePipe_New()))
|
||||
{
|
||||
printf("failed to create message pipe\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(ClientThread = CreateThread(nullptr, 0, message_echo_pipe_client_thread, (void*)EchoPipe,
|
||||
0, nullptr)))
|
||||
{
|
||||
printf("failed to create client thread\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(ServerThread = CreateThread(nullptr, 0, message_echo_pipe_server_thread, (void*)EchoPipe,
|
||||
0, nullptr)))
|
||||
{
|
||||
printf("failed to create server thread\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
(void)WaitForSingleObject(ClientThread, INFINITE);
|
||||
(void)WaitForSingleObject(ServerThread, INFINITE);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (EchoPipe)
|
||||
MessagePipe_Free(EchoPipe);
|
||||
if (ClientThread)
|
||||
(void)CloseHandle(ClientThread);
|
||||
if (ServerThread)
|
||||
(void)CloseHandle(ServerThread);
|
||||
|
||||
return ret;
|
||||
}
|
||||
192
third_party/FreeRDP/winpr/libwinpr/utils/test/TestMessageQueue.c
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
static DWORD WINAPI message_queue_consumer_thread(LPVOID arg)
|
||||
{
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
wMessageQueue* queue = (wMessageQueue*)arg;
|
||||
|
||||
while (MessageQueue_Wait(queue))
|
||||
{
|
||||
if (MessageQueue_Peek(queue, &message, TRUE))
|
||||
{
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
printf("Message.Type: %" PRIu32 "\n", message.id);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool wrap_test(bool (*fkt)(wMessageQueue* queue))
|
||||
{
|
||||
wMessageQueue* queue = MessageQueue_New(nullptr);
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
const bool rc = fkt(queue);
|
||||
MessageQueue_Free(queue);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool check(const wMessage* message, size_t pos)
|
||||
{
|
||||
if (!message)
|
||||
return false;
|
||||
if (message->context != (void*)13)
|
||||
return false;
|
||||
if (message->id != pos)
|
||||
return false;
|
||||
if (message->wParam != (void*)23)
|
||||
return false;
|
||||
if (message->lParam != (void*)42)
|
||||
return false;
|
||||
if (message->Free != nullptr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool append(wMessageQueue* queue, size_t pos)
|
||||
{
|
||||
const wMessage message = { .context = (void*)13,
|
||||
.id = WINPR_ASSERTING_INT_CAST(DWORD, pos),
|
||||
.wParam = (void*)23,
|
||||
.lParam = (void*)42,
|
||||
.Free = nullptr };
|
||||
|
||||
return MessageQueue_Dispatch(queue, &message);
|
||||
}
|
||||
|
||||
static bool fill_capcity(wMessageQueue* queue, size_t* pos)
|
||||
{
|
||||
WINPR_ASSERT(pos);
|
||||
|
||||
size_t cpos = *pos;
|
||||
const size_t capacity = MessageQueue_Capacity(queue);
|
||||
while (MessageQueue_Size(queue) < capacity)
|
||||
{
|
||||
if (!append(queue, cpos++))
|
||||
return false;
|
||||
}
|
||||
*pos = cpos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drain(wMessageQueue* queue, size_t expect)
|
||||
{
|
||||
wMessage message = WINPR_C_ARRAY_INIT;
|
||||
if (MessageQueue_Get(queue, &message) < 0)
|
||||
return false;
|
||||
if (!check(&message, expect))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drain_capcity(wMessageQueue* queue, size_t remain, size_t* pos)
|
||||
{
|
||||
WINPR_ASSERT(pos);
|
||||
|
||||
size_t cpos = *pos;
|
||||
while (MessageQueue_Size(queue) > remain)
|
||||
{
|
||||
if (!drain(queue, cpos++))
|
||||
return false;
|
||||
}
|
||||
*pos = cpos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_growth_move(wMessageQueue* queue, bool big)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
const size_t cap = MessageQueue_Capacity(queue);
|
||||
if (cap < 4)
|
||||
return false;
|
||||
|
||||
size_t wpos = 0;
|
||||
size_t rpos = 0;
|
||||
if (!fill_capcity(queue, &wpos))
|
||||
return false;
|
||||
|
||||
if (big)
|
||||
{
|
||||
if (!append(queue, wpos++))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!drain_capcity(queue, 3, &rpos))
|
||||
return false;
|
||||
|
||||
if (!fill_capcity(queue, &wpos))
|
||||
return false;
|
||||
|
||||
if (!append(queue, wpos++))
|
||||
return false;
|
||||
|
||||
return drain_capcity(queue, 0, &rpos);
|
||||
}
|
||||
|
||||
static bool test_growth_big_move(wMessageQueue* queue)
|
||||
{
|
||||
return test_growth_move(queue, true);
|
||||
}
|
||||
|
||||
static bool test_growth_small_move(wMessageQueue* queue)
|
||||
{
|
||||
return test_growth_move(queue, false);
|
||||
}
|
||||
|
||||
static bool test_operation_run(wMessageQueue* queue, HANDLE thread)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
WINPR_ASSERT(thread);
|
||||
|
||||
if (!MessageQueue_Post(queue, nullptr, 123, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
if (!MessageQueue_Post(queue, nullptr, 456, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
if (!MessageQueue_Post(queue, nullptr, 789, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
if (!MessageQueue_PostQuit(queue, 0))
|
||||
return false;
|
||||
|
||||
const DWORD status = WaitForSingleObject(thread, INFINITE);
|
||||
return (status == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
static bool test_operation(wMessageQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
HANDLE thread = CreateThread(nullptr, 0, message_queue_consumer_thread, queue, 0, nullptr);
|
||||
if (!thread)
|
||||
{
|
||||
printf("failed to create thread\n");
|
||||
return false;
|
||||
}
|
||||
const bool rc = test_operation_run(queue, thread);
|
||||
if (!CloseHandle(thread))
|
||||
return false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestMessageQueue(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
|
||||
{
|
||||
if (!wrap_test(test_growth_big_move))
|
||||
return -1;
|
||||
if (!wrap_test(test_growth_small_move))
|
||||
return -2;
|
||||
if (!wrap_test(test_operation))
|
||||
return -3;
|
||||
return 0;
|
||||
}
|
||||
402
third_party/FreeRDP/winpr/libwinpr/utils/test/TestPrint.c
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
/**
|
||||
* C Programming/C Reference/stdio.h/printf:
|
||||
* http://en.wikibooks.org/wiki/C_Programming/C_Reference/stdio.h/printf
|
||||
*
|
||||
* C Programming/Procedures and functions/printf:
|
||||
* http://en.wikibooks.org/wiki/C_Programming/Procedures_and_functions/printf
|
||||
*
|
||||
* C Tutorial – printf, Format Specifiers, Format Conversions and Formatted Output:
|
||||
* http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output
|
||||
*/
|
||||
|
||||
#define _printf printf // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
|
||||
|
||||
static BOOL test_bin_tohex_string(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
{
|
||||
const BYTE binbuffer[33] = WINPR_C_ARRAY_INIT;
|
||||
const char empty[33] = WINPR_C_ARRAY_INIT;
|
||||
char strbuffer[33] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
size_t len = winpr_BinToHexStringBuffer(nullptr, sizeof(binbuffer), strbuffer,
|
||||
sizeof(strbuffer), TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, 0, strbuffer, sizeof(strbuffer), TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, sizeof(binbuffer), nullptr, sizeof(strbuffer),
|
||||
TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, sizeof(binbuffer), strbuffer, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, 0, strbuffer, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, sizeof(binbuffer), nullptr, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(nullptr, sizeof(binbuffer), strbuffer, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, 0, nullptr, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(nullptr, 0, nullptr, 0, TRUE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer, 0, nullptr, 0, FALSE);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const BYTE binbuffer1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
|
||||
const char strbuffer1[] = "0102030405060708090A0B0C0D0E0F1011";
|
||||
const char strbuffer1_space[] = "01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11";
|
||||
|
||||
char buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len = winpr_BinToHexStringBuffer(binbuffer1, sizeof(binbuffer1), buffer,
|
||||
sizeof(buffer), FALSE);
|
||||
if (len != strnlen(strbuffer1, sizeof(strbuffer1)))
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1, buffer, sizeof(strbuffer1)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer1, sizeof(binbuffer1), buffer, sizeof(buffer),
|
||||
TRUE);
|
||||
if (len != strnlen(strbuffer1_space, sizeof(strbuffer1_space)))
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1_space, buffer, sizeof(strbuffer1_space)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const BYTE binbuffer1[] = { 0xF1, 0xe2, 0xD3, 0xc4, 0xB5, 0xA6, 0x97, 0x88, 0x79,
|
||||
0x6A, 0x5b, 0x4C, 0x3d, 0x2E, 0x1f, 0x00, 0xfF };
|
||||
const char strbuffer1[] = "F1E2D3C4B5A69788796A5B4C3D2E1F00FF";
|
||||
const char strbuffer1_space[] = "F1 E2 D3 C4 B5 A6 97 88 79 6A 5B 4C 3D 2E 1F 00 FF";
|
||||
char buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len = winpr_BinToHexStringBuffer(binbuffer1, sizeof(binbuffer1), buffer,
|
||||
sizeof(buffer), FALSE);
|
||||
if (len != strnlen(strbuffer1, sizeof(strbuffer1)))
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1, buffer, sizeof(strbuffer1)) != 0)
|
||||
goto fail;
|
||||
len = winpr_BinToHexStringBuffer(binbuffer1, sizeof(binbuffer1), buffer, sizeof(buffer),
|
||||
TRUE);
|
||||
if (len != strnlen(strbuffer1_space, sizeof(strbuffer1_space)))
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1_space, buffer, sizeof(strbuffer1_space)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
}
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_bin_tohex_string_alloc(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* str = nullptr;
|
||||
{
|
||||
const BYTE binbuffer[33] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
str = winpr_BinToHexString(nullptr, sizeof(binbuffer), TRUE);
|
||||
if (str)
|
||||
goto fail;
|
||||
str = winpr_BinToHexString(binbuffer, 0, TRUE);
|
||||
if (str)
|
||||
goto fail;
|
||||
str = winpr_BinToHexString(binbuffer, 0, FALSE);
|
||||
if (str)
|
||||
goto fail;
|
||||
str = winpr_BinToHexString(nullptr, sizeof(binbuffer), FALSE);
|
||||
if (str)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const BYTE binbuffer1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
|
||||
const char strbuffer1[] = "0102030405060708090A0B0C0D0E0F1011";
|
||||
const char strbuffer1_space[] = "01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11";
|
||||
|
||||
str = winpr_BinToHexString(binbuffer1, sizeof(binbuffer1), FALSE);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1, str, sizeof(strbuffer1)) != 0)
|
||||
goto fail;
|
||||
free(str);
|
||||
str = winpr_BinToHexString(binbuffer1, sizeof(binbuffer1), TRUE);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1_space, str, sizeof(strbuffer1_space)) != 0)
|
||||
goto fail;
|
||||
free(str);
|
||||
str = nullptr;
|
||||
}
|
||||
{
|
||||
const BYTE binbuffer1[] = { 0xF1, 0xe2, 0xD3, 0xc4, 0xB5, 0xA6, 0x97, 0x88, 0x79,
|
||||
0x6A, 0x5b, 0x4C, 0x3d, 0x2E, 0x1f, 0x00, 0xfF };
|
||||
const char strbuffer1[] = "F1E2D3C4B5A69788796A5B4C3D2E1F00FF";
|
||||
const char strbuffer1_space[] = "F1 E2 D3 C4 B5 A6 97 88 79 6A 5B 4C 3D 2E 1F 00 FF";
|
||||
str = winpr_BinToHexString(binbuffer1, sizeof(binbuffer1), FALSE);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1, str, sizeof(strbuffer1)) != 0)
|
||||
goto fail;
|
||||
|
||||
free(str);
|
||||
str = winpr_BinToHexString(binbuffer1, sizeof(binbuffer1), TRUE);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (memcmp(strbuffer1_space, str, sizeof(strbuffer1_space)) != 0)
|
||||
goto fail;
|
||||
free(str);
|
||||
str = nullptr;
|
||||
}
|
||||
rc = TRUE;
|
||||
fail:
|
||||
free(str);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL test_hex_string_to_bin(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
{
|
||||
const char stringbuffer[] = "123456789ABCDEFabcdef";
|
||||
const BYTE empty[1024] = WINPR_C_ARRAY_INIT;
|
||||
BYTE buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len = winpr_HexStringToBinBuffer(nullptr, 0, nullptr, 0);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(buffer, empty, sizeof(buffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(nullptr, sizeof(stringbuffer), buffer, sizeof(buffer));
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(buffer, empty, sizeof(buffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, 0, buffer, sizeof(buffer));
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(buffer, empty, sizeof(buffer)) != 0)
|
||||
goto fail;
|
||||
len =
|
||||
winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), nullptr, sizeof(buffer));
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(buffer, empty, sizeof(buffer)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer, 0);
|
||||
if (len != 0)
|
||||
goto fail;
|
||||
if (memcmp(buffer, empty, sizeof(buffer)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const char stringbuffer[] = "123456789ABCDEF1abcdef";
|
||||
const BYTE expected[] = {
|
||||
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1, 0xab, 0xcd, 0xef
|
||||
};
|
||||
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
|
||||
size_t len =
|
||||
winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer, sizeof(buffer));
|
||||
if (len != sizeof(expected))
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer,
|
||||
sizeof(expected) / 2);
|
||||
if (len != sizeof(expected) / 2)
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected) / 2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const char stringbuffer[] = "12 34 56 78 9A BC DE F1 ab cd ef";
|
||||
const BYTE expected[] = {
|
||||
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1, 0xab, 0xcd, 0xef
|
||||
};
|
||||
BYTE buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len =
|
||||
winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer, sizeof(buffer));
|
||||
if (len != sizeof(expected))
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer,
|
||||
sizeof(expected) / 2);
|
||||
if (len != sizeof(expected) / 2)
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected) / 2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const char stringbuffer[] = "123456789ABCDEF1abcdef9";
|
||||
const BYTE expected[] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
|
||||
0xde, 0xf1, 0xab, 0xcd, 0xef, 0x09 };
|
||||
BYTE buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len =
|
||||
winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer, sizeof(buffer));
|
||||
if (len != sizeof(expected))
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer,
|
||||
sizeof(expected) / 2);
|
||||
if (len != sizeof(expected) / 2)
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected) / 2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
const char stringbuffer[] = "12 34 56 78 9A BC DE F1 ab cd ef 9";
|
||||
const BYTE expected[] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
|
||||
0xde, 0xf1, 0xab, 0xcd, 0xef, 0x09 };
|
||||
BYTE buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t len =
|
||||
winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer, sizeof(buffer));
|
||||
if (len != sizeof(expected))
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected)) != 0)
|
||||
goto fail;
|
||||
len = winpr_HexStringToBinBuffer(stringbuffer, sizeof(stringbuffer), buffer,
|
||||
sizeof(expected) / 2);
|
||||
if (len != sizeof(expected) / 2)
|
||||
goto fail;
|
||||
if (memcmp(buffer, expected, sizeof(expected) / 2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestPrint(int argc, char* argv[])
|
||||
{
|
||||
int a = 0;
|
||||
int b = 0;
|
||||
float c = NAN;
|
||||
float d = NAN;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
/**
|
||||
* 7
|
||||
* 7
|
||||
* 007
|
||||
* 5.10
|
||||
*/
|
||||
|
||||
a = 15;
|
||||
b = a / 2;
|
||||
_printf("%d\n", b);
|
||||
_printf("%3d\n", b);
|
||||
_printf("%03d\n", b);
|
||||
c = 15.3f;
|
||||
d = c / 3.0f;
|
||||
_printf("%3.2f\n", d);
|
||||
|
||||
/**
|
||||
* 0 -17.778
|
||||
* 20 -6.667
|
||||
* 40 04.444
|
||||
* 60 15.556
|
||||
* 80 26.667
|
||||
* 100 37.778
|
||||
* 120 48.889
|
||||
* 140 60.000
|
||||
* 160 71.111
|
||||
* 180 82.222
|
||||
* 200 93.333
|
||||
* 220 104.444
|
||||
* 240 115.556
|
||||
* 260 126.667
|
||||
* 280 137.778
|
||||
* 300 148.889
|
||||
*/
|
||||
|
||||
for (int a = 0; a <= 300; a = a + 20)
|
||||
_printf("%3d %06.3f\n", a, (5.0 / 9.0) * (a - 32));
|
||||
|
||||
/**
|
||||
* The color: blue
|
||||
* First number: 12345
|
||||
* Second number: 0025
|
||||
* Third number: 1234
|
||||
* Float number: 3.14
|
||||
* Hexadecimal: ff
|
||||
* Octal: 377
|
||||
* Unsigned value: 150
|
||||
* Just print the percentage sign %
|
||||
*/
|
||||
|
||||
_printf("The color: %s\n", "blue");
|
||||
_printf("First number: %d\n", 12345);
|
||||
_printf("Second number: %04d\n", 25);
|
||||
_printf("Third number: %i\n", 1234);
|
||||
_printf("Float number: %3.2f\n", 3.14159);
|
||||
_printf("Hexadecimal: %x/%X\n", 255, 255);
|
||||
_printf("Octal: %o\n", 255);
|
||||
_printf("Unsigned value: %u\n", 150);
|
||||
_printf("Just print the percentage sign %%\n");
|
||||
|
||||
/**
|
||||
* :Hello, world!:
|
||||
* : Hello, world!:
|
||||
* :Hello, wor:
|
||||
* :Hello, world!:
|
||||
* :Hello, world! :
|
||||
* :Hello, world!:
|
||||
* : Hello, wor:
|
||||
* :Hello, wor :
|
||||
*/
|
||||
|
||||
_printf(":%s:\n", "Hello, world!");
|
||||
_printf(":%15s:\n", "Hello, world!");
|
||||
_printf(":%.10s:\n", "Hello, world!");
|
||||
_printf(":%-10s:\n", "Hello, world!");
|
||||
_printf(":%-15s:\n", "Hello, world!");
|
||||
_printf(":%.15s:\n", "Hello, world!");
|
||||
_printf(":%15.10s:\n", "Hello, world!");
|
||||
_printf(":%-15.10s:\n", "Hello, world!");
|
||||
|
||||
if (!test_bin_tohex_string())
|
||||
return -1;
|
||||
if (!test_bin_tohex_string_alloc())
|
||||
return -1;
|
||||
if (!test_hex_string_to_bin())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
75
third_party/FreeRDP/winpr/libwinpr/utils/test/TestPubSub.c
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
DEFINE_EVENT_BEGIN(MouseMotion)
|
||||
int x;
|
||||
int y;
|
||||
DEFINE_EVENT_END(MouseMotion)
|
||||
|
||||
DEFINE_EVENT_BEGIN(MouseButton)
|
||||
int x;
|
||||
int y;
|
||||
int flags;
|
||||
int button;
|
||||
DEFINE_EVENT_END(MouseButton)
|
||||
|
||||
static void MouseMotionEventHandler(void* context, const MouseMotionEventArgs* e)
|
||||
{
|
||||
printf("MouseMotionEvent: x: %d y: %d\n", e->x, e->y);
|
||||
}
|
||||
|
||||
static void MouseButtonEventHandler(void* context, const MouseButtonEventArgs* e)
|
||||
{
|
||||
printf("MouseButtonEvent: x: %d y: %d flags: %d button: %d\n", e->x, e->y, e->flags, e->button);
|
||||
}
|
||||
|
||||
static wEventType Node_Events[] = { DEFINE_EVENT_ENTRY(MouseMotion),
|
||||
DEFINE_EVENT_ENTRY(MouseButton) };
|
||||
|
||||
#define NODE_EVENT_COUNT (sizeof(Node_Events) / sizeof(wEventType))
|
||||
|
||||
int TestPubSub(int argc, char* argv[])
|
||||
{
|
||||
wPubSub* node = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
node = PubSub_New(TRUE);
|
||||
if (!node)
|
||||
return -1;
|
||||
|
||||
PubSub_AddEventTypes(node, Node_Events, NODE_EVENT_COUNT);
|
||||
|
||||
if (PubSub_SubscribeMouseMotion(node, MouseMotionEventHandler) < 0)
|
||||
return -1;
|
||||
if (PubSub_SubscribeMouseButton(node, MouseButtonEventHandler) < 0)
|
||||
return -1;
|
||||
|
||||
/* Call Event Handler */
|
||||
{
|
||||
MouseMotionEventArgs e;
|
||||
|
||||
e.x = 64;
|
||||
e.y = 128;
|
||||
|
||||
PubSub_OnMouseMotion(node, nullptr, &e);
|
||||
}
|
||||
|
||||
{
|
||||
MouseButtonEventArgs e;
|
||||
|
||||
e.x = 23;
|
||||
e.y = 56;
|
||||
e.flags = 7;
|
||||
e.button = 1;
|
||||
|
||||
PubSub_OnMouseButton(node, nullptr, &e);
|
||||
}
|
||||
|
||||
PubSub_Free(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
225
third_party/FreeRDP/winpr/libwinpr/utils/test/TestQueue.c
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
static bool wrap_test(bool (*fkt)(wQueue* queue))
|
||||
{
|
||||
wQueue* queue = Queue_New(TRUE, -1, -1);
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
WINPR_ASSERT(fkt);
|
||||
const bool rc = fkt(queue);
|
||||
Queue_Free(queue);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool check(const void* ptr, size_t pos)
|
||||
{
|
||||
if (!ptr)
|
||||
return false;
|
||||
if (ptr != (void*)(pos + 23))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool append(wQueue* queue, size_t pos)
|
||||
{
|
||||
void* ptr = (void*)(pos + 23);
|
||||
return Queue_Enqueue(queue, ptr);
|
||||
}
|
||||
|
||||
static bool fill_capcity(wQueue* queue, size_t* pos)
|
||||
{
|
||||
WINPR_ASSERT(pos);
|
||||
|
||||
size_t cpos = *pos;
|
||||
const size_t capacity = Queue_Capacity(queue);
|
||||
while (Queue_Count(queue) < capacity)
|
||||
{
|
||||
if (!append(queue, cpos++))
|
||||
return false;
|
||||
}
|
||||
*pos = cpos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drain(wQueue* queue, size_t expect)
|
||||
{
|
||||
void* ptr = Queue_Dequeue(queue);
|
||||
return check(ptr, expect);
|
||||
}
|
||||
|
||||
static bool drain_capcity(wQueue* queue, size_t remain, size_t* pos)
|
||||
{
|
||||
WINPR_ASSERT(pos);
|
||||
|
||||
size_t cpos = *pos;
|
||||
while (Queue_Count(queue) > remain)
|
||||
{
|
||||
if (!drain(queue, cpos++))
|
||||
return false;
|
||||
}
|
||||
*pos = cpos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_growth_move(wQueue* queue, bool big)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
const size_t cap = Queue_Capacity(queue);
|
||||
if (cap < 4)
|
||||
return false;
|
||||
|
||||
size_t wpos = 0;
|
||||
size_t rpos = 0;
|
||||
if (!fill_capcity(queue, &wpos))
|
||||
return false;
|
||||
|
||||
/* Ensure the (base) capacity is larger than the allocation step
|
||||
* so a full copy of tail will not be possible */
|
||||
if (big)
|
||||
{
|
||||
if (!append(queue, wpos++))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!drain_capcity(queue, 3, &rpos))
|
||||
return false;
|
||||
|
||||
if (!fill_capcity(queue, &wpos))
|
||||
return false;
|
||||
|
||||
if (!append(queue, wpos++))
|
||||
return false;
|
||||
|
||||
return drain_capcity(queue, 0, &rpos);
|
||||
}
|
||||
|
||||
static bool test_growth_big_move(wQueue* queue)
|
||||
{
|
||||
return test_growth_move(queue, true);
|
||||
}
|
||||
static bool test_growth_small_move(wQueue* queue)
|
||||
{
|
||||
return test_growth_move(queue, false);
|
||||
}
|
||||
|
||||
static bool check_size(wQueue* queue, size_t expected)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
const size_t count = Queue_Count(queue);
|
||||
printf("queue count: %" PRIuz "\n", count);
|
||||
return (count == expected);
|
||||
}
|
||||
|
||||
static bool enqueue(wQueue* queue, size_t val)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
void* ptr = (void*)(23 + val);
|
||||
return Queue_Enqueue(queue, ptr);
|
||||
}
|
||||
|
||||
static bool dequeue(wQueue* queue, size_t expected)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
const void* pexpect = (void*)(23 + expected);
|
||||
void* ptr = Queue_Dequeue(queue);
|
||||
return (pexpect == ptr);
|
||||
}
|
||||
|
||||
static bool legacy_test(wQueue* queue)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
for (size_t index = 1; index <= 10; index++)
|
||||
{
|
||||
if (!enqueue(queue, index))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_size(queue, 10))
|
||||
return false;
|
||||
|
||||
for (size_t index = 1; index <= 10; index++)
|
||||
{
|
||||
if (!dequeue(queue, index))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_size(queue, 0))
|
||||
return false;
|
||||
|
||||
if (!enqueue(queue, 1))
|
||||
return false;
|
||||
if (!enqueue(queue, 2))
|
||||
return false;
|
||||
if (!enqueue(queue, 3))
|
||||
return false;
|
||||
|
||||
if (!check_size(queue, 3))
|
||||
return false;
|
||||
|
||||
if (!dequeue(queue, 1))
|
||||
return false;
|
||||
if (!dequeue(queue, 2))
|
||||
return false;
|
||||
|
||||
if (!check_size(queue, 1))
|
||||
return false;
|
||||
|
||||
if (!enqueue(queue, 4))
|
||||
return false;
|
||||
if (!enqueue(queue, 5))
|
||||
return false;
|
||||
if (!enqueue(queue, 6))
|
||||
return false;
|
||||
|
||||
if (!check_size(queue, 4))
|
||||
return false;
|
||||
|
||||
if (!dequeue(queue, 3))
|
||||
return false;
|
||||
if (!dequeue(queue, 4))
|
||||
return false;
|
||||
if (!dequeue(queue, 5))
|
||||
return false;
|
||||
if (!dequeue(queue, 6))
|
||||
return false;
|
||||
|
||||
if (!check_size(queue, 0))
|
||||
return false;
|
||||
|
||||
Queue_Clear(queue);
|
||||
|
||||
if (!check_size(queue, 0))
|
||||
return false;
|
||||
|
||||
for (size_t x = 0; x < 32; x++)
|
||||
{
|
||||
void* ptr = (void*)(23 + x);
|
||||
if (!Queue_Enqueue(queue, ptr))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_size(queue, 32))
|
||||
return false;
|
||||
|
||||
Queue_Clear(queue);
|
||||
|
||||
return check_size(queue, 0);
|
||||
}
|
||||
|
||||
int TestQueue(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
|
||||
{
|
||||
if (!wrap_test(test_growth_big_move))
|
||||
return -1;
|
||||
if (!wrap_test(test_growth_small_move))
|
||||
return -2;
|
||||
if (!wrap_test(legacy_test))
|
||||
return -3;
|
||||
return 0;
|
||||
}
|
||||
859
third_party/FreeRDP/winpr/libwinpr/utils/test/TestStream.c
vendored
Normal file
@@ -0,0 +1,859 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
static BOOL TestStream_Verify(wStream* s, size_t mincap, size_t len, size_t pos)
|
||||
{
|
||||
if (Stream_Buffer(s) == nullptr)
|
||||
{
|
||||
printf("stream buffer is null\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_ConstPointer(s) == nullptr)
|
||||
{
|
||||
printf("stream pointer is null\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_PointerAs(s, BYTE) < Stream_Buffer(s))
|
||||
{
|
||||
printf("stream pointer (%p) or buffer (%p) is invalid\n", Stream_ConstPointer(s),
|
||||
(void*)Stream_Buffer(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_Capacity(s) < mincap)
|
||||
{
|
||||
printf("stream capacity is %" PRIuz " but minimum expected value is %" PRIuz "\n",
|
||||
Stream_Capacity(s), mincap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_Length(s) != len)
|
||||
{
|
||||
printf("stream has unexpected length (%" PRIuz " instead of %" PRIuz ")\n",
|
||||
Stream_Length(s), len);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_GetPosition(s) != pos)
|
||||
{
|
||||
printf("stream has unexpected position (%" PRIuz " instead of %" PRIuz ")\n",
|
||||
Stream_GetPosition(s), pos);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_GetPosition(s) > Stream_Length(s))
|
||||
{
|
||||
printf("stream position (%" PRIuz ") exceeds length (%" PRIuz ")\n", Stream_GetPosition(s),
|
||||
Stream_Length(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_GetPosition(s) > Stream_Capacity(s))
|
||||
{
|
||||
printf("stream position (%" PRIuz ") exceeds capacity (%" PRIuz ")\n",
|
||||
Stream_GetPosition(s), Stream_Capacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_Length(s) > Stream_Capacity(s))
|
||||
{
|
||||
printf("stream length (%" PRIuz ") exceeds capacity (%" PRIuz ")\n", Stream_Length(s),
|
||||
Stream_Capacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) != len - pos)
|
||||
{
|
||||
printf("stream remaining length (%" PRIuz " instead of %" PRIuz ")\n",
|
||||
Stream_GetRemainingLength(s), len - pos);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL TestStream_New(void)
|
||||
{
|
||||
/* Test creation of a 0-size stream with no buffer */
|
||||
wStream* s = Stream_New(nullptr, 0);
|
||||
|
||||
if (s)
|
||||
return FALSE;
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Static(void)
|
||||
{
|
||||
BYTE buffer[20] = WINPR_C_ARRAY_INIT;
|
||||
wStream staticStream = WINPR_C_ARRAY_INIT;
|
||||
wStream* s = &staticStream;
|
||||
UINT16 v = 0;
|
||||
/* Test creation of a static stream */
|
||||
Stream_StaticInit(s, buffer, sizeof(buffer));
|
||||
Stream_Write_UINT16(s, 0xcab1);
|
||||
Stream_ResetPosition(s);
|
||||
Stream_Read_UINT16(s, v);
|
||||
|
||||
if (v != 0xcab1)
|
||||
return FALSE;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
Stream_Write_UINT16(s, 1);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, 10)) /* we can ask for 10 bytes */
|
||||
return FALSE;
|
||||
|
||||
/* 30 is bigger than the buffer, it will be reallocated on the heap */
|
||||
if (!Stream_EnsureRemainingCapacity(s, 30) || !s->isOwner)
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT16(s, 2);
|
||||
Stream_ResetPosition(s);
|
||||
Stream_Read_UINT16(s, v);
|
||||
|
||||
if (v != 1)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, v);
|
||||
|
||||
if (v != 2)
|
||||
return FALSE;
|
||||
|
||||
// Intentional warning as the stream is not allocated.
|
||||
// Still, Stream_Free should not release such memory, therefore this statement
|
||||
// is required to test that.
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
Stream_Free(s, TRUE);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Create(size_t count, BOOL selfAlloc)
|
||||
{
|
||||
size_t len = 0;
|
||||
size_t cap = 0;
|
||||
wStream* s = nullptr;
|
||||
void* buffer = nullptr;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
len = cap = i + 1;
|
||||
|
||||
if (selfAlloc)
|
||||
{
|
||||
if (!(buffer = malloc(cap)))
|
||||
{
|
||||
printf("%s: failed to allocate buffer of size %" PRIuz "\n", __func__, cap);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(s = Stream_New(selfAlloc ? buffer : nullptr, len)))
|
||||
{
|
||||
printf("%s: Stream_New failed for stream #%" PRIuz "\n", __func__, i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!TestStream_Verify(s, cap, len, 0))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (size_t pos = 0; pos < len; pos++)
|
||||
{
|
||||
Stream_SetPosition(s, pos);
|
||||
Stream_SealLength(s);
|
||||
|
||||
if (!TestStream_Verify(s, cap, pos, pos))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (selfAlloc)
|
||||
{
|
||||
memset(buffer, (BYTE)(i % 256), cap);
|
||||
|
||||
if (memcmp(buffer, Stream_Buffer(s), cap) != 0)
|
||||
{
|
||||
printf("%s: buffer memory corruption\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, buffer == nullptr);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
free(buffer);
|
||||
|
||||
if (s)
|
||||
{
|
||||
Stream_Free(s, buffer == nullptr);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Extent(UINT32 maxSize)
|
||||
{
|
||||
wStream* s = nullptr;
|
||||
BOOL result = FALSE;
|
||||
|
||||
if (!(s = Stream_New(nullptr, 1)))
|
||||
{
|
||||
printf("%s: Stream_New failed\n", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (UINT32 i = 1; i < maxSize; i++)
|
||||
{
|
||||
if (i % 2)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, i))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Stream_EnsureCapacity(s, i))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Stream_SetPosition(s, i);
|
||||
Stream_SealLength(s);
|
||||
|
||||
if (!TestStream_Verify(s, i, i, i))
|
||||
{
|
||||
printf("%s: failed to verify stream in iteration %" PRIu32 "\n", __func__, i);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
result = TRUE;
|
||||
fail:
|
||||
|
||||
if (s)
|
||||
{
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define Stream_Peek_UINT8_BE Stream_Peek_UINT8
|
||||
#define Stream_Read_UINT8_BE Stream_Read_UINT8
|
||||
#define Stream_Peek_Get_UINT8_BE Stream_Peek_Get_UINT8
|
||||
#define Stream_Get_UINT8_BE Stream_Get_UINT8
|
||||
#define Stream_Peek_INT8_BE Stream_Peek_INT8
|
||||
#define Stream_Peek_Get_INT8_BE Stream_Peek_Get_INT8
|
||||
#define Stream_Read_INT8_BE Stream_Read_INT8
|
||||
#define Stream_Get_INT8_BE Stream_Get_INT8
|
||||
|
||||
#define TestStream_PeekAndRead(_s, _r, _t) \
|
||||
do \
|
||||
{ \
|
||||
_t _a = 0; \
|
||||
_t _b = 0; \
|
||||
BYTE* _p = Stream_Buffer(_s); \
|
||||
Stream_ResetPosition(_s); \
|
||||
Stream_Peek_##_t(_s, _a); \
|
||||
Stream_Read_##_t(_s, _b); \
|
||||
if (_a != _b) \
|
||||
{ \
|
||||
printf("%s: test1 " #_t "_LE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
} \
|
||||
Stream_Rewind(_s, sizeof(_t)); \
|
||||
const _t _d = Stream_Peek_Get_##_t(_s); \
|
||||
const _t _c = Stream_Get_##_t(_s); \
|
||||
if (_c != _d) \
|
||||
{ \
|
||||
printf("%s: test1 " #_t "_LE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
} \
|
||||
for (size_t _i = 0; _i < sizeof(_t); _i++) \
|
||||
{ \
|
||||
if (((_a >> (_i * 8)) & 0xFF) != _p[_i]) \
|
||||
{ \
|
||||
printf("%s: test2 " #_t "_LE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* printf("a: 0x%016llX\n", a); */ \
|
||||
Stream_ResetPosition(_s); \
|
||||
Stream_Peek_##_t##_BE(_s, _a); \
|
||||
Stream_Read_##_t##_BE(_s, _b); \
|
||||
if (_a != _b) \
|
||||
{ \
|
||||
printf("%s: test1 " #_t "_BE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
} \
|
||||
Stream_Rewind(_s, sizeof(_t)); \
|
||||
const _t _e = Stream_Peek_Get_##_t##_BE(_s); \
|
||||
const _t _f = Stream_Get_##_t##_BE(_s); \
|
||||
if (_e != _f) \
|
||||
{ \
|
||||
printf("%s: test1 " #_t "_BE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
} \
|
||||
for (size_t _i = 0; _i < sizeof(_t); _i++) \
|
||||
{ \
|
||||
if (((_a >> (_i * 8)) & 0xFF) != _p[sizeof(_t) - _i - 1]) \
|
||||
{ \
|
||||
printf("%s: test2 " #_t "_BE failed\n", __func__); \
|
||||
(_r) = FALSE; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* printf("a: 0x%016llX\n", a); */ \
|
||||
} while (0)
|
||||
|
||||
static BOOL TestStream_WriteAndRead(UINT64 value)
|
||||
{
|
||||
union
|
||||
{
|
||||
UINT8 u8;
|
||||
UINT16 u16;
|
||||
UINT32 u32;
|
||||
UINT64 u64;
|
||||
INT8 i8;
|
||||
INT16 i16;
|
||||
INT32 i32;
|
||||
INT64 i64;
|
||||
} val;
|
||||
val.u64 = value;
|
||||
|
||||
wStream* s = Stream_New(nullptr, 1024);
|
||||
if (!s)
|
||||
return FALSE;
|
||||
BOOL rc = FALSE;
|
||||
|
||||
{
|
||||
Stream_Write_UINT8(s, val.u8);
|
||||
Stream_Rewind_UINT8(s);
|
||||
const UINT8 ru8 = Stream_Get_UINT8(s);
|
||||
Stream_Rewind_UINT8(s);
|
||||
if (val.u8 != ru8)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT16(s, val.u16);
|
||||
Stream_Rewind_UINT16(s);
|
||||
const UINT16 ru = Stream_Get_UINT16(s);
|
||||
Stream_Rewind_UINT16(s);
|
||||
if (val.u16 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT16_BE(s, val.u16);
|
||||
Stream_Rewind_UINT16(s);
|
||||
const UINT16 ru = Stream_Get_UINT16_BE(s);
|
||||
Stream_Rewind_UINT16(s);
|
||||
if (val.u16 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT32(s, val.u32);
|
||||
Stream_Rewind_UINT32(s);
|
||||
const UINT32 ru = Stream_Get_UINT32(s);
|
||||
Stream_Rewind_UINT32(s);
|
||||
if (val.u32 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT32_BE(s, val.u32);
|
||||
Stream_Rewind_UINT32(s);
|
||||
const UINT32 ru = Stream_Get_UINT32_BE(s);
|
||||
Stream_Rewind_UINT32(s);
|
||||
if (val.u32 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT64(s, val.u64);
|
||||
Stream_Rewind_UINT64(s);
|
||||
const UINT64 ru = Stream_Get_UINT64(s);
|
||||
Stream_Rewind_UINT64(s);
|
||||
if (val.u64 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_UINT64_BE(s, val.u64);
|
||||
Stream_Rewind_UINT64(s);
|
||||
const UINT64 ru = Stream_Get_UINT64_BE(s);
|
||||
Stream_Rewind_UINT64(s);
|
||||
if (val.u64 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT8(s, val.i8);
|
||||
Stream_Rewind(s, 1);
|
||||
const INT8 ru8 = Stream_Get_INT8(s);
|
||||
Stream_Rewind(s, 1);
|
||||
if (val.i8 != ru8)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT16(s, val.i16);
|
||||
Stream_Rewind(s, 2);
|
||||
const INT16 ru = Stream_Get_INT16(s);
|
||||
Stream_Rewind(s, 2);
|
||||
if (val.i16 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT16_BE(s, val.i16);
|
||||
Stream_Rewind(s, 2);
|
||||
const INT16 ru = Stream_Get_INT16_BE(s);
|
||||
Stream_Rewind(s, 2);
|
||||
if (val.i16 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT32(s, val.i32);
|
||||
Stream_Rewind(s, 4);
|
||||
const INT32 ru = Stream_Get_INT32(s);
|
||||
Stream_Rewind(s, 4);
|
||||
if (val.i32 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT32_BE(s, val.i32);
|
||||
Stream_Rewind(s, 4);
|
||||
const INT32 ru = Stream_Get_INT32_BE(s);
|
||||
Stream_Rewind(s, 4);
|
||||
if (val.i32 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT64(s, val.i64);
|
||||
Stream_Rewind(s, 8);
|
||||
const INT64 ru = Stream_Get_INT64(s);
|
||||
Stream_Rewind(s, 8);
|
||||
if (val.i64 != ru)
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
Stream_Write_INT64_BE(s, val.i64);
|
||||
Stream_Rewind(s, 8);
|
||||
const INT64 ru = Stream_Get_INT64_BE(s);
|
||||
Stream_Rewind(s, 8);
|
||||
if (val.i64 != ru)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Reading(void)
|
||||
{
|
||||
BYTE src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
|
||||
wStream* s = nullptr;
|
||||
BOOL result = TRUE;
|
||||
|
||||
if (!(s = Stream_New(src, sizeof(src))))
|
||||
{
|
||||
printf("%s: Stream_New failed\n", __func__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TestStream_PeekAndRead(s, result, UINT8);
|
||||
TestStream_PeekAndRead(s, result, INT8);
|
||||
TestStream_PeekAndRead(s, result, UINT16);
|
||||
TestStream_PeekAndRead(s, result, INT16);
|
||||
TestStream_PeekAndRead(s, result, UINT32);
|
||||
TestStream_PeekAndRead(s, result, INT32);
|
||||
TestStream_PeekAndRead(s, result, UINT64);
|
||||
TestStream_PeekAndRead(s, result, INT64);
|
||||
Stream_Free(s, FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Write(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
UINT8 u8 = 0;
|
||||
UINT16 u16 = 0;
|
||||
UINT32 u32 = 0;
|
||||
UINT64 u64 = 0;
|
||||
const BYTE data[] = "someteststreamdata";
|
||||
wStream* s = Stream_New(nullptr, 100);
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Write(s, data, sizeof(data));
|
||||
|
||||
if (memcmp(Stream_Buffer(s), data, sizeof(data)) == 0)
|
||||
rc = TRUE;
|
||||
|
||||
if (s->pointer != s->buffer + sizeof(data))
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Write_UINT8(s, 42);
|
||||
|
||||
if (s->pointer != s->buffer + 1)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Peek_UINT8(s, u8);
|
||||
|
||||
if (u8 != 42)
|
||||
goto out;
|
||||
|
||||
Stream_Write_UINT16(s, 0x1234);
|
||||
|
||||
if (s->pointer != s->buffer + 2)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Peek_UINT16(s, u16);
|
||||
|
||||
if (u16 != 0x1234)
|
||||
goto out;
|
||||
|
||||
Stream_Write_UINT32(s, 0x12345678UL);
|
||||
|
||||
if (s->pointer != s->buffer + 4)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Peek_UINT32(s, u32);
|
||||
|
||||
if (u32 != 0x12345678UL)
|
||||
goto out;
|
||||
|
||||
Stream_Write_UINT64(s, 0x1234567890ABCDEFULL);
|
||||
|
||||
if (s->pointer != s->buffer + 8)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Peek_UINT64(s, u64);
|
||||
|
||||
if (u64 != 0x1234567890ABCDEFULL)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Seek(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wStream* s = Stream_New(nullptr, 100);
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Seek(s, 5);
|
||||
|
||||
if (s->pointer != s->buffer + 5)
|
||||
goto out;
|
||||
|
||||
Stream_Seek_UINT8(s);
|
||||
|
||||
if (s->pointer != s->buffer + 6)
|
||||
goto out;
|
||||
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
if (s->pointer != s->buffer + 8)
|
||||
goto out;
|
||||
|
||||
Stream_Seek_UINT32(s);
|
||||
|
||||
if (s->pointer != s->buffer + 12)
|
||||
goto out;
|
||||
|
||||
Stream_Seek_UINT64(s);
|
||||
|
||||
if (s->pointer != s->buffer + 20)
|
||||
goto out;
|
||||
|
||||
rc = TRUE;
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Rewind(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wStream* s = Stream_New(nullptr, 100);
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Seek(s, 100);
|
||||
|
||||
if (s->pointer != s->buffer + 100)
|
||||
goto out;
|
||||
|
||||
Stream_Rewind(s, 10);
|
||||
|
||||
if (s->pointer != s->buffer + 90)
|
||||
goto out;
|
||||
|
||||
Stream_Rewind_UINT8(s);
|
||||
|
||||
if (s->pointer != s->buffer + 89)
|
||||
goto out;
|
||||
|
||||
Stream_Rewind_UINT16(s);
|
||||
|
||||
if (s->pointer != s->buffer + 87)
|
||||
goto out;
|
||||
|
||||
Stream_Rewind_UINT32(s);
|
||||
|
||||
if (s->pointer != s->buffer + 83)
|
||||
goto out;
|
||||
|
||||
Stream_Rewind_UINT64(s);
|
||||
|
||||
if (s->pointer != s->buffer + 75)
|
||||
goto out;
|
||||
|
||||
rc = TRUE;
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Zero(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
const BYTE data[] = "someteststreamdata";
|
||||
wStream* s = Stream_New(nullptr, sizeof(data));
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
Stream_Write(s, data, sizeof(data));
|
||||
|
||||
if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Zero(s, 5);
|
||||
|
||||
if (s->pointer != s->buffer + 5)
|
||||
goto out;
|
||||
|
||||
if (memcmp(Stream_ConstPointer(s), data + 5, sizeof(data) - 5) != 0)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
for (UINT32 x = 0; x < 5; x++)
|
||||
{
|
||||
UINT8 val = 0;
|
||||
Stream_Read_UINT8(s, val);
|
||||
|
||||
if (val != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Fill(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
const BYTE fill[7] = "XXXXXXX";
|
||||
const BYTE data[] = "someteststreamdata";
|
||||
wStream* s = Stream_New(nullptr, sizeof(data));
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
Stream_Write(s, data, sizeof(data));
|
||||
|
||||
if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Fill(s, fill[0], sizeof(fill));
|
||||
|
||||
if (s->pointer != s->buffer + sizeof(fill))
|
||||
goto out;
|
||||
|
||||
if (memcmp(Stream_ConstPointer(s), data + sizeof(fill), sizeof(data) - sizeof(fill)) != 0)
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
if (memcmp(Stream_ConstPointer(s), fill, sizeof(fill)) != 0)
|
||||
goto out;
|
||||
|
||||
rc = TRUE;
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestStream_Copy(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
const BYTE data[] = "someteststreamdata";
|
||||
wStream* s = Stream_New(nullptr, sizeof(data));
|
||||
wStream* d = Stream_New(nullptr, sizeof(data));
|
||||
|
||||
if (!s || !d)
|
||||
goto out;
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Write(s, data, sizeof(data));
|
||||
|
||||
if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
|
||||
goto out;
|
||||
|
||||
if (s->pointer != s->buffer + sizeof(data))
|
||||
goto out;
|
||||
|
||||
Stream_ResetPosition(s);
|
||||
|
||||
if (s->pointer != s->buffer)
|
||||
goto out;
|
||||
|
||||
Stream_Copy(s, d, sizeof(data));
|
||||
|
||||
if (s->pointer != s->buffer + sizeof(data))
|
||||
goto out;
|
||||
|
||||
if (d->pointer != d->buffer + sizeof(data))
|
||||
goto out;
|
||||
|
||||
if (Stream_GetPosition(s) != Stream_GetPosition(d))
|
||||
goto out;
|
||||
|
||||
if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
|
||||
goto out;
|
||||
|
||||
if (memcmp(Stream_Buffer(d), data, sizeof(data)) != 0)
|
||||
goto out;
|
||||
|
||||
rc = TRUE;
|
||||
out:
|
||||
Stream_Free(s, TRUE);
|
||||
Stream_Free(d, TRUE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestStream(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!TestStream_Create(200, FALSE))
|
||||
return 1;
|
||||
|
||||
if (!TestStream_Create(200, TRUE))
|
||||
return 2;
|
||||
|
||||
if (!TestStream_Extent(4096))
|
||||
return 3;
|
||||
|
||||
if (!TestStream_Reading())
|
||||
return 4;
|
||||
|
||||
if (!TestStream_New())
|
||||
return 5;
|
||||
|
||||
if (!TestStream_Write())
|
||||
return 6;
|
||||
|
||||
if (!TestStream_Seek())
|
||||
return 7;
|
||||
|
||||
if (!TestStream_Rewind())
|
||||
return 8;
|
||||
|
||||
if (!TestStream_Zero())
|
||||
return 9;
|
||||
|
||||
if (!TestStream_Fill())
|
||||
return 10;
|
||||
|
||||
if (!TestStream_Copy())
|
||||
return 11;
|
||||
|
||||
if (!TestStream_Static())
|
||||
return 12;
|
||||
|
||||
if (!TestStream_WriteAndRead(0x1234567890abcdef))
|
||||
return 13;
|
||||
|
||||
for (size_t x = 0; x < 10; x++)
|
||||
{
|
||||
UINT64 val = 0;
|
||||
if (winpr_RAND(&val, sizeof(val)) < 0)
|
||||
return -1;
|
||||
if (!TestStream_WriteAndRead(val))
|
||||
return 14;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
82
third_party/FreeRDP/winpr/libwinpr/utils/test/TestStreamPool.c
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#define BUFFER_SIZE 16384
|
||||
|
||||
int TestStreamPool(int argc, char* argv[])
|
||||
{
|
||||
wStream* s[5] = WINPR_C_ARRAY_INIT;
|
||||
char buffer[8192] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
wStreamPool* pool = StreamPool_New(TRUE, BUFFER_SIZE);
|
||||
|
||||
s[0] = StreamPool_Take(pool, 0);
|
||||
s[1] = StreamPool_Take(pool, 0);
|
||||
s[2] = StreamPool_Take(pool, 0);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
Stream_Release(s[0]);
|
||||
Stream_Release(s[1]);
|
||||
Stream_Release(s[2]);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
s[3] = StreamPool_Take(pool, 0);
|
||||
s[4] = StreamPool_Take(pool, 0);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
Stream_Release(s[3]);
|
||||
Stream_Release(s[4]);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
s[2] = StreamPool_Take(pool, 0);
|
||||
s[3] = StreamPool_Take(pool, 0);
|
||||
s[4] = StreamPool_Take(pool, 0);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
Stream_AddRef(s[2]);
|
||||
|
||||
Stream_AddRef(s[3]);
|
||||
Stream_AddRef(s[3]);
|
||||
|
||||
Stream_AddRef(s[4]);
|
||||
Stream_AddRef(s[4]);
|
||||
Stream_AddRef(s[4]);
|
||||
|
||||
Stream_Release(s[2]);
|
||||
Stream_Release(s[2]);
|
||||
|
||||
Stream_Release(s[3]);
|
||||
Stream_Release(s[3]);
|
||||
Stream_Release(s[3]);
|
||||
|
||||
Stream_Release(s[4]);
|
||||
Stream_Release(s[4]);
|
||||
Stream_Release(s[4]);
|
||||
Stream_Release(s[4]);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
s[2] = StreamPool_Take(pool, 0);
|
||||
s[3] = StreamPool_Take(pool, 0);
|
||||
s[4] = StreamPool_Take(pool, 0);
|
||||
|
||||
printf("%s\n", StreamPool_GetStatistics(pool, buffer, sizeof(buffer)));
|
||||
|
||||
Stream_Release(s[2]);
|
||||
Stream_Release(s[3]);
|
||||
Stream_Release(s[4]);
|
||||
|
||||
StreamPool_Free(pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
third_party/FreeRDP/winpr/libwinpr/utils/test/TestVersion.c
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <winpr/version.h>
|
||||
#include <winpr/winpr.h>
|
||||
|
||||
int TestVersion(int argc, char* argv[])
|
||||
{
|
||||
const char* version = nullptr;
|
||||
const char* git = nullptr;
|
||||
const char* build = nullptr;
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int revision = 0;
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
winpr_get_version(&major, &minor, &revision);
|
||||
|
||||
if (major != WINPR_VERSION_MAJOR)
|
||||
return -1;
|
||||
|
||||
if (minor != WINPR_VERSION_MINOR)
|
||||
return -1;
|
||||
|
||||
if (revision != WINPR_VERSION_REVISION)
|
||||
return -1;
|
||||
|
||||
version = winpr_get_version_string();
|
||||
|
||||
if (!version)
|
||||
return -1;
|
||||
|
||||
git = winpr_get_build_revision();
|
||||
|
||||
if (!git)
|
||||
return -1;
|
||||
|
||||
if (strncmp(git, WINPR_GIT_REVISION, sizeof(WINPR_GIT_REVISION)) != 0)
|
||||
return -1;
|
||||
|
||||
build = winpr_get_build_config();
|
||||
|
||||
if (!build)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
69
third_party/FreeRDP/winpr/libwinpr/utils/test/TestWLog.c
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
int TestWLog(int argc, char* argv[])
|
||||
{
|
||||
wLog* root = nullptr;
|
||||
wLog* logA = nullptr;
|
||||
wLog* logB = nullptr;
|
||||
wLogLayout* layout = nullptr;
|
||||
wLogAppender* appender = nullptr;
|
||||
char* tmp_path = nullptr;
|
||||
char* wlog_file = nullptr;
|
||||
int result = 1;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!(tmp_path = GetKnownPath(KNOWN_PATH_TEMP)))
|
||||
{
|
||||
(void)fprintf(stderr, "Failed to get temporary directory!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
root = WLog_GetRoot();
|
||||
|
||||
WLog_SetLogAppenderType(root, WLOG_APPENDER_BINARY);
|
||||
|
||||
appender = WLog_GetLogAppender(root);
|
||||
if (!WLog_ConfigureAppender(appender, "outputfilename", "test_w.log"))
|
||||
goto out;
|
||||
if (!WLog_ConfigureAppender(appender, "outputfilepath", tmp_path))
|
||||
goto out;
|
||||
|
||||
layout = WLog_GetLogLayout(root);
|
||||
WLog_Layout_SetPrefixFormat(root, layout, "[%lv:%mn] [%fl|%fn|%ln] - ");
|
||||
|
||||
WLog_OpenAppender(root);
|
||||
|
||||
logA = WLog_Get("com.test.ChannelA");
|
||||
logB = WLog_Get("com.test.ChannelB");
|
||||
|
||||
WLog_SetLogLevel(logA, WLOG_INFO);
|
||||
WLog_SetLogLevel(logB, WLOG_ERROR);
|
||||
|
||||
WLog_Print(logA, WLOG_INFO, "this is a test");
|
||||
WLog_Print(logA, WLOG_WARN, "this is a %dnd %s", 2, "test");
|
||||
WLog_Print(logA, WLOG_ERROR, "this is an error");
|
||||
WLog_Print(logA, WLOG_TRACE, "this is a trace output");
|
||||
|
||||
WLog_Print(logB, WLOG_INFO, "just some info");
|
||||
WLog_Print(logB, WLOG_WARN, "we're warning a %dnd %s", 2, "time");
|
||||
WLog_Print(logB, WLOG_ERROR, "we've got an error");
|
||||
WLog_Print(logB, WLOG_TRACE, "leaving a trace behind");
|
||||
|
||||
WLog_CloseAppender(root);
|
||||
|
||||
if ((wlog_file = GetCombinedPath(tmp_path, "test_w.log")))
|
||||
winpr_DeleteFile(wlog_file);
|
||||
|
||||
result = 0;
|
||||
out:
|
||||
free(wlog_file);
|
||||
free(tmp_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
128
third_party/FreeRDP/winpr/libwinpr/utils/test/TestWLogCallback.c
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/tchar.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 level;
|
||||
char* msg;
|
||||
char* channel;
|
||||
} test_t;
|
||||
|
||||
static const char* function = nullptr;
|
||||
static const char* channels[] = { "com.test.channelA", "com.test.channelB" };
|
||||
|
||||
static const test_t messages[] = { { WLOG_INFO, "this is a test", "com.test.channelA" },
|
||||
{ WLOG_INFO, "Just some info", "com.test.channelB" },
|
||||
{ WLOG_WARN, "this is a %dnd %s", "com.test.channelA" },
|
||||
{ WLOG_WARN, "we're warning a %dnd %s", "com.test.channelB" },
|
||||
{ WLOG_ERROR, "this is an error", "com.test.channelA" },
|
||||
{ WLOG_ERROR, "we've got an error", "com.test.channelB" },
|
||||
{ WLOG_TRACE, "this is a trace output", "com.test.channelA" },
|
||||
{ WLOG_TRACE, "leaving a trace behind", "com.test.channelB" } };
|
||||
|
||||
static BOOL success = TRUE;
|
||||
static int pos = 0;
|
||||
|
||||
static BOOL check(const wLogMessage* msg)
|
||||
{
|
||||
BOOL rc = TRUE;
|
||||
if (!msg)
|
||||
rc = FALSE;
|
||||
else if (strcmp(msg->FileName, __FILE__) != 0)
|
||||
rc = FALSE;
|
||||
else if (strcmp(msg->FunctionName, function) != 0)
|
||||
rc = FALSE;
|
||||
else if (strcmp(msg->PrefixString, messages[pos].channel) != 0)
|
||||
rc = FALSE;
|
||||
else if (msg->Level != messages[pos].level)
|
||||
rc = FALSE;
|
||||
else if (strcmp(msg->FormatString, messages[pos].msg) != 0)
|
||||
rc = FALSE;
|
||||
pos++;
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
(void)fprintf(stderr, "Test failed!\n");
|
||||
success = FALSE;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL CallbackAppenderMessage(const wLogMessage* msg)
|
||||
{
|
||||
check(msg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL CallbackAppenderData(const wLogMessage* msg)
|
||||
{
|
||||
(void)fprintf(stdout, "%s\n", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL CallbackAppenderImage(const wLogMessage* msg)
|
||||
{
|
||||
(void)fprintf(stdout, "%s\n", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL CallbackAppenderPackage(const wLogMessage* msg)
|
||||
{
|
||||
(void)fprintf(stdout, "%s\n", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int TestWLogCallback(int argc, char* argv[])
|
||||
{
|
||||
wLog* root = nullptr;
|
||||
wLog* logA = nullptr;
|
||||
wLog* logB = nullptr;
|
||||
wLogLayout* layout = nullptr;
|
||||
wLogAppender* appender = nullptr;
|
||||
wLogCallbacks callbacks;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
function = __func__;
|
||||
|
||||
root = WLog_GetRoot();
|
||||
|
||||
WLog_SetLogAppenderType(root, WLOG_APPENDER_CALLBACK);
|
||||
|
||||
appender = WLog_GetLogAppender(root);
|
||||
|
||||
callbacks.data = CallbackAppenderData;
|
||||
callbacks.image = CallbackAppenderImage;
|
||||
callbacks.message = CallbackAppenderMessage;
|
||||
callbacks.package = CallbackAppenderPackage;
|
||||
|
||||
if (!WLog_ConfigureAppender(appender, "callbacks", (void*)&callbacks))
|
||||
return -1;
|
||||
|
||||
layout = WLog_GetLogLayout(root);
|
||||
WLog_Layout_SetPrefixFormat(root, layout, "%mn");
|
||||
|
||||
WLog_OpenAppender(root);
|
||||
|
||||
logA = WLog_Get(channels[0]);
|
||||
logB = WLog_Get(channels[1]);
|
||||
|
||||
WLog_SetLogLevel(logA, WLOG_TRACE);
|
||||
WLog_SetLogLevel(logB, WLOG_TRACE);
|
||||
|
||||
WLog_Print(logA, messages[0].level, messages[0].msg);
|
||||
WLog_Print(logB, messages[1].level, messages[1].msg);
|
||||
WLog_Print(logA, messages[2].level, messages[2].msg, 2, "test");
|
||||
WLog_Print(logB, messages[3].level, messages[3].msg, 2, "time");
|
||||
WLog_Print(logA, messages[4].level, messages[4].msg);
|
||||
WLog_Print(logB, messages[5].level, messages[5].msg);
|
||||
WLog_Print(logA, messages[6].level, messages[6].msg);
|
||||
WLog_Print(logB, messages[7].level, messages[7].msg);
|
||||
|
||||
WLog_CloseAppender(root);
|
||||
|
||||
return success ? 0 : -1;
|
||||
}
|
||||
105
third_party/FreeRDP/winpr/libwinpr/utils/test/img-cnv.c
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/image.h>
|
||||
|
||||
static const int formats[] = { WINPR_IMAGE_BITMAP, WINPR_IMAGE_PNG, WINPR_IMAGE_JPEG,
|
||||
WINPR_IMAGE_WEBP };
|
||||
|
||||
static void usage(int argc, char* argv[])
|
||||
{
|
||||
const char* prg = "INVALID";
|
||||
if (argc > 0)
|
||||
prg = argv[0];
|
||||
|
||||
(void)fprintf(stdout, "%s <src> <dst>\n", prg);
|
||||
(void)fprintf(stdout, "\tConvert image <src> to <dst>\n");
|
||||
(void)fprintf(stdout, "\tSupported formats (for this build):\n");
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(formats); x++)
|
||||
{
|
||||
const int format = formats[x];
|
||||
const char* ext = winpr_image_format_extension(format);
|
||||
const char* mime = winpr_image_format_mime(format);
|
||||
const BOOL supported = winpr_image_format_is_supported(format);
|
||||
if (supported)
|
||||
{
|
||||
(void)fprintf(stdout, "\t\t%s [.%s]\n", mime, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int detect_format(const char* name)
|
||||
{
|
||||
const char* dot = strrchr(name, '.');
|
||||
if (!dot)
|
||||
{
|
||||
(void)fprintf(stderr, "'%s' does not have a file extension\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(formats); x++)
|
||||
{
|
||||
const int format = formats[x];
|
||||
const char* ext = winpr_image_format_extension(format);
|
||||
const char* mime = winpr_image_format_mime(format);
|
||||
const BOOL supported = winpr_image_format_is_supported(format);
|
||||
if (strcmp(&dot[1], ext) == 0)
|
||||
{
|
||||
(void)fprintf(stdout, "'%s' is of format %s [supported:%s]\n", name, mime,
|
||||
supported ? "true" : "false");
|
||||
if (!supported)
|
||||
return -2;
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "'%s' is a unsupported format\n", name);
|
||||
return -3;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rc = -4;
|
||||
if (argc != 3)
|
||||
{
|
||||
usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* src = argv[1];
|
||||
const char* dst = argv[2];
|
||||
|
||||
const int sfmt = detect_format(src);
|
||||
const int dfmt = detect_format(dst);
|
||||
if ((sfmt < 0) || (dfmt < 0))
|
||||
{
|
||||
usage(argc, argv);
|
||||
return -2;
|
||||
}
|
||||
|
||||
wImage* img = winpr_image_new();
|
||||
if (!img)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
const int rrc = winpr_image_read(img, src);
|
||||
if (rrc <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "Failed to read image '%s': %d\n", src, rrc);
|
||||
goto fail;
|
||||
}
|
||||
const int wrc = winpr_image_write(img, dst);
|
||||
if (wrc <= 0)
|
||||
{
|
||||
(void)fprintf(stderr, "Failed to write image '%s': %d\n", dst, wrc);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void)fprintf(stdout, "Successfully converted '%s' to '%s'\n", src, dst);
|
||||
rc = 0;
|
||||
fail:
|
||||
winpr_image_free(img, TRUE);
|
||||
return rc;
|
||||
}
|
||||
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/lodepng_32bit.bmp
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/lodepng_32bit.png
vendored
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16a.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16a.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16x.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.16x.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.24.bmp
vendored
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.24.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.32.bmp
vendored
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.32.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.32x.bmp
vendored
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.32x.nocolor.bmp
vendored
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.bmp
vendored
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.jpg
vendored
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.png
vendored
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
third_party/FreeRDP/winpr/libwinpr/utils/test/rgb.webp
vendored
Normal file
|
After Width: | Height: | Size: 20 KiB |
206
third_party/FreeRDP/winpr/libwinpr/utils/unwind/debug.c
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Debugging helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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 _GNU_SOURCE
|
||||
#define _GNU_SOURCE // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#include <winpr/string.h>
|
||||
#include "debug.h"
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include "../log.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define TAG WINPR_TAG("utils.unwind")
|
||||
|
||||
#define UNWIND_MAX_LINE_SIZE 1024ULL
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uintptr_t uw;
|
||||
void* pv;
|
||||
} pc;
|
||||
union
|
||||
{
|
||||
uintptr_t uptr;
|
||||
void* pv;
|
||||
} langSpecificData;
|
||||
} unwind_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t pos;
|
||||
size_t size;
|
||||
unwind_info_t* info;
|
||||
} unwind_context_t;
|
||||
|
||||
static const char* unwind_reason_str(_Unwind_Reason_Code code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) && \
|
||||
!defined(__SEH__)
|
||||
case _URC_OK:
|
||||
return "_URC_OK";
|
||||
#else
|
||||
case _URC_NO_REASON:
|
||||
return "_URC_NO_REASON";
|
||||
case _URC_FATAL_PHASE2_ERROR:
|
||||
return "_URC_FATAL_PHASE2_ERROR";
|
||||
case _URC_FATAL_PHASE1_ERROR:
|
||||
return "_URC_FATAL_PHASE1_ERROR";
|
||||
case _URC_NORMAL_STOP:
|
||||
return "_URC_NORMAL_STOP";
|
||||
#endif
|
||||
case _URC_FOREIGN_EXCEPTION_CAUGHT:
|
||||
return "_URC_FOREIGN_EXCEPTION_CAUGHT";
|
||||
case _URC_END_OF_STACK:
|
||||
return "_URC_END_OF_STACK";
|
||||
case _URC_HANDLER_FOUND:
|
||||
return "_URC_HANDLER_FOUND";
|
||||
case _URC_INSTALL_CONTEXT:
|
||||
return "_URC_INSTALL_CONTEXT";
|
||||
case _URC_CONTINUE_UNWIND:
|
||||
return "_URC_CONTINUE_UNWIND";
|
||||
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) && \
|
||||
!defined(__SEH__)
|
||||
case _URC_FAILURE:
|
||||
return "_URC_FAILURE";
|
||||
#endif
|
||||
default:
|
||||
return "_URC_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* unwind_reason_str_buffer(_Unwind_Reason_Code code, char* buffer, size_t size)
|
||||
{
|
||||
const char* str = unwind_reason_str(code);
|
||||
(void)_snprintf(buffer, size, "%s [0x%02x]", str, code);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg)
|
||||
{
|
||||
unwind_context_t* ctx = arg;
|
||||
|
||||
assert(ctx);
|
||||
|
||||
if (ctx->pos < ctx->size)
|
||||
{
|
||||
unwind_info_t* info = &ctx->info[ctx->pos++];
|
||||
info->pc.uw = _Unwind_GetIP(context);
|
||||
|
||||
/* _Unwind_GetLanguageSpecificData has various return value definitions,
|
||||
* cast to the type we expect and disable linter warnings
|
||||
*/
|
||||
// NOLINTNEXTLINE(google-readability-casting,readability-redundant-casting)
|
||||
info->langSpecificData.pv = (void*)_Unwind_GetLanguageSpecificData(context);
|
||||
}
|
||||
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
void* winpr_unwind_backtrace(DWORD size)
|
||||
{
|
||||
_Unwind_Reason_Code rc = _URC_FOREIGN_EXCEPTION_CAUGHT;
|
||||
unwind_context_t* ctx = calloc(1, sizeof(unwind_context_t));
|
||||
if (!ctx)
|
||||
goto fail;
|
||||
ctx->size = size;
|
||||
ctx->info = calloc(size, sizeof(unwind_info_t));
|
||||
if (!ctx->info)
|
||||
goto fail;
|
||||
|
||||
rc = _Unwind_Backtrace(unwind_backtrace_callback, ctx);
|
||||
if (rc != _URC_END_OF_STACK)
|
||||
{
|
||||
/* https://github.com/FreeRDP/FreeRDP/issues/11490
|
||||
*
|
||||
* there seems to be no consensus on what to return from this function.
|
||||
* so we just warn about unexpected return codes and return the context regardless.
|
||||
*/
|
||||
char buffer[64] = WINPR_C_ARRAY_INIT;
|
||||
WLog_WARN(TAG, "_Unwind_Backtrace failed with %s",
|
||||
unwind_reason_str_buffer(rc, buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
return ctx;
|
||||
fail:
|
||||
winpr_unwind_backtrace_free(ctx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void winpr_unwind_backtrace_free(void* buffer)
|
||||
{
|
||||
unwind_context_t* ctx = buffer;
|
||||
if (!ctx)
|
||||
return;
|
||||
free(ctx->info);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
char** winpr_unwind_backtrace_symbols(void* buffer, size_t* used)
|
||||
{
|
||||
union
|
||||
{
|
||||
void* pv;
|
||||
char* cp;
|
||||
char** cpp;
|
||||
} cnv;
|
||||
unwind_context_t* ctx = buffer;
|
||||
cnv.cpp = nullptr;
|
||||
|
||||
if (!ctx)
|
||||
return nullptr;
|
||||
|
||||
cnv.pv = calloc(ctx->pos * (sizeof(char*) + UNWIND_MAX_LINE_SIZE), sizeof(char*));
|
||||
if (!cnv.pv)
|
||||
return nullptr;
|
||||
|
||||
if (used)
|
||||
*used = ctx->pos;
|
||||
|
||||
for (size_t x = 0; x < ctx->pos; x++)
|
||||
{
|
||||
char* msg = cnv.cp + ctx->pos * sizeof(char*) + x * UNWIND_MAX_LINE_SIZE;
|
||||
const unwind_info_t* info = &ctx->info[x];
|
||||
Dl_info dlinfo = WINPR_C_ARRAY_INIT;
|
||||
int rc = dladdr(info->pc.pv, &dlinfo);
|
||||
|
||||
cnv.cpp[x] = msg;
|
||||
|
||||
if (rc == 0)
|
||||
(void)_snprintf(msg, UNWIND_MAX_LINE_SIZE, "unresolvable, address=%p", info->pc.pv);
|
||||
else
|
||||
(void)_snprintf(msg, UNWIND_MAX_LINE_SIZE, "dli_fname=%s [%p], dli_sname=%s [%p]",
|
||||
dlinfo.dli_fname, dlinfo.dli_fbase, dlinfo.dli_sname, dlinfo.dli_saddr);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(clang-analyzer-unix.Malloc): function is an allocator
|
||||
return cnv.cpp;
|
||||
}
|
||||
47
third_party/FreeRDP/winpr/libwinpr/utils/unwind/debug.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Debugging helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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_DEBUG_UNWIND_H
|
||||
#define WINPR_DEBUG_UNWIND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
void winpr_unwind_backtrace_free(void* buffer);
|
||||
|
||||
WINPR_ATTR_MALLOC(winpr_unwind_backtrace_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
void* winpr_unwind_backtrace(DWORD size);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
char** winpr_unwind_backtrace_symbols(void* buffer, size_t* used);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_DEBUG_UNWIND_H */
|
||||
169
third_party/FreeRDP/winpr/libwinpr/utils/windows/debug.c
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Debugging Utils
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (a) < (b) ? (a) : (b)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PVOID* stack;
|
||||
ULONG used;
|
||||
ULONG max;
|
||||
} t_win_stack;
|
||||
|
||||
void winpr_win_backtrace_free(void* buffer)
|
||||
{
|
||||
t_win_stack* data = (t_win_stack*)buffer;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
free(data->stack);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void* winpr_win_backtrace(DWORD size)
|
||||
{
|
||||
HANDLE process = GetCurrentProcess();
|
||||
t_win_stack* data = calloc(1, sizeof(t_win_stack));
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
data->max = size;
|
||||
data->stack = calloc(data->max, sizeof(PVOID));
|
||||
|
||||
if (!data->stack)
|
||||
{
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SymInitialize(process, nullptr, TRUE);
|
||||
data->used = RtlCaptureStackBackTrace(2, size, data->stack, nullptr);
|
||||
return data;
|
||||
}
|
||||
|
||||
char** winpr_win_backtrace_symbols(void* buffer, size_t* used)
|
||||
{
|
||||
if (used)
|
||||
*used = 0;
|
||||
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
|
||||
{
|
||||
size_t line_len = 1024;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
t_win_stack* data = (t_win_stack*)buffer;
|
||||
size_t array_size = data->used * sizeof(char*);
|
||||
size_t lines_size = data->used * line_len;
|
||||
char** vlines = calloc(1, array_size + lines_size);
|
||||
SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char));
|
||||
IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64));
|
||||
|
||||
if (!vlines || !symbol || !line)
|
||||
{
|
||||
free(vlines);
|
||||
free(symbol);
|
||||
free(line);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
symbol->MaxNameLen = (ULONG)line_len;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
|
||||
/* Set the pointers in the allocated buffer's initial array section */
|
||||
for (size_t i = 0; i < data->used; i++)
|
||||
vlines[i] = (char*)vlines + array_size + i * line_len;
|
||||
|
||||
for (size_t i = 0; i < data->used; i++)
|
||||
{
|
||||
DWORD64 address = (DWORD64)(data->stack[i]);
|
||||
DWORD displacement;
|
||||
SymFromAddr(process, address, 0, symbol);
|
||||
|
||||
if (SymGetLineFromAddr64(process, address, &displacement, line))
|
||||
{
|
||||
sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address,
|
||||
symbol->Name, line->FileName, line->LineNumber);
|
||||
}
|
||||
else
|
||||
sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name);
|
||||
}
|
||||
|
||||
if (used)
|
||||
*used = data->used;
|
||||
|
||||
free(symbol);
|
||||
free(line);
|
||||
return vlines;
|
||||
}
|
||||
}
|
||||
|
||||
char* winpr_win_strerror(DWORD dw, char* dmsg, size_t size)
|
||||
{
|
||||
DWORD nSize = 0;
|
||||
DWORD dwFlags = 0;
|
||||
LPTSTR msg = nullptr;
|
||||
BOOL alloc = FALSE;
|
||||
dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
alloc = TRUE;
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
|
||||
#else
|
||||
nSize = (DWORD)(size * sizeof(WCHAR));
|
||||
msg = (LPTSTR)calloc(nSize, sizeof(WCHAR));
|
||||
#endif
|
||||
const DWORD rc =
|
||||
FormatMessage(dwFlags, nullptr, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, nullptr);
|
||||
|
||||
if (rc > 0)
|
||||
{
|
||||
#if defined(UNICODE)
|
||||
(void)WideCharToMultiByte(CP_ACP, 0, msg, (int)rc, dmsg, (int)(MIN(size - 1, INT_MAX)),
|
||||
nullptr, nullptr);
|
||||
#else /* defined(UNICODE) */
|
||||
memcpy(dmsg, msg, MIN(rc, size - 1));
|
||||
#endif /* defined(UNICODE) */
|
||||
dmsg[MIN(rc, size - 1)] = 0;
|
||||
#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
LocalFree(msg);
|
||||
#else
|
||||
free(msg);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError());
|
||||
}
|
||||
|
||||
return dmsg;
|
||||
}
|
||||
40
third_party/FreeRDP/winpr/libwinpr/utils/windows/debug.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Debugging helpers
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@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_DEBUG_WIN_H
|
||||
#define WINPR_DEBUG_WIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
void* winpr_win_backtrace(DWORD size);
|
||||
void winpr_win_backtrace_free(void* buffer);
|
||||
char** winpr_win_backtrace_symbols(void* buffer, size_t* used);
|
||||
char* winpr_win_strerror(DWORD dw, char* dmsg, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_DEBUG_WIN_H */
|
||||
185
third_party/FreeRDP/winpr/libwinpr/utils/winpr.c
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Debugging Utils
|
||||
*
|
||||
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2015 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/buildflags.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/version.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/build-config.h>
|
||||
|
||||
#include "../utils.h"
|
||||
|
||||
#if !defined(WIN32)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static INIT_ONCE s_winpr_app_details_once = INIT_ONCE_STATIC_INIT;
|
||||
static char s_winpr_vendor_string[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static char s_winpr_product_string[MAX_PATH] = WINPR_C_ARRAY_INIT;
|
||||
static SSIZE_T s_winpr_version = -1;
|
||||
static BOOL s_winpr_app_details_are_custom = FALSE;
|
||||
|
||||
static BOOL CALLBACK init_app_details(WINPR_ATTR_UNUSED PINIT_ONCE once,
|
||||
WINPR_ATTR_UNUSED PVOID param,
|
||||
WINPR_ATTR_UNUSED PVOID* context)
|
||||
{
|
||||
const size_t vlen = sizeof(WINPR_VENDOR_STRING);
|
||||
const size_t plen = sizeof(WINPR_PRODUCT_STRING);
|
||||
if (!strncpy(s_winpr_vendor_string, WINPR_VENDOR_STRING, vlen))
|
||||
return FALSE;
|
||||
|
||||
if (!strncpy(s_winpr_product_string, WINPR_PRODUCT_STRING, plen))
|
||||
return FALSE;
|
||||
|
||||
#if defined(WITH_RESOURCE_VERSIONING)
|
||||
s_winpr_version = WINPR_VERSION_MAJOR;
|
||||
#else
|
||||
s_winpr_version = -1;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL initializeApplicationDetails(void)
|
||||
{
|
||||
return InitOnceExecuteOnce(&s_winpr_app_details_once, init_app_details, nullptr, nullptr);
|
||||
}
|
||||
|
||||
BOOL winpr_setApplicationDetails(const char* vendor, const char* product, SSIZE_T version)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return -1;
|
||||
|
||||
if (!vendor || !product)
|
||||
return FALSE;
|
||||
const size_t vlen = strnlen(vendor, MAX_PATH);
|
||||
const size_t plen = strnlen(product, MAX_PATH);
|
||||
if ((vlen == MAX_PATH) || (plen == MAX_PATH))
|
||||
return FALSE;
|
||||
|
||||
if (!strncpy(s_winpr_vendor_string, vendor, vlen + 1))
|
||||
return FALSE;
|
||||
|
||||
if (!strncpy(s_winpr_product_string, product, plen + 1))
|
||||
return FALSE;
|
||||
|
||||
s_winpr_version = version;
|
||||
s_winpr_app_details_are_custom = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char* winpr_getApplicationDetailsVendor(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return nullptr;
|
||||
return s_winpr_vendor_string;
|
||||
}
|
||||
|
||||
const char* winpr_getApplicationDetailsProduct(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return nullptr;
|
||||
return s_winpr_product_string;
|
||||
}
|
||||
|
||||
char* winpr_getApplicatonDetailsRegKey(const char* fmt)
|
||||
{
|
||||
char* val = winpr_getApplicatonDetailsCombined('\\');
|
||||
if (!val)
|
||||
return nullptr;
|
||||
|
||||
char* str = nullptr;
|
||||
size_t slen = 0;
|
||||
(void)winpr_asprintf(&str, &slen, fmt, val);
|
||||
free(val);
|
||||
return str;
|
||||
}
|
||||
|
||||
char* winpr_getApplicatonDetailsCombined(char separator)
|
||||
{
|
||||
const SSIZE_T version = winpr_getApplicationDetailsVersion();
|
||||
const char* vendor = winpr_getApplicationDetailsVendor();
|
||||
const char* product = winpr_getApplicationDetailsProduct();
|
||||
|
||||
size_t slen = 0;
|
||||
char* str = nullptr;
|
||||
if (version < 0)
|
||||
{
|
||||
(void)winpr_asprintf(&str, &slen, "%s%c%s", vendor, separator, product);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)winpr_asprintf(&str, &slen, "%s%c%s%" PRIdz, vendor, separator, product, version);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
SSIZE_T winpr_getApplicationDetailsVersion(void)
|
||||
{
|
||||
if (!initializeApplicationDetails())
|
||||
return -1;
|
||||
return s_winpr_version;
|
||||
}
|
||||
|
||||
BOOL winpr_areApplicationDetailsCustomized(void)
|
||||
{
|
||||
return s_winpr_app_details_are_custom;
|
||||
}
|
||||
|
||||
void winpr_get_version(int* major, int* minor, int* revision)
|
||||
{
|
||||
if (major)
|
||||
*major = WINPR_VERSION_MAJOR;
|
||||
if (minor)
|
||||
*minor = WINPR_VERSION_MINOR;
|
||||
if (revision)
|
||||
*revision = WINPR_VERSION_REVISION;
|
||||
}
|
||||
|
||||
const char* winpr_get_version_string(void)
|
||||
{
|
||||
return WINPR_VERSION_FULL;
|
||||
}
|
||||
|
||||
const char* winpr_get_build_revision(void)
|
||||
{
|
||||
return WINPR_GIT_REVISION;
|
||||
}
|
||||
|
||||
const char* winpr_get_build_config(void)
|
||||
{
|
||||
static const char build_config[] =
|
||||
"Build configuration: " WINPR_BUILD_CONFIG "\n"
|
||||
"Build type: " WINPR_BUILD_TYPE "\n"
|
||||
"CFLAGS: " WINPR_CFLAGS "\n"
|
||||
"Compiler: " WINPR_COMPILER_ID ", " WINPR_COMPILER_VERSION "\n"
|
||||
"Target architecture: " WINPR_TARGET_ARCH "\n";
|
||||
|
||||
return build_config;
|
||||
}
|
||||
181
third_party/FreeRDP/winpr/libwinpr/utils/wlog/Appender.c
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include "Appender.h"
|
||||
|
||||
void WLog_Appender_Free(wLog* log, wLogAppender* appender)
|
||||
{
|
||||
if (!appender)
|
||||
return;
|
||||
|
||||
if (appender->Layout)
|
||||
{
|
||||
WLog_Layout_Free(log, appender->Layout);
|
||||
appender->Layout = nullptr;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&appender->lock);
|
||||
appender->Free(appender);
|
||||
}
|
||||
|
||||
wLogAppender* WLog_GetLogAppender(wLog* log)
|
||||
{
|
||||
if (!log)
|
||||
return nullptr;
|
||||
|
||||
if (!log->Appender)
|
||||
return WLog_GetLogAppender(log->Parent);
|
||||
|
||||
return log->Appender;
|
||||
}
|
||||
|
||||
BOOL WLog_OpenAppender(wLog* log)
|
||||
{
|
||||
int status = 0;
|
||||
wLogAppender* appender = nullptr;
|
||||
|
||||
appender = WLog_GetLogAppender(log);
|
||||
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
if (!appender->Open)
|
||||
return TRUE;
|
||||
|
||||
if (!appender->active)
|
||||
{
|
||||
status = appender->Open(log, appender);
|
||||
appender->active = TRUE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL WLog_CloseAppender(wLog* log)
|
||||
{
|
||||
int status = 0;
|
||||
wLogAppender* appender = nullptr;
|
||||
|
||||
appender = WLog_GetLogAppender(log);
|
||||
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
if (!appender->Close)
|
||||
return TRUE;
|
||||
|
||||
if (appender->active)
|
||||
{
|
||||
status = appender->Close(log, appender);
|
||||
appender->active = FALSE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static wLogAppender* WLog_Appender_New(wLog* log, DWORD logAppenderType)
|
||||
{
|
||||
wLogAppender* appender = nullptr;
|
||||
|
||||
if (!log)
|
||||
return nullptr;
|
||||
|
||||
switch (logAppenderType)
|
||||
{
|
||||
case WLOG_APPENDER_CONSOLE:
|
||||
appender = WLog_ConsoleAppender_New(log);
|
||||
break;
|
||||
case WLOG_APPENDER_FILE:
|
||||
appender = WLog_FileAppender_New(log);
|
||||
break;
|
||||
case WLOG_APPENDER_BINARY:
|
||||
appender = WLog_BinaryAppender_New(log);
|
||||
break;
|
||||
case WLOG_APPENDER_CALLBACK:
|
||||
appender = WLog_CallbackAppender_New(log);
|
||||
break;
|
||||
#ifdef WINPR_HAVE_SYSLOG_H
|
||||
case WLOG_APPENDER_SYSLOG:
|
||||
appender = WLog_SyslogAppender_New(log);
|
||||
break;
|
||||
#endif
|
||||
#ifdef WINPR_HAVE_JOURNALD_H
|
||||
case WLOG_APPENDER_JOURNALD:
|
||||
appender = WLog_JournaldAppender_New(log);
|
||||
break;
|
||||
#endif
|
||||
case WLOG_APPENDER_UDP:
|
||||
appender = WLog_UdpAppender_New(log);
|
||||
break;
|
||||
default:
|
||||
(void)fprintf(stderr, "%s: unknown handler type %" PRIu32 "\n", __func__,
|
||||
logAppenderType);
|
||||
appender = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!appender)
|
||||
appender = WLog_ConsoleAppender_New(log);
|
||||
|
||||
if (!appender)
|
||||
return nullptr;
|
||||
|
||||
if (!(appender->Layout = WLog_Layout_New(log)))
|
||||
{
|
||||
WLog_Appender_Free(log, appender);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&appender->lock, 4000))
|
||||
{
|
||||
WLog_Appender_Free(log, appender);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return appender;
|
||||
}
|
||||
|
||||
BOOL WLog_SetLogAppenderType(wLog* log, DWORD logAppenderType)
|
||||
{
|
||||
if (!log)
|
||||
return FALSE;
|
||||
|
||||
if (log->Appender)
|
||||
{
|
||||
WLog_Appender_Free(log, log->Appender);
|
||||
log->Appender = nullptr;
|
||||
}
|
||||
|
||||
log->Appender = WLog_Appender_New(log, logAppenderType);
|
||||
return log->Appender != nullptr;
|
||||
}
|
||||
|
||||
BOOL WLog_ConfigureAppender(wLogAppender* appender, const char* setting, void* value)
|
||||
{
|
||||
/* Just check the settings string is not empty */
|
||||
if (!appender || !setting || (strnlen(setting, 2) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (appender->Set)
|
||||
return appender->Set(appender, setting, value);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
39
third_party/FreeRDP/winpr/libwinpr/utils/wlog/Appender.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_WLOG_APPENDER_PRIVATE_H
|
||||
#define WINPR_WLOG_APPENDER_PRIVATE_H
|
||||
|
||||
#include "wlog.h"
|
||||
|
||||
WINPR_LOCAL void WLog_Appender_Free(wLog* log, wLogAppender* appender);
|
||||
|
||||
#include "FileAppender.h"
|
||||
#include "ConsoleAppender.h"
|
||||
#include "BinaryAppender.h"
|
||||
#include "CallbackAppender.h"
|
||||
#ifdef WINPR_HAVE_JOURNALD_H
|
||||
#include "JournaldAppender.h"
|
||||
#endif
|
||||
#ifdef WINPR_HAVE_SYSLOG_H
|
||||
#include "SyslogAppender.h"
|
||||
#endif
|
||||
#include "UdpAppender.h"
|
||||
|
||||
#endif /* WINPR_WLOG_APPENDER_PRIVATE_H */
|
||||
236
third_party/FreeRDP/winpr/libwinpr/utils/wlog/BinaryAppender.c
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 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 "BinaryAppender.h"
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
wLogAppender common;
|
||||
|
||||
char* FileName;
|
||||
char* FilePath;
|
||||
char* FullFileName;
|
||||
FILE* FileDescriptor;
|
||||
} wLogBinaryAppender;
|
||||
|
||||
static BOOL WLog_BinaryAppender_Open(wLog* log, wLogAppender* appender)
|
||||
{
|
||||
wLogBinaryAppender* binaryAppender = nullptr;
|
||||
if (!log || !appender)
|
||||
return FALSE;
|
||||
|
||||
binaryAppender = (wLogBinaryAppender*)appender;
|
||||
if (!binaryAppender->FileName)
|
||||
{
|
||||
binaryAppender->FileName = (char*)malloc(MAX_PATH);
|
||||
if (!binaryAppender->FileName)
|
||||
return FALSE;
|
||||
(void)sprintf_s(binaryAppender->FileName, MAX_PATH, "%" PRIu32 ".wlog",
|
||||
GetCurrentProcessId());
|
||||
}
|
||||
|
||||
if (!binaryAppender->FilePath)
|
||||
{
|
||||
binaryAppender->FilePath = GetKnownSubPath(KNOWN_PATH_TEMP, "wlog");
|
||||
if (!binaryAppender->FilePath)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!binaryAppender->FullFileName)
|
||||
{
|
||||
binaryAppender->FullFileName =
|
||||
GetCombinedPath(binaryAppender->FilePath, binaryAppender->FileName);
|
||||
if (!binaryAppender->FullFileName)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!winpr_PathFileExists(binaryAppender->FilePath))
|
||||
{
|
||||
if (!winpr_PathMakePath(binaryAppender->FilePath, nullptr))
|
||||
return FALSE;
|
||||
UnixChangeFileMode(binaryAppender->FilePath, 0xFFFF);
|
||||
}
|
||||
|
||||
binaryAppender->FileDescriptor = winpr_fopen(binaryAppender->FullFileName, "a+");
|
||||
|
||||
return binaryAppender->FileDescriptor != nullptr;
|
||||
}
|
||||
|
||||
static BOOL WLog_BinaryAppender_Close(WINPR_ATTR_UNUSED wLog* log, wLogAppender* appender)
|
||||
{
|
||||
wLogBinaryAppender* binaryAppender = nullptr;
|
||||
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
binaryAppender = (wLogBinaryAppender*)appender;
|
||||
if (!binaryAppender->FileDescriptor)
|
||||
return TRUE;
|
||||
|
||||
if (binaryAppender->FileDescriptor)
|
||||
(void)fclose(binaryAppender->FileDescriptor);
|
||||
|
||||
binaryAppender->FileDescriptor = nullptr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_BinaryAppender_WriteMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* message)
|
||||
{
|
||||
FILE* fp = nullptr;
|
||||
wStream* s = nullptr;
|
||||
size_t MessageLength = 0;
|
||||
size_t FileNameLength = 0;
|
||||
size_t FunctionNameLength = 0;
|
||||
size_t TextStringLength = 0;
|
||||
BOOL ret = TRUE;
|
||||
wLogBinaryAppender* binaryAppender = nullptr;
|
||||
|
||||
if (!log || !appender || !message)
|
||||
return FALSE;
|
||||
|
||||
binaryAppender = (wLogBinaryAppender*)appender;
|
||||
|
||||
fp = binaryAppender->FileDescriptor;
|
||||
|
||||
if (!fp)
|
||||
return FALSE;
|
||||
|
||||
FileNameLength = strnlen(message->FileName, INT_MAX);
|
||||
FunctionNameLength = strnlen(message->FunctionName, INT_MAX);
|
||||
TextStringLength = strnlen(message->TextString, INT_MAX);
|
||||
|
||||
MessageLength =
|
||||
16 + (4 + FileNameLength + 1) + (4 + FunctionNameLength + 1) + (4 + TextStringLength + 1);
|
||||
|
||||
if ((MessageLength > UINT32_MAX) || (FileNameLength > UINT32_MAX) ||
|
||||
(FunctionNameLength > UINT32_MAX) || (TextStringLength > UINT32_MAX))
|
||||
return FALSE;
|
||||
|
||||
s = Stream_New(nullptr, MessageLength);
|
||||
if (!s)
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT32(s, (UINT32)MessageLength);
|
||||
|
||||
Stream_Write_UINT32(s, message->Type);
|
||||
Stream_Write_UINT32(s, message->Level);
|
||||
|
||||
WINPR_ASSERT(message->LineNumber <= UINT32_MAX);
|
||||
Stream_Write_UINT32(s, (UINT32)message->LineNumber);
|
||||
|
||||
Stream_Write_UINT32(s, (UINT32)FileNameLength);
|
||||
Stream_Write(s, message->FileName, FileNameLength + 1);
|
||||
|
||||
Stream_Write_UINT32(s, (UINT32)FunctionNameLength);
|
||||
Stream_Write(s, message->FunctionName, FunctionNameLength + 1);
|
||||
|
||||
Stream_Write_UINT32(s, (UINT32)TextStringLength);
|
||||
Stream_Write(s, message->TextString, TextStringLength + 1);
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
if (fwrite(Stream_Buffer(s), MessageLength, 1, fp) != 1)
|
||||
ret = FALSE;
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WLog_BinaryAppender_WriteDataMessage(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender,
|
||||
WINPR_ATTR_UNUSED const wLogMessage* message)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_BinaryAppender_WriteImageMessage(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender,
|
||||
WINPR_ATTR_UNUSED const wLogMessage* message)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_BinaryAppender_Set(wLogAppender* appender, const char* setting, void* value)
|
||||
{
|
||||
wLogBinaryAppender* binaryAppender = (wLogBinaryAppender*)appender;
|
||||
|
||||
/* Just check if the value string is longer than 0 */
|
||||
if (!value || (strnlen(value, 2) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (!strcmp("outputfilename", setting))
|
||||
{
|
||||
binaryAppender->FileName = _strdup((const char*)value);
|
||||
if (!binaryAppender->FileName)
|
||||
return FALSE;
|
||||
}
|
||||
else if (!strcmp("outputfilepath", setting))
|
||||
{
|
||||
binaryAppender->FilePath = _strdup((const char*)value);
|
||||
if (!binaryAppender->FilePath)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WLog_BinaryAppender_Free(wLogAppender* appender)
|
||||
{
|
||||
wLogBinaryAppender* binaryAppender = nullptr;
|
||||
if (appender)
|
||||
{
|
||||
binaryAppender = (wLogBinaryAppender*)appender;
|
||||
free(binaryAppender->FileName);
|
||||
free(binaryAppender->FilePath);
|
||||
free(binaryAppender->FullFileName);
|
||||
free(binaryAppender);
|
||||
}
|
||||
}
|
||||
|
||||
wLogAppender* WLog_BinaryAppender_New(WINPR_ATTR_UNUSED wLog* log)
|
||||
{
|
||||
wLogBinaryAppender* BinaryAppender = (wLogBinaryAppender*)calloc(1, sizeof(wLogBinaryAppender));
|
||||
if (!BinaryAppender)
|
||||
return nullptr;
|
||||
|
||||
BinaryAppender->common.Type = WLOG_APPENDER_BINARY;
|
||||
BinaryAppender->common.Open = WLog_BinaryAppender_Open;
|
||||
BinaryAppender->common.Close = WLog_BinaryAppender_Close;
|
||||
BinaryAppender->common.WriteMessage = WLog_BinaryAppender_WriteMessage;
|
||||
BinaryAppender->common.WriteDataMessage = WLog_BinaryAppender_WriteDataMessage;
|
||||
BinaryAppender->common.WriteImageMessage = WLog_BinaryAppender_WriteImageMessage;
|
||||
BinaryAppender->common.Free = WLog_BinaryAppender_Free;
|
||||
BinaryAppender->common.Set = WLog_BinaryAppender_Set;
|
||||
|
||||
return &BinaryAppender->common;
|
||||
}
|
||||
29
third_party/FreeRDP/winpr/libwinpr/utils/wlog/BinaryAppender.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_WLOG_BINARY_APPENDER_PRIVATE_H
|
||||
#define WINPR_WLOG_BINARY_APPENDER_PRIVATE_H
|
||||
|
||||
#include "wlog.h"
|
||||
|
||||
WINPR_ATTR_MALLOC(WLog_Appender_Free, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
WINPR_LOCAL wLogAppender* WLog_BinaryAppender_New(wLog* log);
|
||||
|
||||
#endif /* WINPR_WLOG_BINARY_APPENDER_PRIVATE_H */
|
||||
175
third_party/FreeRDP/winpr/libwinpr/utils/wlog/CallbackAppender.c
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@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 "CallbackAppender.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
wLogAppender common;
|
||||
|
||||
wLogCallbacks* callbacks;
|
||||
} wLogCallbackAppender;
|
||||
|
||||
static BOOL WLog_CallbackAppender_Open(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_Close(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_WriteMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* cmessage)
|
||||
{
|
||||
WINPR_ASSERT(cmessage);
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
|
||||
|
||||
wLogCallbackAppender* callbackAppender = (wLogCallbackAppender*)appender;
|
||||
|
||||
if (callbackAppender->callbacks && callbackAppender->callbacks->message)
|
||||
{
|
||||
wLogMessage message = *cmessage;
|
||||
message.PrefixString = prefix;
|
||||
return callbackAppender->callbacks->message(&message);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_WriteDataMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* cmessage)
|
||||
{
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
|
||||
|
||||
wLogCallbackAppender* callbackAppender = (wLogCallbackAppender*)appender;
|
||||
if (callbackAppender->callbacks && callbackAppender->callbacks->data)
|
||||
{
|
||||
wLogMessage message = *cmessage;
|
||||
message.PrefixString = prefix;
|
||||
return callbackAppender->callbacks->data(&message);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_WriteImageMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* cmessage)
|
||||
{
|
||||
WINPR_ASSERT(cmessage);
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
|
||||
|
||||
wLogCallbackAppender* callbackAppender = (wLogCallbackAppender*)appender;
|
||||
if (callbackAppender->callbacks && callbackAppender->callbacks->image)
|
||||
{
|
||||
wLogMessage message = *cmessage;
|
||||
message.PrefixString = prefix;
|
||||
return callbackAppender->callbacks->image(&message);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_WritePacketMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* cmessage)
|
||||
{
|
||||
WINPR_ASSERT(cmessage);
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
|
||||
|
||||
wLogCallbackAppender* callbackAppender = (wLogCallbackAppender*)appender;
|
||||
if (callbackAppender->callbacks && callbackAppender->callbacks->package)
|
||||
{
|
||||
wLogMessage message = *cmessage;
|
||||
message.PrefixString = prefix;
|
||||
return callbackAppender->callbacks->package(&message);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WLog_CallbackAppender_Set(wLogAppender* appender, const char* setting, void* value)
|
||||
{
|
||||
wLogCallbackAppender* callbackAppender = (wLogCallbackAppender*)appender;
|
||||
|
||||
if (!value || (strcmp(setting, "callbacks") != 0))
|
||||
return FALSE;
|
||||
|
||||
if (!(callbackAppender->callbacks = calloc(1, sizeof(wLogCallbacks))))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
callbackAppender->callbacks = memcpy(callbackAppender->callbacks, value, sizeof(wLogCallbacks));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WLog_CallbackAppender_Free(wLogAppender* appender)
|
||||
{
|
||||
wLogCallbackAppender* callbackAppender = nullptr;
|
||||
if (!appender)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
callbackAppender = (wLogCallbackAppender*)appender;
|
||||
|
||||
free(callbackAppender->callbacks);
|
||||
free(appender);
|
||||
}
|
||||
|
||||
wLogAppender* WLog_CallbackAppender_New(WINPR_ATTR_UNUSED wLog* log)
|
||||
{
|
||||
wLogCallbackAppender* CallbackAppender =
|
||||
(wLogCallbackAppender*)calloc(1, sizeof(wLogCallbackAppender));
|
||||
if (!CallbackAppender)
|
||||
return nullptr;
|
||||
|
||||
CallbackAppender->common.Type = WLOG_APPENDER_CALLBACK;
|
||||
CallbackAppender->common.Open = WLog_CallbackAppender_Open;
|
||||
CallbackAppender->common.Close = WLog_CallbackAppender_Close;
|
||||
CallbackAppender->common.WriteMessage = WLog_CallbackAppender_WriteMessage;
|
||||
CallbackAppender->common.WriteDataMessage = WLog_CallbackAppender_WriteDataMessage;
|
||||
CallbackAppender->common.WriteImageMessage = WLog_CallbackAppender_WriteImageMessage;
|
||||
CallbackAppender->common.WritePacketMessage = WLog_CallbackAppender_WritePacketMessage;
|
||||
CallbackAppender->common.Free = WLog_CallbackAppender_Free;
|
||||
CallbackAppender->common.Set = WLog_CallbackAppender_Set;
|
||||
|
||||
return &CallbackAppender->common;
|
||||
}
|
||||
29
third_party/FreeRDP/winpr/libwinpr/utils/wlog/CallbackAppender.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2014 Armin Novak <armin.novak@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.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_WLOG_CALLBACK_APPENDER_PRIVATE_H
|
||||
#define WINPR_WLOG_CALLBACK_APPENDER_PRIVATE_H
|
||||
|
||||
#include "wlog.h"
|
||||
|
||||
WINPR_ATTR_MALLOC(WLog_Appender_Free, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
WINPR_LOCAL wLogAppender* WLog_CallbackAppender_New(wLog* log);
|
||||
|
||||
#endif /* WINPR_WLOG_CALLBACK_APPENDER_PRIVATE_H */
|
||||
276
third_party/FreeRDP/winpr/libwinpr/utils/wlog/ConsoleAppender.c
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include "ConsoleAppender.h"
|
||||
#include "Message.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#define WLOG_CONSOLE_DEFAULT 0
|
||||
#define WLOG_CONSOLE_STDOUT 1
|
||||
#define WLOG_CONSOLE_STDERR 2
|
||||
#define WLOG_CONSOLE_DEBUG 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
wLogAppender common;
|
||||
|
||||
int outputStream;
|
||||
} wLogConsoleAppender;
|
||||
|
||||
static BOOL WLog_ConsoleAppender_Open(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_ConsoleAppender_Close(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WLog_ConsoleAppender_WriteMessage(wLog* log, wLogAppender* appender,
|
||||
const wLogMessage* cmessage)
|
||||
{
|
||||
if (!appender)
|
||||
return FALSE;
|
||||
|
||||
wLogConsoleAppender* consoleAppender = (wLogConsoleAppender*)appender;
|
||||
|
||||
char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT;
|
||||
WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix));
|
||||
|
||||
#ifdef _WIN32
|
||||
if (consoleAppender->outputStream == WLOG_CONSOLE_DEBUG)
|
||||
{
|
||||
OutputDebugStringA(prefix);
|
||||
OutputDebugStringA(cmessage->TextString);
|
||||
OutputDebugStringA("\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
android_LogPriority level;
|
||||
switch (cmessage->Level)
|
||||
{
|
||||
case WLOG_TRACE:
|
||||
level = ANDROID_LOG_VERBOSE;
|
||||
break;
|
||||
case WLOG_DEBUG:
|
||||
level = ANDROID_LOG_DEBUG;
|
||||
break;
|
||||
case WLOG_INFO:
|
||||
level = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case WLOG_WARN:
|
||||
level = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case WLOG_ERROR:
|
||||
level = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case WLOG_FATAL:
|
||||
level = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
case WLOG_OFF:
|
||||
level = ANDROID_LOG_SILENT;
|
||||
break;
|
||||
default:
|
||||
level = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (level != ANDROID_LOG_SILENT)
|
||||
__android_log_print(level, log->Name, "%s%s", prefix, cmessage->TextString);
|
||||
|
||||
#else
|
||||
FILE* fp = nullptr;
|
||||
switch (consoleAppender->outputStream)
|
||||
{
|
||||
case WLOG_CONSOLE_STDOUT:
|
||||
fp = stdout;
|
||||
break;
|
||||
case WLOG_CONSOLE_STDERR:
|
||||
fp = stderr;
|
||||
break;
|
||||
default:
|
||||
switch (cmessage->Level)
|
||||
{
|
||||
case WLOG_TRACE:
|
||||
case WLOG_DEBUG:
|
||||
case WLOG_INFO:
|
||||
fp = stdout;
|
||||
break;
|
||||
default:
|
||||
fp = stderr;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmessage->Level != WLOG_OFF)
|
||||
(void)fprintf(fp, "%s%s\n", prefix, cmessage->TextString);
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int g_DataId = 0;
|
||||
|
||||
static BOOL WLog_ConsoleAppender_WriteDataMessage(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender,
|
||||
const wLogMessage* message)
|
||||
{
|
||||
#if defined(ANDROID)
|
||||
return FALSE;
|
||||
#else
|
||||
int DataId = 0;
|
||||
char* FullFileName = nullptr;
|
||||
|
||||
DataId = g_DataId++;
|
||||
FullFileName = WLog_Message_GetOutputFileName(DataId, "dat");
|
||||
|
||||
WLog_DataMessage_Write(FullFileName, message->Data, message->Length);
|
||||
|
||||
free(FullFileName);
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int g_ImageId = 0;
|
||||
|
||||
static BOOL WLog_ConsoleAppender_WriteImageMessage(WINPR_ATTR_UNUSED wLog* log,
|
||||
WINPR_ATTR_UNUSED wLogAppender* appender,
|
||||
const wLogMessage* message)
|
||||
{
|
||||
#if defined(ANDROID)
|
||||
return FALSE;
|
||||
#else
|
||||
int ImageId = 0;
|
||||
char* FullFileName = nullptr;
|
||||
|
||||
ImageId = g_ImageId++;
|
||||
FullFileName = WLog_Message_GetOutputFileName(ImageId, "bmp");
|
||||
|
||||
WLog_ImageMessage_Write(FullFileName, message->ImageData, message->ImageWidth,
|
||||
message->ImageHeight, message->ImageBpp);
|
||||
|
||||
free(FullFileName);
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int g_PacketId = 0;
|
||||
|
||||
static BOOL WLog_ConsoleAppender_WritePacketMessage(WINPR_ATTR_UNUSED wLog* log,
|
||||
wLogAppender* appender,
|
||||
const wLogMessage* message)
|
||||
{
|
||||
#if defined(ANDROID)
|
||||
return FALSE;
|
||||
#else
|
||||
char* FullFileName = nullptr;
|
||||
|
||||
g_PacketId++;
|
||||
|
||||
if (!appender->PacketMessageContext)
|
||||
{
|
||||
FullFileName = WLog_Message_GetOutputFileName(-1, "pcap");
|
||||
appender->PacketMessageContext = (void*)Pcap_Open(FullFileName, TRUE);
|
||||
free(FullFileName);
|
||||
}
|
||||
|
||||
if (appender->PacketMessageContext)
|
||||
return WLog_PacketMessage_Write((wPcap*)appender->PacketMessageContext, message->PacketData,
|
||||
message->PacketLength, message->PacketFlags);
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
static BOOL WLog_ConsoleAppender_Set(wLogAppender* appender, const char* setting, void* value)
|
||||
{
|
||||
wLogConsoleAppender* consoleAppender = (wLogConsoleAppender*)appender;
|
||||
|
||||
/* Just check the value string is not empty */
|
||||
if (!value || (strnlen(value, 2) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (strcmp("outputstream", setting) != 0)
|
||||
return FALSE;
|
||||
|
||||
if (!strcmp("stdout", value))
|
||||
consoleAppender->outputStream = WLOG_CONSOLE_STDOUT;
|
||||
else if (!strcmp("stderr", value))
|
||||
consoleAppender->outputStream = WLOG_CONSOLE_STDERR;
|
||||
else if (!strcmp("default", value))
|
||||
consoleAppender->outputStream = WLOG_CONSOLE_DEFAULT;
|
||||
else if (!strcmp("debug", value))
|
||||
consoleAppender->outputStream = WLOG_CONSOLE_DEBUG;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WLog_ConsoleAppender_Free(wLogAppender* appender)
|
||||
{
|
||||
if (appender)
|
||||
{
|
||||
if (appender->PacketMessageContext)
|
||||
{
|
||||
Pcap_Close((wPcap*)appender->PacketMessageContext);
|
||||
}
|
||||
|
||||
free(appender);
|
||||
}
|
||||
}
|
||||
|
||||
wLogAppender* WLog_ConsoleAppender_New(WINPR_ATTR_UNUSED wLog* log)
|
||||
{
|
||||
wLogConsoleAppender* ConsoleAppender =
|
||||
(wLogConsoleAppender*)calloc(1, sizeof(wLogConsoleAppender));
|
||||
|
||||
if (!ConsoleAppender)
|
||||
return nullptr;
|
||||
|
||||
ConsoleAppender->common.Type = WLOG_APPENDER_CONSOLE;
|
||||
ConsoleAppender->common.Open = WLog_ConsoleAppender_Open;
|
||||
ConsoleAppender->common.Close = WLog_ConsoleAppender_Close;
|
||||
ConsoleAppender->common.WriteMessage = WLog_ConsoleAppender_WriteMessage;
|
||||
ConsoleAppender->common.WriteDataMessage = WLog_ConsoleAppender_WriteDataMessage;
|
||||
ConsoleAppender->common.WriteImageMessage = WLog_ConsoleAppender_WriteImageMessage;
|
||||
ConsoleAppender->common.WritePacketMessage = WLog_ConsoleAppender_WritePacketMessage;
|
||||
ConsoleAppender->common.Set = WLog_ConsoleAppender_Set;
|
||||
ConsoleAppender->common.Free = WLog_ConsoleAppender_Free;
|
||||
|
||||
ConsoleAppender->outputStream = WLOG_CONSOLE_DEFAULT;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (IsDebuggerPresent())
|
||||
ConsoleAppender->outputStream = WLOG_CONSOLE_DEBUG;
|
||||
#endif
|
||||
|
||||
return &ConsoleAppender->common;
|
||||
}
|
||||
29
third_party/FreeRDP/winpr/libwinpr/utils/wlog/ConsoleAppender.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_WLOG_CONSOLE_APPENDER_PRIVATE_H
|
||||
#define WINPR_WLOG_CONSOLE_APPENDER_PRIVATE_H
|
||||
|
||||
#include "wlog.h"
|
||||
|
||||
WINPR_ATTR_MALLOC(WLog_Appender_Free, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
WINPR_LOCAL wLogAppender* WLog_ConsoleAppender_New(wLog* log);
|
||||
|
||||
#endif /* WINPR_WLOG_CONSOLE_APPENDER_PRIVATE_H */
|
||||