blob: 6f540f12b5ae3c30f1e643bd0a619d86050c61ca [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 Walkin20696a42017-10-17 21:27:33 -070094 const 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 Walkin20696a42017-10-17 21:27:33 -0700175NativeReal_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
176 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 Walkin20696a42017-10-17 21:27:33 -0700208 const 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 Walkin20696a42017-10-17 21:27:33 -0700211 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
Lev Walkin20696a42017-10-17 21:27:33 -0700241NativeReal_encode_uper(const asn_TYPE_descriptor_t *td,
242 const asn_per_constraints_t *constraints,
243 const void *sptr, 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
Lev Walkin20696a42017-10-17 21:27:33 -0700275NativeReal_encode_oer(const asn_TYPE_descriptor_t *td,
276 const asn_oer_constraints_t *constraints,
277 const void *sptr, asn_app_consume_bytes_f *cb,
278 void *app_key) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700279 asn_enc_rval_t er = {0, 0, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700280
Lev Walkinafcc8912017-10-04 23:48:35 -0700281 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
282 if(constraints && constraints->value.width != 0) {
283 /* X.696 IEEE 754 binary32 and binary64 encoding */
284 uint8_t scratch[sizeof(double)];
285 const asn_NativeReal_specifics_t *specs =
286 (const asn_NativeReal_specifics_t *)td->specifics;
287 size_t wire_size = constraints->value.width;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700288
Lev Walkinafcc8912017-10-04 23:48:35 -0700289 if(specs ? (wire_size == specs->float_size)
290 : (wire_size == sizeof(double))) {
291 /*
292 * Our representation matches the wire, modulo endianness.
293 * That was the whole point of compact encoding!
294 */
295 } else {
Lev Walkinfe374312017-10-07 00:24:51 -0700296 assert((wire_size == sizeof(double))
297 || (specs && specs->float_size == wire_size));
Lev Walkinafcc8912017-10-04 23:48:35 -0700298 ASN__ENCODE_FAILED;
299 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700300
Lev Walkinafcc8912017-10-04 23:48:35 -0700301 /*
302 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
303 * So we assume the network format is big endian.
304 */
305 NativeReal__network_swap(wire_size, sptr, scratch);
306 if(cb(scratch, wire_size, app_key) < 0) {
307 ASN__ENCODE_FAILED;
308 } else {
309 er.encoded = wire_size;
310 ASN__ENCODED_OK(er);
311 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700312 } else {
Lev Walkinafcc8912017-10-04 23:48:35 -0700313 double d = NativeReal__get_double(td, sptr);
314 ssize_t len_len;
315 REAL_t tmp;
316
317 /* Prepare a temporary clean structure */
318 memset(&tmp, 0, sizeof(tmp));
319
320 if(asn_double2REAL(&tmp, d)) {
321 ASN__ENCODE_FAILED;
322 }
323
324 /* Encode a fake REAL */
325 len_len = oer_serialize_length(tmp.size, cb, app_key);
326 if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
327 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
328 ASN__ENCODE_FAILED;
329 } else {
330 er.encoded = len_len + tmp.size;
331 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
332 ASN__ENCODED_OK(er);
333 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700334 }
335}
336
337asn_dec_rval_t
338NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700339 const asn_TYPE_descriptor_t *td,
340 const asn_oer_constraints_t *constraints, void **sptr,
341 const void *ptr, size_t size) {
Lev Walkinab1d1e12017-10-03 18:43:12 -0700342 asn_dec_rval_t ok = {RC_OK, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700343 double d;
344 ssize_t len_len;
345 size_t real_body_len;
346
347 (void)opt_codec_ctx;
Lev Walkinafcc8912017-10-04 23:48:35 -0700348
349 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
350 if(constraints && constraints->value.width != 0) {
351 /* X.696 IEEE 754 binary32 and binary64 encoding */
352 uint8_t scratch[sizeof(double)];
353 size_t wire_size = constraints->value.width;
354
355 if(size < wire_size)
356 ASN__DECODE_STARVED;
357
358 /*
359 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
360 * So we assume the network format is big endian.
361 */
362 NativeReal__network_swap(wire_size, ptr, scratch);
363
Vasil Velichkov39ab82f2017-10-18 20:33:57 +0300364
Lev Walkinafcc8912017-10-04 23:48:35 -0700365 switch(wire_size) {
Vasil Velichkov39ab82f2017-10-18 20:33:57 +0300366 case sizeof(double):
367 {
368 double tmp;
369 memcpy(&tmp, scratch, sizeof(double));
370 if(NativeReal__set(td, sptr, tmp) < 0)
371 ASN__DECODE_FAILED;
372 }
373 break;
374 case sizeof(float):
375 {
376 float tmp;
377 memcpy(&tmp, scratch, sizeof(float));
378 if(NativeReal__set(td, sptr, tmp) < 0)
379 ASN__DECODE_FAILED;
380 }
381 break;
Lev Walkinafcc8912017-10-04 23:48:35 -0700382 default:
383 ASN__DECODE_FAILED;
384 }
385
386 ok.consumed = wire_size;
387 return ok;
388 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700389
390 len_len = oer_fetch_length(ptr, size, &real_body_len);
391 if(len_len < 0) ASN__DECODE_FAILED;
392 if(len_len == 0) ASN__DECODE_STARVED;
393
394 ptr = (const char *)ptr + len_len;
395 size -= len_len;
396
397 if(real_body_len > size) ASN__DECODE_STARVED;
398
399 {
400 uint8_t scratch[24]; /* Longer than %.16f in decimal */
401 REAL_t tmp;
402 int ret;
403
404 if(real_body_len < sizeof(scratch)) {
405 tmp.buf = scratch;
406 tmp.size = real_body_len;
407 } else {
408 /* This rarely happens: impractically long value */
409 tmp.buf = CALLOC(1, real_body_len + 1);
410 tmp.size = real_body_len;
411 if(!tmp.buf) {
412 ASN__DECODE_FAILED;
413 }
414 }
415
416 memcpy(tmp.buf, ptr, real_body_len);
417 tmp.buf[real_body_len] = '\0';
418
419 ret = asn_REAL2double(&tmp, &d);
420 if(tmp.buf != scratch) FREEMEM(tmp.buf);
421 if(ret) {
422 ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
423 real_body_len);
424 ASN__DECODE_FAILED;
425 }
426 }
427
Lev Walkincb5e1c72017-10-04 22:23:08 -0700428 if(NativeReal__set(td, sptr, d) < 0)
429 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700430
Lev Walkinab1d1e12017-10-03 18:43:12 -0700431 ok.consumed = len_len + real_body_len;
432 return ok;
433}
434
435#endif /* ASN_DISABLE_OER_SUPPORT */
436
Lev Walkin8471cec2004-10-21 14:02:19 +0000437/*
438 * Decode the chunk of XML text encoding REAL.
439 */
440asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700441NativeReal_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700442 const asn_TYPE_descriptor_t *td, void **sptr,
443 const char *opt_mname, const void *buf_ptr, size_t size) {
444 asn_dec_rval_t rval;
Lev Walkinb5450702017-10-04 02:52:57 -0700445 REAL_t st = { 0, 0 };
446 REAL_t *stp = &st;
Lev Walkin8471cec2004-10-21 14:02:19 +0000447
Lev Walkinb5450702017-10-04 02:52:57 -0700448 rval = REAL_decode_xer(opt_codec_ctx, td, (void **)&stp, opt_mname,
Lev Walkin8471cec2004-10-21 14:02:19 +0000449 buf_ptr, size);
450 if(rval.code == RC_OK) {
Lev Walkinb5450702017-10-04 02:52:57 -0700451 double d;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700452 if(asn_REAL2double(&st, &d) || NativeReal__set(td, sptr, d) < 0) {
453 rval.code = RC_FAIL;
454 rval.consumed = 0;
Lev Walkinb5450702017-10-04 02:52:57 -0700455 }
Lev Walkin8471cec2004-10-21 14:02:19 +0000456 } else {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700457 /* Convert all errors into RC_FAIL */
458 rval.consumed = 0;
Lev Walkin8471cec2004-10-21 14:02:19 +0000459 }
Lev Walkinb5450702017-10-04 02:52:57 -0700460 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &st);
Lev Walkin8471cec2004-10-21 14:02:19 +0000461 return rval;
462}
463
Lev Walkina9cc46e2004-09-22 16:06:28 +0000464asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700465NativeReal_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
466 int ilevel, enum xer_encoder_flags_e flags,
467 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinb5450702017-10-04 02:52:57 -0700468 double d = NativeReal__get_double(td, sptr);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000469 asn_enc_rval_t er;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000470
471 (void)ilevel;
472
Lev Walkinb5450702017-10-04 02:52:57 -0700473 er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
474 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000475
Lev Walkin7c1dc052016-03-14 03:08:15 -0700476 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000477}
478
Lev Walkin41ba1f22004-09-14 12:46:35 +0000479/*
480 * REAL specific human-readable output.
481 */
482int
Lev Walkin20696a42017-10-17 21:27:33 -0700483NativeReal_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
484 asn_app_consume_bytes_f *cb, void *app_key) {
485 (void)ilevel; /* Unused argument */
Lev Walkin41ba1f22004-09-14 12:46:35 +0000486
Lev Walkinb5450702017-10-04 02:52:57 -0700487 if(sptr) {
488 double d = NativeReal__get_double(td, sptr);
489 return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
490 } else {
491 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
492 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000493}
494
Lev Walkincd2f48e2017-08-10 02:14:59 -0700495int
496NativeReal_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
497 const void *bptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700498
Lev Walkinb5450702017-10-04 02:52:57 -0700499 if(aptr && bptr) {
500 double a = NativeReal__get_double(td, aptr);
501 double b = NativeReal__get_double(td, bptr);
502
Lev Walkincd2f48e2017-08-10 02:14:59 -0700503 /* NaN sorted above everything else */
Lev Walkinb5450702017-10-04 02:52:57 -0700504 if(asn_isnan(a)) {
505 if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700506 return 0;
507 } else {
508 return -1;
509 }
Lev Walkinb5450702017-10-04 02:52:57 -0700510 } else if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700511 return 1;
512 }
513 /* Value comparison. */
Lev Walkinb5450702017-10-04 02:52:57 -0700514 if(a < b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700515 return -1;
Lev Walkinb5450702017-10-04 02:52:57 -0700516 } else if(a > b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700517 return 1;
518 } else {
519 return 0;
520 }
Lev Walkinb5450702017-10-04 02:52:57 -0700521 } else if(!aptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700522 return -1;
523 } else {
524 return 1;
525 }
526}
527
Lev Walkin41ba1f22004-09-14 12:46:35 +0000528void
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700529NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr,
530 enum asn_struct_free_method method) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700531 if(!td || !ptr)
Lev Walkin41ba1f22004-09-14 12:46:35 +0000532 return;
533
534 ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700535 td->name, method, ptr);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000536
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700537 switch(method) {
538 case ASFM_FREE_EVERYTHING:
539 FREEMEM(ptr);
540 break;
541 case ASFM_FREE_UNDERLYING:
542 break;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700543 case ASFM_FREE_UNDERLYING_AND_RESET: {
544 const asn_NativeReal_specifics_t *specs;
545 size_t float_size;
546 specs = (const asn_NativeReal_specifics_t *)td->specifics;
547 float_size = specs ? specs->float_size : sizeof(double);
548 memset(ptr, 0, float_size);
549 } break;
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700550 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000551}
552
Lev Walkina5972be2017-09-29 23:15:58 -0700553asn_random_fill_result_t
554NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
555 const asn_encoding_constraints_t *constraints,
556 size_t max_length) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700557 asn_random_fill_result_t result_ok = {ARFILL_OK, 0};
Lev Walkina5972be2017-09-29 23:15:58 -0700558 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
559 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
Lev Walkinfe374312017-10-07 00:24:51 -0700560#ifndef INFINITY
561#define INFINITY (1.0/0.0)
562#endif
563#ifndef NAN
564#define NAN (0.0/0.0)
565#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700566 static const double double_values[] = {
567 -M_E, M_E, -M_PI, M_PI, /* Better precision than with floats */
568 -1E+308, 1E+308,
Lev Walkinab1d1e12017-10-03 18:43:12 -0700569 /* 2^51 */
570 -2251799813685248.0, 2251799813685248.0,
571 /* 2^52 */
572 -4503599627370496.0, 4503599627370496.0,
573 /* 2^100 */
574 -1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000575 -DBL_MIN, DBL_MIN,
576 -DBL_MAX, DBL_MAX,
Lev Walkin68079d32017-10-08 15:41:20 -0700577#ifdef DBL_TRUE_MIN
578 -DBL_TRUE_MIN, DBL_TRUE_MIN
579#endif
580 };
581 static const float float_values[] = {
582 0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
583 -FLT_MIN, FLT_MIN,
584 -FLT_MAX, FLT_MAX,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000585#ifdef FLT_TRUE_MIN
586 -FLT_TRUE_MIN, FLT_TRUE_MIN,
587#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700588 INFINITY, -INFINITY, NAN
589 };
590 ssize_t float_set_size = NativeReal__float_size(td);
591 const size_t n_doubles = sizeof(double_values) / sizeof(double_values[0]);
592 const size_t n_floats = sizeof(float_values) / sizeof(float_values[0]);
Lev Walkina5972be2017-09-29 23:15:58 -0700593 double d;
594
Lev Walkina5972be2017-09-29 23:15:58 -0700595 (void)constraints;
596
597 if(max_length == 0) return result_skipped;
598
Lev Walkin68079d32017-10-08 15:41:20 -0700599 if(float_set_size == sizeof(double) && asn_random_between(0, 1) == 0) {
600 d = double_values[asn_random_between(0, n_doubles - 1)];
601 } else {
602 d = float_values[asn_random_between(0, n_floats - 1)];
603 }
Lev Walkina5972be2017-09-29 23:15:58 -0700604
Lev Walkin68079d32017-10-08 15:41:20 -0700605 if(NativeReal__set(td, sptr, d) < 0) {
606 return result_failed;
607 }
Lev Walkina5972be2017-09-29 23:15:58 -0700608
Lev Walkincb5e1c72017-10-04 22:23:08 -0700609 result_ok.length = float_set_size;
Lev Walkina5972be2017-09-29 23:15:58 -0700610 return result_ok;
611}
Lev Walkinafcc8912017-10-04 23:48:35 -0700612
613
614/*
615 * Local helper functions.
616 */
617
Lev Walkin68079d32017-10-08 15:41:20 -0700618static size_t
619NativeReal__float_size(const asn_TYPE_descriptor_t *td) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700620 const asn_NativeReal_specifics_t *specs =
621 (const asn_NativeReal_specifics_t *)td->specifics;
Lev Walkin68079d32017-10-08 15:41:20 -0700622 return specs ? specs->float_size : sizeof(double);
623}
624
625static double
626NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
627 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700628 if(float_size == sizeof(float)) {
629 return *(const float *)ptr;
630 } else {
631 return *(const double *)ptr;
632 }
633}
634
635static ssize_t /* Returns -1 or float size. */
636NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
Lev Walkin68079d32017-10-08 15:41:20 -0700637 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700638 void *native;
639
640 if(!(native = *sptr)) {
641 native = (*sptr = CALLOC(1, float_size));
642 if(!native) {
643 return -1;
644 }
645 }
646
647 if(float_size == sizeof(float)) {
Lev Walkin68079d32017-10-08 15:41:20 -0700648 if(asn_double2float(d, (float *)native)) {
649 return -1;
650 }
Lev Walkinafcc8912017-10-04 23:48:35 -0700651 } else {
652 *(double *)native = d;
653 }
654
655 return float_size;
656}
657
658/*
659 * Swap bytes from/to network, if local is little-endian.
660 * Unused endianness sections are likely removed at compile phase.
661 */
662static void
663NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
664 const uint8_t *src = srcp;
665 double test = -0.0;
666 int float_big_endian = *(const char *)&test != 0;
667 /* In lieu of static_assert(sizeof(double) == 8) */
668 static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
669 static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
670 /* In lieu of static_assert(sizeof(sizeof) == 4) */
671 static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
672 static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
673
674 switch(float_size) {
675 case sizeof(double):
676 assert(sizeof(double) == 8);
677 if(float_big_endian) {
678 dst[0] = src[0];
679 dst[1] = src[1];
680 dst[2] = src[2];
681 dst[3] = src[3];
682 dst[4] = src[4];
683 dst[5] = src[5];
684 dst[6] = src[6];
685 dst[7] = src[7];
686 } else {
687 dst[0] = src[7];
688 dst[1] = src[6];
689 dst[2] = src[5];
690 dst[3] = src[4];
691 dst[4] = src[3];
692 dst[5] = src[2];
693 dst[6] = src[1];
694 dst[7] = src[0];
695 }
696 return;
697 case sizeof(float):
698 assert(sizeof(float) == 4);
699 if(float_big_endian) {
700 dst[0] = src[0];
701 dst[1] = src[1];
702 dst[2] = src[2];
703 dst[3] = src[3];
704 } else {
705 dst[0] = src[3];
706 dst[1] = src[2];
707 dst[2] = src[1];
708 dst[3] = src[0];
709 }
710 return;
711 }
712}