text: /*
   *	V A R . C P P
   *
   *	XML document processing
   *
   *	Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
   */
  
  #include "_xml.h"
  
  //	ScVariantTypeFromString()
  //
  //	Returns the variant type associated with a dav datatype string
  //
  SCODE
  ScVariantTypeFromString (LPCWSTR pwszType, USHORT& vt)
  {
  	SCODE sc = S_OK;
  
  	//	NULL, "string" and "uri"
  	//
  	if (!pwszType ||
  		!_wcsicmp (pwszType, gc_wszDavType_String) ||
  		!_wcsicmp (pwszType, gc_wszUri))
  	{
  		vt = VT_LPWSTR;
  	}
  	//	integer
  	//
  	else if (!_wcsicmp (pwszType, gc_wszDavType_Int))
  	{
  		vt = VT_I4;
  	}
  	//	boolean.tf
  	//
  	else if (!_wcsicmp (pwszType, gc_wszDavType_Boolean))
  	{
  		vt = VT_BOOL;
  	}
  	//	float (Floating/Reals)
  	//
  	else if (!_wcsicmp (pwszType, gc_wszDavType_Float))
  	{
  		vt = VT_R8;
  	}
  	//	date.iso8601
  	//
  	else if (!_wcsicmp (pwszType, gc_wszDavType_Date_ISO8601))
  	{
  		vt = VT_FILETIME;
  	}
  	else
  	{
  		DebugTrace ("ScVariantTypeFromString(): unknown type");
  		vt = VT_LPWSTR;
  		sc = S_OK;
  	}
  
  	return sc;
  }
  
  //	ScVariantValueFromString() ------------------------------------------------
  //
  //	Sets the value of a PROPVARIANT
  //
  SCODE
  ScVariantValueFromString (PROPVARIANT& var, LPCWSTR pwszValue)
  {
  	SCODE sc = S_OK;
  
  	LPWSTR pwsz;
  	SYSTEMTIME st;
  
  	switch (var.vt)
  	{
  		case VT_LPWSTR:
  
  			if (pwszValue)
  			{
  				pwsz = static_cast<LPWSTR>(CoTaskMemAlloc(CbSizeWsz(wcslen(pwszValue))));
  				if (NULL == pwsz)
  				{
  					DebugTrace ("ScVariantValueFromString() - CoTaskMemAlloc() failed to allocate %d bytes\n", CbSizeWsz(wcslen(pwszValue)));
  
  					sc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  					goto ret;
  				}
  
  				wcscpy (pwsz, pwszValue);
  				var.pwszVal = pwsz;
  			}
  			else
  				var.pwszVal = NULL;
  
  			break;
  
  		case VT_I4:
  
  			Assert (pwszValue);
  			var.lVal = _wtoi (pwszValue);
  			break;
  
  		case VT_BOOL:
  
  #pragma warning(disable:4310)	//	wtypes.h is broken
  
  			Assert (pwszValue);
  			if (!_wcsnicmp (pwszValue, gc_wsz1, 1))
  				var.boolVal = VARIANT_TRUE;
  			else if (!_wcsnicmp (pwszValue, gc_wsz0, 1))
  				var.boolVal = VARIANT_FALSE;
  			else
  			{
  				sc = E_INVALIDARG;
  				goto ret;
  			}
  			break;
  
  #pragma warning(default:4310)	//	wtypes.h is broken
  
  		case VT_R8:
  
  			Assert (pwszValue);
  			var.dblVal = wcstod (pwszValue, NULL);
  			break;
  
  		case VT_FILETIME:
  
  			Assert (pwszValue);
  			memset (&var.filetime, 0, sizeof(FILETIME));
  			if (!FGetSystimeFromDateIso8601 (pwszValue, &st))
  			{
  				sc = E_INVALIDARG;
  				goto ret;
  			}
  			SystemTimeToFileTime (&st, &var.filetime);
  			break;
  
  		default:
  
  			Assert (pwszValue);
  			TrapSz ("ScVariantValueFromString() unknown type");
  
  			sc = E_INVALIDARG;
  			goto ret;
  	}
  
  ret:
  
  	return sc;
  }
  
  //	ScEmitFromVariant() ------------------------------------------------
  //
  SCODE
  ScEmitFromVariant (CXMLEmitter& emitter,
  	CEmitterNode& enParent,
  	LPCWSTR pwszTag,
  	PROPVARIANT& var)
  {
  	CEmitterNode en;
  	CStackBuffer<CHAR,110> szBuf;
  	CStackBuffer<WCHAR,128> wszBuf;
  	LPCWSTR	pwszType = NULL;
  	LPWSTR pwszValue = NULL;
  	SCODE sc = S_OK;
  	SYSTEMTIME 	st;
  	UINT cch;
  	UINT i;
  	VARIANT* pvarTrue = reinterpret_cast<VARIANT*>(&var);
  
  	switch (var.vt)
  	{
  		case VT_NULL:
  		case VT_EMPTY:
  
  			break;
  
  		case VT_BSTR:
  
  			pwszValue = static_cast<LPWSTR>(var.bstrVal);
  			break;
  
  		case VT_LPWSTR:
  
  			pwszValue = var.pwszVal;
  			break;
  
  		case VT_LPSTR:
  
  			if (!var.pszVal)
  				break;
  
  			cch = static_cast<UINT>(strlen (var.pszVal));
  			pwszValue = wszBuf.resize(CbSizeWsz(cch));
  			if (NULL == pwszValue)
  			{
  				sc = E_OUTOFMEMORY;
  				goto ret;
  			}
  
  			//  We know that the numbers are in ASCII codepage and we know
  			//	that the buffer size is big enough.
  			//
  			cch = MultiByteToWideChar (CP_ACP,
  									   MB_ERR_INVALID_CHARS,
  									   var.pszVal,
  									   cch + 1,
  									   pwszValue,
  									   wszBuf.celems());
  			if (0 == cch)
  			{
  				sc = HRESULT_FROM_WIN32(GetLastError());
  				Assert(FAILED(sc));
  				goto ret;
  			}
  			break;
  
  		case VT_I1:
  
  			pwszType = gc_wszDavType_Int;
  			_itow (pvarTrue->cVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_UI1:
  
  			pwszType = gc_wszDavType_Int;
  			_ultow (var.bVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_I2:
  
  			pwszType = gc_wszDavType_Int;
  			_itow (var.iVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_UI2:
  
  			pwszType = gc_wszDavType_Int;
  			_ultow (var.uiVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_I4:
  
  			pwszType = gc_wszDavType_Int;
  			_ltow (var.lVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_UI4:
  
  			pwszType = gc_wszDavType_Int;
  			_ultow (var.ulVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_I8:
  
  			pwszType = gc_wszDavType_Int;
  
  			//$ REVIEW: negative values of _int64 seem to have problems in
  			//	the __i64tow() API.  Handle those cases ourselves by using the wrapper
  			//  function Int64ToPwsz.
  			//
  			Int64ToPwsz (&var.hVal.QuadPart, wszBuf.get(), wszBuf.size());
  			//
  			//$ REVIEW: end
  
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_UI8:
  
  			pwszType = gc_wszDavType_Int;
  			_ui64tow (var.uhVal.QuadPart, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_INT:
  
  			pwszType = gc_wszDavType_Int;
  			_itow (pvarTrue->intVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_UINT:
  
  			pwszType = gc_wszDavType_Int;
  			_ultow (pvarTrue->uintVal, wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_BOOL:
  
  			pwszType = gc_wszDavType_Boolean;
  			_itow (!(VARIANT_FALSE == var.boolVal), wszBuf.get(), 10);
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_R4:
  			//	_gcvt could add 8 extra chars then the number of digits asked
  			//	for example -3.1415e+019, '-','.' "e+019", plus the terminating
  			//	NULL doesn't count in digits asked. so we have to reserve
  			//	enough space in the provided buffer. using 11 to make sure
  			//	we are absolutely safe.
  			//
  			_gcvt (var.fltVal, szBuf.celems() - 11, szBuf.get());
  
  			cch = static_cast<UINT>(strlen(szBuf.get()));
  			pwszValue = wszBuf.resize(CbSizeWsz(cch));
  			if (NULL == pwszValue)
  			{
  				sc = E_OUTOFMEMORY;
  				goto ret;
  			}
  
  			//  We know that the numbers are in ASCII codepage and we know
  			//	that the buffer size is big enough.
  			//
  			cch = MultiByteToWideChar(CP_ACP,
  									  MB_ERR_INVALID_CHARS,
  									  szBuf.get(),
  									  cch + 1,
  									  wszBuf.get(),
  									  wszBuf.celems());
  			if (0 == cch)
  			{
  				sc = HRESULT_FROM_WIN32(GetLastError());
  				Assert(FAILED(sc));
  				goto ret;
  			}
  
  			pwszType = gc_wszDavType_R4;
  			break;
  
  		case VT_R8:
  			//	_gcvt could add 8 extra chars then the number of digits asked
  			//	for example -3.1415e+019, '-','.' "e+019", plus the terminating
  			//	NULL doesn't count in digits asked. so we have to reserve
  			//	enough space in the provided buffer. using 11 to make sure
  			//	we are absolutely safe.
  			//
  			_gcvt (var.dblVal, szBuf.celems() - 11, szBuf.get());
  
  			cch = static_cast<UINT>(strlen(szBuf.get()));
  			pwszValue = wszBuf.resize(CbSizeWsz(cch));
  			if (NULL == pwszValue)
  			{
  				sc = E_OUTOFMEMORY;
  				goto ret;
  			}
  
  			//  We know that the numbers are in ASCII codepage and we know
  			//	that the buffer size is big enough.
  			//
  			cch = MultiByteToWideChar(CP_ACP,
  									  MB_ERR_INVALID_CHARS,
  									  szBuf.get(),
  									  cch + 1,
  									  wszBuf.get(),
  									  wszBuf.celems());
  			if (0 == cch)
  			{
  				sc = HRESULT_FROM_WIN32(GetLastError());
  				Assert(FAILED(sc));
  				goto ret;
  			}
  
  			pwszType = gc_wszDavType_Float;
  			break;
  
  		case VT_FILETIME:
  
  			if (!FileTimeToSystemTime (&var.filetime, &st))
  			{
  				//	In case the filetime is invalid, default to zero
  				//
  				FILETIME ftDefault = {0};
  				FileTimeToSystemTime (&ftDefault, &st);
  			}
  			if (!FGetDateIso8601FromSystime(&st, wszBuf.get(), wszBuf.celems()))
  				return E_INVALIDARG;
  
  			pwszType = gc_wszDavType_Date_ISO8601;
  			pwszValue = wszBuf.get();
  			break;
  
  		case VT_VECTOR | VT_LPWSTR:
  		{
  			//	Create the emitter node;
  			//
  			sc = en.ScConstructNode (emitter,
  									 enParent.Pxn(),
  									 pwszTag,
  									 NULL,
  									 gc_wszDavType_Mvstring);
  			if (FAILED (sc))
  				goto ret;
  
  			//	Add the values
  			//
  			for (i = 0; i < var.calpwstr.cElems; i++)
  			{
  				CEmitterNode enSub;
  				sc = en.ScAddNode (gc_wszXml_V,
  								   enSub,
  								   var.calpwstr.pElems[i]);
  				if (FAILED (sc))
  					goto ret;
  			}
  
  			//	In this case we have built up the node ourselves.  We do not
  			//	want to fall into recreating the node.
  			//
  			return S_OK;
  		}
  
  		case VT_CY:
  		case VT_DATE:
  		case VT_DISPATCH:
  		case VT_ERROR:
  		case VT_VARIANT:
  		case VT_UNKNOWN:
  		case VT_DECIMAL:
  		case VT_RECORD:
  		case VT_BLOB:
  		case VT_STREAM:
  		case VT_STORAGE:
  		case VT_STREAMED_OBJECT:
  		case VT_STORED_OBJECT:
  		case VT_BLOB_OBJECT:
  		case VT_CF:
  		case VT_CLSID:
  		default:
  
  			TrapSz ("ScEmitterNodeFromVariant() unknown type");
  			return E_UNEXPECTED;
  			break;
  	}
  
  	//	Create the emitter node
  	//
  	sc = en.ScConstructNode (emitter,
  							 enParent.Pxn(),
  							 pwszTag,
  							 pwszValue,
  							 pwszType);
  	if (FAILED (sc))
  		goto ret;
  
  ret:
  	return sc;
  }
  