// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//


#define __INCLUDE_CAPABILITY_NAMES__

#if defined(_MSVCDOTNET__) || defined(__TOOLS2__)
#include <string>
#else //!__MSVCDOTNET__
#include <string.h>
#endif //__MSVCDOTNET__

#include <stdarg.h>
#include <stdlib.h>

#include <e32std.h>

#include "h_utl.h"

#ifdef __LINUX__
 
 // Convert the supplied string to uppercase, in-place 
 char* strupr(char *a)
    {
     char *ret = a;
 
    while (*a)
        {
        *a = toupper(*a);
        a++;
         }
 
     return ret;
     }
 
 off_t filelength(int filedes)
     {
     struct stat buf;
     if(!fstat(filedes, &buf))
         {
        return buf.st_size;
         }
    perror("fstat failed");
   return 0;
    }
 
#endif

TBool PVerbose=ETrue;

HPrint H;

HPrint::~HPrint()
	{
	iLogFile.close();
	}

void HPrint::SetLogFile(TText *aFileName)
	{
	iLogFile.open((const char *)aFileName);
	}


/**
Closing the logfile.(since 'n' number of drive images can be created)

@internalComponent
@released

*/
void HPrint::CloseLogFile()
	{
	if(iLogFile.is_open())
		iLogFile.close();
	}

TInt HPrint::PrintString(TPrintType aType,const char *aFmt,...)
//
// Print text, noting where to send it.
//
	{

	TInt r=KErrNone;
	va_list list;
	va_start(list,aFmt);
	_vsnprintf((char *)iText,KMaxStringLength,aFmt,list);
	va_end(list);
	switch (aType)
		{
	case EAlways:
		cout << iText;
		iLogFile << iText;
		break;
	case EScreen:
		cout << iText;
		break;
	case ELog:
		if (iVerbose)
			cout << iText;
		iLogFile << iText;
		break;
	case EWarning:
		cerr << "WARNING: " << iText;
		iLogFile << "WARNING: "<<iText;
		break;
	case EError:
		cerr << "ERROR: " << iText;
		iLogFile << "ERROR: " << iText;
		r=KErrGeneral;
		break;
	case EPeError:
		if (PVerbose)
			{
			cerr << "ERROR: " << iText;
			iLogFile << "ERROR: " << iText;
			}
		r=KErrGeneral;
		break;
	case ESevereError:
		cerr << "ERROR: " << iText;
		iLogFile << "ERROR: " << iText;
		r=KErrGeneral;
		break;
	case EDiagnostic:
		cerr << "DIAGNOSTIC MESSAGE: " << iText;
		iLogFile << "DIAGNOSTIC MESSAGE: "<<iText;
		break;
	default:
		cerr << "ERROR: Invalid print type" << endl;
		r=KErrGeneral;
		}
	cout.flush();
	iLogFile.flush();
	return r;
    }

TVersion::TVersion()
	{}
TVersion::TVersion(TInt aMajor, TInt aMinor, TInt aBuild)
	: iMajor((TInt8)aMajor), iMinor((TInt8)aMinor), iBuild((TInt16)aBuild)
	{}
#ifdef __TOOLS2__
istringstream &operator>>(istringstream &is, TVersion &aVersion)
#else
istrstream &operator>>(istrstream &is, TVersion &aVersion)
#endif
//
// Input a TVersion with syntax: major[.minor][(build)]
//	
	{
#ifdef __TOOLS2__
string tmp = is.str();
const char *str=tmp.c_str();
#else
#ifdef __LINUX__
    char *str = is.rdbuf()->str();
#else
    char *str=is.str();
#endif
#endif


	TInt build=0;
	memset(&aVersion, sizeof(TVersion), 0);	
	TInt i;
	TInt len=strlen(str);
	for (i=0; i<len; i++)
		if (str[i]=='(')
			break;
	if (i<len)
		build=atoi(str+i+1);
	aVersion.iMajor = (TInt8)Min(KMaxTInt8, atoi(str));
	int majorV = atoi(str);
	// iMajor is defined as TInt8 so it should not be bigger than 127
	if (majorV > 127)
		{ 
		cout << "\n Warning: major version must be in range 0 - 127 \n";
		}
	char* pMinor = strchr(str, '.');
	if (pMinor)
		{
		pMinor++; 
		aVersion.iMinor = (TInt8)Min(KMaxTInt8, atoi(pMinor));
		int minorV = atoi(pMinor);
		// iMinor is defined as TInt8 so it should not be bigger than 127
		if (minorV > 127)
			{ 
			cout << "\n Warning: minor version must be in range 0 - 127 \n";
			}
		}	
	aVersion.iBuild=(TInt16)build;
	return is;
	}

