/*++

Copyright (c) Microsoft Corporation. All rights reserved.

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    ntrtlstringandbuffer.h

Abstract:

    Broken out from nturtl and rtl so I can move it between them in separate
    trees without merge madness. To be integrated into ntrtl.h

--*/

#ifndef _NTRTL_STRING_AND_BUFFER_
#define _NTRTL_STRING_AND_BUFFER_

#if _MSC_VER >= 1100
#pragma once
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if defined (_MSC_VER)
#if ( _MSC_VER >= 800 )
#pragma warning(disable:4514)
#if _MSC_VER >= 1200
#pragma warning(push)
#endif
#pragma warning(disable:4001)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#endif
#endif

//
// not NTSYSAPI so easily statically linked to
//

//
// These work for both UNICODE_STRING and STRING.
// That's why "plain" 0 and sizeof(Buffer[0]) is used.
//

// odd but correct use of RTL_STRING_IS_PUT_AT_SAFE instead of RTL_STRING_IS_GET_AT_SAFE,
// we are reaching past the Length
#define RTL_STRING_IS_NUL_TERMINATED(s)    (RTL_STRING_IS_PUT_AT_SAFE(s, RTL_STRING_GET_LENGTH_CHARS(s), 0) \
                                           && RTL_STRING_GET_AT_UNSAFE(s, RTL_STRING_GET_LENGTH_CHARS(s)) == 0)

#define RTL_STRING_NUL_TERMINATE(s)        ((VOID)(ASSERT(RTL_STRING_IS_PUT_AT_SAFE(s, RTL_STRING_GET_LENGTH_CHARS(s), 0)), \
                                           ((s)->Buffer[RTL_STRING_GET_LENGTH_CHARS(s)] = 0)))

#define RTL_NUL_TERMINATE_STRING(s)        (RTL_STRING_NUL_TERMINATE(s)) /* compatibility */

#define RTL_STRING_MAKE_LENGTH_INCLUDE_TERMINAL_NUL(s) ((VOID)(ASSERT(RTL_STRING_IS_NUL_TERMINATED(s)), \
                                                       ((s)->Length += sizeof((s)->Buffer[0]))))

#define RTL_STRING_IS_EMPTY(s)             ((s)->Length == 0)

#define RTL_STRING_GET_LAST_CHAR(s)        (RTL_STRING_GET_AT((s), RTL_STRING_GET_LENGTH_CHARS(s) - 1))

#define RTL_STRING_GET_LENGTH_CHARS(s)     ((s)->Length / sizeof((s)->Buffer[0]))
#define RTL_STRING_GET_MAX_LENGTH_CHARS(s) ((s)->MaximumLength / sizeof((s)->Buffer[0]))
#define RTL_STRING_GET_LENGTH_BYTES(s)     ((s)->Length)

#define RTL_STRING_SET_LENGTH_CHARS_UNSAFE(s,n) ((s)->Length = (RTL_STRING_LENGTH_TYPE)(((n) * sizeof(s)->Buffer[0])))

//
// We don't provide an explicit/retail RTL_STRING_GET_AT_SAFE because it'd
// need a return value distinct from all values of c. -1? NTSTATUS? Seems too heavy.
//
// For consistency then, we also don't provide RTL_STRING_PUT_AT_SAFE.
//

#define RTL_STRING_IS_GET_AT_SAFE(s,n)   ((n) < RTL_STRING_GET_LENGTH_CHARS(s))
#define RTL_STRING_GET_AT_UNSAFE(s,n)    ((s)->Buffer[n])
#define RTLP_STRING_GET_AT_SAFE(s,n)     (RTL_STRING_IS_GET_AT_SAFE(s,n) ? RTL_STRING_GET_AT_UNSAFE(s,n) : 0)

#define RTL_STRING_IS_PUT_AT_SAFE(s,n,c) ((n) < RTL_STRING_GET_MAX_LENGTH_CHARS(s))
#define RTL_STRING_PUT_AT_UNSAFE(s,n,c)  ((s)->Buffer[n] = (c))
#define RTLP_STRING_PUT_AT_SAFE(s,n,c)   ((void)(RTL_STRING_IS_PUT_AT_SAFE(s,n,c) ? RTL_STRING_PUT_AT_UNSAFE(s,n,c) : 0))

