1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Test for RtlUnicodeStringToCountedOemString
5  * COPYRIGHT:   Copyright 2021 Jérôme Gardou <jerome.gardou@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 static const struct
11 {
12     ULONG AnsiCp;
13     ULONG OemCp;
14     const UNICODE_STRING StrU;
15     NTSTATUS Status;
16     const OEM_STRING StrOem;
17 } TestData[] =
18 {
19     {
20         1252, 932, /* Western SBCS - Modified SJIS */
21         RTL_CONSTANT_STRING(L"\u30c7\u30b9\u30af\u30c8\u30c3\u30d7"),
22         STATUS_BUFFER_OVERFLOW,
23         RTL_CONSTANT_STRING("\x83\x66\x83\x58\x83\x4e")
24     },
25     {
26         932, 1252, /* Modified SJIS - Western SBCS */
27         RTL_CONSTANT_STRING(L"\u30c7\u30b9\u30af\u30c8\u30c3\u30d7"),
28         STATUS_UNMAPPABLE_CHARACTER,
29         RTL_CONSTANT_STRING("??????")
30     },
31     {
32         932, 932, /* Modified SJIS - Modified SJIS */
33         RTL_CONSTANT_STRING(L"\u30c7\u30b9\u30af\u30c8\u30c3\u30d7"),
34         STATUS_SUCCESS,
35         RTL_CONSTANT_STRING("\x83\x66\x83\x58\x83\x4e\x83\x67\x83\x62\x83\x76")
36     },
37     {
38         1252, 1252, /* Western SBCS */
39         RTL_CONSTANT_STRING(L"\u30c7\u30b9\u30af\u30c8\u30c3\u30d7"), /* Some japanese characters */
40         STATUS_UNMAPPABLE_CHARACTER,
41         RTL_CONSTANT_STRING("??????")
42     },
43 };
44 
START_TEST(RtlUnicodeStringToCountedOemString)45 START_TEST(RtlUnicodeStringToCountedOemString)
46 {
47     WCHAR BufferU[10];
48     CHAR BufferOem[10];
49     UNICODE_STRING StringU;
50     OEM_STRING StringOem;
51     NTSTATUS Status;
52     int i;
53 
54     memset(BufferU, 0xAA, sizeof(BufferU));
55     memset(BufferOem, 0xAA, sizeof(BufferOem));
56 
57     BufferU[0] = L'A';
58     BufferU[1] = UNICODE_NULL;
59 
60     StringU.Buffer = BufferU;
61     StringU.MaximumLength = 10 * sizeof(WCHAR);
62 
63     RtlInitUnicodeString(&StringU, BufferU);
64     ok(StringU.Length == 1 * sizeof(WCHAR), "Invalid size: %d\n", StringU.Length);
65     ok(StringU.MaximumLength == 2 * sizeof(WCHAR), "Invalid size: %d\n", StringU.MaximumLength);
66     ok(StringU.Buffer == BufferU, "Invalid buffer: %p\n", StringU.Buffer);
67 
68     StringOem.Buffer = BufferOem;
69     StringOem.Length = 0;
70     StringOem.MaximumLength = 10 * sizeof(CHAR);
71 
72     Status = RtlUnicodeStringToCountedOemString(&StringOem, &StringU, FALSE);
73     ok(NT_SUCCESS(Status), "RtlUnicodeStringToCountedOemString failed: %lx\n", Status);
74     ok(StringOem.Length == 1 * sizeof(CHAR), "Invalid size: %d\n", StringOem.Length);
75     ok(StringOem.MaximumLength == 10 * sizeof(CHAR), "Invalid size: %d\n", StringOem.MaximumLength);
76     ok(StringOem.Buffer == BufferOem, "Invalid buffer: %p\n", StringOem.Buffer);
77 
78     ok(BufferOem[0] == 'A', "Unexpected first char 0x%02x for OEM string.\n", BufferOem[0]);
79     for (i = 1; i < 10; ++i)
80     {
81         ok(BufferOem[i] == (CHAR)0xAA, "Unexpected char 0x%02x at position %d.\n", BufferOem[i], i);
82     }
83 
84     ok(i == 10, "String was not null terminated!\n");
85 
86     /* Test buffer overflow */
87     wcsncpy(BufferU, L"Test", _countof(BufferU));
88     RtlInitUnicodeString(&StringU, BufferU);
89     StringU.MaximumLength = sizeof(BufferU);
90     StringOem.Buffer = BufferOem;
91     StringOem.MaximumLength = 1 * sizeof(CHAR);
92     StringOem.Length = 0;
93     memset(BufferOem, 0xAA, sizeof(BufferOem));
94 
95     Status = RtlUnicodeStringToCountedOemString(&StringOem, &StringU, FALSE);
96     ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW);
97     ok(StringOem.Length == 4 * sizeof(CHAR), "Invalid size: %d\n", StringOem.Length);
98     ok(StringOem.MaximumLength == 1 * sizeof(CHAR), "Invalid size: %d\n", StringOem.MaximumLength);
99     ok(StringOem.Buffer == BufferOem, "Invalid buffer: %p\n", StringOem.Buffer);
100 
101     for (i = 0; i < 10; ++i)
102     {
103         ok(BufferOem[i] == (CHAR)0xAA, "Unexpected char 0x%02x at position %d.\n", BufferOem[i], i);
104     }
105 
106     for (i = 0; i < _countof(TestData); i++)
107     {
108         SetupLocale(TestData[i].AnsiCp, TestData[i].OemCp, -1);
109 
110         trace("Testing locale %u. ANSI: %u, OEM %u\n", i, (UINT)TestData[i].AnsiCp, (UINT)TestData[i].OemCp);
111 
112         /* Get the right length */
113         StringOem.Buffer = NULL;
114         StringOem.Length = 0;
115         StringOem.MaximumLength = 0;
116 
117         Status = RtlUnicodeStringToCountedOemString(&StringOem, &TestData[i].StrU, FALSE);
118         ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW);
119         ok_long(StringOem.Length, TestData[i].StrOem.Length);
120         ok_long(StringOem.MaximumLength, 0);
121 
122         StringOem.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, StringOem.Length);
123         StringOem.MaximumLength = StringOem.Length;
124         StringOem.Length = 0;
125 
126         Status = RtlUnicodeStringToCountedOemString(&StringOem, &TestData[i].StrU, FALSE);
127         ok_ntstatus(Status, TestData[i].Status);
128 
129         ok_long(StringOem.Length, TestData[i].StrOem.Length);
130         ok_long(StringOem.MaximumLength, TestData[i].StrOem.Length); /* Untouched */
131         ok_long(memcmp(StringOem.Buffer, TestData[i].StrOem.Buffer, min(StringOem.Length, TestData[i].StrOem.Length)), 0);
132 
133         RtlFreeHeap(RtlGetProcessHeap(), 0, StringOem.Buffer);
134     }
135 }
136 
137