/** @file
  Provide functions to provide tcg storage core spec related functions.

Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Library/TcgStorageCoreLib.h>

#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
//#include <Library/PrintLib.h>

/**
  Required to be called before calling any other Tcg functions with the TCG_CREATE_STRUCT.
  Initializes the packet variables to NULL.  Additionally, the buffer will be memset.

  @param [in/out]    CreateStruct    Structure to initialize
  @param [in]        Buffer          Buffer allocated by client of library.  It will contain the Tcg encoded packet.  This cannot be null.
  @param [in]        BufferSize      Size of buffer provided.  It cannot be 0.

  @retval       Return the action result.
**/
TCG_RESULT
EFIAPI
TcgInitTcgCreateStruct(
  TCG_CREATE_STRUCT      *CreateStruct,
  VOID                   *Buffer,
  UINT32                 BufferSize
  )
{
  NULL_CHECK(CreateStruct);
  NULL_CHECK(Buffer);

  if (BufferSize == 0) {
    DEBUG ((DEBUG_INFO, "BufferSize=0\n"));
    return (TcgResultFailureZeroSize);
  }

  ZeroMem(Buffer, BufferSize);
  CreateStruct->BufferSize = BufferSize;
  CreateStruct->Buffer = Buffer;
  CreateStruct->ComPacket = NULL;
  CreateStruct->CurPacket = NULL;
  CreateStruct->CurSubPacket = NULL;

  return (TcgResultSuccess);
}

/**

  Encodes the ComPacket header to the data structure.

  @param[in/out]    CreateStruct          Structure to initialize
  @param[in]        ComId                 ComID of the Tcg ComPacket.
  @param[in]        ComIdExtension        ComID Extension of the Tcg ComPacket.

**/
TCG_RESULT
EFIAPI
TcgStartComPacket(
  TCG_CREATE_STRUCT   *CreateStruct,
  UINT16              ComId,
  UINT16              ComIdExtension
  )
{
  NULL_CHECK(CreateStruct);

  if (CreateStruct->ComPacket != NULL ||
      CreateStruct->CurPacket != NULL ||
      CreateStruct->CurSubPacket != NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket,
    CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  if (sizeof(TCG_COM_PACKET) > CreateStruct->BufferSize) {
    DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
    return (TcgResultFailureBufferTooSmall);
  }

  CreateStruct->ComPacket = (TCG_COM_PACKET*)CreateStruct->Buffer;
  CreateStruct->ComPacket->ComIDBE = SwapBytes16(ComId);
  CreateStruct->ComPacket->ComIDExtensionBE = SwapBytes16(ComIdExtension);

  return (TcgResultSuccess);
}

/**

  Starts a new ComPacket in the Data structure.

  @param [in/out]     CreateStruct    Structure used to add Tcg Packet
  @param[in]          Tsn             Packet Tper session number
  @param[in]          Hsn             Packet Host session number
  @param[in]          SeqNumber       Packet Sequence Number
  @param[in]          AckType         Packet Acknowledge Type
  @param[in]          Ack             Packet Acknowledge

**/
TCG_RESULT
EFIAPI
TcgStartPacket(
  TCG_CREATE_STRUCT    *CreateStruct,
  UINT32               Tsn,
  UINT32               Hsn,
  UINT32               SeqNumber,
  UINT16               AckType,
  UINT32               Ack
  )
{
  UINT32 AddedSize;
  NULL_CHECK(CreateStruct);

  AddedSize = 0;

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket != NULL ||
      CreateStruct->CurSubPacket != NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  // update TCG_COM_PACKET and packet lengths
  AddedSize = sizeof(TCG_PACKET);

  if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
    DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
    return (TcgResultFailureBufferTooSmall);
  }

  CreateStruct->CurPacket = (TCG_PACKET*)(CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE));

  CreateStruct->CurPacket->TperSessionNumberBE = SwapBytes32( Tsn );
  CreateStruct->CurPacket->HostSessionNumberBE = SwapBytes32( Hsn );
  CreateStruct->CurPacket->SequenceNumberBE = SwapBytes32( SeqNumber );
  CreateStruct->CurPacket->AckTypeBE = SwapBytes16( AckType );
  CreateStruct->CurPacket->AcknowledgementBE = SwapBytes32( Ack );

  CreateStruct->CurPacket->LengthBE = 0;

  // update TCG_COM_PACKET Length for next pointer
  CreateStruct->ComPacket->LengthBE = SwapBytes32( SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize );

  return (TcgResultSuccess);
}

/**

  Starts a new SubPacket in the Data structure.

  @param[in/out]    CreateStruct        Structure used to start Tcg SubPacket
  @param[in]        Kind                SubPacket kind

**/
TCG_RESULT
EFIAPI
TcgStartSubPacket(
  TCG_CREATE_STRUCT    *CreateStruct,
  UINT16               Kind
  )
{
  UINT32 AddedSize;

  NULL_CHECK(CreateStruct);

  AddedSize = 0;

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket == NULL ||
      CreateStruct->CurSubPacket != NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  AddedSize = sizeof(TCG_SUB_PACKET);

  if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
    DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
    return (TcgResultFailureBufferTooSmall);
  }

  CreateStruct->CurSubPacket = (TCG_SUB_PACKET*)(CreateStruct->CurPacket->Payload + SwapBytes32(CreateStruct->CurPacket->LengthBE));
  CreateStruct->CurSubPacket->KindBE = SwapBytes16(Kind);

  // update lengths
  CreateStruct->CurSubPacket->LengthBE = 0;

  // update TCG_COM_PACKET and packet lengths
  CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize);
  CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize);

  return (TcgResultSuccess);
}

