OpenCorePkg/Library/OcFlexArrayLib/AsciiStringBuffer.c
2023-04-13 13:16:14 +06:00

208 lines
4.7 KiB
C

/** @file
String buffer.
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#include <Base.h>
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcDebugLogLib.h>
#include <Library/OcFlexArrayLib.h>
#include <Library/PrintLib.h>
OC_ASCII_STRING_BUFFER *
OcAsciiStringBufferInit (
VOID
)
{
OC_ASCII_STRING_BUFFER *Buffer;
Buffer = AllocateZeroPool (sizeof (OC_ASCII_STRING_BUFFER));
return Buffer;
}
EFI_STATUS
OcAsciiStringBufferAppend (
IN OUT OC_ASCII_STRING_BUFFER *Buffer,
IN CONST CHAR8 *AppendString OPTIONAL
)
{
return OcAsciiStringBufferAppendN (Buffer, AppendString, MAX_UINTN);
}
/**
Extend string buffer by a specified length.
@param[in,out] Buffer String buffer to be extended.
@param[in] AppendLength Length to be appended.
@param[out] TargetLength Target length of the extended buffer.
@retval EFI_SUCCESS The buffer was extended successfully.
@retval EFI_OUT_OF_RESOURCES The extension failed due to the lack of resources.
@retval EFI_UNSUPPORTED The buffer has no size.
**/
STATIC
EFI_STATUS
InternalAsciiStringBufferExtendBy (
IN OUT OC_ASCII_STRING_BUFFER *Buffer,
IN CONST UINTN AppendLength,
OUT UINTN *TargetLength
)
{
UINTN NewSize;
ASSERT (AppendLength != 0);
if (Buffer->String == NULL) {
ASSERT (Buffer->BufferSize == 0);
Buffer->String = AllocatePool (AppendLength + 1);
if (Buffer->String == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Buffer->BufferSize = AppendLength + 1;
*TargetLength = AppendLength;
} else {
if (Buffer->BufferSize == 0) {
ASSERT (FALSE);
return EFI_UNSUPPORTED;
}
NewSize = Buffer->BufferSize;
if (BaseOverflowAddUN (Buffer->StringLength, AppendLength, TargetLength)) {
return EFI_OUT_OF_RESOURCES;
}
while (NewSize <= *TargetLength) {
if (BaseOverflowMulUN (NewSize, 2, &NewSize)) {
return EFI_OUT_OF_RESOURCES;
}
}
if (NewSize > Buffer->BufferSize) {
Buffer->String = ReallocatePool (Buffer->BufferSize, NewSize, Buffer->String);
if (Buffer->String == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Buffer->BufferSize = NewSize;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
OcAsciiStringBufferAppendN (
IN OUT OC_ASCII_STRING_BUFFER *Buffer,
IN CONST CHAR8 *AppendString, OPTIONAL
IN CONST UINTN Length
)
{
EFI_STATUS Status;
UINTN AppendLength;
UINTN TargetLength;
if (AppendString == NULL) {
return EFI_SUCCESS;
}
AppendLength = AsciiStrnLenS (AppendString, Length);
//
// Buffer stays NULL if zero appended.
//
if (AppendLength == 0) {
return EFI_SUCCESS;
}
Status = InternalAsciiStringBufferExtendBy (Buffer, AppendLength, &TargetLength);
if (EFI_ERROR (Status)) {
return Status;
}
Status = AsciiStrnCpyS (&Buffer->String[Buffer->StringLength], AppendLength + 1, AppendString, AppendLength);
if (EFI_ERROR (Status)) {
return Status;
}
Buffer->StringLength = TargetLength;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
OcAsciiStringBufferSPrint (
IN OUT OC_ASCII_STRING_BUFFER *Buffer,
IN CONST CHAR8 *FormatString,
...
)
{
EFI_STATUS Status;
VA_LIST Marker;
VA_LIST Marker2;
UINTN NumberOfPrinted;
UINTN TargetLength;
ASSERT (FormatString != NULL);
VA_START (Marker, FormatString);
VA_COPY (Marker2, Marker);
NumberOfPrinted = SPrintLengthAsciiFormat (FormatString, Marker2);
VA_END (Marker2);
//
// Buffer stays NULL if zero appended.
//
if (NumberOfPrinted == 0) {
Status = EFI_SUCCESS;
} else {
Status = InternalAsciiStringBufferExtendBy (Buffer, NumberOfPrinted, &TargetLength);
if (!EFI_ERROR (Status)) {
AsciiVSPrint (&Buffer->String[Buffer->StringLength], NumberOfPrinted + 1, FormatString, Marker);
Buffer->StringLength = TargetLength;
}
}
VA_END (Marker);
return Status;
}
CHAR8 *
OcAsciiStringBufferFreeContainer (
IN OUT OC_ASCII_STRING_BUFFER **StringBuffer
)
{
CHAR8 *String;
if ((StringBuffer == NULL) || (*StringBuffer == NULL)) {
ASSERT (FALSE);
return NULL;
}
String = (*StringBuffer)->String;
FreePool (*StringBuffer);
*StringBuffer = NULL;
return String;
}
VOID
OcAsciiStringBufferFree (
IN OUT OC_ASCII_STRING_BUFFER **StringBuffer
)
{
CHAR8 *Result;
Result = OcAsciiStringBufferFreeContainer (StringBuffer);
if (Result != NULL) {
FreePool (Result);
}
}