/*===========================================================================
FILE: 
   CoreUtilities.cpp

DESCRIPTION:
   Collection of various utility methods

PUBLIC CLASSES AND METHODS:
   StringToLONG
   StringToULONG
   StringToLONGLONG
   StringToULONGLONG

   ParseTokens()
   ParseCommandLine()
   ParseFormatSpecifier()

   FromString( CHAR )
   FromString( UCHAR )
   FromString( SHORT )
   FromString( USHORT )
   FromString( int )
   FromString( UINT )
   FromString( LONG )
   FromString( ULONG )
   FromString( LONGLONG )
   FromString( ULONGLONG )

   ToString( CHAR )
   ToString( UCHAR )
   ToString( SHORT )
   ToString( USHORT )
   ToString( int )
   ToString( UINT )
   ToString( LONG )
   ToString( ULONG )
   ToString( LONGLONG )
   ToString( ULONGLONG )

   ContainerToCSVString()
   CSVStringToContainer()
   CSVStringToValidatedContainer()

   SetDiff()
   SetIntersection()
   SetUnion()

   GetProgramPath()
   EnumerateFolders()

Copyright (c) 2011, Code Aurora Forum. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Code Aurora Forum nor
      the names of its contributors may be used to endorse or promote
      products derived from this software without specific prior written
      permission.


THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
===========================================================================*/

//---------------------------------------------------------------------------
// Include Files
//---------------------------------------------------------------------------
#include "StdAfx.h"
#include "CoreUtilities.h"

#include <climits>

//---------------------------------------------------------------------------
// Definitions
//---------------------------------------------------------------------------

// Format specifier states
enum eFormatState
{
   eFMT_STATE_NORMAL,      // [0] Normal state; outputting literal characters
   eFMT_STATE_PERCENT,     // [1] Just read '%'
   eFMT_STATE_FLAG,        // [2] Just read flag character
   eFMT_STATE_WIDTH,       // [3] Just read width specifier
   eFMT_STATE_DOT,         // [4] Just read '.'
   eFMT_STATE_PRECIS,      // [5] Just read precision specifier
   eFMT_STATE_SIZE,        // [6] Just read size specifier
   eFMT_STATE_TYPE,        // [7] Just read type specifier
   eFMT_STATE_INVALID,     // [8] Invalid format

   eFMT_STATES             // [9] Number of format states
};

// Format specifier character classes
enum eFormatCharClass
{
   eFMT_CH_CLASS_OTHER,    // [0] Character with no special meaning
   eFMT_CH_CLASS_PERCENT,  // [1] '%'
   eFMT_CH_CLASS_DOT,      // [2] '.'
   eFMT_CH_CLASS_STAR,     // [3] '*'
   eFMT_CH_CLASS_ZERO,     // [4] '0'
   eFMT_CH_CLASS_DIGIT,    // [5] '1'..'9'
   eFMT_CH_CLASS_FLAG,     // [6] ' ', '+', '-', '#'
   eFMT_CH_CLASS_SIZE,     // [7] 'h', 'l', 'L', 'N', 'F', 'w'
   eFMT_CH_CLASS_TYPE      // [8] Type specifying character
};

