|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <assert.h> |
|
20 #include <string.h> |
|
21 #include <ctype.h> |
|
22 #include <stdlib.h> |
|
23 |
|
24 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) |
|
25 #include <sstream> |
|
26 #include <iostream> |
|
27 using std::cerr; |
|
28 using std::endl; |
|
29 #else //!__MSVCDOTNET__ |
|
30 #ifndef __LINUX__ |
|
31 #include <strstrea.h> |
|
32 #endif //!__LINUX__ |
|
33 #endif //__MSVCDOTNET__ |
|
34 |
|
35 #include "ASTRING.H" |
|
36 #include "NUMVAL.H" |
|
37 #include "STRUCTST.H" |
|
38 #include "Parser.h" |
|
39 #include "rcomp.hpp" |
|
40 #include "MEM.H" |
|
41 #include "ERRORHAN.H" |
|
42 #include "RCBINSTR.H" |
|
43 |
|
44 #if defined(__VC32__) |
|
45 #pragma warning( disable : 4702 ) // unreachable code |
|
46 #endif |
|
47 |
|
48 NumericValue::NumericValue( const String & Source, DataType NumericValueType): |
|
49 iNumericValueType( NumericValueType), |
|
50 iData( NULL), |
|
51 iULongValue( 0), |
|
52 iSignedValue( 0), |
|
53 iDoubleValue( 0.0) |
|
54 { |
|
55 AllocateSpace(); |
|
56 ConvertToNumber( Source); |
|
57 } |
|
58 |
|
59 NumericValue::NumericValue( DataType NumericValueType): |
|
60 iNumericValueType( NumericValueType), |
|
61 iData( NULL), |
|
62 iULongValue( 0), |
|
63 iSignedValue( 0), |
|
64 iDoubleValue( 0.0) |
|
65 { |
|
66 AllocateSpace(); |
|
67 } |
|
68 |
|
69 NumericValue::NumericValue( unsigned long ValueToSet, DataType NumericValueType): |
|
70 iNumericValueType( NumericValueType), |
|
71 iData( NULL), |
|
72 iULongValue( 0), |
|
73 iSignedValue( 0), |
|
74 iDoubleValue( 0.0) |
|
75 { |
|
76 AllocateSpace(); |
|
77 StoreValue( ValueToSet); |
|
78 } |
|
79 |
|
80 NumericValue::~NumericValue() |
|
81 { |
|
82 delete [] iData; |
|
83 } |
|
84 |
|
85 NumericValue::NumericValue( const NumericValue & Source): |
|
86 iNumericValueType( Source.iNumericValueType), |
|
87 iData( NULL), |
|
88 iULongValue( 0), |
|
89 iSignedValue( 0), |
|
90 iDoubleValue( 0.0) |
|
91 { |
|
92 AllocateSpace(); |
|
93 memcpy( iData, Source.iData, iSize); |
|
94 } |
|
95 |
|
96 void NumericValue::AllocateSpace() |
|
97 { |
|
98 switch(iNumericValueType) |
|
99 { |
|
100 case L_BYTE: |
|
101 iData = new unsigned char [1]; |
|
102 iSize = 1; |
|
103 break; |
|
104 case L_WORD: |
|
105 iData = new unsigned char [2]; |
|
106 iSize = 2; |
|
107 break; |
|
108 case L_LONG: |
|
109 iData = new unsigned char [4]; |
|
110 iSize = 4; |
|
111 break; |
|
112 default: |
|
113 if ( iNumericValueType != L_DOUBLE) |
|
114 assert(0); // Cannot use NumericValue for specified data type. |
|
115 } |
|
116 |
|
117 if ( iNumericValueType != L_DOUBLE && iData == NULL) |
|
118 { |
|
119 ErrorHandler::OutputErrorLine( "Failed to allocate space for number."); |
|
120 exit(1); |
|
121 } |
|
122 } |
|
123 |
|
124 const unsigned char * NumericValue::Data() const |
|
125 { |
|
126 return iData; |
|
127 } |
|
128 |
|
129 unsigned long NumericValue::Size() const |
|
130 { |
|
131 return iSize; |
|
132 } |
|
133 |
|
134 DataType NumericValue::NumericValueType() const |
|
135 { |
|
136 return iNumericValueType; |
|
137 } |
|
138 |
|
139 void NumericValue::ConvertToNumber( const String & Source) |
|
140 { |
|
141 if ( iNumericValueType == L_DOUBLE) |
|
142 ConvertToDouble( Source); |
|
143 else |
|
144 ConvertToNatural( Source); |
|
145 } |
|
146 |
|
147 void NumericValue::ConvertToDouble( const String & Source) |
|
148 { |
|
149 assert( iNumericValueType == L_DOUBLE); |
|
150 assert( Source.Length() > 0); |
|
151 |
|
152 double d = atof( Source.GetAssertedNonEmptyBuffer()); |
|
153 if ( d == 0.0 && !( Source == "0.0" || Source == "0") ) |
|
154 { MOFF; cerr << "atof may have failed for " << Source << endl; MON;} |
|
155 |
|
156 iDoubleValue = d; |
|
157 } |
|
158 |
|
159 #if defined(__VC32__) |
|
160 #pragma warning( disable : 4706 ) // assignment within conditional expression |
|
161 #endif |
|
162 |
|
163 void NumericValue::ConvertToNatural( const String & Source) |
|
164 { |
|
165 unsigned long LongValue = 0; |
|
166 |
|
167 assert( sizeof( unsigned long) >= 4); // Assume that LongValue can hold at least 2^32 - 1. |
|
168 |
|
169 const char * pSourceChar = Source.iRep; |
|
170 int bLeadingHyphen = 0; |
|
171 int bHexNumber = 0; |
|
172 |
|
173 if ( pSourceChar[0] == '0' && pSourceChar[1] == 'x') |
|
174 { |
|
175 bHexNumber = 1; |
|
176 pSourceChar++; |
|
177 pSourceChar++; |
|
178 } |
|
179 |
|
180 if ( pSourceChar[0] == '-') |
|
181 { |
|
182 bLeadingHyphen = 1; |
|
183 pSourceChar++; |
|
184 } |
|
185 |
|
186 while ( * pSourceChar != '\0') |
|
187 { |
|
188 unsigned char DigitValue; |
|
189 |
|
190 if ( bHexNumber) |
|
191 { |
|
192 assert( isxdigit( * pSourceChar) ); |
|
193 if ( isdigit( * pSourceChar) ) |
|
194 DigitValue = (unsigned char)(* pSourceChar - '0'); |
|
195 else |
|
196 DigitValue = (unsigned char)(toupper( * pSourceChar) - 'A' + 10); |
|
197 if (LongValue >= 0x10000000) |
|
198 { |
|
199 String st("Number \""); |
|
200 st += Source; |
|
201 st += "\" is too big "; |
|
202 ErrorHandler::OutputErrorLine(st); //prevents overflow if number is bigger than 2^32 - 1. |
|
203 } |
|
204 LongValue = LongValue * 16 + DigitValue; |
|
205 } |
|
206 else |
|
207 { |
|
208 if ( ! isdigit( * pSourceChar) ) |
|
209 { |
|
210 String s( "Cannot convert \""); |
|
211 s += Source; |
|
212 s += "\" to a number."; |
|
213 ErrorHandler::OutputErrorLine( s); |
|
214 exit(1); |
|
215 // unreachable code |
|
216 } |
|
217 DigitValue = (unsigned char)(* pSourceChar - '0'); |
|
218 if ((LongValue > 429496729) || ((LongValue == 429496729) && (DigitValue > 5))) |
|
219 { |
|
220 String st("Number \""); |
|
221 st += Source; |
|
222 st += "\" is too big "; |
|
223 ErrorHandler::OutputErrorLine(st); //prevents overflow if number is bigger than 2^32 - 1. |
|
224 } |
|
225 LongValue = LongValue * 10 + DigitValue; |
|
226 } |
|
227 pSourceChar++; |
|
228 assert( ( pSourceChar - Source.iRep) < 10000); // Safety check! |
|
229 } |
|
230 |
|
231 int inrange=0; |
|
232 |
|
233 // Check value is within the allowed range for the type taking into account |
|
234 // a leading hyphen (minus sign) if there was one. |
|
235 switch( iNumericValueType) |
|
236 { |
|
237 case L_BYTE: // L_BYTE is 8 bits long. |
|
238 if ( bLeadingHyphen) |
|
239 { |
|
240 if ( ! ( inrange = (LongValue <= 128) ) ) // 2 ^ 7 |
|
241 ErrorHandler::OutputErrorLine( "Number too low for BYTE"); |
|
242 } |
|
243 else |
|
244 if ( ! ( inrange = (LongValue <= 0xFF) ) ) |
|
245 ErrorHandler::OutputErrorLine( "Number too big for BYTE"); |
|
246 break; |
|
247 case L_WORD: // L_WORD is 16-bits long. |
|
248 if ( bLeadingHyphen) |
|
249 { |
|
250 if ( ! ( inrange = (LongValue <= 32768) ) ) // 2^15 |
|
251 ErrorHandler::OutputErrorLine( "Number too low for WORD"); |
|
252 } |
|
253 else |
|
254 if ( ! ( inrange = (LongValue <= 0xFFFF) ) ) |
|
255 ErrorHandler::OutputErrorLine( "Number too big for WORD"); |
|
256 break; |
|
257 case L_LONG: // L_LONG is 32-bits long |
|
258 if ( bLeadingHyphen) |
|
259 { |
|
260 if ( ! ( inrange = (LongValue <= 0x80000000) ) ) // 2^31 |
|
261 ErrorHandler::OutputErrorLine( "Number too low for LONG"); |
|
262 } |
|
263 else |
|
264 if ( ! ( inrange = (LongValue <= 0xFFFFFFFF ) ) ) // This test is a bit pointless as long cannot be greater than 0xffffffff |
|
265 ErrorHandler::OutputErrorLine( "Number too big for LONG"); |
|
266 break; |
|
267 default: |
|
268 assert(0); // Other data types cannot be converted to natural numbers. |
|
269 } |
|
270 |
|
271 if(!inrange) |
|
272 exit(1); |
|
273 |
|
274 StoreValue( LongValue); |
|
275 |
|
276 // If there was a hyphen then make the stored number negative (using two's complement). |
|
277 if ( bLeadingHyphen) |
|
278 { |
|
279 LongValue = (LongValue ^ 0xFFFFFFFFu)+1; |
|
280 |
|
281 // Output file will be treated as little-endian. |
|
282 switch ( iNumericValueType) |
|
283 { |
|
284 case L_LONG: |
|
285 iData[3] = (unsigned char)((LongValue & 0xFF000000) >> 24); |
|
286 iData[2] = (unsigned char)((LongValue & 0xFF0000) >> 16); |
|
287 case L_WORD: |
|
288 iData[1] = (unsigned char)((LongValue & 0xFF00) >> 8); |
|
289 case L_BYTE: |
|
290 iData[0] = (unsigned char)(LongValue & 0xFF); |
|
291 } |
|
292 } |
|
293 } |
|
294 |
|
295 #if defined(__VC32__) |
|
296 #pragma warning( default : 4706 ) // assignment within conditional expression |
|
297 #endif |
|
298 |
|
299 void NumericValue::StoreValue( unsigned long LongValue) |
|
300 { |
|
301 iULongValue = LongValue; |
|
302 |
|
303 if ( LongValue <= 0x80000000) |
|
304 iSignedValue = (unsigned long) LongValue; |
|
305 |
|
306 int inrange = 1; |
|
307 |
|
308 switch( iNumericValueType) |
|
309 { |
|
310 case L_BYTE: |
|
311 inrange = ( LongValue <= 0xFF); |
|
312 break; |
|
313 case L_WORD: |
|
314 inrange = ( LongValue <= 0xFFFF); |
|
315 break; |
|
316 case L_LONG: |
|
317 inrange = ( LongValue <= 0xFFFFFFFF); |
|
318 } |
|
319 |
|
320 if ( ! inrange) |
|
321 { |
|
322 ErrorHandler::OutputErrorLine( "Numeric value out of range for specified type"); |
|
323 exit(1); |
|
324 } |
|
325 |
|
326 // Output file will be treated as little-endian. |
|
327 switch ( iNumericValueType) |
|
328 { |
|
329 case L_LONG: |
|
330 iData[3] = (unsigned char)((LongValue & 0xFF000000) >> 24); |
|
331 iData[2] = (unsigned char)((LongValue & 0xFF0000) >> 16); |
|
332 case L_WORD: |
|
333 iData[1] = (unsigned char)((LongValue & 0xFF00) >> 8); |
|
334 case L_BYTE: |
|
335 iData[0] = (unsigned char)(LongValue & 0xFF); |
|
336 } |
|
337 } |
|
338 |
|
339 template<bool> class __CompileTimeAssert {public: __CompileTimeAssert(...) {}}; |
|
340 template<> class __CompileTimeAssert<false> {}; |
|
341 struct COMPILE_TIME_ERROR {}; |
|
342 #define COMPILE_TIME_ASSERT(aCondition) { __CompileTimeAssert<(aCondition)> __temp = __CompileTimeAssert<(aCondition)>(COMPILE_TIME_ERROR()); } |
|
343 |
|
344 RCBinaryStream & operator<< ( RCBinaryStream & os, NumericValue o) |
|
345 { |
|
346 switch( o.iNumericValueType) |
|
347 { |
|
348 case L_BYTE: |
|
349 os.Write( o.iData, 1); |
|
350 break; |
|
351 case L_WORD: |
|
352 os.Write( o.iData, 2); |
|
353 break; |
|
354 case L_LONG: |
|
355 os.Write( o.iData, 4); |
|
356 break; |
|
357 case L_DOUBLE: |
|
358 COMPILE_TIME_ASSERT(sizeof(double) == 8); |
|
359 os.Write(reinterpret_cast<unsigned char*>(&o.iDoubleValue), 8); |
|
360 break; |
|
361 default: |
|
362 assert(0); |
|
363 } |
|
364 |
|
365 return os; |
|
366 } |
|
367 |
|
368 void NumericValue::StreamOut(ResourceDataStream& aStream) const |
|
369 { |
|
370 switch (iNumericValueType) |
|
371 { |
|
372 case L_BYTE: |
|
373 aStream.StreamIn(iData, 1); |
|
374 break; |
|
375 case L_WORD: |
|
376 aStream.StreamIn(iData, 2); |
|
377 break; |
|
378 case L_LONG: |
|
379 aStream.StreamIn(iData, 4); |
|
380 break; |
|
381 case L_DOUBLE: |
|
382 COMPILE_TIME_ASSERT(sizeof(double) == 8); |
|
383 aStream.StreamIn(reinterpret_cast<const unsigned char*>(&iDoubleValue), 8); |
|
384 break; |
|
385 default: |
|
386 assert(0); |
|
387 } |
|
388 } |
|
389 |
|
390 NumericValue & NumericValue::operator= ( unsigned long ValueToSet) |
|
391 { |
|
392 StoreValue( ValueToSet); |
|
393 |
|
394 return * this; |
|
395 } |
|
396 |
|
397 unsigned long NumericValue::GetULong() const |
|
398 { |
|
399 return iULongValue; |
|
400 } |
|
401 |
|
402 long NumericValue::GetLong() const |
|
403 { |
|
404 assert( iULongValue <= 2147483647); // Check that we are not holding a number that is really positive only. |
|
405 return iSignedValue; |
|
406 } |
|
407 |
|
408 bool NumericValue::CheckSigned(unsigned long aValue, DataType aNumericValueType) |
|
409 { |
|
410 switch (aNumericValueType) |
|
411 { |
|
412 case L_BYTE: |
|
413 if (aValue > 0x7f) return false; |
|
414 break; |
|
415 case L_WORD: |
|
416 if (aValue > 0x7fff) return false; |
|
417 break; |
|
418 case L_LONG: |
|
419 if (aValue > 0x7fffffff) return false; |
|
420 break; |
|
421 default: |
|
422 assert(0); |
|
423 } |
|
424 return true; |
|
425 } |
|
426 |
|
427 String NumericValue::ltoa( long Source) |
|
428 { |
|
429 char v[10]; // long can have no more than 10 digits in this implementation. |
|
430 char * pv = v; |
|
431 long x; |
|
432 |
|
433 if ( Source < 0) |
|
434 x = - Source; |
|
435 else |
|
436 x = Source; |
|
437 |
|
438 if ( x == 0) |
|
439 * pv++ = '0'; |
|
440 else |
|
441 { |
|
442 while( x > 0) |
|
443 { |
|
444 assert( pv <= (v+9) ); |
|
445 |
|
446 * pv = char(x%10 + '0'); |
|
447 pv++; |
|
448 x /= 10; |
|
449 } |
|
450 } |
|
451 |
|
452 // Now reverse digits so they are in the correct order. Put in terminating null and hyphen |
|
453 // if necessary. |
|
454 |
|
455 char r[12]; |
|
456 char * pr = r; |
|
457 |
|
458 if ( Source < 0) |
|
459 { |
|
460 r[0] = '-'; |
|
461 pr++; |
|
462 } |
|
463 |
|
464 while( pv != v) |
|
465 { |
|
466 assert( pr < (r+11) ); |
|
467 * pr++ = * --pv; |
|
468 } |
|
469 |
|
470 * pr = '\0'; |
|
471 |
|
472 return r; |
|
473 } |