/**

  Ends the current SubPacket in the Data structure.  This function will also perform the 4-byte padding
  required for Subpackets.

  @param[in/out]       CreateStruct        Structure used to end the current Tcg SubPacket

**/
TCG_RESULT
EFIAPI
TcgEndSubPacket(
  TCG_CREATE_STRUCT   *CreateStruct
  )
{
  UINT32 PadSize;

  NULL_CHECK(CreateStruct);

  PadSize = 0;

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket == NULL  ||
      CreateStruct->CurSubPacket == NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  // align to 4-byte boundaries, so shift padding
  // pad Size does not apply to subpacket Length
  PadSize = TCG_SUBPACKET_ALIGNMENT - (SwapBytes32(CreateStruct->CurSubPacket->LengthBE) & (TCG_SUBPACKET_ALIGNMENT - 1));

  if (PadSize == TCG_SUBPACKET_ALIGNMENT) {
    PadSize = 0;
  }

  if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize) > CreateStruct->BufferSize) {
    DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
    return (TcgResultFailureBufferTooSmall);
  }

  CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + PadSize);
  CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize);

  CreateStruct->CurSubPacket = NULL;

  return (TcgResultSuccess);
}

/**

  Ends the current Packet in the Data structure.

  @param[in/out]       CreateStruct        Structure used to end the current Tcg Packet

**/
TCG_RESULT
EFIAPI
TcgEndPacket(
  TCG_CREATE_STRUCT     *CreateStruct
  )
{
  NULL_CHECK(CreateStruct);

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket == NULL ||
      CreateStruct->CurSubPacket != NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  CreateStruct->CurPacket = NULL;

  return (TcgResultSuccess);
}

/**

  Ends the ComPacket in the Data structure and ret

  @param [in/out]       CreateStruct       Structure used to end the Tcg ComPacket
  @param [in/out]       Size               Describes the Size of the entire ComPacket (Header and payload). Filled out by function.

**/
TCG_RESULT
EFIAPI
TcgEndComPacket(
  TCG_CREATE_STRUCT      *CreateStruct,
  UINT32                 *Size
  )
{
  NULL_CHECK(CreateStruct);
  NULL_CHECK(Size);

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket != NULL ||
      CreateStruct->CurSubPacket != NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  *Size = SwapBytes32(CreateStruct->ComPacket->LengthBE) + sizeof(*CreateStruct->ComPacket);
  CreateStruct->ComPacket = NULL;

  return (TcgResultSuccess);
}

/**
  Adds raw Data with optional Header

  @param       CreateStruct       The create structure.
  @param       Header             The header structure.
  @param       HeaderSize         The header size.
  @param       Data               The data need to add.
  @param       DataSize           The data size.
  @param       ByteSwapData       Whether byte or swap data.

**/
TCG_RESULT
TcgAddRawTokenData(
  TCG_CREATE_STRUCT      *CreateStruct,
  const VOID             *Header,
  UINT8                  HeaderSize,
  const VOID             *Data,
  UINT32                 DataSize,
  BOOLEAN                ByteSwapData
  )
{
  UINT32 AddedSize;
  UINT8* Dest;
  const UINT8* DataBytes;
  UINT32 Index;

  AddedSize = 0;
  Index = 0;
  Dest = NULL;

  NULL_CHECK(CreateStruct);

  if ((HeaderSize != 0 && Header == NULL) ||
      (DataSize != 0 && Data == NULL)
     ) {
    DEBUG ((DEBUG_INFO, "HeaderSize=0x%X Header=%p DataSize=0x%X Data=%p\n", HeaderSize, Header, DataSize, Data));
    return (TcgResultFailureNullPointer);
  }

  if (CreateStruct->ComPacket == NULL ||
      CreateStruct->CurPacket == NULL ||
      CreateStruct->CurSubPacket == NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
    return (TcgResultFailureInvalidAction);
  }

  // verify there is enough Buffer Size
  AddedSize = HeaderSize + DataSize;
  if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
    return (TcgResultFailureBufferTooSmall);
  }

  // Get a pointer to where the new bytes should go
  Dest = CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE);

  switch (HeaderSize) {
    case sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM):
    case sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM):
    case sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM):
      CopyMem(Dest, Header, HeaderSize);
      Dest += HeaderSize;
    case 0: // no Header is valid
      break;
    // invalid Header Size
    default:
      DEBUG ((DEBUG_INFO, "unsupported HeaderSize=%u\n", HeaderSize));
      return TcgResultFailure;
  }

  // copy the Data bytes
  if (ByteSwapData) {
    DataBytes = (const UINT8*)Data;
    for (Index = 0; Index < DataSize; Index++) {
      Dest[Index] = DataBytes[DataSize - 1 - Index];
    }
  } else {
    CopyMem(Dest, Data, DataSize);
  }

  // Update all the packet sizes
  CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize);
  CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize);
  CreateStruct->CurSubPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurSubPacket->LengthBE) + AddedSize);

  return (TcgResultSuccess);
}

