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