blob: 382ef3bf48a43eb804c57fdb88be00846936b2f1 [file] [log] [blame]
Lev Walkin41ba1f22004-09-14 12:46:35 +00001/*-
Lev Walkinab1d1e12017-10-03 18:43:12 -07002 * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkin41ba1f22004-09-14 12:46:35 +00003 * Redistribution and modifications are permitted subject to BSD license.
4 */
5/*
Lev Walkin41635d32006-03-18 05:06:57 +00006 * Read the NativeReal.h for the explanation wrt. differences between
Lev Walkin41ba1f22004-09-14 12:46:35 +00007 * 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 */
Lev Walkina9cc46e2004-09-22 16:06:28 +000012#include <asn_internal.h>
Lev Walkin41ba1f22004-09-14 12:46:35 +000013#include <NativeReal.h>
Lev Walkin41ba1f22004-09-14 12:46:35 +000014#include <REAL.h>
Lev Walkin725883b2006-10-09 12:07:58 +000015#include <OCTET_STRING.h>
Lev Walkincd2f48e2017-08-10 02:14:59 -070016#include <math.h>
Jon Ringle35c3f0d2017-10-04 21:54:39 -040017#include <float.h>
Lev Walkin41ba1f22004-09-14 12:46:35 +000018
Lev Walkineff98a52017-09-13 22:24:35 +000019#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"
29static 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
Lev Walkin41ba1f22004-09-14 12:46:35 +000037/*
38 * NativeReal basic type description.
39 */
Wim Lewis18c2ec92014-07-29 11:30:10 -070040static const ber_tlv_tag_t asn_DEF_NativeReal_tags[] = {
Lev Walkin41ba1f22004-09-14 12:46:35 +000041 (ASN_TAG_CLASS_UNIVERSAL | (9 << 2))
42};
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080043asn_TYPE_operation_t asn_OP_NativeReal = {
Lev Walkina9cc46e2004-09-22 16:06:28 +000044 NativeReal_free,
45 NativeReal_print,
Lev Walkincd2f48e2017-08-10 02:14:59 -070046 NativeReal_compare,
Lev Walkin41ba1f22004-09-14 12:46:35 +000047 NativeReal_decode_ber,
48 NativeReal_encode_der,
Lev Walkin8471cec2004-10-21 14:02:19 +000049 NativeReal_decode_xer,
Lev Walkina9cc46e2004-09-22 16:06:28 +000050 NativeReal_encode_xer,
Lev Walkincc159472017-07-06 08:26:36 -070051#ifdef ASN_DISABLE_OER_SUPPORT
52 0,
53 0,
54#else
Lev Walkinab1d1e12017-10-03 18:43:12 -070055 NativeReal_decode_oer,
56 NativeReal_encode_oer,
Lev Walkincc159472017-07-06 08:26:36 -070057#endif /* ASN_DISABLE_OER_SUPPORT */
Lev Walkinb33425f2017-07-14 14:59:52 +040058#ifdef ASN_DISABLE_PER_SUPPORT
59 0,
60 0,
61#else
62 NativeReal_decode_uper,
63 NativeReal_encode_uper,
64#endif /* ASN_DISABLE_PER_SUPPORT */
Lev Walkina5972be2017-09-29 23:15:58 -070065 NativeReal_random_fill,
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080066 0 /* Use generic outmost tag fetcher */
67};
68asn_TYPE_descriptor_t asn_DEF_NativeReal = {
69 "REAL", /* The ASN.1 type is still REAL */
70 "REAL",
71 &asn_OP_NativeReal,
Lev Walkin5e033762004-09-29 13:26:15 +000072 asn_DEF_NativeReal_tags,
73 sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
74 asn_DEF_NativeReal_tags, /* Same as above */
75 sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
Lev Walkina5972be2017-09-29 23:15:58 -070076 { 0, 0, asn_generic_no_constraint },
Lev Walkin41ba1f22004-09-14 12:46:35 +000077 0, 0, /* No members */
78 0 /* No specifics */
79};
80
Lev Walkin68079d32017-10-08 15:41:20 -070081static size_t NativeReal__float_size(const asn_TYPE_descriptor_t *td);
Lev Walkinafcc8912017-10-04 23:48:35 -070082static double NativeReal__get_double(const asn_TYPE_descriptor_t *td,
83 const void *ptr);
84static ssize_t NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr,
85 double d);
86static void NativeReal__network_swap(size_t float_size, const void *srcp,
87 uint8_t *dst);
Lev Walkincb5e1c72017-10-04 22:23:08 -070088
Lev Walkin41ba1f22004-09-14 12:46:35 +000089/*
90 * Decode REAL type.
91 */
Lev Walkindc06f6b2004-10-20 15:50:55 +000092asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070093NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkinb5450702017-10-04 02:52:57 -070094 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkinab1d1e12017-10-03 18:43:12 -070095 const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinab1d1e12017-10-03 18:43:12 -070096 asn_dec_rval_t rval;
97 ber_tlv_len_t length;
Lev Walkin41ba1f22004-09-14 12:46:35 +000098
Lev Walkinab1d1e12017-10-03 18:43:12 -070099 ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000100
Lev Walkinab1d1e12017-10-03 18:43:12 -0700101 /*
102 * Check tags.
103 */
104 rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
105 &length, 0);
106 if(rval.code != RC_OK) return rval;
Lev Walkin4ca41492017-10-03 20:29:54 -0700107 assert(length >= 0); /* Ensured by ber_check_tags */
Lev Walkin41ba1f22004-09-14 12:46:35 +0000108
Lev Walkinab1d1e12017-10-03 18:43:12 -0700109 ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000110
Lev Walkinab1d1e12017-10-03 18:43:12 -0700111 /*
112 * Make sure we have this length.
113 */
114 buf_ptr = ((const char *)buf_ptr) + rval.consumed;
115 size -= rval.consumed;
116 if(length > (ber_tlv_len_t)size) {
117 rval.code = RC_WMORE;
118 rval.consumed = 0;
119 return rval;
120 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000121
Lev Walkinab1d1e12017-10-03 18:43:12 -0700122 /*
123 * ASN.1 encoded REAL: buf_ptr, length
124 * Fill the Dbl, at the same time checking for overflow.
125 * If overflow occured, return with RC_FAIL.
126 */
127 {
128 uint8_t scratch[24]; /* Longer than %.16f in decimal */
129 REAL_t tmp;
130 double d;
131 int ret;
Lev Walkin7e033b52005-07-02 08:19:17 +0000132
Lev Walkin4ca41492017-10-03 20:29:54 -0700133 if((size_t)length < sizeof(scratch)) {
Lev Walkinab1d1e12017-10-03 18:43:12 -0700134 tmp.buf = scratch;
135 tmp.size = length;
136 } else {
137 /* This rarely happens: impractically long value */
138 tmp.buf = CALLOC(1, length + 1);
139 tmp.size = length;
140 if(!tmp.buf) {
141 rval.code = RC_FAIL;
142 rval.consumed = 0;
143 return rval;
144 }
145 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000146
Lev Walkinab1d1e12017-10-03 18:43:12 -0700147 memcpy(tmp.buf, buf_ptr, length);
148 tmp.buf[length] = '\0';
Lev Walkin41ba1f22004-09-14 12:46:35 +0000149
Lev Walkinab1d1e12017-10-03 18:43:12 -0700150 ret = asn_REAL2double(&tmp, &d);
151 if(tmp.buf != scratch) FREEMEM(tmp.buf);
152 if(ret) {
153 rval.code = RC_FAIL;
154 rval.consumed = 0;
155 return rval;
156 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000157
Lev Walkincb5e1c72017-10-04 22:23:08 -0700158 if(NativeReal__set(td, sptr, d) < 0)
159 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700160 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000161
Lev Walkinab1d1e12017-10-03 18:43:12 -0700162 rval.code = RC_OK;
163 rval.consumed += length;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000164
Lev Walkinb5450702017-10-04 02:52:57 -0700165 ASN_DEBUG("Took %ld/%ld bytes to encode %s", (long)rval.consumed,
166 (long)length, td->name);
Lev Walkinab1d1e12017-10-03 18:43:12 -0700167
168 return rval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000169}
170
171/*
172 * Encode the NativeReal using the standard REAL type DER encoder.
173 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000174asn_enc_rval_t
Lev Walkincb5e1c72017-10-04 22:23:08 -0700175NativeReal_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin41ba1f22004-09-14 12:46:35 +0000176 int tag_mode, ber_tlv_tag_t tag,
177 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700178 double d = NativeReal__get_double(td, sptr);
Lev Walkinb5450702017-10-04 02:52:57 -0700179 asn_enc_rval_t erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000180 REAL_t tmp;
181
Lev Walkina8bbbda2005-02-06 04:29:03 +0000182 /* Prepare a temporary clean structure */
183 memset(&tmp, 0, sizeof(tmp));
184
Lev Walkincb5e1c72017-10-04 22:23:08 -0700185 if(asn_double2REAL(&tmp, d))
186 ASN__ENCODE_FAILED;
187
188 /* Encode a fake REAL */
189 erval = der_encode_primitive(td, &tmp, tag_mode, tag, cb, app_key);
190 if(erval.encoded == -1) {
Lev Walkin41ba1f22004-09-14 12:46:35 +0000191 assert(erval.structure_ptr == &tmp);
Lev Walkincb5e1c72017-10-04 22:23:08 -0700192 erval.structure_ptr = sptr;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000193 }
Lev Walkina8bbbda2005-02-06 04:29:03 +0000194
195 /* Free possibly allocated members of the temporary structure */
Lev Walkincb5e1c72017-10-04 22:23:08 -0700196 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkina8bbbda2005-02-06 04:29:03 +0000197
Lev Walkincb5e1c72017-10-04 22:23:08 -0700198 return erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000199}
200
Lev Walkin41d972b2017-08-23 23:30:59 -0700201#ifndef ASN_DISABLE_PER_SUPPORT
202
Lev Walkin725883b2006-10-09 12:07:58 +0000203/*
204 * Decode REAL type using PER.
205 */
206asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700207NativeReal_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin494fb702017-08-07 20:07:00 -0700208 asn_TYPE_descriptor_t *td,
Lev Walkinb5450702017-10-04 02:52:57 -0700209 const asn_per_constraints_t *constraints, void **sptr,
Lev Walkin494fb702017-08-07 20:07:00 -0700210 asn_per_data_t *pd) {
Lev Walkin725883b2006-10-09 12:07:58 +0000211 asn_dec_rval_t rval;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700212 double d;
Lev Walkin725883b2006-10-09 12:07:58 +0000213 REAL_t tmp;
214 void *ptmp = &tmp;
215 int ret;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000216
Lev Walkin725883b2006-10-09 12:07:58 +0000217 (void)constraints;
218
Lev Walkin725883b2006-10-09 12:07:58 +0000219 memset(&tmp, 0, sizeof(tmp));
Lev Walkinb5450702017-10-04 02:52:57 -0700220 rval = OCTET_STRING_decode_uper(opt_codec_ctx, &asn_DEF_REAL,
221 NULL, &ptmp, pd);
222 if(rval.code != RC_OK) {
Lev Walkin725883b2006-10-09 12:07:58 +0000223 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
224 return rval;
225 }
226
Lev Walkinb5450702017-10-04 02:52:57 -0700227 ret = asn_REAL2double(&tmp, &d);
Lev Walkin725883b2006-10-09 12:07:58 +0000228 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700229 if(ret) ASN__DECODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000230
Lev Walkincb5e1c72017-10-04 22:23:08 -0700231 if(NativeReal__set(td, sptr, d) < 0 )
232 ASN__DECODE_FAILED;
Lev Walkinb5450702017-10-04 02:52:57 -0700233
Lev Walkin725883b2006-10-09 12:07:58 +0000234 return rval;
235}
236
237/*
238 * Encode the NativeReal using the OCTET STRING PER encoder.
239 */
240asn_enc_rval_t
241NativeReal_encode_uper(asn_TYPE_descriptor_t *td,
Lev Walkin494fb702017-08-07 20:07:00 -0700242 const asn_per_constraints_t *constraints, void *sptr,
243 asn_per_outp_t *po) {
Lev Walkinb5450702017-10-04 02:52:57 -0700244 double d = NativeReal__get_double(td, sptr);
Lev Walkin725883b2006-10-09 12:07:58 +0000245 asn_enc_rval_t erval;
246 REAL_t tmp;
247
248 (void)constraints;
249
250 /* Prepare a temporary clean structure */
251 memset(&tmp, 0, sizeof(tmp));
252
Lev Walkinb5450702017-10-04 02:52:57 -0700253 if(asn_double2REAL(&tmp, d))
Lev Walkin7c1dc052016-03-14 03:08:15 -0700254 ASN__ENCODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000255
256 /* Encode a DER REAL */
Lev Walkinb5450702017-10-04 02:52:57 -0700257 erval = OCTET_STRING_encode_uper(&asn_DEF_REAL, NULL, &tmp, po);
258 if(erval.encoded == -1)
Lev Walkin725883b2006-10-09 12:07:58 +0000259 erval.structure_ptr = sptr;
260
261 /* Free possibly allocated members of the temporary structure */
262 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
263
264 return erval;
265}
Lev Walkin8471cec2004-10-21 14:02:19 +0000266
Lev Walkin41d972b2017-08-23 23:30:59 -0700267#endif /* ASN_DISABLE_PER_SUPPORT */
268
Lev Walkinab1d1e12017-10-03 18:43:12 -0700269#ifndef ASN_DISABLE_OER_SUPPORT
270
271/*
272 * Encode as Canonical OER.
273 */
274asn_enc_rval_t
275NativeReal_encode_oer(asn_TYPE_descriptor_t *td,
276 const asn_oer_constraints_t *constraints, void *sptr,
277 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700278 asn_enc_rval_t er = {0, 0, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700279
Lev Walkinafcc8912017-10-04 23:48:35 -0700280 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
281 if(constraints && constraints->value.width != 0) {
282 /* X.696 IEEE 754 binary32 and binary64 encoding */
283 uint8_t scratch[sizeof(double)];
284 const asn_NativeReal_specifics_t *specs =
285 (const asn_NativeReal_specifics_t *)td->specifics;
286 size_t wire_size = constraints->value.width;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700287
Lev Walkinafcc8912017-10-04 23:48:35 -0700288 if(specs ? (wire_size == specs->float_size)
289 : (wire_size == sizeof(double))) {
290 /*
291 * Our representation matches the wire, modulo endianness.
292 * That was the whole point of compact encoding!
293 */
294 } else {
Lev Walkinfe374312017-10-07 00:24:51 -0700295 assert((wire_size == sizeof(double))
296 || (specs && specs->float_size == wire_size));
Lev Walkinafcc8912017-10-04 23:48:35 -0700297 ASN__ENCODE_FAILED;
298 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700299
Lev Walkinafcc8912017-10-04 23:48:35 -0700300 /*
301 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
302 * So we assume the network format is big endian.
303 */
304 NativeReal__network_swap(wire_size, sptr, scratch);
305 if(cb(scratch, wire_size, app_key) < 0) {
306 ASN__ENCODE_FAILED;
307 } else {
308 er.encoded = wire_size;
309 ASN__ENCODED_OK(er);
310 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700311 } else {
Lev Walkinafcc8912017-10-04 23:48:35 -0700312 double d = NativeReal__get_double(td, sptr);
313 ssize_t len_len;
314 REAL_t tmp;
315
316 /* Prepare a temporary clean structure */
317 memset(&tmp, 0, sizeof(tmp));
318
319 if(asn_double2REAL(&tmp, d)) {
320 ASN__ENCODE_FAILED;
321 }
322
323 /* Encode a fake REAL */
324 len_len = oer_serialize_length(tmp.size, cb, app_key);
325 if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
326 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
327 ASN__ENCODE_FAILED;
328 } else {
329 er.encoded = len_len + tmp.size;
330 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
331 ASN__ENCODED_OK(er);
332 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700333 }
334}
335
336asn_dec_rval_t
337NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
338 asn_TYPE_descriptor_t *td,
339 const asn_oer_constraints_t *constraints, void **sptr,
340 const void *ptr, size_t size) {
341 asn_dec_rval_t ok = {RC_OK, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700342 double d;
343 ssize_t len_len;
344 size_t real_body_len;
345
346 (void)opt_codec_ctx;
Lev Walkinafcc8912017-10-04 23:48:35 -0700347
348 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
349 if(constraints && constraints->value.width != 0) {
350 /* X.696 IEEE 754 binary32 and binary64 encoding */
351 uint8_t scratch[sizeof(double)];
352 size_t wire_size = constraints->value.width;
353
354 if(size < wire_size)
355 ASN__DECODE_STARVED;
356
357 /*
358 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
359 * So we assume the network format is big endian.
360 */
361 NativeReal__network_swap(wire_size, ptr, scratch);
362
363 switch(wire_size) {
364 case sizeof(double):
365 if(NativeReal__set(td, sptr, *(const double *)scratch) < 0)
366 ASN__DECODE_FAILED;
367 break;
368 case sizeof(float):
369 if(NativeReal__set(td, sptr, *(const float *)scratch) < 0)
370 ASN__DECODE_FAILED;
371 break;
372 default:
373 ASN__DECODE_FAILED;
374 }
375
376 ok.consumed = wire_size;
377 return ok;
378 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700379
380 len_len = oer_fetch_length(ptr, size, &real_body_len);
381 if(len_len < 0) ASN__DECODE_FAILED;
382 if(len_len == 0) ASN__DECODE_STARVED;
383
384 ptr = (const char *)ptr + len_len;
385 size -= len_len;
386
387 if(real_body_len > size) ASN__DECODE_STARVED;
388
389 {
390 uint8_t scratch[24]; /* Longer than %.16f in decimal */
391 REAL_t tmp;
392 int ret;
393
394 if(real_body_len < sizeof(scratch)) {
395 tmp.buf = scratch;
396 tmp.size = real_body_len;
397 } else {
398 /* This rarely happens: impractically long value */
399 tmp.buf = CALLOC(1, real_body_len + 1);
400 tmp.size = real_body_len;
401 if(!tmp.buf) {
402 ASN__DECODE_FAILED;
403 }
404 }
405
406 memcpy(tmp.buf, ptr, real_body_len);
407 tmp.buf[real_body_len] = '\0';
408
409 ret = asn_REAL2double(&tmp, &d);
410 if(tmp.buf != scratch) FREEMEM(tmp.buf);
411 if(ret) {
412 ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
413 real_body_len);
414 ASN__DECODE_FAILED;
415 }
416 }
417
Lev Walkincb5e1c72017-10-04 22:23:08 -0700418 if(NativeReal__set(td, sptr, d) < 0)
419 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700420
Lev Walkinab1d1e12017-10-03 18:43:12 -0700421 ok.consumed = len_len + real_body_len;
422 return ok;
423}
424
425#endif /* ASN_DISABLE_OER_SUPPORT */
426
Lev Walkin8471cec2004-10-21 14:02:19 +0000427/*
428 * Decode the chunk of XML text encoding REAL.
429 */
430asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700431NativeReal_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin8471cec2004-10-21 14:02:19 +0000432 asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000433 const void *buf_ptr, size_t size) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000434 asn_dec_rval_t rval;
Lev Walkinb5450702017-10-04 02:52:57 -0700435 REAL_t st = { 0, 0 };
436 REAL_t *stp = &st;
Lev Walkin8471cec2004-10-21 14:02:19 +0000437
Lev Walkinb5450702017-10-04 02:52:57 -0700438 rval = REAL_decode_xer(opt_codec_ctx, td, (void **)&stp, opt_mname,
Lev Walkin8471cec2004-10-21 14:02:19 +0000439 buf_ptr, size);
440 if(rval.code == RC_OK) {
Lev Walkinb5450702017-10-04 02:52:57 -0700441 double d;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700442 if(asn_REAL2double(&st, &d) || NativeReal__set(td, sptr, d) < 0) {
443 rval.code = RC_FAIL;
444 rval.consumed = 0;
Lev Walkinb5450702017-10-04 02:52:57 -0700445 }
Lev Walkin8471cec2004-10-21 14:02:19 +0000446 } else {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700447 /* Convert all errors into RC_FAIL */
448 rval.consumed = 0;
Lev Walkin8471cec2004-10-21 14:02:19 +0000449 }
Lev Walkinb5450702017-10-04 02:52:57 -0700450 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &st);
Lev Walkin8471cec2004-10-21 14:02:19 +0000451 return rval;
452}
453
Lev Walkina9cc46e2004-09-22 16:06:28 +0000454asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000455NativeReal_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000456 int ilevel, enum xer_encoder_flags_e flags,
457 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinb5450702017-10-04 02:52:57 -0700458 double d = NativeReal__get_double(td, sptr);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000459 asn_enc_rval_t er;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000460
461 (void)ilevel;
462
Lev Walkinb5450702017-10-04 02:52:57 -0700463 er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
464 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000465
Lev Walkin7c1dc052016-03-14 03:08:15 -0700466 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000467}
468
Lev Walkin41ba1f22004-09-14 12:46:35 +0000469/*
470 * REAL specific human-readable output.
471 */
472int
Lev Walkin5e033762004-09-29 13:26:15 +0000473NativeReal_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkin41ba1f22004-09-14 12:46:35 +0000474 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin41ba1f22004-09-14 12:46:35 +0000475
Lev Walkin41ba1f22004-09-14 12:46:35 +0000476 (void)ilevel; /* Unused argument */
477
Lev Walkinb5450702017-10-04 02:52:57 -0700478 if(sptr) {
479 double d = NativeReal__get_double(td, sptr);
480 return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
481 } else {
482 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
483 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000484}
485
Lev Walkincd2f48e2017-08-10 02:14:59 -0700486int
487NativeReal_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
488 const void *bptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700489
Lev Walkinb5450702017-10-04 02:52:57 -0700490 if(aptr && bptr) {
491 double a = NativeReal__get_double(td, aptr);
492 double b = NativeReal__get_double(td, bptr);
493
Lev Walkincd2f48e2017-08-10 02:14:59 -0700494 /* NaN sorted above everything else */
Lev Walkinb5450702017-10-04 02:52:57 -0700495 if(asn_isnan(a)) {
496 if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700497 return 0;
498 } else {
499 return -1;
500 }
Lev Walkinb5450702017-10-04 02:52:57 -0700501 } else if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700502 return 1;
503 }
504 /* Value comparison. */
Lev Walkinb5450702017-10-04 02:52:57 -0700505 if(a < b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700506 return -1;
Lev Walkinb5450702017-10-04 02:52:57 -0700507 } else if(a > b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700508 return 1;
509 } else {
510 return 0;
511 }
Lev Walkinb5450702017-10-04 02:52:57 -0700512 } else if(!aptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700513 return -1;
514 } else {
515 return 1;
516 }
517}
518
Lev Walkin41ba1f22004-09-14 12:46:35 +0000519void
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700520NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr,
521 enum asn_struct_free_method method) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700522 if(!td || !ptr)
Lev Walkin41ba1f22004-09-14 12:46:35 +0000523 return;
524
525 ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700526 td->name, method, ptr);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000527
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700528 switch(method) {
529 case ASFM_FREE_EVERYTHING:
530 FREEMEM(ptr);
531 break;
532 case ASFM_FREE_UNDERLYING:
533 break;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700534 case ASFM_FREE_UNDERLYING_AND_RESET: {
535 const asn_NativeReal_specifics_t *specs;
536 size_t float_size;
537 specs = (const asn_NativeReal_specifics_t *)td->specifics;
538 float_size = specs ? specs->float_size : sizeof(double);
539 memset(ptr, 0, float_size);
540 } break;
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700541 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000542}
543
Lev Walkina5972be2017-09-29 23:15:58 -0700544asn_random_fill_result_t
545NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
546 const asn_encoding_constraints_t *constraints,
547 size_t max_length) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700548 asn_random_fill_result_t result_ok = {ARFILL_OK, 0};
Lev Walkina5972be2017-09-29 23:15:58 -0700549 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
550 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
Lev Walkinfe374312017-10-07 00:24:51 -0700551#ifndef INFINITY
552#define INFINITY (1.0/0.0)
553#endif
554#ifndef NAN
555#define NAN (0.0/0.0)
556#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700557 static const double double_values[] = {
558 -M_E, M_E, -M_PI, M_PI, /* Better precision than with floats */
559 -1E+308, 1E+308,
Lev Walkinab1d1e12017-10-03 18:43:12 -0700560 /* 2^51 */
561 -2251799813685248.0, 2251799813685248.0,
562 /* 2^52 */
563 -4503599627370496.0, 4503599627370496.0,
564 /* 2^100 */
565 -1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000566 -DBL_MIN, DBL_MIN,
567 -DBL_MAX, DBL_MAX,
Lev Walkin68079d32017-10-08 15:41:20 -0700568#ifdef DBL_TRUE_MIN
569 -DBL_TRUE_MIN, DBL_TRUE_MIN
570#endif
571 };
572 static const float float_values[] = {
573 0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
574 -FLT_MIN, FLT_MIN,
575 -FLT_MAX, FLT_MAX,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000576#ifdef FLT_TRUE_MIN
577 -FLT_TRUE_MIN, FLT_TRUE_MIN,
578#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700579 INFINITY, -INFINITY, NAN
580 };
581 ssize_t float_set_size = NativeReal__float_size(td);
582 const size_t n_doubles = sizeof(double_values) / sizeof(double_values[0]);
583 const size_t n_floats = sizeof(float_values) / sizeof(float_values[0]);
Lev Walkina5972be2017-09-29 23:15:58 -0700584 double d;
585
Lev Walkina5972be2017-09-29 23:15:58 -0700586 (void)constraints;
587
588 if(max_length == 0) return result_skipped;
589
Lev Walkin68079d32017-10-08 15:41:20 -0700590 if(float_set_size == sizeof(double) && asn_random_between(0, 1) == 0) {
591 d = double_values[asn_random_between(0, n_doubles - 1)];
592 } else {
593 d = float_values[asn_random_between(0, n_floats - 1)];
594 }
Lev Walkina5972be2017-09-29 23:15:58 -0700595
Lev Walkin68079d32017-10-08 15:41:20 -0700596 if(NativeReal__set(td, sptr, d) < 0) {
597 return result_failed;
598 }
Lev Walkina5972be2017-09-29 23:15:58 -0700599
Lev Walkincb5e1c72017-10-04 22:23:08 -0700600 result_ok.length = float_set_size;
Lev Walkina5972be2017-09-29 23:15:58 -0700601 return result_ok;
602}
Lev Walkinafcc8912017-10-04 23:48:35 -0700603
604
605/*
606 * Local helper functions.
607 */
608
Lev Walkin68079d32017-10-08 15:41:20 -0700609static size_t
610NativeReal__float_size(const asn_TYPE_descriptor_t *td) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700611 const asn_NativeReal_specifics_t *specs =
612 (const asn_NativeReal_specifics_t *)td->specifics;
Lev Walkin68079d32017-10-08 15:41:20 -0700613 return specs ? specs->float_size : sizeof(double);
614}
615
616static double
617NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
618 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700619 if(float_size == sizeof(float)) {
620 return *(const float *)ptr;
621 } else {
622 return *(const double *)ptr;
623 }
624}
625
626static ssize_t /* Returns -1 or float size. */
627NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
Lev Walkin68079d32017-10-08 15:41:20 -0700628 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700629 void *native;
630
631 if(!(native = *sptr)) {
632 native = (*sptr = CALLOC(1, float_size));
633 if(!native) {
634 return -1;
635 }
636 }
637
638 if(float_size == sizeof(float)) {
Lev Walkin68079d32017-10-08 15:41:20 -0700639 if(asn_double2float(d, (float *)native)) {
640 return -1;
641 }
Lev Walkinafcc8912017-10-04 23:48:35 -0700642 } else {
643 *(double *)native = d;
644 }
645
646 return float_size;
647}
648
649/*
650 * Swap bytes from/to network, if local is little-endian.
651 * Unused endianness sections are likely removed at compile phase.
652 */
653static void
654NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
655 const uint8_t *src = srcp;
656 double test = -0.0;
657 int float_big_endian = *(const char *)&test != 0;
658 /* In lieu of static_assert(sizeof(double) == 8) */
659 static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
660 static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
661 /* In lieu of static_assert(sizeof(sizeof) == 4) */
662 static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
663 static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
664
665 switch(float_size) {
666 case sizeof(double):
667 assert(sizeof(double) == 8);
668 if(float_big_endian) {
669 dst[0] = src[0];
670 dst[1] = src[1];
671 dst[2] = src[2];
672 dst[3] = src[3];
673 dst[4] = src[4];
674 dst[5] = src[5];
675 dst[6] = src[6];
676 dst[7] = src[7];
677 } else {
678 dst[0] = src[7];
679 dst[1] = src[6];
680 dst[2] = src[5];
681 dst[3] = src[4];
682 dst[4] = src[3];
683 dst[5] = src[2];
684 dst[6] = src[1];
685 dst[7] = src[0];
686 }
687 return;
688 case sizeof(float):
689 assert(sizeof(float) == 4);
690 if(float_big_endian) {
691 dst[0] = src[0];
692 dst[1] = src[1];
693 dst[2] = src[2];
694 dst[3] = src[3];
695 } else {
696 dst[0] = src[3];
697 dst[1] = src[2];
698 dst[2] = src[1];
699 dst[3] = src[0];
700 }
701 return;
702 }
703}