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