text: /*****************************************************************************/
  /* Path.h                                 Copyright (c) Ladislav Zezula 2019 */
  /*---------------------------------------------------------------------------*/
  /* Global path merger class                                                  */
  /*---------------------------------------------------------------------------*/
  /*   Date    Ver   Who  Comment                                              */
  /* --------  ----  ---  -------                                              */
  /* 24.07.17  1.00  Lad  Created                                              */
  /*****************************************************************************/
  
  #ifndef __CASC_PATH_H__
  #define __CASC_PATH_H__
  
  //-----------------------------------------------------------------------------
  // Structures
  
  template <typename xchar>
  struct CASC_PATH
  {
      CASC_PATH(xchar chSeparator = PATH_SEP_CHAR)
      {
          m_szBufferBegin = m_szBufferPtr = m_Buffer;
          m_szBufferEnd = m_szBufferBegin + _countof(m_Buffer);
          m_chSeparator = chSeparator;
          m_Buffer[0] = 0;
      }
  
      ~CASC_PATH()
      {
          if(m_szBufferBegin != m_Buffer)
          {
              CASC_FREE(m_szBufferBegin);
          }
      }
  
      // LPCTSTR szPath = Path;
      operator const xchar *()
      {
          return m_szBufferBegin;
      }
  
      // LPTSTR szPath = Path.New();
      xchar * New()
      {
          xchar * szNewStr;
  
          if((szNewStr = CASC_ALLOC<xchar>(Length() + 1)) != NULL)
          {
              memcpy(szNewStr, m_szBufferBegin, Length() * sizeof(xchar));
              szNewStr[Length()] = 0;
          }
  
          return szNewStr;
      }
  
      size_t Save()
      {
          return (m_szBufferPtr - m_szBufferBegin);
      }
  
      bool Restore(size_t nSavePos)
      {
          if((m_szBufferBegin + nSavePos) < m_szBufferEnd)
          {
              m_szBufferPtr = m_szBufferBegin + nSavePos;
              m_szBufferPtr[0] = 0;
              return true;
          }
  
          return false;
      }
  
      // Path.Copy(szBuffer, _countof(szBuffer));
      bool Copy(xchar * szBuffer, size_t cchBuffer)
      {
          if((Length() + 1) > cchBuffer)
              return false;
  
          memcpy(szBuffer, m_szBufferBegin, Length() * sizeof(xchar));
          szBuffer[Length()] = 0;
          return true;
      }
  
      size_t Length()
      {
          return m_szBufferPtr - m_szBufferBegin;
      }
  
      bool SetPathRoot(const xchar * szRoot)
      {
          // Make sure that there is no characters
          m_szBufferPtr = m_szBufferBegin;
          m_szBufferPtr[0] = 0;
  
          // Append the root path
          return AppendString(szRoot, false);
      }
  
      bool AppendStringN(const xchar * szString, size_t nMaxchars, bool bWithSeparator)
      {
          const xchar * szStringEnd = szString + nMaxchars;
          xchar chOneChar;
  
          if(szString && szString[0] && nMaxchars)
          {
              // Append separator, if required and not in begin of the string
              if(m_szBufferPtr > m_szBufferBegin && bWithSeparator)
                  AppendChar(m_chSeparator);
  
              // Append the characters from the string
              while(szString[0] && szString < szStringEnd)
              {
                  // Retrieve the single character
                  chOneChar = *szString++;
  
                  // Normalize the character
                  if(chOneChar == '/' || chOneChar == '\\')
                      chOneChar = m_chSeparator;
  
                  if(!AppendChar(chOneChar))
                      break;
              }
          }
  
          return true;
      }
  
      bool AppendString(const xchar * szString, bool bWithSeparator)
      {
          return AppendStringN(szString, (0x10000 / sizeof(xchar)), bWithSeparator);
      }
  
      bool AppendEKey(LPBYTE pbEKey)
      {
          xchar szEKey[MD5_STRING_SIZE + 1];
  
          StringFromBinary(pbEKey, MD5_HASH_SIZE, szEKey);
          AppendStringN(szEKey, 2, true);
          AppendStringN(szEKey+2, 2, true);
          return AppendString(szEKey, true);
      }
  
      bool AppendChar(xchar chOneChar)
      {
          // Buffer our of space?
          if((m_szBufferPtr + 2) >= m_szBufferEnd)
          {
              xchar * szOldBuffer = m_szBufferBegin;
              xchar * szNewBuffer;
              size_t nToAllocate = (m_szBufferEnd - m_szBufferBegin) * 2;
              size_t nLength = (m_szBufferPtr - m_szBufferBegin);
  
              if((szNewBuffer = CASC_ALLOC<xchar>(nToAllocate)) == NULL)
                  return false;
  
              // Copy the chars
              memcpy(szNewBuffer, m_szBufferBegin, (m_szBufferPtr - m_szBufferBegin) * sizeof(xchar));
              m_szBufferBegin = szNewBuffer;
              m_szBufferPtr = m_szBufferBegin + nLength;
              m_szBufferEnd = m_szBufferBegin + nToAllocate;
              
              // Free the old buffer
              if(szOldBuffer != m_Buffer)
                  CASC_FREE(szOldBuffer);
          }
  
          // Append the character
          *m_szBufferPtr++ = chOneChar;
          m_szBufferPtr[0] = 0;
          return true;
      }
  
      protected:
  
      xchar * m_szBufferBegin;
      xchar * m_szBufferPtr;
      xchar * m_szBufferEnd;
      xchar m_Buffer[MAX_PATH];
      xchar m_chSeparator;
  };
  
  #endif // __CASC_PATH_H__
  