/** @file OcTemplateLib Copyright (c) 2018, vit9696 All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include #include #include #include #include #include #define PRIV_OC_BLOB_FIELDS(_, __) \ OC_BLOB (CHAR8, [], {0}, _, __) OC_DECLARE (PRIV_OC_BLOB) #define PRIV_OC_MAP_FIELDS(_, __) \ OC_MAP (PRIV_OC_BLOB, PRIV_OC_BLOB, _, __) OC_DECLARE (PRIV_OC_MAP) #define PRIV_OC_ARRAY_FIELDS(_, __) \ OC_ARRAY (PRIV_OC_BLOB, _, __) OC_DECLARE (PRIV_OC_ARRAY) typedef union PRIV_OC_LIST_ { PRIV_OC_MAP Map; PRIV_OC_ARRAY Array; } PRIV_OC_LIST; // // We have to be a bit careful about this hack, so assert that type layouts match at the very least. // #if 0 // defined(__GNUC__) || defined(__clang__) STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Count) == OFFSET_OF (PRIV_OC_MAP, Count), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, AllocCount) == OFFSET_OF (PRIV_OC_MAP, AllocCount), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Construct) == OFFSET_OF (PRIV_OC_MAP, Construct), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Destruct) == OFFSET_OF (PRIV_OC_MAP, Destruct), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Values) == OFFSET_OF (PRIV_OC_MAP, Values), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, ValueSize) == OFFSET_OF (PRIV_OC_MAP, ValueSize), "PRIV_OC_ARRAY vs PRIV_OC_MAP"); #endif VOID OcFreePointer ( VOID *Pointer, UINT32 Size ) { VOID **Field = (VOID **) Pointer; if (*Field) { FreePool (*Field); *Field = NULL; } } VOID OcZeroField ( VOID *Pointer, UINT32 Size ) { ZeroMem (Pointer, Size); } VOID OcDestructEmpty ( VOID *Pointer, UINT32 Size ) { (VOID) Pointer; (VOID) Size; } STATIC VOID OcFreeList ( VOID *Pointer, BOOLEAN HasKeys ) { UINT32 Index; PRIV_OC_LIST *List; List = (PRIV_OC_LIST *) Pointer; for (Index = 0; Index < List->Array.Count; Index++) { List->Array.Destruct (List->Array.Values[Index], List->Array.ValueSize); FreePool (List->Array.Values[Index]); if (HasKeys) { List->Map.KeyDestruct (List->Map.Keys[Index], List->Map.KeySize); FreePool (List->Map.Keys[Index]); } } OcFreePointer (&List->Array.Values, List->Array.AllocCount * List->Array.ValueSize); if (HasKeys) { OcFreePointer (&List->Map.Keys, List->Array.AllocCount * List->Map.KeySize); } List->Array.Count = 0; List->Array.AllocCount = 0; } VOID OcFreeMap ( VOID *Pointer, UINT32 Size ) { OcFreeList (Pointer, TRUE); } VOID OcFreeArray ( VOID *Pointer, UINT32 Size ) { OcFreeList (Pointer, FALSE); } VOID * OcBlobAllocate ( VOID *Pointer, UINT32 Size, UINT32 **OutSize OPTIONAL ) { PRIV_OC_BLOB *Blob; VOID *DynValue; Blob = (PRIV_OC_BLOB *) Pointer; DEBUG ((DEBUG_VERBOSE, "OCTPL: Allocating %u bytes in blob %p with size %u/%u curr %p\n", Size, Blob, Blob->Size, Blob->MaxSize, Blob->DynValue)); // // We fit into static space // if (Size <= Blob->MaxSize) { OcFreePointer (&Blob->DynValue, Blob->Size); Blob->Size = Size; if (OutSize != NULL) { *OutSize = &Blob->Size; } return Blob->Value; } // // We do not fit into dynamic space // if (Size > Blob->Size) { OcFreePointer (&Blob->DynValue, Blob->Size); DynValue = AllocatePool (Size); if (DynValue == NULL) { DEBUG ((DEBUG_VERBOSE, "OCTPL: Failed to fit %u bytes in OC_BLOB\n", Size)); return NULL; } // // Propagate default value. // CopyMem (DynValue, Blob->Value, Blob->MaxSize); Blob->DynValue = DynValue; } Blob->Size = Size; if (OutSize != NULL) { *OutSize = &Blob->Size; } return Blob->DynValue; } BOOLEAN OcListEntryAllocate ( VOID *Pointer, VOID **Value, VOID **Key ) { PRIV_OC_LIST *List; UINT32 Count; UINT32 AllocCount; VOID **NewValues; VOID **NewKeys; List = (PRIV_OC_LIST *) Pointer; // // Prepare new pair. // *Value = AllocatePool (List->Array.ValueSize); if (*Value == NULL) { return FALSE; } if (Key != NULL) { *Key = AllocatePool (List->Map.KeySize); if (*Key == NULL) { FreePool (*Value); return FALSE; } } // // Initialize new pair. // List->Array.Construct (*Value, List->Array.ValueSize); if (Key != NULL) { List->Map.KeyConstruct (*Key, List->Map.KeySize); } Count = 0; AllocCount = 1; // // Push new entry if there is enough room. // if (List->Array.Values != NULL) { Count = List->Array.Count; AllocCount = List->Array.AllocCount; if (AllocCount > Count) { List->Array.Count++; List->Array.Values[Count] = *Value; if (Key != NULL) { List->Map.Keys[Count] = *Key; } return TRUE; } } // // Allocate twice more room and destruct on failure. // AllocCount *= 2; NewValues = (VOID **) AllocatePool ( sizeof (VOID *) * AllocCount ); if (NewValues == NULL) { List->Array.Destruct (*Value, List->Array.ValueSize); FreePool (*Value); if (Key != NULL) { List->Map.KeyDestruct (*Key, List->Map.KeySize); FreePool (*Key); } return FALSE; } if (Key != NULL) { NewKeys = (VOID **) AllocatePool ( sizeof (VOID *) * AllocCount ); if (NewKeys == NULL) { List->Array.Destruct (*Value, List->Array.ValueSize); List->Map.KeyDestruct (*Key, List->Map.KeySize); FreePool (NewValues); FreePool (*Value); FreePool (*Key); return FALSE; } } else { NewKeys = NULL; } // // Insert and return. // if (List->Array.Values != NULL) { CopyMem ( &NewValues[0], &List->Array.Values[0], sizeof (VOID *) * Count ); FreePool (List->Array.Values); } if (Key != NULL && List->Map.Keys != NULL) { CopyMem ( &NewKeys[0], &List->Map.Keys[0], sizeof (VOID *) * Count ); FreePool (List->Map.Keys); } List->Array.Count++; List->Array.AllocCount = AllocCount; NewValues[Count] = *Value; List->Array.Values = (PRIV_OC_BLOB **) NewValues; if (Key != NULL) { NewKeys[Count] = *Key; List->Map.Keys = (PRIV_OC_BLOB **) NewKeys; } return TRUE; } OC_BLOB_STRUCTORS (OC_STRING) OC_BLOB_STRUCTORS (OC_DATA) OC_MAP_STRUCTORS (OC_ASSOC)