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

//#include <stdlib.h>
// #include <ctype.h>
// #include <string.h>
#include "tclib.h"
#include "tstutils.h"

#include "drmcrt.h"
#include "drmbase64.h"
#include "oemimpl.h"
#include "tOEMIMP.h"


#define MAX_BUFF 3
DRM_BYTE* g_buf[MAX_BUFF];
DRM_BYTE g_bufUsed; /* This is a bitmap to denote g_buf usage. If bit i is 1, then PostTestCase will free g_buf[i]*/

#define COOKIECHAR 'k'

static DRM_BYTE *GetBuf(char *szIndex)
{
	if (szIndex) {
		int i = OEM_atoi(szIndex);
		if (i >= 0 && i < MAX_BUFF)
			return g_buf[i];
	}
	return NULL;
}

/* Allocate a global buffer
	argv[0]: the index to the buffer to be allocated, from 0 to MAX_BUFF - 1
	argv[1]: the buffer size, in bytes or wchars
	argv[2]: how to initialize the allocated buffer: NULL, EMPTY, RANDOM, COOKIE, literal strings
	argv[3]: optional, "Wide" when the buffer is used as array of WCHARs
*/
DRM_RESULT TestAllocBuffer(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	int index, cbBuf;
	DRM_BOOL fWide = FALSE;

	ChkArg(argc >= 3 && argv[0] && argv[1]);
	if (argc > 3 && argv[3] && !DX_VOS_StrCmp(argv[3], "Wide"))
		fWide = TRUE;
	
	index = OEM_atol(argv[0]);
	ChkArg(index >= 0 && index < MAX_BUFF);
	
	cbBuf = OEM_atoi(argv[1]);
	if (fWide)
		cbBuf *= sizeof(DRM_WCHAR);

	DX_VOS_MemFree(g_buf[index]);
	g_bufUsed |= (1<<index);
	ChkMem(g_buf[index] = (DRM_BYTE*)DX_VOS_MemMalloc(cbBuf));

	if (!argv[2] || !DX_VOS_StrCmp(argv[2], "COOKIE"))
		DX_VOS_MemSet(g_buf[index], argv[2]? COOKIECHAR: 0, cbBuf);
	else if (!DX_VOS_StrCmp(argv[2], "RANDOM")) {
		ChkDR(OEM_GenRandomBytes(g_buf[index], cbBuf));
	} else if (fWide)
		OEM_mbstowcs((DRM_WCHAR*)g_buf[index], argv[2], cbBuf / sizeof(DRM_WCHAR));
	else
		DX_VOS_FastMemCpy(g_buf[index], argv[2], cbBuf);

ErrorExit:
	return dr;
}

/* Compare the contents of two global buffers. Returns DRM_SUCCESS if they match.
	argv[0]: the index to the first buffer
	argv[1]: the index to the second buffer
*/
DRM_RESULT TestCompBuffer(long argc, char **argv)
{
	DRM_RESULT dr;
	DRM_BYTE *pb1, *pb2;
	DRM_DWORD len;

	ChkArg(argc == 3 && argv[2]);
	ChkArg(pb1 = GetBuf(argv[0]));
	ChkArg(pb2 = GetBuf(argv[1]));
	len = OEM_atol(argv[2]);
	dr = DX_VOS_MemCmp(pb1, pb2, len)? DRM_S_FALSE: DRM_SUCCESS;
ErrorExit:
	return dr;
}

/* Set a global buffer pointer to a memory location in another buffer
	argv[0]: the index to the target buffer to change
	argv[1]: the index to the source buffer as a base. If NULL, the target pointer is set to NULL.
	argv[2]: the offset in bytes from the base buffer
*/
DRM_RESULT TestSetBuffer(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	int iTarget, iSource;
	DRM_DWORD dwOffset;

	ChkArg(argc == 3 && argv[0] && argv[2]);
	
	iTarget = OEM_atoi(argv[0]);
	ChkArg(iTarget >= 0 && iTarget < MAX_BUFF);

	if (argv[1]) {
		iSource = OEM_atoi(argv[1]);
		ChkArg(iSource >= 0 && iSource < MAX_BUFF);

		dwOffset = OEM_atol(argv[2]);

		g_buf[iTarget] = g_buf[iSource] + dwOffset;
	} else
		g_buf[iTarget] = NULL;
ErrorExit:
	return dr;
}

