blob: 7a0d82a74cfdf9dcb483a60efc3ec06a49dedc83 [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 Walkinafcc8912017-10-04 23:48:35 -070081static double NativeReal__get_double(const asn_TYPE_descriptor_t *td,
82 const void *ptr);
83static ssize_t NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr,
84 double d);
85static void NativeReal__network_swap(size_t float_size, const void *srcp,
86 uint8_t *dst);
Lev Walkincb5e1c72017-10-04 22:23:08 -070087
Lev Walkin41ba1f22004-09-14 12:46:35 +000088/*
89 * Decode REAL type.
90 */
Lev Walkindc06f6b2004-10-20 15:50:55 +000091asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070092NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkinb5450702017-10-04 02:52:57 -070093 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkinab1d1e12017-10-03 18:43:12 -070094 const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinab1d1e12017-10-03 18:43:12 -070095 asn_dec_rval_t rval;
96 ber_tlv_len_t length;
Lev Walkin41ba1f22004-09-14 12:46:35 +000097
Lev Walkinab1d1e12017-10-03 18:43:12 -070098 ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
Lev Walkin41ba1f22004-09-14 12:46:35 +000099
Lev Walkinab1d1e12017-10-03 18:43:12 -0700100 /*
101 * Check tags.
102 */
103 rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
104 &length, 0);
105 if(rval.code != RC_OK) return rval;
Lev Walkin4ca41492017-10-03 20:29:54 -0700106 assert(length >= 0); /* Ensured by ber_check_tags */
Lev Walkin41ba1f22004-09-14 12:46:35 +0000107
Lev Walkinab1d1e12017-10-03 18:43:12 -0700108 ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000109
Lev Walkinab1d1e12017-10-03 18:43:12 -0700110 /*
111 * Make sure we have this length.
112 */
113 buf_ptr = ((const char *)buf_ptr) + rval.consumed;
114 size -= rval.consumed;
115 if(length > (ber_tlv_len_t)size) {
116 rval.code = RC_WMORE;
117 rval.consumed = 0;
118 return rval;
119 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000120
Lev Walkinab1d1e12017-10-03 18:43:12 -0700121 /*
122 * ASN.1 encoded REAL: buf_ptr, length
123 * Fill the Dbl, at the same time checking for overflow.
124 * If overflow occured, return with RC_FAIL.
125 */
126 {
127 uint8_t scratch[24]; /* Longer than %.16f in decimal */
128 REAL_t tmp;
129 double d;
130 int ret;
Lev Walkin7e033b52005-07-02 08:19:17 +0000131
Lev Walkin4ca41492017-10-03 20:29:54 -0700132 if((size_t)length < sizeof(scratch)) {
Lev Walkinab1d1e12017-10-03 18:43:12 -0700133 tmp.buf = scratch;
134 tmp.size = length;
135 } else {
136 /* This rarely happens: impractically long value */
137 tmp.buf = CALLOC(1, length + 1);
138 tmp.size = length;
139 if(!tmp.buf) {
140 rval.code = RC_FAIL;
141 rval.consumed = 0;
142 return rval;
143 }
144 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000145
Lev Walkinab1d1e12017-10-03 18:43:12 -0700146 memcpy(tmp.buf, buf_ptr, length);
147 tmp.buf[length] = '\0';
Lev Walkin41ba1f22004-09-14 12:46:35 +0000148
Lev Walkinab1d1e12017-10-03 18:43:12 -0700149 ret = asn_REAL2double(&tmp, &d);
150 if(tmp.buf != scratch) FREEMEM(tmp.buf);
151 if(ret) {
152 rval.code = RC_FAIL;
153 rval.consumed = 0;
154 return rval;
155 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000156
Lev Walkincb5e1c72017-10-04 22:23:08 -0700157 if(NativeReal__set(td, sptr, d) < 0)
158 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700159 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000160
Lev Walkinab1d1e12017-10-03 18:43:12 -0700161 rval.code = RC_OK;
162 rval.consumed += length;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000163
Lev Walkinb5450702017-10-04 02:52:57 -0700164 ASN_DEBUG("Took %ld/%ld bytes to encode %s", (long)rval.consumed,
165 (long)length, td->name);
Lev Walkinab1d1e12017-10-03 18:43:12 -0700166
167 return rval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000168}
169
170/*
171 * Encode the NativeReal using the standard REAL type DER encoder.
172 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000173asn_enc_rval_t
Lev Walkincb5e1c72017-10-04 22:23:08 -0700174NativeReal_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin41ba1f22004-09-14 12:46:35 +0000175 int tag_mode, ber_tlv_tag_t tag,
176 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700177 double d = NativeReal__get_double(td, sptr);
Lev Walkinb5450702017-10-04 02:52:57 -0700178 asn_enc_rval_t erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000179 REAL_t tmp;
180
Lev Walkina8bbbda2005-02-06 04:29:03 +0000181 /* Prepare a temporary clean structure */
182 memset(&tmp, 0, sizeof(tmp));
183
Lev Walkincb5e1c72017-10-04 22:23:08 -0700184 if(asn_double2REAL(&tmp, d))
185 ASN__ENCODE_FAILED;
186
187 /* Encode a fake REAL */
188 erval = der_encode_primitive(td, &tmp, tag_mode, tag, cb, app_key);
189 if(erval.encoded == -1) {
Lev Walkin41ba1f22004-09-14 12:46:35 +0000190 assert(erval.structure_ptr == &tmp);
Lev Walkincb5e1c72017-10-04 22:23:08 -0700191 erval.structure_ptr = sptr;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000192 }
Lev Walkina8bbbda2005-02-06 04:29:03 +0000193
194 /* Free possibly allocated members of the temporary structure */
Lev Walkincb5e1c72017-10-04 22:23:08 -0700195 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkina8bbbda2005-02-06 04:29:03 +0000196
Lev Walkincb5e1c72017-10-04 22:23:08 -0700197 return erval;
Lev Walkin41ba1f22004-09-14 12:46:35 +0000198}
199
Lev Walkin41d972b2017-08-23 23:30:59 -0700200#ifndef ASN_DISABLE_PER_SUPPORT
201
Lev Walkin725883b2006-10-09 12:07:58 +0000202/*
203 * Decode REAL type using PER.
204 */
205asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700206NativeReal_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin494fb702017-08-07 20:07:00 -0700207 asn_TYPE_descriptor_t *td,
Lev Walkinb5450702017-10-04 02:52:57 -0700208 const asn_per_constraints_t *constraints, void **sptr,
Lev Walkin494fb702017-08-07 20:07:00 -0700209 asn_per_data_t *pd) {
Lev Walkin725883b2006-10-09 12:07:58 +0000210 asn_dec_rval_t rval;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700211 double d;
Lev Walkin725883b2006-10-09 12:07:58 +0000212 REAL_t tmp;
213 void *ptmp = &tmp;
214 int ret;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000215
Lev Walkin725883b2006-10-09 12:07:58 +0000216 (void)constraints;
217
Lev Walkin725883b2006-10-09 12:07:58 +0000218 memset(&tmp, 0, sizeof(tmp));
Lev Walkinb5450702017-10-04 02:52:57 -0700219 rval = OCTET_STRING_decode_uper(opt_codec_ctx, &asn_DEF_REAL,
220 NULL, &ptmp, pd);
221 if(rval.code != RC_OK) {
Lev Walkin725883b2006-10-09 12:07:58 +0000222 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
223 return rval;
224 }
225
Lev Walkinb5450702017-10-04 02:52:57 -0700226 ret = asn_REAL2double(&tmp, &d);
Lev Walkin725883b2006-10-09 12:07:58 +0000227 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700228 if(ret) ASN__DECODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000229
Lev Walkincb5e1c72017-10-04 22:23:08 -0700230 if(NativeReal__set(td, sptr, d) < 0 )
231 ASN__DECODE_FAILED;
Lev Walkinb5450702017-10-04 02:52:57 -0700232
Lev Walkin725883b2006-10-09 12:07:58 +0000233 return rval;
234}
235
236/*
237 * Encode the NativeReal using the OCTET STRING PER encoder.
238 */
239asn_enc_rval_t
240NativeReal_encode_uper(asn_TYPE_descriptor_t *td,
Lev Walkin494fb702017-08-07 20:07:00 -0700241 const asn_per_constraints_t *constraints, void *sptr,
242 asn_per_outp_t *po) {
Lev Walkinb5450702017-10-04 02:52:57 -0700243 double d = NativeReal__get_double(td, sptr);
Lev Walkin725883b2006-10-09 12:07:58 +0000244 asn_enc_rval_t erval;
245 REAL_t tmp;
246
247 (void)constraints;
248
249 /* Prepare a temporary clean structure */
250 memset(&tmp, 0, sizeof(tmp));
251
Lev Walkinb5450702017-10-04 02:52:57 -0700252 if(asn_double2REAL(&tmp, d))
Lev Walkin7c1dc052016-03-14 03:08:15 -0700253 ASN__ENCODE_FAILED;
Lev Walkin725883b2006-10-09 12:07:58 +0000254
255 /* Encode a DER REAL */
Lev Walkinb5450702017-10-04 02:52:57 -0700256 erval = OCTET_STRING_encode_uper(&asn_DEF_REAL, NULL, &tmp, po);
257 if(erval.encoded == -1)
Lev Walkin725883b2006-10-09 12:07:58 +0000258 erval.structure_ptr = sptr;
259
260 /* Free possibly allocated members of the temporary structure */
261 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
262
263 return erval;
264}
Lev Walkin8471cec2004-10-21 14:02:19 +0000265
Lev Walkin41d972b2017-08-23 23:30:59 -0700266#endif /* ASN_DISABLE_PER_SUPPORT */
267
Lev Walkinab1d1e12017-10-03 18:43:12 -0700268#ifndef ASN_DISABLE_OER_SUPPORT
269
270/*
271 * Encode as Canonical OER.
272 */
273asn_enc_rval_t
274NativeReal_encode_oer(asn_TYPE_descriptor_t *td,
275 const asn_oer_constraints_t *constraints, void *sptr,
276 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinafcc8912017-10-04 23:48:35 -0700277 asn_enc_rval_t er = {0, 0, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700278
Lev Walkinafcc8912017-10-04 23:48:35 -0700279 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
280 if(constraints && constraints->value.width != 0) {
281 /* X.696 IEEE 754 binary32 and binary64 encoding */
282 uint8_t scratch[sizeof(double)];
283 const asn_NativeReal_specifics_t *specs =
284 (const asn_NativeReal_specifics_t *)td->specifics;
285 size_t wire_size = constraints->value.width;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700286
Lev Walkinafcc8912017-10-04 23:48:35 -0700287 if(specs ? (wire_size == specs->float_size)
288 : (wire_size == sizeof(double))) {
289 /*
290 * Our representation matches the wire, modulo endianness.
291 * That was the whole point of compact encoding!
292 */
293 } else {
294 assert(wire_size == sizeof(double)
295 || specs && specs->float_size == wire_size);
296 ASN__ENCODE_FAILED;
297 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700298
Lev Walkinafcc8912017-10-04 23:48:35 -0700299 /*
300 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
301 * So we assume the network format is big endian.
302 */
303 NativeReal__network_swap(wire_size, sptr, scratch);
304 if(cb(scratch, wire_size, app_key) < 0) {
305 ASN__ENCODE_FAILED;
306 } else {
307 er.encoded = wire_size;
308 ASN__ENCODED_OK(er);
309 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700310 } else {
Lev Walkinafcc8912017-10-04 23:48:35 -0700311 double d = NativeReal__get_double(td, sptr);
312 ssize_t len_len;
313 REAL_t tmp;
314
315 /* Prepare a temporary clean structure */
316 memset(&tmp, 0, sizeof(tmp));
317
318 if(asn_double2REAL(&tmp, d)) {
319 ASN__ENCODE_FAILED;
320 }
321
322 /* Encode a fake REAL */
323 len_len = oer_serialize_length(tmp.size, cb, app_key);
324 if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
325 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
326 ASN__ENCODE_FAILED;
327 } else {
328 er.encoded = len_len + tmp.size;
329 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
330 ASN__ENCODED_OK(er);
331 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700332 }
333}
334
335asn_dec_rval_t
336NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
337 asn_TYPE_descriptor_t *td,
338 const asn_oer_constraints_t *constraints, void **sptr,
339 const void *ptr, size_t size) {
340 asn_dec_rval_t ok = {RC_OK, 0};
Lev Walkinab1d1e12017-10-03 18:43:12 -0700341 double d;
342 ssize_t len_len;
343 size_t real_body_len;
344
345 (void)opt_codec_ctx;
Lev Walkinafcc8912017-10-04 23:48:35 -0700346
347 if(!constraints) constraints = td->encoding_constraints.oer_constraints;
348 if(constraints && constraints->value.width != 0) {
349 /* X.696 IEEE 754 binary32 and binary64 encoding */
350 uint8_t scratch[sizeof(double)];
351 size_t wire_size = constraints->value.width;
352
353 if(size < wire_size)
354 ASN__DECODE_STARVED;
355
356 /*
357 * The X.696 standard doesn't specify endianness, neither is IEEE 754.
358 * So we assume the network format is big endian.
359 */
360 NativeReal__network_swap(wire_size, ptr, scratch);
361
362 switch(wire_size) {
363 case sizeof(double):
364 if(NativeReal__set(td, sptr, *(const double *)scratch) < 0)
365 ASN__DECODE_FAILED;
366 break;
367 case sizeof(float):
368 if(NativeReal__set(td, sptr, *(const float *)scratch) < 0)
369 ASN__DECODE_FAILED;
370 break;
371 default:
372 ASN__DECODE_FAILED;
373 }
374
375 ok.consumed = wire_size;
376 return ok;
377 }
Lev Walkinab1d1e12017-10-03 18:43:12 -0700378
379 len_len = oer_fetch_length(ptr, size, &real_body_len);
380 if(len_len < 0) ASN__DECODE_FAILED;
381 if(len_len == 0) ASN__DECODE_STARVED;
382
383 ptr = (const char *)ptr + len_len;
384 size -= len_len;
385
386 if(real_body_len > size) ASN__DECODE_STARVED;
387
388 {
389 uint8_t scratch[24]; /* Longer than %.16f in decimal */
390 REAL_t tmp;
391 int ret;
392
393 if(real_body_len < sizeof(scratch)) {
394 tmp.buf = scratch;
395 tmp.size = real_body_len;
396 } else {
397 /* This rarely happens: impractically long value */
398 tmp.buf = CALLOC(1, real_body_len + 1);
399 tmp.size = real_body_len;
400 if(!tmp.buf) {
401 ASN__DECODE_FAILED;
402 }
403 }
404
405 memcpy(tmp.buf, ptr, real_body_len);
406 tmp.buf[real_body_len] = '\0';
407
408 ret = asn_REAL2double(&tmp, &d);
409 if(tmp.buf != scratch) FREEMEM(tmp.buf);
410 if(ret) {
411 ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
412 real_body_len);
413 ASN__DECODE_FAILED;
414 }
415 }
416
Lev Walkincb5e1c72017-10-04 22:23:08 -0700417 if(NativeReal__set(td, sptr, d) < 0)
418 ASN__DECODE_FAILED;
Lev Walkinab1d1e12017-10-03 18:43:12 -0700419
Lev Walkinab1d1e12017-10-03 18:43:12 -0700420 ok.consumed = len_len + real_body_len;
421 return ok;
422}
423
424#endif /* ASN_DISABLE_OER_SUPPORT */
425
Lev Walkin8471cec2004-10-21 14:02:19 +0000426/*
427 * Decode the chunk of XML text encoding REAL.
428 */
429asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700430NativeReal_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin8471cec2004-10-21 14:02:19 +0000431 asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000432 const void *buf_ptr, size_t size) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000433 asn_dec_rval_t rval;
Lev Walkinb5450702017-10-04 02:52:57 -0700434 REAL_t st = { 0, 0 };
435 REAL_t *stp = &st;
Lev Walkin8471cec2004-10-21 14:02:19 +0000436
Lev Walkinb5450702017-10-04 02:52:57 -0700437 rval = REAL_decode_xer(opt_codec_ctx, td, (void **)&stp, opt_mname,
Lev Walkin8471cec2004-10-21 14:02:19 +0000438 buf_ptr, size);
439 if(rval.code == RC_OK) {
Lev Walkinb5450702017-10-04 02:52:57 -0700440 double d;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700441 if(asn_REAL2double(&st, &d) || NativeReal__set(td, sptr, d) < 0) {
442 rval.code = RC_FAIL;
443 rval.consumed = 0;
Lev Walkinb5450702017-10-04 02:52:57 -0700444 }
Lev Walkin8471cec2004-10-21 14:02:19 +0000445 } else {
Lev Walkincb5e1c72017-10-04 22:23:08 -0700446 /* Convert all errors into RC_FAIL */
447 rval.consumed = 0;
Lev Walkin8471cec2004-10-21 14:02:19 +0000448 }
Lev Walkinb5450702017-10-04 02:52:57 -0700449 ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &st);
Lev Walkin8471cec2004-10-21 14:02:19 +0000450 return rval;
451}
452
Lev Walkina9cc46e2004-09-22 16:06:28 +0000453asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000454NativeReal_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000455 int ilevel, enum xer_encoder_flags_e flags,
456 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinb5450702017-10-04 02:52:57 -0700457 double d = NativeReal__get_double(td, sptr);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000458 asn_enc_rval_t er;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000459
460 (void)ilevel;
461
Lev Walkinb5450702017-10-04 02:52:57 -0700462 er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
463 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000464
Lev Walkin7c1dc052016-03-14 03:08:15 -0700465 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000466}
467
Lev Walkin41ba1f22004-09-14 12:46:35 +0000468/*
469 * REAL specific human-readable output.
470 */
471int
Lev Walkin5e033762004-09-29 13:26:15 +0000472NativeReal_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkin41ba1f22004-09-14 12:46:35 +0000473 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin41ba1f22004-09-14 12:46:35 +0000474
Lev Walkin41ba1f22004-09-14 12:46:35 +0000475 (void)ilevel; /* Unused argument */
476
Lev Walkinb5450702017-10-04 02:52:57 -0700477 if(sptr) {
478 double d = NativeReal__get_double(td, sptr);
479 return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
480 } else {
481 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
482 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000483}
484
Lev Walkincd2f48e2017-08-10 02:14:59 -0700485int
486NativeReal_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
487 const void *bptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700488
Lev Walkinb5450702017-10-04 02:52:57 -0700489 if(aptr && bptr) {
490 double a = NativeReal__get_double(td, aptr);
491 double b = NativeReal__get_double(td, bptr);
492
Lev Walkincd2f48e2017-08-10 02:14:59 -0700493 /* NaN sorted above everything else */
Lev Walkinb5450702017-10-04 02:52:57 -0700494 if(asn_isnan(a)) {
495 if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700496 return 0;
497 } else {
498 return -1;
499 }
Lev Walkinb5450702017-10-04 02:52:57 -0700500 } else if(asn_isnan(b)) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700501 return 1;
502 }
503 /* Value comparison. */
Lev Walkinb5450702017-10-04 02:52:57 -0700504 if(a < b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700505 return -1;
Lev Walkinb5450702017-10-04 02:52:57 -0700506 } else if(a > b) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700507 return 1;
508 } else {
509 return 0;
510 }
Lev Walkinb5450702017-10-04 02:52:57 -0700511 } else if(!aptr) {
Lev Walkincd2f48e2017-08-10 02:14:59 -0700512 return -1;
513 } else {
514 return 1;
515 }
516}
517
Lev Walkin41ba1f22004-09-14 12:46:35 +0000518void
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700519NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr,
520 enum asn_struct_free_method method) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700521 if(!td || !ptr)
Lev Walkin41ba1f22004-09-14 12:46:35 +0000522 return;
523
524 ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700525 td->name, method, ptr);
Lev Walkin41ba1f22004-09-14 12:46:35 +0000526
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700527 switch(method) {
528 case ASFM_FREE_EVERYTHING:
529 FREEMEM(ptr);
530 break;
531 case ASFM_FREE_UNDERLYING:
532 break;
Lev Walkincb5e1c72017-10-04 22:23:08 -0700533 case ASFM_FREE_UNDERLYING_AND_RESET: {
534 const asn_NativeReal_specifics_t *specs;
535 size_t float_size;
536 specs = (const asn_NativeReal_specifics_t *)td->specifics;
537 float_size = specs ? specs->float_size : sizeof(double);
538 memset(ptr, 0, float_size);
539 } break;
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700540 }
Lev Walkin41ba1f22004-09-14 12:46:35 +0000541}
542
Lev Walkina5972be2017-09-29 23:15:58 -0700543
544asn_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 Walkinab1d1e12017-10-03 18:43:12 -0700551 static const double values[] = {
552 0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
553 /* 2^51 */
554 -2251799813685248.0, 2251799813685248.0,
555 /* 2^52 */
556 -4503599627370496.0, 4503599627370496.0,
557 /* 2^100 */
558 -1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
Lev Walkin4ca41492017-10-03 20:29:54 -0700559#if __STDC_VERSION__ >= 199901L
Jon Ringle35c3f0d2017-10-04 21:54:39 -0400560 -FLT_MAX, FLT_MAX,
Lev Walkin43292722017-10-05 00:33:32 -0700561 -DBL_TRUE_MIN, DBL_TRUE_MIN,
Lev Walkin4ca41492017-10-03 20:29:54 -0700562#endif
563 INFINITY, -INFINITY, NAN};
Lev Walkincb5e1c72017-10-04 22:23:08 -0700564 ssize_t float_set_size;
Lev Walkina5972be2017-09-29 23:15:58 -0700565 double d;
566
Lev Walkina5972be2017-09-29 23:15:58 -0700567 (void)constraints;
568
569 if(max_length == 0) return result_skipped;
570
571 d = values[asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1)];
572
Lev Walkincb5e1c72017-10-04 22:23:08 -0700573 float_set_size = NativeReal__set(td, sptr, d);
574 if(float_set_size < 0) return result_failed;
Lev Walkina5972be2017-09-29 23:15:58 -0700575
Lev Walkincb5e1c72017-10-04 22:23:08 -0700576 result_ok.length = float_set_size;
Lev Walkina5972be2017-09-29 23:15:58 -0700577 return result_ok;
578}
Lev Walkinafcc8912017-10-04 23:48:35 -0700579
580
581/*
582 * Local helper functions.
583 */
584
585static double
586NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
587 const asn_NativeReal_specifics_t *specs =
588 (const asn_NativeReal_specifics_t *)td->specifics;
589 size_t float_size = specs ? specs->float_size : sizeof(double);
590 if(float_size == sizeof(float)) {
591 return *(const float *)ptr;
592 } else {
593 return *(const double *)ptr;
594 }
595}
596
597static ssize_t /* Returns -1 or float size. */
598NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
599 const asn_NativeReal_specifics_t *specs =
600 (const asn_NativeReal_specifics_t *)td->specifics;
601 size_t float_size = specs ? specs->float_size : sizeof(double);
602 void *native;
603
604 if(!(native = *sptr)) {
605 native = (*sptr = CALLOC(1, float_size));
606 if(!native) {
607 return -1;
608 }
609 }
610
611 if(float_size == sizeof(float)) {
612 *(float *)native = d;
613 } else {
614 *(double *)native = d;
615 }
616
617 return float_size;
618}
619
620/*
621 * Swap bytes from/to network, if local is little-endian.
622 * Unused endianness sections are likely removed at compile phase.
623 */
624static void
625NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
626 const uint8_t *src = srcp;
627 double test = -0.0;
628 int float_big_endian = *(const char *)&test != 0;
629 /* In lieu of static_assert(sizeof(double) == 8) */
630 static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
631 static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
632 /* In lieu of static_assert(sizeof(sizeof) == 4) */
633 static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
634 static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
635
636 switch(float_size) {
637 case sizeof(double):
638 assert(sizeof(double) == 8);
639 if(float_big_endian) {
640 dst[0] = src[0];
641 dst[1] = src[1];
642 dst[2] = src[2];
643 dst[3] = src[3];
644 dst[4] = src[4];
645 dst[5] = src[5];
646 dst[6] = src[6];
647 dst[7] = src[7];
648 } else {
649 dst[0] = src[7];
650 dst[1] = src[6];
651 dst[2] = src[5];
652 dst[3] = src[4];
653 dst[4] = src[3];
654 dst[5] = src[2];
655 dst[6] = src[1];
656 dst[7] = src[0];
657 }
658 return;
659 case sizeof(float):
660 assert(sizeof(float) == 4);
661 if(float_big_endian) {
662 dst[0] = src[0];
663 dst[1] = src[1];
664 dst[2] = src[2];
665 dst[3] = src[3];
666 } else {
667 dst[0] = src[3];
668 dst[1] = src[2];
669 dst[2] = src[1];
670 dst[3] = src[0];
671 }
672 return;
673 }
674}