blob: 448e1b1afb244a524c6deeb92aa9428f864b1715 [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);
Lev Walkincb5e1c72017-10-04 22:23:08 -070086
Lev Walkin41ba1f22004-09-14 12:46:35 +000087/*
88 * Decode REAL type.
89 */
Lev Walkindc06f6b2004-10-20 15:50:55 +000090asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070091NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -070092 const asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkinab1d1e12017-10-03 18:43:12 -070093 const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinab1d1e12017-10-03 18:43:12 -070094 asn_dec_rval_t rval;
95 ber_tlv_len_t length;
Lev Walkin41ba1f22004-09-14 12:46:35 +000096
Lev Walkinab1d1e12017-10-03 18:43:12 -070097 ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
Lev Walkin41ba1f22004-09-14 12:46:35 +000098
Lev Walkinab1d1e12017-10-03 18:43:12 -070099 /*
100 * Check tags.
101 */
102 rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
103 &length, 0);
104 if(rval.code != RC_OK) return rval;
Lev Walkin4ca41492017-10-03 20:29:54 -0700105 assert(length >= 0); /* Ensured by ber_check_tags */
Lev Walkin41ba1f22004-09-14 12:46:35 +0000106
Lev Walkinab1d1e12017-10-03 18:43:12 -0700107 ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000108
Lev Walkinab1d1e12017-10-03 18:43:12 -0700109 /*
110 * Make sure we have this length.
111 */
112 buf_ptr = ((const char *)buf_ptr) + rval.consumed;
113 size -= rval.consumed;
114 if(length > (ber_tlv_len_t)size) {
115 rval.code = RC_WMORE;
116 rval.consumed = 0;
117 return rval;
118 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000119
Lev Walkinab1d1e12017-10-03 18:43:12 -0700120 /*
121 * ASN.1 encoded REAL: buf_ptr, length
122 * Fill the Dbl, at the same time checking for overflow.
123 * If overflow occured, return with RC_FAIL.
124 */
125 {
126 uint8_t scratch[24]; /* Longer than %.16f in decimal */
127 REAL_t tmp;
128 double d;
129 int ret;
Lev Walkin7e033b52005-07-02 08:19:17 +0000130
Lev Walkin4ca41492017-10-03 20:29:54 -0700131 if((size_t)length < sizeof(scratch)) {
Lev Walkinab1d1e12017-10-03 18:43:12 -0700132 tmp.buf = scratch;
133 tmp.size = length;
134 } else {
135 /* This rarely happens: impractically long value */
136 tmp.buf = CALLOC(1, length + 1);
137 tmp.size = length;
138 if(!tmp.buf) {
139 rval.code = RC_FAIL;
140 rval.consumed = 0;
141 return rval;
142 }
143 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000144
Lev Walkinab1d1e12017-10-03 18:43:12 -0700145 memcpy(tmp.buf, buf_ptr, length);
146 tmp.buf[length] = '\0';
Lev Walkin41ba1f22004-09-14 12:46:35 +0000147
Lev Walkinab1d1e12017-10-03 18:43:12 -0700148 ret = asn_REAL2double(&tmp, &d);
149 if(tmp.buf != scratch) FREEMEM(tmp.buf);
150 if(ret) {
151 rval.code = RC_FAIL;
152 rval.consumed = 0;
153 return rval;
154 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000155
Lev Walkincb5e1c72017-10-04 22:23:08 -0700156 if(NativeReal__set(td, sptr, d) < 0)
157 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700158 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000159
Lev Walkinab1d1e12017-10-03 18:43:12 -0700160 rval.code = RC_OK;
161 rval.consumed += length;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000162
Lev Walkinb5450702017-10-04 02:52:57 -0700163 ASN_DEBUG("Took %ld/%ld bytes to encode %s", (long)rval.consumed,
164 (long)length, td->name);
Lev Walkinab1d1e12017-10-03 18:43:12 -0700165
166 return rval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000167}
168
169/*
170 * Encode the NativeReal using the standard REAL type DER encoder.
171 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000172asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700173NativeReal_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
174 int tag_mode, ber_tlv_tag_t tag,
175 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700176 double d = NativeReal__get_double(td, sptr);
Lev Walkinb5450702017-10-04 02:52:57 -0700177 asn_enc_rval_t erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000178 REAL_t tmp;
179
Lev Walkina8bbbda2005-02-06 04:29:03 +0000180 /* Prepare a temporary clean structure */
181 memset(&tmp, 0, sizeof(tmp));
182
Lev Walkincb5e1c72017-10-04 22:23:08 -0700183 if(asn_double2REAL(&tmp, d))
184 ASN__ENCODE_FAILED;
185
186 /* Encode a fake REAL */
187 erval = der_encode_primitive(td, &tmp, tag_mode, tag, cb, app_key);
188 if(erval.encoded == -1) {
Lev Walkin41ba1f22004-09-14 12:46:35 +0000189 assert(erval.structure_ptr == &tmp);
Lev Walkincb5e1c72017-10-04 22:23:08 -0700190 erval.structure_ptr = sptr;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000191 }
Lev Walkina8bbbda2005-02-06 04:29:03 +0000192
193 /* Free possibly allocated members of the temporary structure */
Lev Walkincb5e1c72017-10-04 22:23:08 -0700194 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkina8bbbda2005-02-06 04:29:03 +0000195
Lev Walkincb5e1c72017-10-04 22:23:08 -0700196 return erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000197}
198
Lev Walkin41d972b2017-08-23 23:30:59 -0700199#ifndef ASN_DISABLE_PER_SUPPORT
200
Lev Walkin725883b2006-10-09 12:07:58 +0000201/*
202 * Decode REAL type using PER.
203 */
204asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700205NativeReal_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700206 const asn_TYPE_descriptor_t *td,
Lev Walkinb5450702017-10-04 02:52:57 -0700207 const asn_per_constraints_t *constraints, void **sptr,
Lev Walkin494fb702017-08-07 20:07:00 -0700208 asn_per_data_t *pd) {
Lev Walkin20696a42017-10-17 21:27:33 -0700209 asn_dec_rval_t rval;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700210 double d;
Lev Walkin725883b2006-10-09 12:07:58 +0000211 REAL_t tmp;
212 void *ptmp = &tmp;
213 int ret;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000214
Lev Walkin725883b2006-10-09 12:07:58 +0000215 (void)constraints;
216
Lev Walkin725883b2006-10-09 12:07:58 +0000217 memset(&tmp, 0, sizeof(tmp));
Lev Walkinb5450702017-10-04 02:52:57 -0700218 rval = OCTET_STRING_decode_uper(opt_codec_ctx, &asn_DEF_REAL,
219 NULL, &ptmp, pd);
220 if(rval.code != RC_OK) {
Lev Walkin725883b2006-10-09 12:07:58 +0000221 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
222 return rval;
223 }
224
Lev Walkinb5450702017-10-04 02:52:57 -0700225 ret = asn_REAL2double(&tmp, &d);
Lev Walkin725883b2006-10-09 12:07:58 +0000226 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700227 if(ret) ASN__DECODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000228
Lev Walkincb5e1c72017-10-04 22:23:08 -0700229 if(NativeReal__set(td, sptr, d) < 0 )
230 ASN__DECODE_FAILED;
Lev Walkinb5450702017-10-04 02:52:57 -0700231
Lev Walkin725883b2006-10-09 12:07:58 +0000232 return rval;
233}
234
235/*
236 * Encode the NativeReal using the OCTET STRING PER encoder.
237 */
238asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700239NativeReal_encode_uper(const asn_TYPE_descriptor_t *td,
240 const asn_per_constraints_t *constraints,
241 const void *sptr, asn_per_outp_t *po) {
Lev Walkinb5450702017-10-04 02:52:57 -0700242 double d = NativeReal__get_double(td, sptr);
Lev Walkin725883b2006-10-09 12:07:58 +0000243 asn_enc_rval_t erval;
244 REAL_t tmp;
245
246 (void)constraints;
247
248 /* Prepare a temporary clean structure */
249 memset(&tmp, 0, sizeof(tmp));
250
Lev Walkinb5450702017-10-04 02:52:57 -0700251 if(asn_double2REAL(&tmp, d))
Lev Walkin7c1dc052016-03-14 03:08:15 -0700252 ASN__ENCODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000253
254 /* Encode a DER REAL */
Lev Walkinb5450702017-10-04 02:52:57 -0700255 erval = OCTET_STRING_encode_uper(&asn_DEF_REAL, NULL, &tmp, po);
256 if(erval.encoded == -1)
Lev Walkin725883b2006-10-09 12:07:58 +0000257 erval.structure_ptr = sptr;
258
259 /* Free possibly allocated members of the temporary structure */
260 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
261
262 return erval;
263}
Lev Walkin8471cec2004-10-21 14:02:19 +0000264
Lev Walkin41d972b2017-08-23 23:30:59 -0700265#endif /* ASN_DISABLE_PER_SUPPORT */
266
Lev Walkinab1d1e12017-10-03 18:43:12 -0700267#ifndef ASN_DISABLE_OER_SUPPORT
268
269/*
Lev Walkinbc09dd42017-10-19 02:16:35 -0700270 * Swap bytes from/to network, if local is little-endian.
271 * Unused endianness sections are likely removed at compile phase.
272 */
273static void
274NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
275 const uint8_t *src = srcp;
276 double test = -0.0;
277 int float_big_endian = *(const char *)&test != 0;
278 /* In lieu of static_assert(sizeof(double) == 8) */
279 static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
280 static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
281 /* In lieu of static_assert(sizeof(sizeof) == 4) */
282 static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
283 static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
284
285 switch(float_size) {
286 case sizeof(double):
287 assert(sizeof(double) == 8);
288 if(float_big_endian) {
289 dst[0] = src[0];
290 dst[1] = src[1];
291 dst[2] = src[2];
292 dst[3] = src[3];
293 dst[4] = src[4];
294 dst[5] = src[5];
295 dst[6] = src[6];
296 dst[7] = src[7];
297 } else {
298 dst[0] = src[7];
299 dst[1] = src[6];
300 dst[2] = src[5];
301 dst[3] = src[4];
302 dst[4] = src[3];
303 dst[5] = src[2];
304 dst[6] = src[1];
305 dst[7] = src[0];
306 }
307 return;
308 case sizeof(float):
309 assert(sizeof(float) == 4);
310 if(float_big_endian) {
311 dst[0] = src[0];
312 dst[1] = src[1];
313 dst[2] = src[2];
314 dst[3] = src[3];
315 } else {
316 dst[0] = src[3];
317 dst[1] = src[2];
318 dst[2] = src[1];
319 dst[3] = src[0];
320 }
321 return;
322 }
323}
324
325/*
Lev Walkinab1d1e12017-10-03 18:43:12 -0700326 * Encode as Canonical OER.
327 */
328asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700329NativeReal_encode_oer(const asn_TYPE_descriptor_t *td,
330 const asn_oer_constraints_t *constraints,
331 const void *sptr, asn_app_consume_bytes_f *cb,
332 void *app_key) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700333 asn_enc_rval_t er = {0, 0, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700334
Lev Walkinafcc8912017-10-04 23:48:35 -0700335 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
336 if(constraints && constraints->value.width != 0) {
337 /* X.696 IEEE 754 binary32 and binary64 encoding */
338 uint8_t scratch[sizeof(double)];
339 const asn_NativeReal_specifics_t *specs =
340 (const asn_NativeReal_specifics_t *)td->specifics;
341 size_t wire_size = constraints->value.width;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700342
Lev Walkinafcc8912017-10-04 23:48:35 -0700343 if(specs ? (wire_size == specs->float_size)
344 : (wire_size == sizeof(double))) {
345 /*
346 * Our representation matches the wire, modulo endianness.
347 * That was the whole point of compact encoding!
348 */
349 } else {
Lev Walkinfe374312017-10-07 00:24:51 -0700350 assert((wire_size == sizeof(double))
351 || (specs && specs->float_size == wire_size));
Lev Walkinafcc8912017-10-04 23:48:35 -0700352 ASN__ENCODE_FAILED;
353 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700354
Lev Walkinafcc8912017-10-04 23:48:35 -0700355 /*
356 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
357 * So we assume the network format is big endian.
358 */
359 NativeReal__network_swap(wire_size, sptr, scratch);
360 if(cb(scratch, wire_size, app_key) < 0) {
361 ASN__ENCODE_FAILED;
362 } else {
363 er.encoded = wire_size;
364 ASN__ENCODED_OK(er);
365 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700366 } else {
Lev Walkinafcc8912017-10-04 23:48:35 -0700367 double d = NativeReal__get_double(td, sptr);
368 ssize_t len_len;
369 REAL_t tmp;
370
371 /* Prepare a temporary clean structure */
372 memset(&tmp, 0, sizeof(tmp));
373
374 if(asn_double2REAL(&tmp, d)) {
375 ASN__ENCODE_FAILED;
376 }
377
378 /* Encode a fake REAL */
379 len_len = oer_serialize_length(tmp.size, cb, app_key);
380 if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
381 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
382 ASN__ENCODE_FAILED;
383 } else {
384 er.encoded = len_len + tmp.size;
385 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
386 ASN__ENCODED_OK(er);
387 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700388 }
389}
390
391asn_dec_rval_t
392NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700393 const asn_TYPE_descriptor_t *td,
394 const asn_oer_constraints_t *constraints, void **sptr,
395 const void *ptr, size_t size) {
Lev Walkinab1d1e12017-10-03 18:43:12 -0700396 asn_dec_rval_t ok = {RC_OK, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700397 double d;
398 ssize_t len_len;
399 size_t real_body_len;
400
401 (void)opt_codec_ctx;
Lev Walkinafcc8912017-10-04 23:48:35 -0700402
403 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
404 if(constraints && constraints->value.width != 0) {
405 /* X.696 IEEE 754 binary32 and binary64 encoding */
406 uint8_t scratch[sizeof(double)];
407 size_t wire_size = constraints->value.width;
408
409 if(size < wire_size)
410 ASN__DECODE_STARVED;
411
412 /*
413 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
414 * So we assume the network format is big endian.
415 */
416 NativeReal__network_swap(wire_size, ptr, scratch);
417
Vasil Velichkov39ab82f2017-10-18 20:33:57 +0300418
Lev Walkinafcc8912017-10-04 23:48:35 -0700419 switch(wire_size) {
Vasil Velichkov39ab82f2017-10-18 20:33:57 +0300420 case sizeof(double):
421 {
422 double tmp;
423 memcpy(&tmp, scratch, sizeof(double));
424 if(NativeReal__set(td, sptr, tmp) < 0)
425 ASN__DECODE_FAILED;
426 }
427 break;
428 case sizeof(float):
429 {
430 float tmp;
431 memcpy(&tmp, scratch, sizeof(float));
432 if(NativeReal__set(td, sptr, tmp) < 0)
433 ASN__DECODE_FAILED;
434 }
435 break;
Lev Walkinafcc8912017-10-04 23:48:35 -0700436 default:
437 ASN__DECODE_FAILED;
438 }
439
440 ok.consumed = wire_size;
441 return ok;
442 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700443
444 len_len = oer_fetch_length(ptr, size, &real_body_len);
445 if(len_len < 0) ASN__DECODE_FAILED;
446 if(len_len == 0) ASN__DECODE_STARVED;
447
448 ptr = (const char *)ptr + len_len;
449 size -= len_len;
450
451 if(real_body_len > size) ASN__DECODE_STARVED;
452
453 {
454 uint8_t scratch[24]; /* Longer than %.16f in decimal */
455 REAL_t tmp;
456 int ret;
457
458 if(real_body_len < sizeof(scratch)) {
459 tmp.buf = scratch;
460 tmp.size = real_body_len;
461 } else {
462 /* This rarely happens: impractically long value */
463 tmp.buf = CALLOC(1, real_body_len + 1);
464 tmp.size = real_body_len;
465 if(!tmp.buf) {
466 ASN__DECODE_FAILED;
467 }
468 }
469
470 memcpy(tmp.buf, ptr, real_body_len);
471 tmp.buf[real_body_len] = '\0';
472
473 ret = asn_REAL2double(&tmp, &d);
474 if(tmp.buf != scratch) FREEMEM(tmp.buf);
475 if(ret) {
476 ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
477 real_body_len);
478 ASN__DECODE_FAILED;
479 }
480 }
481
Lev Walkincb5e1c72017-10-04 22:23:08 -0700482 if(NativeReal__set(td, sptr, d) < 0)
483 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700484
Lev Walkinab1d1e12017-10-03 18:43:12 -0700485 ok.consumed = len_len + real_body_len;
486 return ok;
487}
488
489#endif /* ASN_DISABLE_OER_SUPPORT */
490
Lev Walkin8471cec2004-10-21 14:02:19 +0000491/*
492 * Decode the chunk of XML text encoding REAL.
493 */
494asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700495NativeReal_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700496 const asn_TYPE_descriptor_t *td, void **sptr,
497 const char *opt_mname, const void *buf_ptr, size_t size) {
498 asn_dec_rval_t rval;
Lev Walkinb5450702017-10-04 02:52:57 -0700499 REAL_t st = { 0, 0 };
500 REAL_t *stp = &st;
Lev Walkin8471cec2004-10-21 14:02:19 +0000501
Lev Walkinb5450702017-10-04 02:52:57 -0700502 rval = REAL_decode_xer(opt_codec_ctx, td, (void **)&stp, opt_mname,
Lev Walkin8471cec2004-10-21 14:02:19 +0000503 buf_ptr, size);
504 if(rval.code == RC_OK) {
Lev Walkinb5450702017-10-04 02:52:57 -0700505 double d;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700506 if(asn_REAL2double(&st, &d) || NativeReal__set(td, sptr, d) < 0) {
507 rval.code = RC_FAIL;
508 rval.consumed = 0;
Lev Walkinb5450702017-10-04 02:52:57 -0700509 }
Lev Walkin8471cec2004-10-21 14:02:19 +0000510 } else {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700511 /* Convert all errors into RC_FAIL */
512 rval.consumed = 0;
Lev Walkin8471cec2004-10-21 14:02:19 +0000513 }
Lev Walkinb5450702017-10-04 02:52:57 -0700514 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &st);
Lev Walkin8471cec2004-10-21 14:02:19 +0000515 return rval;
516}
517
Lev Walkina9cc46e2004-09-22 16:06:28 +0000518asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700519NativeReal_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
520 int ilevel, enum xer_encoder_flags_e flags,
521 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinb5450702017-10-04 02:52:57 -0700522 double d = NativeReal__get_double(td, sptr);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000523 asn_enc_rval_t er;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000524
525 (void)ilevel;
526
Lev Walkinb5450702017-10-04 02:52:57 -0700527 er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
528 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000529
Lev Walkin7c1dc052016-03-14 03:08:15 -0700530 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000531}
532
Lev Walkin41ba1f22004-09-14 12:46:35 +0000533/*
534 * REAL specific human-readable output.
535 */
536int
Lev Walkin20696a42017-10-17 21:27:33 -0700537NativeReal_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
538 asn_app_consume_bytes_f *cb, void *app_key) {
539 (void)ilevel; /* Unused argument */
Lev Walkin41ba1f22004-09-14 12:46:35 +0000540
Lev Walkinb5450702017-10-04 02:52:57 -0700541 if(sptr) {
542 double d = NativeReal__get_double(td, sptr);
543 return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
544 } else {
545 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
546 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000547}
548
Lev Walkincd2f48e2017-08-10 02:14:59 -0700549int
550NativeReal_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
551 const void *bptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700552
Lev Walkinb5450702017-10-04 02:52:57 -0700553 if(aptr && bptr) {
554 double a = NativeReal__get_double(td, aptr);
555 double b = NativeReal__get_double(td, bptr);
556
Lev Walkincd2f48e2017-08-10 02:14:59 -0700557 /* NaN sorted above everything else */
Lev Walkinb5450702017-10-04 02:52:57 -0700558 if(asn_isnan(a)) {
559 if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700560 return 0;
561 } else {
562 return -1;
563 }
Lev Walkinb5450702017-10-04 02:52:57 -0700564 } else if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700565 return 1;
566 }
567 /* Value comparison. */
Lev Walkinb5450702017-10-04 02:52:57 -0700568 if(a < b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700569 return -1;
Lev Walkinb5450702017-10-04 02:52:57 -0700570 } else if(a > b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700571 return 1;
572 } else {
573 return 0;
574 }
Lev Walkinb5450702017-10-04 02:52:57 -0700575 } else if(!aptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700576 return -1;
577 } else {
578 return 1;
579 }
580}
581
Lev Walkin41ba1f22004-09-14 12:46:35 +0000582void
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700583NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr,
584 enum asn_struct_free_method method) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700585 if(!td || !ptr)
Lev Walkin41ba1f22004-09-14 12:46:35 +0000586 return;
587
588 ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700589 td->name, method, ptr);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000590
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700591 switch(method) {
592 case ASFM_FREE_EVERYTHING:
593 FREEMEM(ptr);
594 break;
595 case ASFM_FREE_UNDERLYING:
596 break;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700597 case ASFM_FREE_UNDERLYING_AND_RESET: {
598 const asn_NativeReal_specifics_t *specs;
599 size_t float_size;
600 specs = (const asn_NativeReal_specifics_t *)td->specifics;
601 float_size = specs ? specs->float_size : sizeof(double);
602 memset(ptr, 0, float_size);
603 } break;
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700604 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000605}
606
Lev Walkina5972be2017-09-29 23:15:58 -0700607asn_random_fill_result_t
608NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
609 const asn_encoding_constraints_t *constraints,
610 size_t max_length) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700611 asn_random_fill_result_t result_ok = {ARFILL_OK, 0};
Lev Walkina5972be2017-09-29 23:15:58 -0700612 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
613 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
Lev Walkinfe374312017-10-07 00:24:51 -0700614#ifndef INFINITY
615#define INFINITY (1.0/0.0)
616#endif
617#ifndef NAN
618#define NAN (0.0/0.0)
619#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700620 static const double double_values[] = {
621 -M_E, M_E, -M_PI, M_PI, /* Better precision than with floats */
622 -1E+308, 1E+308,
Lev Walkinab1d1e12017-10-03 18:43:12 -0700623 /* 2^51 */
624 -2251799813685248.0, 2251799813685248.0,
625 /* 2^52 */
626 -4503599627370496.0, 4503599627370496.0,
627 /* 2^100 */
628 -1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000629 -DBL_MIN, DBL_MIN,
630 -DBL_MAX, DBL_MAX,
Lev Walkin68079d32017-10-08 15:41:20 -0700631#ifdef DBL_TRUE_MIN
632 -DBL_TRUE_MIN, DBL_TRUE_MIN
633#endif
634 };
635 static const float float_values[] = {
636 0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
637 -FLT_MIN, FLT_MIN,
638 -FLT_MAX, FLT_MAX,
Lev Walkinad4c63d2017-10-05 18:07:15 +0000639#ifdef FLT_TRUE_MIN
640 -FLT_TRUE_MIN, FLT_TRUE_MIN,
641#endif
Lev Walkin68079d32017-10-08 15:41:20 -0700642 INFINITY, -INFINITY, NAN
643 };
644 ssize_t float_set_size = NativeReal__float_size(td);
645 const size_t n_doubles = sizeof(double_values) / sizeof(double_values[0]);
646 const size_t n_floats = sizeof(float_values) / sizeof(float_values[0]);
Lev Walkina5972be2017-09-29 23:15:58 -0700647 double d;
648
Lev Walkina5972be2017-09-29 23:15:58 -0700649 (void)constraints;
650
651 if(max_length == 0) return result_skipped;
652
Lev Walkin68079d32017-10-08 15:41:20 -0700653 if(float_set_size == sizeof(double) && asn_random_between(0, 1) == 0) {
654 d = double_values[asn_random_between(0, n_doubles - 1)];
655 } else {
656 d = float_values[asn_random_between(0, n_floats - 1)];
657 }
Lev Walkina5972be2017-09-29 23:15:58 -0700658
Lev Walkin68079d32017-10-08 15:41:20 -0700659 if(NativeReal__set(td, sptr, d) < 0) {
660 return result_failed;
661 }
Lev Walkina5972be2017-09-29 23:15:58 -0700662
Lev Walkincb5e1c72017-10-04 22:23:08 -0700663 result_ok.length = float_set_size;
Lev Walkina5972be2017-09-29 23:15:58 -0700664 return result_ok;
665}
Lev Walkinafcc8912017-10-04 23:48:35 -0700666
667
668/*
669 * Local helper functions.
670 */
671
Lev Walkin68079d32017-10-08 15:41:20 -0700672static size_t
673NativeReal__float_size(const asn_TYPE_descriptor_t *td) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700674 const asn_NativeReal_specifics_t *specs =
675 (const asn_NativeReal_specifics_t *)td->specifics;
Lev Walkin68079d32017-10-08 15:41:20 -0700676 return specs ? specs->float_size : sizeof(double);
677}
678
679static double
680NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
681 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700682 if(float_size == sizeof(float)) {
683 return *(const float *)ptr;
684 } else {
685 return *(const double *)ptr;
686 }
687}
688
689static ssize_t /* Returns -1 or float size. */
690NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
Lev Walkin68079d32017-10-08 15:41:20 -0700691 size_t float_size = NativeReal__float_size(td);
Lev Walkinafcc8912017-10-04 23:48:35 -0700692 void *native;
693
694 if(!(native = *sptr)) {
695 native = (*sptr = CALLOC(1, float_size));
696 if(!native) {
697 return -1;
698 }
699 }
700
701 if(float_size == sizeof(float)) {
Lev Walkin68079d32017-10-08 15:41:20 -0700702 if(asn_double2float(d, (float *)native)) {
703 return -1;
704 }
Lev Walkinafcc8912017-10-04 23:48:35 -0700705 } else {
706 *(double *)native = d;
707 }
708
709 return float_size;
710}
711