// Lookup table for determining class of a character (lower nibble) 
// and next format specifier state (upper nibble)
const UCHAR gLookupTable[] = 
{
   0x06, // ' ', FLAG
   0x80, // '!', OTHER
   0x80, // '"', OTHER
   0x86, // '#', FLAG
   0x80, // '$', OTHER
   0x81, // '%', PERCENT 
   0x80, // '&', OTHER
   0x00, // ''', OTHER
   0x00, // '(', OTHER
   0x10, // ')', OTHER
   0x03, // '*', STAR
   0x86, // '+', FLAG
   0x80, // ',', OTHER
   0x86, // '-', FLAG
   0x82, // '.', DOT
   0x80, // '/', OTHER
   0x14, // '0', ZERO
   0x05, // '1', DIGIT
   0x05, // '2', DIGIT
   0x45, // '3', DIGIT
   0x45, // '4', DIGIT
   0x45, // '5', DIGIT
   0x85, // '6', DIGIT
   0x85, // '7', DIGIT
   0x85, // '8', DIGIT
   0x05, // '9', DIGIT
   0x00, // :!', OTHER
   0x00, // ';', OTHER
   0x30, // '<', OTHER
   0x30, // '=', OTHER
   0x80, // '>', OTHER
   0x50, // '?', OTHER
   0x80, // '@', OTHER
   0x80, // 'A', OTHER
   0x00, // 'B', OTHER
   0x08, // 'C', TYPE
   0x00, // 'D', OTHER
   0x28, // 'E', TYPE
   0x27, // 'F', SIZE
   0x38, // 'G', TYPE
   0x50, // 'H', OTHER
   0x57, // 'I', SIZE
   0x80, // 'J', OTHER
   0x00, // 'K', OTHER
   0x07, // 'L', SIZE
   0x00, // 'M', OTHER
   0x37, // 'N', SIZE
   0x30, // 'O', OTHER
   0x30, // 'P', OTHER
   0x50, // 'Q', OTHER
   0x50, // 'R', OTHER
   0x88, // 'S', TYPE
   0x00, // 'T', OTHER
   0x00, // 'U', OTHER
   0x00, // 'V', OTHER
   0x20, // 'W', OTHER
   0x28, // 'X', TYPE
   0x80, // 'Y', OTHER
   0x88, // 'Z', TYPE
   0x80, // '[', OTHER
   0x80, // '\', OTHER
   0x00, // ']', OTHER
   0x00, // '^', OTHER
   0x00, // '-', OTHER
   0x60, // '`', OTHER
   0x60, // 'a', OTHER
   0x60, // 'b', OTHER
   0x68, // 'c', TYPE
   0x68, // 'd', TYPE
   0x68, // 'e', TYPE
   0x08, // 'f', TYPE
   0x08, // 'g', TYPE
   0x07, // 'h', SIZE
   0x78, // 'i', TYPE
   0x70, // 'j', OTHER
   0x70, // 'k', OTHER
   0x77, // 'l', SIZE
   0x70, // 'm', OTHER
   0x70, // 'n', OTHER
   0x08, // 'o', TYPE
   0x08, // 'p', TYPE
   0x00, // 'q', OTHER
   0x00, // 'r', OTHER
   0x08, // 's', TYPE
   0x00, // 't', OTHER
   0x08, // 'u', TYPE
   0x00, // 'v', OTHER
   0x07, // 'w', SIZE
   0x08  // 'x', TYPE
};

/*=========================================================================*/
// Free Methods
/*=========================================================================*/

/*===========================================================================
METHOD:
   IsWhitespace (Private Free Method)

DESCRIPTION:
   Is this whitespace?

PARAMETERS:   
   pStr          [ I ] - The string 

RETURN VALUE:
   bool
===========================================================================*/
static bool IsWhitespace( LPCSTR pStr )
{
   bool bWS = false;

   int c = (int)*pStr;
   if (isspace( c ))
   {
      bWS = true;
   }

   return bWS;
}

/*===========================================================================
METHOD:
   IsHexadecimalString (Private Free Method)

DESCRIPTION:
   Is this a hexadecimal digits string?

PARAMETERS:   
   pStr          [ I ] - The string 

RETURN VALUE:
   bool
===========================================================================*/
static bool IsHexadecimalString( LPCSTR pStr )
{
   // Assume not
   bool bHex = false;

   // Skip whitespace
   LPCSTR pTmp = pStr;
   while (IsWhitespace( pTmp ) == true)
   {
      pTmp++;
   }

   // Skip leading +/-
   CHAR ch = *pTmp;
   if (ch == '+' || ch == '-')
   {
      pTmp++;
   }

   if (*pTmp == '0')
   {
      pTmp++;
      if (*pTmp == 'x' || *pTmp == 'X')
      {
         bHex = true;
      }
   }

   return bHex;
}