/**

  Adds a single raw token byte to the Data structure.

  @param[in/out]   CreateStruct        Structure used to add the byte
  @param[in]       Byte                Byte to add

**/
TCG_RESULT
EFIAPI
TcgAddRawByte(
  TCG_CREATE_STRUCT     *CreateStruct,
  UINT8                 Byte
  )
{
  return TcgAddRawTokenData(CreateStruct, NULL, 0, &Byte, 1, FALSE);
}


/**
   simple tokens - atoms: tiny, short, medium, long and empty atoms.
   tiny atom can be a signed or unsigned integer.
   short, medium, long can be a signed or unsigned integer OR a complete or non-final byte sequence.

  @param       CreateStruct       The create structure.
  @param       Data               The data need to add.
  @param       DataSize           The data size.
  @param       ByteOrInt,         Data format is byte or int.
  @param       SignOrCont         sign or cont.


**/
TCG_RESULT
TcgAddAtom(
  TCG_CREATE_STRUCT   *CreateStruct,
  const VOID          *Data,
  UINT32              DataSize,
  UINT8               ByteOrInt,
  UINT8               SignOrCont
  )
{
  const UINT8* DataBytes;
  TCG_SIMPLE_TOKEN_TINY_ATOM TinyAtom;
  TCG_SIMPLE_TOKEN_SHORT_ATOM ShortAtom;
  TCG_SIMPLE_TOKEN_MEDIUM_ATOM MediumAtom;
  TCG_SIMPLE_TOKEN_LONG_ATOM LongAtom;

  NULL_CHECK(CreateStruct);

  if (DataSize == 0) {
    if (ByteOrInt == TCG_ATOM_TYPE_INTEGER) {
      DEBUG ((DEBUG_INFO, "0-Size integer not allowed\n"));
      return TcgResultFailure;
    }
  } else {
    // if DataSize != 0, Data must be valid
    NULL_CHECK(Data);
  }

  // encode Data using the shortest possible atom
  DataBytes = (const UINT8*)Data;
  if ((DataSize == 1) &&
      (ByteOrInt == TCG_ATOM_TYPE_INTEGER) &&
      ((SignOrCont != 0 && ((TCG_TOKEN_TINYATOM_SIGNED_MIN_VALUE <= *(INT8*)Data) && (*(INT8*)Data <= TCG_TOKEN_TINYATOM_SIGNED_MAX_VALUE))) ||
       (SignOrCont == 0 && ((*DataBytes <= TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE))))
     ) {
    TinyAtom.TinyAtomBits.IsZero = 0;
    TinyAtom.TinyAtomBits.Sign = SignOrCont;
    TinyAtom.TinyAtomBits.Data = *DataBytes & TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE;
    return TcgAddRawTokenData(CreateStruct, NULL, 0, (UINT8*)&TinyAtom, sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM), FALSE);
  }

  if (DataSize <= TCG_TOKEN_SHORTATOM_MAX_BYTE_SIZE) {
    ShortAtom.ShortAtomBits.IsOne = 1;
    ShortAtom.ShortAtomBits.IsZero = 0;
    ShortAtom.ShortAtomBits.ByteOrInt = ByteOrInt;
    ShortAtom.ShortAtomBits.SignOrCont = SignOrCont;
    ShortAtom.ShortAtomBits.Length = DataSize & 0x0F;
    return TcgAddRawTokenData(CreateStruct, &ShortAtom, sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
  }

  if (DataSize <= TCG_TOKEN_MEDIUMATOM_MAX_BYTE_SIZE) {
    MediumAtom.MediumAtomBits.IsOne1 = 1;
    MediumAtom.MediumAtomBits.IsOne2 = 1;
    MediumAtom.MediumAtomBits.IsZero = 0;
    MediumAtom.MediumAtomBits.ByteOrInt = ByteOrInt;
    MediumAtom.MediumAtomBits.SignOrCont = SignOrCont;
    MediumAtom.MediumAtomBits.LengthLow = DataSize & 0xFF;
    MediumAtom.MediumAtomBits.LengthHigh = (DataSize >> TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) & TCG_MEDIUM_ATOM_LENGTH_HIGH_MASK;
    return TcgAddRawTokenData(CreateStruct, &MediumAtom, sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
  }

  LongAtom.LongAtomBits.IsOne1 = 1;
  LongAtom.LongAtomBits.IsOne2 = 1;
  LongAtom.LongAtomBits.IsOne3 = 1;
  LongAtom.LongAtomBits.IsZero = 0;
  LongAtom.LongAtomBits.ByteOrInt = ByteOrInt;
  LongAtom.LongAtomBits.SignOrCont = SignOrCont;
  LongAtom.LongAtomBits.LengthLow = DataSize & 0xFF;
  LongAtom.LongAtomBits.LengthMid = (DataSize >> TCG_LONG_ATOM_LENGTH_MID_SHIFT) & 0xFF;
  LongAtom.LongAtomBits.LengthHigh = (DataSize >> TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) & 0xFF;
  return TcgAddRawTokenData(CreateStruct, &LongAtom, sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
}

/**

  Adds the Data parameter as a byte sequence to the Data structure.

  @param[in/out]    CreateStruct      Structure used to add the byte sequence
  @param[in]        Data              Byte sequence that will be encoded and copied into Data structure
  @param[in]        DataSize          Length of Data provided
  @param[in]        Continued         TRUE if byte sequence is continued or
                                      FALSE if the Data contains the entire byte sequence to be encoded

**/
TCG_RESULT
EFIAPI
TcgAddByteSequence(
  TCG_CREATE_STRUCT     *CreateStruct,
  const VOID            *Data,
  UINT32                DataSize,
  BOOLEAN               Continued
  )
{
  return TcgAddAtom(CreateStruct, Data, DataSize, TCG_ATOM_TYPE_BYTE, Continued ? 1 : 0);
}

/**

  Adds an arbitrary-Length integer to the Data structure.
  The integer will be encoded using the shortest possible atom.

  @param[in/out]     CreateStruct      Structure used to add the integer
  @param[in]         Data              Integer in host byte order that will be encoded and copied into Data structure
  @param[in]         DataSize          Length in bytes of the Data provided
  @param[in]         SignedInteger     TRUE if the integer is signed or FALSE if the integer is unsigned

**/
TCG_RESULT
EFIAPI
TcgAddInteger(
  TCG_CREATE_STRUCT  *CreateStruct,
  const VOID         *Data,
  UINT32             DataSize,
  BOOLEAN            SignedInteger
  )
{
  const UINT8* DataBytes;
  UINT32 ActualDataSize;
  BOOLEAN ValueIsNegative;

  NULL_CHECK(CreateStruct);
  NULL_CHECK(Data);

  if (DataSize == 0) {
    DEBUG ((DEBUG_INFO, "invalid DataSize=0\n"));
    return TcgResultFailure;
  }

  DataBytes = (const UINT8*)Data;

  // integer should be represented by smallest atom possible
  // so calculate real Data Size
  ValueIsNegative = SignedInteger && DataBytes[ DataSize - 1 ] & 0x80;

  // assumes native Data is little endian
  // shorten Data to smallest byte representation
  for (ActualDataSize = DataSize; ActualDataSize > 1; ActualDataSize--) {
    // ignore sign extended  FFs
    if (ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0xFF)) {
      break;
    } else if (!ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0)) {
      // ignore extended 00s
      break;
    }
  }

  return TcgAddAtom(CreateStruct, Data, ActualDataSize, TCG_ATOM_TYPE_INTEGER, SignedInteger ? 1 : 0);
}

