text: /*
  ** utils.c - Miscellaneous utility routines used in compression / expansion
  **           modules.  Theoretically these functions are DBCS-enabled.
  **
  ** Author:  DavidDi
  */
  
  
  // Headers
  ///////////
  
  #ifndef LZA_DLL
     #include <ctype.h>
     #include <string.h>
  #endif
  
  #include "lz_common.h"
  
  
  /*
  ** char ARG_PTR *ExtractFileName(char ARG_PTR pszPathName);
  **
  ** Find the file name in a fully specified path name.
  **
  ** Arguments:  pszPathName - path string from which to extract file name
  **
  ** Returns:    char ARG_PTR * - Pointer to file name in pszPathName.
  **
  ** Globals:    none
  */
  LPWSTR
  ExtractFileNameW(
      LPWSTR pszPathName)
  {
     LPWSTR pszLastComponent, psz;
  
     for (pszLastComponent = psz = pszPathName; *psz != L'\0'; psz++)
     {
        if (*psz == L'\\' || *psz == L':')
           pszLastComponent = psz + 1;
     }
  
     return(pszLastComponent);
  }
  
  
  CHAR ARG_PTR *ExtractFileName(CHAR ARG_PTR *pszPathName)
  {
     CHAR ARG_PTR *pszLastComponent, ARG_PTR *psz;
  
     for (pszLastComponent = psz = pszPathName; *psz != '\0'; psz = CharNext(psz))
     {
        if (! IsDBCSLeadByte(*psz) && (ISSLASH(*psz) || *psz == COLON))
           pszLastComponent = CharNext(psz);
     }
  
     return(pszLastComponent);
  }
  
  
  /*
  ** char ARG_PTR *ExtractExtension(char ARG_PTR *pszFileName);
  **
  ** Find the extension of a file name.
  **
  ** Arguments:  pszFileName - file name to examine
  **
  ** Returns:    char ARG_PTR * - Pointer to file name extension if one exists.
  **                              NULL if the file name doesn't include an
  **                              extension.
  **
  ** Globals:    none
  */
  LPWSTR
  ExtractExtensionW(
      LPWSTR pszFileName)
  {
     WCHAR *psz;
  
     // Make sure we have an isolated file name.
     psz = ExtractFileNameW(pszFileName);
  
     while (*psz != L'\0' && *psz != L'.')
        psz++;
  
     if (*psz == L'.')
        return(psz + 1);
     else
        return(NULL);
  }
  
  
  CHAR ARG_PTR *ExtractExtension(CHAR ARG_PTR *pszFileName)
  {
     CHAR ARG_PTR *psz;
  
     // Make sure we have an isolated file name.
     psz = ExtractFileName(pszFileName);
  
     while (IsDBCSLeadByte(*psz) || (*psz != '\0' && *psz != PERIOD))
        psz = CharNext(psz);
  
     if (*psz == PERIOD)
        return(psz + 1);
     else
        return(NULL);
  }
  
  
  /*
  ** void MakePathName(char ARG_PTR *pszPath, char ARG_PTR *pszFileName);
  **
  ** Append a filename to a path string.
  **
  ** Arguments:  pszPath     - path string to which pszFileName will be appended
  **             pszFileName - file name to append
  **
  ** Returns:    void
  **
  ** Globals:    none
  */
  VOID MakePathName(CHAR ARG_PTR *pszPath, CHAR ARG_PTR *pszFileName)
  {
     CHAR chLastPathChar;
  
     // Make sure we have an isolated file name.
     pszFileName = ExtractFileName(pszFileName);
  
     // Dont append to a NULL string or a single ".".
     if (*pszFileName != '\0' &&
         ! (! IsDBCSLeadByte(pszFileName[0]) && pszFileName[0] == PERIOD &&
            ! IsDBCSLeadByte(pszFileName[1]) && pszFileName[1] == '\0'))
     {
        chLastPathChar = *CharPrev(pszPath, pszPath + STRLEN(pszPath));
  
        //NTRAID:MSKKBUG #3411    Nov.09.93   v-hajimy
        if (! ISSLASH(chLastPathChar) && chLastPathChar != COLON)
           STRCAT(pszPath, SEP_STR);
  
        STRCAT(pszPath, pszFileName);
     }
  }
  
  
  /*
  ** char MakeCompressedName(char ARG_PTR *pszFileName);
  **
  ** Make a file name into the corresponding compressed file name.
  **
  ** Arguments:  pszOriginalName - file name to convert to compressed file name
  **
  ** Returns:    char - Uncompressed file name extension character that was
  **                    replaced.  '\0' if no character needed to be replaced.
  **
  ** Globals:    none
  **
  ** N.b., assumes pszFileName's buffer is long enough to hold an extra two
  ** characters ("._").
  **
  ** For DBCS filenames, we know we can have at most one DBCS character in the
  ** extension.  So instead of just blindly replacing the last character of a
  ** three-byte extension with an underscore, we replace the last single-byte
  ** character with an underscore.
  */
  
  #define chEXTENSION_CHARW      L'_'
  #define pszEXTENSION_STRW      L"_"
  #define pszNULL_EXTENSIONW     L"._"
  
  WCHAR
  MakeCompressedNameW(
      LPWSTR pszFileName)
  {
     WCHAR chReplaced = L'\0';
     WCHAR ARG_PTR *pszExt;
  
     if ((pszExt = ExtractExtensionW(pszFileName)) != NULL)
     {
        if (lstrlenW(pszExt) >= 3)
        {
           chReplaced = pszExt[lstrlenW(pszExt) - 1];
           pszExt[lstrlenW(pszExt) - 1] = chEXTENSION_CHARW;
        }
        else
           lstrcatW(pszExt, pszEXTENSION_STRW);
     }
     else
        lstrcatW(pszFileName, pszNULL_EXTENSIONW);
  
     return(chReplaced);
  }
  
  
  
  CHAR MakeCompressedName(CHAR ARG_PTR *pszFileName)
  {
      CHAR chReplaced = '\0';
      ULONG NameLength = STRLEN( pszFileName );
      ULONG DotIndex   = NameLength;
  
      while (( DotIndex > 0 ) && ( pszFileName[ --DotIndex ] != '.' )) {
          if (( pszFileName[ DotIndex ] == '\\' ) ||
              ( pszFileName[ DotIndex ] == ':' )) {   // end of filename part of path
              DotIndex = 0;                       // name has no extension
              break;
              }
          }
  
      if ( DotIndex > 0 ) {                       // name has an extension
          if (( NameLength - DotIndex ) <= 3 ) {  // extension less than 3 chars
              pszFileName[ NameLength++ ] = '_';  // append '_' to extension
              pszFileName[ NameLength ] = 0;      // terminate
              }
          else {                                  // extension more than 3 chars
              chReplaced = pszFileName[ NameLength - 1 ]; // return original
              pszFileName[ NameLength - 1 ] = '_';   // replace last char with '_'
              }
          }
      else {                                      // name has no extension
          pszFileName[ NameLength++ ] = '.';      // append '.'
          pszFileName[ NameLength++ ] = '_';      // append '_'
          pszFileName[ NameLength ] = 0;          // terminate
          }
  
      return(chReplaced);
  }
  
  
  /*
  ** void MakeExpandedName(char ARG_PTR *pszFileName, BYTE byteExtensionChar);
  **
  ** Create expanded output file name.
  **
  ** Arguments:  pszFileName       - expanded file name to change
  **             byteExtensionChar - expanded file name extension character to
  **                                 use
  **
  ** Returns:    void
  **
  ** Globals:    none
  */
  VOID MakeExpandedName(CHAR ARG_PTR *pszFileName, BYTE byteExtensionChar)
  {
     CHAR ARG_PTR *pszExt;
     INT nExtLen;
  
     // Is there any extension to change?
     if ((pszExt = ExtractExtension(pszFileName)) != NULL)
     {
        // Determine case of extension character.  Match case of first non-DB
        // character in name.  If all characters are DB, leave case alone.
  
        if (ISLETTER(byteExtensionChar))
        {
           // Find first alphabetic character in name.
           while (*pszFileName)
           {
              if (IsDBCSLeadByte(*pszFileName))
                 pszFileName += 2;
              else if (ISLETTER(*pszFileName))
                 break;
              else
                 pszFileName++;
           }
  
           // Here pszFileName points to the first alphabetic character in the
           // name or to the null terminator.  Set the case of the extension
           // character.
  
           if (ISLOWER(*pszFileName))
              byteExtensionChar = (BYTE)TOLOWERCASE(byteExtensionChar);
           else if (ISUPPER(*pszFileName))
              byteExtensionChar = (BYTE)TOUPPERCASE(byteExtensionChar);
        }
  
        if ((nExtLen = STRLEN(pszExt)) > 0)
        {
           // Find the underscore character to replace, if it exists.
  
           // Assert: The underscore is either the last character in the
           // extension, or it is the first character in the extension followed
           // by a double-byte character.
  
           if (! IsDBCSLeadByte(*pszExt) && *pszExt == chEXTENSION_CHAR &&
               IsDBCSLeadByte(pszExt[1]))
              // Here the underscore is followed by a double-byte character.
              *pszExt = byteExtensionChar;
           else
           {
              // Here the underscore is the last character in the extension, if
              // there is an underscore at all.
              CHAR ARG_PTR *psz, *pszPrevious;
  
              for (psz = pszPrevious = pszExt; *psz != '\0'; psz = CharNext(psz))
                 pszPrevious = psz;
  
              if (! IsDBCSLeadByte(*pszPrevious) &&
                  *pszPrevious == chEXTENSION_CHAR)
                 *pszPrevious = byteExtensionChar;
           }
        }
  
        // Get rid of trailing dot with no extension.
        if (*pszExt == '\0' && *(pszExt - 1) == PERIOD)
           *(pszExt - 1) = '\0';
     }
  }
  
  
  /*
  ** int CopyDateTimeStamp(INT_PTR doshFrom, INT_PTR doshTo);
  **
  ** Copy date and time stamp from one file to another.
  **
  ** Arguments:  doshFrom - date and time stamp source DOS file handle
  **             doshTo   - target DOS file handle
  **
  ** Returns:    TRUE if successful.  LZERROR_BADINHANDLE or
  **             LZERROR_BADOUTHANDLE if unsuccessful.
  **
  ** Globals:    none
  **
  ** N.b., stream-style I/O routines like fopen() and fclose() may counter the
  ** intended effect of this function.  fclose() writes the current date to any
  ** file it's called with which was opened in write "w" or append "a" mode.
  ** One way to get around this in order to modify the date of a file opened
  ** for writing or appending by fopen() is to fclose() the file and fopen() it
  ** again in read "r" mode.  Then set its date and time stamp with
  ** CopyDateTimeStamp().
  */
  INT CopyDateTimeStamp(INT_PTR doshFrom, INT_PTR doshTo)
  {
  #ifdef ORGCODE
     // DOS prototypes from <dos.h>
     extern DWORD _dos_getftime(INT dosh, DWORD *puDate, DWORD *puTime);
     extern DWORD _dos_setftime(INT dosh, DWORD uDate, DWORD uTime);
  
  #ifdef LZA_DLL
     static
  #endif
     DWORD uFrom_date,    // temporary storage for date
           uFrom_time;    // and time stamps
  
     if (_dos_getftime(doshFrom, &uFrom_date, &uFrom_time) != 0u)
        return((INT)LZERROR_BADINHANDLE);
  
     if (_dos_setftime(doshTo, uFrom_date, uFrom_time) != 0u)
        return((INT)LZERROR_BADOUTHANDLE);
  #else
  
      FILETIME lpCreationTime, lpLastAccessTime, lpLastWriteTime;
  
     if(!GetFileTime((HANDLE) doshFrom, &lpCreationTime, &lpLastAccessTime,
                      &lpLastWriteTime)){
        return((INT)LZERROR_BADINHANDLE);
     }
     if(!SetFileTime((HANDLE) doshTo, &lpCreationTime, &lpLastAccessTime,
                      &lpLastWriteTime)){
        return((INT)LZERROR_BADINHANDLE);
     }
  
  #endif
     return(TRUE);
  }
  
  