/*===========================================================================
METHOD:
   IsNegativeString (Private Free Method)

DESCRIPTION:
   Is this a string starting with a negative sign?

PARAMETERS:   
   pStr          [ I ] - The string 

RETURN VALUE:
   bool
===========================================================================*/
static bool IsNegativeString( LPCSTR pStr )
{
   // Assume not
   bool bNeg = false;

   // Skip whitespace
   LPCSTR pTmp = pStr;
   while (IsWhitespace( pTmp ) == true)
   {
      pTmp++;
   }

   CHAR ch = *pTmp;
   if (ch == '-')
   {
      bNeg = true;
   }

   return bNeg;
}

/*===========================================================================
METHOD:
   StringToLONG (Free Method)

DESCRIPTION:
   Replacement/front end for strtol
  
   NOTE: strtol does not correctly handle a negative integer
   when specified in hexadecimal, so we have to check for that
   first

PARAMETERS:   
   pStr          [ I ] - The string 
   base          [ I ] - Base for conversion
   val           [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool StringToLONG( 
   LPCSTR                    pStr,
   int                        base,
   LONG &                     val )
{
   // Assume failure
   bool bOK = false;
   if (pStr == 0 || *pStr == 0)
   {
      return bOK;
   }
  
   // Hexadecimal?
   if (base == 16 || (base == 0 && IsHexadecimalString( pStr ) == true))
   {
      // No negative hexadecimal strings allowed
      if (IsNegativeString( pStr ) == false)
      {
         // Reset error
         errno = 0;

         // Use the unsigned version, then cast
         LPSTR pEnd = (LPSTR)pStr;
         ULONG tmpVal = strtoul( pStr, &pEnd, base );
         if (tmpVal != ULONG_MAX || errno != ERANGE)
         {
            // Where did we end?
            if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
            {
               // Success!
               val = (LONG)tmpVal;
               bOK = true;
            }
         }
      }
   }
   else
   {
      // Proceed as normal
      LPSTR pEnd = (LPSTR)pStr;
      LONG tmpVal = strtol( pStr, &pEnd, base );
      if ((tmpVal != LONG_MAX && tmpVal != LONG_MIN) || errno != ERANGE)
      {
         // Where did we end?
         if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
         {             
            // Success!
            val = tmpVal;
            bOK = true;
         }
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   StringToULONG (Free Method)

DESCRIPTION:
   Replacement/front end for strtoul
  
PARAMETERS:   
   pStr          [ I ] - The string 
   base          [ I ] - Base for conversion
   val           [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool StringToULONG( 
   LPCSTR                    pStr,
   int                        base,
   ULONG &                    val )
{
   // Assume failure
   bool bOK = false;
   if (pStr == 0 || *pStr == 0)
   {
      return bOK;
   }

   // No negative strings allowed
   if (IsNegativeString( pStr ) == true)
   {
      return bOK;
   }
   
   // Reset error
   errno = 0;

   LPSTR pEnd = (LPSTR)pStr;
   ULONG tmpVal = strtoul( pStr, &pEnd, base );
   if (tmpVal != ULONG_MAX || errno != ERANGE)
   {
      if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
      {
         // Success!
         val = tmpVal;
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   StringToLONGLONG (Free Method)

DESCRIPTION:
   Replacement/front end for strtoll
  
   NOTE: strtoll does not correctly handle a negative integer
   when specified in hexadecimal, so we have to check for that
   first

PARAMETERS:   
   pStr          [ I ] - The string 
   base          [ I ] - Base for conversion
   val           [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool StringToLONGLONG( 
   LPCSTR                     pStr,
   int                        base,
   LONGLONG &                 val )
{
   // Assume failure
   bool bOK = false;
   if (pStr == 0 || *pStr == 0)
   {
      return bOK;
   }

   if (base == 16 || (base == 0 && IsHexadecimalString( pStr ) == true))
   {
      // No negative hexadecimal strings allowed
      if (IsNegativeString( pStr ) == false)
      {
         // Reset error
         errno = 0;

         // Use the unsigned version, then cast
         LPSTR pEnd = (LPSTR)pStr;
         ULONGLONG tmpVal = strtoull( pStr, &pEnd, base );
         if (tmpVal != ULLONG_MAX || errno != ERANGE)
         {
            // Where did we end?
            if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
            {
               // Success!
               val = (LONGLONG)tmpVal;
               bOK = true;
            }
         }
      }
   }
   else
   {
      // Proceed as normal
      LPSTR pEnd = (LPSTR)pStr;
      LONGLONG tmpVal = strtoll( pStr, &pEnd, base );
      if ((tmpVal != LLONG_MAX && tmpVal != LLONG_MIN) || errno != ERANGE)
      {
         if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
         {
            // Success!
            val = tmpVal;
            bOK = true;
         }
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   StringToULONGLONG (Free Method)

DESCRIPTION:
   Replacement/front end for strtouill
  
PARAMETERS:   
   pStr          [ I ] - The string 
   base          [ I ] - Base for conversion
   val           [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool StringToULONGLONG( 
   LPCSTR                    pStr,
   int                        base,
   ULONGLONG &                val )
{
   // Assume failure
   bool bOK = false;
   if (pStr == 0 || *pStr == 0)
   {
      return bOK;
   }
 
   // No negative strings allowed
   if (IsNegativeString( pStr ) == true)
   {
      return bOK;
   }
   
   // Reset error
   errno = 0;

   LPSTR pEnd = (LPSTR)pStr;
   ULONGLONG tmpVal = strtoull( pStr, &pEnd, base );
   if (tmpVal != ULLONG_MAX || errno != ERANGE)
   {
      if (pEnd != pStr && (*pEnd == 0 || IsWhitespace( pEnd ) == true))
      {
         // Success!
         val = tmpVal;
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ParseCommandLine (Free Method)

DESCRIPTION:
   Parse a command line to tokens (a command line is a string of
   space delimited values where a value that contains space is
   enclosed in text)
  
PARAMETERS:
   commandLine [ I ] - The characters separating tokens
   tokens      [ O ] - The resultant vector of tokens

RETURN VALUE:
   None
===========================================================================*/
void ParseCommandLine(
   std::string                    commandLine,
   std::vector <std::string> &    tokens )
{
   ULONG count = (ULONG)commandLine.size();

   for (ULONG nEndToken = 0; nEndToken < count;)
   {
      // Skip leading spaces
      int nStartToken = commandLine.find_first_not_of( " ", nEndToken );
      if (nStartToken == -1)
      {
         // All that is left is spaces
         return;
      }

      int stringLength = 0;

      // In Quotes? If so ignore spaces until next quote
      if (commandLine[ nStartToken ] == '\"')
      {
         nStartToken++;
         nEndToken = commandLine.find( '\"', nStartToken );
         if (nEndToken == -1)
         {
            // Unable to find trailing quote, fail
            return;
         }
         stringLength = nEndToken - nStartToken;
         nEndToken++;
      }
      else
      {
         nEndToken = commandLine.find( ' ', nStartToken );
         if (nEndToken == -1)
         {
            // Unable to find trailing space, use end
            nEndToken = commandLine.size();
         }

         stringLength = nEndToken - nStartToken;
      }

      std::string newToken = commandLine.substr( nStartToken, stringLength );
      tokens.push_back( newToken );
   }
}