static DRM_BOOL _memcmpwm(DRM_BYTE *pw, DRM_BYTE *pm, DRM_DWORD cch, DRM_BOOL fpwIsWide)
{
	DRM_BOOL ret;
	if (fpwIsWide) {
		DRM_WCHAR *wsz = NULL;
		DRM_DWORD cchwsz;

		cchwsz = OEM_mbstowcs(NULL,(const char *)pm, cch);
		wsz = (DRM_WCHAR*)DX_VOS_MemMalloc(cchwsz * sizeof(DRM_WCHAR));
		OEM_mbstowcs(wsz, (char *)pm, cch);
		ret = DX_VOS_MemCmp(pw, wsz, cchwsz * sizeof(DRM_WCHAR));
		DX_VOS_MemFree(wsz);
	} else
		ret = DX_VOS_MemCmp(pw, pm, cch);
	return ret;
}

/* Verify the content of a global buffer. Returns DRM_SUCCESS if the buffer matches the content.
	argv[0]: the index to the buffer to verify
	argv[1]: the size of the buffer to verify
	argv[2]: the content to be verify
	argv[3]: optional. If "Wide" then argv[2] is a wide string
*/
DRM_RESULT TestVerifyBuffer(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_BYTE *pBuf;
	DRM_BOOL fWide = FALSE;
	int cbBuf;
	
	ChkArg(argc >= 3 && argv[1]);

	if (argc > 3 && argv[3] && !DX_VOS_StrCmp(argv[3], "Wide"))
		fWide = TRUE;

	pBuf = GetBuf(argv[0]);
	cbBuf = OEM_atoi(argv[1]);

	if (!argv[2] && pBuf || (argv[2] && !pBuf)) {
		dr = DRM_S_FALSE;
		goto ErrorExit;
	}

	if (pBuf && argv[2] && _memcmpwm(pBuf,(DRM_BYTE*)argv[2], cbBuf, fWide))
		dr = DRM_S_FALSE;

ErrorExit:
	return dr;
}

/* Test API DRMCRT_memmove
	argv[0]: index to the target buffer.
	argv[1]: index to the source buffer.
	argv[2]: the size to move in bytes
*/
DRM_RESULT Test_API_DRMCRT_memmove(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_BYTE *pb1, *pb2;
	DRM_DWORD len;

	ChkArg(argc == 3 && argv[2]);
	pb1 = GetBuf(argv[0]);
	pb2 = GetBuf(argv[1]);
	len = OEM_atol(argv[2]);
	DRM_memmove(pb1, pb2, len);
ErrorExit:
	return dr;
}

/* Test API DRMCRT_wcsntol
	argv[0]: the string to convert to long.
	argv[1]: the expected long value.
*/
DRM_RESULT Test_API_DRMCRT_wcsntol(long argc, char **argv)
{
	DRM_RESULT dr;
	DRM_LONG lExpValue, lRetValue;
	DRM_CONST_STRING szIn;
	DX_VOS_MemSet(&szIn, 0, sizeof(szIn));

	ChkArg(argc == 2);
	MakeDRMString(&szIn, argv[0]);
	lExpValue = OEM_atol(argv[1]);

	ChkDR(DRMCRT_wcsntol(szIn.pwszString, szIn.cchString, &lRetValue));
	if (lRetValue != lExpValue)
		dr = DRM_S_FALSE;
ErrorExit:
	DX_VOS_MemFree((DRM_WCHAR*)szIn.pwszString);
	return dr;
}