#if defined(RTL_STRING_RANGE_CHECKED)
#define RTL_STRING_GET_AT(s,n)         (ASSERT(RTL_STRING_IS_GET_AT_SAFE(s,n)), \
                                       RTL_STRING_GET_AT_UNSAFE(s,n))
#else
#define RTL_STRING_GET_AT(s,n)         (RTL_STRING_GET_AT_UNSAFE(s,n))
#endif

#if defined(RTL_STRING_RANGE_CHECKED)
#define RTL_STRING_PUT_AT(s,n,c)       (ASSERT(RTL_STRING_IS_PUT_AT_SAFE(s,n,c)), \
                                       RTL_STRING_PUT_AT_UNSAFE(s,n,c))
#else
#define RTL_STRING_PUT_AT(s,n,c)       (RTL_STRING_PUT_AT_UNSAFE(s,n,c))
#endif

//
// preallocated heap-growable buffers
//
struct _RTL_BUFFER;

#if !defined(RTL_BUFFER)
// This is duplicated in ntldr.h.

#define RTL_BUFFER RTL_BUFFER

typedef struct _RTL_BUFFER {
    PUCHAR    Buffer;
    PUCHAR    StaticBuffer;
    SIZE_T    Size;
    SIZE_T    StaticSize;
    SIZE_T    ReservedForAllocatedSize; // for future doubling
    PVOID     ReservedForIMalloc; // for future pluggable growth
} RTL_BUFFER, *PRTL_BUFFER;

#endif

#define RTLP_BUFFER_IS_HEAP_ALLOCATED(b) ((b)->Buffer != (b)->StaticBuffer)

//++
//
// NTSTATUS
// RtlInitBuffer(
//     OUT PRTL_BUFFER Buffer,
//     IN  PUCHAR      StaticBuffer,
//     IN  SIZE_T      StaticSize
//     );
//
// Routine Description:
//
// Initialize a preallocated heap-growable buffer.
//
// Arguments:
//
//     Buffer - "this"
//     StaticBuffer - preallocated storage for Buffer to use until/unless more than StaticSize is needed
//     StaticSize - the size of StaticBuffer in bytes
//
// Return Value:
//
//     STATUS_SUCCESS
//
//--
#define RtlInitBuffer(Buff, StatBuff, StatSize) \
    do {                                        \
        (Buff)->Buffer       = (StatBuff);      \
        (Buff)->Size         = (StatSize);      \
        (Buff)->StaticBuffer = (StatBuff);      \
        (Buff)->StaticSize   = (StatSize);      \
    } while (0)

#define RTL_ENSURE_BUFFER_SIZE_NO_COPY (0x00000001)

NTSYSAPI
NTSTATUS
NTAPI
RtlpEnsureBufferSize(
    IN ULONG           Flags,
    IN OUT PRTL_BUFFER Buffer,
    IN SIZE_T          NewSizeBytes
    );

//++
//
// NTSTATUS
// RtlEnsureBufferSize(
//      IN OUT PRTL_BUFFER Buffer,
//      IN     SIZE_T      NewSizeBytes
//      );
//
// Routine Description:
//
// If Buffer is smaller than NewSize, grow it to NewSize, using the static buffer if it
// is large enough, else heap allocating
//
// Arguments:
//
//     Flags -
//               RTL_ENSURE_BUFFER_SIZE_NO_COPY
//     Buffer -
//     NewSizeBytes -
//
// Return Value:
//
//     STATUS_SUCCESS
//     STATUS_NO_MEMORY
//
//--
#define RtlEnsureBufferSize(Flags, Buff, NewSizeBytes) \
    (   ((Buff) != NULL && (NewSizeBytes) <= (Buff)->Size) \
        ? STATUS_SUCCESS \
        : RtlpEnsureBufferSize((Flags), (Buff), (NewSizeBytes)) \
    )

