summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/utils/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/utils/test
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/utils/test')
-rw-r--r--winpr/libwinpr/utils/test/CMakeLists.txt55
-rw-r--r--winpr/libwinpr/utils/test/TestASN1.c335
-rw-r--r--winpr/libwinpr/utils/test/TestArrayList.c82
-rw-r--r--winpr/libwinpr/utils/test/TestBacktrace.c34
-rw-r--r--winpr/libwinpr/utils/test/TestBitStream.c86
-rw-r--r--winpr/libwinpr/utils/test/TestBufferPool.c68
-rw-r--r--winpr/libwinpr/utils/test/TestCmdLine.c352
-rw-r--r--winpr/libwinpr/utils/test/TestHashTable.c448
-rw-r--r--winpr/libwinpr/utils/test/TestImage.c232
-rw-r--r--winpr/libwinpr/utils/test/TestIni.c160
-rw-r--r--winpr/libwinpr/utils/test/TestLinkedList.c135
-rw-r--r--winpr/libwinpr/utils/test/TestListDictionary.c178
-rw-r--r--winpr/libwinpr/utils/test/TestMessagePipe.c105
-rw-r--r--winpr/libwinpr/utils/test/TestMessageQueue.c56
-rw-r--r--winpr/libwinpr/utils/test/TestPrint.c401
-rw-r--r--winpr/libwinpr/utils/test/TestPubSub.c73
-rw-r--r--winpr/libwinpr/utils/test/TestQueue.c58
-rw-r--r--winpr/libwinpr/utils/test/TestStream.c682
-rw-r--r--winpr/libwinpr/utils/test/TestStreamPool.c78
-rw-r--r--winpr/libwinpr/utils/test/TestVersion.c47
-rw-r--r--winpr/libwinpr/utils/test/TestWLog.c69
-rw-r--r--winpr/libwinpr/utils/test/TestWLogCallback.c128
-rw-r--r--winpr/libwinpr/utils/test/lodepng_32bit.bmpbin0 -> 16522 bytes
-rw-r--r--winpr/libwinpr/utils/test/lodepng_32bit.pngbin0 -> 3968 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16.bmpbin0 -> 1966218 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16.nocolor.bmpbin0 -> 1966150 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16a.bmpbin0 -> 1966218 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16a.nocolor.bmpbin0 -> 1966150 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16x.bmpbin0 -> 1966218 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.16x.nocolor.bmpbin0 -> 1966150 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.24.bmpbin0 -> 2949258 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.24.nocolor.bmpbin0 -> 2949174 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.32.bmpbin0 -> 3932298 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.32.nocolor.bmpbin0 -> 3932230 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.32x.bmpbin0 -> 3932298 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.32x.nocolor.bmpbin0 -> 3932230 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.bmpbin0 -> 2949258 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.jpgbin0 -> 280142 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.pngbin0 -> 70251 bytes
-rw-r--r--winpr/libwinpr/utils/test/rgb.webpbin0 -> 20912 bytes
40 files changed, 3862 insertions, 0 deletions
diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt
new file mode 100644
index 0000000..ad22f20
--- /dev/null
+++ b/winpr/libwinpr/utils/test/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+set(MODULE_NAME "TestWinPRUtils")
+set(MODULE_PREFIX "TEST_WINPR_UTILS")
+
+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_definitions(-DTEST_SOURCE_PATH="${CMAKE_CURRENT_SOURCE_DIR}")
+add_definitions(-DTEST_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")
+
diff --git a/winpr/libwinpr/utils/test/TestASN1.c b/winpr/libwinpr/utils/test/TestASN1.c
new file mode 100644
index 0000000..d54bdbc
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestASN1.c
@@ -0,0 +1,335 @@
+#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 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 seqDecoder;
+ wStream staticS;
+ WinPrAsn1_BOOL boolV = 0;
+ WinPrAsn1_INTEGER integerV = 0;
+ WinPrAsn1_OID oidV;
+ WinPrAsn1_IA5STRING ia5stringV = NULL;
+ WinPrAsn1_UTCTIME utctimeV;
+ 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, 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))
+ 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"))
+ 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 = NULL;
+ size_t expectedOuputSz = 0;
+ int retCode = 100;
+ WinPrAsn1_UTCTIME utcTime;
+ WinPrAsn1_IA5STRING ia5string = NULL;
+ 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(NULL, 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);
+}
diff --git a/winpr/libwinpr/utils/test/TestArrayList.c b/winpr/libwinpr/utils/test/TestArrayList.c
new file mode 100644
index 0000000..069394c
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestArrayList.c
@@ -0,0 +1,82 @@
+
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/collections.h>
+
+int TestArrayList(int argc, char* argv[])
+{
+ int count = 0;
+ int rc = 0;
+ size_t val = 0;
+ wArrayList* arrayList = NULL;
+ const size_t elemsToInsert = 10;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ arrayList = ArrayList_New(TRUE);
+ if (!arrayList)
+ return -1;
+
+ for (size_t index = 0; index < elemsToInsert; index++)
+ {
+ if (!ArrayList_Append(arrayList, (void*)index))
+ return -1;
+ }
+
+ count = ArrayList_Count(arrayList);
+
+ printf("ArrayList count: %d\n", count);
+
+ SSIZE_T index = ArrayList_IndexOf(arrayList, (void*)(size_t)6, -1, -1);
+
+ printf("ArrayList index: %" PRIdz "\n", index);
+
+ if (index != 6)
+ return -1;
+
+ 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)
+ return -1;
+
+ ArrayList_Remove(arrayList, (void*)(size_t)100);
+
+ rc = ArrayList_IndexOf(arrayList, (void*)(size_t)6, -1, -1);
+ printf("ArrayList index: %d\n", rc);
+
+ if (rc != 6)
+ return -1;
+
+ for (size_t index = 0; index < elemsToInsert; index++)
+ {
+ val = (size_t)ArrayList_GetItem(arrayList, 0);
+ if (!ArrayList_RemoveAt(arrayList, 0))
+ return -1;
+ if (val != index)
+ {
+ printf("ArrayList: shifted %" PRIdz " entries, expected value %" PRIdz ", got %" PRIdz
+ "\n",
+ index, index, val);
+ return -1;
+ }
+ }
+
+ rc = ArrayList_IndexOf(arrayList, (void*)(size_t)elemsToInsert, -1, -1);
+ printf("ArrayList index: %d\n", rc);
+ if (rc != -1)
+ return -1;
+
+ count = ArrayList_Count(arrayList);
+ printf("ArrayList count: %d\n", count);
+ if (count != 0)
+ return -1;
+
+ ArrayList_Clear(arrayList);
+ ArrayList_Free(arrayList);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestBacktrace.c b/winpr/libwinpr/utils/test/TestBacktrace.c
new file mode 100644
index 0000000..5fea333
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestBacktrace.c
@@ -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 = NULL;
+ void* stack = winpr_backtrace(20);
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (!stack)
+ {
+ 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(msg);
+ return rc;
+}
diff --git a/winpr/libwinpr/utils/test/TestBitStream.c b/winpr/libwinpr/utils/test/TestBitStream.c
new file mode 100644
index 0000000..83c911c
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestBitStream.c
@@ -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] = { 0 };
+
+ 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 = NULL;
+ BYTE buffer[1024] = { 0 };
+
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestBufferPool.c b/winpr/libwinpr/utils/test/TestBufferPool.c
new file mode 100644
index 0000000..d954caa
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestBufferPool.c
@@ -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;
+ int BufferSize = 0;
+ wBufferPool* pool = NULL;
+ BYTE* Buffers[10];
+ 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: %d Expected: %" PRIu32 "\n", BufferSize,
+ DefaultSize);
+ return -1;
+ }
+
+ BufferSize = BufferPool_GetBufferSize(pool, Buffers[1]);
+
+ if (BufferSize != DefaultSize)
+ {
+ printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %" PRIu32 "\n", BufferSize,
+ DefaultSize);
+ return -1;
+ }
+
+ BufferSize = BufferPool_GetBufferSize(pool, Buffers[2]);
+
+ if (BufferSize != 2048)
+ {
+ printf("BufferPool_GetBufferSize failure: Actual: %d 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestCmdLine.c b/winpr/libwinpr/utils/test/TestCmdLine.c
new file mode 100644
index 0000000..b6657f5
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestCmdLine.c
@@ -0,0 +1,352 @@
+#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:",
+ 0 };
+
+static const char testListAppName[] = "test app name";
+static const char* testListArgs[] = {
+ "a,b,c,d", "a:,\"b:xxx, yyy\",c", "a:,,,b", "a:,\",b", "\"a,b,c,d d d,fff\"", "",
+ NULL, "'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** testListArgsResult[] = { testListArgs1,
+ testListArgs2,
+ NULL /* testListArgs3 */,
+ NULL /* testListArgs4 */,
+ testListArgs5,
+ testListArgs6,
+ testListArgs7,
+ testListArgs8,
+ testListArgs9,
+ NULL /* testListArgs10 */,
+ NULL /* testListArgs11 */ };
+static const size_t testListArgsCount[] = {
+ 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 == NULL);
+ }
+ 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++)
+ {
+ const char* list = testListArgs[x];
+ size_t count = 42;
+ char** ptr = CommandLineParseCommaSeparatedValuesEx(testListAppName, list, &count);
+ BOOL valid = checkResult(x, ptr, count);
+ free(ptr);
+ 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 = NULL;
+ int testArgc = 0;
+ char** command_line = NULL;
+ COMMAND_LINE_ARGUMENT_A args[] = {
+ { "v", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "destination server" },
+ { "port", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "server port" },
+ { "w", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "width" },
+ { "h", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "height" },
+ { "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "fullscreen" },
+ { "bpp", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL,
+ "session bpp (color depth)" },
+ { "admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "console",
+ "admin (or console) session" },
+ { "multimon", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "multi-monitor" },
+ { "a", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "addin", "addin" },
+ { "u", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "username" },
+ { "p", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "password" },
+ { "d", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "domain" },
+ { "z", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "compression" },
+ { "audio", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "audio output mode" },
+ { "mic", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "audio input (microphone)" },
+ { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
+ "smooth fonts (cleartype)" },
+ { "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL,
+ "desktop composition" },
+ { "window-drag", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
+ "full window drag" },
+ { "menu-anims", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
+ "menu animations" },
+ { "themes", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "themes" },
+ { "wallpaper", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "wallpaper" },
+ { "codec", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "codec" },
+ { "nego", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
+ "protocol security negotiation" },
+ { "sec", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL,
+ "force specific protocol security" },
+#if defined(WITH_FREERDP_DEPRECATED)
+ { "sec-rdp", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
+ "rdp protocol security" },
+ { "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
+ "tls protocol security" },
+ { "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
+ "nla protocol security" },
+ { "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
+ "nla extended protocol security" },
+ { "cert-name", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL,
+ "certificate name" },
+ { "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL,
+ "ignore certificate" },
+#endif
+ { "valuelist", COMMAND_LINE_VALUE_REQUIRED, "<val1>,<val2>", NULL, NULL, -1, NULL,
+ "List of comma separated values." },
+ { "valuelist-empty", COMMAND_LINE_VALUE_REQUIRED, "<val1>,<val2>", NULL, NULL, -1, NULL,
+ "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, NULL, NULL, NULL, -1,
+ NULL, "print version" },
+ { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?",
+ "print help" },
+ { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
+ };
+
+ 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, NULL, NULL, NULL);
+
+ 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, NULL, 0);
+
+ if (errno != 0)
+ goto out;
+ }
+ CommandLineSwitchCase(arg, "h")
+ {
+ height = strtol(arg->Value, NULL, 0);
+
+ if (errno != 0)
+ goto out;
+ }
+ CommandLineSwitchCase(arg, "valuelist")
+ {
+ char** p = NULL;
+ size_t count = 0;
+ p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
+ free(p);
+
+ if (!p || count != 3)
+ {
+ printf("CommandLineParseCommaSeparatedValuesEx: invalid p or count (%" PRIuz
+ "!=3)\n",
+ count);
+ goto out;
+ }
+ }
+ CommandLineSwitchCase(arg, "valuelist-empty")
+ {
+ char** p = NULL;
+ size_t count = 0;
+ p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
+ free(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)) != NULL);
+
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestHashTable.c b/winpr/libwinpr/utils/test/TestHashTable.c
new file mode 100644
index 0000000..764853f
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestHashTable.c
@@ -0,0 +1,448 @@
+
+#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 = NULL;
+ wHashTable* table = NULL;
+ 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 = NULL;
+ 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;
+ int strlenCounter;
+ int 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++;
+
+ if (d->foreachCalls == 2)
+ return FALSE;
+ return TRUE;
+}
+
+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 = NULL;
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestImage.c b/winpr/libwinpr/utils/test/TestImage.c
new file mode 100644
index 0000000..8635fa1
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestImage.c
@@ -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] = { 0 };
+ _snprintf(path, sizeof(path), "%s.%s", name, winpr_image_format_extension(format));
+ const int cmpSize = winpr_image_read(cmp, path);
+ if (cmpSize <= 0)
+ {
+ fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, path);
+ goto fail;
+ }
+
+ rc = test_image_equal(bmp, cmp);
+ if (!rc)
+ 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] = { 0 };
+ _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)
+ {
+ 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] = { 0 };
+ char dpath[MAX_PATH] = { 0 };
+ char bpath1[MAX_PATH] = { 0 };
+ char bpath2[MAX_PATH] = { 0 };
+ _snprintf(spath, sizeof(spath), "%s.%s", tname, winpr_image_format_extension(format));
+ _snprintf(dpath, sizeof(dpath), "%s.%s", tdst, winpr_image_format_extension(format));
+ _snprintf(bpath1, sizeof(bpath1), "%s.src.%s", dpath,
+ winpr_image_format_extension(WINPR_IMAGE_BITMAP));
+ _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)
+ {
+ fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, spath);
+ goto fail;
+ }
+
+ const int bmpWSize = winpr_image_write(bmp1, dpath);
+ if (bmpWSize <= 0)
+ {
+ fprintf(stderr, "[%s] winpr_image_write failed for %s", __func__, dpath);
+ goto fail;
+ }
+
+ const int bmp2RSize = winpr_image_read(bmp2, dpath);
+ if (bmp2RSize <= 0)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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))
+ {
+ 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)
+ 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) ? TRUE : FALSE;
+
+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;
+}
diff --git a/winpr/libwinpr/utils/test/TestIni.c b/winpr/libwinpr/utils/test/TestIni.c
new file mode 100644
index 0000000..2dd24f0
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestIni.c
@@ -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 = NULL;
+ const char* sValue = NULL;
+ char** keyNames = NULL;
+ char** sectionNames = NULL;
+
+ 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(sectionNames);
+ sectionNames = IniFile_GetSectionNames(ini, &nSections);
+ if (!sectionNames && (nSections > 0))
+ goto fail;
+
+ for (size_t i = 0; i < nSections; i++)
+ {
+ free(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(sectionNames);
+ sectionNames = IniFile_GetSectionNames(ini, &nSections);
+ if (!sectionNames && (nSections > 0))
+ goto fail;
+
+ for (size_t i = 0; i < nSections; i++)
+ {
+ free(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(keyNames);
+ free(sectionNames);
+ IniFile_Free(ini);
+ return rc;
+}
diff --git a/winpr/libwinpr/utils/test/TestLinkedList.c b/winpr/libwinpr/utils/test/TestLinkedList.c
new file mode 100644
index 0000000..6c6a2c3
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestLinkedList.c
@@ -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;
+}
diff --git a/winpr/libwinpr/utils/test/TestListDictionary.c b/winpr/libwinpr/utils/test/TestListDictionary.c
new file mode 100644
index 0000000..7be8013
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestListDictionary.c
@@ -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 = NULL;
+ wListDictionary* list = NULL;
+
+ 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) || 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) || 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestMessagePipe.c b/winpr/libwinpr/utils/test/TestMessagePipe.c
new file mode 100644
index 0000000..c5a3ee2
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestMessagePipe.c
@@ -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 = { 0 };
+ int count = -1;
+
+ if (!MessageQueue_Post(pipe->In, NULL, 0, (void*)(size_t)index, NULL))
+ 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 = { 0 };
+ 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 = NULL;
+ HANDLE ServerThread = NULL;
+ wMessagePipe* EchoPipe = NULL;
+ 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(NULL, 0, message_echo_pipe_client_thread, (void*)EchoPipe, 0, NULL)))
+ {
+ printf("failed to create client thread\n");
+ goto out;
+ }
+
+ if (!(ServerThread =
+ CreateThread(NULL, 0, message_echo_pipe_server_thread, (void*)EchoPipe, 0, NULL)))
+ {
+ printf("failed to create server thread\n");
+ goto out;
+ }
+
+ WaitForSingleObject(ClientThread, INFINITE);
+ WaitForSingleObject(ServerThread, INFINITE);
+
+ ret = 0;
+
+out:
+ if (EchoPipe)
+ MessagePipe_Free(EchoPipe);
+ if (ClientThread)
+ CloseHandle(ClientThread);
+ if (ServerThread)
+ CloseHandle(ServerThread);
+
+ return ret;
+}
diff --git a/winpr/libwinpr/utils/test/TestMessageQueue.c b/winpr/libwinpr/utils/test/TestMessageQueue.c
new file mode 100644
index 0000000..b3245b1
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestMessageQueue.c
@@ -0,0 +1,56 @@
+
+#include <winpr/crt.h>
+#include <winpr/thread.h>
+#include <winpr/collections.h>
+
+static DWORD WINAPI message_queue_consumer_thread(LPVOID arg)
+{
+ wMessage message = { 0 };
+ 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;
+}
+
+int TestMessageQueue(int argc, char* argv[])
+{
+ HANDLE thread = NULL;
+ wMessageQueue* queue = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (!(queue = MessageQueue_New(NULL)))
+ {
+ printf("failed to create message queue\n");
+ return 1;
+ }
+
+ if (!(thread = CreateThread(NULL, 0, message_queue_consumer_thread, (void*)queue, 0, NULL)))
+ {
+ printf("failed to create thread\n");
+ MessageQueue_Free(queue);
+ return 1;
+ }
+
+ if (!MessageQueue_Post(queue, NULL, 123, NULL, NULL) ||
+ !MessageQueue_Post(queue, NULL, 456, NULL, NULL) ||
+ !MessageQueue_Post(queue, NULL, 789, NULL, NULL) || !MessageQueue_PostQuit(queue, 0) ||
+ WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
+ return -1;
+
+ MessageQueue_Free(queue);
+ CloseHandle(thread);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestPrint.c b/winpr/libwinpr/utils/test/TestPrint.c
new file mode 100644
index 0000000..f60b903
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestPrint.c
@@ -0,0 +1,401 @@
+
+#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
+
+static BOOL test_bin_tohex_string(void)
+{
+ BOOL rc = FALSE;
+ {
+ const BYTE binbuffer[33] = { 0 };
+ const char empty[33] = { 0 };
+ char strbuffer[33] = { 0 };
+
+ size_t len =
+ winpr_BinToHexStringBuffer(NULL, 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), NULL, 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), NULL, 0, TRUE);
+ if (len != 0)
+ goto fail;
+ if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
+ goto fail;
+ len = winpr_BinToHexStringBuffer(NULL, sizeof(binbuffer), strbuffer, 0, TRUE);
+ if (len != 0)
+ goto fail;
+ if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
+ goto fail;
+
+ len = winpr_BinToHexStringBuffer(binbuffer, 0, NULL, 0, TRUE);
+ if (len != 0)
+ goto fail;
+ if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
+ goto fail;
+ len = winpr_BinToHexStringBuffer(NULL, 0, NULL, 0, TRUE);
+ if (len != 0)
+ goto fail;
+ if (memcmp(strbuffer, empty, sizeof(strbuffer)) != 0)
+ goto fail;
+ len = winpr_BinToHexStringBuffer(binbuffer, 0, NULL, 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] = { 0 };
+ 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] = { 0 };
+ 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 = NULL;
+ {
+ const BYTE binbuffer[33] = { 0 };
+
+ str = winpr_BinToHexString(NULL, 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(NULL, 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 = NULL;
+ }
+ {
+ 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 = NULL;
+ }
+ 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] = { 0 };
+ BYTE buffer[1024] = { 0 };
+ size_t len = winpr_HexStringToBinBuffer(NULL, 0, NULL, 0);
+ if (len != 0)
+ goto fail;
+ if (memcmp(buffer, empty, sizeof(buffer)) != 0)
+ goto fail;
+ len = winpr_HexStringToBinBuffer(NULL, 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), NULL, 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] = { 0 };
+ 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] = { 0 };
+ 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] = { 0 };
+ 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] = { 0 };
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestPubSub.c b/winpr/libwinpr/utils/test/TestPubSub.c
new file mode 100644
index 0000000..0b05b15
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestPubSub.c
@@ -0,0 +1,73 @@
+
+#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 = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ node = PubSub_New(TRUE);
+ if (!node)
+ return -1;
+
+ PubSub_AddEventTypes(node, Node_Events, NODE_EVENT_COUNT);
+
+ PubSub_SubscribeMouseMotion(node, MouseMotionEventHandler);
+ PubSub_SubscribeMouseButton(node, MouseButtonEventHandler);
+
+ /* Call Event Handler */
+ {
+ MouseMotionEventArgs e;
+
+ e.x = 64;
+ e.y = 128;
+
+ PubSub_OnMouseMotion(node, NULL, &e);
+ }
+
+ {
+ MouseButtonEventArgs e;
+
+ e.x = 23;
+ e.y = 56;
+ e.flags = 7;
+ e.button = 1;
+
+ PubSub_OnMouseButton(node, NULL, &e);
+ }
+
+ PubSub_Free(node);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestQueue.c b/winpr/libwinpr/utils/test/TestQueue.c
new file mode 100644
index 0000000..9c65af5
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestQueue.c
@@ -0,0 +1,58 @@
+
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/collections.h>
+
+int TestQueue(int argc, char* argv[])
+{
+ size_t item = 0;
+ size_t count = 0;
+ wQueue* queue = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ queue = Queue_New(TRUE, -1, -1);
+ if (!queue)
+ return -1;
+
+ for (size_t index = 1; index <= 10; index++)
+ {
+ Queue_Enqueue(queue, (void*)(size_t)index);
+ }
+
+ count = Queue_Count(queue);
+ printf("queue count: %" PRIuz "\n", count);
+
+ for (size_t index = 1; index <= 10; index++)
+ {
+ item = (size_t)Queue_Dequeue(queue);
+
+ if (item != index)
+ return -1;
+ }
+
+ count = Queue_Count(queue);
+ printf("queue count: %" PRIuz "\n", count);
+
+ Queue_Enqueue(queue, (void*)(size_t)1);
+ Queue_Enqueue(queue, (void*)(size_t)2);
+ Queue_Enqueue(queue, (void*)(size_t)3);
+
+ Queue_Dequeue(queue);
+ Queue_Dequeue(queue);
+
+ Queue_Enqueue(queue, (void*)(size_t)4);
+ Queue_Enqueue(queue, (void*)(size_t)5);
+ Queue_Enqueue(queue, (void*)(size_t)6);
+
+ Queue_Dequeue(queue);
+ Queue_Dequeue(queue);
+ Queue_Dequeue(queue);
+ Queue_Dequeue(queue);
+
+ Queue_Clear(queue);
+ Queue_Free(queue);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestStream.c b/winpr/libwinpr/utils/test/TestStream.c
new file mode 100644
index 0000000..00130ae
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestStream.c
@@ -0,0 +1,682 @@
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/stream.h>
+
+static BOOL TestStream_Verify(wStream* s, size_t mincap, size_t len, size_t pos)
+{
+ if (Stream_Buffer(s) == NULL)
+ {
+ printf("stream buffer is null\n");
+ return FALSE;
+ }
+
+ if (Stream_ConstPointer(s) == NULL)
+ {
+ 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)
+{
+ wStream* s = NULL;
+ /* Test creation of a 0-size stream with no buffer */
+ s = Stream_New(NULL, 0);
+
+ if (s)
+ return FALSE;
+
+ return TRUE;
+}
+
+static BOOL TestStream_Static(void)
+{
+ BYTE buffer[20];
+ wStream staticStream;
+ wStream* s = &staticStream;
+ UINT16 v = 0;
+ /* Test creation of a static stream */
+ Stream_StaticInit(s, buffer, sizeof(buffer));
+ Stream_Write_UINT16(s, 0xcab1);
+ Stream_SetPosition(s, 0);
+ Stream_Read_UINT16(s, v);
+
+ if (v != 0xcab1)
+ return FALSE;
+
+ Stream_SetPosition(s, 0);
+ 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_SetPosition(s, 0);
+ Stream_Read_UINT16(s, v);
+
+ if (v != 1)
+ return FALSE;
+
+ Stream_Read_UINT16(s, v);
+
+ if (v != 2)
+ return FALSE;
+
+ Stream_Free(s, TRUE);
+ return TRUE;
+}
+
+static BOOL TestStream_Create(size_t count, BOOL selfAlloc)
+{
+ size_t len = 0;
+ size_t cap = 0;
+ wStream* s = NULL;
+ void* buffer = NULL;
+
+ 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 : NULL, 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, i % 256, cap);
+
+ if (memcmp(buffer, Stream_Buffer(s), cap))
+ {
+ printf("%s: buffer memory corruption\n", __func__);
+ goto fail;
+ }
+ }
+
+ Stream_Free(s, buffer ? FALSE : TRUE);
+ free(buffer);
+ }
+
+ return TRUE;
+fail:
+ free(buffer);
+
+ if (s)
+ {
+ Stream_Free(s, buffer ? FALSE : TRUE);
+ }
+
+ return FALSE;
+}
+
+static BOOL TestStream_Extent(UINT32 maxSize)
+{
+ wStream* s = NULL;
+ BOOL result = FALSE;
+
+ if (!(s = Stream_New(NULL, 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_INT8_BE Stream_Peek_INT8
+#define Stream_Read_INT8_BE Stream_Read_INT8
+
+#define TestStream_PeekAndRead(_s, _r, _t) \
+ do \
+ { \
+ _t _a; \
+ _t _b; \
+ BYTE* _p = Stream_Buffer(_s); \
+ Stream_SetPosition(_s, 0); \
+ Stream_Peek_##_t(_s, _a); \
+ Stream_Read_##_t(_s, _b); \
+ if (_a != _b) \
+ { \
+ 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_SetPosition(_s, 0); \
+ 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; \
+ } \
+ 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_Reading(void)
+{
+ BYTE src[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+ wStream* s = NULL;
+ 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(NULL, 100);
+
+ if (!s)
+ goto out;
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Write(s, data, sizeof(data));
+
+ if (memcmp(Stream_Buffer(s), data, sizeof(data)) == 0)
+ rc = TRUE;
+
+ if (s->pointer != s->buffer + sizeof(data))
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Write_UINT8(s, 42);
+
+ if (s->pointer != s->buffer + 1)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Peek_UINT8(s, u8);
+
+ if (u8 != 42)
+ goto out;
+
+ Stream_Write_UINT16(s, 0x1234);
+
+ if (s->pointer != s->buffer + 2)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Peek_UINT16(s, u16);
+
+ if (u16 != 0x1234)
+ goto out;
+
+ Stream_Write_UINT32(s, 0x12345678UL);
+
+ if (s->pointer != s->buffer + 4)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Peek_UINT32(s, u32);
+
+ if (u32 != 0x12345678UL)
+ goto out;
+
+ Stream_Write_UINT64(s, 0x1234567890ABCDEFULL);
+
+ if (s->pointer != s->buffer + 8)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Peek_UINT64(s, u64);
+
+ if (u64 != 0x1234567890ABCDEFULL)
+ goto out;
+
+out:
+ Stream_Free(s, TRUE);
+ return rc;
+}
+
+static BOOL TestStream_Seek(void)
+{
+ BOOL rc = FALSE;
+ wStream* s = Stream_New(NULL, 100);
+
+ if (!s)
+ goto out;
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Seek(s, 5);
+
+ if (s->pointer != s->buffer + 5)
+ goto out;
+
+ Stream_Seek_UINT8(s);
+
+ if (s->pointer != s->buffer + 6)
+ goto out;
+
+ Stream_Seek_UINT16(s);
+
+ if (s->pointer != s->buffer + 8)
+ goto out;
+
+ Stream_Seek_UINT32(s);
+
+ if (s->pointer != s->buffer + 12)
+ goto out;
+
+ Stream_Seek_UINT64(s);
+
+ if (s->pointer != s->buffer + 20)
+ goto out;
+
+ rc = TRUE;
+out:
+ Stream_Free(s, TRUE);
+ return rc;
+}
+
+static BOOL TestStream_Rewind(void)
+{
+ BOOL rc = FALSE;
+ wStream* s = Stream_New(NULL, 100);
+
+ if (!s)
+ goto out;
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Seek(s, 100);
+
+ if (s->pointer != s->buffer + 100)
+ goto out;
+
+ Stream_Rewind(s, 10);
+
+ if (s->pointer != s->buffer + 90)
+ goto out;
+
+ Stream_Rewind_UINT8(s);
+
+ if (s->pointer != s->buffer + 89)
+ goto out;
+
+ Stream_Rewind_UINT16(s);
+
+ if (s->pointer != s->buffer + 87)
+ goto out;
+
+ Stream_Rewind_UINT32(s);
+
+ if (s->pointer != s->buffer + 83)
+ goto out;
+
+ Stream_Rewind_UINT64(s);
+
+ if (s->pointer != s->buffer + 75)
+ goto out;
+
+ rc = TRUE;
+out:
+ Stream_Free(s, TRUE);
+ return rc;
+}
+
+static BOOL TestStream_Zero(void)
+{
+ BOOL rc = FALSE;
+ const BYTE data[] = "someteststreamdata";
+ wStream* s = Stream_New(NULL, sizeof(data));
+
+ if (!s)
+ goto out;
+
+ Stream_Write(s, data, sizeof(data));
+
+ if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Zero(s, 5);
+
+ if (s->pointer != s->buffer + 5)
+ goto out;
+
+ if (memcmp(Stream_ConstPointer(s), data + 5, sizeof(data) - 5) != 0)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ 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(NULL, sizeof(data));
+
+ if (!s)
+ goto out;
+
+ Stream_Write(s, data, sizeof(data));
+
+ if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Fill(s, fill[0], sizeof(fill));
+
+ if (s->pointer != s->buffer + sizeof(fill))
+ goto out;
+
+ if (memcmp(Stream_ConstPointer(s), data + sizeof(fill), sizeof(data) - sizeof(fill)) != 0)
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ if (memcmp(Stream_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(NULL, sizeof(data));
+ wStream* d = Stream_New(NULL, sizeof(data));
+
+ if (!s || !d)
+ goto out;
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Write(s, data, sizeof(data));
+
+ if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
+ goto out;
+
+ if (s->pointer != s->buffer + sizeof(data))
+ goto out;
+
+ Stream_SetPosition(s, 0);
+
+ if (s->pointer != s->buffer)
+ goto out;
+
+ Stream_Copy(s, d, sizeof(data));
+
+ if (s->pointer != s->buffer + sizeof(data))
+ goto out;
+
+ if (d->pointer != d->buffer + sizeof(data))
+ goto out;
+
+ if (Stream_GetPosition(s) != Stream_GetPosition(d))
+ goto out;
+
+ if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0)
+ goto out;
+
+ if (memcmp(Stream_Buffer(d), data, sizeof(data)) != 0)
+ goto out;
+
+ rc = TRUE;
+out:
+ Stream_Free(s, TRUE);
+ Stream_Free(d, TRUE);
+ return rc;
+}
+
+int TestStream(int argc, char* argv[])
+{
+ 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;
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestStreamPool.c b/winpr/libwinpr/utils/test/TestStreamPool.c
new file mode 100644
index 0000000..1844a53
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestStreamPool.c
@@ -0,0 +1,78 @@
+
+#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] = { 0 };
+ char buffer[8192] = { 0 };
+
+ 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)));
+
+ StreamPool_Free(pool);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestVersion.c b/winpr/libwinpr/utils/test/TestVersion.c
new file mode 100644
index 0000000..71a1d74
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestVersion.c
@@ -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 = NULL;
+ const char* git = NULL;
+ const char* build = NULL;
+ 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)))
+ return -1;
+
+ build = winpr_get_build_config();
+
+ if (!build)
+ return -1;
+
+ return 0;
+}
diff --git a/winpr/libwinpr/utils/test/TestWLog.c b/winpr/libwinpr/utils/test/TestWLog.c
new file mode 100644
index 0000000..92f1114
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestWLog.c
@@ -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 = NULL;
+ wLog* logA = NULL;
+ wLog* logB = NULL;
+ wLogLayout* layout = NULL;
+ wLogAppender* appender = NULL;
+ char* tmp_path = NULL;
+ char* wlog_file = NULL;
+ int result = 1;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (!(tmp_path = GetKnownPath(KNOWN_PATH_TEMP)))
+ {
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/TestWLogCallback.c b/winpr/libwinpr/utils/test/TestWLogCallback.c
new file mode 100644
index 0000000..1acbf65
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestWLogCallback.c
@@ -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 = NULL;
+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__))
+ rc = FALSE;
+ else if (strcmp(msg->FunctionName, function))
+ rc = FALSE;
+ else if (strcmp(msg->PrefixString, messages[pos].channel))
+ rc = FALSE;
+ else if (msg->Level != messages[pos].level)
+ rc = FALSE;
+ else if (strcmp(msg->FormatString, messages[pos].msg))
+ rc = FALSE;
+ pos++;
+
+ if (!rc)
+ {
+ 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)
+{
+ fprintf(stdout, "%s\n", __func__);
+ return TRUE;
+}
+
+static BOOL CallbackAppenderImage(const wLogMessage* msg)
+{
+ fprintf(stdout, "%s\n", __func__);
+ return TRUE;
+}
+
+static BOOL CallbackAppenderPackage(const wLogMessage* msg)
+{
+ fprintf(stdout, "%s\n", __func__);
+ return TRUE;
+}
+
+int TestWLogCallback(int argc, char* argv[])
+{
+ wLog* root = NULL;
+ wLog* logA = NULL;
+ wLog* logB = NULL;
+ wLogLayout* layout = NULL;
+ wLogAppender* appender = NULL;
+ 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;
+}
diff --git a/winpr/libwinpr/utils/test/lodepng_32bit.bmp b/winpr/libwinpr/utils/test/lodepng_32bit.bmp
new file mode 100644
index 0000000..d52d34c
--- /dev/null
+++ b/winpr/libwinpr/utils/test/lodepng_32bit.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/lodepng_32bit.png b/winpr/libwinpr/utils/test/lodepng_32bit.png
new file mode 100644
index 0000000..9c55f28
--- /dev/null
+++ b/winpr/libwinpr/utils/test/lodepng_32bit.png
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16.bmp b/winpr/libwinpr/utils/test/rgb.16.bmp
new file mode 100644
index 0000000..3e6e1ad
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.16.nocolor.bmp
new file mode 100644
index 0000000..70875dd
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16a.bmp b/winpr/libwinpr/utils/test/rgb.16a.bmp
new file mode 100644
index 0000000..4a7b506
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16a.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16a.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.16a.nocolor.bmp
new file mode 100644
index 0000000..ae739dd
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16a.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16x.bmp b/winpr/libwinpr/utils/test/rgb.16x.bmp
new file mode 100644
index 0000000..5fb5cd8
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16x.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.16x.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.16x.nocolor.bmp
new file mode 100644
index 0000000..7e04ec3
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.16x.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.24.bmp b/winpr/libwinpr/utils/test/rgb.24.bmp
new file mode 100644
index 0000000..7719f9d
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.24.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.24.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.24.nocolor.bmp
new file mode 100644
index 0000000..ffc30ed
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.24.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.32.bmp b/winpr/libwinpr/utils/test/rgb.32.bmp
new file mode 100644
index 0000000..5d9c1df
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.32.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.32.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.32.nocolor.bmp
new file mode 100644
index 0000000..5217757
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.32.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.32x.bmp b/winpr/libwinpr/utils/test/rgb.32x.bmp
new file mode 100644
index 0000000..41ae40c
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.32x.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.32x.nocolor.bmp b/winpr/libwinpr/utils/test/rgb.32x.nocolor.bmp
new file mode 100644
index 0000000..10abb96
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.32x.nocolor.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.bmp b/winpr/libwinpr/utils/test/rgb.bmp
new file mode 100644
index 0000000..3e7e5bb
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.bmp
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.jpg b/winpr/libwinpr/utils/test/rgb.jpg
new file mode 100644
index 0000000..89c5a31
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.jpg
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.png b/winpr/libwinpr/utils/test/rgb.png
new file mode 100644
index 0000000..70877d4
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.png
Binary files differ
diff --git a/winpr/libwinpr/utils/test/rgb.webp b/winpr/libwinpr/utils/test/rgb.webp
new file mode 100644
index 0000000..26e0c05
--- /dev/null
+++ b/winpr/libwinpr/utils/test/rgb.webp
Binary files differ