8bb4d141235a2c20dc65b4122c910fa2ded4ba9b
[reactos.git] / reactos / include / ddk / ntstrsafe.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: include/ddk/ntstrsafe.h
5 * PURPOSE: Safe String Library for NT Code (Native/Kernel)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #ifndef _NTSTRSAFE_H_INCLUDED_
12 #define _NTSTRSAFE_H_INCLUDED_
13
14 //
15 // Dependencies
16 //
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdarg.h>
20
21 //
22 // Maximum limits: allow overriding the maximum
23 //
24 #ifndef NTSTRSAFE_MAX_CCH
25 #define NTSTRSAFE_MAX_CCH 2147483647
26 #endif
27 #define NTSTRSAFE_MAX_LENGTH (NTSTRSAFE_MAX_CCH - 1)
28
29 //
30 // Typedefs
31 //
32 typedef unsigned long DWORD;
33
34 #ifndef UNIMPLEMENTED
35 #define UNIMPLEMENTED DbgPrint("WARNING: %s at %s:%d is UNIMPLEMENTED!\n",__FUNCTION__,__FILE__,__LINE__);
36 #endif
37
38 /* PRIVATE FUNCTIONS *********************************************************/
39
40 FORCEINLINE
41 NTSTATUS
42 NTAPI
43 RtlStringLengthWorkerA(IN PCHAR String,
44 IN SIZE_T MaxLength,
45 OUT PSIZE_T ReturnLength OPTIONAL)
46 {
47 NTSTATUS Status = STATUS_SUCCESS;
48 SIZE_T LocalMax = MaxLength;
49
50 while (MaxLength && (*String != ANSI_NULL))
51 {
52 String++;
53 MaxLength--;
54 }
55
56 if (!MaxLength) Status = STATUS_INVALID_PARAMETER;
57
58 if (ReturnLength)
59 {
60 if (NT_SUCCESS(Status))
61 {
62 *ReturnLength = LocalMax - MaxLength;
63 }
64 else
65 {
66 *ReturnLength = 0;
67 }
68 }
69
70 return Status;
71 }
72
73 FORCEINLINE
74 NTSTATUS
75 NTAPI
76 RtlStringValidateDestA(IN PCHAR Destination,
77 IN SIZE_T Length,
78 OUT PSIZE_T ReturnLength OPTIONAL,
79 IN SIZE_T MaxLength)
80 {
81 NTSTATUS Status = STATUS_SUCCESS;
82
83 if (!(Length) || (Length > MaxLength)) Status = STATUS_INVALID_PARAMETER;
84
85 if (ReturnLength)
86 {
87 if (NT_SUCCESS(Status))
88 {
89 Status = RtlStringLengthWorkerA(Destination,
90 Length,
91 ReturnLength);
92 }
93 else
94 {
95 *ReturnLength = 0;
96 }
97 }
98
99 return Status;
100 }
101
102 FORCEINLINE
103 NTSTATUS
104 NTAPI
105 RtlStringExValidateDestA(IN OUT PCHAR *Destination,
106 IN OUT PSIZE_T DestinationLength,
107 OUT PSIZE_T ReturnLength OPTIONAL,
108 IN SIZE_T MaxLength,
109 IN DWORD Flags)
110 {
111 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
112 return RtlStringValidateDestA(*Destination,
113 *DestinationLength,
114 ReturnLength,
115 MaxLength);
116 }
117
118 FORCEINLINE
119 NTSTATUS
120 NTAPI
121 RtlStringExValidateSrcA(IN OUT PCCHAR *Source OPTIONAL,
122 IN OUT PSIZE_T ReturnLength OPTIONAL,
123 IN SIZE_T MaxLength,
124 IN DWORD Flags)
125 {
126 NTSTATUS Status = STATUS_SUCCESS;
127 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
128
129 if ((ReturnLength) && (*ReturnLength >= MaxLength))
130 {
131 Status = STATUS_INVALID_PARAMETER;
132 }
133
134 return Status;
135 }
136
137 FORCEINLINE
138 NTSTATUS
139 NTAPI
140 RtlStringVPrintfWorkerA(OUT PCHAR Destination,
141 IN SIZE_T Length,
142 OUT PSIZE_T NewLength OPTIONAL,
143 IN PCCHAR Format,
144 IN va_list argList)
145 {
146 NTSTATUS Status = STATUS_SUCCESS;
147 LONG Return;
148 SIZE_T MaxLength, LocalNewLength = 0;
149
150 MaxLength = Length - 1;
151
152 Return = _vsnprintf(Destination, MaxLength, Format, argList);
153 if ((Return < 0) || ((SIZE_T)Return > MaxLength))
154 {
155 Destination += MaxLength;
156 *Destination = ANSI_NULL;
157
158 LocalNewLength = MaxLength;
159
160 Status = STATUS_BUFFER_OVERFLOW;
161 }
162 else if ((SIZE_T)Return == MaxLength)
163 {
164 Destination += MaxLength;
165 *Destination = ANSI_NULL;
166
167 LocalNewLength = MaxLength;
168 }
169 else
170 {
171 LocalNewLength = Return;
172 }
173
174 if (NewLength) *NewLength = LocalNewLength;
175 return Status;
176 }
177
178 FORCEINLINE
179 NTSTATUS
180 NTAPI
181 RtlStringCopyWorkerA(OUT PCHAR Destination,
182 IN SIZE_T Length,
183 OUT PSIZE_T NewLength OPTIONAL,
184 IN PCCHAR Source,
185 IN SIZE_T CopyLength)
186 {
187 NTSTATUS Status = STATUS_SUCCESS;
188 SIZE_T LocalNewLength = 0;
189
190 while ((Length) && (CopyLength) && (*Source != ANSI_NULL))
191 {
192 *Destination++ = *Source++;
193 Length--;
194 CopyLength--;
195
196 LocalNewLength++;
197 }
198
199 if (!Length)
200 {
201 Destination--;
202 LocalNewLength--;
203
204 Status = STATUS_BUFFER_OVERFLOW;
205 }
206
207 *Destination = ANSI_NULL;
208
209 if (NewLength) *NewLength = LocalNewLength;
210 return Status;
211 }
212
213 /* PUBLIC FUNCTIONS **********************************************************/
214
215 NTSTATUS
216 NTAPI
217 RtlStringCbPrintfA(OUT PCHAR Destination,
218 IN SIZE_T Length,
219 IN PCHAR Format,
220 ...)
221 {
222 NTSTATUS Status;
223 SIZE_T CharLength = Length / sizeof(CHAR);
224 va_list argList;
225
226 Status = RtlStringValidateDestA(Destination,
227 CharLength,
228 NULL,
229 NTSTRSAFE_MAX_CCH);
230 if (NT_SUCCESS(Status))
231 {
232 va_start(argList, Format);
233 Status = RtlStringVPrintfWorkerA(Destination,
234 CharLength,
235 NULL,
236 Format,
237 argList);
238 va_end(argList);
239 }
240
241 return Status;
242 }
243
244 NTSTATUS
245 NTAPI
246 RtlStringCbPrintfExA(OUT PCHAR Destination,
247 IN SIZE_T Length,
248 OUT PCHAR *DestinationEnd OPTIONAL,
249 OUT PSIZE_T RemainingSize OPTIONAL,
250 IN DWORD Flags,
251 IN PCCHAR Format,
252 ...)
253 {
254 NTSTATUS Status;
255 SIZE_T CharLength = Length / sizeof(CHAR), Remaining, LocalNewLength = 0;
256 PCHAR LocalDestinationEnd;
257 va_list argList;
258 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
259
260 Status = RtlStringExValidateDestA(&Destination,
261 &CharLength,
262 NULL,
263 NTSTRSAFE_MAX_CCH,
264 Flags);
265 if (NT_SUCCESS(Status))
266 {
267 LocalDestinationEnd = Destination;
268 Remaining = CharLength;
269
270 Status = RtlStringExValidateSrcA(&Format,
271 NULL,
272 NTSTRSAFE_MAX_CCH,
273 Flags);
274 if (NT_SUCCESS(Status))
275 {
276 if (!Length)
277 {
278 if (*Format != ANSI_NULL)
279 {
280 if (!Destination)
281 {
282 Status = STATUS_INVALID_PARAMETER;
283 }
284 else
285 {
286 Status = STATUS_BUFFER_OVERFLOW;
287 }
288 }
289 }
290 else
291 {
292 va_start(argList, Format);
293 Status = RtlStringVPrintfWorkerA(Destination,
294 CharLength,
295 &LocalNewLength,
296 Format,
297 argList);
298 va_end(argList);
299
300 LocalDestinationEnd = Destination + LocalNewLength;
301 Remaining = CharLength - LocalNewLength;
302 }
303 }
304 else
305 {
306 if (Length) *Destination = ANSI_NULL;
307 }
308
309 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
310 {
311 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
312
313 if (RemainingSize)
314 {
315 *RemainingSize = (Remaining * sizeof(CHAR)) +
316 (Length % sizeof(CHAR));
317 }
318 }
319 }
320
321 return Status;
322 }
323
324 FORCEINLINE
325 NTSTATUS
326 NTAPI
327 RtlStringCbCopyExA(OUT PCHAR Destination,
328 IN SIZE_T Length,
329 IN PCCHAR Source,
330 OUT PCHAR *DestinationEnd OPTIONAL,
331 OUT PSIZE_T RemainingSize OPTIONAL,
332 IN DWORD Flags)
333 {
334 NTSTATUS Status;
335 SIZE_T CharLength = Length / sizeof(CHAR), Copied = 0, Remaining;
336 PCHAR LocalDestinationEnd;
337 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
338
339 Status = RtlStringExValidateDestA(&Destination,
340 &Length,
341 NULL,
342 NTSTRSAFE_MAX_CCH,
343 Flags);
344 if (NT_SUCCESS(Status))
345 {
346 LocalDestinationEnd = Destination;
347 Remaining = CharLength;
348
349 Status = RtlStringExValidateSrcA(&Source,
350 NULL,
351 NTSTRSAFE_MAX_CCH,
352 Flags);
353 if (NT_SUCCESS(Status))
354 {
355 if (!CharLength)
356 {
357 if (*Source != ANSI_NULL)
358 {
359 if (!Destination)
360 {
361 Status = STATUS_INVALID_PARAMETER;
362 }
363 else
364 {
365 Status = STATUS_BUFFER_OVERFLOW;
366 }
367 }
368 }
369 else
370 {
371 Status = RtlStringCopyWorkerA(Destination,
372 CharLength,
373 &Copied,
374 Source,
375 NTSTRSAFE_MAX_LENGTH);
376
377 LocalDestinationEnd = Destination + Copied;
378 Remaining = CharLength - Copied;
379 }
380 }
381 else
382 {
383 if (CharLength) *Destination = ANSI_NULL;
384 }
385
386 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
387 {
388 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
389
390 if (RemainingSize)
391 {
392 *RemainingSize = (Remaining * sizeof(CHAR)) +
393 (Length % sizeof(CHAR));
394 }
395 }
396 }
397
398 return Status;
399 }
400
401
402 NTSTATUS
403 NTAPI
404 RtlStringCbPrintfW(
405 LPWSTR pszDest,
406 IN size_t cbDest,
407 IN LPCWSTR pszFormat,
408 ...)
409 {
410 UNIMPLEMENTED
411 return STATUS_NOT_IMPLEMENTED;
412 }
413
414 FORCEINLINE
415 NTSTATUS
416 NTAPI
417 RtlStringCbCatExA(IN OUT PCHAR Destination,
418 IN SIZE_T Length,
419 IN PCCHAR Source,
420 OUT PCHAR *DestinationEnd OPTIONAL,
421 OUT PSIZE_T RemainingSize OPTIONAL,
422 IN DWORD Flags)
423 {
424 NTSTATUS Status;
425 SIZE_T CharLength = Length / sizeof(CHAR);
426 SIZE_T DestinationLength, Remaining, Copied = 0;
427 PCHAR LocalDestinationEnd;
428 //ASSERTMSG("We don't support Extended Flags yet!\n", Flags == 0);
429
430 Status = RtlStringExValidateDestA(&Destination,
431 &CharLength,
432 &DestinationLength,
433 NTSTRSAFE_MAX_CCH,
434 Flags);
435 if (NT_SUCCESS(Status))
436 {
437 LocalDestinationEnd = Destination + DestinationLength;
438 Remaining = CharLength - DestinationLength;
439
440 Status = RtlStringExValidateSrcA(&Source,
441 NULL,
442 NTSTRSAFE_MAX_CCH,
443 Flags);
444 if (NT_SUCCESS(Status))
445 {
446 if (Remaining <= 1)
447 {
448 if (*Source != ANSI_NULL)
449 {
450 if (!Destination)
451 {
452 Status = STATUS_INVALID_PARAMETER;
453 }
454 else
455 {
456 Status = STATUS_BUFFER_OVERFLOW;
457 }
458 }
459 }
460 else
461 {
462 Status = RtlStringCopyWorkerA(LocalDestinationEnd,
463 Remaining,
464 &Copied,
465 Source,
466 NTSTRSAFE_MAX_LENGTH);
467
468 LocalDestinationEnd = LocalDestinationEnd + Copied;
469 Remaining = Remaining - Copied;
470 }
471 }
472
473 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
474 {
475 if (DestinationEnd) *DestinationEnd = LocalDestinationEnd;
476
477 if (RemainingSize)
478 {
479 *RemainingSize = (Remaining * sizeof(CHAR)) +
480 (Length % sizeof(CHAR));
481 }
482 }
483 }
484
485 return Status;
486 }
487
488 FORCEINLINE
489 NTSTATUS
490 NTAPI
491 RtlStringCbCopyA(OUT PCHAR Destination,
492 IN SIZE_T Length,
493 IN PCCHAR Source)
494 {
495 NTSTATUS Status;
496 SIZE_T CharLength = Length / sizeof(CHAR);
497
498 Status = RtlStringValidateDestA(Destination,
499 CharLength,
500 NULL,
501 NTSTRSAFE_MAX_CCH);
502 if (NT_SUCCESS(Status))
503 {
504 Status = RtlStringCopyWorkerA(Destination,
505 CharLength,
506 NULL,
507 Source,
508 NTSTRSAFE_MAX_LENGTH);
509 }
510
511 return Status;
512 }
513
514 #endif