blob: 79b5173614ee020871cc2afbf6a461c63e67ce27 [file] [log] [blame]
vlm785435b2004-09-14 12:46:35 +00001/*-
2 * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <REAL.h>
6#include <INTEGER.h>
7#include <stdlib.h> /* for strtod(3) */
8#include <math.h>
9#include <errno.h>
10#include <assert.h>
11
12#undef INT_MAX
13#define INT_MAX ((int)(((unsigned int)-1) >> 1))
14
15/*
16 * REAL basic type description.
17 */
18static ber_tlv_tag_t asn1_DEF_REAL_tags[] = {
19 (ASN_TAG_CLASS_UNIVERSAL | (9 << 2))
20};
21asn1_TYPE_descriptor_t asn1_DEF_REAL = {
22 "REAL",
23 asn_generic_no_constraint,
24 INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
25 INTEGER_encode_der,
26 REAL_print,
27 INTEGER_free,
28 0, /* Use generic outmost tag fetcher */
29 asn1_DEF_REAL_tags,
30 sizeof(asn1_DEF_REAL_tags) / sizeof(asn1_DEF_REAL_tags[0]),
31 asn1_DEF_REAL_tags, /* Same as above */
32 sizeof(asn1_DEF_REAL_tags) / sizeof(asn1_DEF_REAL_tags[0]),
33 0, /* Always in primitive form */
34 0, 0, /* No members */
35 0 /* No specifics */
36};
37
38int
39REAL_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
40 asn_app_consume_bytes_f *cb, void *app_key) {
41 const REAL_t *st = (const REAL_t *)sptr;
42 char buf[128];
43 double d;
44 int ret;
45
46 (void)td; /* Unused argument */
47 (void)ilevel; /* Unused argument */
48
49 if(!st)
50 return cb("<absent>", 8, app_key);
51
52 if(asn1_REAL2double(st, &d))
53 return cb("<error>", 7, app_key);
54
55 ret = snprintf(buf, sizeof(buf), "%f", d);
56 if(ret < 0 || ret >= sizeof(buf))
57 return cb("<error>", 7, app_key);
58
59 return cb(buf, ret, app_key);
60}
61
62int
63asn1_REAL2double(const REAL_t *st, double *dbl_value) {
64 unsigned long octv;
65
66 if(!st || !st->buf) {
67 errno = EINVAL;
68 return -1;
69 }
70
71 if(st->size == 0) {
72 *dbl_value = 0;
73 return 0;
74 }
75
76 octv = st->buf[0]; /* unsigned byte */
77
78 switch(octv & 0xC0) {
79 case 0x40: /* X.690: 8.5.8 */
80 /* "SpecialRealValue" */
81
82 /* Be liberal in what you accept...
83 if(st->size != 1) ...
84 */
85
86 switch(st->buf[0]) {
87 case 0x40: /* 01000000: PLUS-INFINITY */
88 *dbl_value = INFINITY;
89 return 0;
90 case 0x41: /* 01000001: MINUS-INFINITY */
91 *dbl_value = -INFINITY;
92 return 0;
93 /*
94 * The following cases are defined by
95 * X.690 Amendment 1 (10/03)
96 */
97 case 0x42: /* 01000010: NOT-A-NUMBER */
98 *dbl_value = NAN;
99 return 0;
100 case 0x43: /* 01000011: minus zero */
101 *dbl_value = NAN;
102 return 0;
103 }
104
105 errno = EINVAL;
106 return -1;
107 case 0x00: { /* X.690: 8.5.6 */
108 /*
109 * Decimal. NR{1,2,3} format.
110 */
111 double d;
112
113 assert(st->buf[st->size - 1] == 0); /* Security, vashu mat' */
114
115 d = strtod((char *)st->buf, 0);
116 if(finite(d)) {
117 *dbl_value = d;
118 return 0;
119 } else {
120 errno = ERANGE;
121 return 0;
122 }
123 }
124 }
125
126 /*
127 * Binary representation.
128 */
129 {
130 double m;
131 int expval; /* exponent value */
132 unsigned int elen; /* exponent value length, in octets */
133 unsigned int scaleF;
134 unsigned int baseF;
135 uint8_t *ptr;
136 uint8_t *end;
137 int sign;
138
139 switch((octv & 0x30) >> 4) {
140 case 0x00: baseF = 1; break; /* base 2 */
141 case 0x01: baseF = 3; break; /* base 8 */
142 case 0x02: baseF = 4; break; /* base 16 */
143 default:
144 /* Reserved field, can't parse now. */
145 errno = EINVAL;
146 return -1;
147 }
148
149 sign = (octv & 0x40); /* bit 7 */
150 scaleF = (octv & 0x0C) >> 2; /* bits 4 to 3 */
151
152 if(st->size <= (1 + (octv & 0x03))) {
153 errno = EINVAL;
154 return -1;
155 }
156
157 if((octv & 0x03) == 0x11) {
158 /* 8.5.6.4, case d) */
159 elen = st->buf[1]; /* unsigned binary number */
160 if(elen == 0 || st->size <= (2 + elen)) {
161 errno = EINVAL;
162 return -1;
163 }
164 ptr = &st->buf[2];
165 } else {
166 elen = (octv & 0x03);
167 ptr = &st->buf[1];
168 }
169
170 /* Fetch the multibyte exponent */
171 expval = (int)(*(int8_t *)ptr);
172 end = ptr + elen + 1;
173 for(ptr++; ptr < end; ptr++)
174 expval = (expval * 256) + *ptr;
175
176 m = 0.0; /* Initial mantissa value */
177
178 /* Okay, the exponent is here. Now, what about mantissa? */
179 end = st->buf + st->size;
180 if(ptr < end) {
181 for(; ptr < end; ptr++)
182 m = scalbn(m, 8) + *ptr;
183 }
184
185 ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, scalbn()=%f",
186 m, scaleF, baseF, expval,
187 ldexp(m, expval * baseF + scaleF),
188 scalbn(m, scaleF) * pow(pow(2, baseF), expval)
189 );
190
191 /*
192 * (S * N * 2^F) * B^E
193 * Essentially:
194 m = scalbn(m, scaleF) * pow(pow(2, base), expval);
195 */
196 m = ldexp(m, expval * baseF + scaleF);
197 if(finite(m)) {
198 *dbl_value = sign ? -m : m;
199 } else {
200 errno = ERANGE;
201 return -1;
202 }
203
204 } /* if(binary_format) */
205
206 return 0;
207}
208
209/*
210 * Assume IEEE 754 floating point: standard 64 bit double.
211 * [1 bit sign] [11 bits exponent] [52 bits mantissa]
212 */
213int
214asn1_double2REAL(REAL_t *st, double dbl_value) {
215#ifdef WORDS_BIGENDIAN /* Known to be big-endian */
216 int littleEndian = 0;
217#else /* need to test: have no explicit information */
218 unsigned int LE = 1;
219 int littleEndian = *(unsigned char *)&LE;
220#endif
221 uint8_t buf[16]; /* More than enough for 8-byte dbl_value */
222 uint8_t dscr[sizeof(dbl_value)]; /* double value scratch pad */
223 /* Assertion guards: won't even compile, if unexpected double size */
224 char assertion_buffer1[9 - sizeof(dbl_value)] __attribute__((unused));
225 char assertion_buffer2[sizeof(dbl_value) - 7] __attribute__((unused));
226 uint8_t *ptr = buf;
227 uint8_t *mstop; /* Last byte of mantissa */
228 unsigned int mval; /* Value of the last byte of mantissa */
229 unsigned int bmsign; /* binary mask with sign */
230 unsigned int buflen;
231 unsigned int accum;
232 int expval;
233
234 if(!st) {
235 errno = EINVAL;
236 return -1;
237 }
238
239 expval = ilogb(dbl_value);
240
241 if(expval == -INT_MAX /* Also catches (dbl_value == 0) */
242 || expval == INT_MAX /* catches finite() which catches isnan() */
243 ) {
244 if(!st->buf || st->size < 2) {
245 (void *)ptr = MALLOC(2);
246 if(!ptr) return -1;
247 st->buf = ptr;
248 }
249 /* fpclassify(3) is not portable yet */
250 if(expval == -INT_MAX) {
251 if(signbit(dbl_value)) {
252 st->buf[0] = 0x80 | 0x40;
253 st->buf[1] = 0;
254 st->size = 2;
255 } else {
256 st->buf[0] = 0; /* JIC */
257 st->size = 0;
258 }
259 } else if(isinf(dbl_value)) {
260 if(signbit(dbl_value)) {
261 st->buf[0] = 0x41; /* MINUS-INFINITY */
262 } else {
263 st->buf[0] = 0x40; /* PLUS-INFINITY */
264 }
265 st->buf[1] = 0;
266 st->size = 1;
267 } else {
268 st->buf[0] = 0x42; /* NaN */
269 st->buf[1] = 0;
270 st->size = 1;
271 }
272 return 0;
273 }
274
275 if(littleEndian) {
276 uint8_t *s = ((uint8_t *)&dbl_value) + sizeof(dbl_value) - 2;
277 uint8_t *d;
278
279 bmsign = 0x80 | ((s[1] >> 1) & 0x40); /* binary mask & - */
280 for(mstop = d = dscr; s >= (uint8_t *)&dbl_value; d++, s--) {
281 *d = *s;
282 if(*d) mstop = d;
283 }
284 } else {
285 uint8_t *s = ((uint8_t *)&dbl_value) + 1;
286 uint8_t *end = ((uint8_t *)&dbl_value) + sizeof(double);
287 uint8_t *d;
288
289 bmsign = 0x80 | ((s[-1] >> 1) & 0x40); /* binary mask & - */
290 for(mstop = d = dscr; s < end; d++, s++) {
291 *d = *s;
292 if(*d) mstop = d;
293 }
294 }
295
296 /* Remove parts of the exponent, leave mantissa and explicit 1. */
297 dscr[0] = 0x10 | (dscr[0] & 0x0f);
298
299 /* Adjust exponent in a very unobvious way */
300 expval -= 8 * ((mstop - dscr) + 1) - 4;
301
302 /* This loop ensures DER conformance by forcing mantissa odd: 11.3.1 */
303 mval = *mstop;
304 if(mval && !(mval & 1)) {
305 unsigned int shift_count = 1;
306 unsigned int ishift;
307 uint8_t *mptr;
308
309 /*
310 * Figure out what needs to be done to make mantissa odd.
311 */
312 if(!(mval & 0x0f)) /* Speed-up a little */
313 shift_count = 4;
314 while(((mval >> shift_count) & 1) == 0)
315 shift_count++;
316
317 ishift = 8 - shift_count;
318 accum = 0;
319
320 /* Go over the buffer, shifting it shift_count bits right. */
321 for(mptr = dscr; mptr <= mstop; mptr++) {
322 mval = *mptr;
323 *mptr = accum | (mval >> shift_count);
324 accum = mval << ishift;
325 }
326
327 /* Adjust mantissa appropriately. */
328 expval += shift_count;
329 }
330
331 if(expval < 0) {
332 if((expval >> 7) == -1) {
333 *ptr++ = bmsign | 0x00;
334 *ptr++ = expval;
335 } else if((expval >> 15) == -1) {
336 *ptr++ = bmsign | 0x01;
337 *ptr++ = expval >> 8;
338 *ptr++ = expval;
339 } else {
340 assert((expval >> 23) == -1);
341 *ptr++ = bmsign | 0x02;
342 *ptr++ = expval >> 16;
343 *ptr++ = expval >> 8;
344 *ptr++ = expval;
345 }
346 } else if(expval <= 0x7f) {
347 *ptr++ = bmsign | 0x00;
348 *ptr++ = expval;
349 } else if(expval <= 0x7fff) {
350 *ptr++ = bmsign | 0x01;
351 *ptr++ = expval >> 8;
352 *ptr++ = expval;
353 } else {
354 assert(expval <= 0x7fffff);
355 *ptr++ = bmsign | 0x02;
356 *ptr++ = expval >> 16;
357 *ptr++ = expval >> 8;
358 *ptr++ = expval;
359 }
360
361 buflen = (mstop - dscr) + 1;
362 memcpy(ptr, dscr, buflen);
363 ptr += buflen;
364 buflen = ptr - buf;
365
366 (void *)ptr = MALLOC(buflen + 1);
367 if(!ptr) return -1;
368
369 memcpy(ptr, buf, buflen);
370 buf[buflen] = 0; /* JIC */
371
372 if(st->buf) FREEMEM(st->buf);
373 st->buf = ptr;
374 st->size = buflen;
375
376 return 0;
377}