bintools/rcomp/src/NUMVAL.CPP
changeset 0 044383f39525
child 590 360bd6b35136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/rcomp/src/NUMVAL.CPP	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,473 @@
+/*
+* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
+#include <sstream>
+#include <iostream>
+using std::cerr;
+using std::endl;
+#else //!__MSVCDOTNET__
+#ifndef __LINUX__
+#include <strstrea.h>
+#endif //!__LINUX__
+#endif //__MSVCDOTNET__
+
+#include "ASTRING.H"
+#include "NUMVAL.H"  
+#include "STRUCTST.H"
+#include "Parser.h"
+#include "rcomp.hpp"
+#include "MEM.H"     
+#include "ERRORHAN.H"
+#include "RCBINSTR.H"
+
+#if defined(__VC32__)
+#pragma warning( disable : 4702 )	// unreachable code
+#endif
+
+NumericValue::NumericValue( const String & Source, DataType NumericValueType):
+	iNumericValueType( NumericValueType),
+	iData( NULL),
+	iULongValue( 0),
+	iSignedValue( 0),
+	iDoubleValue( 0.0)
+	{
+	AllocateSpace();
+	ConvertToNumber( Source);
+	}
+
+NumericValue::NumericValue( DataType NumericValueType):
+	iNumericValueType( NumericValueType),
+	iData( NULL),
+	iULongValue( 0),
+	iSignedValue( 0),
+	iDoubleValue( 0.0)
+	{
+	AllocateSpace();
+	}
+
+NumericValue::NumericValue( unsigned long ValueToSet, DataType NumericValueType):
+	iNumericValueType( NumericValueType),
+	iData( NULL),
+	iULongValue( 0),
+	iSignedValue( 0),
+	iDoubleValue( 0.0)
+	{
+	AllocateSpace();
+	StoreValue( ValueToSet);
+	}
+
+NumericValue::~NumericValue()
+	{
+	delete [] iData;
+	}
+
+NumericValue::NumericValue( const NumericValue & Source):
+	iNumericValueType( Source.iNumericValueType),
+	iData( NULL),
+	iULongValue( 0),
+	iSignedValue( 0),
+	iDoubleValue( 0.0)	
+	{
+	AllocateSpace();
+	memcpy( iData, Source.iData, iSize);
+	}
+
+void NumericValue::AllocateSpace()
+	{
+	switch(iNumericValueType)
+		{
+		case L_BYTE:
+			iData = new unsigned char [1];
+			iSize = 1;
+			break;
+		case L_WORD:
+			iData = new unsigned char [2];
+			iSize = 2;
+			break;
+		case L_LONG:
+			iData = new unsigned char [4];
+			iSize = 4;
+			break;
+		default:
+			if ( iNumericValueType != L_DOUBLE)
+				assert(0);	// Cannot use NumericValue for specified data type.
+		}
+
+	if ( iNumericValueType != L_DOUBLE && iData == NULL)
+		{
+		ErrorHandler::OutputErrorLine( "Failed to allocate space for number.");
+		exit(1);
+		}
+	}
+
+const unsigned char * NumericValue::Data() const
+	{
+	return iData;
+	}
+
+unsigned long NumericValue::Size() const
+	{
+	return iSize;
+	}
+
+DataType NumericValue::NumericValueType() const
+	{
+	return iNumericValueType;
+	}
+
+void NumericValue::ConvertToNumber( const String & Source)
+	{
+	if ( iNumericValueType == L_DOUBLE)
+		ConvertToDouble( Source);
+	else
+		ConvertToNatural( Source);
+	}
+
+void NumericValue::ConvertToDouble( const String & Source)
+	{
+	assert( iNumericValueType == L_DOUBLE);
+	assert( Source.Length() > 0);
+	
+	double d = atof( Source.GetAssertedNonEmptyBuffer());
+	if ( d == 0.0 && !( Source == "0.0" || Source == "0") )
+		{ MOFF; cerr << "atof may have failed for " << Source << endl; MON;}
+		
+	iDoubleValue = d;
+	}
+ 
+#if defined(__VC32__)
+#pragma warning( disable : 4706 ) // assignment within conditional expression
+#endif
+
+void NumericValue::ConvertToNatural( const String & Source)
+	{
+	unsigned long	LongValue = 0;
+	
+	assert( sizeof( unsigned long) >= 4);	// Assume that LongValue can hold at least 2^32 - 1.
+	
+	const char *	pSourceChar = Source.iRep;
+	int	bLeadingHyphen = 0;
+	int	bHexNumber = 0;
+
+	if ( pSourceChar[0] == '0' && pSourceChar[1] == 'x')
+		{
+		bHexNumber = 1;
+		pSourceChar++;
+		pSourceChar++;
+		}
+	
+	if ( pSourceChar[0] == '-')
+		{
+		bLeadingHyphen = 1;
+		pSourceChar++;
+		}
+
+	while ( * pSourceChar != '\0')
+		{
+		unsigned char DigitValue;
+		
+		if ( bHexNumber)
+			{
+			assert( isxdigit( * pSourceChar) );
+			if ( isdigit( * pSourceChar) )
+				DigitValue = (unsigned char)(* pSourceChar - '0');
+			else
+				DigitValue = (unsigned char)(toupper( * pSourceChar) - 'A' + 10);
+				if (LongValue >= 0x10000000)
+					{
+					String st("Number \"");	
+					st += Source;
+					st +=  "\" is too big ";
+					ErrorHandler::OutputErrorLine(st);	//prevents overflow if number is bigger than 2^32 - 1.
+					}
+			LongValue = LongValue * 16 + DigitValue;
+			}
+		else
+			{
+			if ( ! isdigit( * pSourceChar) )
+				{
+				String s( "Cannot convert \"");
+				s += Source;
+				s += "\" to a number.";
+				ErrorHandler::OutputErrorLine( s);
+				exit(1);
+				// unreachable code
+				}
+			DigitValue = (unsigned char)(* pSourceChar - '0');
+			if ((LongValue > 429496729) || ((LongValue == 429496729) && (DigitValue > 5)))
+				{
+				String st("Number \"");	
+				st += Source;
+				st +=  "\" is too big ";
+				ErrorHandler::OutputErrorLine(st);	//prevents overflow if number is bigger than 2^32 - 1.
+				}
+			LongValue = LongValue * 10 + DigitValue;
+			}	
+		pSourceChar++;		
+		assert( ( pSourceChar - Source.iRep) < 10000);	// Safety check!
+		}
+
+	int inrange=0;
+	
+	// Check value is within the allowed range for the type taking into account
+	// a leading hyphen (minus sign) if there was one.
+	switch( iNumericValueType)
+		{
+		case L_BYTE:							// L_BYTE is 8 bits long.
+			if ( bLeadingHyphen)
+				{
+				if ( ! ( inrange = (LongValue <= 128) ) )			// 2 ^ 7
+					ErrorHandler::OutputErrorLine( "Number too low for BYTE");
+				}
+			else
+				if ( ! ( inrange = (LongValue <= 0xFF) ) )
+					ErrorHandler::OutputErrorLine( "Number too big for BYTE");
+			break;
+		case L_WORD:							// L_WORD is 16-bits long.
+			if ( bLeadingHyphen)
+				{
+				if ( ! ( inrange = (LongValue <= 32768) ) )		// 2^15
+					ErrorHandler::OutputErrorLine( "Number too low for WORD");
+				}
+			else
+				if ( ! ( inrange = (LongValue <= 0xFFFF) ) )
+					ErrorHandler::OutputErrorLine( "Number too big for WORD");
+			break;
+		case L_LONG:							// L_LONG is 32-bits long
+			if ( bLeadingHyphen)
+				{
+				if ( ! ( inrange = (LongValue <= 0x80000000) ) )	// 2^31
+					ErrorHandler::OutputErrorLine( "Number too low for LONG");
+				}
+			else
+				if ( ! ( inrange = (LongValue <= 0xFFFFFFFF ) ) ) // This test is a bit pointless as long cannot be greater than 0xffffffff
+					ErrorHandler::OutputErrorLine( "Number too big for LONG");
+			break;
+		default:
+			assert(0);	// Other data types cannot be converted to natural numbers.
+		}
+
+	if(!inrange)
+		exit(1);
+	
+	StoreValue( LongValue);
+
+	// If there was a hyphen then make the stored number negative (using two's complement).
+	if ( bLeadingHyphen)
+		{
+		LongValue = (LongValue ^ 0xFFFFFFFFu)+1;
+
+		// Output file will be treated as little-endian.
+		switch ( iNumericValueType)
+			{
+			case L_LONG:
+				iData[3] = (unsigned char)((LongValue & 0xFF000000) >> 24);
+				iData[2] = (unsigned char)((LongValue & 0xFF0000) >> 16);
+			case L_WORD:
+				iData[1] = (unsigned char)((LongValue & 0xFF00) >> 8);
+			case L_BYTE:
+				iData[0] = (unsigned char)(LongValue & 0xFF);
+			}
+		}
+	}
+
+#if defined(__VC32__)
+#pragma warning( default : 4706 ) // assignment within conditional expression
+#endif
+
+void NumericValue::StoreValue( unsigned long LongValue)
+	{		
+	iULongValue = LongValue;
+	
+	if ( LongValue <= 0x80000000)
+		iSignedValue = (unsigned long) LongValue;
+
+	int inrange = 1;
+		
+	switch( iNumericValueType)
+		{
+		case L_BYTE:
+			inrange = ( LongValue <= 0xFF);
+			break;
+		case L_WORD:
+			inrange = ( LongValue <= 0xFFFF);
+			break;
+		case L_LONG:
+			inrange = ( LongValue <= 0xFFFFFFFF);
+		}
+
+	if ( ! inrange)	
+		{
+		ErrorHandler::OutputErrorLine( "Numeric value out of range for specified type");
+		exit(1);
+		}
+
+	// Output file will be treated as little-endian.
+	switch ( iNumericValueType)
+		{
+		case L_LONG:
+			iData[3] = (unsigned char)((LongValue & 0xFF000000) >> 24);
+			iData[2] = (unsigned char)((LongValue & 0xFF0000) >> 16);
+		case L_WORD:
+			iData[1] = (unsigned char)((LongValue & 0xFF00) >> 8);
+		case L_BYTE:
+			iData[0] = (unsigned char)(LongValue & 0xFF);
+		}
+	}
+
+template<bool> class __CompileTimeAssert {public: __CompileTimeAssert(...) {}};
+template<> class __CompileTimeAssert<false> {};
+struct COMPILE_TIME_ERROR {};
+#define COMPILE_TIME_ASSERT(aCondition) { __CompileTimeAssert<(aCondition)> __temp = __CompileTimeAssert<(aCondition)>(COMPILE_TIME_ERROR()); }
+
+RCBinaryStream & operator<< ( RCBinaryStream & os, NumericValue o)
+	{
+	switch( o.iNumericValueType)
+		{
+		case L_BYTE:
+			os.Write( o.iData, 1);
+			break;
+		case L_WORD:
+			os.Write( o.iData, 2);
+			break;
+		case L_LONG:
+			os.Write( o.iData, 4);
+			break;
+		case L_DOUBLE:
+			COMPILE_TIME_ASSERT(sizeof(double) == 8);
+			os.Write(reinterpret_cast<unsigned char*>(&o.iDoubleValue), 8);
+			break;
+		default:
+			assert(0);
+		}
+	
+	return os;
+	}
+
+void NumericValue::StreamOut(ResourceDataStream& aStream) const
+	{
+	switch (iNumericValueType)
+		{
+		case L_BYTE:
+			aStream.StreamIn(iData, 1);
+			break;
+		case L_WORD:
+			aStream.StreamIn(iData, 2);
+			break;
+		case L_LONG:
+			aStream.StreamIn(iData, 4);
+			break;
+		case L_DOUBLE:
+			COMPILE_TIME_ASSERT(sizeof(double) == 8);
+			aStream.StreamIn(reinterpret_cast<const unsigned char*>(&iDoubleValue), 8);
+			break;
+		default:
+			assert(0);
+		}
+	}
+
+NumericValue & NumericValue::operator= ( unsigned long ValueToSet)
+	{
+	StoreValue( ValueToSet);
+	
+	return * this;
+	}
+
+unsigned long NumericValue::GetULong() const
+	{
+	return iULongValue;
+	}
+
+long NumericValue::GetLong() const
+	{
+	assert( iULongValue <= 2147483647);	// Check that we are not holding a number that is really positive only.
+	return iSignedValue;
+	}
+
+bool NumericValue::CheckSigned(unsigned long aValue, DataType aNumericValueType)
+	{
+	switch (aNumericValueType)
+		{
+		case L_BYTE:
+			if (aValue > 0x7f) return false;
+			break;
+		case L_WORD:
+			if (aValue > 0x7fff) return false;
+			break;
+		case L_LONG:
+			if (aValue > 0x7fffffff) return false;
+			break;
+		default:
+			assert(0);
+		}
+	return true;
+	}
+
+String NumericValue::ltoa( long Source)
+	{
+	char	v[10];	// long can have no more than 10 digits in this implementation.
+	char *	pv = v;
+	long	x;
+	
+	if ( Source < 0)
+		x = - Source;
+	else
+		x = Source;
+
+	if ( x == 0)
+		* pv++ = '0';
+	else
+		{
+		while( x > 0)
+			{
+			assert( pv <= (v+9) );
+
+			* pv = char(x%10 + '0');
+			pv++;
+			x /= 10;
+			}
+		}
+
+	// Now reverse digits so they are in the correct order. Put in terminating null and hyphen
+	// if necessary.
+	
+	char	r[12];
+	char *	pr = r;
+
+	if ( Source < 0)
+		{
+		r[0] = '-';
+		pr++;
+		}
+
+	while( pv != v)
+		{
+		assert( pr < (r+11) );
+		* pr++ = * --pv;
+		}
+		
+	* pr = '\0';
+	
+	return r;
+	}