/*===========================================================================
METHOD:
   ParseTokens (Free Method)

DESCRIPTION:
   Parse a line into individual tokens

   NOTE: No attempt is made to handle accidental separators, i.e. searching
   for ',' on 'foo, bar, "foo, bar"' will return four tokens, not three so
   pick something like '^' instead of ','!
  
PARAMETERS:
   pSeparator  [ I ] - The characters separating tokens
   pLine       [ I ] - The string being parsed
   tokens      [ O ] - The resultant vector of tokens

RETURN VALUE:
   None
===========================================================================*/
void ParseTokens(
   LPCSTR                    pSeparator,
   LPSTR                     pLine,
   std::vector <LPSTR> &     tokens )
{
   if (pSeparator != 0 && pSeparator[0] != 0 && pLine != 0 && pLine[0] != 0)
   {
      LPSTR pToken = strtok( pLine, pSeparator );
      while (pToken != 0)
      {
         // Store token
         tokens.push_back( pToken );

         // Get next token:
         pToken = strtok( 0, pSeparator );
      }
   }
}

/*===========================================================================
METHOD:
   ParseFormatSpecifier (Free Method)

DESCRIPTION:
   Parse a format specifier into individual format type tokens
  
PARAMETERS:
   pFmt        [ I ] - The format specifier (must be NULL terminated)
   fmtLen      [ I ] - Length of above format specifier
   fmtTypes    [ O ] - The individual format type tokens ('d', 'u', 'us' etc.)

RETURN VALUE:
   bool - Valid format specifier?
===========================================================================*/
bool ParseFormatSpecifier( 
   LPCSTR                    pFmt,
   ULONG                      fmtLen,
   std::vector <CHAR> &      fmtTypes )
{
   // Assume failure
   bool bOK = false;

   // Make sure string is NULL terminated
   CHAR ch; 
   ULONG chars = 0;
   while (chars < fmtLen)
   {
      if (pFmt[chars] == '\0')
      {
         break;
      }
      else
      {
         chars++;
      }
   }

   if (pFmt[chars] != '\0')
   {
      return bOK;
   }

   // Extract individual format type tokens
   eFormatState state = eFMT_STATE_NORMAL; 
   eFormatCharClass cc = eFMT_CH_CLASS_OTHER;
   while ((ch = *pFmt++) != '\0' && state != eFMT_STATE_INVALID) 
   {
      // Find character class
      cc = eFMT_CH_CLASS_OTHER;
      if (ch >= ' ' && ch <= 'x')
      {
         cc = (eFormatCharClass)(gLookupTable[ch - ' '] & 0xF);
      }

      // Find next state
      state = (eFormatState)(gLookupTable[cc * eFMT_STATES + (state)] >> 4);
      switch (state) 
      {
         case eFMT_STATE_NORMAL:
         NORMAL_STATE:
            break;

         case eFMT_STATE_PERCENT:
         case eFMT_STATE_FLAG:
         case eFMT_STATE_DOT:
            break;

         case eFMT_STATE_WIDTH:
         case eFMT_STATE_PRECIS:
            if (ch == '*') 
            {
               fmtTypes.push_back( ch );
            }
            break;

         case eFMT_STATE_SIZE:
            switch (ch) 
            {
               case 'l':
                  if (*pFmt == 'l')
                  {
                     ++pFmt;
                  }
                  break;

               case 'I':
                  if ( (*pFmt == '6') && (*(pFmt + 1) == '4') )
                  {
                     pFmt += 2;
                  }
                  else if ( (*pFmt == '3') && (*(pFmt + 1) == '2') )
                  {
                     pFmt += 2;
                  }
                  else if ( (*pFmt == 'd') 
                        ||  (*pFmt == 'i')
                        ||  (*pFmt == 'o')
                        ||  (*pFmt == 'u')
                        ||  (*pFmt == 'x')
                        ||  (*pFmt == 'X') ) 
                  {
                     // Nothing further needed
                  }
                  else 
                  {
                     state = eFMT_STATE_NORMAL;
                     goto NORMAL_STATE;
                  }
                  break;

                  case 'h':
                  case 'w':
                     break;
               }
               break;

         case eFMT_STATE_TYPE:
            fmtTypes.push_back( ch );
            break;
      }
    }

   bOK = (state == eFMT_STATE_NORMAL || state == eFMT_STATE_TYPE);
   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   CHAR &                     theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      LONG val = LONG_MAX;
      bOK = StringToLONG( pStr, 0, val );
      if (bOK == true)
      {
         // Reset status
         bOK = false;

         // Was this provided as a hexadecimal string?
         if (IsHexadecimalString( pStr ) == true)
         {
            // Yes, the return value is a LONG, so check against
            // the maximum range for a UCHAR, before casting to
            // a CHAR (to pick sign back up)
            if (val <= UCHAR_MAX)
            {
               // Success!
               theType = (CHAR)val;
               bOK = true;
            }           
         }          
         else if (val >= SCHAR_MIN && val <= SCHAR_MAX)
         {
            // Success!
            theType = (CHAR)val;
            bOK = true;
         }
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   UCHAR &                    theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      ULONG val = ULONG_MAX;
      bOK = StringToULONG( pStr, 0, val );
      if (bOK == true && val <= UCHAR_MAX)
      {
         // Success!
         theType = (UCHAR)val;         
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   SHORT &                    theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      LONG val = LONG_MAX;
      bOK = StringToLONG( pStr, 0, val );
      if (bOK == true)
      {
         // Reset status
         bOK = false;

         // Was this provided as a hexadecimal string?
         if (IsHexadecimalString( pStr ) == true)
         {
            // Yes, the return value is a LONG, so check against
            // the maximum range for a USHORT, before casting to
            // a SHORT (to pick sign back up)
            if (val <= USHRT_MAX)
            {
               // Success!
               theType = (SHORT)val;
               bOK = true;
            }
         }
         else if (val >= SHRT_MIN && val <= SHRT_MAX)
         {
            // Success!
            theType = (SHORT)val;
            bOK = true;
         }
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   USHORT &                   theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      ULONG val = ULONG_MAX;
      bOK = StringToULONG( pStr, 0, val );
      if (bOK == true && val <= USHRT_MAX)
      {
         // Success!
         theType = (USHORT)val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   int &                      theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      LONG val = LONG_MAX;
      bOK = StringToLONG( pStr, 0, val );
      if (bOK == true && (val >= INT_MIN && val <= INT_MAX))
      {
         // Success!
         theType = (int)val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   UINT &                     theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      ULONG val = ULONG_MAX;
      bOK = StringToULONG( pStr, 0, val );
      if (bOK == true && val <= UINT_MAX)
      {
         // Success!
         theType = (UINT)val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   LONG &                     theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      LONG val = LONG_MAX;
      bOK = StringToLONG( pStr, 0, val );
      if (bOK == true)
      {
         // Success!
         theType = val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   ULONG &                    theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      ULONG val = ULONG_MAX;
      bOK = StringToULONG( pStr, 0, val );
      if (bOK == true)
      {
         // Success!
         theType = val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   LONGLONG &                 theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      LONGLONG val = LLONG_MAX;
      bOK = StringToLONGLONG( pStr, 0, val );
      if (bOK == true)
      {
         // Success!
         theType = val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   FromString (Free Method)

DESCRIPTION:
   Convert a string to a value
  
PARAMETERS:   
   pStr          [ I ] - The string 
   theType       [ O ] - Resulting value

RETURN VALUE:
   bool
===========================================================================*/
bool FromString( 
   LPCSTR                    pStr,
   ULONGLONG &                theType )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      ULONGLONG val = ULLONG_MAX;
      bOK = StringToULONGLONG( pStr, 0, val );
      if (bOK == true)
      {
         // Success!
         theType = val;
      }
      else
      {
         bOK = false;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   CHAR                       val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int tmp = (int)val;
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%d", 
                         tmp ); 

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   UCHAR                      val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                       (size_t)(SUGGESTED_BUFFER_LEN - 1),
                       "%u", 
                       (UINT)val );

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   SHORT                      val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int tmp = (int)val;
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%d", 
                         tmp ); 

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   USHORT                     val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%u", 
                         (UINT)val );

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   int                        val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%d", 
                         val ); 

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}


/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   UINT                       val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%u", 
                         val );

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   LONG                       val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%ld", 
                         val ); 

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}


/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   ULONG                      val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%lu", 
                         val );

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   LONGLONG                   val,
   LPSTR                      pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%lld", 
                         val ); 

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   ToString (Free Method)