/* Test API DRMCRT_strncmp. Returns DRM_SUCCESS if it returns expected value
	argv[0]: index to the first string
	argv[1]: index to the second string
	argv[2]: string length to compare, in chars
	argv[3]: expected return value: Positive, Negative or Zero
*/
DRM_RESULT Test_API_DRMCRT_strncmp(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_CHAR *sz1, *sz2;
	DRM_DWORD count;
	DRM_INT lRet;

	ChkArg(argc == 4 && argv[2] && argv[3]);
	sz1 = (DRM_CHAR*)GetBuf(argv[0]);
	sz2 = (DRM_CHAR*)GetBuf(argv[1]);
	count =OEM_atol(argv[2]);

	lRet = DRM_strncmp(sz1, sz2, count);
	if ((DX_VOS_StrCmp(argv[3], "Positive") || lRet <= 0) &&
		(DX_VOS_StrCmp(argv[3], "Negative") || lRet >= 0) &&
		(DX_VOS_StrCmp(argv[3], "Zero") || lRet != 0))
		dr = DRM_S_FALSE;
ErrorExit:
	return dr;
}

/* Test API DRMCRT_wcsncmp. Returns DRM_SUCCESS if it returns expected value
	argv[0]: index to the first string
	argv[1]: index to the second string
	argv[2]: string length to compare, in wchars
	argv[3]: expected return value: Positive, Negative or Zero
*/
DRM_RESULT Test_API_DRMCRT_wcsncmp(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_WCHAR *wsz1, *wsz2;
	DRM_DWORD count;
	DRM_INT lRet;

	ChkArg(argc == 4 && argv[2] && argv[3]);
	wsz1 = (DRM_WCHAR*)GetBuf(argv[0]);
	wsz2 = (DRM_WCHAR*)GetBuf(argv[1]);
	count = OEM_atol(argv[2]);

	lRet = DRMCRT_wcsncmp(wsz1, wsz2, count);
	if ((DX_VOS_StrCmp(argv[3], "Positive") || lRet <= 0) &&
		(DX_VOS_StrCmp(argv[3], "Negative") || lRet >= 0) &&
		(DX_VOS_StrCmp(argv[3], "Zero") || lRet != 0))
		dr = DRM_S_FALSE;
ErrorExit:
	return dr;
}

/* Test API DRMCRT_wcslen. Returns DRM_SUCCESS if the function returns the expected length.
	argv[0]: index to the wide string buffer
	argv[1]: the expected returned length
*/
DRM_RESULT Test_API_DRMCRT_wcslen(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_WCHAR *wsz;
	DRM_DWORD cchExpected;

	ChkArg(argc == 2 && argv[1]);
	wsz = (DRM_WCHAR*)GetBuf(argv[0]);
	cchExpected = OEM_atol(argv[1]);

	if (cchExpected != DRM_wcslen(wsz))
		dr = DRM_S_FALSE;
ErrorExit:
	return dr;
}

/* Test API DRMCRT_wcsncpy.
	argv[0]: index to the destination string buffer
	argv[1]: index to the source string buffer
	argv[2]: the length to copy, in wchars
*/
DRM_RESULT Test_API_DRMCRT_wcsncpy(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_WCHAR *wszDest, *wszSource;
	DRM_DWORD cchCopy;

	ChkArg(argc == 3 && argv[2]);
	ChkArg(wszDest = (DRM_WCHAR*)GetBuf(argv[0]));
	ChkArg(wszSource = (DRM_WCHAR*)GetBuf(argv[1]));
	cchCopy = OEM_atol(argv[2]);

	DRM_wcsncpy(wszDest, wszSource, cchCopy);
ErrorExit:
	return dr;
}

/* Test API DRMCRT_abs. Returns DRM_SUCCESS if the function returns the expected value.
	argv[0]: the number to pass to the DRMCRT_abs function
	argv[1]: the expected return value
*/
DRM_RESULT Test_API_DRMCRT_abs(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_INT lRet;
	ChkArg(argc == 2 && argv[0] && argv[1]);
	lRet = DRMCRT_abs(OEM_atoi(argv[0]));
	if (lRet != OEM_atoi(argv[1]))
		dr = DRM_S_FALSE;
ErrorExit:
	return dr;
}

