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@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// 32typedef ULONG DWORD; 33 34/* PRIVATE FUNCTIONS *********************************************************/ 35 36static __inline 37NTSTATUS 38NTAPI 39RtlStringLengthWorkerA(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 69static __inline 70NTSTATUS 71NTAPI 72RtlStringValidateDestA(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 98static __inline 99NTSTATUS 100NTAPI 101RtlStringExValidateDestA(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 114static __inline 115NTSTATUS 116NTAPI 117RtlStringExValidateSrcA(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 133static __inline 134NTSTATUS 135NTAPI 136RtlStringVPrintfWorkerA(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 174static __inline 175NTSTATUS 176NTAPI 177RtlStringCopyWorkerA(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 211static __inline 212NTSTATUS 213NTAPI 214RtlStringCchCopyA(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 222static __inline 223NTSTATUS 224RtlStringCbPrintfA(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 251static __inline 252NTSTATUS 253RtlStringCbPrintfExA(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 331static __inline 332NTSTATUS 333NTAPI 334RtlStringCbCopyExA(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 408static __inline 409NTSTATUS 410RtlStringCbPrintfW( 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 420static __inline 421NTSTATUS 422NTAPI 423RtlStringCbCatExA(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 494static __inline 495NTSTATUS 496NTAPI 497RtlStringCbCopyA(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