DESCRIPTION:
   Convert a value to a string
  
PARAMETERS:   
   val           [ I ] - The value to convert
   pStr          [ O ] - The resulting string 

RETURN VALUE:
   bool
===========================================================================*/
bool ToString( 
   ULONGLONG                  val,
   LPSTR                     pStr )
{
   // Assume failure
   bool bOK = false;

   if (pStr != 0)
   {
      int rc = snprintf( pStr, 
                         (size_t)(SUGGESTED_BUFFER_LEN - 1),
                         "%llu", 
                         val );

      if (rc < 0)
      {
         pStr[0] = 0;
      }
      else
      {
         // Success!
         bOK = true;
      }
   }

   return bOK;
}

/*===========================================================================
METHOD:
   GetProgramPath (Public Method)

DESCRIPTION:
   Return the special folder used for storing program files
   
RETURN VALUE:
   std::string (Static value of "/opt/Qualcomm/Gobi/")
===========================================================================*/
std::string GetProgramPath()
{
   // If running programs's path is desired we could
   //   use readlink with /proc/getpid()/exe

   // Just using static path, as we don't want them to move it
   std::string path = "/opt/Qualcomm/Gobi/";

   return path;

}

/*===========================================================================
METHOD:
   IsFolder (Free Method)

DESCRIPTION:
   Helper function for EnumerateFolders, tells if a dirent is a folder.
   This reduces the memory usage by scandir, as compared to checking after
   scandir returns.

PARAMETERS:
   pFile         [ I ] - dirent structure describing file
  
RETURN VALUE:
   int:  zero    - Ignore this file
         nonzero - Process this file
===========================================================================*/
int IsFolder( const struct dirent * pFile )
{
   // Ignore anything beginning with a '.'
   if (pFile->d_name[0] == '.')
   {
      return 0;
   }

   return (pFile->d_type == DT_DIR ? 1 : 0);
}