TInt Locate(const char *aString, char aChar)
//
// Locate aChar in aString
//
	{

	if (aString==NULL)
		return KErrNotFound;
	TInt i=0;
	while (*aString!=0)
		{
		if (*aString==aChar)
			return i;
		aString++;
		i++;
		}
	return KErrNotFound;
	}


#define KHoursToMicroSeconds	Int64(3600000000UL) 
#define KDaysToMicroSeconds		(Int64(24)*KHoursToMicroSeconds)
const TInt KMinutesToMicroSeconds = 60000000;
const TInt KSecondsToMicroSeconds =  1000000;

const TInt8 mTab[2][12]=
    {
    {31,28,31,30,31,30,31,31,30,31,30,31}, // 28 days in Feb
    {31,29,31,30,31,30,31,31,30,31,30,31}  // 29 days in Feb
    };

TInt Time::LeapYearsUpTo(TInt aYear)
//
// from 0AD to present year according to the rule above
//
	{

	if (aYear<=0)
		return(aYear/4);
	if (aYear<=1600)
		return(1+((aYear-1)/4));
	TInt num=401; // 1600/4+1
	aYear-=1601;
	num+=(aYear/4-aYear/100+aYear/400);
	return(num);
	}

TBool Time::IsLeapYear(TInt aYear)
//
// up to and including 1600 leap years were every 4 years,since then leap years are every 4 years unless
// the year falls on a century which is not divisible by 4 (ie 1900 wasnt,2000 will be)
// for simplicity define year 0 as a leap year
//
	{

	if (aYear>1600)
    	return(!(aYear%4) && (aYear%100 || !(aYear%400)));
	return(!(aYear%4));
	}


Int64 ConvertTime(TInt aDay, TInt aMonth, TInt aYear, TInt aHour, TInt aMinute, TInt aSecond, TInt aMilliSeconds)
//
// converts TDateTime into a TTime, doesnt check for overflows
//
	{
	
	TInt days=365*aYear+Time::LeapYearsUpTo(aYear);
	TBool isleap=Time::IsLeapYear(aYear);
	for (TInt ii=0; ii<aMonth; ii++)
	    days+=(mTab[isleap][ii]);	
	days+=aDay;
	TInt sum=aMilliSeconds+aSecond*KSecondsToMicroSeconds;
	return((Int64(days)*KDaysToMicroSeconds+Int64(aHour)*KHoursToMicroSeconds) 
			+(Int64(KMinutesToMicroSeconds)*Int64(aMinute)+Int64(sum))); 
	}
	
TInt StringToTime(Int64 &aTime, char *aString)
//
// Convert string to time. String is in the format:
//
// dd/mm/yyyy hh:mm:ss.mmmmmmm
//
	{
	TInt day=1;
	TInt month=1;
	TInt year=1997;
	TInt hour=10;
	TInt minute=10;
	TInt sec=0;
	TInt mill=0;
	char ch;
	#ifdef __TOOLS2__
	istringstream val(aString);
	#else
	istrstream val(aString,strlen(aString));
	#endif
	val >> dec >> day; // locks istrstream in decimal mode for further extractions
	val >> ch;
	if (ch!='/')
		return KErrGeneral;
	val >> month;
	val >> ch;
	if (ch!='/')
		return KErrGeneral;
	val >> year;
	val >> ch;

	if (ch=='_')
		{
		// time too.
		val >> hour;
		val >> ch;
		if (ch!=':')
			return KErrGeneral;
		val >> minute;
		val >> ch;
		if (ch!=':')
			return KErrGeneral;
		val >> sec;
		val >> ch;
		if (ch=='.')
			{
			val >> mill;
			}
		}

	if (day<1 || day>31)
		return KErrArgument;
	if (month<1 || month>12)
		return KErrArgument;
	if (year<1970 || year>2060)
		return KErrArgument;
	if (hour<0 || hour>23)
		return KErrArgument;
	if (minute<0 || minute>59)
		return KErrArgument;
	if (sec<0 || sec>59)
		return KErrArgument;
	if (mill<0 || mill>999999)
		return KErrArgument;

	aTime=ConvertTime(day-1, month-1, year, hour, minute, sec, mill);
	return KErrNone;
	}

void ByteSwap(TUint &aVal)
	{
	TUint t0=aVal & 0xff;
	TUint t1=(aVal>>8)  & 0xff;
	TUint t2=(aVal>>16) & 0xff;
	TUint t3=aVal>>24;
	aVal=(t0 << 24) | (t1 << 16) | (t2 << 8) | (t3);
	}

void ByteSwap(TUint16 &aVal)
	{
	TUint16 t0=(TUint16)((aVal >> 8) & 0xff);
	TUint16 t1=(TUint16)(aVal & 0xff);
	aVal=(TUint16)((t1 << 8) | t0);
	}

