[NTOSKRNL_VISTA]
[reactos.git] / reactos / 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 #ifndef __REACTOS__
74 assert(ch <= 0x10ffff);
75 #endif
76 if (ch < 0x80)
77 {
78 utf8_ch[0] = ch & 0x7f;
79 utf8_ch_len = 1;
80 }
81 else if (ch < 0x800)
82 {
83 utf8_ch[0] = 0xc0 | (ch >> 6 & 0x1f);
84 utf8_ch[1] = 0x80 | (ch >> 0 & 0x3f);
85 utf8_ch_len = 2;
86 }
87 else if (ch < 0x10000)
88 {
89 utf8_ch[0] = 0xe0 | (ch >> 12 & 0x0f);
90 utf8_ch[1] = 0x80 | (ch >> 6 & 0x3f);
91 utf8_ch[2] = 0x80 | (ch >> 0 & 0x3f);
92 utf8_ch_len = 3;
93 }
94 else if (ch < 0x200000)
95 {
96 utf8_ch[0] = 0xf0 | (ch >> 18 & 0x07);
97 utf8_ch[1] = 0x80 | (ch >> 12 & 0x3f);
98 utf8_ch[2] = 0x80 | (ch >> 6 & 0x3f);
99 utf8_ch[3] = 0x80 | (ch >> 0 & 0x3f);
100 utf8_ch_len = 4;
101 }
102
103 if (!utf8_dest)
104 {
105 written += utf8_ch_len;
106 continue;
107 }
108
109 if (utf8_bytes_max >= utf8_ch_len)
110 {
111 memcpy(utf8_dest, utf8_ch, utf8_ch_len);
112 utf8_dest += utf8_ch_len;
113 utf8_bytes_max -= utf8_ch_len;
114 written += utf8_ch_len;
115 }
116 else
117 {
118 utf8_bytes_max = 0;
119 status = STATUS_BUFFER_TOO_SMALL;
120 }
121 }
122
123 *utf8_bytes_written = written;
124 return status;
125 }
126
127
128 /******************************************************************************
129 * RtlUTF8ToUnicodeN [NTDLL.@]
130 */
131 NTSTATUS NTAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max,
132 ULONG *uni_bytes_written,
133 const CHAR *utf8_src, ULONG utf8_bytes)
134 {
135 NTSTATUS status;
136 ULONG i, j;
137 ULONG written;
138 ULONG ch;
139 ULONG utf8_trail_bytes;
140 WCHAR utf16_ch[3];
141 ULONG utf16_ch_len;
142
143 if (!utf8_src)
144 return STATUS_INVALID_PARAMETER_4;
145 if (!uni_bytes_written)
146 return STATUS_INVALID_PARAMETER;
147
148 written = 0;
149 status = STATUS_SUCCESS;
150
151 for (i = 0; i < utf8_bytes; i++)
152 {
153 /* read UTF-8 lead byte */
154 ch = (BYTE)utf8_src[i];
155 utf8_trail_bytes = 0;
156 if (ch >= 0xf5)
157 {
158 ch = 0xfffd;
159 status = STATUS_SOME_NOT_MAPPED;
160 }
161 else if (ch >= 0xf0)
162 {
163 ch &= 0x07;
164 utf8_trail_bytes = 3;
165 }
166 else if (ch >= 0xe0)
167 {
168 ch &= 0x0f;
169 utf8_trail_bytes = 2;
170 }
171 else if (ch >= 0xc2)
172 {
173 ch &= 0x1f;
174 utf8_trail_bytes = 1;
175 }
176 else if (ch >= 0x80)
177 {
178 /* overlong or trail byte */
179 ch = 0xfffd;
180 status = STATUS_SOME_NOT_MAPPED;
181 }
182
183 /* read UTF-8 trail bytes */
184 if (i + utf8_trail_bytes < utf8_bytes)
185 {
186 for (j = 0; j < utf8_trail_bytes; j++)
187 {
188 if ((utf8_src[i + 1] & 0xc0) == 0x80)
189 {
190 ch <<= 6;
191 ch |= utf8_src[i + 1] & 0x3f;
192 i++;
193 }
194 else
195 {
196 ch = 0xfffd;
197 utf8_trail_bytes = 0;
198 status = STATUS_SOME_NOT_MAPPED;
199 break;
200 }
201 }
202 }
203 else
204 {
205 ch = 0xfffd;
206 utf8_trail_bytes = 0;
207 status = STATUS_SOME_NOT_MAPPED;
208 i = utf8_bytes;
209 }
210
211 /* encode ch as UTF-16 */
212 if ((ch > 0x10ffff) ||
213 (ch >= 0xd800 && ch <= 0xdfff) ||
214 (utf8_trail_bytes == 2 && ch < 0x00800) ||
215 (utf8_trail_bytes == 3 && ch < 0x10000))
216 {
217 /* invalid codepoint or overlong encoding */
218 utf16_ch[0] = 0xfffd;
219 utf16_ch[1] = 0xfffd;
220 utf16_ch[2] = 0xfffd;
221 utf16_ch_len = utf8_trail_bytes;
222 status = STATUS_SOME_NOT_MAPPED;
223 }
224 else if (ch >= 0x10000)
225 {
226 /* surrogate pair */
227 ch -= 0x010000;
228 utf16_ch[0] = 0xd800 + (ch >> 10 & 0x3ff);
229 utf16_ch[1] = 0xdc00 + (ch >> 0 & 0x3ff);
230 utf16_ch_len = 2;
231 }
232 else
233 {
234 /* single unit */
235 utf16_ch[0] = ch;
236 utf16_ch_len = 1;
237 }
238
239 if (!uni_dest)
240 {
241 written += utf16_ch_len;
242 continue;
243 }
244
245 for (j = 0; j < utf16_ch_len; j++)
246 {
247 if (uni_bytes_max >= sizeof(WCHAR))
248 {
249 *uni_dest++ = utf16_ch[j];
250 uni_bytes_max -= sizeof(WCHAR);
251 written++;
252 }
253 else
254 {
255 uni_bytes_max = 0;
256 status = STATUS_BUFFER_TOO_SMALL;
257 }
258 }
259 }
260
261 *uni_bytes_written = written * sizeof(WCHAR);
262 return status;
263 }