//++
//
// VOID
// RtlFreeBuffer(
//     IN OUT PRTL_BUFFER Buffer,
//     );
//
//
// Routine Description:
//
// Free any heap allocated storage associated with Buffer.
// Notes:
// - RtlFreeBuffer returns a buffer to the state it was in after
//   calling RtlInitBuffer, so you may reuse it.
// - If you want to shrink the buffer without freeing it, just poke Buffer->Size down.
//     This is safe regardless of if the buffer has gone heap allocated or not.
// - You may RtlFreeBuffer an RTL_BUFFER that is all zeros. You do not need to track if you
//     called RtlInitBuffer if you know you filled it with zeros.
// - You may RtlFreeBuffer an RTL_BUFFER repeatedly.
//
// Arguments:
//
//     Buffer -
//
// Return Value:
//
//     none, unconditional success
//
//--
#define RtlFreeBuffer(Buff)                              \
    do {                                                 \
        if ((Buff) != NULL && (Buff)->Buffer != NULL) {  \
            if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buff)) {   \
                UNICODE_STRING UnicodeString;            \
                UnicodeString.Buffer = (PWSTR)(PVOID)(Buff)->Buffer; \
                RtlFreeUnicodeString(&UnicodeString);    \
            }                                            \
            (Buff)->Buffer = (Buff)->StaticBuffer;       \
            (Buff)->Size = (Buff)->StaticSize;           \
        }                                                \
    } while (0)

//
// a preallocated buffer that is "tied" to a UNICODE_STRING
//
struct _RTL_UNICODE_STRING_BUFFER;

typedef struct _RTL_UNICODE_STRING_BUFFER {
    UNICODE_STRING String;
    RTL_BUFFER     ByteBuffer;
    UCHAR          MinimumStaticBufferForTerminalNul[sizeof(WCHAR)];
} RTL_UNICODE_STRING_BUFFER, *PRTL_UNICODE_STRING_BUFFER;

//
// MAX_UNICODE_STRING_MAXLENGTH is the maximum allowed value for UNICODE_STRING::MaximumLength.
// MAX_UNICODE_STRING_LENGTH is the maximum allowed value for UNICODE_STRING::Length, allowing
//   room for a terminal nul.
//
// Explanation of MAX_UNICODE_STRING_MAXLENGTH implementation
//   ~0 is all bits set, maximum value in two's complement arithmetic, which C guarantees for unsigned types
//   << shifts out the number of bits that fit in UNICODE_STRING::Length
//   ~ and now we have all bits set that fit in UNICODE_STRING::Length,
//     like if UNICODE_STRING::Length is 16 bits, we have 0xFFFF
//   then mask so it is even multiple of whatever UNICODE_STRING::Buffer points to.
//   If Length is changed to ULONG or SIZE_T, this macro is still correct.
//   If Buffer pointed to CHAR or "WIDER_CHAR" or something else, this macro is still correct.
//
#define MAX_UNICODE_STRING_MAXLENGTH  ((~((~(SIZE_T)0) << (RTL_FIELD_SIZE(UNICODE_STRING, Length) * CHAR_BIT))) & ~(sizeof(((PCUNICODE_STRING)0)->Buffer[0]) - 1))
#define MAX_UNICODE_STRING_LENGTH     (MAX_UNICODE_STRING_MAXLENGTH - sizeof(((PCUNICODE_STRING)0)->Buffer[0]))