void ByteSwap(TUint *aPtr, TInt aSize)
	{

	while ((aSize-=4)>=0)
		ByteSwap(*aPtr++);
	}

TBool IsBracketedHex(const char* s, const char* brackets, TInt digits, TUint32& aValue)
	{
	if (s[0]!=brackets[0] || s[1+digits]!=brackets[1])
		return EFalse;
	TInt i;
	TUint32 x = 0;
	for (i=1; i<=digits; ++i)
		{
		TInt c = s[i];
		if (c>='a' && c<='z') c-=32;
		if (c<'0' || (c>'9' && c<'A') || c>'F')
			return EFalse;
		c-='0';
		if (c>9) c-=7;
		x = (x<<4) | (TUint32)c;
		}
	aValue = x;
	return ETrue;
	}

TInt CheckForDecimalVersion(const char* begin, const char* s, TUint32& aValue)
	{
	aValue = 0;
	if (s <= begin || *s != '}')
		return 0;
	TUint32 v[2] = {0,0};
	TUint32 m = 1;
	TInt pos = 0;
	const char* s0 = s + 1;
	for (--s; s >= begin; --s)
		{
		int c = *s;
		if (c >= '0' && c <= '9')
			{
			v[pos] += m * (c - '0');
			if (v[pos] >= 65536u)
				return 0;
			m *= 10;
			}
		else if (c == '.')
			{
			m = 1;
			if (++pos >= 2)
				return 0;
			}
		else if (c == '{')
			break;
		else
			return 0;
		}
	if (s < begin)
		return 0;
	aValue = (v[1] << 16) | v[0];
	return s0 - s;
	}

// Decompose a name of the form NAME{MMMMmmmm}[UUUUUUUU].EXT where the bracketed
// sections and extension are both optional.
// Return a newly malloc-ed string containing NAME.EXT
// Set aUid = 0xUUUUUUUU if present, 0 if not
// Set aModuleVersion = 0xMMMMmmmm if present, 0 if not
// Set aFlags according to which of these are present
char* SplitFileName(const char* aName, TUint32& aUid, TUint32& aModuleVersion, TUint32& aFlags)
	{
	TFileNameInfo f(aName, ETrue);
	aUid = f.iUid3;
	aModuleVersion = f.iModuleVersion;
	aFlags = f.iFlags;
	TInt nl = f.iBaseLength;
	TInt el = f.iTotalLength - f.iExtPos;
	TInt tl = nl + el;
	char* t = (char*)malloc(tl + 1);
	if (t)
		{
		memcpy(t, aName, nl);
		if (el)
			memcpy(t + nl, aName + f.iExtPos, el);
		t[tl] = 0;
		}
	return t;
	}


// Decompose a name of the form NAME{MMMMmmmm}.EXT where the bracketed
// sections and extension are both optional.
// Return a newly malloc-ed string containing NAME.EXT
// Set aModuleVersion = 0xMMMMmmmm if present, 0 if not
// Set aFlags according to whether version present
char* SplitFileName(const char* aName, TUint32& aModuleVersion, TUint32& aFlags)
	{
	TFileNameInfo f(aName, EFalse);
	aModuleVersion = f.iModuleVersion;
	aFlags = f.iFlags;
	TInt nl = f.iBaseLength;
	TInt el = f.iTotalLength - f.iExtPos;
	TInt tl = nl + el;
	char* t = (char*)malloc(tl + 1);
	if (t)
		{
		memcpy(t, aName, nl);
		if (el)
			memcpy(t + nl, aName + f.iExtPos, el);
		t[tl] = 0;
		}
	return t;
	}


// Parse a filename and convert decimal version number to hex
char* NormaliseFileName(const char* aName)
{
	//convert forward slashes into back slashes.
	char* filename = strdup(aName);  //prevent violated access from stack.
	char* fwdslashfinder = filename;
	fwdslashfinder=strstr(fwdslashfinder, "/");
	while(fwdslashfinder)
	  {
		*fwdslashfinder++ = '\\';
		fwdslashfinder=strstr(fwdslashfinder, "/");
	  }

	//normalize filename.
	TFileNameInfo f(filename, EFalse);
	TInt nl = f.iBaseLength;
	TInt el = f.iTotalLength - f.iExtPos;
	TInt tl = nl + el;
	if (f.iFlags & EVerPresent)
		tl += 10;
	char* t = (char*)malloc(tl + 1);
	if (t)
		{
		memcpy(t, filename, nl);
		if (f.iFlags & EVerPresent)
			sprintf(t + nl, "{%08lx}%s", f.iModuleVersion, filename + f.iExtPos);
		else if (el)
			memcpy(t + nl, filename + f.iExtPos, el);
		t[tl] = 0;
		}
	free(filename);

	return t;
}