/**
  Adds an 8-bit unsigned integer to the Data structure.

  @param[in/out]       CreateStruct        Structure used to add the integer
  @param[in]           Value               Integer Value to add

**/
TCG_RESULT
EFIAPI
TcgAddUINT8(
  TCG_CREATE_STRUCT   *CreateStruct,
  UINT8               Value
  )
{
  return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
}

/**

  Adds a 16-bit unsigned integer to the Data structure.

  @param[in/out]       CreateStruct        Structure used to add the integer
  @param[in]           Value               Integer Value to add

**/
TCG_RESULT
EFIAPI
TcgAddUINT16 (
  TCG_CREATE_STRUCT   *CreateStruct,
  UINT16              Value
  )
{
  return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
}

/**

  Adds a 32-bit unsigned integer to the Data structure.

  @param[in/out]        CreateStruct        Structure used to add the integer
  @param[in]            Value               Integer Value to add

**/
TCG_RESULT
EFIAPI
TcgAddUINT32(
  TCG_CREATE_STRUCT    *CreateStruct,
  UINT32               Value
  )
{
  return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
}


/**

  Adds a 64-bit unsigned integer to the Data structure.

  @param[in/out]      CreateStruct        Structure used to add the integer
  @param[in]          Value               Integer Value to add

**/
TCG_RESULT
EFIAPI
TcgAddUINT64(
  TCG_CREATE_STRUCT   *CreateStruct,
  UINT64              Value
  )
{
  return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
}

/**
  Adds a BOOLEAN to the Data structure.

  @param[in/out]       CreateStruct     Structure used to add the integer
  @param[in]           Value              BOOLEAN Value to add

**/
TCG_RESULT
EFIAPI
TcgAddBOOLEAN(
  TCG_CREATE_STRUCT    *CreateStruct,
  BOOLEAN              Value
  )
{
  return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
}