//++
//
// NTSTATUS
// RtlInitUnicodeStringBuffer(
//     OUT PRTL_UNICODE_STRING_BUFFER Buffer,
//     IN  PUCHAR                     StaticBuffer,
//     IN  SIZE_T                     StaticSize
//     );
//
// Routine Description:
//
//
// Arguments:
//
//     Buffer -
//     StaticBuffer - can be NULL, but generally is not
//     StaticSize - should be at least sizeof(WCHAR), but can be zero
//                  ought to be an even multiple of sizeof(WCHAR)
//                  gets rounded to down to an even multiple of sizeof(WCHAR)
//                  gets clamped to MAX_UNICODE_STRING_MAXLENGTH (64k - 2)
//
// RTL_UNICODE_STRING_BUFFER contains room for the terminal nul for the
// case of StaticBuffer == NULL or StaticSize < sizeof(WCHAR), or, more likely,
// for RtlTakeRemainingStaticBuffer leaving it with no static buffer.
//
// Return Value:
//
//     STATUS_SUCCESS
//
//--
#define RtlInitUnicodeStringBuffer(Buff, StatBuff, StatSize)      \
    do {                                                          \
        SIZE_T TempStaticSize = (StatSize);                       \
        PUCHAR TempStaticBuff = (StatBuff);                       \
        TempStaticSize &= ~(sizeof((Buff)->String.Buffer[0]) - 1);  \
        if (TempStaticSize > UNICODE_STRING_MAX_BYTES) {          \
            TempStaticSize = UNICODE_STRING_MAX_BYTES;            \
        }                                                         \
        if (TempStaticSize < sizeof(WCHAR)) {                     \
            TempStaticBuff = (Buff)->MinimumStaticBufferForTerminalNul; \
            TempStaticSize = sizeof(WCHAR);                       \
        }                                                         \
        RtlInitBuffer(&(Buff)->ByteBuffer, TempStaticBuff, TempStaticSize); \
        (Buff)->String.Buffer = (WCHAR*)TempStaticBuff;           \
        if ((Buff)->String.Buffer != NULL)                        \
            (Buff)->String.Buffer[0] = 0;                         \
        (Buff)->String.Length = 0;                                \
        (Buff)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)TempStaticSize;    \
    } while (0)

//++
//
// NTSTATUS
// RtlSyncStringToBuffer(
//      IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer
//      );
//
// Routine Description:
//
// After carefully modifying the underlying RTL_BUFFER, this updates
// dependent fields in the underlying UNICODE_STRING.
//
// For example, use this after you grow the buffer with RtlEnsureBufferSize,
// but that example you don't need, use RtlEnsureUnicodeStringBufferSizeChars
// or RtlEnsureStringBufferSizeBytes.
//
// Arguments:
//
//     UnicodeStringBuffer - 
//
// Return Value:
//
//     STATUS_SUCCESS
//
//--
#define RtlSyncStringToBuffer(x)                                            \
    (                                                                       \
      ( ASSERT((x)->String.Length < (x)->ByteBuffer.Size)                ), \
      ( ASSERT((x)->String.MaximumLength >= (x)->String.Length)          ), \
      ( ASSERT((x)->String.MaximumLength <= (x)->ByteBuffer.Size)        ), \
      ( (x)->String.Buffer        = (PWSTR)(x)->ByteBuffer.Buffer        ), \
      ( (x)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)((x)->ByteBuffer.Size) ), \
      ( ASSERT(RTL_STRING_IS_NUL_TERMINATED(&(x)->String))               ), \
      ( STATUS_SUCCESS                                                   )  \
    )

//++
//
// NTSTATUS
// RtlSyncBufferToString(
//      IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer
//      );
//
// Routine Description:
//
// After carefully modifying the underlying UNICODE_STRING, this updates
// dependent fields in the underlying RTL_BUFFER.
//
// For example, use this after you the alloc the buffer with RtlAnsiStringToUnicodeString.
// This is possible because RTL_BUFFER deliberately uses the same memory allocator
// as RtlAnsiStringToUnicodeString.
//
// Arguments:
//
//     UnicodeStringBuffer - 
//
// Return Value:
//
//     STATUS_SUCCESS
//
//--
#define RtlSyncBufferToString(Buff_)                                         \
    (                                                                        \
      ( (Buff_)->ByteBuffer.Buffer        = (Buff_)->String.Buffer        ), \
      ( (Buff_)->ByteBuffer.Buffer.Size   = (Buff_)->String.MaximumLength ), \
      ( STATUS_SUCCESS )                                                     \
    )

