/***************************************************************************** * resource.cpp - resource list object implementation ***************************************************************************** * Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved. */ #include "private.h" /***************************************************************************** * Factory. */ #pragma code_seg("PAGE") /***************************************************************************** * CreateResourceList() ***************************************************************************** * Creates a resource list object. */ NTSTATUS CreateResourceList ( OUT PUNKNOWN * Unknown, IN REFCLSID, IN PUNKNOWN UnknownOuter OPTIONAL, IN POOL_TYPE PoolType ) { PAGED_CODE(); ASSERT(Unknown); _DbgPrintF(DEBUGLVL_LIFETIME,("Creating RESOURCELIST")); STD_CREATE_BODY ( CResourceList, Unknown, UnknownOuter, PoolType ); } /***************************************************************************** * PcNewResourceList() ***************************************************************************** * Creates and initializes a resource list. * Creates an empty resource list if both of the PCM_RESOURCE_LIST parameters * are NULL. */ PORTCLASSAPI NTSTATUS NTAPI PcNewResourceList ( OUT PRESOURCELIST * OutResourceList, IN PUNKNOWN OuterUnknown OPTIONAL, IN POOL_TYPE PoolType, IN PCM_RESOURCE_LIST TranslatedResources, IN PCM_RESOURCE_LIST UntranslatedResources ) { PAGED_CODE(); ASSERT(OutResourceList); // // Validate Parameters. // if (NULL == OutResourceList) { _DbgPrintF(DEBUGLVL_TERSE, ("PcNewResourceList : Invalid Parameter")); return STATUS_INVALID_PARAMETER; } PUNKNOWN unknown; NTSTATUS ntStatus = CreateResourceList ( &unknown, GUID_NULL, OuterUnknown, PoolType ); if (NT_SUCCESS(ntStatus)) { PRESOURCELISTINIT resourceList; ntStatus = unknown->QueryInterface ( IID_IResourceList, (PVOID *) &resourceList ); if (NT_SUCCESS(ntStatus)) { ntStatus = resourceList->Init ( TranslatedResources, UntranslatedResources, PoolType ); if (NT_SUCCESS(ntStatus)) { *OutResourceList = resourceList; } else { resourceList->Release(); } } unknown->Release(); } return ntStatus; } /***************************************************************************** * PcNewResourceSublist() ***************************************************************************** * Creates and initializes an empty resource list derived from another * resource list. */ PORTCLASSAPI NTSTATUS NTAPI PcNewResourceSublist ( OUT PRESOURCELIST * OutResourceList, IN PUNKNOWN OuterUnknown OPTIONAL, IN POOL_TYPE PoolType, IN PRESOURCELIST ParentList, IN ULONG MaximumEntries ) { PAGED_CODE(); ASSERT(OutResourceList); ASSERT(ParentList); ASSERT(MaximumEntries); // // Validate Parameters. // if (NULL == OutResourceList || NULL == ParentList || 0 == MaximumEntries) { _DbgPrintF(DEBUGLVL_TERSE, ("PcNewResourceSubList : Invalid Parameter")); return STATUS_INVALID_PARAMETER; } PUNKNOWN unknown; NTSTATUS ntStatus = CreateResourceList ( &unknown, GUID_NULL, OuterUnknown, PoolType ); if (NT_SUCCESS(ntStatus)) { PRESOURCELISTINIT resourceList; ntStatus = unknown->QueryInterface ( IID_IResourceList, (PVOID *) &resourceList ); if (NT_SUCCESS(ntStatus)) { ntStatus = resourceList->InitFromParent ( ParentList, MaximumEntries, PoolType ); if (NT_SUCCESS(ntStatus)) { *OutResourceList = resourceList; } else { resourceList->Release(); } } unknown->Release(); } return ntStatus; } /***************************************************************************** * Member functions. */ /***************************************************************************** * CResourceList::~CResourceList() ***************************************************************************** * Destructor. */ CResourceList:: ~CResourceList ( void ) { PAGED_CODE(); _DbgPrintF(DEBUGLVL_LIFETIME,("Destroying RESOURCELIST (0x%08x)",this)); if (Translated) { ExFreePool(Translated); } if (Untranslated) { ExFreePool(Untranslated); } } /***************************************************************************** * CResourceList::NonDelegatingQueryInterface() ***************************************************************************** * Obtains an interface. */ STDMETHODIMP_(NTSTATUS) CResourceList:: NonDelegatingQueryInterface ( REFIID Interface, PVOID * Object ) { PAGED_CODE(); ASSERT(Object); if (IsEqualGUIDAligned(Interface,IID_IUnknown)) { *Object = PVOID(PUNKNOWN(this)); } else if (IsEqualGUIDAligned(Interface,IID_IResourceList)) { *Object = PVOID(PRESOURCELISTINIT(this)); } else { *Object = NULL; } if (*Object) { PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER; } /***************************************************************************** * CResourceList::Init() ***************************************************************************** * Initializes the object. */ STDMETHODIMP_(NTSTATUS) CResourceList:: Init ( IN PCM_RESOURCE_LIST TranslatedResources, IN PCM_RESOURCE_LIST UntranslatedResources, IN POOL_TYPE PoolType ) { PAGED_CODE(); _DbgPrintF(DEBUGLVL_LIFETIME,("Initializing RESOURCELIST (0x%08x)",this)); // check NULL resource lists. if (!TranslatedResources && !UntranslatedResources) { EntriesAllocated = EntriesInUse = 0; Translated = Untranslated = NULL; return STATUS_SUCCESS; } // this check fails if _one_ of the resource lists is NULL, which should // never happen. ASSERT (TranslatedResources); ASSERT (UntranslatedResources); if (!TranslatedResources || !UntranslatedResources) { return STATUS_INVALID_PARAMETER; } EntriesAllocated = EntriesInUse = UntranslatedResources->List[0].PartialResourceList.Count; ULONG listSize = ( sizeof(CM_RESOURCE_LIST) + ( (EntriesInUse - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) ); NTSTATUS ntStatus = STATUS_SUCCESS; Translated = PCM_RESOURCE_LIST(ExAllocatePoolWithTag(PoolType,listSize,'lRcP')); if (Translated) { Untranslated = PCM_RESOURCE_LIST(ExAllocatePoolWithTag(PoolType,listSize,'lRcP')); if (Untranslated) { RtlCopyMemory(Untranslated,UntranslatedResources,listSize); RtlCopyMemory(Translated,TranslatedResources,listSize); } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(Translated); Translated = NULL; } } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } return ntStatus; } /***************************************************************************** * CResourceList::InitFromParent() ***************************************************************************** * Initializes the object from a parent object. */ STDMETHODIMP_(NTSTATUS) CResourceList:: InitFromParent ( IN PRESOURCELIST ParentList, IN ULONG MaximumEntries, IN POOL_TYPE PoolType ) { PAGED_CODE(); ASSERT(ParentList); ASSERT(MaximumEntries); ULONG listSize = ( sizeof(CM_RESOURCE_LIST) + ( ( MaximumEntries - 1 ) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) ); NTSTATUS ntStatus = STATUS_SUCCESS; Translated = PCM_RESOURCE_LIST(ExAllocatePoolWithTag(PoolType,listSize,'lRcP')); if (Translated) { Untranslated = PCM_RESOURCE_LIST(ExAllocatePoolWithTag(PoolType,listSize,'lRcP')); if (Untranslated) { RtlZeroMemory(Translated,listSize); RtlZeroMemory(Untranslated,listSize); // Copy headers from the parent. RtlCopyMemory ( Translated, ParentList->TranslatedList(), ( sizeof(CM_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) ); RtlCopyMemory ( Untranslated, ParentList->UntranslatedList(), ( sizeof(CM_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) ) ); EntriesAllocated = MaximumEntries; EntriesInUse = 0; Translated->List[0].PartialResourceList.Count = EntriesInUse; Untranslated->List[0].PartialResourceList.Count = EntriesInUse; } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(Translated); Translated = NULL; } } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } return ntStatus; } /***************************************************************************** * CResourceList::NumberOfEntries() ***************************************************************************** * Determine the number of entries in the list. */ STDMETHODIMP_(ULONG) CResourceList:: NumberOfEntries ( void ) { PAGED_CODE(); return EntriesInUse; } /***************************************************************************** * CResourceList::NumberOfEntriesOfType() ***************************************************************************** * Determines the number of entries of a given type in the list. */ STDMETHODIMP_(ULONG) CResourceList:: NumberOfEntriesOfType ( IN CM_RESOURCE_TYPE Type ) { PAGED_CODE(); if (!Untranslated) { return 0; } PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = Untranslated->List[0].PartialResourceList.PartialDescriptors; ULONG entriesOfType = 0; for ( ULONG count = EntriesInUse; count--; descriptor++ ) { if (descriptor->Type == Type) { entriesOfType++; } } return entriesOfType; } /***************************************************************************** * CResourceList::FindTranslatedEntry() ***************************************************************************** * Finds a translated entry. */ STDMETHODIMP_(PCM_PARTIAL_RESOURCE_DESCRIPTOR) CResourceList:: FindTranslatedEntry ( IN CM_RESOURCE_TYPE Type, IN ULONG Index ) { PAGED_CODE(); if (!Translated) { return 0; } PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = Translated->List[0].PartialResourceList.PartialDescriptors; ULONG count = EntriesInUse; if (count) { while (descriptor) { if (count-- == 0) { descriptor = NULL; } else { if (descriptor->Type == Type) { if (Index-- == 0) { break; } } descriptor++; } } } return descriptor; } /***************************************************************************** * CResourceList::FindUntranslatedEntry() ***************************************************************************** * Finds an untranslated entry. */ STDMETHODIMP_(PCM_PARTIAL_RESOURCE_DESCRIPTOR) CResourceList:: FindUntranslatedEntry ( IN CM_RESOURCE_TYPE Type, IN ULONG Index ) { PAGED_CODE(); if (!Untranslated) { return 0; } PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = Untranslated->List[0].PartialResourceList.PartialDescriptors; ULONG count = EntriesInUse; if (count) { while (descriptor) { if (count-- == 0) { descriptor = NULL; } else { if (descriptor->Type == Type) { if (Index-- == 0) { break; } } descriptor++; } } } return descriptor; } /***************************************************************************** * CResourceList::AddEntry() ***************************************************************************** * Adds an entry. */ STDMETHODIMP_(NTSTATUS) CResourceList:: AddEntry ( IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescr, IN PCM_PARTIAL_RESOURCE_DESCRIPTOR UntranslatedDescr ) { PAGED_CODE(); ASSERT(TranslatedDescr); ASSERT(UntranslatedDescr); NTSTATUS ntStatus = STATUS_SUCCESS; // when there is no resource list stored in this object, both EntriesInUse // and EntriesAllocated are 0. if (EntriesInUse < EntriesAllocated) { Translated-> List[0].PartialResourceList.PartialDescriptors[EntriesInUse] = *TranslatedDescr; Untranslated-> List[0].PartialResourceList.PartialDescriptors[EntriesInUse] = *UntranslatedDescr; EntriesInUse++; // update counts Translated-> List[0].PartialResourceList.Count = EntriesInUse; Untranslated-> List[0].PartialResourceList.Count = EntriesInUse; } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } return ntStatus; } /***************************************************************************** * CResourceList::AddEntryFromParent() ***************************************************************************** * Adds an entry from a parent. */ STDMETHODIMP_(NTSTATUS) CResourceList:: AddEntryFromParent ( IN PRESOURCELIST Parent, IN CM_RESOURCE_TYPE Type, IN ULONG Index ) { PAGED_CODE(); ASSERT(Parent); PCM_PARTIAL_RESOURCE_DESCRIPTOR translated = Parent->FindTranslatedEntry(Type,Index); PCM_PARTIAL_RESOURCE_DESCRIPTOR untranslated = Parent->FindUntranslatedEntry(Type,Index); NTSTATUS ntStatus; if (translated && untranslated) { ntStatus = AddEntry(translated,untranslated); } else { ntStatus = STATUS_INVALID_PARAMETER; } return ntStatus; } /***************************************************************************** * CResourceList::TranslatedList() ***************************************************************************** * Gets the list of translated resources. */ STDMETHODIMP_(PCM_RESOURCE_LIST) CResourceList:: TranslatedList ( void ) { PAGED_CODE(); return Translated; // Attention: This could be NULL. } /***************************************************************************** * CResourceList::UntranslatedList() ***************************************************************************** * Gets the list of untranslated resources. */ STDMETHODIMP_(PCM_RESOURCE_LIST) CResourceList:: UntranslatedList ( void ) { PAGED_CODE(); return Untranslated; // Attention: This could be NULL. } #pragma code_seg()