/** @file
  Helper functions for mangling file names in UDF/ECMA-167 file systems.

  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include "Udf.h"

/**
  Trim the leading and trailing spaces for a give Unicode string.

  @param[in]  String              The Unicode string to trim.

  @return  A pointer to the trimmed string.

**/
CHAR16 *
TrimString (
  IN CHAR16  *String
  )
{
  CHAR16  *TempString;

  for ( ; *String != L'\0' && *String == L' '; String++) {
  }

  TempString = String + StrLen (String) - 1;
  while ((TempString >= String) && (*TempString == L' ')) {
    TempString--;
  }

  *(TempString + 1) = L'\0';

  return String;
}

/**
  Replace the content of a Unicode string with the content of another Unicode
  string.

  @param[in]  Destination         A pointer to a Unicode string.
  @param[in]  Source              A pointer to a Unicode string.

**/
VOID
ReplaceLeft (
  IN CHAR16        *Destination,
  IN CONST CHAR16  *Source
  )
{
  CONST CHAR16  *EndString;

  EndString = Source + StrLen (Source);
  while (Source <= EndString) {
    *Destination++ = *Source++;
  }
}

/**
  Remove one or more consecutive backslashes starting from the second character
  of a given Unicode string.

  @param[in]  String              A pointer to a Unicode string.

  @return  A pointer to the modified string.

**/
CHAR16 *
ExcludeTrailingBackslashes (
  IN CHAR16  *String
  )
{
  CHAR16  *TempString;

  switch (*(String + 1)) {
    case L'\\':
      break;
    case L'\0':
    default:
      String++;
      goto Exit;
  }

  TempString = String;
  while (*TempString != L'\0' && *TempString == L'\\') {
    TempString++;
  }

  if (TempString - 1 > String) {
    ReplaceLeft (String + 1, TempString);
  }

  String++;

Exit:
  return String;
}

/**
  Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".

  @param[in] FileName Filename.

  @retval The mangled Filename.

**/
CHAR16 *
MangleFileName (
  IN CHAR16  *FileName
  )
{
  CHAR16  *FileNameSavedPointer;
  CHAR16  *TempFileName;
  UINTN   BackslashesNo;

  if ((FileName == NULL) || (*FileName == L'\0')) {
    FileName = NULL;
    goto Exit;
  }

  FileName = TrimString (FileName);
  if (*FileName == L'\0') {
    goto Exit;
  }

  if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
    FileName[StrLen (FileName) - 1] = L'\0';
  }

  FileNameSavedPointer = FileName;

  if (FileName[0] == L'.') {
    if (FileName[1] == L'.') {
      if (FileName[2] == L'\0') {
        goto Exit;
      } else {
        FileName += 2;
      }
    } else if (FileName[1] == L'\0') {
      goto Exit;
    }
  }

  while (*FileName != L'\0') {
    if (*FileName == L'\\') {
      FileName = ExcludeTrailingBackslashes (FileName);
    } else if (*FileName == L'.') {
      switch (*(FileName + 1)) {
        case L'\0':
          *FileName = L'\0';
          break;
        case L'\\':
          TempFileName = FileName + 1;
          TempFileName = ExcludeTrailingBackslashes (TempFileName);
          ReplaceLeft (FileName, TempFileName);
          break;
        case '.':
          if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||
                                             (*(FileName + 2) != L'\0')))
          {
            FileName++;
            continue;
          }

          BackslashesNo = 0;
          TempFileName  = FileName - 1;
          while (TempFileName >= FileNameSavedPointer) {
            if (*TempFileName == L'\\') {
              if (++BackslashesNo == 2) {
                break;
              }
            }

            TempFileName--;
          }

          TempFileName++;

          if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {
            FileName += 2;
          } else {
            if (*(FileName + 2) != L'\0') {
              ReplaceLeft (TempFileName, FileName + 3);
              if (*(TempFileName - 1) == L'\\') {
                FileName = TempFileName;
                ExcludeTrailingBackslashes (TempFileName - 1);
                TempFileName = FileName;
              }
            } else {
              *TempFileName = L'\0';
            }

            FileName = TempFileName;
          }

          break;
        default:
          FileName++;
      }
    } else {
      FileName++;
    }
  }

  FileName = FileNameSavedPointer;
  if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
    FileName[StrLen (FileName) - 1] = L'\0';
  }

Exit:
  return FileName;
}
