os/boardsupport/emulator/emulatorbsp/specific/property.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
parent 0 bde4ae8d615e
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // wins\specific\property.cpp
    15 // Emulator property management for emulator settings
    16 // 
    17 //
    18 
    19 #define _CRTIMP			// we want to use the static runtime library
    20 
    21 #define __INCLUDE_CAPABILITY_NAMES__
    22 #include "variant.h"
    23 #include <string.h>
    24 #include <stdlib.h>
    25 #include <emulator.h>
    26 
    27 #ifdef _DEBUG
    28 #define _DUMP_PROPERTY
    29 #endif
    30 
    31 
    32 //SL: added this to support relative paths
    33 #include <stdio.h>
    34 #ifdef WIN32
    35 #include <direct.h>
    36 #define GetCurrentDir _getcwd
    37 #define FullPath _fullpath
    38 #else
    39 #include <unistd.h>
    40 #define GetCurrentDir getcwd
    41 #define FullPath fullpath
    42 #endif
    43 
    44 
    45 
    46 const char* KDefaultMachineName = "epoc";
    47 const char* KDefaultTestMachineName = "defaulttest";
    48 
    49 // name of the environment variable to check for default path
    50 const char* KDefaultEpocRootName = "EPOCROOT";
    51 
    52 TInt ScreenId=0;
    53 
    54 // At the point this is created there is no kernel heap available
    55 // So all memory allocation is done from a custom allocator
    56 
    57 const TInt KMaxTokenLength = 255;
    58 
    59 class Allocator
    60 	{
    61 	enum {ETotalMemory=0x10000};	// 64K
    62 public:
    63 	Allocator();
    64 	TAny* Alloc(TInt aSize);
    65 	TAny* Realloc(TAny* aCell, TInt aSize);
    66 	void Free(TAny* aCell);
    67 private:
    68 	TUint iBuf[ETotalMemory];
    69 	TUint* iFree;
    70 	};
    71 
    72 Allocator::Allocator()
    73 	:iFree(iBuf)
    74 	{}
    75 
    76 TAny* Allocator::Alloc(TInt aSize)
    77 	{
    78 	aSize = (aSize + 7) >> 2;
    79 	if (iFree + aSize > iBuf + ETotalMemory)
    80 		return NULL;
    81 	TUint* p = iFree;
    82 	iFree += aSize;
    83 	*p++ = aSize;
    84 	return p;
    85 	}
    86 
    87 TAny* Allocator::Realloc(TAny* aCell, TInt aSize)
    88 	{
    89 	if (!aCell)
    90 		return Alloc(aSize);
    91 
    92 	TUint* p = (TUint*)aCell;
    93 	TInt size = *--p;
    94 	if (iFree == p + size)
    95 		{
    96 		aSize = (aSize + 7) >> 2;
    97 		if (p + aSize > iBuf + ETotalMemory)
    98 			return NULL;
    99 		iFree = p + aSize;
   100 		*p = aSize;
   101 		return aCell;
   102 		}
   103 
   104 	TAny* newp = Alloc(aSize);
   105 	if (newp)
   106 		{
   107 		memcpy(newp, aCell, size*sizeof(TUint));
   108 		Free(aCell);
   109 		}
   110 	return newp;
   111 	}
   112 
   113 void Allocator::Free(TAny* )
   114 	{
   115 	}
   116 
   117 Allocator TheAllocator;
   118 
   119 ///////
   120 
   121 char* Duplicate(const char* aString)
   122 	{
   123 	if (aString == NULL)
   124 		aString = "";
   125 
   126 	TInt size = strlen(aString) + 1;
   127 	char* p = (char*)TheAllocator.Alloc(size);
   128 	if (p)
   129 		memcpy(p, aString, size);
   130 	return p;
   131 	}
   132 
   133 // Properties class implementation
   134 
   135 Properties::Properties()
   136 	:iEntries(NULL),iCount(0),iSize(0)
   137 	{}
   138 
   139 const char* Properties::Insert(TInt aIndex, const char* aProperty, const char* aValue)
   140 	{
   141 	if (iCount == iSize)
   142 		{
   143 		TInt size = iSize == 0 ? 8 : iSize*2;
   144 		TAny* array = TheAllocator.Realloc(iEntries, size*sizeof(SEntry));
   145 		if (array == NULL)
   146 			return NULL;
   147 		iEntries = (SEntry*)array;
   148 		iSize = size;
   149 		}
   150 
   151 	char* prop = Duplicate(aProperty);
   152 	if (prop == NULL)
   153 		return NULL;
   154 	char* value = Duplicate(aValue);
   155 	if (value == NULL)
   156 		TheAllocator.Free(prop);
   157 	else
   158 		{
   159 		SEntry* e = &iEntries[aIndex];
   160 		memmove(e+1, e, (iCount-aIndex)*sizeof(SEntry));
   161 		e->iProperty = prop;
   162 		e->iValue = value;
   163 		++iCount;
   164 		}
   165 	return value;
   166 	}
   167 
   168 const char* Properties::Replace(const char* aProperty, const char* aValue)
   169 	{
   170 	TInt ix = Find(aProperty);
   171 	if (ix < 0)
   172 		return Insert(~ix, aProperty, aValue);
   173 	// replacing a property
   174 	SEntry& e = iEntries[ix];
   175 	char* value = Duplicate(aValue);
   176 	if (value != NULL)
   177 		{
   178 		TheAllocator.Free(e.iValue);
   179 		e.iValue = value;
   180 		}
   181 	return value;
   182 	}
   183 
   184 const char* Properties::Append(const char* aProperty, const char* aValue)
   185 	{
   186 	TInt ix = Find(aProperty);
   187 	if (ix < 0)
   188 		return Insert(~ix, aProperty, aValue);
   189 
   190 	// append a property
   191 	SEntry& e = iEntries[ix];
   192 	TInt size = strlen(e.iValue) + strlen(aValue) + 2;
   193 	char* value = (char*)TheAllocator.Realloc(e.iValue, size);
   194 	if (value != NULL)
   195 		{
   196 		strcat(value, ";");
   197 		strcat(value, aValue);
   198 		e.iValue = value;
   199 		}
   200 	return value;
   201 	}
   202 
   203 TInt Properties::GetString(const char* aProperty, const char*& aValue) const
   204 	{
   205 	TInt ix = Find(aProperty);
   206 	if (ix < 0)
   207 		return KErrNotFound;
   208 	aValue = iEntries[ix].iValue;
   209 	return KErrNone;
   210 	}
   211 
   212 TInt Properties::GetInt(const char* aProperty, TInt& aValue) const
   213 	{
   214 	TInt ix = Find(aProperty);
   215 	if (ix < 0)
   216 		return KErrNotFound;
   217 	char* value = iEntries[ix].iValue;
   218 	char* end;
   219 	TBool neg = *value=='-';
   220 	value += neg;
   221 	long val = strtoul(value, &end, 0);
   222 	if(neg)
   223 		{
   224 		if(val<0)
   225 			return KErrArgument;
   226 		val = -val;
   227 		}
   228 	if (*end != '\0')
   229 		return KErrArgument;
   230 	aValue = val;
   231 	return KErrNone;
   232 	}
   233 
   234 TInt Properties::GetBool(const char* aProperty, TBool& aValue, TBool aDefaultValue) const
   235 	{
   236 	TInt ix = Find(aProperty);
   237 	if (ix < 0)
   238 		{
   239 		aValue = aDefaultValue;
   240 		return KErrNone;
   241 		}
   242 	const char* value=iEntries[ix].iValue;
   243 	if (_stricmp(value, "on")==0 || _stricmp(value, "yes")==0 || _stricmp(value, "1")==0 || strlen(value)==0)
   244 		{
   245 		aValue = ETrue;
   246 		return KErrNone;
   247 		}
   248 	if (_stricmp(value, "off")==0 || _stricmp(value, "no")==0 || _stricmp(value, "0")==0 )
   249 		{
   250 		aValue = EFalse;
   251 		return KErrNone;
   252 		}
   253 
   254 	// Bool property has an illegal value!
   255 	return KErrArgument;
   256 	}
   257 
   258 TInt Properties::Find(const char* aProperty) const
   259 //
   260 // Lookup a property in the table
   261 // return index (>=0) if found, ~insertion-point (<0) if not
   262 //
   263 	{
   264 	TInt l = 0, r = iCount;
   265 	while (l < r)
   266 		{
   267 		TInt m = (l + r) >> 1;
   268 		const SEntry& e = iEntries[m];
   269 		TInt k = _stricmp(aProperty,e.iProperty);
   270 		if (k < 0)
   271 			r = m;
   272 		else if (k > 0)
   273 			l = m + 1;
   274 		else
   275 			return m;
   276 		}
   277 	return ~l;
   278 	}
   279 
   280 #ifdef _DUMP_PROPERTY
   281 void Properties::Dump() const
   282 	{
   283 	for (TInt i = 0; i < iCount; ++i)
   284 		{
   285 		const SEntry& e = iEntries[i];
   286 		char buf[512];
   287 		strcpy(buf, e.iProperty);
   288 		TInt len = strlen(e.iValue);
   289 		if (len)
   290 			{
   291 			strcat(buf, " = ");
   292 			if (len <= 256)
   293 				strcat(buf, e.iValue);
   294 			else
   295 				{
   296 				strncat(buf, e.iValue, 256);
   297 				strcat(buf, "...");
   298 				}
   299 			}
   300 		strcat(buf, "\r\n");
   301 		OutputDebugStringA(buf);
   302 		}
   303 	}
   304 #endif
   305 
   306 // Property related variant functions
   307 
   308 TInt Wins::EmulatorHal(TInt aFunction, TAny* a1, TAny* a2)
   309 	{
   310 	TInt r=KErrNone;
   311 	switch(aFunction)
   312 		{
   313 		case EEmulatorHalStringProperty:
   314 			return iProperties.GetString((const char*)a1,*(const char**)a2);
   315 		case EEmulatorHalIntProperty:
   316 			return iProperties.GetInt((const char*)a1,*(TInt*)a2);
   317 		case EEmulatorHalBoolProperty:
   318 			return iProperties.GetBool((const char*)a1,*(TBool*)a2);
   319 		case EEmulatorHalMapFilename:
   320 			return MapFilename(*(const TDesC*)a1,*(TDes*)a2);
   321 		case EEmulatorHalSetFlip:
   322 			{
   323 			if (iUi)
   324 				{
   325 				TInt screen = (TInt)a2;
   326 				if((TUint)screen < (TUint)iUi->NumberOfScreens())
   327 					return iUi->SetFlip(TEmulatorFlip(TInt(a1)),screen);
   328 				}
   329 			break;
   330 			}
   331 		case EEmulatorHalColorDepth:
   332 			{
   333 			TUint colorDepth = KDefaultColorDepth;
   334 			if(iUi)
   335 				{
   336 				if((TUint)a2 < (TUint)iUi->NumberOfScreens())
   337 					colorDepth = iUi->ColorDepth((TInt)a2);
   338 				}
   339 			*(TUint*)a1 = colorDepth;
   340 			return KErrNone;
   341 			}
   342 		case EEmulatorHalCPUSpeed:
   343 			if (a1)
   344 				return SetCpuSpeed(TUint(a2)/1000);
   345 			*(TInt*)a2 = iCpuSpeed ? iCpuSpeed * 1000 : 1;
   346 			return KErrNone;
   347 		case EEmulatorHalNumberOfScreens:
   348 			*(TInt*)a2 = iUi ? iUi->NumberOfScreens() : 1;
   349 			return KErrNone;
   350 		case EEmulatorHalSetDisplayChannel:
   351 			if (iUi && (TUint)a1 < (TUint)iUi->NumberOfScreens())
   352 				{
   353 				r = iUi->SetDisplayChannel((TInt)a1, static_cast<DDisplayChannel*>(a2));
   354 				}
   355 			else
   356 				{
   357 				r = KErrNotSupported;
   358 				}
   359 			break;
   360 		default:
   361 			r=KErrNotSupported;
   362 			break;
   363 		}
   364 	return r;
   365 	}
   366 
   367 const char* KExtensionListNormal = "btracex.ldd;hcr.dll;winsgui;elocd.ldd;medint.pdd;medlfs.pdd;medmmc.pdd;epbusmmc.dll;epbusv.dll";
   368 const char* KExtensionUsiiNand = "?medusiiw.pdd";
   369 const char* KExtensionUsiiNandLoader = "?medusiiws.pdd";
   370 const char* KExtensionUsiiNandTest = "?medusiiwt.pdd";
   371 
   372 
   373 
   374 
   375 const int KMaxEpocRootSize = 120;
   376 
   377 TInt Wins::InitProperties(TBool aRunExe)
   378 	{
   379 	if (iProperties.Replace("MachineName", KDefaultMachineName) == NULL)
   380 		return KErrNoMemory;
   381 
   382     char epocRoot[KMaxEpocRootSize];
   383 
   384     TInt total = GetEnvironmentVariableA( KDefaultEpocRootName, epocRoot, KMaxEpocRootSize);
   385 
   386     if (total != 0)
   387 		{
   388 	    if (iProperties.Replace("EpocRoot", epocRoot) == NULL)
   389     	    return KErrNoMemory;
   390 		}
   391 
   392 	if (iProperties.Append("Extension", KExtensionListNormal) == NULL)
   393 		return KErrNoMemory;
   394 
   395 	char overrideCDrive[MAX_PATH];
   396 	overrideCDrive[0] = '\0';
   397 	TInt r = ProcessCommandLine(aRunExe, overrideCDrive);
   398 	if (r != KErrNone)
   399 		return r;
   400 
   401 	r = SetupPaths();
   402 	if (r != KErrNone)
   403 		return r;
   404 
   405 	r = LoadProperties();
   406 	if (r != KErrNone)
   407 		return r;
   408 
   409 	//	get Unistore II Media Driver type from epoc.ini
   410 	const char* value = NULL;
   411 	
   412 
   413 	iProperties.GetString("NandDriverType", value);
   414 	if (value)
   415 		{
   416 		if (value && _stricmp("XSR",value)==0)
   417 			{
   418 			// epoc.ini "NandDriverType=XSR" for XSR/Unistore-II driver
   419 			if (iProperties.Append("Extension", KExtensionUsiiNand) == NULL)
   420 				return KErrNoMemory;		
   421 			}
   422 		else if (value && _stricmp("XSRNandloader",value)==0)
   423 			{
   424 			// epoc.ini "NandDriverType=XSRNandloader" for XSR/Unistore-II nandloader driver
   425 			if (iProperties.Append("Extension", KExtensionUsiiNandLoader) == NULL)
   426 				return KErrNoMemory;		
   427 			}
   428 		else if (value && _stricmp("XSRTest",value)==0)
   429 			{
   430 			// epoc.ini "NandDriverType=XSRTest" for XSR/Unistore-II test driver
   431 			if (iProperties.Append("Extension", KExtensionUsiiNandTest) == NULL)
   432 				return KErrNoMemory;
   433 			}
   434 		else	
   435 			{
   436 			// If epoc.ini contains "NandDriverType=???" but ??? not equal to any
   437 			// of above XSR driver types then load production/release XSR
   438 			// driver
   439 			if (iProperties.Append("Extension", KExtensionUsiiNand) == NULL)
   440 				return KErrNoMemory;
   441 
   442 			}
   443 		}
   444 	else
   445 		{
   446 		// Load the production/release XSR driver, if value is NULL
   447 		if (iProperties.Append("Extension", KExtensionUsiiNand) == NULL)
   448 			return KErrNoMemory;
   449 
   450 		}
   451 	
   452 
   453 //	load additional configuration specific properties
   454 
   455 //	get the multi property "configuration"
   456 	value = NULL;
   457 	iProperties.GetString("configuration", value);
   458 	
   459 //	load each one of these
   460 //	check for any screen specific properties in the main epoc.ini
   461 //	if configuration property is set
   462 	if (value && !iConfigPropertySet)	//configuration
   463 		{
   464 		iConfigId = 0;
   465 		char configFileName[100];
   466 		do
   467 			{
   468 			//load each set of properties
   469 
   470 		   const char * pdest = strchr(value, ';');
   471 		   TInt result = pdest - value;
   472 		   if(pdest)
   473 			   {
   474 			   strncpy(configFileName, value, result);
   475 			   configFileName[result] = '\0';
   476 			   value = value + result + 1;
   477 			   }
   478 		   else
   479 			   {
   480 			   strcpy(configFileName, value);
   481 			   value += strlen(value);
   482 			   }
   483 
   484 			r = LoadConfigSpecificProperties(configFileName);
   485 			if (r == KErrNone)
   486 				iConfigId++;
   487 			}
   488 		while(*value);
   489 		}
   490 
   491 	char scr[30];
   492 	//if iConfigId is zero, there is only 1 configuration
   493 	wsprintfA(scr, "ConfigCount %d", iConfigId ? iConfigId : 1);
   494 	r = AddProperty(scr, scr+strlen(scr));
   495 	if (r != KErrNone)
   496 		return r;
   497 
   498 	r = SetupMediaPath();
   499 	if (r != KErrNone)
   500 		return r;
   501 
   502 	if (overrideCDrive[0] != '\0')
   503 		SetupDrive('c', overrideCDrive);
   504 
   505 	if (iProperties.Append("Extension", "exstart") == NULL)
   506 		return KErrNoMemory;
   507 
   508 #ifdef _DUMP_PROPERTY
   509 	iProperties.Dump();
   510 #endif
   511 
   512 	return KErrNone;
   513 	}
   514 
   515 char* skipws(char* aPtr)
   516 	{
   517 	while (isspace(*aPtr))
   518 		++aPtr;
   519 	return aPtr;
   520 	}
   521 
   522 char* skiptok(char* aPtr)
   523 	{
   524 	if (*aPtr == '\"')
   525 		{
   526 		++aPtr;
   527 		while (*aPtr && *aPtr++ != '\"')
   528 			{}
   529 		}
   530 	else
   531 		{
   532 		while (*aPtr && !isspace(*aPtr))
   533 			++aPtr;
   534 		}
   535 	return aPtr;
   536 	}
   537 
   538 #ifdef _DEBUG
   539 struct TDebugTrace
   540 	{
   541 	const char* iName;
   542 	TInt iMask;
   543 	};
   544 
   545 // Only the first 32 trace bits can be defined using these values
   546 // "ALWAYS" in this context means all of the first 32 bits not all 256 bits
   547 const TDebugTrace KTraceValues[] =
   548 	{
   549 	{"ALWAYS", KALWAYS},
   550 	{"BOOT", 1<<KBOOT},
   551 	{"DEVICE", 1<<KDEVICE},
   552 	{"DFC", 1<<KDFC},
   553 	{"DLL", 1<<KDLL},
   554 	{"EVENT", 1<<KEVENT},      
   555 	{"EXEC", 1<<KEXEC},
   556 	{"DEBUGGER", 1<<KDEBUGGER},
   557 	{"EXTENSION", 1<<KEXTENSION},
   558 	{"FAIL", 1<<KFAIL},
   559 	{"HARDWARE", 1<<KHARDWARE},
   560 	{"IPC", 1<<KIPC},
   561 	{"LOCDRV", 1<<KLOCDRV},
   562 	{"MEMTRACE", 1<<KMEMTRACE},
   563 	{"MMU", 1<<KMMU},
   564 	{"NKERN", 1<<KNKERN},
   565 	{"OBJECT", 1<<KOBJECT},
   566 	{"PANIC", 1<<KPANIC},
   567 	{"PBUS1", 1<<KPBUS1},
   568 	{"PBUS2", 1<<KPBUS2},
   569 	{"PBUSDRV", 1<<KPBUSDRV},
   570 	{"POWER", 1<<KPOWER},      
   571 	{"PROC", 1<<KPROC},
   572 	{"SCHED", 1<<KSCHED},
   573 	{"SCHED2", 1<<KSCHED2},
   574 	{"SCRATCH", 1<<KSCRATCH},
   575 	{"SEMAPHORE", 1<<KSEMAPHORE},
   576 	{"SERVER", 1<<KSERVER},
   577 	{"THREAD", 1<<KTHREAD},
   578 	{"THREAD2", 1<<KTHREAD2},
   579 	{"TIMING", 1<<KTIMING},
   580 	{"DMA", 1<<KDMA},
   581 	{"MMU2", 1<<KMMU2}
   582 	};
   583 const TInt KMaxTraceName = 9;
   584 const TInt KCountTraceValues = sizeof(KTraceValues)/sizeof(TDebugTrace);
   585 
   586 static const TDebugTrace* TraceType(const char* aTrace, TInt aLen)
   587 	{
   588 	if (aLen > KMaxTraceName)
   589 		return 0;
   590 
   591 	char name[KMaxTraceName + 1];
   592 	strncpy(name, aTrace, aLen);
   593 	name[aLen] = '\0';
   594 
   595 	for (TInt i=KCountTraceValues; --i>=0;)
   596 		{
   597 		if (_stricmp(name, KTraceValues[i].iName)==0)
   598 			return &KTraceValues[i];
   599 		}
   600 	return 0;
   601 	}
   602 #endif
   603 
   604 TInt Wins::DebugMask()
   605 	{
   606 	TInt mask = KDefaultDebugMask;
   607 	if (iProperties.GetInt("DebugMask", mask) != KErrArgument)
   608 		return mask;
   609 #ifdef _DEBUG
   610 	// allow text ones
   611 	const char* e;
   612 	if (iProperties.GetString("DebugMask", e) != KErrNone)
   613 		return mask;
   614 
   615 	for (;;)
   616 		{
   617 		char* p = skipws((char*)e);
   618 		if (*p == 0)
   619 			break;
   620 		e = skiptok(p);
   621 		TBool add = ETrue;
   622 		if (*p == '+')
   623 			++p;
   624 		else if (*p == '-')
   625 			{
   626 			add = EFalse;
   627 			++p;
   628 			}
   629 		const TDebugTrace* type = TraceType(p, e - p);
   630 		if (type)
   631 			{
   632 			if (add)
   633 				mask |= type->iMask;
   634 			else
   635 				mask &= ~type->iMask;
   636 			}
   637 		}
   638 #endif
   639 	return mask;
   640 	}
   641 
   642 TUint32 Wins::KernelConfigFlags()
   643 	{
   644 	TUint32 flags = 0;
   645 	TBool b;
   646 
   647 	b=0;
   648 	iProperties.GetBool("PlatSecEnforcement",b,EFalse);
   649 	if(b) flags |= EKernelConfigPlatSecEnforcement;
   650 	Wins::EarlyLogging("PlatSecEnforcement ",b?"ON":"OFF");
   651 
   652 	b=0;
   653 	iProperties.GetBool("PlatSecDiagnostics",b,EFalse);
   654 	if(b) flags |= EKernelConfigPlatSecDiagnostics;
   655 	Wins::EarlyLogging("PlatSecDiagnostics ",b?"ON":"OFF");
   656 
   657 	b=0;
   658 	iProperties.GetBool("PlatSecProcessIsolation",b,EFalse);
   659 	if(b) flags |= EKernelConfigPlatSecProcessIsolation;
   660 	Wins::EarlyLogging("PlatSecProcessIsolation ",b?"ON":"OFF");
   661 
   662 	b=0;
   663 	iProperties.GetBool("PlatSecEnforceSysBin",b,EFalse);
   664 	if(b) flags |= EKernelConfigPlatSecEnforceSysBin;
   665 	Wins::EarlyLogging("PlatSecEnforceSysBin ",b?"ON":"OFF");
   666 
   667 	b=0;
   668 	iProperties.GetBool("CrazyScheduling",b,EFalse);
   669 	if(b) flags |= EKernelConfigCrazyScheduling;
   670 	Wins::EarlyLogging("CrazyScheduling ",b?"ON":"OFF");
   671 
   672 	return flags;
   673 	}
   674 
   675 void Wins::DisabledCapabilities(SCapabilitySet& aCapabilities)
   676 	{
   677 	const char* text;
   678 	if(iProperties.GetString("PlatSecDisabledCaps", text)!=KErrNone)
   679 		text = "NONE";
   680 	Wins::EarlyLogging("PlatSecDisabledCaps ",text);
   681 	ParseCapabilitiesArg(aCapabilities,text);
   682 	}
   683 
   684 #define PARSE_CAPABILITIES_ERROR(aMessage) Wins::EarlyLogging(aMessage,0)
   685 #define PARSE_CAPABILITIES_ERROR2(aMessage,aArg) Wins::EarlyLogging(aMessage,aArg)
   686 #define strnicmp _strnicmp
   687 
   688 TInt Wins::ParseCapabilitiesArg(SCapabilitySet& aCapabilities, const char *aText)
   689 //
   690 // This is a cun'n'paste copy of the function in TOOLS\E32TOOLS\HOST\H_UTIL.CPP
   691 // Keep both of these versions up to date with each other
   692 //
   693 	{
   694 	memset(&aCapabilities,0,sizeof(aCapabilities));
   695 	char c;
   696 	while((c=*aText)!=0)
   697 		{
   698 		if(c<=' ')
   699 			{
   700 			++aText;
   701 			continue;
   702 			}
   703 		int invert=0;
   704 		if(c=='+')
   705 			{
   706 			++aText;
   707 			c=*aText;
   708 			}
   709 		if(c=='-')
   710 			{
   711 			invert=1;
   712 			++aText;
   713 			}
   714 		const char* name = aText;
   715 		while((c=*aText)>' ')
   716 			{
   717 			if(c=='-' || c=='+')
   718 				break;
   719 			++aText;
   720 			}
   721 		TInt n = aText-name;
   722 		TInt i;
   723 
   724 		if(n==3 && strnicmp("all",name,n)==0)
   725 			{
   726 			if(invert)
   727 				{
   728 				PARSE_CAPABILITIES_ERROR("Capability '-ALL' not allowed");
   729 				return KErrArgument;
   730 				}
   731 			for(i=0; i<ECapability_Limit; i++)
   732 				{
   733 				if(CapabilityNames[i])
   734 					aCapabilities[i>>5] |= (1<<(i&31));
   735 				}
   736 			continue;
   737 			}
   738 
   739 		if(n==4 && strnicmp("none",name,n)==0)
   740 			{
   741 			if(invert)
   742 				{
   743 				PARSE_CAPABILITIES_ERROR("Capability '-NONE' not allowed");
   744 				return KErrArgument;
   745 				}
   746 			memset(&aCapabilities,0,sizeof(aCapabilities));
   747 			continue;
   748 			}
   749 
   750 		for(i=0; i<ECapability_Limit; i++)
   751 			{
   752 			const char* cap = CapabilityNames[i];
   753 			if(!cap)
   754 				continue;
   755 			if((int)strlen(cap)!=n)
   756 				continue;
   757 			if(strnicmp(cap,name,n)!=0)
   758 				continue;
   759 			break;
   760 			}
   761 		if(i>=ECapability_Limit)
   762 			{
   763 			char badName[32];
   764 			if(n>=sizeof(badName)) n=sizeof(badName)-1;
   765 			memcpy(badName,name,n);
   766 			badName[n]=0;
   767 			PARSE_CAPABILITIES_ERROR2("Unrecognised capability name: ",badName);
   768 			return KErrArgument;
   769 			}
   770 		if(invert)
   771 			aCapabilities[i>>5] &= ~(1<<(i&31));
   772 		else
   773 			aCapabilities[i>>5] |= (1<<(i&31));
   774 		}
   775 	return KErrNone;
   776 	}
   777 
   778 TInt Wins::AddProperty(char* aProperty, const char* aEol)
   779 	{
   780 	const char* tok = aProperty;
   781 	int c;
   782 	do
   783 		{
   784 		if (aProperty == aEol)
   785 			{
   786 			// boolean property
   787 			if (_stricmp(tok, "_NewScreen_") == 0)
   788  				{
   789  				++ScreenId;
   790  				return KErrNone;
   791  				}
   792 			else
   793 				{
   794 				char newtok[KMaxTokenLength];
   795 				if (ConfigSpecificProperty(tok))
   796 					{
   797 					wsprintfA(newtok, "Configuration[%d]", iConfigId);
   798 					strcat(newtok, tok);
   799 					tok = newtok;
   800 					}
   801 				}
   802 			return iProperties.Replace(tok, NULL) == NULL ? KErrNoMemory : KErrNone;
   803 			}
   804 		c=*aProperty++;
   805 		} while (isalnum(c) || c=='_');
   806 	aProperty[-1]='\0';	// terminate property name
   807 	while (isspace(c))
   808 		c=*aProperty++;
   809 	TBool append=ETrue;
   810 	if (c=='=')
   811 		{
   812 		append=EFalse;
   813 		c=*aProperty++;
   814 		}
   815 	else if (c=='+' && *aProperty=='=')
   816 		{
   817 		++aProperty;
   818 		c=*aProperty++;
   819 		}
   820 	while (isspace(c))
   821 		c=*aProperty++;
   822 	--aProperty;	// point back to value
   823 
   824 	if (_strnicmp(tok, "_epoc_drive_", 12) == 0)
   825 		return SetupDrive(tok[12], aProperty);
   826 	else
   827 		{
   828 		char newtok[KMaxTokenLength];
   829 		if (ConfigSpecificProperty(tok))
   830 			{
   831 			if (ScreenSpecificProperty(tok))
   832 				{
   833 				wsprintfA(newtok, "Configuration[%d][%d]", iConfigId, ScreenId);
   834 				}
   835 			else
   836 				{
   837 				wsprintfA(newtok, "Configuration[%d]", iConfigId);
   838 				}
   839 			strcat(newtok, tok);
   840 			tok = newtok;
   841 			}
   842 		if (append)
   843 			return iProperties.Append(tok, aProperty) == NULL ? KErrNoMemory : KErrNone;
   844 		else
   845 			return iProperties.Replace(tok, aProperty) == NULL ? KErrNoMemory : KErrNone;
   846 		}
   847 	}
   848 
   849 TInt Wins::ProcessCommandLine(TBool aRunExe, char* aCDrive)
   850 	{
   851 	if (aRunExe)
   852 		{
   853 		char exe[MAX_PATH];
   854 		DWORD len=GetModuleFileNameA(NULL, exe, MAX_PATH);
   855 		if (len == 0)
   856 			return KErrGeneral;
   857 		exe[len] = '\0';
   858 		const char* base = strrchr(exe, '\\') + 1;
   859 		if (iProperties.Replace("AutoRun", base) == NULL)
   860 			return KErrNoMemory;
   861 		}
   862 
   863 	char* cmd = skipws(skiptok(GetCommandLineA()));
   864 	if (strstr(cmd, "--") != NULL)
   865 		{
   866 		for (;;)
   867 			{
   868 			cmd = strchr(cmd, '-') + 1;
   869 			TInt opt = *cmd++;
   870 			if (opt == '-')
   871 				break;
   872 			char* end = skiptok(cmd);
   873 			*end = '\0';
   874 			switch (tolower(opt))
   875 				{
   876 			    case 'd':
   877 				    {
   878 				    TInt r = AddProperty(cmd, end);
   879 				    if (r != KErrNone)
   880 				    	return r;
   881 				    }
   882 				    break;
   883 			    case 'm':
   884 			    	// specify base name for .INI file
   885 				    if (iProperties.Replace("MachineName", cmd) == NULL)
   886 				    	return KErrNoMemory;
   887 				    break;
   888 			    case 'l':
   889 			    	// specify language
   890 			    	if (iProperties.Replace("TheMachineLanguageIndex", cmd) == NULL)
   891 			    		return KErrNoMemory;
   892 			    	break;
   893 		    	case 'c':
   894 		    		// specify path for emulated C drive
   895 			    	{
   896 			    	DWORD len=GetFullPathNameA(cmd, MAX_PATH, aCDrive, NULL);
   897 			    	if (len==0 || len >= MAX_PATH)
   898 			    		aCDrive[0] = '\0';
   899 			    	}
   900 			        break;
   901 			    case 't':
   902 			    	// specify the temp path as the emulated C drive
   903 			    	{
   904 			    	DWORD len=GetTempPathA(MAX_PATH, aCDrive);
   905 			    	if (len==0 || len >= MAX_PATH)
   906 			    		aCDrive[0] = '\0';
   907 			    	}
   908 			    	break;
   909 				}
   910 			cmd = end+1;
   911 			}
   912 		cmd = skipws(cmd);
   913 		}
   914 
   915 	if (aRunExe && iProperties.Replace("CommandLine", cmd) == NULL)
   916 		return KErrNoMemory;
   917 
   918 	return KErrNone;
   919 	}
   920 
   921 TInt Wins::LoadConfigSpecificProperties(const char * aFile)
   922 	{
   923 	const char* path;
   924 	TInt r = iProperties.GetString("EmulatorDataPath", path);
   925 	if (r != KErrNone)
   926 		return r;
   927 
   928 	char file[KMaxFileName + 1];
   929 	strcpy(file, path);
   930 	strcat(file, aFile);
   931 
   932 	char* iniData;
   933 	r = ReadIniFile(file, iniData);
   934 	if (r == KErrNone)
   935 		{
   936 		r = ReadProperties(iniData);
   937 		VirtualFree(iniData, 0, MEM_RELEASE);
   938 		}
   939 	else if (r == KErrNotFound)
   940 		r = KErrNotFound;
   941 
   942 	return r;
   943 
   944 	}
   945 
   946 
   947 
   948 TInt Wins::LoadProperties()
   949 	{
   950 	const char* path;
   951 	TInt r = iProperties.GetString("EmulatorDataPath", path);
   952 	if (r != KErrNone)
   953 		return r;
   954 	const char* name;
   955 	r = iProperties.GetString("MachineName", name);
   956 	if (r != KErrNone)
   957 		return r;
   958 retry:
   959 	char file[KMaxFileName + 1];
   960 	strcpy(file, path);
   961 	strcat(file, name);
   962 	strcat(file, ".ini");
   963 
   964 	char* iniData;
   965 	r = ReadIniFile(file, iniData);
   966 	if (r == KErrNone)
   967 		{
   968 		r = ReadProperties(iniData);
   969 		VirtualFree(iniData, 0, MEM_RELEASE);
   970 		}
   971 	else if (r == KErrNotFound)
   972 		{
   973 		if(_stricmp(name,KDefaultMachineName)==0)
   974 			{
   975 			// try test ini file
   976 			name = KDefaultTestMachineName;
   977 			goto retry;
   978 			}
   979 		r = KErrNone;		// no ini file - oh well
   980 		}
   981 
   982 	return r;
   983 	}
   984 
   985 TInt Wins::ReadProperties(char* aData)
   986 	{
   987 	ScreenId = 0;
   988 	while (*aData)
   989 		{
   990 		char* beg = aData;
   991 		char* eol = strchr(beg, '\n');
   992 		aData = eol+1;
   993 		if (eol == beg)
   994 			continue;
   995 		if (eol[-1] == '\r' && --eol == beg)
   996 			continue;
   997 		*eol = '\0';		// terminate line
   998 
   999 		while (isspace(*beg))
  1000 			++beg;
  1001 		char* comment = strchr(beg, '#');
  1002 		if (comment)
  1003 			eol = comment;
  1004 		while (eol > beg && isspace(eol[-1]))
  1005 			--eol;
  1006 		if (beg == eol)
  1007 			continue;
  1008 		*eol = '\0';		// terminate line
  1009 
  1010 		TInt r = AddProperty(beg, eol);
  1011 		if (r != KErrNone)
  1012 			return r;
  1013 		}
  1014 	char sc[5];
  1015  	wsprintfA(sc, "%d", ScreenId+1);
  1016 	TInt screens;
  1017 	if(iProperties.GetInt("[screens]", screens) == KErrNone && screens > ScreenId)
  1018 		return KErrNone;
  1019  	else
  1020 		return iProperties.Replace("[screens]", sc)  == NULL ? KErrNoMemory : KErrNone;
  1021 	}
  1022 
  1023 TInt Wins::ReadIniFile(const char* aFileName, char*& aContents)
  1024 	{
  1025 	TInt r = KErrNone;
  1026 	HANDLE file=CreateFileA(aFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1027 	if (!file || file==INVALID_HANDLE_VALUE)
  1028 		r = KErrNotFound;	// More than likely !
  1029 	else
  1030 		{
  1031 		TInt size=GetFileSize(file, NULL);
  1032 		if (size==INVALID_FILE_SIZE)
  1033 			r = KErrGeneral;
  1034 		else
  1035 			{
  1036 			// fileSize+3 to ensure zero-termination of file and trailing CRLF
  1037 			// VirtualAlloc initializes memory to zero
  1038 			TAny* data = VirtualAlloc(NULL, size+3, MEM_COMMIT, PAGE_READWRITE);
  1039 			if (!data)
  1040 				r = KErrNoMemory;
  1041 			else
  1042 				{
  1043 				DWORD bytesRead;
  1044 				if (!ReadFile(file, data, size, &bytesRead, NULL))
  1045 					{
  1046 					VirtualFree(data, 0, MEM_RELEASE);
  1047 					r = KErrGeneral;
  1048 					}
  1049 				else
  1050 					{
  1051 					aContents = (LPSTR)data;
  1052 					strcpy(aContents + size,"\r\n");
  1053 					}
  1054 				}
  1055 			}
  1056 		CloseHandle(file);
  1057 		}
  1058 	return r;
  1059 	}
  1060 
  1061 
  1062 TInt Wins::SetupPaths()
  1063 //
  1064 // set up the Emulator paths
  1065 //
  1066 	{
  1067 	// the Emulator path
  1068 	CHAR path[KMaxFileName + 1];
  1069 	DWORD len=GetModuleFileNameA(NULL, path, KMaxFileName);
  1070 	if (len == 0)
  1071 		return(KErrGeneral);
  1072 	path[len] = '\0';
  1073 	_strlwr(path);
  1074 	*(strrchr(path, '\\') + 1) = '\0';
  1075 	const char* emulatorPath = iProperties.Replace("EmulatorPath", path);
  1076 	if (!emulatorPath)
  1077 		return KErrNoMemory;
  1078 
  1079 	CHAR drive[KMaxFileName + 1];
  1080 
  1081 	// the Emulator data path
  1082 	strcat(path, "data\\");
  1083 	DWORD att = GetFileAttributesA(path);
  1084 	if (att != -1 && (att&FILE_ATTRIBUTE_DIRECTORY))
  1085 		{
  1086 		// if Data directory exists in the emulator path, do things the new way
  1087 		strcpy(drive, emulatorPath);
  1088 		strcat(drive,"c\\");
  1089 		}
  1090 	else
  1091 		{
  1092 		// the old way
  1093 #if defined(__VC32__)
  1094 		char* p = strstr(path, "\\epoc32\\release\\wins\\");
  1095 #elif defined(__CW32__)
  1096 		char* p = strstr(path, "\\epoc32\\release\\winscw\\");
  1097 #endif
  1098 		if (p == NULL)
  1099 			return KErrNotFound;
  1100 		strcpy(p, "\\epoc32\\");
  1101 		strcpy(drive, path);
  1102 		strcat(path, "data\\");
  1103 #if defined(__VC32__)
  1104 		strcat(drive,"wins\\c\\");
  1105 #elif defined(__CW32__)
  1106 		strcat(drive,"winscw\\c\\");
  1107 #endif
  1108 		}
  1109 	if (!iProperties.Replace("EmulatorDataPath", path))
  1110 		return KErrNoMemory;
  1111 
  1112 	// The Emulator Image path (for temporary EXE files)
  1113 	const char* eip;
  1114 	TInt r = iProperties.GetString("EmulatorImagePath", eip);
  1115 	if (r!=KErrNone)
  1116 		{
  1117 		len=GetTempPathA(KMaxFileName, path);
  1118 		strcat(path, "epoc\\");
  1119 		char* p = path + strlen(path);
  1120 		*p++ = emulatorPath[0];
  1121 		strcpy(p, emulatorPath+2);
  1122 		if (!iProperties.Replace("EmulatorImagePath", path))
  1123 			return KErrNoMemory;
  1124 		}
  1125 	else
  1126 		strcpy(path, eip);
  1127 	if (!Emulator::CreateAllDirectories(path))
  1128 		return Emulator::LastError();
  1129 
  1130 	// Win32 filesystem paths mapped to local WINS drives
  1131 	r = SetupDrive('c',drive);  // set up C here, can be overridden by system.ini settings
  1132 	if (r)
  1133 		return(r);
  1134 
  1135 	strcpy(drive, emulatorPath);
  1136 	strcat(drive,"z\\");
  1137 
  1138 	r=SetupDrive('z',drive);  // set up Z here, can be overridden by system.ini settings
  1139 	if (r)
  1140 		return(r);
  1141 
  1142 	return(KErrNone);
  1143 	}
  1144 
  1145 TInt Wins::SetupMediaPath()
  1146 //
  1147 // Set up the path for emulated media devices 'EmulatedMediaPath'
  1148 // The default is <datapath>media/
  1149 // The system temporary path can be set by value '%temp%'
  1150 //
  1151 	{
  1152 	CHAR path[KMaxFileName + 1];
  1153 	const char* mpath;
  1154 	if (iProperties.GetString("EmulatorMediaPath", mpath) == KErrNotFound)
  1155 		{
  1156 		const char* dpath;
  1157 		TInt r = iProperties.GetString("EmulatorDataPath", dpath);
  1158 		if (r != KErrNone)
  1159 			return r;
  1160 		strcpy(path, dpath);
  1161 		strcat(path, "media\\");
  1162 		return iProperties.Replace("EmulatorMediaPath", path) ? KErrNone : KErrNoMemory;
  1163 		}
  1164 
  1165 	if (_stricmp(mpath, "%temp%") == 0)
  1166 		{
  1167 		DWORD len=GetTempPathA(KMaxFileName, path);
  1168 		if (len > 0 && len < KMaxFileName)
  1169 			return iProperties.Replace("EmulatorMediaPath", path) ? KErrNone : KErrNoMemory;
  1170 		}
  1171 
  1172 	return KErrNone;
  1173 	}
  1174 
  1175 const char* Wins::EmulatorMediaPath()
  1176 	{
  1177 	const char* mpath = NULL;
  1178 	iProperties.GetString("EmulatorMediaPath", mpath);
  1179 	return mpath;
  1180 	}
  1181 
  1182 
  1183 TInt Wins::SetupDrive(int aDrive, const char* aPath)
  1184 //
  1185 // set up emulated drives
  1186 //
  1187 	{
  1188 
  1189 	// Z drive can't end in anything but "Z\\", since we chop this off and use
  1190 	// the resulting directory to find filenames with no drive specified in
  1191 	// MapFileName() below.
  1192 	aDrive = tolower(aDrive);
  1193 	if (aDrive=='z')
  1194 		{
  1195 		const char* end = aPath + strlen(aPath);
  1196 		if (_stricmp(end-2,"\\z") != 0 && _stricmp(end-3,"\\z\\") != 0)
  1197 			return KErrArgument;
  1198 		}
  1199 
  1200 	char prop[] = "_epoc_drive_?";
  1201 	*strchr(prop, '?') = char(aDrive);
  1202 
  1203 
  1204     // If the path begins with the keyword %epocroot%, replace this with EPOCROOT
  1205     if (_strnicmp(aPath, "%epocroot%", 10) == 0)
  1206         {
  1207 		aPath += 10; // skip "%epocroot%"
  1208 
  1209         const char* eRoot;
  1210         TInt r = iProperties.GetString("EpocRoot", eRoot);
  1211         if (r != KErrNone)
  1212             return r;
  1213 
  1214 		int rootSize = strlen(eRoot);
  1215 		int pathSize = strlen(aPath);
  1216 		if(rootSize+pathSize>MAX_PATH)
  1217 			return KErrArgument;
  1218 
  1219         char fullPath[MAX_PATH+1];
  1220 		memcpy(fullPath,eRoot,rootSize);
  1221 		memcpy(fullPath+rootSize,aPath,pathSize+1); // +1 to get the terminating NULL char
  1222 
  1223         return iProperties.Replace(prop, fullPath) ? KErrNone : KErrNoMemory;
  1224 
  1225         }
  1226     else
  1227 		{
  1228 		//Otherwise aPath is potentially a relative path
  1229 		char path[FILENAME_MAX+1];
  1230 		//Resolve relative path
  1231 		FullPath(path,aPath,sizeof(path)/sizeof(char));
  1232         //Now path is fully qualified path name. Use that.
  1233         return iProperties.Replace(prop, path) ? KErrNone : KErrNoMemory;
  1234 		}
  1235 
  1236   
  1237 	}
  1238 
  1239 TInt Wins::MapDrive(int aDrive, TDes& aBuffer) const
  1240 //
  1241 // Map aDrive to a path given by environment variables or defaults
  1242 // Use this function only in WINS builds
  1243 //
  1244 	{
  1245 	char drive[KMaxFileName + 1];
  1246 	char prop[] = "_epoc_drive_?";
  1247 	*strchr(prop, '?') = char(tolower(aDrive));
  1248 
  1249 	TInt len;
  1250 	const char* val;
  1251 	if (iProperties.GetString(prop, val) == KErrNone)
  1252 		{
  1253 		len = strlen(val);
  1254 		if (len > KMaxFileName)
  1255 			return KErrArgument;
  1256 		strcpy(drive, val);
  1257 		}
  1258 	else
  1259 		{
  1260 		// not in properties, so check environment
  1261 		len = GetEnvironmentVariableA(prop, drive, KMaxFileName + 1);
  1262 		if (len > KMaxFileName)
  1263 			return KErrArgument;
  1264 		}
  1265 	while (len > 0 && isspace(drive[len-1]))
  1266 		--len;
  1267 	if (len == 0)
  1268 		return KErrNotFound;
  1269 	if (drive[len-1] != '\\') // add trailing backslash
  1270 		drive[len++] = '\\';
  1271 	if (drive[0] == '\\')
  1272 		{
  1273 		// put in the emulator drive
  1274 		TInt r = iProperties.GetString("EmulatorPath", val);
  1275 		if (r != KErrNone)
  1276 			return r;
  1277 
  1278 		memmove(drive + 2, drive, len);
  1279 		drive[0] = val[0];
  1280 		drive[1] = ':';
  1281 		len += 2;
  1282 		}
  1283 	else if (len < 3 || drive[1] != ':' || drive[2] != '\\')
  1284 		return KErrArgument;
  1285 #ifdef _UNICODE
  1286 	TUint16* aBufPtr = (TUint16*)aBuffer.Ptr();
  1287 	const TText* drv = (const TText*)drive;
  1288 	for(int index=0;index<len;index++)
  1289 		*aBufPtr++ = (TUint16)*drv++;
  1290 	aBuffer.SetLength(len<<1);
  1291 #else
  1292 	aBuffer.Copy(TPtrC8((const TText8*)drive,len));
  1293 #endif
  1294 	return KErrNone;
  1295 	}
  1296 
  1297 TInt Wins::MapFilename(const TDesC& aFilename, TDes& aBuffer) const
  1298 //
  1299 // Map aFileName to real windows directory - aFileName must be a full filepath
  1300 //
  1301 	{
  1302 
  1303 	// if the filename does not have a drive specified then don't imagine
  1304 	// it describes an Epoc filepath
  1305 	// Assume it's a subdirectory/file of the file containing the emulated Z drive
  1306 	TInt offset;
  1307 	if (aFilename.Length() < 4 || aFilename[2] != ':')
  1308 		{
  1309 		TInt r = MapDrive('z', aBuffer);
  1310 		if (r)
  1311 			return(r);
  1312 		aBuffer.SetLength(aBuffer.Length()-4);	// chop "Z\\"
  1313 		offset = aFilename[0] == '\\' ? 1 : 0; // remove the guaranteed backslash
  1314 		}
  1315 	else
  1316 		{
  1317 		TInt r = MapDrive(aFilename[0], aBuffer);
  1318 		if (r)
  1319 			return(r);
  1320 		if (aFilename.Length() >= 6 && aFilename[4] == '\\')
  1321 			offset = 3;
  1322 		else
  1323 			offset = 2;
  1324 		}
  1325 #ifdef _UNICODE
  1326 	offset = offset<<1;
  1327 	TUint8* ptrFilename = (TUint8*)aFilename.Ptr() + offset;
  1328 	TUint8* ptrBuffer = (TUint8*)aBuffer.Ptr()+aBuffer.Length();
  1329 	if (aBuffer.MaxLength()<aBuffer.Length()+aFilename.Length()-offset+1)
  1330 		return KErrBadName;
  1331 
  1332 	memcpy(ptrBuffer, ptrFilename, aFilename.Length()-offset);
  1333 	aBuffer.SetLength(aBuffer.Length()+aFilename.Length()-offset);
  1334 #else
  1335 	TPtrC name(aFilename.Mid(offset));
  1336 	if (aBuffer.MaxLength()<aBuffer.Length()+name.Length()+1)
  1337 		return KErrBadName;
  1338 	aBuffer.Append(name);
  1339 #endif
  1340 	return KErrNone;
  1341 	}
  1342 
  1343 
  1344 //table of the property names which can be used in multiple configurations
  1345 const char * KConfigSpecificProperties[] =
  1346 	{
  1347 	"ScreenWidth",
  1348 	"ScreenHeight",
  1349 	"PhysicalScreenWidth",
  1350 	"PhysicalScreenHeight",
  1351 	"ScreenOffsetX",
  1352 	"ScreenOffsetY",
  1353 	"LedSize",
  1354 	"LedArrangeVertically",
  1355 	"LedArrangeHorizontally",
  1356 	"LedOffsetX",
  1357 	"LedOffsetY",
  1358 	"LedGap",
  1359 	"PointerType",
  1360 	"ColorDepth",
  1361 	"KeyMap",
  1362 	"DrawVirtualKeys",
  1363 	"VirtualKeyColor",
  1364 	"VirtualKey",
  1365 	"MouseTarget",
  1366 	"FasciaBitmap",
  1367 	"DigitizerOffsetX",
  1368 	"DigitizerOffsetY",
  1369 	"DigitizerWidth",
  1370 	"DigitizerHeight",
  1371 	"DisableDigitizer",
  1372 	"DefineKeyName",
  1373 	"WindowTitle",
  1374 	"NoVersionInfo",
  1375 	"OnActivation",
  1376 	"EmulatorControl",
  1377 	"EmulatorControlHotKey",
  1378 	"CompositionBuffers",
  1379 	"RefreshRateHz",
  1380 	};
  1381 
  1382 const char * KScreenSpecificProperties[] =
  1383  	{
  1384  	"ScreenWidth",
  1385  	"ScreenHeight",
  1386  	"PhysicalScreenWidth",
  1387  	"PhysicalScreenHeight",
  1388  	"ScreenOffsetX",
  1389  	"ScreenOffsetY",
  1390  	"ColorDepth",
  1391 	"FasciaBitmap",
  1392 	"CompositionBuffers",
  1393 	"RefreshRateHz",
  1394  	};
  1395 
  1396 
  1397 TBool Wins::ConfigSpecificProperty(const char * aProperty)
  1398 	{
  1399 	TInt x;
  1400 	TInt count = sizeof(KConfigSpecificProperties) / sizeof(char *);
  1401 	for (x = 0; x < count; ++x)
  1402 		if (_stricmp(aProperty, KConfigSpecificProperties[x]) == 0)	return ETrue;
  1403 	return EFalse;
  1404 	}
  1405 
  1406 TBool Wins::ScreenSpecificProperty(const char * aProperty)
  1407 	{
  1408 	TInt x;
  1409 	TInt count = sizeof(KScreenSpecificProperties) / sizeof(char *);
  1410 	for (x = 0; x < count; ++x)
  1411 		if (_stricmp(aProperty, KScreenSpecificProperties[x]) == 0)	return ETrue;
  1412 	return EFalse;
  1413 	}