//+----------------------------------------------------------------------------
//
//  Copyright (C) 1992, Microsoft Corporation
//
//  File:       DfsMrshl.c
//
//  Contents:   Routines to handle marshalling of data structures. This file
//              has been specifically created so that user level code can
//              avail of the marshalling code simply by including this file.
//
//  Classes:
//
//  Functions:
//
//  History:    March 29, 1994          Milans created from PeterCo's routines
//
//-----------------------------------------------------------------------------

#ifdef KERNEL_MODE

#include "dfsprocs.h"
#include "dfsmrshl.h"
#include "dfsrtl.h"

#define Dbg              (DEBUG_TRACE_RTL)

#else // !KERNEL_MODE

#include "dfsmrshl.h"

#ifndef ExRaiseStatus
#define ExRaiseStatus(x)        RtlRaiseStatus(x)
#endif // ExRaiseStatus

#ifndef try_return
#define try_return(s)           {s; goto try_exit;}
#endif // try_return

#ifndef DebugTrace
#define DebugTrace(i,l,f,s)
#endif // DebugTrace

#endif // KERNEL_MODE



NTSTATUS
DfsRtlGetpwString(
    IN OUT PMARSHAL_BUFFER      MarshalBuffer,
    OUT    PWSTR                *ppwszString
);

NTSTATUS
DfsRtlPutpwString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PWSTR       *ppwszString
);

NTSTATUS
DfsRtlGetString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PSTRING String
);

NTSTATUS
DfsRtlPutString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PSTRING String
);


#ifdef ALLOC_PRAGMA

#pragma alloc_text( PAGE, DfsRtlGetpwString )
#pragma alloc_text( PAGE, DfsRtlPutpwString )
#pragma alloc_text( PAGE, DfsRtlGetString )
#pragma alloc_text( PAGE, DfsRtlPutString )
#pragma alloc_text( PAGE, DfsRtlGet )
#pragma alloc_text( PAGE, DfsRtlPut )
#pragma alloc_text( PAGE, DfsRtlSize )
#pragma alloc_text( PAGE, DfsRtlUnwindGet )

#endif //ALLOC_PRAGMA

#define UNREFERENCED_LABEL(label)\
    if(0) goto label;

#define DfsRtlGetUchar(MarshalBuffer, pValue) (                         \
    ((MarshalBuffer)->Current + 1 <= (MarshalBuffer)->Last) ?           \
        *(pValue) = (UCHAR)((MarshalBuffer)->Current[0]     ),          \
        (MarshalBuffer)->Current += 1,                                  \
        STATUS_SUCCESS                                                  \
     :  STATUS_DATA_ERROR                                               \
    )

#define DfsRtlPutUchar(MarshalBuffer, pValue) (                         \
    ((MarshalBuffer)->Current + 1 <= (MarshalBuffer)->Last) ?           \
        (MarshalBuffer)->Current[0] = BYTE_0(*pValue),                  \
        (MarshalBuffer)->Current += 1,                                  \
        STATUS_SUCCESS                                                  \
     :  STATUS_BUFFER_TOO_SMALL                                         \
    )


#define DfsRtlUnwindStringGet(s) {                                      \
    if((s)->Length != 0 && (s)->Buffer != NULL) {                       \
        MarshalBufferFree((s)->Buffer);                                 \
        (s)->Buffer = NULL;                                             \
        (s)->Length = 0;                                                \
    }                                                                   \
}

#define DfsRtlUnwindUnicodeStringGet(s)                                 \
    DfsRtlUnwindStringGet(s)


