updated image tag version to 1.0.3
[ric-app/rc.git] / e2sm / lib / NativeReal.c
1 /*-
2  * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 /*
6  * Read the NativeReal.h for the explanation wrt. differences between
7  * REAL and NativeReal.
8  * Basically, both are decoders and encoders of ASN.1 REAL type, but this
9  * implementation deals with the standard (machine-specific) representation
10  * of them instead of using the platform-independent buffer.
11  */
12 #include <asn_internal.h>
13 #include <NativeReal.h>
14 #include <REAL.h>
15 #include <OCTET_STRING.h>
16 #include <math.h>
17 #include <float.h>
18
19 #if defined(__clang__)
20 /*
21  * isnan() is defined using generic selections and won't compile in
22  * strict C89 mode because of too fancy system's standard library.
23  * However, prior to C11 the math had a perfectly working isnan()
24  * in the math library.
25  * Disable generic selection warning so we can test C89 mode with newer libc.
26  */
27 #pragma clang diagnostic push
28 #pragma clang diagnostic ignored "-Wc11-extensions"
29 static int asn_isnan(double d) {
30     return isnan(d);
31 }
32 #pragma clang diagnostic pop
33 #else
34 #define asn_isnan(v)    isnan(v)
35 #endif  /* generic selections */
36
37 /*
38  * NativeReal basic type description.
39  */
40 static const ber_tlv_tag_t asn_DEF_NativeReal_tags[] = {
41         (ASN_TAG_CLASS_UNIVERSAL | (9 << 2))
42 };
43 asn_TYPE_operation_t asn_OP_NativeReal = {
44         NativeReal_free,
45         NativeReal_print,
46         NativeReal_compare,
47         NativeReal_decode_ber,
48         NativeReal_encode_der,
49         NativeReal_decode_xer,
50         NativeReal_encode_xer,
51 #ifdef  ASN_DISABLE_OER_SUPPORT
52         0,
53         0,
54 #else
55         NativeReal_decode_oer,
56         NativeReal_encode_oer,
57 #endif  /* ASN_DISABLE_OER_SUPPORT */
58 #ifdef  ASN_DISABLE_PER_SUPPORT
59         0,
60         0,
61         0,
62         0,
63 #else
64         NativeReal_decode_uper,
65         NativeReal_encode_uper,
66         NativeReal_decode_aper,
67         NativeReal_encode_aper,
68 #endif  /* ASN_DISABLE_PER_SUPPORT */
69         NativeReal_random_fill,
70         0       /* Use generic outmost tag fetcher */
71 };
72 asn_TYPE_descriptor_t asn_DEF_NativeReal = {
73         "REAL",                 /* The ASN.1 type is still REAL */
74         "REAL",
75         &asn_OP_NativeReal,
76         asn_DEF_NativeReal_tags,
77         sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
78         asn_DEF_NativeReal_tags,        /* Same as above */
79         sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
80         { 0, 0, asn_generic_no_constraint },
81         0, 0,   /* No members */
82         0       /* No specifics */
83 };
84
85 static size_t NativeReal__float_size(const asn_TYPE_descriptor_t *td);
86 static double NativeReal__get_double(const asn_TYPE_descriptor_t *td,
87                                      const void *ptr);
88 static ssize_t NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr,
89                                double d);
90
91 /*
92  * Decode REAL type.
93  */
94 asn_dec_rval_t
95 NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
96                       const asn_TYPE_descriptor_t *td, void **sptr,
97                       const void *buf_ptr, size_t size, int tag_mode) {
98     asn_dec_rval_t rval;
99     ber_tlv_len_t length;
100
101     ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
102
103     /*
104      * Check tags.
105      */
106     rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
107                           &length, 0);
108     if(rval.code != RC_OK) return rval;
109     assert(length >= 0);    /* Ensured by ber_check_tags */
110
111     ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
112
113     /*
114      * Make sure we have this length.
115      */
116     buf_ptr = ((const char *)buf_ptr) + rval.consumed;
117     size -= rval.consumed;
118     if(length > (ber_tlv_len_t)size) {
119         rval.code = RC_WMORE;
120         rval.consumed = 0;
121         return rval;
122     }
123
124     /*
125      * ASN.1 encoded REAL: buf_ptr, length
126      * Fill the Dbl, at the same time checking for overflow.
127      * If overflow occured, return with RC_FAIL.
128      */
129     {
130         uint8_t scratch[24]; /* Longer than %.16f in decimal */
131         REAL_t tmp;
132         double d;
133         int ret;
134
135         if((size_t)length < sizeof(scratch)) {
136             tmp.buf = scratch;
137             tmp.size = length;
138         } else {
139             /* This rarely happens: impractically long value */
140             tmp.buf = CALLOC(1, length + 1);
141             tmp.size = length;
142             if(!tmp.buf) {
143                 rval.code = RC_FAIL;
144                 rval.consumed = 0;
145                 return rval;
146             }
147         }
148
149         memcpy(tmp.buf, buf_ptr, length);
150         tmp.buf[length] = '\0';
151
152         ret = asn_REAL2double(&tmp, &d);
153         if(tmp.buf != scratch) FREEMEM(tmp.buf);
154         if(ret) {
155             rval.code = RC_FAIL;
156             rval.consumed = 0;
157             return rval;
158         }
159
160         if(NativeReal__set(td, sptr, d) < 0)
161             ASN__DECODE_FAILED;
162     }
163
164     rval.code = RC_OK;
165     rval.consumed += length;
166
167     ASN_DEBUG("Took %ld/%ld bytes to encode %s", (long)rval.consumed,
168               (long)length, td->name);
169
170     return rval;
171 }
172
173 /*
174  * Encode the NativeReal using the standard REAL type DER encoder.
175  */
176 asn_enc_rval_t
177 NativeReal_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
178                       int tag_mode, ber_tlv_tag_t tag,
179                       asn_app_consume_bytes_f *cb, void *app_key) {
180     double d = NativeReal__get_double(td, sptr);
181     asn_enc_rval_t erval = {0,0,0};
182         REAL_t tmp;
183
184         /* Prepare a temporary clean structure */
185         memset(&tmp, 0, sizeof(tmp));
186
187     if(asn_double2REAL(&tmp, d))
188         ASN__ENCODE_FAILED;
189
190     /* Encode a fake REAL */
191     erval = der_encode_primitive(td, &tmp, tag_mode, tag, cb, app_key);
192     if(erval.encoded == -1) {
193                 assert(erval.structure_ptr == &tmp);
194                 erval.structure_ptr = sptr;
195         }
196
197         /* Free possibly allocated members of the temporary structure */
198     ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
199
200     return erval;
201 }
202
203 #ifndef ASN_DISABLE_PER_SUPPORT
204
205 /*
206  * Decode REAL type using PER.
207  */
208 asn_dec_rval_t
209 NativeReal_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
210                        const asn_TYPE_descriptor_t *td,
211                        const asn_per_constraints_t *constraints, void **sptr,
212                        asn_per_data_t *pd) {
213     asn_dec_rval_t rval;
214     double d;
215         REAL_t tmp;
216         void *ptmp = &tmp;
217         int ret;
218
219         (void)constraints;
220
221         memset(&tmp, 0, sizeof(tmp));
222     rval = OCTET_STRING_decode_uper(opt_codec_ctx, &asn_DEF_REAL,
223                                     NULL, &ptmp, pd);
224     if(rval.code != RC_OK) {
225                 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
226                 return rval;
227         }
228
229         ret = asn_REAL2double(&tmp, &d);
230         ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
231         if(ret) ASN__DECODE_FAILED;
232
233     if(NativeReal__set(td, sptr, d) < 0 )
234         ASN__DECODE_FAILED;
235
236         return rval;
237 }
238
239 /*
240  * Encode the NativeReal using the OCTET STRING PER encoder.
241  */
242 asn_enc_rval_t
243 NativeReal_encode_uper(const asn_TYPE_descriptor_t *td,
244                        const asn_per_constraints_t *constraints,
245                        const void *sptr, asn_per_outp_t *po) {
246     double d = NativeReal__get_double(td, sptr);
247         asn_enc_rval_t erval = {0,0,0};
248         REAL_t tmp;
249
250         (void)constraints;
251
252         /* Prepare a temporary clean structure */
253         memset(&tmp, 0, sizeof(tmp));
254
255         if(asn_double2REAL(&tmp, d))
256                 ASN__ENCODE_FAILED;
257         
258         /* Encode a DER REAL */
259     erval = OCTET_STRING_encode_uper(&asn_DEF_REAL, NULL, &tmp, po);
260     if(erval.encoded == -1)
261                 erval.structure_ptr = sptr;
262
263         /* Free possibly allocated members of the temporary structure */
264         ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
265
266         return erval;
267 }
268
269
270 asn_dec_rval_t
271 NativeReal_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
272                        const asn_TYPE_descriptor_t *td,
273                        const asn_per_constraints_t *constraints,
274                        void **dbl_ptr, asn_per_data_t *pd) {
275         double *Dbl = (double *)*dbl_ptr;
276         asn_dec_rval_t rval;
277         REAL_t tmp;
278         void *ptmp = &tmp;
279         int ret;
280
281         (void)constraints;
282
283         /*
284          * If the structure is not there, allocate it.
285          */
286         if(Dbl == NULL) {
287                 *dbl_ptr = CALLOC(1, sizeof(*Dbl));
288                 Dbl = (double *)*dbl_ptr;
289                 if(Dbl == NULL)
290                         ASN__DECODE_FAILED;
291         }
292
293         memset(&tmp, 0, sizeof(tmp));
294         rval = OCTET_STRING_decode_aper(opt_codec_ctx, td, NULL,
295                         &ptmp, pd);
296         if(rval.code != RC_OK) {
297                 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
298                 return rval;
299         }
300
301         ret = asn_REAL2double(&tmp, Dbl);
302         ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
303         if(ret) ASN__DECODE_FAILED;
304
305         return rval;
306 }
307
308 asn_enc_rval_t
309 NativeReal_encode_aper(const asn_TYPE_descriptor_t *td,
310                        const asn_per_constraints_t *constraints,
311                        const void *sptr, asn_per_outp_t *po) {
312         double Dbl = *(const double *)sptr;
313         asn_enc_rval_t erval = {0,0,0};
314         REAL_t tmp;
315
316         (void)constraints;
317
318         /* Prepare a temporary clean structure */
319         memset(&tmp, 0, sizeof(tmp));
320
321         if(asn_double2REAL(&tmp, Dbl))
322                 ASN__ENCODE_FAILED;
323
324         /* Encode a DER REAL */
325         erval = OCTET_STRING_encode_aper(td, NULL, &tmp, po);
326         if(erval.encoded == -1)
327                 erval.structure_ptr = sptr;
328
329         /* Free possibly allocated members of the temporary structure */
330         ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
331
332         return erval;
333 }
334
335 #endif /* ASN_DISABLE_PER_SUPPORT */
336
337 #ifndef ASN_DISABLE_OER_SUPPORT
338
339 /*
340  * Swap bytes from/to network, if local is little-endian.
341  * Unused endianness sections are likely removed at compile phase.
342  */
343 static void
344 NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
345     const uint8_t *src = srcp;
346     double test = -0.0;
347     int float_big_endian = *(const char *)&test != 0;
348     /* In lieu of static_assert(sizeof(double) == 8) */
349     static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
350     static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
351     /* In lieu of static_assert(sizeof(sizeof) == 4) */
352     static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
353     static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
354
355     switch(float_size) {
356     case sizeof(double):
357         assert(sizeof(double) == 8);
358         if(float_big_endian) {
359             dst[0] = src[0];
360             dst[1] = src[1];
361             dst[2] = src[2];
362             dst[3] = src[3];
363             dst[4] = src[4];
364             dst[5] = src[5];
365             dst[6] = src[6];
366             dst[7] = src[7];
367         } else {
368             dst[0] = src[7];
369             dst[1] = src[6];
370             dst[2] = src[5];
371             dst[3] = src[4];
372             dst[4] = src[3];
373             dst[5] = src[2];
374             dst[6] = src[1];
375             dst[7] = src[0];
376         }
377         return;
378     case sizeof(float):
379         assert(sizeof(float) == 4);
380         if(float_big_endian) {
381             dst[0] = src[0];
382             dst[1] = src[1];
383             dst[2] = src[2];
384             dst[3] = src[3];
385         } else {
386             dst[0] = src[3];
387             dst[1] = src[2];
388             dst[2] = src[1];
389             dst[3] = src[0];
390         }
391         return;
392     }
393 }
394
395 /*
396  * Encode as Canonical OER.
397  */
398 asn_enc_rval_t
399 NativeReal_encode_oer(const asn_TYPE_descriptor_t *td,
400                       const asn_oer_constraints_t *constraints,
401                       const void *sptr, asn_app_consume_bytes_f *cb,
402                       void *app_key) {
403     asn_enc_rval_t er = {0, 0, 0};
404
405     if(!constraints) constraints = td->encoding_constraints.oer_constraints;
406     if(constraints && constraints->value.width != 0) {
407         /* X.696 IEEE 754 binary32 and binary64 encoding */
408         uint8_t scratch[sizeof(double)];
409         const asn_NativeReal_specifics_t *specs =
410             (const asn_NativeReal_specifics_t *)td->specifics;
411         size_t wire_size = constraints->value.width;
412
413         if(specs ? (wire_size == specs->float_size)
414                  : (wire_size == sizeof(double))) {
415             /*
416              * Our representation matches the wire, modulo endianness.
417              * That was the whole point of compact encoding!
418              */
419         } else {
420             assert((wire_size == sizeof(double))
421                    || (specs && specs->float_size == wire_size));
422             ASN__ENCODE_FAILED;
423         }
424
425         /*
426          * The X.696 standard doesn't specify endianness, neither is IEEE 754.
427          * So we assume the network format is big endian.
428          */
429         NativeReal__network_swap(wire_size, sptr, scratch);
430         if(cb(scratch, wire_size, app_key) < 0) {
431             ASN__ENCODE_FAILED;
432         } else {
433             er.encoded = wire_size;
434             ASN__ENCODED_OK(er);
435         }
436     } else {
437         double d = NativeReal__get_double(td, sptr);
438         ssize_t len_len;
439         REAL_t tmp;
440
441         /* Prepare a temporary clean structure */
442         memset(&tmp, 0, sizeof(tmp));
443
444         if(asn_double2REAL(&tmp, d)) {
445             ASN__ENCODE_FAILED;
446         }
447
448         /* Encode a fake REAL */
449         len_len = oer_serialize_length(tmp.size, cb, app_key);
450         if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
451             ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
452             ASN__ENCODE_FAILED;
453         } else {
454             er.encoded = len_len + tmp.size;
455             ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
456             ASN__ENCODED_OK(er);
457         }
458     }
459 }
460
461 asn_dec_rval_t
462 NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
463                       const asn_TYPE_descriptor_t *td,
464                       const asn_oer_constraints_t *constraints, void **sptr,
465                       const void *ptr, size_t size) {
466     asn_dec_rval_t ok = {RC_OK, 0};
467     double d;
468     ssize_t len_len;
469     size_t real_body_len;
470
471     (void)opt_codec_ctx;
472
473     if(!constraints) constraints = td->encoding_constraints.oer_constraints;
474     if(constraints && constraints->value.width != 0) {
475         /* X.696 IEEE 754 binary32 and binary64 encoding */
476         uint8_t scratch[sizeof(double)];
477         size_t wire_size = constraints->value.width;
478
479         if(size < wire_size)
480             ASN__DECODE_STARVED;
481
482         /*
483          * The X.696 standard doesn't specify endianness, neither is IEEE 754.
484          * So we assume the network format is big endian.
485          */
486         NativeReal__network_swap(wire_size, ptr, scratch);
487
488
489         switch(wire_size) {
490             case sizeof(double):
491                 {
492                     double tmp;
493                     memcpy(&tmp, scratch, sizeof(double));
494                     if(NativeReal__set(td, sptr, tmp) < 0)
495                         ASN__DECODE_FAILED;
496                 }
497                 break;
498             case sizeof(float):
499                 {
500                     float tmp;
501                     memcpy(&tmp, scratch, sizeof(float));
502                     if(NativeReal__set(td, sptr, tmp) < 0)
503                         ASN__DECODE_FAILED;
504                 }
505                 break;
506         default:
507             ASN__DECODE_FAILED;
508         }
509
510         ok.consumed = wire_size;
511         return ok;
512     }
513
514     len_len = oer_fetch_length(ptr, size, &real_body_len);
515     if(len_len < 0) ASN__DECODE_FAILED;
516     if(len_len == 0) ASN__DECODE_STARVED;
517
518     ptr = (const char *)ptr + len_len;
519     size -= len_len;
520
521     if(real_body_len > size) ASN__DECODE_STARVED;
522
523     {
524         uint8_t scratch[24]; /* Longer than %.16f in decimal */
525         REAL_t tmp;
526         int ret;
527
528         if(real_body_len < sizeof(scratch)) {
529             tmp.buf = scratch;
530             tmp.size = real_body_len;
531         } else {
532             /* This rarely happens: impractically long value */
533             tmp.buf = CALLOC(1, real_body_len + 1);
534             tmp.size = real_body_len;
535             if(!tmp.buf) {
536                 ASN__DECODE_FAILED;
537             }
538         }
539
540         memcpy(tmp.buf, ptr, real_body_len);
541         tmp.buf[real_body_len] = '\0';
542
543         ret = asn_REAL2double(&tmp, &d);
544         if(tmp.buf != scratch) FREEMEM(tmp.buf);
545         if(ret) {
546             ASN_DEBUG("REAL decoded in %" ASN_PRI_SIZE " bytes, but can't convert t double",
547                       real_body_len);
548             ASN__DECODE_FAILED;
549         }
550     }
551
552     if(NativeReal__set(td, sptr, d) < 0)
553         ASN__DECODE_FAILED;
554
555     ok.consumed = len_len + real_body_len;
556     return ok;
557 }
558
559 #endif /* ASN_DISABLE_OER_SUPPORT */
560
561 /*
562  * Decode the chunk of XML text encoding REAL.
563  */
564 asn_dec_rval_t
565 NativeReal_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
566                       const asn_TYPE_descriptor_t *td, void **sptr,
567                       const char *opt_mname, const void *buf_ptr, size_t size) {
568     asn_dec_rval_t rval;
569         REAL_t st = { 0, 0 };
570         REAL_t *stp = &st;
571
572         rval = REAL_decode_xer(opt_codec_ctx, td, (void **)&stp, opt_mname,
573                 buf_ptr, size);
574         if(rval.code == RC_OK) {
575         double d;
576         if(asn_REAL2double(&st, &d) || NativeReal__set(td, sptr, d) < 0) {
577             rval.code = RC_FAIL;
578             rval.consumed = 0;
579         }
580         } else {
581         /* Convert all errors into RC_FAIL */
582         rval.consumed = 0;
583         }
584         ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &st);
585         return rval;
586 }
587
588 asn_enc_rval_t
589 NativeReal_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
590                       int ilevel, enum xer_encoder_flags_e flags,
591                       asn_app_consume_bytes_f *cb, void *app_key) {
592         double d = NativeReal__get_double(td, sptr);
593         asn_enc_rval_t er = {0,0,0};
594
595         (void)ilevel;
596
597         er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
598         if(er.encoded < 0) ASN__ENCODE_FAILED;
599
600         ASN__ENCODED_OK(er);
601 }
602
603 /*
604  * REAL specific human-readable output.
605  */
606 int
607 NativeReal_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
608                  asn_app_consume_bytes_f *cb, void *app_key) {
609     (void)ilevel;       /* Unused argument */
610
611         if(sptr) {
612         double d = NativeReal__get_double(td, sptr);
613         return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
614     } else {
615         return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
616     }
617 }
618
619 int
620 NativeReal_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
621                    const void *bptr) {
622
623     if(aptr && bptr) {
624         double a = NativeReal__get_double(td, aptr);
625         double b = NativeReal__get_double(td, bptr);
626
627         /* NaN sorted above everything else */
628         if(asn_isnan(a)) {
629             if(asn_isnan(b)) {
630                 return 0;
631             } else {
632                 return -1;
633             }
634         } else if(asn_isnan(b)) {
635             return 1;
636         }
637         /* Value comparison. */
638         if(a < b) {
639             return -1;
640         } else if(a > b) {
641             return 1;
642         } else {
643             return 0;
644         }
645     } else if(!aptr) {
646         return -1;
647     } else {
648         return 1;
649     }
650 }
651
652 void
653 NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr,
654                 enum asn_struct_free_method method) {
655     if(!td || !ptr)
656                 return;
657
658         ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
659                 td->name, method, ptr);
660
661     switch(method) {
662     case ASFM_FREE_EVERYTHING:
663         FREEMEM(ptr);
664         break;
665     case ASFM_FREE_UNDERLYING:
666         break;
667     case ASFM_FREE_UNDERLYING_AND_RESET: {
668         const asn_NativeReal_specifics_t *specs;
669         size_t float_size;
670         specs = (const asn_NativeReal_specifics_t *)td->specifics;
671         float_size = specs ? specs->float_size : sizeof(double);
672         memset(ptr, 0, float_size);
673     } break;
674     }
675 }
676
677 asn_random_fill_result_t
678 NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
679                        const asn_encoding_constraints_t *constraints,
680                        size_t max_length) {
681     asn_random_fill_result_t result_ok = {ARFILL_OK, 0};
682     asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
683     asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
684 #ifndef INFINITY
685 #define INFINITY (1.0/0.0)
686 #endif
687 #ifndef NAN
688 #define NAN (0.0/0.0)
689 #endif
690     static const double double_values[] = {
691         -M_E, M_E, -M_PI, M_PI, /* Better precision than with floats */
692         -1E+308, 1E+308,
693         /* 2^51 */
694         -2251799813685248.0, 2251799813685248.0,
695         /* 2^52 */
696         -4503599627370496.0, 4503599627370496.0,
697         /* 2^100 */
698         -1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
699         -DBL_MIN, DBL_MIN,
700         -DBL_MAX, DBL_MAX,
701 #ifdef  DBL_TRUE_MIN
702         -DBL_TRUE_MIN, DBL_TRUE_MIN
703 #endif
704     };
705     static const float float_values[] = {
706         0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
707         -FLT_MIN, FLT_MIN,
708         -FLT_MAX, FLT_MAX,
709 #ifdef  FLT_TRUE_MIN
710         -FLT_TRUE_MIN, FLT_TRUE_MIN,
711 #endif
712         INFINITY, -INFINITY, NAN
713     };
714     ssize_t float_set_size = NativeReal__float_size(td);
715     const size_t n_doubles = sizeof(double_values) / sizeof(double_values[0]);
716     const size_t n_floats = sizeof(float_values) / sizeof(float_values[0]);
717     double d;
718
719     (void)constraints;
720
721     if(max_length == 0) return result_skipped;
722
723     if(float_set_size == sizeof(double) && asn_random_between(0, 1) == 0) {
724         d = double_values[asn_random_between(0, n_doubles - 1)];
725     } else {
726         d = float_values[asn_random_between(0, n_floats - 1)];
727     }
728
729     if(NativeReal__set(td, sptr, d) < 0) {
730         return result_failed;
731     }
732
733     result_ok.length = float_set_size;
734     return result_ok;
735 }
736
737
738 /*
739  * Local helper functions.
740  */
741
742 static size_t
743 NativeReal__float_size(const asn_TYPE_descriptor_t *td) {
744     const asn_NativeReal_specifics_t *specs =
745         (const asn_NativeReal_specifics_t *)td->specifics;
746     return specs ? specs->float_size : sizeof(double);
747 }
748
749 static double
750 NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
751     size_t float_size = NativeReal__float_size(td);
752     if(float_size == sizeof(float)) {
753         return *(const float *)ptr;
754     } else {
755         return *(const double *)ptr;
756     }
757 }
758
759 static ssize_t  /* Returns -1 or float size. */
760 NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
761     size_t float_size = NativeReal__float_size(td);
762     void *native;
763
764     if(!(native = *sptr)) {
765         native = (*sptr = CALLOC(1, float_size));
766         if(!native) {
767             return -1;
768         }
769     }
770
771     if(float_size == sizeof(float)) {
772         if(asn_double2float(d, (float *)native)) {
773             return -1;
774         }
775     } else {
776         *(double *)native = d;
777     }
778
779     return float_size;
780 }
781