Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / sdk / lib / drivers / ntoskrnl_vista / rtl.c
1 /*
2 * PROJECT: ReactOS Kernel - Vista+ APIs
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/drivers/ntoskrnl_vista/rtl.c
5 * PURPOSE: Rtl functions of Vista+
6 * PROGRAMMERS: Thomas Faber <thomas.faber@reactos.org>
7 */
8
9 #include <ntdef.h>
10 #include <ntifs.h>
11
12 typedef UCHAR BYTE;
13
14 /******************************************************************************
15 * RtlUnicodeToUTF8N [NTDLL.@]
16 */
17 NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
18 ULONG *utf8_bytes_written,
19 const WCHAR *uni_src, ULONG uni_bytes)
20 {
21 NTSTATUS status;
22 ULONG i;
23 ULONG written;
24 ULONG ch;
25 BYTE utf8_ch[4];
26 ULONG utf8_ch_len;
27
28 if (!uni_src)
29 return STATUS_INVALID_PARAMETER_4;
30 if (!utf8_bytes_written)
31 return STATUS_INVALID_PARAMETER;
32 if (utf8_dest && uni_bytes % sizeof(WCHAR))
33 return STATUS_INVALID_PARAMETER_5;
34
35 written = 0;
36 status = STATUS_SUCCESS;
37
38 for (i = 0; i < uni_bytes / sizeof(WCHAR); i++)
39 {
40 /* decode UTF-16 into ch */
41 ch = uni_src[i];
42 if (ch >= 0xdc00 && ch <= 0xdfff)
43 {
44 ch = 0xfffd;
45 status = STATUS_SOME_NOT_MAPPED;
46 }
47 else if (ch >= 0xd800 && ch <= 0xdbff)
48 {
49 if (i + 1 < uni_bytes / sizeof(WCHAR))
50 {
51 ch -= 0xd800;
52 ch <<= 10;
53 if (uni_src[i + 1] >= 0xdc00 && uni_src[i + 1] <= 0xdfff)
54 {
55 ch |= uni_src[i + 1] - 0xdc00;
56 ch += 0x010000;
57 i++;
58 }
59 else
60 {
61 ch = 0xfffd;
62 status = STATUS_SOME_NOT_MAPPED;
63 }
64 }
65 else
66 {
67 ch = 0xfffd;
68 status = STATUS_SOME_NOT_MAPPED;
69 }
70 }
71
72 /* encode ch as UTF-8 */
73 ASSERT(ch <= 0x10ffff);
74 if (ch < 0x80)
75 {
76 utf8_ch[0] = ch & 0x7f;
77 utf8_ch_len = 1;
78 }
79 else if (ch < 0x800)
80 {
81 utf8_ch[0] = 0xc0 | (ch >> 6 & 0x1f);
82 utf8_ch[1] = 0x80 | (ch >> 0 & 0x3f);
83 utf8_ch_len = 2;
84 }
85 else if (ch < 0x10000)
86 {
87 utf8_ch[0] = 0xe0 | (ch >> 12 & 0x0f);
88 utf8_ch[1] = 0x80 | (ch >> 6 & 0x3f);
89 utf8_ch[2] = 0x80 | (ch >> 0 & 0x3f);
90 utf8_ch_len = 3;
91 }
92 else if (ch < 0x200000)
93 {
94 utf8_ch[0] = 0xf0 | (ch >> 18 & 0x07);
95 utf8_ch[1] = 0x80 | (ch >> 12 & 0x3f);
96 utf8_ch[2] = 0x80 | (ch >> 6 & 0x3f);
97 utf8_ch[3] = 0x80 | (ch >> 0 & 0x3f);
98 utf8_ch_len = 4;
99 }
100
101 if (!utf8_dest)
102 {
103 written += utf8_ch_len;
104 continue;
105 }
106
107 if (utf8_bytes_max >= utf8_ch_len)
108 {
109 memcpy(utf8_dest, utf8_ch, utf8_ch_len);
110 utf8_dest += utf8_ch_len;
111 utf8_bytes_max -= utf8_ch_len;
112 written += utf8_ch_len;
113 }
114 else
115 {
116 utf8_bytes_max = 0;
117 status = STATUS_BUFFER_TOO_SMALL;
118 }
119 }
120
121 *utf8_bytes_written = written;
122 return status;
123 }
124
125
126 /******************************************************************************
127 * RtlUTF8ToUnicodeN [NTDLL.@]
128 */
129 NTSTATUS NTAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max,
130 ULONG *uni_bytes_written,
131 const CHAR *utf8_src, ULONG utf8_bytes)
132 {
133 NTSTATUS status;
134 ULONG i, j;
135 ULONG written;
136 ULONG ch;
137 ULONG utf8_trail_bytes;
138 WCHAR utf16_ch[3];
139 ULONG utf16_ch_len;
140
141 if (!utf8_src)
142 return STATUS_INVALID_PARAMETER_4;
143 if (!uni_bytes_written)
144 return STATUS_INVALID_PARAMETER;
145
146 written = 0;
147 status = STATUS_SUCCESS;
148
149 for (i = 0; i < utf8_bytes; i++)
150 {
151 /* read UTF-8 lead byte */
152 ch = (BYTE)utf8_src[i];
153 utf8_trail_bytes = 0;
154 if (ch >= 0xf5)
155 {
156 ch = 0xfffd;
157 status = STATUS_SOME_NOT_MAPPED;
158 }
159 else if (ch >= 0xf0)
160 {
161 ch &= 0x07;
162 utf8_trail_bytes = 3;
163 }
164 else if (ch >= 0xe0)
165 {
166 ch &= 0x0f;
167 utf8_trail_bytes = 2;
168 }
169 else if (ch >= 0xc2)
170 {
171 ch &= 0x1f;
172 utf8_trail_bytes = 1;
173 }
174 else if (ch >= 0x80)
175 {
176 /* overlong or trail byte */
177 ch = 0xfffd;
178 status = STATUS_SOME_NOT_MAPPED;
179 }
180
181 /* read UTF-8 trail bytes */
182 if (i + utf8_trail_bytes < utf8_bytes)
183 {
184 for (j = 0; j < utf8_trail_bytes; j++)
185 {
186 if ((utf8_src[i + 1] & 0xc0) == 0x80)
187 {
188 ch <<= 6;
189 ch |= utf8_src[i + 1] & 0x3f;
190 i++;
191 }
192 else
193 {
194 ch = 0xfffd;
195 utf8_trail_bytes = 0;
196 status = STATUS_SOME_NOT_MAPPED;
197 break;
198 }
199 }
200 }
201 else
202 {
203 ch = 0xfffd;
204 utf8_trail_bytes = 0;
205 status = STATUS_SOME_NOT_MAPPED;
206 i = utf8_bytes;
207 }
208
209 /* encode ch as UTF-16 */
210 if ((ch > 0x10ffff) ||
211 (ch >= 0xd800 && ch <= 0xdfff) ||
212 (utf8_trail_bytes == 2 && ch < 0x00800) ||
213 (utf8_trail_bytes == 3 && ch < 0x10000))
214 {
215 /* invalid codepoint or overlong encoding */
216 utf16_ch[0] = 0xfffd;
217 utf16_ch[1] = 0xfffd;
218 utf16_ch[2] = 0xfffd;
219 utf16_ch_len = utf8_trail_bytes;
220 status = STATUS_SOME_NOT_MAPPED;
221 }
222 else if (ch >= 0x10000)
223 {
224 /* surrogate pair */
225 ch -= 0x010000;
226 utf16_ch[0] = 0xd800 + (ch >> 10 & 0x3ff);
227 utf16_ch[1] = 0xdc00 + (ch >> 0 & 0x3ff);
228 utf16_ch_len = 2;
229 }
230 else
231 {
232 /* single unit */
233 utf16_ch[0] = ch;
234 utf16_ch_len = 1;
235 }
236
237 if (!uni_dest)
238 {
239 written += utf16_ch_len;
240 continue;
241 }
242
243 for (j = 0; j < utf16_ch_len; j++)
244 {
245 if (uni_bytes_max >= sizeof(WCHAR))
246 {
247 *uni_dest++ = utf16_ch[j];
248 uni_bytes_max -= sizeof(WCHAR);
249 written++;
250 }
251 else
252 {
253 uni_bytes_max = 0;
254 status = STATUS_BUFFER_TOO_SMALL;
255 }
256 }
257 }
258
259 *uni_bytes_written = written * sizeof(WCHAR);
260 return status;
261 }