/**@@@+++@@@@******************************************************************
**
** Microsoft Windows Media
** Copyright (C) Microsoft Corporation. All rights reserved.
**
***@@@---@@@@******************************************************************
*/

#include <drmcommon.h>
#include <drmcrt.h>

/* String CRT functions */
DRM_INT DRM_API DRMCRT_wcsncmp(
    IN const DRM_WCHAR *first,
    IN const DRM_WCHAR *last,
    IN       DRM_DWORD  count )
{
    if (!count)
    {
        return(0);
    }

    while (--count && *first && *first == *last)
    {
        first++;
        last++;
    }

    return((DRM_INT)(*first - *last));
}

/* BUGBUG:  Should anyone ever call strncmp?  They should always use DRM_CompareBytes I think.  Remove this function... */
DRM_INT DRM_API DRMCRT_strncmp (
    IN const DRM_CHAR  *first,
    IN const DRM_CHAR  *last,
    IN       DRM_DWORD  count)
{
    if (!count)
    {
        return(0);
    }

    while (--count && *first && *first == *last)
    {
        first++;
        last++;
    }

    return((DRM_INT)(*first - *last));
}


DRM_BOOL DRM_API DRMCRT_iswxdigit (DRM_WCHAR f_wch)
{
    DRM_WCHAR wch = NATIVE_WCHAR( f_wch );
    return ((wch >= NATIVE_WCHAR(g_wch0) && wch <= NATIVE_WCHAR(g_wch9))   /* A digit */ 
        ||  (wch >= NATIVE_WCHAR(g_wchA) && wch <= NATIVE_WCHAR(g_wchF))   /* Upper case hex char */ 
        ||  (wch >= NATIVE_WCHAR(g_wcha) && wch <= NATIVE_WCHAR(g_wchf))); /* lower case hex char */
}

DRM_BOOL DRM_API DRMCRT_iswdigit( DRM_WCHAR wch )
{
    return ( NATIVE_WCHAR(wch) >= NATIVE_WCHAR(g_wch0) 
          && NATIVE_WCHAR(wch) <= NATIVE_WCHAR(g_wch9) ); /* A digit */
}
DRM_BOOL DRM_API DRMCRT_iswalpha (DRM_WCHAR wch)
{
    return ((NATIVE_WCHAR(wch) >= NATIVE_WCHAR(g_wchA) && NATIVE_WCHAR(wch) <= NATIVE_WCHAR(g_wchZ))   /* Upper case char */
         || (NATIVE_WCHAR(wch) >= NATIVE_WCHAR(g_wcha) && NATIVE_WCHAR(wch) <= NATIVE_WCHAR(g_wchz))); /* lower case char */
}

DRM_WCHAR DRM_API DRMCRT_towlower (DRM_WCHAR wch)
{
    if (DRM_iswalpha (wch)
    &&   NATIVE_WCHAR(wch) < NATIVE_WCHAR(g_wcha))
    {
        DRM_WCHAR wchTemp = NATIVE_WCHAR(g_wcha) - NATIVE_WCHAR(g_wchA);
        wch = NATIVE_WCHAR(wch) + wchTemp;
        wch = WCHAR_CAST( wch );
    }

    return wch;
}

DRM_RESULT DRM_API DRMCRT_wcsntol( 
    IN const DRM_WCHAR *pwszStringInput,
    IN       DRM_DWORD  cchStringInput,
    OUT      DRM_LONG  *plValue )
{    
    DRM_CONST_STRING wszString;
    DRM_DWORD lMaxVal    = ULONG_MAX / 10;
    DRM_DWORD lNextDigit = 0;
    DRM_DWORD lValue     = 0;
    DRM_BOOL fPositive   = TRUE;

    if( NULL == plValue || 
        NULL == pwszStringInput ||
        0 == cchStringInput )
    {
        return DRM_E_INVALIDARG;
    }

    if( pwszStringInput[0] == g_wchMinus || pwszStringInput[0] == g_wchPlus )
    {
        if( pwszStringInput[0] == g_wchMinus )
        {
            fPositive = FALSE;
        }
        pwszStringInput++;
        cchStringInput--;
    }

    wszString.pwszString = pwszStringInput;
    wszString.cchString = cchStringInput;    
    *plValue = 0;

    while( wszString.cchString > 0 && DRM_iswdigit( *( wszString.pwszString ) ) )
    {

        lNextDigit = (NATIVE_WCHAR(*(wszString.pwszString)) - NATIVE_WCHAR(g_wch0));
        if( lValue < lMaxVal || 
            ( lValue == lMaxVal && lNextDigit <= ULONG_MAX % 10 ) )
        {
            lValue = lValue * 10 + lNextDigit;            
        }
        else
        {            
            return DRM_E_ARITHMETIC_OVERFLOW;
        }
        wszString.pwszString++;
        wszString.cchString--;
    }

    if( lValue & 0x80000000 )
    {
        /* The high bit is set.  */
        if( lValue == 0x80000000 && !fPositive )
        {
            /* Special case */
            *plValue = lValue;
        }
        else
        {
            /* This is fine for an unsigned long, but means we really have overflowed to return a signed long */
            return DRM_E_ARITHMETIC_OVERFLOW;
        }       
    }
    else    
    {
        *plValue = lValue;
        if( !fPositive )
        {
           *plValue *= -1;
        }
    }

    return DRM_SUCCESS;
}