/**
  Add tcg uid info.

  @param [in/out]       CreateStruct       Structure used to add the integer
  @param                Uid                Input uid info.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddTcgUid(
  TCG_CREATE_STRUCT   *CreateStruct,
  TCG_UID             Uid
  )
{
  return TcgAddByteSequence(CreateStruct, &Uid, sizeof(TCG_UID), FALSE);
}

/**
  Add start list.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddStartList(
  TCG_CREATE_STRUCT          *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTLIST);
}

/**
  Add end list.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddEndList(
  TCG_CREATE_STRUCT       *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDLIST);
}

/**
  Add start name.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddStartName(
  TCG_CREATE_STRUCT          *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTNAME);
}

/**
  Add end name.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddEndName(
  TCG_CREATE_STRUCT          *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDNAME);
}

/**
  Add end call.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddCall(
  TCG_CREATE_STRUCT      *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_CALL);
}

/**
  Add end of data.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddEndOfData(
  TCG_CREATE_STRUCT          *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDDATA);
}

/**
  Add end of session.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddEndOfSession(
  TCG_CREATE_STRUCT              *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDSESSION);
}

/**
  Add start transaction.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddStartTransaction(
  TCG_CREATE_STRUCT             *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTTRANSACTION);
}

/**
  Add end transaction.

  @param [in/out]       CreateStruct       Structure used to add the integer

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgAddEndTransaction(
  TCG_CREATE_STRUCT           *CreateStruct
  )
{
  return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDTRANSACTION);
}

/**
  Initial the tcg parse stucture.

  @param    ParseStruct    Input parse structure.
  @param    Buffer         Input buffer data.
  @param    BufferSize     Input buffer size.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgInitTcgParseStruct(
  TCG_PARSE_STRUCT          *ParseStruct,
  const VOID                *Buffer,
  UINT32                    BufferSize
  )
{
  UINT32 ComPacketLength;
  UINT32 PacketLength;

  NULL_CHECK(ParseStruct);
  NULL_CHECK(Buffer);

  if (BufferSize < sizeof(TCG_COM_PACKET)) {
    return (TcgResultFailureBufferTooSmall);
  }

  ParseStruct->ComPacket = (TCG_COM_PACKET*)Buffer;

  ComPacketLength = SwapBytes32(ParseStruct->ComPacket->LengthBE);

  if ((BufferSize - sizeof(TCG_COM_PACKET)) < ComPacketLength) {
    DEBUG ((DEBUG_INFO, "Buffer %u too small for ComPacket %u\n", BufferSize, ComPacketLength));
    return (TcgResultFailureBufferTooSmall);
  }

  ParseStruct->BufferSize = BufferSize;
  ParseStruct->Buffer = Buffer;

  ParseStruct->CurPacket = NULL;
  ParseStruct->CurSubPacket = NULL;
  ParseStruct->CurPtr = NULL;

  // if payload > 0, then must have a packet
  if (ComPacketLength != 0) {
    if (ComPacketLength < sizeof(TCG_PACKET)) {
      DEBUG ((DEBUG_INFO, "ComPacket too small for Packet\n"));
      return (TcgResultFailureBufferTooSmall);
    }
    ParseStruct->CurPacket = (TCG_PACKET*)ParseStruct->ComPacket->Payload;

    PacketLength = SwapBytes32(ParseStruct->CurPacket->LengthBE);

    if (PacketLength > 0) {
      if (PacketLength < sizeof(TCG_SUB_PACKET)) {
          DEBUG ((DEBUG_INFO, "Packet too small for SubPacket\n"));
          return (TcgResultFailureBufferTooSmall);
      }

      ParseStruct->CurSubPacket = (TCG_SUB_PACKET*)ParseStruct->CurPacket->Payload;
    }
  }

  //TODO should check for method status list at this point?

  return (TcgResultSuccess);
}

/**
  Get next token info.

  @param    ParseStruct      Input parse structure info.
  @param    TcgToken         return the tcg token info.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextToken(
  TCG_PARSE_STRUCT      *ParseStruct,
  TCG_TOKEN             *TcgToken
  )
{
  const UINT8* EndOfSubPacket;
  UINT8* TokenEnd;
  UINT8 Hdr;
  TCG_SIMPLE_TOKEN_SHORT_ATOM* TmpShort;
  const TCG_SIMPLE_TOKEN_MEDIUM_ATOM* TmpMed;
  const TCG_SIMPLE_TOKEN_LONG_ATOM* TmpLong;

  NULL_CHECK(ParseStruct);
  NULL_CHECK(TcgToken);

  if (ParseStruct->ComPacket == NULL ||
      ParseStruct->CurPacket == NULL ||
      ParseStruct->CurSubPacket == NULL
     ) {
    DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", ParseStruct->ComPacket, ParseStruct->CurPacket, ParseStruct->CurSubPacket));
    return TcgResultFailureInvalidAction;
  }

  // initial call, start at sub packet
  if (ParseStruct->CurPtr == NULL) {
    ParseStruct->CurPtr = ParseStruct->CurSubPacket->Payload;
  }

  EndOfSubPacket = ParseStruct->CurSubPacket->Payload + SwapBytes32(ParseStruct->CurSubPacket->LengthBE);
  TokenEnd = NULL;

  // confirmed that subpacket Length falls within end of Buffer and TCG_COM_PACKET,
  // so simply need to verify the loop stays within current subpacket
  if (ParseStruct->CurPtr >= EndOfSubPacket) {
    DEBUG ((DEBUG_INFO, "ParseStruct->CurPtr >= EndOfSubPacket\n"));
    return (TcgResultFailureEndBuffer);
  }

  Hdr = *ParseStruct->CurPtr;
  TcgToken->HdrStart = ParseStruct->CurPtr;

  // Tiny Atom range
  if (Hdr <= 0x7F) {
    // tiny atom Header is only 1 byte, so don't need to verify Size before cast and access
    TcgToken->Type = TcgTokenTypeTinyAtom;

    TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM);

    // verify caller will have enough Size to reference token
    if (TokenEnd >= EndOfSubPacket) {
      DEBUG ((DEBUG_INFO, "Tiny Atom TokenEnd >= EndOfSubPacket\n"));
      return (TcgResultFailureEndBuffer);
    }
  }
  // Short Atom Range
  else if (0x80 <= Hdr && Hdr <= 0xBF) {
    // short atom Header is only 1 byte, so don't need to verify Size before cast and access
    TmpShort = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)(ParseStruct->CurPtr);
    TcgToken->Type = TcgTokenTypeShortAtom;

    TokenEnd = (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM) + TmpShort->ShortAtomBits.Length);

    // verify caller will have enough Size to reference token
    if (TokenEnd >= EndOfSubPacket) {
      DEBUG ((DEBUG_INFO, "Short Atom TokenEnd >= EndOfSubPacket\n"));
      return (TcgResultFailureEndBuffer);
    }
  }
  // Medium Atom Range
  else if (0xC0 <= Hdr && Hdr <= 0xDF) {
    if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) >= EndOfSubPacket) {
      return (TcgResultFailureEndBuffer);
    }
    TmpMed = (const TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)ParseStruct->CurPtr;
    TcgToken->Type = TcgTokenTypeMediumAtom;
    TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) +
               ((TmpMed->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) |
                TmpMed->MediumAtomBits.LengthLow);

    // verify caller will have enough Size to reference token
    if (TokenEnd >= EndOfSubPacket) {
      DEBUG ((DEBUG_INFO, "Medium Atom TokenEnd >= EndOfSubPacket\n"));
      return (TcgResultFailureEndBuffer);
    }
  }
  // Long Atom Range
  else if (0xE0 <= Hdr && Hdr <= 0xE3) {
    if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) >= EndOfSubPacket) {
      return (TcgResultFailureEndBuffer);
    }
    TmpLong = (const TCG_SIMPLE_TOKEN_LONG_ATOM*)ParseStruct->CurPtr;
    TcgToken->Type = TcgTokenTypeLongAtom;

    TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) +
               ((TmpLong->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) |
                (TmpLong->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT)   |
                TmpLong->LongAtomBits.LengthLow);

    // verify caller will have enough Size to reference token
    if (TokenEnd >= EndOfSubPacket) {
      DEBUG ((DEBUG_INFO, "Long Atom TokenEnd >= EndOfSubPacket\n"));
      return (TcgResultFailureEndBuffer);
    }
  } else {
    // single byte tokens
    switch (Hdr) {
      case TCG_TOKEN_STARTLIST:
          TcgToken->Type = TcgTokenTypeStartList;
          break;
      case TCG_TOKEN_ENDLIST:
          TcgToken->Type = TcgTokenTypeEndList;
          break;
      case TCG_TOKEN_STARTNAME:
          TcgToken->Type = TcgTokenTypeStartName;
          break;
      case TCG_TOKEN_ENDNAME:
          TcgToken->Type = TcgTokenTypeEndName;
          break;
      case TCG_TOKEN_CALL:
          TcgToken->Type = TcgTokenTypeCall;
          break;
      case TCG_TOKEN_ENDDATA:
          TcgToken->Type = TcgTokenTypeEndOfData;
          break;
      case TCG_TOKEN_ENDSESSION:
          TcgToken->Type = TcgTokenTypeEndOfSession;
          break;
      case TCG_TOKEN_STARTTRANSACTION:
          TcgToken->Type = TcgTokenTypeStartTransaction;
          break;
      case TCG_TOKEN_ENDTRANSACTION:
          TcgToken->Type = TcgTokenTypeEndTransaction;
          break;
      case TCG_TOKEN_EMPTY:
          TcgToken->Type = TcgTokenTypeEmptyAtom;
          break;
      default:
          DEBUG ((DEBUG_INFO, "WARNING: reserved token Type 0x%02X\n", Hdr));
          TcgToken->Type = TcgTokenTypeReserved;
          break;
    }
    ParseStruct->CurPtr++;
    TokenEnd = TcgToken->HdrStart + 1;
  }

  // increment curptr for next call
  ParseStruct->CurPtr = TokenEnd;
  return (TcgResultSuccess);
}

/**
  Get atom info.

  @param    TcgToken          Input token info.
  @param    HeaderLength      return the header length.
  @param    DataLength        return the data length.
  @param    ByteOrInt         return the atom Type.
  @param    SignOrCont        return the sign or count info.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetAtomInfo(
  const TCG_TOKEN      *TcgToken,
  UINT32               *HeaderLength,
  UINT32               *DataLength,
  UINT8                *ByteOrInt,
  UINT8                *SignOrCont
  )
{
  TCG_SIMPLE_TOKEN_TINY_ATOM* TinyAtom;
  TCG_SIMPLE_TOKEN_SHORT_ATOM* ShortAtom;
  TCG_SIMPLE_TOKEN_MEDIUM_ATOM* MediumAtom;
  TCG_SIMPLE_TOKEN_LONG_ATOM* LongAtom;

  NULL_CHECK(TcgToken);
  NULL_CHECK(HeaderLength);
  NULL_CHECK(DataLength);
  NULL_CHECK(ByteOrInt);
  NULL_CHECK(SignOrCont);

  switch (TcgToken->Type) {
    case TcgTokenTypeTinyAtom: {
      TinyAtom = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart;
      *ByteOrInt      = TCG_ATOM_TYPE_INTEGER;
      *SignOrCont     = TinyAtom->TinyAtomBits.Sign;
      *HeaderLength   = 0;
      *DataLength     = 0; // tiny atom must be handled as a special case - Header and Data in the same byte
      return TcgResultSuccess;
    }

    case TcgTokenTypeShortAtom: {
      ShortAtom = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)TcgToken->HdrStart;
      *ByteOrInt      = ShortAtom->ShortAtomBits.ByteOrInt;
      *SignOrCont     = ShortAtom->ShortAtomBits.SignOrCont;
      *HeaderLength   = sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM);
      *DataLength     = ShortAtom->ShortAtomBits.Length;
      return TcgResultSuccess;
    }

    case TcgTokenTypeMediumAtom: {
      MediumAtom = (TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)TcgToken->HdrStart;
      *ByteOrInt      = MediumAtom->MediumAtomBits.ByteOrInt;
      *SignOrCont     = MediumAtom->MediumAtomBits.SignOrCont;
      *HeaderLength   = sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM);
      *DataLength     = (MediumAtom->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) | MediumAtom->MediumAtomBits.LengthLow;
      return TcgResultSuccess;
    }

    case TcgTokenTypeLongAtom: {
      LongAtom = (TCG_SIMPLE_TOKEN_LONG_ATOM*)TcgToken->HdrStart;
      *ByteOrInt      = LongAtom->LongAtomBits.ByteOrInt;
      *SignOrCont     = LongAtom->LongAtomBits.SignOrCont;
      *HeaderLength   = sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM);
      *DataLength     = (LongAtom->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) |
                        (LongAtom->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT) |
                        LongAtom->LongAtomBits.LengthLow;
      return TcgResultSuccess;
    }

    default:
      DEBUG ((DEBUG_INFO, "Token Type is not simple atom (%d)\n", TcgToken->Type));
      return (TcgResultFailureInvalidType);
  }
}

/**
  Get token specified value.

  @param    TcgToken   Input token info.
  @param    Value      return the value.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetTokenUINT64(
  const TCG_TOKEN      *TcgToken,
  UINT64               *Value
  )
{
  UINT32 HdrLength;
  UINT32 DataLength;
  UINT8 ByteOrInt;
  UINT8 IsSigned;
  TCG_SIMPLE_TOKEN_TINY_ATOM* TmpTiny;
  const UINT8* Data;
  UINT32 Index;

  NULL_CHECK(TcgToken);
  NULL_CHECK(Value);

  Index = 0;
  *Value = 0;
  ERROR_CHECK(TcgGetAtomInfo(TcgToken, &HdrLength, &DataLength, &ByteOrInt, &IsSigned));

  if (ByteOrInt != TCG_ATOM_TYPE_INTEGER) {
    DEBUG ((DEBUG_INFO, "Invalid Type, expected integer not byte sequence\n"));
    return TcgResultFailureInvalidType;
  }

  if (IsSigned != 0) {
    DEBUG ((DEBUG_INFO, "Integer is signed, expected unsigned\n"));
    return TcgResultFailureInvalidType;
  }

  // special case for tiny atom
  // Header and Data are in one byte, so extract only the Data bitfield
  if (TcgToken->Type == TcgTokenTypeTinyAtom) {
    TmpTiny = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart;
    *Value = TmpTiny->TinyAtomBits.Data;
    return TcgResultSuccess;
  }

  if (DataLength > sizeof(UINT64)) {
    DEBUG ((DEBUG_INFO, "Length %d is greater than Size of UINT64\n", DataLength));
    return TcgResultFailureBufferTooSmall;
  }

  // read big-endian integer
  Data = TcgToken->HdrStart + HdrLength;
  for (Index = 0; Index < DataLength; Index++) {
    *Value = LShiftU64(*Value, 8) | Data[Index];
  }

  return TcgResultSuccess;
}

/**
  Get token byte sequence.

  @param    TcgToken   Input token info.
  @param    Length     Input the length info.

  @retval   Return the value data.

**/
UINT8*
EFIAPI
TcgGetTokenByteSequence(
  const TCG_TOKEN     *TcgToken,
  UINT32              *Length
  )
{
  UINT32 HdrLength;
  UINT8 ByteOrInt;
  UINT8 SignOrCont;

  if (TcgToken == NULL || Length == NULL) {
    return NULL;
  }

  *Length = 0;
  if (TcgGetAtomInfo(TcgToken, &HdrLength, Length, &ByteOrInt, &SignOrCont) != TcgResultSuccess) {
    DEBUG ((DEBUG_INFO, "Failed to get simple token info\n"));
    return NULL;
  }

  if (ByteOrInt != TCG_ATOM_TYPE_BYTE) {
    DEBUG ((DEBUG_INFO, "Invalid Type, expected byte sequence not integer\n"));
    return NULL;
  }

  return (TcgToken->HdrStart + HdrLength);
}