//++
//
// NTSTATUS
// RtlEnsureUnicodeStringBufferSizeChars(
//      IN OUT PRTL_BUFFER Buffer,
//      IN     USHORT      NewSizeChars
//      );
//
// NTSTATUS
// RtlEnsureUnicodeStringBufferSizeBytes(
//      IN OUT PRTL_BUFFER Buffer,
//      IN     USHORT      NewSizeBytes
//      );
//
// Routine Description:
//
// Optionally multiply cch to go from count of character to count of bytes.
// +1 or +2 for you to account for the terminal nul.
// Delegate to underlying RtlEnsureBufferSize.
// Keep String.Buffer, .MaximumLength, and terminal nul in sync.
//
// Arguments:
//
//     Buffer -
//     NewSizeChars -
//     NewSizeBytes - must be a multiple of sizeof(WCHAR), and we don't presently
//                    verify that.
//
// Return Value:
//
//     STATUS_SUCCESS
//     STATUS_NO_MEMORY     - out of memory
//     STATUS_NAME_TOO_LONG - (NewSizeChars + 1) * sizeof(WCHAR) > UNICODE_STRING_MAX_BYTES (USHORT)
//
//--
#define RtlEnsureUnicodeStringBufferSizeBytes(Buff_, NewSizeBytes_)                            \
    (     ( ((NewSizeBytes_) + sizeof((Buff_)->String.Buffer[0])) > UNICODE_STRING_MAX_BYTES ) \
        ? STATUS_NAME_TOO_LONG                                                                 \
        : !NT_SUCCESS(RtlEnsureBufferSize(0, &(Buff_)->ByteBuffer, ((NewSizeBytes_) + sizeof((Buff_)->String.Buffer[0])))) \
        ? STATUS_NO_MEMORY                                                                      \
        : (RtlSyncStringToBuffer(Buff_))                                                       \
    )

#define RtlEnsureUnicodeStringBufferSizeChars(Buff_, NewSizeChars_) \
    (RtlEnsureUnicodeStringBufferSizeBytes((Buff_), (NewSizeChars_) * sizeof((Buff_)->String.Buffer[0])))

//++
//
// NTSTATUS
// RtlAppendUnicodeStringBuffer(
//     OUT PRTL_UNICODE_STRING_BUFFER Destination,
//     IN  PCUNICODE_STRING           Source
//     );
//
// Routine Description:
//
//
// Arguments:
//
//     Destination - 
//     Source - 
//
// Return Value:
//
//     STATUS_SUCCESS
//     STATUS_NO_MEMORY
//     STATUS_NAME_TOO_LONG (64K UNICODE_STRING length would be exceeded)
//
//--
#define RtlAppendUnicodeStringBuffer(Dest, Source)                            \
    ( ( ( (Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]) ) > UNICODE_STRING_MAX_BYTES ) \
        ? STATUS_NAME_TOO_LONG                                                \
        : (!NT_SUCCESS(                                                       \
                RtlEnsureBufferSize(                                          \
                    0,                                                        \
                    &(Dest)->ByteBuffer,                                          \
                    (Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]) ) ) \
                ? STATUS_NO_MEMORY                                            \
                : ( ( (Dest)->String.Buffer = (PWSTR)(Dest)->ByteBuffer.Buffer ), \
                    ( RtlMoveMemory(                                          \
                        (Dest)->String.Buffer + (Dest)->String.Length / sizeof((Dest)->String.Buffer[0]), \
                        (Source)->Buffer,                                     \
                        (Source)->Length) ),                                  \
                    ( (Dest)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)((Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]))), \
                    ( (Dest)->String.Length = (USHORT) ((Dest)->String.Length + (Source)->Length )),            \
                    ( (Dest)->String.Buffer[(Dest)->String.Length / sizeof((Dest)->String.Buffer[0])] = 0 ), \
                    ( STATUS_SUCCESS ) ) ) )

NTSYSAPI
NTSTATUS
NTAPI
RtlMultiAppendUnicodeStringBuffer(
    OUT PRTL_UNICODE_STRING_BUFFER  Destination,
    IN  ULONG                       NumberOfSources,
    IN  const UNICODE_STRING*       SourceArray
    );

