diff -r 000000000000 -r 044383f39525 bintools/rcomp/src/NUMVAL.CPP --- /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 +#include +#include +#include + +#if defined(__MSVCDOTNET__) || defined(__TOOLS2__) +#include +#include +using std::cerr; +using std::endl; +#else //!__MSVCDOTNET__ +#ifndef __LINUX__ +#include +#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 class __CompileTimeAssert {public: __CompileTimeAssert(...) {}}; +template<> class __CompileTimeAssert {}; +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(&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(&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; + }