DRM_BOOL DRM_API DRMCRT_iswspace (DRM_WCHAR wch)
{
    return (NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchTab)
         || NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchLineFeed)
         || NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchVerticalTab)
         || NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchFormFeed)
         || NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchCarriageReturn)
         || NATIVE_WCHAR(wch) == NATIVE_WCHAR(g_wchSpace));
}

DRM_DWORD DRM_API DRMCRT_wcslen(
    IN const DRM_WCHAR *wsz )
{
    const DRM_WCHAR *eos = wsz;
	while( *((DRM_WCHAR *)eos++) ) ;
    return  ( (DRM_DWORD)((DRM_WCHAR*)eos - (DRM_WCHAR*)wsz - 1));
}

DRM_WCHAR* DRM_API DRMCRT_wcsncpy( 
    OUT      DRM_WCHAR *wszDestination,
    IN const DRM_WCHAR *wszSource,
    IN       DRM_DWORD  cchMax )
{
    DRM_WCHAR *ret = wszDestination;    

    while (cchMax > 0) 
    {
        /* copy string */
        *wszDestination = *wszSource;
	++wszDestination;
	++wszSource;

        if ( *(wszDestination - 1) == 0)
        {
            break;
        }
        
        cchMax--;
    }

    if (cchMax > 0)
    {
        /* pad out with zeros */
        while (--cchMax)
        {
            *wszDestination++ = g_wchNull;
        }
    }
    return ret;
}


/***
*memmove - Copy source buffer to destination buffer
*
*Purpose:
*       memmove() copies a source memory buffer to a destination memory buffer.
*       This routine recognize overlapping buffers to avoid propogation.
*       For cases where propogation is not a problem, memcpy() can be used.
*
*Entry:
*       void *dst = pointer to destination buffer
*       const void *src = pointer to source buffer
*       size_t count = number of bytes to copy
*
*Exit:
*       Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/

DRM_VOID * DRM_API DRMCRT_memmove (
    OUT      DRM_VOID  *dst,
    IN const DRM_VOID  *src,
    IN       DRM_DWORD count )
{
        DRM_VOID * ret = dst;

        if (dst <= src || (DRM_CHAR *)dst >= ((DRM_CHAR *)src + count)) {
                /*
                 * Buffers don't overlap in a way that would cause problems
                 * copy from lower addresses to higher addresses
                 */
                while (count--) {
                        *(DRM_CHAR *)dst = *(DRM_CHAR *)src;
                        dst = (DRM_CHAR *)dst + 1;
                        src = (DRM_CHAR *)src + 1;
                }
        }
        else {
                /*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */
                dst = (DRM_CHAR *)dst + count - 1;
                src = (DRM_CHAR *)src + count - 1;

                while (count--) {
                        *(DRM_CHAR *)dst = *(DRM_CHAR *)src;
                        dst = (DRM_CHAR *)dst - 1;
                        src = (DRM_CHAR *)src - 1;
                }
        }

        return(ret);
}

DRM_VOID DRM_API DRMCRT_memcpy(
       OUT   DRM_VOID  *dst,
    IN const DRM_VOID  *src,
    IN       DRM_DWORD  count )
{
    while( count > 0 )
    {
        *(DRM_BYTE*)dst = *(DRM_BYTE*)src;
        dst = (DRM_CHAR *)dst + 1;
        src = (DRM_CHAR *)src + 1;
        count--;
    }
}

DRM_VOID DRM_API DRMCRT_memset(
       OUT   DRM_VOID  *dst,
    IN       DRM_BYTE   b,
    IN       DRM_DWORD  count )
{
    while( count > 0 )
    {
        *(DRM_BYTE*)dst = b;
        dst = (DRM_CHAR *)dst + 1;
        count--;
    }
}

DRM_INT DRM_API DRMCRT_memcmp(
    IN const DRM_VOID  *src1,
    IN const DRM_VOID  *src2,
    IN       DRM_DWORD  count )
{
    while( count > 0 )
    {
        if( *(DRM_BYTE*)src1 > *(DRM_BYTE*)src2 )
        {
            return 1;
        }
        else if( *(DRM_BYTE*)src1 < *(DRM_BYTE*)src2 )
        {
            return -1;
        }
        src1 = (DRM_CHAR *)src1 + 1;
        src2 = (DRM_CHAR *)src2 + 1;
        count--;
    }
    return 0;
}

DRM_INT DRM_API DRMCRT_abs( DRM_INT number )
{
    return (number>=0 ? number : -number);
}