/*===========================================================================
METHOD:
   EnumerateFolders (Public Method)

DESCRIPTION:
   Enumerate the subfolders of the given folder (recursive)

PARAMETERS:
   baseFolder     [ I ] - Folder to search in
   foundFolders   [ O ] - Fully qualified paths of found folders
  
RETURN VALUE:
   None
===========================================================================*/
void EnumerateFolders( 
   const std::string &           baseFolder,
   std::vector <std::string> &   foundFolders )
{
   if (baseFolder.size() == 0)
   {
      return;
   }

   std::string folderSearch = baseFolder;

   // Add trailing / if not present
   int folderLen = folderSearch.size();
   if (folderSearch[folderLen - 1] != '/')
   {
      folderSearch += '/';
   }

   dirent ** ppDevFiles;
   
   // Yes, scandir really takes a triple pointer for its second param
   int nNumDevFiles = scandir( folderSearch.c_str(), 
                               &ppDevFiles, 
                               IsFolder, 
                               alphasort );
   for (int nFile = 0; nFile < nNumDevFiles; nFile++)
   {
      std::string newFolder = folderSearch + ppDevFiles[nFile]->d_name;
      free( ppDevFiles[nFile] );

      foundFolders.push_back( newFolder );
      EnumerateFolders( newFolder, foundFolders );
   }
   
   if (nNumDevFiles != -1)
   {
      free( ppDevFiles );
   }
}