//++
//
// VOID
// RtlFreeUnicodeStringBuffer(
//     OUT PRTL_UNICODE_STRING_BUFFER Buffer
//     );
//
// Routine Description:
//
// Arguments:
//
//     Buffer - 
//
// Return Value:
//
//     none, unconditional success
//
// If Buffer is a local, the stores are generally "dead" (their result
// is never read) and the optimizer should "kill" them (not bother performing them).
//
// A buffer can be freed multiple times.
// A buffer that has been freed is in the same state as one that just been initialized.
// A buffer that is all zeros (RtlZeroMemory) can be freed. You do not need to
//   track if you initialized it.
//--
#define RtlFreeUnicodeStringBuffer(Buff)      \
    do {                                      \
        if ((Buff) != NULL) {                 \
            RtlFreeBuffer(&(Buff)->ByteBuffer);   \
            (Buff)->String.Buffer = (PWSTR)(Buff)->ByteBuffer.StaticBuffer; \
            if ((Buff)->String.Buffer != NULL) \
                (Buff)->String.Buffer[0] = 0;  \
            (Buff)->String.Length = 0;         \
            (Buff)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)(Buff)->ByteBuffer.StaticSize; \
        } \
    } while (0)

//++
//
// NTSTATUS
// RtlAssignUnicodeStringBuffer(
//     IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
//     PCUNICODE_STRING                  String
//     );
// Routine Description:
//
// Arguments:
//
//     Buffer - 
//     String - 
//
// Return Value:
//
//     STATUS_SUCCESS
//     STATUS_NO_MEMORY
//--
#define RtlAssignUnicodeStringBuffer(Buff, Str) \
    (((Buff)->String.Length = 0), (RtlAppendUnicodeStringBuffer((Buff), (Str))))

//++
//
// NTSTATUS
// RtlTakeRemainingStaticBuffer(
//     IN OUT PRTL_BUFFER Buffer,
//     OUT PUCHAR*        RemainingStaticBuffer,
//     OUT SIZE_T*        RemainingStaticSize
//     );
// 
// Routine Description:
//
// This function makes it easy to share a static buffer among
// multiple buffers, as long as the buffers are actually initialized
// and "sealed" linearly/independently/one after another with
// no "overlap" (overlap in control and dataflow, not in actual addresses).
//
// Note that if a buffer is using exactly all of its static buffer, you
// will get back 0 and STATUS_SUCCESS. This is not an error condition.
// This is why RtlInitUnicodeStringBuffer can now accept zero sized static buffers.
//
// Note that even if you violate the conditions that make this function most
// useful, your code will still work, just less quickly.
//
// A pattern that should work is allocating one static buffer and moving it "through"
// multiple buffers. Even if you run out of static space, it should work to
// move the remaining zero size static buffer forward. Of course, you'll heap allocate.
//
// Arguments:
//
//     Buffer - 
//     RemainingStaticBuffer - 
//     RemainingStaticSize - 
//
// Return Value:
//
//     STATUS_SUCCESS
//
//--
#define RtlTakeRemainingStaticBuffer(Buff, OutBuff, OutSize)  \
    (((Buff)->Buffer != (Buff)->StaticBuffer)                 \
    ? ( /* take the whole thing */                            \
        ( *(OutBuff) = (Buff)->StaticBuffer ),                \
        ( *(OutSize) = (Buff)->StaticSize   ),                \
        /* leave the buffer with nothing */                   \
        ( (Buff)->StaticBuffer = NULL       ),                \
        ( (Buff)->StaticSize = 0            ),                \
        ( STATUS_SUCCESS                    )                 \
      )                                                       \
    : ( /* only take what isn't being used */                 \
        ( *(OutBuff) = &(Buff)->StaticBuffer[(Buff)->Size] ), \
        ( *(OutSize) = ((Buff)->StaticSize - (Buff)->Size) ), \
        /* leave the buffer with just what it is using */     \
        ( (Buff)->StaticSize = (Buff)->Size                ), \
        ( STATUS_SUCCESS                                   )  \
      ))

NTSTATUS
NTAPI
RtlPrependStringToUnicodeStringBuffer(
    IN     ULONG                      Flags,
    IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer,
    IN     PCUNICODE_STRING           UnicodeString
    );

NTSTATUS
NTAPI
RtlUnicodeStringBufferRight(
    IN     ULONG                      Flags,
    IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
    IN     ULONG                      Length
    );