/**
  Get next specify value.

  @param    ParseStruct   Input parse structure.
  @param    Value         Return vlaue.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextUINT8(
  TCG_PARSE_STRUCT      *ParseStruct,
  UINT8                 *Value
  )
{
  UINT64 Value64;
  TCG_TOKEN Tok;

  NULL_CHECK(Value);

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));

  if (Value64 > MAX_UINT8) {
    return TcgResultFailure;
  }

  *Value = (UINT8)Value64;

  return TcgResultSuccess;
}

/**
  Get next specify value.

  @param    ParseStruct   Input parse structure.
  @param    Value         Return vlaue.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextUINT16(
  TCG_PARSE_STRUCT     *ParseStruct,
  UINT16               *Value
  )
{
  UINT64 Value64;
  TCG_TOKEN Tok;

  NULL_CHECK(Value);

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));

  if (Value64 > MAX_UINT16) {
    return TcgResultFailure;
  }

  *Value = (UINT16)Value64;

  return TcgResultSuccess;
}

/**
  Get next specify value.

  @param    ParseStruct   Input parse structure.
  @param    Value         Return vlaue.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextUINT32(
  TCG_PARSE_STRUCT          *ParseStruct,
  UINT32                    *Value
  )
{
  UINT64 Value64;
  TCG_TOKEN Tok;

  NULL_CHECK(Value);

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));

  if (Value64 > MAX_UINT32) {
    return TcgResultFailure;
  }

  *Value = (UINT32)Value64;

  return TcgResultSuccess;
}

/**
  Get next specify value.

  @param    ParseStruct   Input parse structure.
  @param    Value         Return vlaue.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextUINT64(
  TCG_PARSE_STRUCT           *ParseStruct,
  UINT64                     *Value
  )
{
  TCG_TOKEN Tok;
  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ERROR_CHECK(TcgGetTokenUINT64(&Tok, Value));
  return TcgResultSuccess;
}

/**
  Get next specify value.

  @param    ParseStruct   Input parse structure.
  @param    Value         Return vlaue.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextBOOLEAN(
  TCG_PARSE_STRUCT        *ParseStruct,
  BOOLEAN                 *Value
  )
{
  UINT64 Value64;
  TCG_TOKEN Tok;

  NULL_CHECK(Value);

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));

  if (Value64 > 1) {
    return TcgResultFailure;
  }

  *Value = (BOOLEAN)Value64;

  return TcgResultSuccess;
}

/**
  Get next tcg uid info.

  @param    ParseStruct    Input parse structure.
  @param    Uid            Get the uid info.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextTcgUid(
  TCG_PARSE_STRUCT         *ParseStruct,
  TCG_UID                  *Uid
  )
{
  TCG_TOKEN Tok;
  UINT32 Length;
  const UINT8* ByteSeq;

  NULL_CHECK(Uid);

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  ByteSeq = TcgGetTokenByteSequence(&Tok, &Length);

  if (Length != sizeof(TCG_UID)) {
    DEBUG ((DEBUG_INFO, "Token Length %u != TCG_UID Size %u\n", Length, (UINT32)sizeof(TCG_UID)));
    return TcgResultFailure;
  }

  ASSERT (ByteSeq != NULL);

  CopyMem(Uid, ByteSeq, sizeof(TCG_UID));

  return TcgResultSuccess;
}

/**
  Get next byte sequence.

  @param    ParseStruct     Input parse structure.
  @param    Data            return the data.
  @param    Length          return the length.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextByteSequence(
  TCG_PARSE_STRUCT      *ParseStruct,
  const VOID            **Data,
  UINT32                *Length
  )
{
  TCG_TOKEN Tok;
  const UINT8* Bs;

  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  Bs = TcgGetTokenByteSequence(&Tok, Length);

  if (Bs == NULL) {
    return TcgResultFailure;
  }
  *Data = Bs;
  return TcgResultSuccess;
}

/**
  Get next token Type.

  @param    ParseStruct    Input parse structure.
  @param    Type           Input the type need to check.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextTokenType(
  TCG_PARSE_STRUCT        *ParseStruct,
  TCG_TOKEN_TYPE          Type
  )
{
  TCG_TOKEN Tok;
  ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
  if (Tok.Type != Type) {
    DEBUG ((DEBUG_INFO, "expected Type %u, got Type %u\n", Type, Tok.Type));
    return TcgResultFailure;
  }
  return TcgResultSuccess;
}

/**
  Get next start list.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextStartList(
  TCG_PARSE_STRUCT          *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartList);
}

/**
  Get next end list.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextEndList(
  TCG_PARSE_STRUCT             *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndList);
}

/**
  Get next start name.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextStartName(
  TCG_PARSE_STRUCT              *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartName);
}

/**
  Get next end name.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextEndName(
  TCG_PARSE_STRUCT               *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndName);
}

/**
  Get next call.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextCall(
  TCG_PARSE_STRUCT                   *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeCall);
}

/**
  Get next end data.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextEndOfData(
  TCG_PARSE_STRUCT                    *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfData);
}

/**
  Get next end of session.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextEndOfSession(
  TCG_PARSE_STRUCT                      *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfSession);
}

/**
  Get next start transaction.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextStartTransaction(
  TCG_PARSE_STRUCT                        *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartTransaction);
}

/**
  Get next end transaction.

  @param    ParseStruct   Input parse structure.

  @retval   return the action result.

**/
TCG_RESULT
EFIAPI
TcgGetNextEndTransaction(
  TCG_PARSE_STRUCT                  *ParseStruct
  )
{
  return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndTransaction);
}