TFileNameInfo::TFileNameInfo(const char* aFileName, TBool aLookForUid)
	{
	iFileName = aFileName;
	TInt l = strlen(aFileName);
	iTotalLength = l;
	TInt remain = l;
	iFlags = 0;
	iUid3 = 0;
	iModuleVersion = 0;
	iBaseLength = l;
	iExtPos = l;
	const char* s = iFileName + l;
	for (; s>=iFileName && *s!='.' && *s!='}' && (!aLookForUid || *s!=']'); --s) {}
	if (s<iFileName)
		return;
	if (*s == '.')
		{
		iExtPos = s - iFileName;
		if (iExtPos == 0)
			{
			iBaseLength = 0;
			return;
			}
		remain = iExtPos;
		--s;
		}
	else if (s != iFileName + l)
		return;
	if (aLookForUid && remain>=10 && IsBracketedHex(s-9, "[]", 8, iUid3))
		{
		iFlags |= EUidPresent;
		remain -= 10;
		s -= 10;
		}
	if (remain>=10 && IsBracketedHex(s-9, "{}", 8, iModuleVersion))
		{
		iFlags |= EVerPresent;
		remain -= 10;
		s -= 10;
		}
	else
		{
		TInt n = CheckForDecimalVersion(iFileName, s, iModuleVersion);
		if (n>0)
			{
			iFlags |= EVerPresent;
			remain -= n;
			s -= n;
			}
		}
	iBaseLength = remain;
	}


#define PARSE_CAPABILITIES_ERROR(aMessage) Print(EError, "%s\n",aMessage)
#define PARSE_CAPABILITIES_ERROR2(aMessage1,aMessage2) Print(EError, "%s%s\n",aMessage1,aMessage2)

TInt ParseCapabilitiesArg(SCapabilitySet& aCapabilities, const char *aText)
//
// This is a cun'n'paste copy of the function in BASE\WINS\SPECIFIC\PROPERTY.CPP
// Keep both of these versions up to date with each other
//
	{
	memset(&aCapabilities,0,sizeof(aCapabilities));
	char c;
	while((c=*aText)!=0)
		{
		if(c<=' ')
			{
			++aText;
			continue;
			}
		int invert=0;
		if(c=='+')
			{
			++aText;
			c=*aText;
			}
		if(c=='-')
			{
			invert=1;
			++aText;
			}
		const char* name = aText;
		while((c=*aText)>' ')
			{
			if(c=='-' || c=='+')
				break;
			++aText;
			}
		TUint n = aText-name; 
		TInt i; 

		if(n==3 && strnicmp("all",name,n)==0)
			{
			if(invert)
				{
				PARSE_CAPABILITIES_ERROR("Capability '-ALL' not allowed");
				return KErrArgument;
				}
			for(i=0; i<ECapability_Limit; i++)
				{
				if(CapabilityNames[i])
					aCapabilities[i>>5] |= (1<<(i&31));
				}
			continue;
			}

		if(n==4 && strnicmp("none",name,n)==0)
			{
			if(invert)
				{
				PARSE_CAPABILITIES_ERROR("Capability '-NONE' not allowed");
				return KErrArgument;
				}
			memset(&aCapabilities,0,sizeof(aCapabilities));
			continue;
			}

		for(i=0; i<ECapability_Limit; i++)
			{
			const char* cap = CapabilityNames[i];
			if(!cap)
				continue;
			if((TUint)strlen(cap)!=n) 
				continue;
			if(strnicmp(cap,name,n)!=0)
				continue;
			break;
			}
		if(i>=ECapability_Limit)
			{
			char badName[32];
			if(n>=sizeof(badName)) n=sizeof(badName)-1;
			memcpy(badName,name,n);
			badName[n]=0;
			PARSE_CAPABILITIES_ERROR2("Unrecognised capability name: ",badName);
			return KErrArgument;
			}
		if(invert)
			aCapabilities[i>>5] &= ~(1<<(i&31));
		else
			aCapabilities[i>>5] |= (1<<(i&31));
		}
	return KErrNone;
	}

TInt ParseBoolArg(TBool& aValue, const char *aText)
	{
	if (_stricmp(aText, "on")==0 || _stricmp(aText, "yes")==0 || _stricmp(aText, "1")==0 || strlen(aText)==0)
		{
		aValue = ETrue;
		return KErrNone;
		}
	if (_stricmp(aText, "off")==0 || _stricmp(aText, "no")==0 || _stricmp(aText, "0")==0 )
		{
		aValue = EFalse;
		return KErrNone;
		}
	Print(EError, "Expected a boolean on/off value but found %s\n",aText);
	return KErrArgument;
	}
