/** @file

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


**/

#include "Edb.h"

/**

  Convert hex string to uint.

  @param  Str  -  The string

**/
UINTN
EFIAPI
Xtoi (
  CHAR16  *Str
  )
{
  UINTN   RetVal;
  CHAR16  TempChar;
  UINTN   MaxVal;

  if (Str == NULL) {
    ASSERT (Str != NULL);
    return 0;
  }

  MaxVal = (UINTN)-1 >> 4;
  //
  // skip preceeding white space
  //
  while (*Str == ' ') {
    Str += 1;
  }

  //
  // skip preceeding zeros
  //
  while (*Str == '0') {
    Str += 1;
  }

  //
  // skip preceeding white space
  //
  if (((*Str == 'x') || (*Str == 'X'))) {
    Str += 1;
  }

  //
  // convert hex digits
  //
  RetVal   = 0;
  TempChar = *(Str++);
  while (TempChar != '\0') {
    if ((TempChar >= 'a') && (TempChar <= 'f')) {
      TempChar -= 'a' - 'A';
    }

    if (((TempChar >= '0') && (TempChar <= '9')) || ((TempChar >= 'A') && (TempChar <= 'F'))) {
      if (RetVal > MaxVal) {
        return (UINTN)-1;
      }

      RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
    } else {
      break;
    }

    TempChar = *(Str++);
  }

  return RetVal;
}

