]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c++-lib/c++/asn-real.cpp
Security-54.1.7.tar.gz
[apple/security.git] / SecuritySNACCRuntime / c++-lib / c++ / asn-real.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 // file: .../c++-lib/src/asn-real.C - AsnReal (ASN.1 REAL) type
20 //
21 // Mike Sample
22 // 92/07/02
23 // Copyright (C) 1992 Michael Sample and the University of British Columbia
24 //
25 // This library is free software; you can redistribute it and/or
26 // modify it provided that this copyright/license information is retained
27 // in original form.
28 //
29 // If you modify this file, you must clearly indicate your changes.
30 //
31 // This source code is distributed in the hope that it will be
32 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
33 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
34 //
35 // $Header: /cvs/root/Security/SecuritySNACCRuntime/c++-lib/c++/Attic/asn-real.cpp,v 1.4 2002/03/21 05:38:45 dmitch Exp $
36 // $Log: asn-real.cpp,v $
37 // Revision 1.4 2002/03/21 05:38:45 dmitch
38 // Radar 2868524: no more setjmp/longjmp in SNACC-generated code.
39 //
40 // Revision 1.3.44.1 2002/03/20 00:36:50 dmitch
41 // Radar 2868524: SNACC-generated code now uses throw/catch instead of setjmp/longjmp.
42 //
43 // Revision 1.3 2001/06/27 23:09:15 dmitch
44 // Pusuant to Radar 2664258, avoid all cerr-based output in NDEBUG configuration.
45 //
46 // Revision 1.2 2001/06/21 21:57:00 dmitch
47 // Avoid global const PLUS_INFINITY, MINUS_INFINITY
48 //
49 // Revision 1.1.1.1 2001/05/18 23:14:06 mb
50 // Move from private repository to open source repository
51 //
52 // Revision 1.3 2001/05/05 00:59:19 rmurphy
53 // Adding darwin license headers
54 //
55 // Revision 1.2 2000/06/08 20:05:36 dmitch
56 // Mods for X port. These files are actually machine generated and probably don't need to be in CVS....
57 //
58 // Revision 1.1.1.1 2000/03/09 01:00:06 rmurphy
59 // Base Fortissimo Tree
60 //
61 // Revision 1.3 1999/03/21 02:07:37 mb
62 // Added Copy to every AsnType.
63 //
64 // Revision 1.2 1999/02/26 00:23:40 mb
65 // Fixed for Mac OS 8
66 //
67 // Revision 1.1 1999/02/25 05:21:53 mb
68 // Added snacc c++ library
69 //
70 // Revision 1.7 1997/02/28 13:39:46 wan
71 // Modifications collected for new version 1.3: Bug fixes, tk4.2.
72 //
73 // Revision 1.6 1995/08/17 15:27:19 rj
74 // recognize and return "±inf" for PLUS-INFINITY/MINUS-INFINITY.
75 //
76 // Revision 1.5 1995/07/24 20:29:24 rj
77 // #if TCL ... #endif wrapped into #if META ... #endif
78 //
79 // call constructor with additional pdu and create arguments.
80 //
81 // changed `_' to `-' in file names.
82 //
83 // Revision 1.4 1995/02/18 17:01:49 rj
84 // denote a long if we want a long.
85 // make the code work on little endian CPUs.
86 // ported to work with CPU/compiler combinations providing 64 bit longs.
87 //
88 // Revision 1.3 1994/10/08 04:18:29 rj
89 // code for meta structures added (provides information about the generated code itself).
90 //
91 // code for Tcl interface added (makes use of the above mentioned meta code).
92 //
93 // virtual inline functions (the destructor, the Clone() function, BEnc(), BDec() and Print()) moved from inc/*.h to src/*.C because g++ turns every one of them into a static non-inline function in every file where the .h file gets included.
94 //
95 // made Print() const (and some other, mainly comparison functions).
96 //
97 // several `unsigned long int' turned into `size_t'.
98 //
99 // Revision 1.2 1994/08/28 10:01:18 rj
100 // comment leader fixed.
101 //
102 // Revision 1.1 1994/08/28 09:21:07 rj
103 // first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
104
105 #include "asn-config.h"
106 #include "asn-len.h"
107 #include "asn-tag.h"
108 #include "asn-type.h"
109 #include "asn-real.h"
110
111 #ifndef IEEE_REAL_LIB
112 /* ieee functions (in case not in math.h)*/
113 extern "C" {
114 extern int iszero (double);
115 //extern int isinf (double);
116 //extern int signbit (double);
117 extern int ilogb (double);
118 //extern double scalbn (double, int);
119 }
120 #endif
121
122 double AsnPlusInfinity();
123 double AsnMinusInfinity();
124
125 #define ENC_PLUS_INFINITY 0x40
126 #define ENC_MINUS_INFINITY 0x41
127
128 #define REAL_BINARY 0x80
129 #define REAL_SIGN 0x40
130 #define REAL_EXPLEN_MASK 0x03
131 #define REAL_EXPLEN_1 0x00
132 #define REAL_EXPLEN_2 0x01
133 #define REAL_EXPLEN_3 0x02
134 #define REAL_EXPLEN_LONG 0x03
135 #define REAL_FACTOR_MASK 0x0c
136 #define REAL_BASE_MASK 0x30
137 #define REAL_BASE_2 0x00
138 #define REAL_BASE_8 0x10
139 #define REAL_BASE_16 0x20
140
141 AsnType *AsnReal::Clone() const
142 {
143 return new AsnReal;
144 }
145
146 AsnType *AsnReal::Copy() const
147 {
148 return new AsnReal (*this);
149 }
150
151 // Returns the smallest octet length needed to hold the given long int value
152 static unsigned int
153 SignedIntOctetLen (long int val)
154 {
155 unsigned long int mask = (0x7f80L << ((sizeof (long int) - 2) * 8));
156 unsigned int retVal = sizeof (long int);
157
158 if (val < 0)
159 val = val ^ (~0L); /* XOR val with all 1's */
160
161 while ((retVal > 1) && ((val & mask) == 0))
162 {
163 mask >>= 8;
164 retVal--;
165 }
166
167 return retVal;
168
169 } /* SignedIntOctetLen */
170
171
172
173 #ifdef IEEE_REAL_FMT
174
175 // Returns the PLUS INFINITY in double format
176 // This assumes that a C++ double is an IEEE double.
177 // The bits for IEEE double PLUS INFINITY are
178 // 0x7ff0000000000000
179 double AsnPlusInfinity()
180 {
181 #ifndef _IBM_ENC_
182 double d;
183 unsigned char *c = (unsigned char *)&d;
184
185 #if WORDS_BIGENDIAN
186 c[0] = 0x7f;
187 c[1] = 0xf0;
188 c[2] = 0x0;
189 c[3] = 0x0;
190 c[4] = 0x0;
191 c[5] = 0x0;
192 c[6] = 0x0;
193 c[7] = 0x0;
194 #else
195 c[7] = 0x7f;
196 c[6] = 0xf0;
197 c[5] = 0x0;
198 c[4] = 0x0;
199 c[3] = 0x0;
200 c[2] = 0x0;
201 c[1] = 0x0;
202 c[0] = 0x0;
203 #endif
204
205 return d;
206 #else
207 return 1.7976931348623158e+308;
208 #endif /* _IBM_ENC_ */
209 } /* AsnPlusInfinity */
210
211 double AsnMinusInfinity()
212 {
213 return -AsnPlusInfinity();
214 }
215
216 #if SIZEOF_DOUBLE != 8
217 #error oops: doubles are expected to be 8 bytes in size!
218 #endif
219
220 /*
221 * Use this routine if you system/compiler represents doubles in the IEEE format.
222 */
223 AsnLen AsnReal::BEncContent (BUF_TYPE b)
224 {
225 int exponent;
226 int isNeg;
227 #if SIZEOF_LONG == 8
228 unsigned long mantissa, val, *p;
229 int i;
230 #elif SIZEOF_LONG == 4
231 unsigned char *dbl;
232 unsigned long int *first4;
233 unsigned long int *second4;
234 #else
235 #error long neither 8 nor 4 bytes in size?
236 #endif
237
238 /* no contents for 0.0 reals */
239 if (value == 0.0) /* all bits zero, disregarding top/sign bit */
240 return 0;
241
242 #if SIZEOF_LONG == 8
243 /*
244 * this part assumes that sizeof (long) == sizeof (double) == 8
245 * It shouldn't be endian-dependent but I haven't verified that
246 */
247
248 p = (unsigned long*) &value;
249 val = *p;
250
251 isNeg = (val >> 63) & 1;
252 /* special real values for +/- oo */
253 if (!finite (value))
254 {
255 if (isNeg)
256 b.PutByteRvs(ENC_MINUS_INFINITY);
257 else
258 b.PutByteRvs(ENC_PLUS_INFINITY);
259 return 1;
260 }
261 else /* encode a binary real value */
262 {
263 exponent = (val >> 52) & 0x7ff;
264 mantissa = (val & 0xfffffffffffffL) | 0x10000000000000L;
265
266 for (i = 0; i < 7; i++)
267 {
268 b.PutByteRvs(mantissa & 0xff);
269 mantissa >>= 8;
270 }
271 exponent -= (1023 + 52);
272
273 #elif SIZEOF_LONG == 4
274 /*
275 * this part assumes that sizeof (long) == 4 and
276 * that sizeof (double) == 8
277 *
278 * sign exponent
279 * b 2-12 incl
280 * Sv-----------v----- rest is mantissa
281 * -------------------------------------------
282 * | |
283 * -------------------------------------------
284 * 123456878 1234
285 *
286 * sign bit is 1 if real is < 0
287 * exponent is an 11 bit unsigned value (subtract 1023 to get correct exp value)
288 * decimal pt implied before mantissa (ie mantissa is all fractional)
289 * and implicit 1 bit to left of decimal
290 *
291 * when given NaN (not a number - ie oo/oo) it encodes the wrong value
292 * instead of checking for the error. If you want to check for it,
293 * a NaN is any sign bit with a max exponent (all bits a 1) followed
294 * by any non-zero mantissa. (a zero mantissa is used for infinity)
295 *
296 */
297
298 first4 = (unsigned long int*) (dbl = (unsigned char*) &value);
299 second4 = (unsigned long int *) (dbl + sizeof (long int));
300
301 /* no contents for 0.0 reals */
302 if (value == 0.0) /* all bits zero, disregarding top/sign bit */
303 return 0;
304
305 isNeg = dbl[0] & 0x80;
306
307 /* special real values for +/- oo */
308 if (((*first4 & 0x7fffffff) == 0x7ff00000) && (*second4 == 0))
309 {
310 if (isNeg)
311 b.PutByteRvs (ENC_MINUS_INFINITY);
312 else
313 b.PutByteRvs (ENC_PLUS_INFINITY);
314
315 return 1;
316 }
317 else /* encode a binary real value */
318 {
319 exponent = (((*first4) >> 20) & 0x07ff);
320
321 /* write the mantissa (N value) */
322 b.PutSegRvs ((char*)(dbl+2), sizeof (double)-2);
323
324 /*
325 * The rightmost 4 bits of a double 2nd octet are the
326 * most sig bits of the mantissa.
327 * write the most signficant byte of the asn1 real manitssa,
328 * adding implicit bit to 'left of decimal' if not de-normalized
329 * (de normalized if exponent == 0)
330 *
331 * if the double is not in de-normalized form subtract 1023
332 * from the exponent to get proper signed exponent.
333 *
334 * for both the normalized and de-norm forms
335 * correct the exponent by subtracting 52 since:
336 * 1. mantissa is 52 bits in the double (56 in ASN.1 REAL form)
337 * 2. implicit decimal at the beginning of double's mantissa
338 * 3. ASN.1 REAL's implicit decimal is after its mantissa
339 * so converting the double mantissa to the ASN.1 form has the
340 * effect of multiplying it by 2^52. Subtracting 52 from the
341 * exponent corrects this.
342 */
343 if (exponent == 0) /* de-normalized - no implicit 1 to left of dec.*/
344 {
345 b.PutByteRvs (dbl[1] & 0x0f);
346 exponent -= 52;
347 }
348 else
349 {
350 b.PutByteRvs ((dbl[1] & 0x0f) | 0x10); /* 0x10 adds implicit bit */
351 exponent -= (1023 + 52);
352 }
353
354 #else
355 #error long neither 8 nor 4 bytes in size?
356 #endif
357
358 /* write the exponent */
359 b.PutByteRvs (exponent & 0xff);
360 b.PutByteRvs (exponent >> 8);
361
362 /* write format octet */
363 /* bb is 00 since base is 2 so do nothing */
364 /* ff is 00 since no other shifting is nec */
365 if (isNeg)
366 b.PutByteRvs (REAL_BINARY | REAL_EXPLEN_2 | REAL_SIGN);
367 else
368 b.PutByteRvs (REAL_BINARY | REAL_EXPLEN_2);
369
370 return sizeof (double) + 2;
371 }
372
373 /* not reached */
374
375 } /* AsnReal::BEncContent */
376
377 #else /* IEEE_REAL_FMT not def */
378
379 #ifdef IEEE_REAL_LIB
380
381 // Returns the PLUS INFINITY in double format
382 // this assumes you have the IEEE functions in
383 // the math lib
384 double AsnPlusInfinity()
385 {
386 return infinity();
387 } /* AsnPlusInfinity */
388
389 double AsnMinusInfinity()
390 {
391 return -AsnPlusInfinity();
392 }
393
394 // This routine uses the ieee library routines to encode
395 // this AsnReal's double value
396 AsnLen AsnReal::BEncContent (BUF_TYPE b)
397 {
398 AsnLen encLen;
399 double mantissa;
400 double tmpMantissa;
401 unsigned int truncatedMantissa;
402 int exponent;
403 unsigned int expLen;
404 int sign;
405 unsigned char buf[sizeof (double)];
406 int i, mantissaLen;
407 unsigned char firstOctet;
408
409 /* no contents for 0.0 reals */
410 if (iszero (value))
411 return 0;
412
413 /* special real values for +/- oo */
414 if (isinf (value))
415 {
416 if (signbit (value)) /* neg */
417 b.PutByteRvs (ENC_MINUS_INFINITY);
418 else
419 b.PutByteRvs (ENC_PLUS_INFINITY);
420
421 encLen = 1;
422 }
423 else /* encode a binary real value */
424 {
425 if (signbit (value))
426 sign = -1;
427 else
428 sign = 1;
429
430 exponent = ilogb (value);
431
432 /* get the absolute value of the mantissa (subtract 1 to make < 1) */
433 mantissa = scalbn (fabs (value), -exponent-1);
434
435
436 tmpMantissa = mantissa;
437
438 /* convert mantissa into an unsigned integer */
439 for (i = 0; i < sizeof (double); i++)
440 {
441 /* normalizied so shift 8 bits worth to the left of the decimal */
442 tmpMantissa *= (1<<8);
443
444 /* grab only (octet sized) the integer part */
445 truncatedMantissa = (unsigned int) tmpMantissa;
446
447 /* remove part to left of decimal now for next iteration */
448 tmpMantissa -= truncatedMantissa;
449
450 /* write into tmp buffer */
451 buf[i] = truncatedMantissa;
452
453 /* keep track of last non zero octet so can zap trailing zeros */
454 if (truncatedMantissa)
455 mantissaLen = i+1;
456 }
457
458 /*
459 * write format octet (first octet of content)
460 * field 1 S bb ff ee
461 * bit# 8 7 65 43 21
462 *
463 * 1 in bit#1 means binary rep
464 * 1 in bit#2 means the mantissa is neg, 0 pos
465 * bb is the base: 65 base
466 * 00 2
467 * 01 8
468 * 10 16
469 * 11 future ext.
470 *
471 * ff is the Value of F where Mantissa = sign x N x 2^F
472 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
473 *
474 * ee is the length of the exponent: 21 length
475 * 00 1
476 * 01 2
477 * 10 3
478 * 11 long form
479 *
480 *
481 * encoded binary real value looks like
482 *
483 * fmt oct
484 * --------------------------------------------------------
485 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
486 * --------------------------------------------------------
487 * 87654321
488 */
489 firstOctet = REAL_BINARY;
490 if (signbit (value))
491 firstOctet |= REAL_SIGN;
492
493 /* bb is 00 since base is 2 so do nothing */
494 /* ff is 00 since no other shifting is nec */
495
496 /*
497 * get exponent calculate its encoded length
498 * Note that the process of converting the mantissa
499 * double to an int shifted the decimal mantissaLen * 8
500 * to the right - so correct that here
501 */
502 exponent++; /* compensate for trick to put mantissa < 1 */
503 exponent -= (mantissaLen * 8);
504 expLen = SignedIntOctetLen (exponent);
505
506 switch (expLen)
507 {
508 case 1:
509 firstOctet |= REAL_EXPLEN_1;
510 break;
511 case 2:
512 firstOctet |= REAL_EXPLEN_2;
513 break;
514 case 3:
515 firstOctet |= REAL_EXPLEN_3;
516 break;
517 default:
518 firstOctet |= REAL_EXPLEN_LONG;
519 break;
520 }
521
522 encLen = mantissaLen + expLen + 1;
523
524 /* write the mantissa (N value) */
525 b.PutSegRvs ((char*)buf, mantissaLen);
526
527 /* write the exponent */
528 for (i = expLen; i > 0; i--)
529 {
530 b.PutByteRvs (exponent);
531 exponent >> 8;
532 }
533
534 /* write the exponents length if nec */
535 if (expLen > 3)
536 {
537 encLen++;
538 b.PutByteRvs (expLen);
539 }
540
541 /* write the format octet */
542 b.PutByteRvs (firstOctet);
543
544 }
545 return encLen;
546
547 } /* AsnReal::BEncContent */
548
549 #else /* neither IEEE_REAL_FMT or IEEE_REAL_LIB are def */
550
551
552 // Returns the PLUS INFINITY in double format
553 // This assumes that a C++ double is an IEEE double.
554 // The bits for IEEE double PLUS INFINITY are
555 // 0x7ff0000000000000
556 // NOTE: this is a guess - you should set this up for
557 // your architecture
558 double AsnPlusInfinity()
559 {
560 double d;
561 unsigned char *c;
562 unsigned i;
563
564 c = (unsigned char*)&d;
565 c[0] = 0x7f;
566 c[1] = 0xf0;
567 for (i = 2; i < sizeof (double); i++)
568 c[i] = 0;
569 return d;
570 } /* AsnPlusInfinity */
571
572 double AsnMinusInfinity()
573 {
574 return -AsnPlusInfinity();
575 }
576
577 /*
578 * Encodes the content of an ASN.1 REAL value to the given buffer.
579 * This version of the routine does not assume an IEEE double rep.
580 * or the existence of the IEEE library routines. Uses old style
581 * UNIX frexp etc.
582 */
583 AsnLen AsnReal::BEncContent (BUF_TYPE b)
584 {
585 unsigned long int encLen;
586 double mantissa;
587 double tmpMantissa;
588 unsigned int truncatedMantissa;
589 int exponent;
590 unsigned int expLen;
591 int sign;
592 unsigned char buf[sizeof (double)];
593 unsigned i, mantissaLen;
594 unsigned char firstOctet;
595
596 /* no contents for 0.0 reals */
597 if (value == 0.0)
598 return 0;
599
600 /* special real values for +/- oo */
601 if (value == MINUS_INFINITY)
602 {
603 b.PutByteRvs (ENC_MINUS_INFINITY);
604 encLen = 1;
605 }
606 else if (value == PLUS_INFINITY)
607 {
608 b.PutByteRvs (ENC_PLUS_INFINITY);
609 encLen = 1;
610 }
611 else /* encode a binary real value */
612 {
613 /*
614 * this is what frexp gets from value
615 * value == mantissa * 2^exponent
616 * where 0.5 <= |manitissa| < 1.0
617 */
618 mantissa = frexp (value, &exponent);
619
620 /* set sign and make mantissa = | mantissa | */
621 if (mantissa < 0.0)
622 {
623 sign = -1;
624 mantissa *= -1;
625 }
626 else
627 sign = 1;
628
629
630 tmpMantissa = mantissa;
631
632 /* convert mantissa into an unsigned integer */
633 for (i = 0; i < sizeof (double); i++)
634 {
635 /* normalizied so shift 8 bits worth to the left of the decimal */
636 tmpMantissa *= (1<<8);
637
638 /* grab only (octet sized) the integer part */
639 truncatedMantissa = (unsigned int) tmpMantissa;
640
641 /* remove part to left of decimal now for next iteration */
642 tmpMantissa -= truncatedMantissa;
643
644 /* write into tmp buffer */
645 buf[i] = truncatedMantissa;
646
647 /* keep track of last non zero octet so can zap trailing zeros */
648 if (truncatedMantissa)
649 mantissaLen = i+1;
650 }
651
652 /*
653 * write format octet (first octet of content)
654 * field 1 S bb ff ee
655 * bit# 8 7 65 43 21
656 *
657 * 1 in bit#1 means binary rep
658 * 1 in bit#2 means the mantissa is neg, 0 pos
659 * bb is the base: 65 base
660 * 00 2
661 * 01 8
662 * 10 16
663 * 11 future ext.
664 *
665 * ff is the Value of F where Mantissa = sign x N x 2^F
666 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
667 *
668 * ee is the length of the exponent: 21 length
669 * 00 1
670 * 01 2
671 * 10 3
672 * 11 long form
673 *
674 *
675 * encoded binary real value looks like
676 *
677 * fmt oct
678 * --------------------------------------------------------
679 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
680 * --------------------------------------------------------
681 * 87654321
682 */
683 firstOctet = REAL_BINARY;
684 if (sign == -1)
685 firstOctet |= REAL_SIGN;
686
687 /* bb is 00 since base is 2 so do nothing */
688 /* ff is 00 since no other shifting is nec */
689
690 /*
691 * get exponent calculate its encoded length
692 * Note that the process of converting the mantissa
693 * double to an int shifted the decimal mantissaLen * 8
694 * to the right - so correct that here
695 */
696 exponent -= (mantissaLen * 8);
697 expLen = SignedIntOctetLen (exponent);
698
699 switch (expLen)
700 {
701 case 1:
702 firstOctet |= REAL_EXPLEN_1;
703 break;
704 case 2:
705 firstOctet |= REAL_EXPLEN_2;
706 break;
707 case 3:
708 firstOctet |= REAL_EXPLEN_3;
709 break;
710 default:
711 firstOctet |= REAL_EXPLEN_LONG;
712 break;
713 }
714
715 encLen = mantissaLen + expLen + 1;
716
717 /* write the mantissa (N value) */
718 b.PutSegRvs ((char*)buf, mantissaLen);
719
720 /* write the exponent */
721 for (i = expLen; i > 0; i--)
722 {
723 b.PutByteRvs (exponent);
724 exponent >>= 8;
725 }
726
727 /* write the exponents length if nec */
728 if (expLen > 3)
729 {
730 encLen++;
731 b.PutByteRvs (expLen);
732 }
733
734 /* write the format octet */
735 b.PutByteRvs (firstOctet);
736
737 }
738 return encLen;
739
740 } /* AsnReal:BEncContent */
741
742
743
744 #endif
745 #endif
746
747
748 // Decode a REAL value's content from the given buffer.
749 // places the result in this object.
750 void AsnReal::BDecContent (BUF_TYPE b, AsnTag tagId, AsnLen elmtLen, AsnLen &bytesDecoded, ENV_TYPE env)
751 {
752 unsigned char firstOctet;
753 unsigned char firstExpOctet;
754 unsigned i;
755 unsigned int expLen;
756 double mantissa;
757 unsigned short base;
758 long int exponent = 0;
759 double tmpBase;
760 double tmpExp;
761
762
763 if (elmtLen == 0)
764 {
765 value = 0.0;
766 return;
767 }
768
769 firstOctet = b.GetByte();
770 if (elmtLen == 1)
771 {
772 bytesDecoded += 1;
773 if (firstOctet == ENC_PLUS_INFINITY)
774 value = PLUS_INFINITY;
775 else if (firstOctet == ENC_MINUS_INFINITY)
776 value = MINUS_INFINITY;
777 else
778 {
779 Asn1Error << "AsnReal::BDecContent: ERROR - unrecognized 1 octet length real number" << endl;
780 #if SNACC_EXCEPTION_ENABLE
781 SnaccExcep::throwMe(-18);
782 #else
783 longjmp (env, -18);
784 #endif
785 }
786 }
787 else
788 {
789 if (firstOctet & REAL_BINARY)
790 {
791 firstExpOctet = b.GetByte();
792 if (firstExpOctet & 0x80)
793 exponent = -1;
794 switch (firstOctet & REAL_EXPLEN_MASK)
795 {
796 case REAL_EXPLEN_1:
797 expLen = 1;
798 exponent = (exponent << 8) | firstExpOctet;
799 break;
800
801 case REAL_EXPLEN_2:
802 expLen = 2;
803 exponent = (exponent << 16) | (((unsigned long int) firstExpOctet) << 8) | b.GetByte();
804 break;
805
806 case REAL_EXPLEN_3:
807 expLen = 3;
808 exponent = (exponent << 16) | (((unsigned long int) firstExpOctet) << 8) | b.GetByte();
809 exponent = (exponent << 8) | b.GetByte();
810 break;
811
812 default: /* long form */
813 expLen = firstExpOctet +1;
814 i = firstExpOctet-1;
815 firstExpOctet = b.GetByte();
816 if (firstExpOctet & 0x80)
817 exponent = (-1 <<8) | firstExpOctet;
818 else
819 exponent = firstExpOctet;
820 for (;i > 0; firstExpOctet--)
821 exponent = (exponent << 8) | b.GetByte();
822 break;
823 }
824
825 mantissa = 0.0;
826 for (i = 1 + expLen; i < elmtLen; i++)
827 {
828 mantissa *= (1<<8);
829 mantissa += b.GetByte();
830 }
831
832 /* adjust N by scaling factor */
833 mantissa *= (1<<((firstOctet & REAL_FACTOR_MASK) >> 2));
834
835 switch (firstOctet & REAL_BASE_MASK)
836 {
837 case REAL_BASE_2:
838 base = 2;
839 break;
840
841 case REAL_BASE_8:
842 base = 8;
843 break;
844
845 case REAL_BASE_16:
846 base = 16;
847 break;
848
849 default:
850 Asn1Error << "AsnReal::BDecContent: ERROR - unsupported base for a binary real number." << endl;
851 #if SNACC_EXCEPTION_ENABLE
852 SnaccExcep::throwMe(-19);
853 #else
854 longjmp (env, -19);
855 #endif
856 break;
857
858 }
859
860 tmpBase = base;
861 tmpExp = exponent;
862
863 value = mantissa * pow ((double)base, (double)exponent);
864
865 if (firstOctet & REAL_SIGN)
866 value = -value;
867
868 bytesDecoded += elmtLen;
869 }
870 else /* decimal version */
871 {
872 Asn1Error << "AsnReal::BDecContent: ERROR - decimal REAL form is not currently supported" << endl;
873 #if SNACC_EXCEPTION_ENABLE
874 SnaccExcep::throwMe(-20);
875 #else
876 longjmp (env, -20);
877 #endif
878 }
879 }
880
881 } /* AsnInt::BDecContent */
882
883 AsnLen AsnReal::BEnc (BUF_TYPE b)
884 {
885 AsnLen l;
886 l = BEncContent (b);
887 l += BEncDefLen (b, l);
888 l += BEncTag1 (b, UNIV, PRIM, REAL_TAG_CODE);
889 return l;
890 }
891
892 void AsnReal::BDec (BUF_TYPE b, AsnLen &bytesDecoded, ENV_TYPE env)
893 {
894 AsnLen elmtLen;
895 if (BDecTag (b, bytesDecoded, env) != MAKE_TAG_ID (UNIV, PRIM, REAL_TAG_CODE))
896 {
897 Asn1Error << "AsnReal::BDec: ERROR tag on REAL is wrong." << endl;
898 #if SNACC_EXCEPTION_ENABLE
899 SnaccExcep::throwMe(-58);
900 #else
901 longjmp (env,-58);
902 #endif
903 }
904 elmtLen = BDecLen (b, bytesDecoded, env);
905
906 BDecContent (b, MAKE_TAG_ID (UNIV, PRIM, REAL_TAG_CODE), elmtLen, bytesDecoded, env);
907 }
908
909 void AsnReal::Print (ostream &os) const
910 {
911 #ifndef NDEBUG
912 os << value;
913 #endif
914 }
915
916 #if META
917
918 const AsnRealTypeDesc AsnReal::_desc (NULL, NULL, false, AsnTypeDesc::REAL, NULL);
919
920 const AsnTypeDesc *AsnReal::_getdesc() const
921 {
922 return &_desc;
923 }
924
925 #if TCL
926
927 int AsnReal::TclGetVal (Tcl_Interp *interp) const
928 {
929 if (value == PLUS_INFINITY)
930 strcpy (interp->result, "+inf");
931 else if (value == MINUS_INFINITY)
932 strcpy (interp->result, "-inf");
933 else
934 sprintf (interp->result, "%g", value);
935 return TCL_OK;
936 }
937
938 int AsnReal::TclSetVal (Tcl_Interp *interp, const char *valstr)
939 {
940 double valval;
941
942 if (!strcmp (valstr, "+inf"))
943 valval = PLUS_INFINITY;
944 else if (!strcmp (valstr, "-inf"))
945 valval = MINUS_INFINITY;
946 else if (Tcl_GetDouble (interp, (char*)valstr, &valval) != TCL_OK)
947 return TCL_ERROR;
948
949 value = valval;
950
951 return TCL_OK;
952 }
953
954 #endif /* TCL */
955 #endif /* META */