/*
	Test these functions work the same as the CRT equivalents:
	DRMCRT_iswspace, DRMCRT_iswxdigit, DRMCRT_iswdigit, DRMCRT_iswalpha, DRMCRT_towlower
	argv[0]: the first wchar to test
	argv[1]: the last wchar to test
*/
DRM_RESULT Test_API_DRMCRT_isxxx(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
#if defined(WIN32) || defined (WIN_CE)
	DRM_WCHAR chFrom, chTo, chNow;
	ChkArg(argc == 2 && argv[0] && argv[1]);
	chFrom = (DRM_WCHAR)OEM_atol(argv[0]);
	chTo = (DRM_WCHAR)OEM_atol(argv[1]);
	for (chNow = chFrom; DRM_SUCCESS == dr && chNow < chTo; chNow++) {
		dr = DRM_S_FALSE;
		if (!DRM_iswspace(chNow) != !iswspace(chNow)) {
			Log("DRMCRT_iswspace", "DRMCRT_iswspace and iswspace returns different values for %d", chNow);
		} else if (!DRMCRT_iswxdigit(chNow) != !iswxdigit(chNow)) {
			Log("DRMCRT_iswxdigit", "DRMCRT_iswxdigit and iswxdigit returns different values for %d", chNow);
		} else if (!DRMCRT_iswdigit(chNow) != !iswdigit(chNow)) {
			Log("DRMCRT_iswdigit", "DRMCRT_iswdigit and iswdigit returns different values for %d", chNow);
		} else if (!DRMCRT_iswalpha(chNow) != !iswalpha(chNow)) {
			Log("DRMCRT_iswalpha", "DRMCRT_iswalpha and iswalpha returns different values for %d", chNow);
		} else if (DRMCRT_towlower(chNow) != towlower(chNow)) {
			Log("DRMCRT_towlower", "DRMCRT_towlower and towlower returns different values for %d", chNow);
		} else
			dr = DRM_SUCCESS;
	}
ErrorExit:
#endif	
	return dr;
}

/* Test API DRM_B64_Encode
	argv[0]: ANSI or WIDE
	argv[1]: index to the binary buffer to encode
	argv[2]: the binary buffer length
	argv[3]: index to the buffer to store the encoded string, can be NULL
	argv[4]: the initial value for the size of the encoded string
	argv[5]: the expected encoded string length
*/
DRM_RESULT Test_API_DRM_Base64Encode(long argc, char **argv)
{
	DRM_RESULT dr = DRM_E_FAIL;
	DRM_BYTE *pBuf = NULL;
	DRM_WCHAR *pwszEncoded = NULL;
	DRM_CHAR *pszEncoded = NULL;
	DRM_DWORD cchEncoded, cchMaxEncoded;

	ChkArg(argc == 6 && argv[0]);
	pBuf = GetBuf(argv[1]);
	if (argv[4])
		cchEncoded = cchMaxEncoded = OEM_atol(argv[4]);

	if (!DX_VOS_StrCmp(argv[0], "ANSI")) {
		pszEncoded = (DRM_CHAR*)GetBuf(argv[3]);
		ChkDR(DRM_B64_EncodeA(pBuf, OEM_atol(argv[2]), pszEncoded, argv[4]? &cchEncoded: NULL,0));
	} else {
		pwszEncoded = (DRM_WCHAR*)GetBuf(argv[3]);
		ChkDR(DRM_B64_EncodeW(pBuf, OEM_atol(argv[2]), pwszEncoded, argv[4]? &cchEncoded: NULL,0));
	}
	if (argv[4]) {
		if (argv[5] && cchEncoded !=(DRM_DWORD) OEM_atol(argv[5]))
			dr = DRM_S_FALSE;
		if (pwszEncoded && cchEncoded < cchMaxEncoded)
			pwszEncoded[cchEncoded] = 0;
		if (pszEncoded && cchEncoded < cchMaxEncoded)
			pszEncoded[cchEncoded] = 0;
	}

ErrorExit:
	return dr;
}

