/*++

Copyright (c) 1999  Microsoft Corporation

Module Name:

    rtl.c

Abstract:

    Some handy-dany RTL functions. These really should be part of the kernel


Author:

Environment:

    NT Kernel Model Driver only

Revision History:

--*/

#include "pch.h"


PCM_RESOURCE_LIST
RtlDuplicateCmResourceList(
    IN  POOL_TYPE           PoolType,
    IN  PCM_RESOURCE_LIST   ResourceList,
    IN  ULONG               Tag
    )
/*++

Routine Description:

    This routine will attempt to allocate memory to copy the supplied
    resource list.  If sufficient memory cannot be allocated then the routine
    will return NULL.

Arguments:

    PoolType - the type of pool to allocate the duplicate from

    ResourceList - the resource list to be copied

    Tag - a value to tag the memory allocation with.  If 0 then untagged
          memory will be allocated.

Return Value:

    an allocated copy of the resource list (caller must free) or
    NULL if memory could not be allocated.

--*/
{
    ULONG size = sizeof(CM_RESOURCE_LIST);
    PVOID buffer;

    PAGED_CODE();

    //
    // How much memory do we need for this resource list?
    //
    size = RtlSizeOfCmResourceList(ResourceList);

    //
    // Allocate the memory and copy the list
    //
    buffer = ExAllocatePoolWithTag(PoolType, size, Tag);
    if(buffer != NULL) {

        RtlCopyMemory(
            buffer,
            ResourceList,
            size
            );

    }

    return buffer;
}

ULONG
RtlSizeOfCmResourceList(
    IN  PCM_RESOURCE_LIST   ResourceList
    )
/*++

Routine Description:

    This routine returns the size of a CM_RESOURCE_LIST.

Arguments:

    ResourceList - the resource list to be copied

Return Value:

    an allocated copy of the resource list (caller must free) or
    NULL if memory could not be allocated.

--*/

{
    ULONG size = sizeof(CM_RESOURCE_LIST);
    ULONG i;

    PAGED_CODE();

    for(i = 0; i < ResourceList->Count; i++) {

        PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor = &(ResourceList->List[i]);
        ULONG j;

        //
        // First descriptor is included in the size of the resource list.
        //
        if(i != 0) {

            size += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);

        }

        for(j = 0; j < fullDescriptor->PartialResourceList.Count; j++) {

            //
            // First descriptor is included in the size of the partial list.
            //
            if(j != 0) {

                size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);

            }

        }

    }
    return size;
}

PCM_PARTIAL_RESOURCE_DESCRIPTOR
RtlUnpackPartialDesc(
    IN  UCHAR               Type,
    IN  PCM_RESOURCE_LIST   ResList,
    IN  OUT PULONG          Count
    )
/*++

Routine Description:

    Pulls out a pointer to the partial descriptor you're interested in

Arguments:

    Type - CmResourceTypePort, ...
    ResList - The list to search
    Count - Points to the index of the partial descriptor you're looking
            for, gets incremented if found, i.e., start with *Count = 0,
            then subsequent calls will find next partial, make sense?

Return Value:

    Pointer to the partial descriptor if found, otherwise NULL

--*/
{
    ULONG hit = 0;
    ULONG i;
    ULONG j;

    for (i = 0; i < ResList->Count; i++) {

        for (j = 0; j < ResList->List[i].PartialResourceList.Count; j++) {

            if (ResList->List[i].PartialResourceList.PartialDescriptors[j].Type == Type) {

                if (hit == *Count) {

                    (*Count)++;
                    return &ResList->List[i].PartialResourceList.PartialDescriptors[j];

                } else {

                    hit++;

                }

            }

        }

    }
    return NULL;
}