NTSTATUS
NTAPI
RtlUnicodeStringBufferLeft(
    IN     ULONG                      Flags,
    IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
    IN     ULONG                      Length
    );

NTSTATUS
NTAPI
RtlUnicodeStringBufferMid(
    IN     ULONG                      Flags,
    IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
    IN     ULONG                      Offset,
    IN     ULONG                      Length
    );

NTSTATUS
NTAPI
RtlInsertStringIntoUnicodeStringBuffer(
    IN     ULONG                      Flags,
    IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer,
    IN     ULONG                      Offset,
    IN     PCUNICODE_STRING           InsertString
    );

NTSTATUS
NTAPI
RtlBufferTakeValue(
    IN     ULONG       Flags,
    IN OUT PRTL_BUFFER DestinationBuffer,
    IN OUT PRTL_BUFFER SourceBuffer
    );

//++
//
// NTSTATUS
// RtlUnicodeStringBufferTakeValue(
//      OUT NTSTATUS* Status,
//      IN ULONG      Flags,
//      IN OUT RTL_UNICODE_STRING_BUFFER DestinationBuffer,
//      IN OUT RTL_UNICODE_STRING_BUFFER SourceBuffer
//      );
//
//--
#define RtlUnicodeStringBufferTakeValue(Status, Flags, DestinationBuffer, SourceBuffer) \
    ( \
      ((Flags) != 0) \
    ? (*(Status) = STATUS_INVALID_PARAMETER) \
    : (!NT_SUCCESS(*(Status) = RtlBufferTakeValue(0, &(DestinationBuffer)->ByteBuffer, &(SourceBuffer)->ByteBuffer))) \
    ? (*(Status)) \
    : (*(Status) = RtlSyncStringToBuffer(DestinationBuffer), RtlSyncStringToBuffer(SourceBuffer)) \
    )

NTSTATUS
NTAPI
RtlValidateBuffer(
    IN ULONG Flags,
    IN CONST RTL_BUFFER* Buffer
    );

NTSTATUS
NTAPI
RtlValidateUnicodeStringBuffer(
    IN ULONG Flags,
    IN CONST RTL_UNICODE_STRING_BUFFER* UnicodeStringBuffer
    );

#define RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE (0x00000001)

NTSTATUS
NTAPI
RtlFindAndReplaceCharacterInString(
    ULONG           Flags,
    PVOID           Reserved,
    PUNICODE_STRING String,
    WCHAR           Find,
    WCHAR           Replace
    );

typedef struct _RTL_ANSI_STRING_BUFFER {
    ANSI_STRING String;
    RTL_BUFFER  ByteBuffer;
    UCHAR       MinimumStaticBufferForTerminalNul[1];
} RTL_ANSI_STRING_BUFFER, *PRTL_ANSI_STRING_BUFFER;

NTSTATUS
NTAPI
RtlInitAnsiStringBuffer(
    PRTL_ANSI_STRING_BUFFER StringBuffer,
    PUCHAR                  StaticBuffer,
    SIZE_T                  StaticSize
    );

VOID
NTAPI
RtlFreeAnsiStringBuffer(
    PRTL_ANSI_STRING_BUFFER AnsiStringBuffer
    );

NTSTATUS
NTAPI
RtlAssignAnsiStringBufferFromUnicodeString(
    PRTL_ANSI_STRING_BUFFER AnsiStringBuffer,
    PCUNICODE_STRING UnicodeString
    );

NTSTATUS
NTAPI
RtlAssignAnsiStringBufferFromUnicode(
    PRTL_ANSI_STRING_BUFFER AnsiStringBuffer,
    PCWSTR Unicode
    );

NTSTATUS
NTAPI
RtlUnicodeStringBufferEnsureTrailingNtPathSeparator(
    PRTL_UNICODE_STRING_BUFFER StringBuffer
    );

#ifdef __cplusplus
}       // extern "C"
#endif

#if defined (_MSC_VER) && ( _MSC_VER >= 800 )
#if _MSC_VER >= 1200
#pragma warning(pop)
#else
#pragma warning(default:4001)
#pragma warning(default:4201)
#pragma warning(default:4214)
#endif
#endif
#endif