/**

  Convert hex string to uint.

  @param  Str  -  The string

**/
UINT64
EFIAPI
LXtoi (
  CHAR16  *Str
  )
{
  UINT64  RetVal;
  CHAR16  TempChar;
  UINT64  MaxVal;

  ASSERT (Str != NULL);

  MaxVal = RShiftU64 ((UINT64)-1, 4);
  //
  // skip preceeding white space
  //
  while (*Str == ' ') {
    Str += 1;
  }

  //
  // skip preceeding zeros
  //
  while (*Str == '0') {
    Str += 1;
  }

  //
  // skip preceeding white space
  //
  if (((*Str == 'x') || (*Str == 'X'))) {
    Str += 1;
  }

  //
  // convert hex digits
  //
  RetVal   = 0;
  TempChar = *(Str++);
  while (TempChar != '\0') {
    if ((TempChar >= 'a') && (TempChar <= 'f')) {
      TempChar -= 'a' - 'A';
    }

    if (((TempChar >= '0') && (TempChar <= '9')) || ((TempChar >= 'A') && (TempChar <= 'F'))) {
      if (RetVal > MaxVal) {
        return (UINT64)-1;
      }

      RetVal = LShiftU64 (RetVal, 4);
      RetVal = RetVal + (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
    } else {
      break;
    }

    TempChar = *(Str++);
  }

  return RetVal;
}

/**

  Convert hex string to uint.

  @param Str  -  The string

**/
UINTN
EFIAPI
Atoi (
  CHAR16  *Str
  )
{
  UINTN   RetVal;
  CHAR16  TempChar;
  UINTN   MaxVal;
  UINTN   ResteVal;

  ASSERT (Str != NULL);

  MaxVal   = (UINTN)-1 / 10;
  ResteVal = (UINTN)-1 % 10;
  //
  // skip preceeding white space
  //
  while (*Str == ' ') {
    Str += 1;
  }

  //
  // convert digits
  //
  RetVal   = 0;
  TempChar = *(Str++);
  while (TempChar != '\0') {
    if ((TempChar >= '0') && (TempChar <= '9')) {
      if ((RetVal > MaxVal) || ((RetVal == MaxVal) && (TempChar - '0' > (INTN)ResteVal))) {
        return (UINTN)-1;
      }

      RetVal = (RetVal * 10) + TempChar - '0';
    } else {
      break;
    }

    TempChar = *(Str++);
  }

  return RetVal;
}

/**

  Convert hex string to uint.

  @param  Str  -  The string

**/
UINTN
EFIAPI
AsciiXtoi (
  CHAR8  *Str
  )
{
  UINTN  RetVal;
  CHAR8  TempChar;
  UINTN  MaxVal;

  ASSERT (Str != NULL);

  MaxVal = (UINTN)-1 >> 4;
  //
  // skip preceeding white space
  //
  while (*Str == ' ') {
    Str += 1;
  }

  //
  // skip preceeding zeros
  //
  while (*Str == '0') {
    Str += 1;
  }

  //
  // skip preceeding white space
  //
  if (((*Str == 'x') || (*Str == 'X'))) {
    Str += 1;
  }

  //
  // convert hex digits
  //
  RetVal   = 0;
  TempChar = *(Str++);
  while (TempChar != '\0') {
    if ((TempChar >= 'a') && (TempChar <= 'f')) {
      TempChar -= 'a' - 'A';
    }

    if (((TempChar >= '0') && (TempChar <= '9')) || ((TempChar >= 'A') && (TempChar <= 'F'))) {
      if (RetVal > MaxVal) {
        return (UINTN)-1;
      }

      RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
    } else {
      break;
    }

    TempChar = *(Str++);
  }

  return RetVal;
}

/**

  Convert hex string to uint.

  @param Str  -  The string

**/
UINTN
EFIAPI
AsciiAtoi (
  CHAR8  *Str
  )
{
  UINTN  RetVal;
  CHAR8  TempChar;
  UINTN  MaxVal;
  UINTN  ResteVal;

  ASSERT (Str != NULL);

  MaxVal   = (UINTN)-1 / 10;
  ResteVal = (UINTN)-1 % 10;
  //
  // skip preceeding white space
  //
  while (*Str == ' ') {
    Str += 1;
  }

  //
  // convert digits
  //
  RetVal   = 0;
  TempChar = *(Str++);
  while (TempChar != '\0') {
    if ((TempChar >= '0') && (TempChar <= '9')) {
      if ((RetVal > MaxVal) || ((RetVal == MaxVal) && (TempChar - '0' > (INTN)ResteVal))) {
        return (UINTN)-1;
      }

      RetVal = (RetVal * 10) + TempChar - '0';
    } else {
      break;
    }

    TempChar = *(Str++);
  }

  return RetVal;
}

/**
  Compare the Unicode and Ascii string pointed by String to the string pointed by String2.

  @param String - Unicode String to process

  @param String2 - Ascii string to process

  @return Return a positive integer if String is lexicall greater than String2; Zero if
  the two strings are identical; and a negative interger if String is lexically
  less than String2.

**/
INTN
EFIAPI
StrCmpUnicodeAndAscii (
  IN CHAR16  *String,
  IN CHAR8   *String2
  )
{
  while (*String != '\0') {
    if (*String != (CHAR16)*String2) {
      break;
    }

    String  += 1;
    String2 += 1;
  }

  return (*String - (CHAR16)*String2);
}

/**

  Compare the Unicode string pointed by String to the string pointed by String2.

  @param  String - Unicode String to process
  @param  String2 - Unicode string to process

  @return Return a positive integer if String is lexically greater than String2; Zero if
  the two strings are identical; and a negative integer if String is lexically
  less than String2.

**/
INTN
EFIAPI
StriCmp (
  IN CHAR16  *String,
  IN CHAR16  *String2
  )
{
  while ((*String != L'\0') &&
         (CharToUpper (*String) == CharToUpper (*String2)))
  {
    String++;
    String2++;
  }

  return CharToUpper (*String) - CharToUpper (*String2);
}

/**

  Compare the Unicode and Ascii string pointed by String to the string pointed by String2.

  @param  String - Unicode String to process
  @param  String2 - Ascii string to process

  @return Return a positive integer if String is lexically greater than String2; Zero if
  the two strings are identical; and a negative integer if String is lexically
  less than String2.

**/
INTN
EFIAPI
StriCmpUnicodeAndAscii (
  IN CHAR16  *String,
  IN CHAR8   *String2
  )
{
  while ((*String != L'\0') &&
         (CharToUpper (*String) == (CHAR16)AsciiCharToUpper (*String2)))
  {
    String++;
    String2++;
  }

  return CharToUpper (*String) - (CHAR16)AsciiCharToUpper (*String2);
}

/**

  Verify if the string is end with the sub string.

  @param  Str - The string where to search the sub string
  @param  SubStr - The substring.

**/
BOOLEAN
EFIAPI
StrEndWith (
  IN CHAR16  *Str,
  IN CHAR16  *SubStr
  )
{
  CHAR16  *Temp;

  if ((Str == NULL) || (SubStr == NULL) || (StrLen (Str) < StrLen (SubStr))) {
    return FALSE;
  }

  Temp = Str + StrLen (Str) - StrLen (SubStr);

  //
  // Compare
  //
  if (StriCmp (Temp, SubStr) == 0) {
    return TRUE;
  } else {
    return FALSE;
  }
}

/**
  Duplicate a string.

  @param  Src  The string to be duplicated.

**/
CHAR16 *
EFIAPI
StrDuplicate (
  IN CHAR16  *Src
  )
{
  CHAR16  *Dest;
  UINTN   Size;

  Size = (StrLen (Src) + 1) * sizeof (CHAR16);
  Dest = AllocateZeroPool (Size);
  if (Dest != NULL) {
    CopyMem (Dest, Src, Size);
  }

  return Dest;
}

CHAR16  *mLineBuffer  = NULL;
CHAR16  *mFieldBuffer = NULL;

/**

  Find the first substring.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
UINTN
EFIAPI
StrSpn (
  IN CHAR16  *String,
  IN CHAR16  *CharSet
  )
{
  UINTN   Count;
  CHAR16  *Str1;
  CHAR16  *Str2;

  Count = 0;

  for (Str1 = String; *Str1 != L'\0'; Str1++) {
    for (Str2 = CharSet; *Str2 != L'\0'; Str2++) {
      if (*Str1 == *Str2) {
        break;
      }
    }

    if (*Str2 == L'\0') {
      return Count;
    }

    Count++;
  }

  return Count;
}

/**

  Searches a string for the first occurrence of a character contained in a
  specified buffer.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrBrk (
  IN CHAR16  *String,
  IN CHAR16  *CharSet
  )
{
  CHAR16  *Str1;
  CHAR16  *Str2;

  for (Str1 = String; *Str1 != L'\0'; Str1++) {
    for (Str2 = CharSet; *Str2 != L'\0'; Str2++) {
      if (*Str1 == *Str2) {
        return (CHAR16 *)Str1;
      }
    }
  }

  return NULL;
}

/**

  Find the next token after one or more specified characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrTokenLine (
  IN CHAR16  *String OPTIONAL,
  IN CHAR16  *CharSet
  )
{
  CHAR16  *Begin;
  CHAR16  *End;

  Begin = (String == NULL) ? mLineBuffer : String;
  if (Begin == NULL) {
    return NULL;
  }

  Begin += StrSpn (Begin, CharSet);
  if (*Begin == L'\0') {
    mLineBuffer = NULL;
    return NULL;
  }

  End = StrBrk (Begin, CharSet);
  if ((End != NULL) && (*End != L'\0')) {
    *End = L'\0';
    End++;
  }

  mLineBuffer = End;
  return Begin;
}

/**

  Find the next token after one specificed characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrTokenField (
  IN CHAR16  *String OPTIONAL,
  IN CHAR16  *CharSet
  )
{
  CHAR16  *Begin;
  CHAR16  *End;

  Begin = (String == NULL) ? mFieldBuffer : String;
  if (Begin == NULL) {
    return NULL;
  }

  if (*Begin == L'\0') {
    mFieldBuffer = NULL;
    return NULL;
  }

  End = StrBrk (Begin, CharSet);
  if ((End != NULL) && (*End != L'\0')) {
    *End = L'\0';
    End++;
  }

  mFieldBuffer = End;
  return Begin;
}

/**

  Find the next token after one or more specified characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrGetNewTokenLine (
  IN CHAR16  *String,
  IN CHAR16  *CharSet
  )
{
  return StrTokenLine (String, CharSet);
}

/**

  Find the next token after one or more specified characters.

  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrGetNextTokenLine (
  IN CHAR16  *CharSet
  )
{
  return StrTokenLine (NULL, CharSet);
}

/**

  Find the next token after one specificed characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrGetNewTokenField (
  IN CHAR16  *String,
  IN CHAR16  *CharSet
  )
{
  return StrTokenField (String, CharSet);
}

/**

  Find the next token after one specificed characters.

  @param  CharSet   Point to the string to be found.

**/
CHAR16 *
EFIAPI
StrGetNextTokenField (
  IN CHAR16  *CharSet
  )
{
  return StrTokenField (NULL, CharSet);
}

/**

  Patch a character to the end of a string.

  @param  Buffer   The string to be patched.
  @param  Patch    The patch character.

**/
VOID
EFIAPI
PatchForStrTokenAfter (
  IN CHAR16  *Buffer,
  IN CHAR16  Patch
  )
{
  CHAR16  *Str;

  if (Buffer == NULL) {
    return;
  }

  Str = Buffer;
  while (*Str != 0) {
    Str++;
  }

  *Str = Patch;

  while (*(Str++) != '\0') {
    if (*Str == 0) {
      *Str = Patch;
    } else {
      break;
    }
  }

  return;
}

/**
  Patch a character at the beginning of a string.

  @param  Buffer   The string to be patched.
  @param  Patch    The patch character.

**/
VOID
EFIAPI
PatchForStrTokenBefore (
  IN CHAR16  *Buffer,
  IN CHAR16  Patch
  )
{
  CHAR16  *Str;

  if (Buffer == NULL) {
    return;
  }

  Str = Buffer;
  while (*(Str--) != '\0') {
    if ((*Str == 0) || (*Str == Patch)) {
      *Str = Patch;
    } else {
      break;
    }
  }

  return;
}

CHAR8  *mAsciiLineBuffer  = NULL;
CHAR8  *mAsciiFieldBuffer = NULL;

/**

  Find the first substring.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
UINTN
EFIAPI
AsciiStrSpn (
  IN CHAR8  *String,
  IN CHAR8  *CharSet
  )
{
  UINTN  Count;
  CHAR8  *Str1;
  CHAR8  *Str2;

  Count = 0;

  for (Str1 = String; *Str1 != '\0'; Str1++) {
    for (Str2 = CharSet; *Str2 != '\0'; Str2++) {
      if (*Str1 == *Str2) {
        break;
      }
    }

    if (*Str2 == '\0') {
      return Count;
    }

    Count++;
  }

  return Count;
}

/**
  Searches a string for the first occurrence of a character contained in a
  specified buffer.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrBrk (
  IN CHAR8  *String,
  IN CHAR8  *CharSet
  )
{
  CHAR8  *Str1;
  CHAR8  *Str2;

  for (Str1 = String; *Str1 != '\0'; Str1++) {
    for (Str2 = CharSet; *Str2 != '\0'; Str2++) {
      if (*Str1 == *Str2) {
        return (CHAR8 *)Str1;
      }
    }
  }

  return NULL;
}

/**

  Find the next token after one or more specified characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrTokenLine (
  IN CHAR8  *String OPTIONAL,
  IN CHAR8  *CharSet
  )
{
  CHAR8  *Begin;
  CHAR8  *End;

  Begin = (String == NULL) ? mAsciiLineBuffer : String;
  if (Begin == NULL) {
    return NULL;
  }

  Begin += AsciiStrSpn (Begin, CharSet);
  if (*Begin == '\0') {
    mAsciiLineBuffer = NULL;
    return NULL;
  }

  End = AsciiStrBrk (Begin, CharSet);
  if ((End != NULL) && (*End != '\0')) {
    *End = '\0';
    End++;
  }

  mAsciiLineBuffer = End;
  return Begin;
}

/**

  Find the next token after one specificed characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrTokenField (
  IN CHAR8  *String OPTIONAL,
  IN CHAR8  *CharSet
  )
{
  CHAR8  *Begin;
  CHAR8  *End;

  Begin = (String == NULL) ? mAsciiFieldBuffer : String;
  if (Begin == NULL) {
    return NULL;
  }

  if (*Begin == '\0') {
    mAsciiFieldBuffer = NULL;
    return NULL;
  }

  End = AsciiStrBrk (Begin, CharSet);
  if ((End != NULL) && (*End != '\0')) {
    *End = '\0';
    End++;
  }

  mAsciiFieldBuffer = End;
  return Begin;
}

/**

  Find the next token after one or more specified characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrGetNewTokenLine (
  IN CHAR8  *String,
  IN CHAR8  *CharSet
  )
{
  return AsciiStrTokenLine (String, CharSet);
}

/**

  Find the next token after one or more specified characters.

  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrGetNextTokenLine (
  IN CHAR8  *CharSet
  )
{
  return AsciiStrTokenLine (NULL, CharSet);
}

/**

  Find the next token after one specificed characters.

  @param  String    Point to the string where to find the substring.
  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrGetNewTokenField (
  IN CHAR8  *String,
  IN CHAR8  *CharSet
  )
{
  return AsciiStrTokenField (String, CharSet);
}

/**

  Find the next token after one specificed characters.

  @param  CharSet   Point to the string to be found.

**/
CHAR8 *
EFIAPI
AsciiStrGetNextTokenField (
  IN CHAR8  *CharSet
  )
{
  return AsciiStrTokenField (NULL, CharSet);
}

/**

  Patch a character to the end of a string.

  @param  Buffer   The string to be patched.
  @param  Patch    The patch character.

**/
VOID
EFIAPI
PatchForAsciiStrTokenAfter (
  IN CHAR8  *Buffer,
  IN CHAR8  Patch
  )
{
  CHAR8  *Str;

  if (Buffer == NULL) {
    return;
  }

  Str = Buffer;
  while (*Str != 0) {
    Str++;
  }

  *Str = Patch;

  while (*(Str++) != '\0') {
    if (*Str == 0) {
      *Str = Patch;
    } else {
      break;
    }
  }

  return;
}

/**
  Patch a character at the beginning of a string.

  @param  Buffer   The string to be patched.
  @param  Patch    The patch character.

**/
VOID
EFIAPI
PatchForAsciiStrTokenBefore (
  IN CHAR8  *Buffer,
  IN CHAR8  Patch
  )
{
  CHAR8  *Str;

  if (Buffer == NULL) {
    return;
  }

  Str = Buffer;
  while (*(Str--) != '\0') {
    if ((*Str == 0) || (*Str == Patch)) {
      *Str = Patch;
    } else {
      break;
    }
  }

  return;
}
