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

//#include <stdlib.h>
// #include <stdio.h>
// #include <string.h>
#include "DX_VOS_String.h"
#include "tstutils.h"
#include "drmcrt.h"
#include "oemimpl.h"
#include "drmxmlparser.h"
#include "tOEMIMP.h"


#ifdef WINCE_TEST
#include <winbase.h>
#endif


void DRM_API MakeDRMString(DRM_CONST_STRING *pwszStr, const char *szStr)
{
	#ifdef SIXTEEN_BIT_ADDRESSING
	int native_length = 0;
	DRM_SUBSTRING f_pad = {0};
	char *temp = NULL;
	DRM_NATIVE_BYTE *fnative = NULL;
	#endif
	
		
	
	if (szStr) {
		#ifdef SIXTEEN_BIT_ADDRESSING
			native_length = strlen(szStr);
			temp = OEM_malloc(CB_NATIVE_BYTE * (native_length + 1));
			strncpy(temp,szStr,(native_length+1));
			fnative = temp;
			
		
			/*We need packed representaion here. fnative could already have been in packed ansi format
			If it is not, we need to convert it to packed ansi format*/
			if ( (fnative[0] >> 8 ) == 0)
			{
				testDRM_16B_Pack8BitBytes(fnative,native_length+1,NULL,DRM_PACK_BYTES_IN_PLACE);
			}
			else
			{
				/*if it was initially in packed ansi, the length determined by strlen would be half the actual
				length, thus we double it here*/
				native_length = native_length * 2;
			}
			
			pwszStr->cchString = (DRM_DWORD)(native_length);
			pwszStr->pwszString = (const DRM_WCHAR*)OEM_malloc(CB_NATIVE_BYTE * native_length);
			f_pad.m_cch = native_length+1;
			f_pad.m_ich = 0;
		       /*Convert Ansi to UNICODE using the dev function rather than mbstowcs*/
			DRM_UTL_PromoteANSItoUNICODE((const DRM_CHAR *)temp,&f_pad,(DRM_STRING *)pwszStr);
			pwszStr->cchString = (DRM_DWORD)(native_length);
			SAFE_OEM_FREE(temp);
		#else
			pwszStr->cchString = (DRM_DWORD)OEM_mbstowcs(NULL, szStr, DX_VOS_StrLen(szStr));
			pwszStr->pwszString = (const DRM_WCHAR*)OEM_malloc((pwszStr->cchString + 1) * SIZEOF(DRM_WCHAR));
			OEM_mbstowcs((DRM_WCHAR*)pwszStr->pwszString, szStr, pwszStr->cchString + 1);
		#endif

	} 
	else
	{
		MEMSET(pwszStr, 0, SIZEOF(DRM_CONST_STRING));
	}
}

int DRM_API CompDRMString(DRM_CONST_STRING *pwszStr, const char *szStr)
{
	int iRet;
	DRM_CONST_STRING wsz;

	MakeDRMString(&wsz, szStr);
	iRet = DRM_wcsncmp(pwszStr->pwszString, wsz.pwszString, min(pwszStr->cchString, wsz.cchString));
	if (!iRet && pwszStr->cchString != wsz.cchString)
		iRet = (pwszStr->cchString > wsz.cchString)? 1: -1;

	OEM_free((void*)wsz.pwszString);
	return iRet;
}

int DRM_API CompWideString(const DRM_WCHAR *pwszStr, const char *szStr)
{
	DRM_CONST_STRING wsz;
	wsz.pwszString = pwszStr;
	wsz.cchString = DRM_wcslen(pwszStr);
	return CompDRMString(&wsz, szStr);
}

DRM_BOOL DRM_API LoadTestFileW(const DRM_WCHAR* pwszFolder, const DRM_WCHAR* pwszPath, DRM_BYTE **ppBuffer, DRM_DWORD *pSize)
{
	DRM_BOOL fRet = FALSE;
	OEM_FILEHDL hFile = OEM_INVALID_HANDLE_VALUE;
	DRM_WCHAR wcpath[256]; /* _MAX_PATH not ansi */
	DRM_DWORD cbRead;

	ZEROMEM(wcpath,256);
	
	if (!(pwszPath && ppBuffer && pSize))
		goto ErrorExit;
		

#ifdef WINCE_TEST
	if (pwszFolder)
        /*replacing swprintf , as swprintf may not be available on all platforms*/
		wcpath[0] = ONE_WCHAR('.','\0');
		wcpath[1] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[2], BASE_DIR);
		cbRead = DRM_wcslen(wcpath);
		wcpath[cbRead] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[cbRead+1], pwszFolder);
		cbRead = DRM_wcslen(wcpath);
		wcpath[cbRead] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[cbRead+1],pwszPath);
	else
        /*replacing swprintf , as swprintf may not be available on all platforms*/
		wcpath[0] = ONE_WCHAR('.','\0');
		wcpath[1] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[2], BASE_DIR);
		cbRead = DRM_wcslen(wcpath);
		wcpath[cbRead] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[cbRead+1], pwszFolder);
		cbRead = DRM_wcslen(wcpath);
		wcpath[cbRead] = ONE_WCHAR('\\','\0');
		OEM_wcscat(&wcpath[cbRead+1],pwszPath);
