]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c-lib/src/asn-real.c
Security-54.1.3.tar.gz
[apple/security.git] / SecuritySNACCRuntime / c-lib / src / asn-real.c
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 /*
20 * asn_real.c - BER encode, decode, print and free routines for ASN.1 REAL type.
21 *
22 * MS 92
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/Darwin/src/live/Security/SecuritySNACCRuntime/c-lib/src/asn-real.c,v 1.1.1.1 2001/05/18 23:14:08 mb Exp $
36 * $Log: asn-real.c,v $
37 * Revision 1.1.1.1 2001/05/18 23:14:08 mb
38 * Move from private repository to open source repository
39 *
40 * Revision 1.2 2001/05/05 00:59:25 rmurphy
41 * Adding darwin license headers
42 *
43 * Revision 1.1.1.1 1999/03/16 18:06:31 aram
44 * Originals from SMIME Free Library.
45 *
46 * Revision 1.5 1997/02/28 13:39:50 wan
47 * Modifications collected for new version 1.3: Bug fixes, tk4.2.
48 *
49 * Revision 1.4 1995/07/24 21:04:54 rj
50 * changed `_' to `-' in file names.
51 *
52 * Revision 1.3 1995/02/18 16:25:13 rj
53 * added support for CPU/compiler combination presenting 64 bit little endian long integers
54 * (in addition to the aforesupported 32 bit big endian long ints).
55 *
56 * Revision 1.2 1994/09/01 00:06:28 rj
57 * reduce the risk of unwanted surprises with macro expansion by properly separating the C tokens.
58 *
59 * Revision 1.1 1994/08/28 09:46:00 rj
60 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
61 *
62 */
63
64 #include "asn-config.h"
65 #include "asn-len.h"
66 #include "asn-tag.h"
67 #include "asn-real.h"
68
69 double pow PROTO ((double base, double exp));
70
71 #ifdef IEEE_REAL_LIB
72 /* ieee functions (in case not in math.h)*/
73 extern int iszero (double);
74 extern int isinf (double);
75 extern int signbit (double);
76 extern int ilogb (double);
77 extern double scalbn (double, int);
78 #endif
79
80
81 /*
82 * You must call InitAsnInfinity() to initailize these values
83 * (necessary if you deal with REAL values.)
84 */
85 AsnReal PLUS_INFINITY;
86 AsnReal MINUS_INFINITY;
87
88
89 #define ENC_PLUS_INFINITY 0x40
90 #define ENC_MINUS_INFINITY 0x41
91
92 #define REAL_BINARY 0x80
93 #define REAL_SIGN 0x40
94 #define REAL_EXPLEN_MASK 0x03
95 #define REAL_EXPLEN_1 0x00
96 #define REAL_EXPLEN_2 0x01
97 #define REAL_EXPLEN_3 0x02
98 #define REAL_EXPLEN_LONG 0x03
99 #define REAL_FACTOR_MASK 0x0c
100 #define REAL_BASE_MASK 0x30
101 #define REAL_BASE_2 0x00
102 #define REAL_BASE_8 0x10
103 #define REAL_BASE_16 0x20
104
105
106 /*
107 * Returns the smallest octet length needed to
108 * hold the given long int value
109 */
110 unsigned int
111 SignedIntOctetLen PARAMS ((val),
112 long int val)
113 {
114 unsigned long int mask = (0x7f80L << ((sizeof (long int) - 2) * 8));
115 unsigned int retVal = sizeof (long int);
116
117 if (val < 0)
118 val = val ^ (~0L); /* XOR val with all 1's */
119
120 while ((retVal > 1) && ((val & mask) == 0))
121 {
122 mask >>= 8;
123 retVal--;
124 }
125
126 return retVal;
127
128 } /* SignedIntOctetLen */
129
130
131 /*
132 * encodes universal TAG LENGTH and Contents of and ASN.1 REAL
133 */
134 AsnLen
135 BEncAsnReal PARAMS ((b, data),
136 BUF_TYPE b _AND_
137 AsnReal *data)
138 {
139 AsnLen len;
140
141 len = BEncAsnRealContent (b, data);
142 len += BEncDefLen (b, len);
143 len += BEncTag1 (b, UNIV, PRIM, REAL_TAG_CODE);
144 return len;
145 } /* BEncAsnReal */
146
147
148 /*
149 * decodes universal TAG LENGTH and Contents of and ASN.1 REAL
150 */
151 void
152 BDecAsnReal PARAMS ((b, result, bytesDecoded, env),
153 BUF_TYPE b _AND_
154 AsnReal *result _AND_
155 AsnLen *bytesDecoded _AND_
156 jmp_buf env)
157 {
158 AsnTag tag;
159 AsnLen elmtLen;
160
161 if ((tag = BDecTag (b, bytesDecoded, env)) != MAKE_TAG_ID (UNIV, PRIM, REAL_TAG_CODE))
162 {
163 Asn1Error ("BDecAsnReal: ERROR wrong tag on REAL.\n");
164 longjmp (env, -40);
165 }
166
167 elmtLen = BDecLen (b, bytesDecoded, env);
168 BDecAsnRealContent (b, tag, elmtLen, result, bytesDecoded, env);
169
170 } /* BDecAsnReal */
171
172
173
174 #ifdef IEEE_REAL_FMT
175
176 /*
177 * Inits the PLUS_INFINITY and MINUS_INFINITY globals assuming
178 * that the double is an IEEE DOUBLE
179 * The bits for MINUS_INFINITY are 0xfff0000000000000
180 * The bits for PLUS_INFINITY are 0x7ff0000000000000
181 */
182 void
183 InitAsnInfinity()
184 {
185 unsigned char *c = (unsigned char *)&PLUS_INFINITY;
186 int i;
187
188 if (sizeof (double) != 8)
189 Asn1Error ("InitAsnInfinity: ERROR expected sizeof (AsnReal) to be 8");
190
191 #if WORDS_BIGENDIAN /* Big endian */
192 c[0] = 0x7f;
193 c[1] = 0xf0;
194 for (i = 2; i < sizeof (double); i++)
195 c[i] = 0;
196 #else /* Little endian */
197 c[7] = 0x7f;
198 c[6] = 0xf0;
199 for (i = 0; i < 6; i++)
200 c[i] = 0;
201 #endif
202
203 MINUS_INFINITY = -PLUS_INFINITY;
204 } /* InitAsnInfinity */
205
206 /*
207 * Encodes the content of an ASN.1 REAL value to the given buffer.
208 * This version of the routine ASSUMES that the C rep. of a double
209 * is the same as the IEEE std.
210 */
211 AsnLen
212 BEncAsnRealContent PARAMS ((b, value),
213 BUF_TYPE b _AND_
214 AsnReal *value)
215 {
216 int exponent;
217 int isNeg;
218 #if SIZEOF_LONG == 4
219 unsigned char *dbl;
220 unsigned long int *first4;
221 unsigned long int *second4;
222 #else
223 #if SIZEOF_LONG == 8
224 unsigned long mantissa, val, *p;
225 int i;
226 #endif
227 #endif
228
229 /* no contents for 0.0 reals */
230 if (*value == 0.0) /* all bits zero, disregarding top/sign bit */
231 return 0;
232
233 #if SIZEOF_LONG == 4
234 #if !WORDS_BIGENDIAN
235 #error sorry! this 32 bit code requires big endianess.
236 #endif
237
238 /* this code is designed to work were longs are 32 bit wide and big endian */
239
240 dbl = (unsigned char *) value;
241
242 first4 = (unsigned long int *) dbl;
243 second4 = (unsigned long int *) (dbl + sizeof (long int));
244
245 isNeg = dbl[0] & 0x80;
246
247 /* special real values for +/- oo */
248 if (((*first4 & 0x7fffffff) == 0x7ff00000) && (*second4 == 0))
249 {
250 if (isNeg)
251 {
252 BufPutByteRvs (b, ENC_MINUS_INFINITY);
253 }
254 else
255 {
256 BufPutByteRvs (b, ENC_PLUS_INFINITY);
257 }
258 return 1;
259 }
260 else /* encode a binary real value */
261 {
262 exponent = (((*first4) >> 20) & 0x07ff);
263
264 /* write the mantissa (N value) */
265 BufPutSegRvs (b, (char *)(dbl+2), sizeof (double)-2);
266
267 /*
268 * The rightmost 4 bits of a double 2nd octet are the
269 * most sig bits of the mantissa.
270 * write the most signficant byte of the asn1 real mantissa,
271 * adding implicit bit to 'left of decimal' if not de-normalized
272 * (de normalized if exponent == 0)
273 *
274 * if the double is not in de-normalized form subtract 1023
275 * from the exponent to get proper signed exponent.
276 *
277 * for both the normalized and de-norm forms
278 * correct the exponent by subtracting 52 since:
279 * 1. mantissa is 52 bits in the double (56 in ASN.1 REAL form)
280 * 2. implicit decimal at the beginning of double's mantissa
281 * 3. ASN.1 REAL's implicit decimal is after its mantissa
282 * so converting the double mantissa to the ASN.1 form has the
283 * effect of multiplying it by 2^52. Subtracting 52 from the
284 * exponent corrects this.
285 */
286 if (exponent == 0) /* de-normalized - no implicit 1 to left of dec.*/
287 {
288 BufPutByteRvs (b, dbl[1] & 0x0f);
289 exponent -= 52;
290 }
291 else
292 {
293 BufPutByteRvs (b, (dbl[1] & 0x0f) | 0x10); /* 0x10 adds implicit bit */
294 exponent -= (1023 + 52);
295 }
296
297 #else
298 #if SIZEOF_LONG == 8
299 #if WORDS_BIGENDIAN
300 #error sorry! this 64 bit code requires little endianess.
301 #endif
302
303 /* this code is designed to work on Alpha under OSF/1 (64 bit longs, little endian) */
304
305 p = (unsigned long *) value;
306 val = *p;
307
308 isNeg = (val >> 63) & 1;
309 /* special real values for +/- oo */
310 if (!finite (*value))
311 {
312 if (isNeg)
313 {
314 BufPutByteRvs (b, ENC_MINUS_INFINITY);
315 }
316 else
317 {
318 BufPutByteRvs (b, ENC_PLUS_INFINITY);
319 }
320 return 1;
321 }
322 else /* encode a binary real value */
323 {
324 exponent = (val >> 52) & 0x7ff;
325 mantissa = (val & 0xfffffffffffffL) | 0x10000000000000L;
326
327 for (i = 0; i < 7; i++)
328 {
329 BufPutByteRvs (b, mantissa & 0xff);
330 mantissa >>= 8;
331 }
332 exponent -= (1023 + 52);
333
334 #else
335 #error long neither 8 nor 4 bytes in size?
336 #endif
337 #endif
338
339 /* write the exponent */
340 BufPutByteRvs (b, exponent & 0xff);
341 BufPutByteRvs (b, exponent >> 8);
342
343 /* write format octet */
344 /* bb is 00 since base is 2 so do nothing */
345 /* ff is 00 since no other shifting is nec */
346 if (isNeg)
347 {
348 BufPutByteRvs (b, REAL_BINARY | REAL_EXPLEN_2 | REAL_SIGN);
349 }
350 else
351 {
352 BufPutByteRvs (b, REAL_BINARY | REAL_EXPLEN_2);
353 }
354
355 return sizeof (double) + 2;
356 }
357
358 /* not reached */
359
360 } /* BEncAsnRealContent */
361
362 #else /* IEEE_REAL_FMT not def */
363
364 #ifdef IEEE_REAL_LIB
365
366
367 /*
368 * Inits the PLUS_INFINITY and MINUS_INFINITY globals assuming
369 * that the ieee_values library is present
370 */
371 void
372 InitAsnInfinity()
373 {
374 PLUS_INFINITY = infinity();
375 MINUS_INFINITY = -PLUS_INFINITY;
376 } /* InitAsnInfinity */
377
378 /*
379 * Encodes the content of an ASN.1 REAL value to the given buffer.
380 * This version of the routine does not assume an IEEE double rep.
381 * ieee library conversion routine are used instead.
382 */
383 AsnLen
384 BEncAsnRealContent PARAMS ((b, value),
385 BUF_TYPE b _AND_
386 AsnReal *value)
387 {
388 unsigned long int encLen;
389 double mantissa;
390 double tmpMantissa;
391 unsigned int truncatedMantissa;
392 int exponent;
393 unsigned int expLen;
394 int sign;
395 unsigned char buf[sizeof (double)];
396 int i, mantissaLen;
397 unsigned char firstOctet;
398
399 /* no contents for 0.0 reals */
400 if (iszero (*value))
401 return 0;
402
403 /* special real values for +/- oo */
404 if (isinf (*value))
405 {
406 if (signbit (*value)) /* neg */
407 BufPutByteRvs (b, ENC_MINUS_INFINITY);
408 else
409 BufPutByteRvs (b, ENC_PLUS_INFINITY);
410 encLen = 1;
411 }
412 else /* encode a binary real value */
413 {
414 if (signbit (*value))
415 sign = -1;
416 else
417 sign = 1;
418
419 exponent = ilogb (*value);
420
421 /* get the absolute value of the mantissa (subtract 1 to make < 1) */
422 mantissa = scalbn (fabs (*value), -exponent-1);
423
424
425 tmpMantissa = mantissa;
426
427 /* convert mantissa into an unsigned integer */
428 for (i = 0; i < sizeof (double); i++)
429 {
430 /* normalizied so shift 8 bits worth to the left of the decimal */
431 tmpMantissa *= (1<<8);
432
433 /* grab only (octet sized) the integer part */
434 truncatedMantissa = (unsigned int) tmpMantissa;
435
436 /* remove part to left of decimal now for next iteration */
437 tmpMantissa -= truncatedMantissa;
438
439 /* write into tmp buffer */
440 buf[i] = truncatedMantissa;
441
442 /* keep track of last non zero octet so can zap trailing zeros */
443 if (truncatedMantissa)
444 mantissaLen = i+1;
445 }
446
447 /*
448 * write format octet (first octet of content)
449 * field 1 S bb ff ee
450 * bit# 8 7 65 43 21
451 *
452 * 1 in bit#1 means binary rep
453 * 1 in bit#2 means the mantissa is neg, 0 pos
454 * bb is the base: 65 base
455 * 00 2
456 * 01 8
457 * 10 16
458 * 11 future ext.
459 *
460 * ff is the Value of F where Mantissa = sign x N x 2^F
461 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
462 *
463 * ee is the length of the exponent: 21 length
464 * 00 1
465 * 01 2
466 * 10 3
467 * 11 long form
468 *
469 *
470 * encoded binary real value looks like
471 *
472 * fmt oct
473 * --------------------------------------------------------
474 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
475 * --------------------------------------------------------
476 * 87654321
477 */
478 firstOctet = REAL_BINARY;
479 if (signbit (*value))
480 firstOctet |= REAL_SIGN;
481
482 /* bb is 00 since base is 2 so do nothing */
483 /* ff is 00 since no other shifting is nec */
484
485 /*
486 * get exponent calculate its encoded length
487 * Note that the process of converting the mantissa
488 * double to an int shifted the decimal mantissaLen * 8
489 * to the right - so correct that here
490 */
491 exponent++; /* compensate for trick to put mantissa < 1 */
492 exponent -= (mantissaLen * 8);
493 expLen = SignedIntOctetLen (exponent);
494
495 switch (expLen)
496 {
497 case 1:
498 firstOctet |= REAL_EXPLEN_1;
499 break;
500 case 2:
501 firstOctet |= REAL_EXPLEN_2;
502 break;
503 case 3:
504 firstOctet |= REAL_EXPLEN_3;
505 break;
506 default:
507 firstOctet |= REAL_EXPLEN_LONG;
508 break;
509 }
510
511 encLen = mantissaLen + expLen + 1;
512
513 /* write the mantissa (N value) */
514 BufPutSegRvs (b, (char*)buf, mantissaLen);
515
516 /* write the exponent */
517 for (i = expLen; i > 0; i--)
518 {
519 BufPutByteRvs (b, exponent);
520 exponent >>= 8;
521 }
522
523 /* write the exponents length if nec */
524 if (expLen > 3)
525 {
526 encLen++;
527 BufPutByteRvs (b, expLen);
528 }
529
530 /* write the format octet */
531 BufPutByteRvs (b, firstOctet);
532
533 }
534 return encLen;
535
536 } /* BEncAsnRealContent */
537
538 #else /* neither IEEE_REAL_FMT or IEEE_REAL_LIB are def */
539
540 /*
541 * Inits the PLUS_INFINITY and MINUS_INFINITY globals assuming
542 * that the double is an IEEE DOUBLE. This should be changed
543 * for the target architecture (if it is not IEEE)
544 */
545 void
546 InitAsnInfinity()
547 {
548 unsigned char *c;
549 int i;
550
551 if (sizeof (double) != 8)
552 Asn1Error ("InitAsnInfinity: ERROR expected sizeof (AsnReal) to be 8");
553
554 c = (unsigned char*)&PLUS_INFINITY;
555 c[0] = 0x7f;
556 c[1] = 0xf0;
557 for (i = 2; i < sizeof (double); i++)
558 c[i] = 0;
559
560 MINUS_INFINITY = -PLUS_INFINITY;
561 } /* InitAsnInfinity */
562
563 /*
564 * Encodes the content of an ASN.1 REAL value to the given buffer.
565 * This version of the routine does not assume an IEEE double rep.
566 * or the existence of the IEEE library routines. Uses old style
567 * UNIX frexp etc.
568 */
569 AsnLen
570 BEncAsnRealContent PARAMS ((b, value),
571 BUF_TYPE b _AND_
572 AsnReal *value)
573 {
574 unsigned long int encLen;
575 double mantissa;
576 double tmpMantissa;
577 unsigned int truncatedMantissa;
578 int exponent;
579 unsigned int expLen;
580 int sign;
581 unsigned char buf[sizeof (double)];
582 int i, mantissaLen;
583 unsigned char firstOctet;
584
585 /* no contents for 0.0 reals */
586 if (*value == 0.0)
587 return 0;
588
589 /* special real values for +/- oo */
590 if (*value == MINUS_INFINITY)
591 {
592 BufPutByteRvs (b, ENC_MINUS_INFINITY);
593 encLen = 1;
594 }
595 else if (*value == PLUS_INFINITY)
596 {
597 BufPutByteRvs (b, ENC_PLUS_INFINITY);
598 encLen = 1;
599 }
600 else /* encode a binary real value */
601 {
602 /*
603 * this is what frexp gets from *value
604 * *value == mantissa * 2^exponent
605 * where 0.5 <= |manitissa| < 1.0
606 */
607 mantissa = frexp (*value, &exponent);
608
609 /* set sign and make mantissa = | mantissa | */
610 if (mantissa < 0.0)
611 {
612 sign = -1;
613 mantissa *= -1;
614 }
615 else
616 sign = 1;
617
618
619 tmpMantissa = mantissa;
620
621 /* convert mantissa into an unsigned integer */
622 for (i = 0; i < sizeof (double); i++)
623 {
624 /* normalizied so shift 8 bits worth to the left of the decimal */
625 tmpMantissa *= (1<<8);
626
627 /* grab only (octet sized) the integer part */
628 truncatedMantissa = (unsigned int) tmpMantissa;
629
630 /* remove part to left of decimal now for next iteration */
631 tmpMantissa -= truncatedMantissa;
632
633 /* write into tmp buffer */
634 buf[i] = truncatedMantissa;
635
636 /* keep track of last non zero octet so can zap trailing zeros */
637 if (truncatedMantissa)
638 mantissaLen = i+1;
639 }
640
641 /*
642 * write format octet (first octet of content)
643 * field 1 S bb ff ee
644 * bit# 8 7 65 43 21
645 *
646 * 1 in bit#1 means binary rep
647 * 1 in bit#2 means the mantissa is neg, 0 pos
648 * bb is the base: 65 base
649 * 00 2
650 * 01 8
651 * 10 16
652 * 11 future ext.
653 *
654 * ff is the Value of F where Mantissa = sign x N x 2^F
655 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
656 *
657 * ee is the length of the exponent: 21 length
658 * 00 1
659 * 01 2
660 * 10 3
661 * 11 long form
662 *
663 *
664 * encoded binary real value looks like
665 *
666 * fmt oct
667 * --------------------------------------------------------
668 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
669 * --------------------------------------------------------
670 * 87654321
671 */
672 firstOctet = REAL_BINARY;
673 if (sign == -1)
674 firstOctet |= REAL_SIGN;
675
676 /* bb is 00 since base is 2 so do nothing */
677 /* ff is 00 since no other shifting is nec */
678
679 /*
680 * get exponent calculate its encoded length
681 * Note that the process of converting the mantissa
682 * double to an int shifted the decimal mantissaLen * 8
683 * to the right - so correct that here
684 */
685 exponent -= (mantissaLen * 8);
686 expLen = SignedIntOctetLen (exponent);
687
688 switch (expLen)
689 {
690 case 1:
691 firstOctet |= REAL_EXPLEN_1;
692 break;
693 case 2:
694 firstOctet |= REAL_EXPLEN_2;
695 break;
696 case 3:
697 firstOctet |= REAL_EXPLEN_3;
698 break;
699 default:
700 firstOctet |= REAL_EXPLEN_LONG;
701 break;
702 }
703
704 encLen = mantissaLen + expLen + 1;
705
706 /* write the mantissa (N value) */
707 BufPutSegRvs (b, (char*)buf, mantissaLen);
708
709 /* write the exponent */
710 for (i = expLen; i > 0; i--)
711 {
712 BufPutByteRvs (b, exponent);
713 exponent >>= 8;
714 }
715
716 /* write the exponents length if nec */
717 if (expLen > 3)
718 {
719 encLen++;
720 BufPutByteRvs (b, expLen);
721 }
722
723 /* write the format octet */
724 BufPutByteRvs (b, firstOctet);
725
726 }
727 return encLen;
728
729 } /* BEncAsnRealContent */
730
731 #endif /* IEEE_REAL_LIB */
732 #endif /* IEEE_REAL_FMT */
733
734
735
736 /*
737 * Decodes the content of a BER REAL value.
738 * This only supports the binary REAL encoding. The decimal encoding
739 * is left as an exercise to the reader.
740 */
741 void
742 BDecAsnRealContent PARAMS ((b, tagId, len, result, bytesDecoded, env),
743 BUF_TYPE b _AND_
744 AsnTag tagId _AND_
745 AsnLen len _AND_
746 AsnReal *result _AND_
747 AsnLen *bytesDecoded _AND_
748 jmp_buf env)
749 {
750 unsigned char firstOctet;
751 unsigned char firstExpOctet;
752 int i;
753 unsigned int expLen;
754 double mantissa;
755 unsigned short base;
756 long int exponent = 0;
757 double tmpBase;
758 double tmpExp;
759
760 if (len == 0)
761 {
762 *result = 0.0;
763 return;
764 }
765
766 firstOctet = BufGetByte (b);
767 if (len == 1)
768 {
769 (*bytesDecoded) += 1;
770 if (firstOctet == ENC_PLUS_INFINITY)
771 *result = PLUS_INFINITY;
772 else if (firstOctet == ENC_MINUS_INFINITY)
773 *result = MINUS_INFINITY;
774 else
775 {
776 Asn1Error ("BDecAsnRealContent: ERROR - unrecognized real number of length 1 octet.\n");
777 longjmp (env, -22);
778 }
779 }
780 else
781 {
782 if (firstOctet & REAL_BINARY)
783 {
784 firstExpOctet = BufGetByte (b);
785 if (firstExpOctet & 0x80)
786 exponent = -1;
787 switch (firstOctet & REAL_EXPLEN_MASK)
788 {
789 case REAL_EXPLEN_1:
790 expLen = 1;
791 exponent = (exponent << 8)| firstExpOctet;
792 break;
793
794 case REAL_EXPLEN_2:
795 expLen = 2;
796 exponent = (exponent << 16) |
797 (((unsigned long int) firstExpOctet) << 8) |
798 BufGetByte (b);
799 break;
800
801 case REAL_EXPLEN_3:
802 expLen = 3;
803 exponent = (exponent << 16) |
804 (((unsigned long int) firstExpOctet) << 8) |
805 BufGetByte (b);
806 exponent = (exponent << 8) | BufGetByte (b);
807 break;
808
809 default: /* long form */
810 expLen = firstExpOctet +1;
811 i = firstExpOctet-1;
812 firstExpOctet = BufGetByte (b);
813 if (firstExpOctet & 0x80)
814 exponent = (-1 <<8) | firstExpOctet;
815 else
816 exponent = firstExpOctet;
817 for (;i > 0; firstExpOctet--)
818 exponent = (exponent << 8) | BufGetByte (b);
819 break;
820 }
821
822 mantissa = 0.0;
823 for (i = 1 + expLen; i < len; i++)
824 {
825 mantissa *= (1<<8);
826 mantissa += BufGetByte (b);
827 }
828
829 /* adjust N by scaling factor */
830 mantissa *= (1<<((firstOctet & REAL_FACTOR_MASK) >> 2));
831
832 switch (firstOctet & REAL_BASE_MASK)
833 {
834 case REAL_BASE_2:
835 base = 2;
836 break;
837
838 case REAL_BASE_8:
839 base = 8;
840 break;
841
842 case REAL_BASE_16:
843 base = 16;
844 break;
845
846 default:
847 Asn1Error ("BDecAsnRealContent: ERROR - unsupported base for a binary real number.\n");
848 longjmp (env, -23);
849 break;
850
851 }
852
853 tmpBase = base;
854 tmpExp = exponent;
855
856 *result = mantissa * pow ((double)base, (double)exponent);
857
858 if (firstOctet & REAL_SIGN)
859 *result = -*result;
860
861 (*bytesDecoded) += len;
862 }
863 else /* decimal version */
864 {
865 Asn1Error ("BDecAsnRealContent: ERROR - decimal REAL form is not currently supported\n");
866 longjmp (env, -24);
867 }
868 }
869
870 } /* BDecAsnRealContent */
871
872
873 /*
874 * Prints given REAL value to the given FILE * in ASN.1 Value Notation.
875 * indent is ignored.
876 */
877 void
878 PrintAsnReal PARAMS ((f, v, indent),
879 FILE *f _AND_
880 AsnReal *v _AND_
881 unsigned short int indent)
882 {
883 fprintf (f, "%.17E", *v);
884 }