text: /** @file
    ACPI Sdt Protocol Driver
  
    Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include "AcpiTable.h"
  
  /**
    Check if it is AML Root name
  
    @param[in]    Buffer AML path.
  
    @retval       TRUE  AML path is root.
    @retval       FALSE AML path is not root.
  **/
  BOOLEAN
  AmlIsRootPath (
    IN UINT8              *Buffer
    )
  {
    if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == 0)) {
      return TRUE;
    } else {
      return FALSE;
    }
  }
  
  /**
    Check if it is AML LeadName.
  
    @param[in]    Ch   Char.
  
    @retval       TRUE  Char is AML LeadName.
    @retval       FALSE Char is not AML LeadName.
  **/
  BOOLEAN
  AmlIsLeadName (
    IN CHAR8 Ch
    )
  {
    if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z')) {
      return TRUE;
    } else {
      return FALSE;
    }
  }
  
  /**
    Check if it is AML Name.
  
    @param[in]    Ch   Char.
  
    @retval       TRUE  Char is AML Name.
    @retval       FALSE Char is not AML Name.
  **/
  BOOLEAN
  AmlIsName (
    IN CHAR8 Ch
    )
  {
    if (AmlIsLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
      return TRUE;
    } else {
      return FALSE;
    }
  }
  
  /**
    Return is buffer is AML NameSeg.
  
    @param[in]    Buffer     AML NameSement.
  
    @retval       TRUE       It is AML NameSegment.
    @retval       FALSE      It is not AML NameSegment.
  **/
  BOOLEAN
  AmlIsNameSeg (
    IN  UINT8              *Buffer
    )
  {
    UINTN  Index;
    if (!AmlIsLeadName (Buffer[0])) {
      return FALSE;
    }
    for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
      if (!AmlIsName (Buffer[Index])) {
        return FALSE;
      }
    }
    return TRUE;
  }
  
  /**
    Get AML NameString size.
  
    @param[in]    Buffer     AML NameString.
    @param[out]   BufferSize AML NameString size
  
    @retval       EFI_SUCCESS           Success.
    @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
  **/
  EFI_STATUS
  AmlGetNameStringSize (
    IN  UINT8              *Buffer,
    OUT UINTN              *BufferSize
    )
  {
    UINTN                 SegCount;
    UINTN                 Length;
    UINTN                 Index;
  
    Length = 0;
  
    //
    // Parse root or parent prefix
    //
    if (*Buffer == AML_ROOT_CHAR) {
      Buffer ++;
      Length ++;
    } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
      do {
        Buffer ++;
        Length ++;
      } while (*Buffer == AML_PARENT_PREFIX_CHAR);
    }
  
    //
    // Parse name segment
    //
    if (*Buffer == AML_DUAL_NAME_PREFIX) {
      Buffer ++;
      Length ++;
      SegCount = 2;
    } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
      Buffer ++;
      Length ++;
      SegCount = *Buffer;
      Buffer ++;
      Length ++;
    } else if (*Buffer == 0) {
      //
      // NULL Name, only for Root
      //
      SegCount = 0;
      Buffer --;
      if ((Length == 1) && (*Buffer == AML_ROOT_CHAR)) {
        *BufferSize = 2;
        return EFI_SUCCESS;
      } else {
        return EFI_INVALID_PARAMETER;
      }
    } else {
      //
      // NameSeg
      //
      SegCount = 1;
    }
  
    Index = 0;
    do {
      if (!AmlIsNameSeg (Buffer)) {
        return EFI_INVALID_PARAMETER;
      }
      Buffer += AML_NAME_SEG_SIZE;
      Length += AML_NAME_SEG_SIZE;
      Index ++;
    } while (Index < SegCount);
  
    *BufferSize = Length;
    return EFI_SUCCESS;
  }
  
  /**
    Check if it is ASL LeadName.
  
    @param[in]    Ch   Char.
  
    @retval       TRUE  Char is ASL LeadName.
    @retval       FALSE Char is not ASL LeadName.
  **/
  BOOLEAN
  AmlIsAslLeadName (
    IN CHAR8 Ch
    )
  {
    if (AmlIsLeadName (Ch) || (Ch >= 'a' && Ch <= 'z')) {
      return TRUE;
    } else {
      return FALSE;
    }
  }
  
  /**
    Check if it is ASL Name.
  
    @param[in]    Ch   Char.
  
    @retval       TRUE  Char is ASL Name.
    @retval       FALSE Char is not ASL Name.
  **/
  BOOLEAN
  AmlIsAslName (
    IN CHAR8 Ch
    )
  {
    if (AmlIsAslLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
      return TRUE;
    } else {
      return FALSE;
    }
  }
  
  /**
    Get ASL NameString size.
  
    @param[in]    Buffer   ASL NameString.
  
    @return       ASL NameString size.
  **/
  UINTN
  AmlGetAslNameSegLength (
    IN UINT8 *Buffer
    )
  {
    UINTN Length;
    UINTN Index;
  
    if (*Buffer == 0) {
      return 0;
    }
  
    Length = 0;
    //
    // 1st
    //
    if (AmlIsAslLeadName (*Buffer)) {
      Length ++;
      Buffer ++;
    }
    if ((*Buffer == 0) || (*Buffer == '.')) {
      return Length;
    }
    //
    // 2, 3, 4 name char
    //
    for (Index = 0; Index < 3; Index++) {
      if (AmlIsAslName (*Buffer)) {
        Length ++;
        Buffer ++;
      }
      if ((*Buffer == 0) || (*Buffer == '.')) {
        return Length;
      }
    }
  
    //
    // Invalid ASL name
    //
    return 0;
  }
  
  /**
    Get ASL NameString size.
  
    @param[in]    Buffer   ASL NameString.
    @param[out]   Root     On return, points to Root char number.
    @param[out]   Parent   On return, points to Parent char number.
    @param[out]   SegCount On return, points to Segment count.
  
    @return       ASL NameString size.
  **/
  UINTN
  AmlGetAslNameStringSize (
    IN UINT8              *Buffer,
    OUT UINTN             *Root,
    OUT UINTN             *Parent,
    OUT UINTN             *SegCount
    )
  {
    UINTN NameLength;
    UINTN TotalLength;
  
    *Root   = 0;
    *Parent = 0;
    *SegCount = 0;
    TotalLength = 0;
    NameLength = 0;
    if (*Buffer == AML_ROOT_CHAR) {
      *Root = 1;
      Buffer ++;
    } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
      do {
        Buffer ++;
        (*Parent) ++;
      } while (*Buffer == AML_PARENT_PREFIX_CHAR);
    }
  
    //
    // Now parse name
    //
    while (*Buffer != 0) {
      NameLength = AmlGetAslNameSegLength (Buffer);
      if ((NameLength == 0) || (NameLength > AML_NAME_SEG_SIZE)) {
        return 0;
      }
      (*SegCount) ++;
      Buffer += NameLength;
      if (*Buffer == 0) {
        break;
      }
      Buffer ++;
    }
  
    //
    // Check SegCoount
    //
    if (*SegCount > 0xFF) {
      return 0;
    }
  
    //
    // Calculate total length
    //
    TotalLength = *Root + *Parent + (*SegCount) * AML_NAME_SEG_SIZE;
    if (*SegCount > 2) {
      TotalLength += 2;
    } else if (*SegCount == 2) {
      TotalLength += 1;
    }
  
    //
    // Add NULL char
    //
    TotalLength ++;
  
    return TotalLength;
  }
  
  /**
    Copy mem, and cast all the char in dest to be upper case.
  
    @param[in]    DstBuffer   Destination buffer.
    @param[in]    SrcBuffer   Source buffer.
    @param[in]    Length      Buffer length.
  **/
  VOID
  AmlUpperCaseCopyMem(
    IN UINT8 *DstBuffer,
    IN UINT8 *SrcBuffer,
    IN UINTN Length
    )
  {
    UINTN Index;
  
    for (Index = 0; Index < Length; Index++) {
      if (SrcBuffer[Index] >= 'a' && SrcBuffer[Index] <= 'z') {
        DstBuffer[Index] = (UINT8)(SrcBuffer[Index] - 'a' + 'A');
      } else {
        DstBuffer[Index] = SrcBuffer[Index];
      }
    }
  }
  
  /**
    Return AML name according to ASL name.
    The caller need free the AmlName returned.
  
    @param[in]    AslPath     ASL name.
  
    @return AmlName
  **/
  UINT8 *
  AmlNameFromAslName (
    IN UINT8 *AslPath
    )
  {
    UINTN Root;
    UINTN Parent;
    UINTN SegCount;
    UINTN TotalLength;
    UINTN NameLength;
    UINT8 *Buffer;
    UINT8 *AmlPath;
    UINT8 *AmlBuffer;
  
    TotalLength = AmlGetAslNameStringSize (AslPath, &Root, &Parent, &SegCount);
    if (TotalLength == 0) {
      return NULL;
    }
  
    AmlPath = AllocatePool (TotalLength);
    ASSERT (AmlPath != NULL);
  
    AmlBuffer = AmlPath;
    Buffer = AslPath;
  
    //
    // Handle Root and Parent
    //
    if (Root == 1) {
      *AmlBuffer = AML_ROOT_CHAR;
      AmlBuffer ++;
      Buffer ++;
    } else if (Parent > 0) {
      SetMem(AmlBuffer, Parent, AML_PARENT_PREFIX_CHAR);
      AmlBuffer += Parent;
      Buffer += Parent;
    }
  
    //
    // Handle SegCount
    //
    if (SegCount > 2) {
      *AmlBuffer = AML_MULTI_NAME_PREFIX;
      AmlBuffer ++;
      *AmlBuffer = (UINT8)SegCount;
      AmlBuffer ++;
    } else if (SegCount == 2) {
      *AmlBuffer = AML_DUAL_NAME_PREFIX;
      AmlBuffer ++;
    }
  
    //
    // Now to name
    //
    while (*Buffer != 0) {
      NameLength = AmlGetAslNameSegLength (Buffer);
      ASSERT ((NameLength != 0) && (NameLength <= AML_NAME_SEG_SIZE));
      AmlUpperCaseCopyMem(AmlBuffer, Buffer, NameLength);
      SetMem(AmlBuffer + NameLength, AML_NAME_SEG_SIZE - NameLength, AML_NAME_CHAR__);
      Buffer += NameLength;
      AmlBuffer += AML_NAME_SEG_SIZE;
      if (*Buffer == 0) {
        break;
      }
      Buffer ++;
    }
  
    //
    // Add NULL
    //
    AmlPath[TotalLength - 1] = 0;
  
    return AmlPath;
  }
  
  /**
    Print AML NameSeg.
  
    @param[in] Buffer AML NameSeg.
  **/
  VOID
  AmlPrintNameSeg (
    IN UINT8              *Buffer
    )
  {
    DEBUG ((EFI_D_ERROR, "%c", Buffer[0]));
    if ((Buffer[1] == '_') && (Buffer[2] == '_') && (Buffer[3] == '_')) {
      return ;
    }
    DEBUG ((EFI_D_ERROR, "%c", Buffer[1]));
    if ((Buffer[2] == '_') && (Buffer[3] == '_')) {
      return ;
    }
    DEBUG ((EFI_D_ERROR, "%c", Buffer[2]));
    if (Buffer[3] == '_') {
      return ;
    }
    DEBUG ((EFI_D_ERROR, "%c", Buffer[3]));
    return ;
  }
  
  /**
    Print AML NameString.
  
    @param[in] Buffer AML NameString.
  **/
  VOID
  AmlPrintNameString (
    IN UINT8              *Buffer
    )
  {
    UINT8                 SegCount;
    UINT8                 Index;
  
    if (*Buffer == AML_ROOT_CHAR) {
      //
      // RootChar
      //
      Buffer ++;
      DEBUG ((EFI_D_ERROR, "\\"));
    } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
      //
      // ParentPrefixChar
      //
      do {
        Buffer ++;
        DEBUG ((EFI_D_ERROR, "^"));
      } while (*Buffer == AML_PARENT_PREFIX_CHAR);
    }
  
    if (*Buffer == AML_DUAL_NAME_PREFIX) {
      //
      // DualName
      //
      Buffer ++;
      SegCount = 2;
    } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
      //
      // MultiName
      //
      Buffer ++;
      SegCount = *Buffer;
      Buffer ++;
    } else if (*Buffer == 0) {
      //
      // NULL Name
      //
      return ;
    } else {
      //
      // NameSeg
      //
      SegCount = 1;
    }
  
    AmlPrintNameSeg (Buffer);
    Buffer += AML_NAME_SEG_SIZE;
    for (Index = 0; Index < SegCount - 1; Index++) {
      DEBUG ((EFI_D_ERROR, "."));
      AmlPrintNameSeg (Buffer);
      Buffer += AML_NAME_SEG_SIZE;
    }
  
    return ;
  }
  