#else
	if (pwszFolder){
		#ifdef SIXTEEN_BIT_ADDRESSING
                     /*replacing swprintf by this code for 16-bit, as swprintf is not available on TI platform*/
			wcpath[0] = ONE_WCHAR('.','\0');
			wcpath[1] = ONE_WCHAR('\\','\0');
			OEM_wcscat(&wcpath[2], pwszFolder);
			cbRead = DRM_wcslen(wcpath);
			wcpath[cbRead] = ONE_WCHAR('\\','\0');
			OEM_wcscat(&wcpath[cbRead+1],pwszPath);
		#else
        /*replacing swprintf , as swprintf may not be available on all platforms*/
			wcpath[0] = ONE_WCHAR('.','\0');
			wcpath[1] = ONE_WCHAR(DX_VOS_PATH_DIVIDER[0],'\0');
			OEM_wcscat(&wcpath[2], pwszFolder);
			cbRead = DRM_wcslen(wcpath);
			wcpath[cbRead] = ONE_WCHAR(DX_VOS_PATH_DIVIDER[0],'\0');
			OEM_wcscat(&wcpath[cbRead+1],pwszPath);
		#endif
	}
	else{
		#ifdef SIXTEEN_BIT_ADDRESSING
                  /*Replacing wcscpy by wcsncpy as wcscpy is not available on TI platform*/
		    cbRead = DRM_wcslen(pwszPath);
		    DRM_wcsncpy(wcpath,pwszPath,cbRead + 1);
	       #else
		    cbRead = DRM_wcslen(pwszPath);
		    DRM_wcsncpy(wcpath,pwszPath,cbRead + 1);
		#endif
     	
		}
#endif /*if WINCE_TEST*/
	*pSize = 0;
	*ppBuffer = 0;

	hFile = OEM_OpenFile(wcpath, OEM_GENERIC_READ, OEM_FILE_SHARE_READ, OEM_OPEN_EXISTING, OEM_ATTRIBUTE_NORMAL);
	if (OEM_INVALID_HANDLE_VALUE == hFile)
		goto ErrorExit;

	if (!OEM_GetFileSize(hFile, pSize))
		goto ErrorExit;

	if (!(*ppBuffer = (DRM_BYTE*) OEM_malloc((*pSize) * 2 + SIZEOF(DRM_WCHAR))))
		goto ErrorExit;

	MEMSET(*ppBuffer, 0, SIZEOF(DRM_WCHAR) + *pSize);

	 if(!OEM_ReadFile(hFile, *ppBuffer, *pSize, &cbRead) || cbRead != *pSize)	
		goto ErrorExit;
	fRet = TRUE;
ErrorExit:
	if (hFile != OEM_INVALID_HANDLE_VALUE)
		OEM_CloseFile(hFile);
	return fRet;
}

DRM_BOOL DRM_API LoadTestFile(const DRM_CHAR* pszFolder, const DRM_CHAR* pszPath, DRM_BYTE **ppBuffer, DRM_DWORD *pSize)
{

	DRM_CONST_STRING dstrFolder = {0}, dstrPath = {0};
	DRM_BOOL fRet; 
	MakeDRMString(&dstrFolder, pszFolder);
	MakeDRMString(&dstrPath, pszPath);
		
	fRet = LoadTestFileW(dstrFolder.pwszString, dstrPath.pwszString, ppBuffer, pSize);
	OEM_free((DRM_VOID*)dstrFolder.pwszString);
	OEM_free((DRM_VOID*)dstrPath.pwszString);
	return fRet; 
	

}

DRM_BOOL DRM_API SaveToFileW(const DRM_WCHAR* pwszPath, DRM_BYTE *pbData, DRM_DWORD cbData)
{
	DRM_BOOL fRet = FALSE;
	OEM_FILEHDL hFile = OEM_INVALID_HANDLE_VALUE;
	DRM_DWORD cbWritten;

	if (!(pwszPath && pbData))
		goto ErrorExit;

	hFile = OEM_OpenFile(pwszPath, OEM_GENERIC_WRITE, OEM_FILE_SHARE_NONE, OEM_CREATE_ALWAYS, OEM_ATTRIBUTE_NORMAL);
	if (hFile == OEM_INVALID_HANDLE_VALUE)
		goto ErrorExit;

	if (!OEM_WriteFile(hFile, pbData, cbData, &cbWritten) || cbWritten != cbData)
		goto ErrorExit;
	fRet = TRUE;
ErrorExit:
	if (hFile != OEM_INVALID_HANDLE_VALUE)
		OEM_CloseFile(hFile);
	return fRet;
}

#ifdef WINCE_TEST
/*replace c remove function with win32 */
void remove(char* filename)
{
 	DRM_WCHAR wszHdsName[256]={0};
	OEM_mbstowcs(wszHdsName, filename, strlen(filename)+1);
	DeleteFile(wszHdsName);
}