NTSTATUS
DfsRtlGetArrayUchar(
    IN OUT PMARSHAL_BUFFER      MarshalBuffer,
    IN ULONG                    cbArray,
    OUT PUCHAR                  pArray)
{
    NTSTATUS    status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGetArrayUchar: Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    // ASSERT(ARGUMENT_PRESENT(pArray));

    try {
        UNREFERENCED_LABEL(try_exit);
        if (MarshalBuffer->Current + cbArray <= MarshalBuffer->Last) {
            memcpy(pArray, MarshalBuffer->Current, cbArray);
            MarshalBuffer->Current += cbArray;
        } else {
            status = STATUS_DATA_ERROR;
        }
    try_exit: NOTHING;
    } finally {
        if (AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlGetArrayUchar - Abnormal termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

    }

    DebugTrace(-1, Dbg, "DfsRtlGetArrayUchar: Exited %08lx\n", ULongToPtr( status ));
    return(status);
}

NTSTATUS
DfsRtlPutArrayUchar(
    IN OUT PMARSHAL_BUFFER      MarshalBuffer,
    IN ULONG                    cbArray,
    OUT PUCHAR                  pArray)
{
    NTSTATUS    status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGetArrayUchar: Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    // ASSERT(ARGUMENT_PRESENT(pArray));

    try {
        UNREFERENCED_LABEL(try_exit);
        if (MarshalBuffer->Current + cbArray <= MarshalBuffer->Last) {
            if (cbArray) {
                memcpy(MarshalBuffer->Current, pArray, cbArray);
                MarshalBuffer->Current += cbArray;
            }
        } else {
            status = STATUS_BUFFER_TOO_SMALL;
        }
    try_exit: NOTHING;
    } finally {
        if (AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlPutArrayUchar - Abnormal termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

    }

    DebugTrace(-1, Dbg, "DfsRtlPutArrayUchar: Exited %08lx\n", ULongToPtr( status ));
    return(status);
}


NTSTATUS
DfsRtlGetpwString(
    IN OUT PMARSHAL_BUFFER      MarshalBuffer,
    OUT    PWSTR                *ppwszString
)
{
    USHORT size;
    PCHAR cp = NULL;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGetpwString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(ppwszString));

    try {
        UNREFERENCED_LABEL(try_exit);
        *ppwszString = NULL;
        if(NT_SUCCESS(status = DfsRtlGetUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(
                    MarshalBuffer->Current + size <= MarshalBuffer->Last &&
                    ((ULONG)size + sizeof(WCHAR)) <= MAXUSHORT &&
                    (size & 0x1) == 0
                ) {
                    if((cp = ExAllocatePoolWithTag(
                                    PagedPool,
                                    size+sizeof(WCHAR),
                                    ' sfD')) != NULL) {
                        memcpy(cp, MarshalBuffer->Current, size);
                        *((WCHAR *) (cp + size)) = UNICODE_NULL;
                        *ppwszString = (PWCHAR) cp;
                        MarshalBuffer->Current += size;
                    } else
                        status = STATUS_INSUFFICIENT_RESOURCES;
                } else
                    status = STATUS_DATA_ERROR;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlGetpwString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

        if(!NT_SUCCESS(status) && cp)
                MarshalBufferFree(cp);
    }
    DebugTrace(-1, Dbg, "DfsRtlGetpwString:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}


NTSTATUS
DfsRtlPutpwString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PWSTR       *ppwszString
)
{
    USHORT size;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlPutpwString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(ppwszString));


    try {
        UNREFERENCED_LABEL(try_exit);
        if (*ppwszString != NULL)
            size = wcslen(*ppwszString)*sizeof(WCHAR);
        else
            size = 0;
        if(NT_SUCCESS(status = DfsRtlPutUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(MarshalBuffer->Current + size <= MarshalBuffer->Last) {
                    memcpy(MarshalBuffer->Current, *ppwszString, size);
                    MarshalBuffer->Current += size;
                } else
                    status = STATUS_BUFFER_TOO_SMALL;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlPutString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }
    }
    DebugTrace(-1, Dbg, "DfsRtlPutString:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}



NTSTATUS
DfsRtlGetString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PSTRING String
)
{
    USHORT size;
    PCHAR cp = NULL;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGetString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(String));

    try {
        UNREFERENCED_LABEL(try_exit);
        String->Length = String->MaximumLength = 0;
        String->Buffer = NULL;
        if(NT_SUCCESS(status = DfsRtlGetUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(
                    MarshalBuffer->Current + size <= MarshalBuffer->Last &&
                    ((ULONG)size + sizeof(WCHAR)) <= MAXUSHORT &&
                    (size & 0x1) == 0
                ) {
                    if((cp = ExAllocatePoolWithTag(
                                PagedPool,
                                size+sizeof(WCHAR),
                                ' sfD')) != NULL) {
                        RtlZeroMemory(cp, size+sizeof(WCHAR));
                        memcpy(cp, MarshalBuffer->Current, size);
                        String->Length = (USHORT)size;
                        String->MaximumLength = size + sizeof(WCHAR);
                        String->Buffer = cp;
                        MarshalBuffer->Current += size;
                    } else
                        status = STATUS_INSUFFICIENT_RESOURCES;
                } else
                    status = STATUS_DATA_ERROR;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlGetString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

        if(!NT_SUCCESS(status) && cp)
                MarshalBufferFree(cp);
    }
    DebugTrace(-1, Dbg, "DfsRtlGetString:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}



NTSTATUS
DfsRtlPutString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PSTRING String
)
{
    USHORT size;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlPutString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(String));


    try {
        UNREFERENCED_LABEL(try_exit);
        size = String->Length;
        if(NT_SUCCESS(status = DfsRtlPutUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(MarshalBuffer->Current + size <= MarshalBuffer->Last) {
                    if(String->Buffer != NULL) {
                        memcpy(MarshalBuffer->Current, String->Buffer, size);
                        MarshalBuffer->Current += size;
                    } else
                        status = STATUS_DATA_ERROR;
                } else
                    status = STATUS_BUFFER_TOO_SMALL;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlPutString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }
    }
    DebugTrace(-1, Dbg, "DfsRtlPutString:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}



#ifdef  NOT_NEEDED

NTSTATUS
DfsRtlGetUnicodeString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PUNICODE_STRING UnicodeString
)
{
    USHORT size;
    PWCHAR wcp = NULL;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGetUnicodeString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(UnicodeString));

    try {
        UnicodeString->Length = UnicodeString->MaximumLength = 0;
        UnicodeString->Buffer = NULL;
        if(NT_SUCCESS(status = DfsRtlGetUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(
                    MarshalBuffer->Current + size <= MarshalBuffer->Last &&
                    ((ULONG)size + sizeof(WCHAR)) <= MAXUSHORT &&
                    (size & 0x1) == 0
                ) {
                    if((wcp = (ExAllocatePoolWithTag)(
                                    PagedPool,
                                    size+sizeof(WCHAR)
                                    ' sfD')) != NULL) {
                        memcpy(wcp, MarshalBuffer->Current, size);
                        wcp[size/sizeof(WCHAR)] = UNICODE_NULL;
                        UnicodeString->Length = size;
                        UnicodeString->MaximumLength = size + sizeof(WCHAR);
                        UnicodeString->Buffer = wcp;
                        MarshalBuffer->Current += size;
                    } else
                        status = STATUS_INSUFFICIENT_RESOURCES;
                } else
                    status = STATUS_DATA_ERROR;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlGetUnicodeString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

        if(!NT_SUCCESS(status) && wcp)
                MarshalBufferFree(wcp);
    }
    DebugTrace(-1, Dbg, "DfsRtlGetUnicodeString:  Exit -> %08lx\n",
                status);
    return status;
}



NTSTATUS
DfsRtlPutUnicodeString(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    OUT     PUNICODE_STRING UnicodeString
)
{
    USHORT size;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlPutUnicodeString:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(UnicodeString));

    try {
        size = UnicodeString->Length;
        if(NT_SUCCESS(status = DfsRtlPutUshort(MarshalBuffer, &size))) {
            if(size > 0) {
                if(MarshalBuffer->Current + size <= MarshalBuffer->Last) {
                    if(UnicodeString->Buffer != NULL) {
                        memcpy(
                            MarshalBuffer->Current,
                            UnicodeString->Buffer,
                            size
                        );
                        MarshalBuffer->Current += size;
                    } else
                        status = STATUS_DATA_ERROR;
                } else
                    status = STATUS_BUFFER_TOO_SMALL;
            }
        }
    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg,
                "DfsRtlPutUnicodeString:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }
    }
    DebugTrace(-1, Dbg, "DfsRtlPutUnicodeString:  Exit -> %08lx\n",
                status);
    return status;
}

#else   // NOT_NEEDED

#define DfsRtlGetUnicodeString(b, s)\
    DfsRtlGetString(b, (PSTRING)(s))

#define DfsRtlPutUnicodeString(b, s)\
    DfsRtlPutString(b, (PSTRING)(s))

#endif  // NOT_NEEDED





NTSTATUS
DfsRtlGet(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    IN  PMARSHAL_INFO MarshalInfo,
    OUT PVOID Item
)
{
    PMARSHAL_TYPE_INFO typeInfo;
    PVOID subItem;
    PVOID subItemElem;
    ULONG cnt;
    ULONG unwindcnt;
    PUCHAR cntptr;
    ULONG itemSize;
    PMARSHAL_INFO subInfo;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlGet:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(MarshalInfo));
    ASSERT(ARGUMENT_PRESENT(Item));

    try {

        RtlZeroMemory(Item, MarshalInfo->_size);

        for(typeInfo = &MarshalInfo->_typeInfo[0];
            typeInfo < &MarshalInfo->_typeInfo[MarshalInfo->_typecnt];
            typeInfo++) {

            switch(typeInfo->_type & MTYPE_BASE_TYPE) {
            case MTYPE_COMPOUND:
                subInfo = typeInfo->_subinfo;
                itemSize = subInfo->_size;
                //
                // If this compound type is a conformant structure, then
                // we need to adjust the size field here.
                //
                if (subInfo->_typecnt > 0 &&
                      subInfo->_typeInfo[0]._type == MTYPE_CONFORMANT_CNT) {
                   MARSHAL_BUFFER tempMarshalBuffer = *MarshalBuffer;
                   ULONG extraSize = 0;

                   status = DfsRtlGetUlong(&tempMarshalBuffer, &extraSize);
                   if (!NT_SUCCESS(status) || (itemSize + extraSize) < itemSize) {
                       try_return(status = STATUS_DATA_ERROR);
                   }
                   itemSize += extraSize;
                }
                break;
            case MTYPE_CONFORMANT_CNT:
                itemSize = 0;
                break;
            case MTYPE_GUID:
                itemSize = sizeof(GUID);
                break;
            case MTYPE_STRING:
                itemSize = sizeof(STRING);
                break;
            case MTYPE_UNICODE_STRING:
                itemSize = sizeof(UNICODE_STRING);
                break;
            case MTYPE_PWSTR:
                itemSize = sizeof(PWSTR);
                break;
            case MTYPE_ULONG:
                itemSize = sizeof(ULONG);
                break;
            case MTYPE_USHORT:
                itemSize = sizeof(USHORT);
                break;
            case MTYPE_UCHAR:
                itemSize = sizeof(UCHAR);
                break;
            default:
                try_return(status = STATUS_DATA_ERROR);
            }

            if(typeInfo->_type & MTYPE_COUNTED_ARRAY) {
                cntptr = ((PUCHAR)Item + typeInfo->_cntoff);
                switch(typeInfo->_cntsize) {
                case sizeof(UCHAR):
                    cnt = *(PUCHAR)cntptr;
                    break;
                case sizeof(USHORT):
                    cnt = *(PUSHORT)cntptr;
                    break;
                case sizeof(ULONG):
                    cnt = *(PULONG)cntptr;
                    break;
                default:
                    try_return(status = STATUS_DATA_ERROR);
                }
            } else if (typeInfo->_type & MTYPE_STATIC_ARRAY) {
                cnt = typeInfo->_cntoff;
            } else {
                cnt = 1;
            }

            if(typeInfo->_type & MTYPE_INDIRECT) {
                if((typeInfo->_type & MTYPE_COUNTED_ARRAY) && cnt == 0)
                    subItem = NULL;
                else {
                    subItem = NULL;
                    if ((cnt != 0) && ((itemSize * cnt) / cnt) == itemSize)
                        subItem = ExAllocatePoolWithTag(
                                    PagedPool,
                                    itemSize * cnt,
                                    ' sfD');
                    if(subItem == NULL)
                        try_return(status = STATUS_INSUFFICIENT_RESOURCES);
                }
                *(PVOID *)((PUCHAR)Item + typeInfo->_off) = subItem;
            }
            else
                subItem = ((PUCHAR)Item + typeInfo->_off);

            switch(typeInfo->_type & ~MTYPE_INDIRECT) {

            case MTYPE_COMPOUND:
                    status = DfsRtlGet(
                        MarshalBuffer,
                        subInfo,
                        subItem
                    );
                    break;
            case MTYPE_CONFORMANT_CNT:
                    //
                    // this field is used only when sizing a conformant
                    // structure. As such, there is no place to unmarshal
                    // it into. So, simply eat the ulong.
                    //
                    status = DfsRtlGetUlong(MarshalBuffer, &itemSize);
                    break;
            case (MTYPE_COMPOUND|MTYPE_COUNTED_ARRAY):
            case (MTYPE_COMPOUND|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    unwindcnt = cnt;
                    while(cnt--) {
                        status = DfsRtlGet(
                            MarshalBuffer,
                            subInfo,
                            subItemElem
                        );
                        if(!NT_SUCCESS(status)) {
                            while((++cnt) < unwindcnt) {
                                ((PUCHAR)subItemElem) -= itemSize;
                                DfsRtlUnwindGet(
                                    subInfo,
                                    &subInfo->_typeInfo[subInfo->_typecnt],
                                    subItemElem
                                );
                            }
                            if(typeInfo->_type & MTYPE_INDIRECT)
                                MarshalBufferFree(subItem);
                            break;
                        }
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_GUID:
                    status = DfsRtlGetGuid(
                        MarshalBuffer,
                        (GUID *)subItem
                    );
                    break;
            case MTYPE_STRING:
                    status = DfsRtlGetString(
                        MarshalBuffer,
                        (PSTRING)subItem
                    );
                    break;
            case MTYPE_UNICODE_STRING:
                    status = DfsRtlGetUnicodeString(
                        MarshalBuffer,
                        (PUNICODE_STRING)subItem
                    );
                    break;

            case MTYPE_PWSTR:
                    status = DfsRtlGetpwString(
                        MarshalBuffer,
                        (PWSTR *)subItem
                    );
                    break;

            case (MTYPE_PWSTR|MTYPE_COUNTED_ARRAY):
            case (MTYPE_PWSTR|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    unwindcnt = cnt;
                    while (cnt--) {
                        status = DfsRtlGetpwString(
                            MarshalBuffer,
                            (PWSTR *)subItemElem);
                        if (!NT_SUCCESS(status)) {
                            while ((++cnt) < unwindcnt) {
                                ((PUCHAR)subItemElem) -= itemSize;
                                MarshalBufferFree((PVOID)*(PWSTR *)subItemElem);
                            }
                            if (typeInfo->_type & MTYPE_INDIRECT) {
                                MarshalBufferFree(subItem);
                            }
                            break;
                        }
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case (MTYPE_UNICODE_STRING|MTYPE_COUNTED_ARRAY):
            case (MTYPE_UNICODE_STRING|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    unwindcnt = cnt;
                    while(cnt--) {
                        status = DfsRtlGetUnicodeString(
                            MarshalBuffer,
                            (PUNICODE_STRING)subItemElem
                        );
                        if(!NT_SUCCESS(status)) {
                            while((++cnt) < unwindcnt) {
                                ((PUCHAR)subItemElem) -= itemSize;
                                DfsRtlUnwindUnicodeStringGet(
                                    (PUNICODE_STRING)subItemElem
                                );
                            }
                            if(typeInfo->_type & MTYPE_INDIRECT)
                                MarshalBufferFree(subItem);
                            break;
                        }
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_ULONG:
                    status = DfsRtlGetUlong(
                        MarshalBuffer,
                        (PULONG)subItem
                    );
                    break;
            case MTYPE_USHORT:
                    status = DfsRtlGetUshort(
                        MarshalBuffer,
                        (PUSHORT)subItem);
                    break;
            case MTYPE_UCHAR:
                    status = DfsRtlGetUchar(
                        MarshalBuffer,
                        (PUCHAR)subItem);
                    break;
            case MTYPE_UCHAR|MTYPE_COUNTED_ARRAY:
            case MTYPE_UCHAR|MTYPE_STATIC_ARRAY:
                    status = DfsRtlGetArrayUchar(
                        MarshalBuffer,
                        cnt,
                        (PUCHAR)subItem);
                    break;
            default:
                    status = STATUS_DATA_ERROR;
                    break;
            };
            if(!NT_SUCCESS(status))
                break;
        }

    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg, "DfsRtlGet:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }

        if(!NT_SUCCESS(status))
            DfsRtlUnwindGet(MarshalInfo, typeInfo, Item);
    }

    DebugTrace(-1, Dbg, "DfsRtlGet:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}



NTSTATUS
DfsRtlPut(
    IN OUT  PMARSHAL_BUFFER MarshalBuffer,
    IN  PMARSHAL_INFO MarshalInfo,
    OUT PVOID Item
)
{
    PMARSHAL_TYPE_INFO typeInfo;
    PVOID subItem;
    PVOID subItemElem;
    ULONG cnt;
    PUCHAR cntptr;
    ULONG itemSize;
    PMARSHAL_INFO subInfo;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlPut:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalBuffer));
    ASSERT(ARGUMENT_PRESENT(MarshalInfo));
    ASSERT(ARGUMENT_PRESENT(Item));

    try {
        for(typeInfo = &MarshalInfo->_typeInfo[0];
            typeInfo < &MarshalInfo->_typeInfo[MarshalInfo->_typecnt];
            typeInfo++) {

            switch(typeInfo->_type & MTYPE_BASE_TYPE) {
            case MTYPE_COMPOUND:
                subInfo = typeInfo->_subinfo;
                itemSize = subInfo->_size;
                break;
            case MTYPE_CONFORMANT_CNT:
                itemSize = typeInfo->_off;
                break;
            case MTYPE_GUID:
                itemSize = sizeof(GUID);
                break;
            case MTYPE_STRING:
                itemSize = sizeof(STRING);
                break;
            case MTYPE_UNICODE_STRING:
                itemSize = sizeof(UNICODE_STRING);
                break;
            case MTYPE_PWSTR:
                itemSize = sizeof(PWSTR);
                break;
            case MTYPE_ULONG:
                itemSize = sizeof(ULONG);
                break;
            case MTYPE_USHORT:
                itemSize = sizeof(USHORT);
                break;
            case MTYPE_UCHAR:
                itemSize = sizeof(UCHAR);
                break;
            default:
                try_return(status = STATUS_DATA_ERROR);
            }

            if(typeInfo->_type & MTYPE_COUNTED_ARRAY ||
               typeInfo->_type == MTYPE_CONFORMANT_CNT) {
                cntptr = ((PUCHAR)Item + typeInfo->_cntoff);
                switch(typeInfo->_cntsize) {
                case sizeof(UCHAR):
                    cnt = *(PUCHAR)cntptr;
                    break;
                case sizeof(USHORT):
                    cnt = *(PUSHORT)cntptr;
                    break;
                case sizeof(ULONG):
                    cnt = *(PULONG)cntptr;
                    break;
                default:
                    try_return(status = STATUS_DATA_ERROR);
                }
            } else
                cnt = typeInfo->_cntoff;

            if(typeInfo->_type & MTYPE_INDIRECT) {
                subItem = *(PUCHAR *)((PUCHAR)Item + typeInfo->_off);
                if(subItem == NULL &&
                   !((typeInfo->_type & MTYPE_COUNTED_ARRAY) && cnt == 0))
                    try_return(status = STATUS_DATA_ERROR);
            } else
                subItem = ((PUCHAR)Item + typeInfo->_off);

            switch(typeInfo->_type & ~MTYPE_INDIRECT) {

            case MTYPE_COMPOUND:
                    status = DfsRtlPut(
                        MarshalBuffer,
                        subInfo,
                        subItem
                    );
                    break;
            case MTYPE_CONFORMANT_CNT:
                    cnt *= itemSize;
                    status = DfsRtlPutUlong(
                                MarshalBuffer,
                                &cnt);
                    break;
            case (MTYPE_COMPOUND|MTYPE_COUNTED_ARRAY):
            case (MTYPE_COMPOUND|MTYPE_STATIC_ARRAY):
                    //
                    // No sense in having an array of conformant structures
                    // ASSERT this fact
                    //

                    ASSERT(subInfo->_typecnt == 0
                                    ||
                           subInfo->_typeInfo[0]._type != MTYPE_CONFORMANT_CNT
                          );

                    subItemElem = (PUCHAR)subItem;
                    while(cnt--) {
                        status = DfsRtlPut(
                            MarshalBuffer,
                            subInfo,
                            subItemElem
                        );
                        if(!NT_SUCCESS(status))
                            break;
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_GUID:
                    status = DfsRtlPutGuid(
                        MarshalBuffer,
                        (GUID *)subItem
                    );
                    break;
            case MTYPE_STRING:
                    status = DfsRtlPutString(
                        MarshalBuffer,
                        (PSTRING)subItem
                    );
                    break;
            case MTYPE_UNICODE_STRING:
                    status = DfsRtlPutUnicodeString(
                        MarshalBuffer,
                        (PUNICODE_STRING)subItem
                    );
                    break;
            case MTYPE_PWSTR:
                    status = DfsRtlPutpwString(
                        MarshalBuffer,
                        (PWSTR *)subItem
                    );
                    break;

            case (MTYPE_PWSTR|MTYPE_COUNTED_ARRAY):
            case (MTYPE_PWSTR|MTYPE_STATIC_ARRAY):
                    subItemElem = (PWSTR *)subItem;
                    while(cnt--) {
                        status = DfsRtlPutpwString(
                            MarshalBuffer,
                            (PWSTR *)subItemElem);
                        if (!NT_SUCCESS(status))
                            break;
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case (MTYPE_UNICODE_STRING|MTYPE_COUNTED_ARRAY):
            case (MTYPE_UNICODE_STRING|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    while(cnt--) {
                        status = DfsRtlPutUnicodeString(
                            MarshalBuffer,
                            (PUNICODE_STRING)subItemElem
                        );
                        if(!NT_SUCCESS(status))
                            break;
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_ULONG:
                    status = DfsRtlPutUlong(
                        MarshalBuffer,
                        (PULONG)subItem
                    );
                    break;
            case MTYPE_USHORT:
                    status = DfsRtlPutUshort(
                        MarshalBuffer,
                        (PUSHORT)subItem);
                    break;
            case MTYPE_UCHAR:
                    status = DfsRtlPutUchar(
                        MarshalBuffer,
                        (PUCHAR)subItem);
                    break;
            case (MTYPE_UCHAR|MTYPE_COUNTED_ARRAY):
            case (MTYPE_UCHAR|MTYPE_STATIC_ARRAY):
                    status = DfsRtlPutArrayUchar(
                                    MarshalBuffer,
                                    cnt,
                                    (PUCHAR)subItem);
                    break;
            default:
                    status = STATUS_DATA_ERROR;
                break;
            }

            if(!NT_SUCCESS(status))
                break;
        }

    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg, "DfsRtlPut:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }
    }

    DebugTrace(-1, Dbg, "DfsRtlPut:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}




NTSTATUS
DfsRtlSize(
    IN  PMARSHAL_INFO MarshalInfo,
    IN  PVOID Item,
    OUT PULONG Size
)
{
    PMARSHAL_TYPE_INFO typeInfo;
    PVOID subItem;
    PVOID subItemElem;
    ULONG cnt;
    PUCHAR cntptr;
    ULONG itemSize;
    PMARSHAL_INFO subInfo;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlSize:  Entered\n", 0);

    ASSERT(ARGUMENT_PRESENT(MarshalInfo));
    ASSERT(ARGUMENT_PRESENT(Item));
    ASSERT(ARGUMENT_PRESENT(Size));

    try {
        for(typeInfo = &MarshalInfo->_typeInfo[0];
            typeInfo < &MarshalInfo->_typeInfo[MarshalInfo->_typecnt];
            typeInfo++) {

            switch(typeInfo->_type & MTYPE_BASE_TYPE) {
            case MTYPE_COMPOUND:
                subInfo = typeInfo->_subinfo;
                itemSize = subInfo->_size;
                break;
            case MTYPE_CONFORMANT_CNT:
                //
                // For conformant structures, _offset is sizeof each
                // element, _cntsize is sizeof cnt field, and _cntoff is
                // offset of cnt field.
                //
                itemSize = typeInfo->_off;
                break;
            case MTYPE_GUID:
                itemSize = sizeof(GUID);
                break;
            case MTYPE_STRING:
                itemSize = sizeof(STRING);
                break;
            case MTYPE_UNICODE_STRING:
                itemSize = sizeof(UNICODE_STRING);
                break;
            case MTYPE_PWSTR:
                itemSize = sizeof(PWCHAR);
                break;
            case MTYPE_ULONG:
                itemSize = sizeof(ULONG);
                break;
            case MTYPE_USHORT:
                itemSize = sizeof(USHORT);
                break;
            case MTYPE_UCHAR:
                itemSize = sizeof(UCHAR);
                break;
            default:
                try_return(status = STATUS_DATA_ERROR);
            }

            if(typeInfo->_type & MTYPE_COUNTED_ARRAY ||
               typeInfo->_type == MTYPE_CONFORMANT_CNT) {
                cntptr = ((PUCHAR)Item + typeInfo->_cntoff);
                switch(typeInfo->_cntsize) {
                case sizeof(UCHAR):
                    cnt = *(PUCHAR)cntptr;
                    break;
                case sizeof(USHORT):
                    cnt = *(PUSHORT)cntptr;
                    break;
                case sizeof(ULONG):
                    cnt = *(PULONG)cntptr;
                    break;
                default:
                    try_return(status = STATUS_DATA_ERROR);
                }
            } else
                cnt = typeInfo->_cntoff;

            if(typeInfo->_type & MTYPE_INDIRECT) {
                subItem = *(PUCHAR *)((PUCHAR)Item + typeInfo->_off);
                if(subItem == NULL &&
                   !((typeInfo->_type & MTYPE_COUNTED_ARRAY) && cnt == 0))
                    try_return(status = STATUS_DATA_ERROR);
            } else
                subItem = ((PUCHAR)Item + typeInfo->_off);

            switch(typeInfo->_type & ~MTYPE_INDIRECT) {

            case MTYPE_COMPOUND:
                    status = DfsRtlSize(
                        subInfo,
                        subItem,
                        Size
                    );
                    break;
            case MTYPE_CONFORMANT_CNT:
                    (*Size) += sizeof(ULONG);
                    break;
            case (MTYPE_COMPOUND|MTYPE_COUNTED_ARRAY):
            case (MTYPE_COMPOUND|MTYPE_STATIC_ARRAY):
                    //
                    // No sense in having an array of conformant structures
                    // ASSERT this fact
                    //

                    ASSERT(subInfo->_typecnt == 0
                                    ||
                           subInfo->_typeInfo[0]._type != MTYPE_CONFORMANT_CNT
                          );

                    subItemElem = (PUCHAR)subItem;
                    while(cnt--) {
                        status = DfsRtlSize(
                            subInfo,
                            subItemElem,
                            Size
                        );
                        if(!NT_SUCCESS(status))
                            break;
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_GUID:
                    (*Size) += 16;
                    break;
            case MTYPE_STRING:
                    status = DfsRtlSizeString(
                        (PSTRING)subItem,
                        Size
                    );
                    break;
            case MTYPE_UNICODE_STRING:
                    status = DfsRtlSizeUnicodeString(
                        (PUNICODE_STRING)subItem,
                        Size
                    );
                    break;

            case MTYPE_PWSTR:
                    status = DfsRtlSizepwString(
                        (PWSTR *)subItem,
                        Size
                    );
                    break;
            case (MTYPE_PWSTR|MTYPE_COUNTED_ARRAY):
            case (MTYPE_PWSTR|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    while (cnt--) {
                        status = DfsRtlSizepwString(
                            (PWSTR *)subItemElem,
                            Size);
                        if (!NT_SUCCESS(status)) {
                            break;
                        }
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case (MTYPE_UNICODE_STRING|MTYPE_COUNTED_ARRAY):
            case (MTYPE_UNICODE_STRING|MTYPE_STATIC_ARRAY):
                    subItemElem = (PUCHAR)subItem;
                    while(cnt--) {
                        status = DfsRtlSizeUnicodeString(
                            (PUNICODE_STRING)subItemElem,
                            Size
                        );
                        if(!NT_SUCCESS(status))
                            break;
                        ((PUCHAR)subItemElem) += itemSize;
                    }
                    break;
            case MTYPE_ULONG:
                    (*Size) += 4;
                    break;
            case MTYPE_USHORT:
                    (*Size) += 2;
                    break;
            case MTYPE_UCHAR:
                    (*Size) += 1;
                    break;
            case MTYPE_UCHAR|MTYPE_COUNTED_ARRAY:
            case MTYPE_UCHAR|MTYPE_STATIC_ARRAY:
                    (*Size) += (cnt * sizeof(UCHAR));
                    break;
            default:
                    status = STATUS_DATA_ERROR;
                    break;
            };
            if(!NT_SUCCESS(status))
                break;
        }

    try_exit: NOTHING;
    } finally {
        if(AbnormalTermination()) {
            DebugTrace(0, Dbg, "DfsRtlSize:  Abnormal Termination!\n", 0);
            status = STATUS_DATA_ERROR;
        }
    }

    DebugTrace(0, Dbg, "DfsRtlSize:  (*Size) = %ld\n", ULongToPtr( (*Size) ));
    DebugTrace(-1, Dbg, "DfsRtlSize:  Exit -> %08lx\n", ULongToPtr( status ));
    return status;
}




VOID
DfsRtlUnwindGet(
    IN  PMARSHAL_INFO MarshalInfo,
    IN  PMARSHAL_TYPE_INFO LastTypeInfo,
    IN  PVOID Item
)
{
    PMARSHAL_TYPE_INFO typeInfo;
    PVOID subItem;
    PVOID subItemElem;
    ULONG cnt;
    PUCHAR cntptr;
    ULONG itemSize;
    PMARSHAL_INFO subInfo;
    NTSTATUS status = STATUS_SUCCESS;

    DebugTrace(+1, Dbg, "DfsRtlUnwindGet:  Entered\n", 0);

    for(typeInfo = &MarshalInfo->_typeInfo[0];
        typeInfo < LastTypeInfo;
        typeInfo++) {

        switch(typeInfo->_type & MTYPE_BASE_TYPE) {
        case MTYPE_COMPOUND:
            subInfo = typeInfo->_subinfo;
            itemSize = subInfo->_size;
            break;
        case MTYPE_GUID:
            itemSize = sizeof(GUID);
            break;
        case MTYPE_STRING:
            itemSize = sizeof(STRING);
            break;
        case MTYPE_UNICODE_STRING:
            itemSize = sizeof(UNICODE_STRING);
            break;
        case MTYPE_ULONG:
            itemSize = sizeof(ULONG);
            break;
        case MTYPE_USHORT:
            itemSize = sizeof(USHORT);
            break;
        case MTYPE_UCHAR:
            itemSize = sizeof(UCHAR);
            break;
        default:
            ExRaiseStatus(STATUS_DATA_ERROR);
        }

        if(typeInfo->_type & MTYPE_COUNTED_ARRAY) {
            cntptr = ((PUCHAR)Item + typeInfo->_cntoff);
            switch(typeInfo->_cntsize) {
            case sizeof(UCHAR):
                cnt = *(PUCHAR)cntptr;
                break;
            case sizeof(USHORT):
                cnt = *(PUSHORT)cntptr;
                break;
            case sizeof(ULONG):
                cnt = *(PULONG)cntptr;
                break;
            default:
                ExRaiseStatus(STATUS_DATA_ERROR);
            }
        } else
            cnt = typeInfo->_cntoff;

        if(typeInfo->_type & MTYPE_INDIRECT) {
            subItem = *(PUCHAR *)((PUCHAR)Item + typeInfo->_off);
            if(subItem == NULL &&
               !((typeInfo->_type & MTYPE_COUNTED_ARRAY) && cnt == 0))
                ExRaiseStatus(STATUS_DATA_ERROR);
        } else
            subItem = ((PUCHAR)Item + typeInfo->_off);

        switch(typeInfo->_type & ~MTYPE_INDIRECT) {

        case MTYPE_COMPOUND:
                DfsRtlUnwindGet(
                    subInfo,
                    &subInfo->_typeInfo[subInfo->_typecnt],
                    subItem
                );
                break;
        case (MTYPE_COMPOUND|MTYPE_COUNTED_ARRAY):
        case (MTYPE_COMPOUND|MTYPE_STATIC_ARRAY):
                subItemElem = (PUCHAR)subItem;
                while(cnt--) {
                    DfsRtlUnwindGet(
                        subInfo,
                        &subInfo->_typeInfo[subInfo->_typecnt],
                        subItemElem
                    );
                    ((PUCHAR)subItemElem) += itemSize;
                }
                break;
        case MTYPE_STRING:
                DfsRtlUnwindStringGet((PSTRING)subItem);
                break;
        case MTYPE_UNICODE_STRING:
                DfsRtlUnwindUnicodeStringGet((PUNICODE_STRING)subItem);
                break;
        case (MTYPE_UNICODE_STRING|MTYPE_COUNTED_ARRAY):
        case (MTYPE_UNICODE_STRING|MTYPE_STATIC_ARRAY):
                subItemElem = (PUCHAR)subItem;
                while(cnt--) {
                    DfsRtlUnwindUnicodeStringGet((PUNICODE_STRING)subItemElem);
                    ((PUCHAR)subItemElem) += itemSize;
                }
                break;
        case MTYPE_GUID:
        case MTYPE_ULONG:
        case MTYPE_USHORT:
        case MTYPE_UCHAR:
                break;
        default:
                ExRaiseStatus(STATUS_DATA_ERROR);
        };

        if(typeInfo->_type & MTYPE_INDIRECT) {
            MarshalBufferFree(subItem);
            *(PUCHAR *)((PUCHAR)Item + typeInfo->_off) = NULL;
        }
    }
    DebugTrace(-1, Dbg, "DfsRtlUnwindGet:  Exit -> VOID\n", 0);
}