/* Test API DRM_B64_Decode
	argv[0]: ANSI or WIDE
	argv[1]: index to the encoded string, can be NULL
	argv[2]: the initial value for the size of the decoded binary buffer
	argv[3]: index to the buffer to store the decoded binary
	argv[4]: the dwFlag value passed to the function
	argv[5]: the expected decoded binary length, can be NULL
*/
DRM_RESULT Test_API_DRM_Base64Decode(long argc, char **argv)
{
	DRM_RESULT dr = DRM_E_FAIL;
	DRM_CONST_STRING wszSource;
	DRM_ANSI_CONST_STRING dastrSource  = EMPTY_DRM_STRING;
	DRM_SUBSTRING         dasstrSource = { 0 };
	DRM_DWORD cbDest;
	DRM_BYTE *pbDest;
	DRM_DWORD dwFlags;

	ChkArg(argc == 6 && argv[0]);

	if (argv[2])
		cbDest = OEM_atol(argv[2]);

	pbDest = GetBuf(argv[3]);
	dwFlags = OEM_atol(argv[4]);

	if (!DX_VOS_StrCmp(argv[0], "ANSI")) {
		if (dastrSource.pszString = (DRM_CHAR*)GetBuf(argv[1]))
		{
			dastrSource.cchString = DX_VOS_StrLen(dastrSource.pszString);
        }
        
       dasstrSource.m_ich = 0;
       dasstrSource.m_cch = dastrSource.cchString;
       
		dr = DRM_B64_DecodeA(
			argv [1] ?  dastrSource.pszString : NULL,
			argv [1] ? &dasstrSource          : NULL,
			argv [2] ? &cbDest                : NULL,
			pbDest, dwFlags);
	} else {
		if (wszSource.pwszString = (DRM_WCHAR*)GetBuf(argv[1]))
			wszSource.cchString = DRM_wcslen(wszSource.pwszString);

		dr = DRM_B64_DecodeW(
			argv[1]? &wszSource: NULL,
			argv[2]? &cbDest: NULL,
			pbDest, dwFlags);
	}

	if (argv[2] && argv[5] && cbDest !=(DRM_DWORD) OEM_atol(argv[5]))
		dr = DRM_S_FALSE;

ErrorExit:
	return dr;
}

/*	Test API DRM_UTL_DecodeKID
	argv[0]: KID string
	argv[1]: index to the buffer to store the decoded kid
*/
DRM_RESULT Test_API_DecodeKID(long argc, char **argv)
{
	DRM_RESULT dr;
	DRM_CONST_STRING dstrKID = {0};
	DRM_KID *pKID = NULL;
	ChkArg(argc == 2);

	MakeDRMString(&dstrKID, argv[0]);
	pKID = (DRM_KID*)GetBuf(argv[1]);

	ChkDR(DRM_UTL_DecodeKID(&dstrKID, pKID));
ErrorExit:
	DX_VOS_MemFree((DRM_WCHAR*)dstrKID.pwszString);
	return dr;
}

DRM_RESULT U_PreTestCase(long lTCID, char *strTCName)
{
	DX_VOS_MemSet(g_buf, 0, MAX_BUFF * sizeof(DRM_BYTE*));
	g_bufUsed = 0;
	return DRM_SUCCESS;
}

DRM_RESULT U_PostTestCase(long lTCID, char *strTCName)
{
	int i;
	for (i = 0; i < MAX_BUFF; i++)
		if ((g_bufUsed >> i) & 0x1)
			DX_VOS_MemFree(g_buf[i]);
	return DRM_SUCCESS;
}

static DRM_RESULT WrapTestRun(long lTCID, DRM_BOOL fPreTestRun)
{
	return DRM_SUCCESS;
}

/*
BEGIN_APIMAP(DRMUtilTest_ansi, "UtilTest") 
 	API_ENTRY(TestAllocBuffer)
	API_ENTRY(TestSetBuffer)
	API_ENTRY(TestCompBuffer)
	API_ENTRY(TestVerifyBuffer)
	API_ENTRY(Test_API_DRMCRT_memmove)
	API_ENTRY(Test_API_DRMCRT_wcsntol)
	API_ENTRY(Test_API_DRMCRT_strncmp)
	API_ENTRY(Test_API_DRMCRT_wcsncmp)
	API_ENTRY(Test_API_DRMCRT_wcslen)
	API_ENTRY(Test_API_DRMCRT_wcsncpy)
	API_ENTRY(Test_API_DRMCRT_abs)
	API_ENTRY(Test_API_DRMCRT_isxxx)
	API_ENTRY(Test_API_DRM_Base64Encode)
	API_ENTRY(Test_API_DRM_Base64Decode)
	API_ENTRY(Test_API_DecodeKID)
END_APIMAP
*/
