/*==========================================================================
 *
 *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
 *
 *  File:       util.c
 *  Content:    miscellaneous functions
 *
 *
 ***************************************************************************/
#include "duel.h"
#include <stdlib.h>

/*
 * Globals
 */
static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
                                8, 9, '-', 10, 11, 12, 13, 14, 15 };
static const WCHAR wszDigits[] = L"0123456789ABCDEF";

#ifdef DEBUG
static const TCHAR DEBUG_MODULE_STR[] = TEXT("DUEL: ");
#endif

#define GUIDSTR_MAX 38
#define GUID_STRING_SIZE 64

/*
 * Local prototypes
 */
int		GetDigit(LPSTR lpstr);
void	ConvertField(LPBYTE lpByte, LPSTR * ppStr, int iFieldSize, 
					 BOOL fRightToLeft);
/*
 * StringFromGUID
 * 
 * Converts a GUID into a wide string
 */
int StringFromGUID(GUID* lpguid, LPWSTR lpwsz)
{
    int i;

    const BYTE * pBytes = (const BYTE *) lpguid;

    *lpwsz++ = L'{';

    for (i = 0; i < sizeof(GuidMap); i++)
    {
        if (GuidMap[i] == '-')
        {
            *lpwsz++ = L'-';
        }
        else
        {
            *lpwsz++ = wszDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
            *lpwsz++ = wszDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
        }
    }
    *lpwsz++ = L'}';
    *lpwsz   = L'\0';

    return GUIDSTR_MAX;
}

/*
 * IsEqualGuid
 *
 * Determines if two guids are equal
 */
BOOL  IsEqualGuid(GUID *lpguid1, GUID *lpguid2)
{
   return (
      ((PLONG) lpguid1)[0] == ((PLONG) lpguid2)[0] &&
      ((PLONG) lpguid1)[1] == ((PLONG) lpguid2)[1] &&
      ((PLONG) lpguid1)[2] == ((PLONG) lpguid2)[2] &&
      ((PLONG) lpguid1)[3] == ((PLONG) lpguid2)[3]);
}


// convert a hex char to an int - used by str to guid conversion
// we wrote our own, since the ole one is slow, and requires ole32.dll
// we use ansi strings here, since guids won't get internationalized
int GetDigit(LPSTR lpstr)
{
	char ch = *lpstr;
    
    if (ch >= '0' && ch <= '9')
        return(ch - '0');
    if (ch >= 'a' && ch <= 'f')
        return(ch - 'a' + 10);
    if (ch >= 'A' && ch <= 'F')
        return(ch - 'A' + 10);
    return(0);
}
// walk the string, writing pairs of bytes into the byte stream (guid)
// we need to write the bytes into the byte stream from right to left
// or left to right as indicated by fRightToLeft
void ConvertField(LPBYTE lpByte,LPSTR * ppStr,int iFieldSize,BOOL fRightToLeft)
{
	int i;

	for (i=0;i<iFieldSize ;i++ )
	{
		// don't barf on the field separators
		if ('-' == **ppStr) (*ppStr)++; 
		if (fRightToLeft == TRUE)
		{
			// work from right to left within the byte stream
			*(lpByte + iFieldSize - (i+1)) = 16*GetDigit(*ppStr) + GetDigit((*ppStr)+1);
		} 
		else 
		{
			// work from  left to right within the byte stream
			*(lpByte + i) = 16*GetDigit(*ppStr) + GetDigit((*ppStr)+1);
		}
		*ppStr+=2; // get next two digit pair
	}
} // ConvertField


// convert the passed in string to a real GUID
// walk the guid, setting each byte in the guid to the two digit hex pair in the
// passed string
HRESULT GUIDFromString(LPWSTR lpWStr, GUID * pGuid)
{
	BYTE * lpByte; // byte index into guid
	int iFieldSize; // size of current field we're converting
	// since its a guid, we can do a "brute force" conversion
	char lpTemp[GUID_STRING_SIZE];
	char *lpStr = lpTemp;

	WideToAnsi(lpStr,lpWStr,GUID_STRING_SIZE);
	
	// make sure we have a {xxxx-...} type guid
	if ('{' !=  *lpStr) return E_FAIL;
	lpStr++;
	
	lpByte = (BYTE *)pGuid;
	// data 1
	iFieldSize = sizeof(unsigned long);
	ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
	lpByte += iFieldSize;

	// data 2
	iFieldSize = sizeof(unsigned short);
	ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
	lpByte += iFieldSize;

	// data 3
	iFieldSize = sizeof(unsigned short);
	ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
	lpByte += iFieldSize;

	// data 4
	iFieldSize = 8*sizeof(unsigned char);
	ConvertField(lpByte,&lpStr,iFieldSize,FALSE);
	lpByte += iFieldSize;

	// make sure we ended in the right place
	if ('}' != *lpStr) 
	{
		memset(pGuid,0,sizeof(GUID));
		return E_FAIL;
	}

	return S_OK;
}// GUIDFromString

/*
 ** WideToAnsi
 *
 *  CALLED BY:	everywhere
 *
 *  PARAMETERS: lpStr - destination string
 *				lpWStr - string to convert
 *				cchStr - size of dest buffer
 *
 *  DESCRIPTION:
 *				converts unicode lpWStr to ansi lpStr.
 *				fills in unconvertable chars w/ DPLAY_DEFAULT_CHAR "-"
 *				
 *
 *  RETURNS:  if cchStr is 0, returns the size required to hold the string
 *				otherwise, returns the number of chars converted
 *
 */
int WideToAnsi(LPSTR lpStr,LPWSTR lpWStr,int cchStr)
{

	int rval;
	BOOL bDefault;

	// use the default code page (CP_ACP)
	// -1 indicates WStr must be null terminated
	rval = WideCharToMultiByte(CP_ACP,0,lpWStr,-1,lpStr,cchStr,"-",&bDefault);

	return rval;

} // WideToAnsi

/*
 ** AnsiToWide
 *
 *  CALLED BY: everywhere
 *
 *  PARAMETERS: lpWStr - dest string
 *				lpStr  - string to convert
 *				cchWstr - size of dest buffer
 *
 *  DESCRIPTION: converts Ansi lpStr to Unicode lpWstr
 *
 *
 *  RETURNS:  if cchStr is 0, returns the size required to hold the string
 *				otherwise, returns the number of chars converted
 *
 */
int AnsiToWide(LPWSTR lpWStr,LPSTR lpStr,int cchWStr)
{
	int rval;

	rval =  MultiByteToWideChar(CP_ACP,0,lpStr,-1,lpWStr,cchWStr);

	return rval;
}  // AnsiToWide


/* 
 * randInt
 *
 * returns a random integer in the specified range
 */
int randInt( int low, int high )
{
    int range = high - low;
    int num = rand() % range;
    return( num + low );
}

/*
 * randDouble
 *
 * returns a random double in the specified range
 */
double randDouble( double low, double high )
{
    double range = high - low;
    double num = range * (double)rand()/(double)RAND_MAX;
    return( num + low );
}

/*
 * dtrace - diagnostic trace to OutputDebugString() (UNICODE supported)
 */
void dtrace(LPTSTR szFormat, ...)
{
#ifdef DEBUG
    int		offset = 0;
	TCHAR 	szBuf[256];
    va_list ap;

    va_start(ap,szFormat);

	offset = wsprintf((LPTSTR)szBuf, DEBUG_MODULE_STR);
	offset += wvsprintf(szBuf+offset, szFormat, ap);

	OutputDebugString(szBuf);

    va_end(ap);
#endif
} /* dtrace */