/*replace c clock with win32. Return millseconds */
DRM_DWORD MyClock()
{
   return (DRM_DWORD)GetTickCount();
}
#endif


DRM_BOOL DRM_API IsDigitalOnlyString(char *p)
{
	if(!p)
		return FALSE;
	if (*p == '-')
		p++;
 	while(*p && OEM_isdigit((unsigned char)*p))
		p++;
	return !(*p);
}

static DRM_WORD     _dwDeviceStoreBlockSize=32768;
static DRM_HDSBLKNUM _eDeviceStoreBlockNumType=eDRM_HDSBLKNUM_DWORD;


/*	Allocates the hds context and opens the specific store. If fails, then *ppHds==NULL */
DRM_RESULT DRM_API OpenHDS(DRM_HDS_CONTEXT **ppHds, const DRM_WCHAR *pwszStorePath, DRM_BOOL fCreateNew)
{
	DRM_RESULT dr;
	DRM_BOOL fHdsInited = FALSE;

	ChkArg(ppHds);
	ChkMem(*ppHds = (DRM_HDS_CONTEXT*)OEM_malloc(SIZEOF(DRM_HDS_CONTEXT)));

	ChkDR(DRM_HDS_Init(*ppHds));
	fHdsInited = TRUE;

	dr = DRM_HDS_CreateStore(pwszStorePath, _dwDeviceStoreBlockSize, _eDeviceStoreBlockNumType, *ppHds, fCreateNew);
	if (fCreateNew || dr != DRM_E_HDSFILEEXISTS) {
		ChkDR(dr);
	}
    ChkDR(DRM_HDS_OpenStore(pwszStorePath, *ppHds));
ErrorExit:
	if (DRM_FAILED(dr) && ppHds && *ppHds) {
		if (fHdsInited)
			DRM_HDS_Uninit(*ppHds);
		SAFE_OEM_FREE(*ppHds);
		*ppHds = NULL;
	}
	return dr;
}

/* Close the hds store and release the context. *pHds is invalid after the call succeeds. */
DRM_RESULT DRM_API CloseHDS(DRM_HDS_CONTEXT *pHds)
{
	DRM_RESULT dr = DRM_SUCCESS;
	if (pHds) {
		ChkDR(DRM_HDS_CloseStore(pHds));
		ChkDR(DRM_HDS_Uninit(pHds));
		SAFE_OEM_FREE(pHds);
	}
ErrorExit:
	return dr;
}

/*	wszXML is <XX><DATA>...</DATA><SIGNATURE>...</SIGNATURE></XX> 
	This function verify the <DATA> section using the public key.
*/
DRM_RESULT DRM_API VerifyXMLDataSigature(DRM_CONST_STRING *pwszXML, DRM_CONST_STRING *pwszPubKey)
{
	DRM_RESULT dr;
	PUBKEY pubKey;
	DRM_DWORD dwSize;
	DRM_CONST_STRING wszSignature, wszData;
	DRM_CRYPTO_CONTEXT *pCrypto = NULL;

	ChkMem(pCrypto = (DRM_CRYPTO_CONTEXT*)OEM_malloc(SIZEOF(DRM_CRYPTO_CONTEXT)));

	dwSize = SIZEOF(PUBKEY);
	ChkDR(DRM_B64_DecodeW(pwszPubKey, &dwSize, (DRM_BYTE*)&pubKey, 0));

	ChkDR(DRM_XML_GetSubNodeByPath(pwszXML, &g_dstrXPathSigValue, NULL, NULL, NULL, &wszSignature, g_wchForwardSlash));

	ChkDR(DRM_XML_GetAndVerifySubNode(pwszXML, &g_dstrTagData, NULL, NULL, 0,
		pCrypto, &pubKey, TRUE, &wszSignature, &wszData, NULL, 1));
ErrorExit:
	SAFE_OEM_FREE(pCrypto);
	return dr;
}

/*offset time in seconds */
DRM_RESULT DRM_API tChangeSystemTime(long loffset)
{
	DRM_RESULT dr = DRM_SUCCESS;
 	DRMSYSTEMTIME tSysTime;
    DRMFILETIME  mcFileTime;
	DRM_UINT64 u64;

	if (!loffset)
		goto ErrorExit;

	OEM_GetDeviceTime(&mcFileTime);
	
	FILETIME_TO_UI64(mcFileTime, u64);
	if(loffset > 0)
		u64 = DRM_UI64Add(u64, DRM_UI64Mul(DRM_UI64(loffset), DRM_UI64(FILETIME_TO_SECONDS)));
	else
		u64 = DRM_UI64Sub(u64, DRM_UI64Mul(DRM_UI64(-loffset), DRM_UI64(FILETIME_TO_SECONDS)));
	UI64_TO_FILETIME(u64, mcFileTime);

	ChkArg(OEM_FileTimeToSystemTime(&mcFileTime, &tSysTime));
	OEM_SetSystemTime(&tSysTime);
ErrorExit:
	return dr;
}




