Lev Walkin | 4eceeba | 2007-07-23 06:48:26 +0000 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <assert.h> |
| 3 | #include <math.h> |
Lev Walkin | 8ca13c8 | 2016-01-24 22:40:00 -0800 | [diff] [blame] | 4 | #include <float.h> |
Lev Walkin | 4eceeba | 2007-07-23 06:48:26 +0000 | [diff] [blame] | 5 | |
Lev Walkin | 681f059 | 2016-03-14 04:21:26 -0700 | [diff] [blame] | 6 | /* C11 specifies DBL_TRUE_MIN, might not be immediately available. */ |
| 7 | #ifndef DBL_TRUE_MIN |
| 8 | #define DBL_TRUE_MIN 4.9406564584124654E-324 |
| 9 | #endif |
| 10 | |
Lev Walkin | 4eceeba | 2007-07-23 06:48:26 +0000 | [diff] [blame] | 11 | #include <REAL.h> |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 12 | |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 13 | static char reconstructed[2][512]; |
| 14 | static int reconstr_lens[2]; |
| 15 | |
| 16 | static int |
| 17 | callback(const void *buffer, size_t size, void *app_key) { |
| 18 | char *buf = reconstructed[app_key ? 1 : 0]; |
| 19 | int *len = &reconstr_lens[app_key ? 1 : 0]; |
| 20 | |
| 21 | if(*len + size >= sizeof(reconstructed[0])) |
| 22 | return -1; |
| 23 | |
| 24 | memcpy(buf + *len, buffer, size); |
| 25 | *len += size; |
| 26 | |
| 27 | return 0; |
| 28 | } |
| 29 | |
Lev Walkin | 833d275 | 2012-01-07 15:29:25 -0800 | [diff] [blame] | 30 | static char * |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 31 | d2s(double d, int canonical) { |
Lev Walkin | 833d275 | 2012-01-07 15:29:25 -0800 | [diff] [blame] | 32 | ssize_t s; |
| 33 | |
| 34 | reconstr_lens[canonical] = 0; |
| 35 | s = REAL__dump(d, canonical, callback, (void *)(ptrdiff_t)canonical); |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 36 | assert(s > 0 && (size_t)s < sizeof(reconstructed[canonical])); |
Lev Walkin | 833d275 | 2012-01-07 15:29:25 -0800 | [diff] [blame] | 37 | assert(s == reconstr_lens[canonical]); |
| 38 | reconstructed[canonical][s] = '\0'; // ASCIIZ |
| 39 | return reconstructed[canonical]; |
| 40 | } |
| 41 | |
| 42 | /* |
| 43 | * Verify that a string representation of a given floating point value |
| 44 | * is as given in the (sample) and (canonical_sample) arguments. |
| 45 | */ |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 46 | static void |
Lev Walkin | 9854e66 | 2017-10-04 03:18:06 -0700 | [diff] [blame] | 47 | check_str_representation(double d, const char *sample, |
| 48 | const char *canonical_sample, int lineno) { |
| 49 | char *s0, *s1; |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 50 | |
Lev Walkin | 9854e66 | 2017-10-04 03:18:06 -0700 | [diff] [blame] | 51 | s0 = d2s(d, 0); |
| 52 | s1 = d2s(d, 1); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 53 | |
Lev Walkin | 9854e66 | 2017-10-04 03:18:06 -0700 | [diff] [blame] | 54 | if(sample) { |
| 55 | printf("%03d: Checking %g->[\"%s\"] against [\"%s\"]%s\n", lineno, d, |
| 56 | s0, sample, canonical_sample ? " (canonical follows...)" : ""); |
| 57 | assert(!strcmp(s0, sample)); |
| 58 | } |
| 59 | if(canonical_sample) { |
| 60 | if(*s1 == '<') { |
| 61 | printf( |
| 62 | "%03d: Checking %g->[\"%s\"] against [\"%s\"] " |
| 63 | "(canonical)\n", |
| 64 | lineno, d, s1, canonical_sample); |
| 65 | assert(!strcmp(s1, canonical_sample)); |
| 66 | } else { |
| 67 | double reconstructed = strtod(s1, 0); |
| 68 | printf( |
| 69 | "%03d: Checking %g->[\"%s\"] against [\"%s\"]->%g " |
| 70 | "(canonical, 𝟄=%.17g %g)\n", |
| 71 | lineno, d, s1, canonical_sample, reconstructed, |
| 72 | fabs(reconstructed - d), 1e-52); |
| 73 | if(d != reconstructed) { |
| 74 | printf( |
| 75 | "WARNING: Difference in a small epsilon (given " |
| 76 | "%%.15g=%.15g, %%.17g=%.17g, %%.20g=%.20g, " |
| 77 | "reconstructed %%.15g=%.15g, %%.17g=%.17g, " |
| 78 | "%%.20g=%.20g)!\n", |
| 79 | d, d, d, reconstructed, reconstructed, reconstructed); |
| 80 | } |
| 81 | assert(fabs(d - reconstructed) < 1e-52); |
| 82 | } |
| 83 | } |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 84 | } |
| 85 | |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 86 | #define check(rn, d, str1, str2) \ |
| 87 | check_impl(rn, d, str1, str2, __LINE__) |
| 88 | |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 89 | static void |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 90 | check_impl(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sample, int lineno) { |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 91 | double val; |
| 92 | uint8_t *p, *end; |
| 93 | int ret; |
| 94 | |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 95 | printf("Line %d: double value %.12f [", lineno, orig_dbl); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 96 | for(p = (uint8_t *)&orig_dbl, end = p + sizeof(double); p < end ; p++) |
| 97 | printf("%02x", *p); |
| 98 | printf("] (ilogb %d)\n", ilogb(orig_dbl)); |
| 99 | |
| 100 | val = frexp(orig_dbl, &ret); |
| 101 | printf("frexp(%f, %d): [", val, ret); |
| 102 | for(p = (uint8_t *)&val, end = p + sizeof(double); p < end ; p++) |
| 103 | printf("%02x", *p); |
| 104 | printf("]\n"); |
| 105 | |
Lev Walkin | 5e03376 | 2004-09-29 13:26:15 +0000 | [diff] [blame] | 106 | ret = asn_double2REAL(rn, orig_dbl); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 107 | assert(ret == 0); |
| 108 | |
| 109 | printf("converted into ["); |
| 110 | for(p = rn->buf, end = p + rn->size; p < end; p++) |
| 111 | printf("%02x", *p); |
Lev Walkin | 494fb70 | 2017-08-07 20:07:00 -0700 | [diff] [blame] | 112 | printf("]: %zu\n", rn->size); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 113 | |
Lev Walkin | 5e03376 | 2004-09-29 13:26:15 +0000 | [diff] [blame] | 114 | ret = asn_REAL2double(rn, &val); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 115 | assert(ret == 0); |
| 116 | |
| 117 | printf("and back to double: ["); |
| 118 | for(p = (uint8_t *)&val, end = p + sizeof(double); p < end ; p++) |
| 119 | printf("%02x", *p); |
| 120 | printf("] (ilogb %d)\n", ilogb(val)); |
| 121 | |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 122 | printf("%.12f vs %.12f\n", val, orig_dbl); |
| 123 | assert((isnan(orig_dbl) && isnan(val)) || val == orig_dbl); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 124 | printf("OK\n"); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 125 | |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 126 | check_str_representation(val, sample, canonical_sample, lineno); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 127 | } |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 128 | static void |
| 129 | check_xer(int fuzzy, double orig_value) { |
| 130 | asn_enc_rval_t er; |
| 131 | asn_dec_rval_t rc; |
| 132 | REAL_t st; |
| 133 | REAL_t *newst0 = 0; |
| 134 | REAL_t *newst1 = 0; |
Lev Walkin | b191938 | 2006-07-27 11:46:25 +0000 | [diff] [blame] | 135 | REAL_t **newst0p = &newst0; |
| 136 | REAL_t **newst1p = &newst1; |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 137 | double value0, value1; |
| 138 | int ret; |
| 139 | |
| 140 | memset(&st, 0, sizeof(st)); |
| 141 | ret = asn_double2REAL(&st, orig_value); |
| 142 | assert(ret == 0); |
| 143 | |
| 144 | reconstr_lens[0] = 0; |
| 145 | reconstr_lens[1] = 0; |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 146 | er = xer_encode(&asn_DEF_REAL, &st, XER_F_BASIC, callback, 0); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 147 | assert(er.encoded == reconstr_lens[0]); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 148 | er = xer_encode(&asn_DEF_REAL, &st, XER_F_CANONICAL, callback, (void *)1); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 149 | assert(er.encoded == reconstr_lens[1]); |
| 150 | reconstructed[0][reconstr_lens[0]] = 0; |
| 151 | reconstructed[1][reconstr_lens[1]] = 0; |
| 152 | |
| 153 | printf("%f vs (%d)[%s] & (%d)%s", |
| 154 | orig_value, |
| 155 | reconstr_lens[1], reconstructed[1], |
| 156 | reconstr_lens[0], reconstructed[0] |
| 157 | ); |
| 158 | |
Lev Walkin | b191938 | 2006-07-27 11:46:25 +0000 | [diff] [blame] | 159 | rc = xer_decode(0, &asn_DEF_REAL, (void **)newst0p, |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 160 | reconstructed[0], reconstr_lens[0]); |
| 161 | assert(rc.code == RC_OK); |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 162 | assert(reconstr_lens[0] > 0 && rc.consumed < (size_t)reconstr_lens[0]); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 163 | |
Lev Walkin | b191938 | 2006-07-27 11:46:25 +0000 | [diff] [blame] | 164 | rc = xer_decode(0, &asn_DEF_REAL, (void **)newst1p, |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 165 | reconstructed[1], reconstr_lens[1]); |
| 166 | assert(rc.code == RC_OK); |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 167 | assert(rc.consumed == (size_t)reconstr_lens[1]); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 168 | |
| 169 | ret = asn_REAL2double(newst0, &value0); |
| 170 | assert(ret == 0); |
| 171 | ret = asn_REAL2double(newst1, &value1); |
| 172 | assert(ret == 0); |
| 173 | |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 174 | assert((isnan(value0) && isnan(orig_value)) |
| 175 | || value0 == orig_value |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 176 | || fuzzy); |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 177 | assert((isnan(value1) && isnan(orig_value)) |
| 178 | || value1 == orig_value); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 179 | |
| 180 | assert(newst0->size == st.size || fuzzy); |
| 181 | assert(newst1->size == st.size); |
| 182 | assert(fuzzy || memcmp(newst0->buf, st.buf, st.size) == 0); |
| 183 | assert(memcmp(newst1->buf, st.buf, st.size) == 0); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 184 | ASN_STRUCT_RESET(asn_DEF_REAL, &st); |
| 185 | ASN_STRUCT_FREE(asn_DEF_REAL, newst0); |
| 186 | ASN_STRUCT_FREE(asn_DEF_REAL, newst1); |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 187 | } |
| 188 | |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 189 | static void |
Lev Walkin | 53e5ae6 | 2017-08-23 10:56:19 -0700 | [diff] [blame] | 190 | check_ber_buffer_twoway(double d, const char *sample, const char *canonical_sample, const uint8_t *inbuf, size_t insize, uint8_t *outbuf, size_t outsize, int lineno) { |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 191 | REAL_t rn; |
| 192 | double val; |
| 193 | int ret; |
| 194 | |
| 195 | /* |
| 196 | * Decode our expected buffer and check that it matches the given (d). |
| 197 | */ |
Lev Walkin | 53e5ae6 | 2017-08-23 10:56:19 -0700 | [diff] [blame] | 198 | rn.buf = calloc(1, insize + 1); /* By convention, buffers have extra \0 */ |
| 199 | assert(rn.buf); |
| 200 | memcpy(rn.buf, inbuf, insize); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 201 | rn.size = insize; |
| 202 | asn_REAL2double(&rn, &val); |
| 203 | if(isnan(val)) assert(isnan(d)); |
| 204 | if(isnan(d)) assert(isnan(val)); |
| 205 | if(!isnan(val) && !isnan(d)) { |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 206 | assert(copysign(1.0, d) == copysign(1.0, val)); |
| 207 | assert(d == val); |
| 208 | } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 209 | |
| 210 | /* |
| 211 | * Encode value and check that it matches our expected buffer. |
| 212 | */ |
Lev Walkin | 53e5ae6 | 2017-08-23 10:56:19 -0700 | [diff] [blame] | 213 | free(rn.buf); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 214 | memset(&rn, 0, sizeof(rn)); |
| 215 | ret = asn_double2REAL(&rn, d); |
| 216 | assert(ret == 0); |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 217 | if((size_t)rn.size != outsize) { |
Lev Walkin | 6cbed3d | 2017-10-07 16:42:41 -0700 | [diff] [blame^] | 218 | printf("Encoded %f into %d expected %zd\n", |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 219 | d, (int)rn.size, outsize); |
Lev Walkin | 9736348 | 2016-01-24 19:23:02 -0800 | [diff] [blame] | 220 | assert((size_t)rn.size == outsize); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 221 | } |
| 222 | assert(memcmp(rn.buf, outbuf, rn.size) == 0); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 223 | ASN_STRUCT_RESET(asn_DEF_REAL, &rn); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 224 | |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 225 | check_str_representation(d, sample, canonical_sample, lineno); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | static void |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 229 | check_ber_buffer_oneway(double d, const char *sample, const char *canonical_sample, uint8_t *buf, size_t bufsize, int lineno) { |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 230 | REAL_t rn0; |
| 231 | REAL_t rn1; |
| 232 | double val0; |
| 233 | double val1; |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 234 | uint8_t *p, *end; |
| 235 | int ret; |
| 236 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 237 | memset(&rn0, 0, sizeof(rn0)); |
| 238 | memset(&rn1, 0, sizeof(rn1)); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 239 | |
| 240 | printf("verify double value %.12f [", d); |
| 241 | for(p = (uint8_t *)&d, end = p + sizeof(double); p < end ; p++) |
| 242 | printf("%02x", *p); |
| 243 | printf("] (ilogb %d)\n", ilogb(d)); |
| 244 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 245 | ret = asn_double2REAL(&rn0, d); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 246 | assert(ret == 0); |
| 247 | |
| 248 | printf("canonical DER: ["); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 249 | for(p = rn0.buf, end = p + rn0.size; p < end; p++) |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 250 | printf("%02x", *p); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 251 | ret = asn_REAL2double(&rn0, &val0); |
| 252 | assert(ret == 0); |
| 253 | printf("] => %f\n", val0); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 254 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 255 | rn1.buf = buf; |
| 256 | rn1.size = bufsize; |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 257 | |
| 258 | printf("received as: ["); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 259 | for(p = rn1.buf, end = p + rn1.size; p < end; p++) |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 260 | printf("%02x", *p); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 261 | ret = asn_REAL2double(&rn1, &val1); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 262 | assert(ret == 0); |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 263 | printf("] => %f\n", val1); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 264 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 265 | printf("%.12f vs %.12f vs %.12f\n", d, val0, val1); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 266 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 267 | assert(val0 == d); |
| 268 | assert(val1 == d); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 269 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 270 | ASN_STRUCT_RESET(asn_DEF_REAL, &rn0); |
| 271 | |
| 272 | check_str_representation(val1, sample, canonical_sample, lineno); |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 273 | } |
| 274 | |
Lev Walkin | e8727ec | 2012-01-09 05:46:16 -0800 | [diff] [blame] | 275 | /* |
| 276 | * 8.5.7 Verify binary encoding, two-way. |
| 277 | */ |
| 278 | static void |
| 279 | check_ber_857_encoding(int base, int sign, int scaling_factor, int exponent, int mantissa) { |
| 280 | uint8_t buf[100]; |
| 281 | uint8_t *b = buf; |
| 282 | int explen, mantlen; |
| 283 | REAL_t rn; |
| 284 | static REAL_t rn_check; |
| 285 | double d; |
| 286 | double verify; |
| 287 | int baseF = 0; |
| 288 | int ret; |
| 289 | |
| 290 | #define BIT(b) (1<<(b - 1)) |
| 291 | |
| 292 | switch(base) { |
| 293 | case 0: baseF = 1; break; |
| 294 | case 1: baseF = 3; break; |
| 295 | case 2: baseF = 4; break; |
| 296 | default: assert(base >= 0 && base <= 2); |
| 297 | } |
| 298 | |
| 299 | if(exponent >= -128 && exponent <= 127) { |
| 300 | explen = 1; |
| 301 | } else { |
| 302 | assert(exponent > -60000 && exponent < 60000); |
| 303 | explen = 2; |
| 304 | } |
| 305 | |
| 306 | if(mantissa == 0) { |
| 307 | mantlen = 0; |
| 308 | } else if(mantissa >= 0 && mantissa <= 255) { |
| 309 | mantlen = 1; |
| 310 | } else if(mantissa >= 0 && mantissa <= 65535) { |
| 311 | mantlen = 2; |
| 312 | } else { |
| 313 | assert(mantissa >= 0 && mantissa <= 256 * 65536); |
| 314 | mantlen = 3; |
| 315 | } |
| 316 | |
| 317 | *b = BIT(8) | (sign ? BIT(7) : 0); |
| 318 | *b |= (base & 0x03) << 4; /* 8.5.7.2 */ |
| 319 | *b |= (scaling_factor & 0x03) << 2; /* 8.5.7.3 */ |
| 320 | *b |= ((explen - 1) & 0x03); /* 8.5.7.4 */ |
| 321 | b++; |
| 322 | switch(explen) { |
| 323 | case 2: *b++ = (int8_t)(exponent >> 8); |
| 324 | case 1: *b++ = (int8_t)exponent; |
| 325 | } |
| 326 | switch(mantlen) { |
| 327 | case 3: *b++ = (mantissa >> 16) & 0xff; |
| 328 | case 2: *b++ = (mantissa >> 8) & 0xff; |
| 329 | case 1: *b++ = (mantissa & 0xff); |
| 330 | } |
| 331 | |
| 332 | verify = (sign ? -1.0 : 1.0) * ldexp(mantissa, exponent * baseF + scaling_factor); |
| 333 | |
| 334 | /* Verify than encoding of this double value round-trips */ |
| 335 | if(!isinf(verify)) { |
| 336 | d = verify; |
| 337 | verify = 0.0; |
| 338 | ret = asn_double2REAL(&rn_check, d); |
| 339 | assert(ret == 0); |
| 340 | ret = asn_REAL2double(&rn_check, &verify); |
| 341 | assert(ret == 0); |
| 342 | assert(d == verify); |
| 343 | |
| 344 | /* Verify with a slight non-friendly offset. Not too easy. */ |
| 345 | d = verify - 0.13; |
| 346 | verify = 0.0; |
| 347 | ret = asn_double2REAL(&rn_check, d); |
| 348 | assert(ret == 0); |
| 349 | ret = asn_REAL2double(&rn_check, &verify); |
| 350 | assert(ret == 0); |
| 351 | assert(ret == 0); |
| 352 | assert(d == verify); |
| 353 | } |
| 354 | |
| 355 | verify = (sign ? -1.0 : 1.0) * ldexp(mantissa, exponent * baseF + scaling_factor); |
| 356 | |
| 357 | rn.buf = buf; |
| 358 | rn.size = b - buf; |
| 359 | ret = asn_REAL2double(&rn, &d); |
| 360 | if(!isinf(verify) && (ret != 0 || d != verify)) { |
| 361 | printf("Converting B=%d, S=%d, F=%d, E=%d/%d, M=%d/%d\n", (1 << baseF), sign, scaling_factor, exponent, explen, mantissa, mantlen); |
| 362 | printf("Verify: %e\n", verify); |
| 363 | uint8_t *p; |
| 364 | printf("received as: ["); |
| 365 | for(p = buf; p < b; p++) printf("%02x", *p); |
| 366 | printf("]\n"); |
| 367 | assert(ret == 0); |
| 368 | printf("Converted: %e\n", d); |
| 369 | assert(d == verify); |
| 370 | } |
| 371 | } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 372 | |
| 373 | static void |
| 374 | check_ber_encoding() { |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 375 | #define CHECK_BER_STRICT(v, nocan, can, inbuf, outbuf) \ |
| 376 | check_ber_buffer_twoway(v, nocan, can, inbuf, sizeof(inbuf), \ |
| 377 | outbuf, sizeof(outbuf), __LINE__) |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 378 | |
| 379 | #define CHECK_BER_NONSTRICT(v, nocan, can, buf) \ |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 380 | check_ber_buffer_oneway(v, nocan, can, buf, sizeof(buf), __LINE__) |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 381 | |
| 382 | /* |
| 383 | * X.690 8.4 Encoding of an enumerated value. |
| 384 | */ |
| 385 | |
| 386 | /* 8.5.2 If the real value is the value plus zero, |
| 387 | * there shall be no contents octet in the encoding */ |
| 388 | { uint8_t b_0[] = {}; |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 389 | CHECK_BER_STRICT(0.0, "0", "0", b_0, b_0); } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 390 | |
| 391 | /* 8.5.3 When -0 is to be encoded, there shall be only one contents octet */ |
| 392 | { uint8_t b_m0[] = { 0x43 }; |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 393 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0, b_m0); } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 394 | |
| 395 | /* Old way of encoding -0.0: 8.5.6 a) */ |
| 396 | { uint8_t b_m0[] = { 0x43 }; |
| 397 | uint8_t b_m0_856a[] = { 0xC0, 0x00 }; /* #8.5.6 a) */ |
| 398 | uint8_t b_m0_856a_1[] = { 0xC0, 0x00, 0x00 }; |
| 399 | uint8_t b_m0_856a_2[] = { 0xC0, 0x00, 0x00, 0x00 }; |
| 400 | uint8_t b_m0_856a_3[] = { 0xC0, 0x00, 0x00, 0x00, 0x00 }; |
| 401 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a, b_m0); |
| 402 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_1, b_m0); |
| 403 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_2, b_m0); |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 404 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_856a_3, b_m0); } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 405 | |
| 406 | /* 8.5.6 c) => 8.5.9 SpecialRealValue */ |
| 407 | { uint8_t b_pinf[] = { 0x40 }; |
| 408 | uint8_t b_minf[] = { 0x41 }; |
| 409 | uint8_t b_nan[] = { 0x42 }; |
Lev Walkin | 9c57f33 | 2017-09-17 22:30:49 -0700 | [diff] [blame] | 410 | CHECK_BER_STRICT(INFINITY, "<PLUS-INFINITY/>", "<PLUS-INFINITY/>", b_pinf, b_pinf); |
| 411 | CHECK_BER_STRICT(-INFINITY, "<MINUS-INFINITY/>", "<MINUS-INFINITY/>", b_minf, b_minf); |
| 412 | CHECK_BER_STRICT(NAN, "<NOT-A-NUMBER/>", "<NOT-A-NUMBER/>", b_nan, b_nan); } |
Lev Walkin | 5fda7d5 | 2012-01-09 03:20:19 -0800 | [diff] [blame] | 413 | |
| 414 | /* 8.5.6 b) => 8.5.8 Decimal encoding is used; NR1 form */ |
| 415 | { uint8_t b_0_nr1[] = { 0x01, '0' }; |
| 416 | uint8_t b_0[] = { }; |
| 417 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr1, b_0); } |
| 418 | { uint8_t b_0_nr1[] = { 0x01, '0', '0' }; |
| 419 | uint8_t b_0[] = { }; |
| 420 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr1, b_0); } |
| 421 | { uint8_t b_0_nr1[] = { 0x01, ' ', '0' }; |
| 422 | uint8_t b_0[] = { }; |
| 423 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr1, b_0); } |
| 424 | { uint8_t b_p0_nr1[] = { 0x01, '+', '0' }; |
| 425 | uint8_t b_0[] = { }; |
| 426 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr1, b_0); } |
| 427 | { uint8_t b_p0_nr1[] = { 0x01, ' ', '+', '0' }; |
| 428 | uint8_t b_0[] = { }; |
| 429 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr1, b_0); } |
| 430 | { uint8_t b_m0_nr1[] = { 0x01, '-', '0' }; |
| 431 | uint8_t b_m0[] = { 0x43 }; |
| 432 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr1, b_m0); } |
| 433 | { uint8_t b_m0_nr1[] = { 0x01, ' ', '-', '0' }; |
| 434 | uint8_t b_m0[] = { 0x43 }; |
| 435 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr1, b_m0); } |
| 436 | |
| 437 | { uint8_t b_1_nr1[] = { 0x01, '1' }; |
| 438 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 439 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr1, b_1); } |
| 440 | { uint8_t b_1_nr1[] = { 0x01, '0', '1' }; |
| 441 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 442 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr1, b_1); } |
| 443 | { uint8_t b_1_nr1[] = { 0x01, ' ', '1' }; |
| 444 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 445 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr1, b_1); } |
| 446 | { uint8_t b_p1_nr1[] = { 0x01, '+', '1' }; |
| 447 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 448 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_p1_nr1, b_1); } |
| 449 | { uint8_t b_p1_nr1[] = { 0x01, ' ', '+', '1' }; |
| 450 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 451 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_p1_nr1, b_1); } |
| 452 | { uint8_t b_m1_nr1[] = { 0x01, '-', '1' }; |
| 453 | uint8_t b_m1[] = { 0xC0, 0x00, 0x01 }; |
| 454 | CHECK_BER_STRICT(-1.0, "-1.0", "-1.0E0", b_m1_nr1, b_m1); } |
| 455 | { uint8_t b_m1_nr1[] = { 0x01, ' ', '-', '1' }; |
| 456 | uint8_t b_m1[] = { 0xC0, 0x00, 0x01 }; |
| 457 | CHECK_BER_STRICT(-1.0, "-1.0", "-1.0E0", b_m1_nr1, b_m1); } |
| 458 | |
| 459 | { |
| 460 | uint8_t comma_symbol[] = { '.', ',' }; |
| 461 | int csi; |
| 462 | for(csi = 0; csi < 2; csi++) { |
| 463 | uint8_t CS = comma_symbol[csi]; |
| 464 | |
| 465 | /* 8.5.6 b) => 8.5.8 Decimal encoding is used; NR2 form */ |
| 466 | { uint8_t b_0_nr2[] = { 0x02, '0', CS, '0' }; |
| 467 | uint8_t b_0[] = { }; |
| 468 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr2, b_0); } |
| 469 | { uint8_t b_0_nr2[] = { 0x02, '0', '0', CS, '0' }; |
| 470 | uint8_t b_0[] = { }; |
| 471 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr2, b_0); } |
| 472 | { uint8_t b_0_nr2[] = { 0x02, ' ', '0', CS, '0' }; |
| 473 | uint8_t b_0[] = { }; |
| 474 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr2, b_0); } |
| 475 | { uint8_t b_p0_nr2[] = { 0x02, '+', '0', CS, '0' }; |
| 476 | uint8_t b_0[] = { }; |
| 477 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr2, b_0); } |
| 478 | { uint8_t b_p0_nr2[] = { 0x02, ' ', '+', '0', CS, '0' }; |
| 479 | uint8_t b_0[] = { }; |
| 480 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr2, b_0); } |
| 481 | { uint8_t b_m0_nr2[] = { 0x02, '-', '0', CS, '0' }; |
| 482 | uint8_t b_m0[] = { 0x43 }; |
| 483 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr2, b_m0); } |
| 484 | { uint8_t b_m0_nr2[] = { 0x02, ' ', '-', '0', CS, '0' }; |
| 485 | uint8_t b_m0[] = { 0x43 }; |
| 486 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr2, b_m0); } |
| 487 | |
| 488 | /* 8.5.6 b) => 8.5.8 NR2 "1." */ |
| 489 | { uint8_t b_1_nr2[] = { 0x02, '1', CS }; |
| 490 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 491 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr2, b_1); } |
| 492 | { uint8_t b_1_nr2[] = { 0x02, '0', '1', CS }; |
| 493 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 494 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr2, b_1); } |
| 495 | { uint8_t b_1_nr2[] = { 0x02, ' ', '1', CS }; |
| 496 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 497 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_1_nr2, b_1); } |
| 498 | { uint8_t b_p1_nr2[] = { 0x02, '+', '1', CS }; |
| 499 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 500 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_p1_nr2, b_1); } |
| 501 | { uint8_t b_p1_nr2[] = { 0x02, ' ', '+', '1', CS }; |
| 502 | uint8_t b_1[] = { 0x80, 0x00, 0x01 }; |
| 503 | CHECK_BER_STRICT(1.0, "1.0", "1.0E0", b_p1_nr2, b_1); } |
| 504 | { uint8_t b_m1_nr2[] = { 0x02, '-', '1', CS }; |
| 505 | uint8_t b_m1[] = { 0xC0, 0x00, 0x01 }; |
| 506 | CHECK_BER_STRICT(-1.0, "-1.0", "-1.0E0", b_m1_nr2, b_m1); } |
| 507 | { uint8_t b_m1_nr2[] = { 0x02, ' ', '-', '1', CS }; |
| 508 | uint8_t b_m1[] = { 0xC0, 0x00, 0x01 }; |
| 509 | CHECK_BER_STRICT(-1.0, "-1.0", "-1.0E0", b_m1_nr2, b_m1); } |
| 510 | |
| 511 | /* 8.5.6 b) => 8.5.8 NR2 ".5" */ |
| 512 | { uint8_t b_05_nr2[] = { 0x02, CS, '5' }; |
| 513 | uint8_t b_05[] = { 0x80, 0xff, 0x01 }; |
| 514 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_05_nr2, b_05); } |
| 515 | { uint8_t b_05_nr2[] = { 0x02, '0', CS, '5' }; |
| 516 | uint8_t b_05[] = { 0x80, 0xff, 0x01 }; |
| 517 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_05_nr2, b_05); } |
| 518 | { uint8_t b_05_nr2[] = { 0x02, ' ', CS, '5' }; |
| 519 | uint8_t b_05[] = { 0x80, 0xff, 0x01 }; |
| 520 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_05_nr2, b_05); } |
| 521 | { uint8_t b_p1_nr2[] = { 0x02, '+', CS, '5' }; |
| 522 | uint8_t b_05[] = { 0x80, 0xff, 0x01 }; |
| 523 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_p1_nr2, b_05); } |
| 524 | { uint8_t b_p1_nr2[] = { 0x02, ' ', '+', CS, '5' }; |
| 525 | uint8_t b_05[] = { 0x80, 0xff, 0x01 }; |
| 526 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_p1_nr2, b_05); } |
| 527 | { uint8_t b_m05_nr2[] = { 0x02, '-', CS, '5' }; |
| 528 | uint8_t b_m05[] = { 0xC0, 0xff, 0x01 }; |
| 529 | CHECK_BER_STRICT(-0.5, "-0.5", "-5.0E-1", b_m05_nr2, b_m05); } |
| 530 | { uint8_t b_m05_nr2[] = { 0x02, ' ', '-', CS, '5' }; |
| 531 | uint8_t b_m05[] = { 0xC0, 0xff, 0x01 }; |
| 532 | CHECK_BER_STRICT(-0.5, "-0.5", "-5.0E-1", b_m05_nr2, b_m05); } |
| 533 | |
| 534 | /* 8.5.6 b) => 8.5.8 Decimal encoding is used; NR3 form */ |
| 535 | { uint8_t b_0_nr3[] = { 0x03, '0', CS, '0', 'e', '0' }; |
| 536 | uint8_t b_0[] = { }; |
| 537 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr3, b_0); } |
| 538 | { uint8_t b_0_nr3[] = { 0x03, '0', '0', CS, '0', 'E', '0' }; |
| 539 | uint8_t b_0[] = { }; |
| 540 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr3, b_0); } |
| 541 | { uint8_t b_0_nr3[] = { 0x03, ' ', '0', CS, '0', 'e', '0' }; |
| 542 | uint8_t b_0[] = { }; |
| 543 | CHECK_BER_STRICT(0.0, "0", "0", b_0_nr3, b_0); } |
| 544 | { uint8_t b_p0_nr3[] = { 0x03, '+', '0', CS, '0', 'E', '+', '0' }; |
| 545 | uint8_t b_0[] = { }; |
| 546 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr3, b_0); } |
| 547 | { uint8_t b_p0_nr3[] = { 0x03, ' ', '+', '0', CS, '0', 'e', '+', '0' }; |
| 548 | uint8_t b_0[] = { }; |
| 549 | CHECK_BER_STRICT(0.0, "0", "0", b_p0_nr3, b_0); } |
| 550 | { uint8_t b_m0_nr3[] = { 0x03, '-', '0', CS, '0', 'E', '-', '0' }; |
| 551 | uint8_t b_m0[] = { 0x43 }; |
| 552 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr3, b_m0); } |
| 553 | { uint8_t b_m0_nr3[] = { 0x03, ' ', '-', '0', CS, '0', 'e', '-', '0' }; |
| 554 | uint8_t b_m0[] = { 0x43 }; |
| 555 | CHECK_BER_STRICT(-0.0, "-0", "-0", b_m0_nr3, b_m0); } |
| 556 | |
| 557 | /* 8.5.6 b) => 8.5.8 NR3 "5.e-1" */ |
| 558 | { uint8_t b_5_nr3[] = { 0x03, '5', CS, 'e', '-', '1' }; |
| 559 | uint8_t b_5[] = { 0x80, 0xff, 0x01 }; |
| 560 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_5_nr3, b_5); } |
| 561 | { uint8_t b_5_nr3[] = { 0x03, '0', '5', CS, 'E', '-', '1' }; |
| 562 | uint8_t b_5[] = { 0x80, 0xff, 0x01 }; |
| 563 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_5_nr3, b_5); } |
| 564 | { uint8_t b_5_nr3[] = { 0x03, ' ', '5', CS, 'e', '-', '1' }; |
| 565 | uint8_t b_5[] = { 0x80, 0xff, 0x01 }; |
| 566 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_5_nr3, b_5); } |
| 567 | { uint8_t b_p5_nr3[] = { 0x03, '+', '5', CS, 'E', '-', '1' }; |
| 568 | uint8_t b_5[] = { 0x80, 0xff, 0x01 }; |
| 569 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_p5_nr3, b_5); } |
| 570 | { uint8_t b_p5_nr3[] = { 0x03, ' ', '+', '5', CS, 'e', '-', '1' }; |
| 571 | uint8_t b_5[] = { 0x80, 0xff, 0x01 }; |
| 572 | CHECK_BER_STRICT(0.5, "0.5", "5.0E-1", b_p5_nr3, b_5); } |
| 573 | { uint8_t b_m5_nr3[] = { 0x03, '-', '5', CS, 'E', '-', '1' }; |
| 574 | uint8_t b_m5[] = { 0xC0, 0xff, 0x01 }; |
| 575 | CHECK_BER_STRICT(-0.5, "-0.5", "-5.0E-1", b_m5_nr3, b_m5); } |
| 576 | { uint8_t b_m5_nr3[] = { 0x03, ' ', '-', '5', CS, 'e', '-', '1' }; |
| 577 | uint8_t b_m5[] = { 0xC0, 0xff, 0x01 }; |
| 578 | CHECK_BER_STRICT(-0.5, "-0.5", "-5.0E-1", b_m5_nr3, b_m5); } |
| 579 | |
| 580 | /* 8.5.6 b) => 8.5.8 NR3 ".5e1" */ |
| 581 | { uint8_t b_05_nr3[] = { 0x03, CS, '5', 'e', '+', '1' }; |
| 582 | uint8_t b_05[] = { 0x80, 0x00, 0x05 }; |
| 583 | CHECK_BER_STRICT(5.0, "5.0", "5.0E0", b_05_nr3, b_05); } |
| 584 | { uint8_t b_05_nr3[] = { 0x03, '0', CS, '5', 'E', '+', '1'}; |
| 585 | uint8_t b_05[] = { 0x80, 0x00, 0x05 }; |
| 586 | CHECK_BER_STRICT(5.0, "5.0", "5.0E0", b_05_nr3, b_05); } |
| 587 | { uint8_t b_05_nr3[] = { 0x03, ' ', CS, '5', 'e', '1'}; |
| 588 | uint8_t b_05[] = { 0x80, 0x00, 0x05 }; |
| 589 | CHECK_BER_STRICT(5.0, "5.0", "5.0E0", b_05_nr3, b_05); } |
| 590 | { uint8_t b_p1_nr3[] = { 0x03, '+', CS, '5', 'E', '1' }; |
| 591 | uint8_t b_05[] = { 0x80, 0x00, 0x05 }; |
| 592 | CHECK_BER_STRICT(5.0, "5.0", "5.0E0", b_p1_nr3, b_05); } |
| 593 | { uint8_t b_p1_nr3[] = { 0x03, ' ', '+', CS, '5', 'e', '+', '1' }; |
| 594 | uint8_t b_05[] = { 0x80, 0x00, 0x05 }; |
| 595 | CHECK_BER_STRICT(5.0, "5.0", "5.0E0", b_p1_nr3, b_05); } |
| 596 | { uint8_t b_m05_nr3[] = { 0x03, '-', CS, '5', 'E', '+', '1' }; |
| 597 | uint8_t b_m05[] = { 0xC0, 0x00, 0x05 }; |
| 598 | CHECK_BER_STRICT(-5.0, "-5.0", "-5.0E0", b_m05_nr3, b_m05); } |
| 599 | { uint8_t b_m05_nr3[] = { 0x03, ' ', '-', CS, '5', 'e', '1' }; |
| 600 | uint8_t b_m05[] = { 0xC0, 0x00, 0x05 }; |
| 601 | CHECK_BER_STRICT(-5.0, "-5.0", "-5.0E0", b_m05_nr3, b_m05); } |
| 602 | } /* for(comma symbol) */ |
| 603 | } |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 604 | |
Lev Walkin | e8727ec | 2012-01-09 05:46:16 -0800 | [diff] [blame] | 605 | /* Scan through the range of bits, construct the valid base-2 numbers, and |
| 606 | * try two-way conversion with them */ |
| 607 | { |
| 608 | int base, sign, scaling_factor, exponent, mantissa; |
| 609 | for(base = 0; base <= 2; base++) { |
| 610 | for(sign = 0; sign <= 1; sign++) { |
| 611 | for(scaling_factor = 0; scaling_factor <= 3; scaling_factor++) { |
| 612 | for(exponent = -1000; exponent < 1000; exponent += (exponent > -990 && exponent < 990) ? 100 : 1) { |
| 613 | for(mantissa = 0; mantissa < 66000; mantissa += (mantissa > 300 && mantissa < 65400) ? 100 : 1) { |
| 614 | check_ber_857_encoding(base, sign, scaling_factor, exponent, mantissa); |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | } |
| 619 | } |
| 620 | } |
| 621 | |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 622 | { |
| 623 | uint8_t b_1_0[] = |
| 624 | { 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
| 625 | uint8_t b_1_1[] = |
| 626 | { 0x80, 0xcc, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a }; |
| 627 | uint8_t b_3_14[] = |
| 628 | { 0x80, 0xcd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f }; |
| 629 | uint8_t b_3_14_mo1[] = |
| 630 | { 0xC0, 0xc5, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3}; |
| 631 | uint8_t b_3_14_mo2[] = |
| 632 | { 0x80, 0xbd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3,2}; |
| 633 | |
| 634 | CHECK_BER_NONSTRICT(1.0, "1.0", "1.0E0", b_1_0); |
| 635 | CHECK_BER_NONSTRICT(1.1, "1.1", "1.1E0", b_1_1); |
| 636 | CHECK_BER_NONSTRICT(3.14, "3.14", "3.14E0", b_3_14); |
| 637 | /* These two are very interesting! They check mantissa overflow! */ |
| 638 | CHECK_BER_NONSTRICT(-3.14, "-3.14", "-3.14E0", b_3_14_mo1); |
| 639 | CHECK_BER_NONSTRICT(3.14, "3.14", "3.14E0", b_3_14_mo2); |
| 640 | } |
| 641 | } |
Lev Walkin | f0b808d | 2005-04-25 21:08:25 +0000 | [diff] [blame] | 642 | |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 643 | int |
| 644 | main() { |
| 645 | REAL_t rn; |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 646 | memset(&rn, 0, sizeof(rn)); |
| 647 | |
Lev Walkin | 5fe72e9 | 2012-01-07 17:00:29 -0800 | [diff] [blame] | 648 | check_ber_encoding(); |
| 649 | |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 650 | check(&rn, 0.0, "0", "0"); |
| 651 | check(&rn, -0.0, "-0", "-0"); /* minus-zero */ |
Lev Walkin | 9c57f33 | 2017-09-17 22:30:49 -0700 | [diff] [blame] | 652 | check(&rn, NAN, "<NOT-A-NUMBER/>", "<NOT-A-NUMBER/>"); |
| 653 | check(&rn, INFINITY, "<PLUS-INFINITY/>", "<PLUS-INFINITY/>"); |
| 654 | check(&rn, -INFINITY, "<MINUS-INFINITY/>", "<MINUS-INFINITY/>"); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 655 | check(&rn, 1.0, "1.0", "1.0E0"); |
| 656 | check(&rn, -1.0, "-1.0", "-1.0E0"); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 657 | check(&rn, 0.1, "0.1", "1.0E-1"); |
Lev Walkin | f0b808d | 2005-04-25 21:08:25 +0000 | [diff] [blame] | 658 | check(&rn, 0.01, "0.01", "1.0E-2"); |
| 659 | check(&rn, 0.02, "0.02", "2.0E-2"); |
| 660 | check(&rn, 0.09, "0.09", "9.0E-2"); |
| 661 | check(&rn, 1.5, "1.5", "1.5E0"); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 662 | check(&rn, 0.33333, "0.33333", "3.3333E-1"); |
| 663 | check(&rn, 2, "2.0", "2.0E0"); |
| 664 | check(&rn, 2.1, "2.1", "2.1E0"); |
| 665 | check(&rn, 3, "3.0", "3.0E0"); |
| 666 | check(&rn, 3.1, "3.1", "3.1E0"); |
| 667 | check(&rn, 3.14, "3.14", "3.14E0"); |
| 668 | check(&rn, 3.1415, "3.1415", "3.1415E0"); |
| 669 | check(&rn, 3.141592, "3.141592", "3.141592E0"); |
| 670 | check(&rn, 3.14159265, "3.14159265", "3.14159265E0"); |
| 671 | check(&rn, -3.14159265, "-3.14159265", "-3.14159265E0"); |
| 672 | check(&rn, 14159265.0, "14159265.0", "1.4159265E7"); |
| 673 | check(&rn, -123456789123456789.0, "-123456789123456784.0", "-1.234567891234568E17"); |
Lev Walkin | f0b808d | 2005-04-25 21:08:25 +0000 | [diff] [blame] | 674 | check(&rn, 0.00000000001, "0.00000000001", "9.999999999999999E-12"); |
| 675 | check(&rn, 0.00000000002, "0.00000000002", "2.0E-11"); |
| 676 | check(&rn, 0.00000000009, "0.00000000009", "9.0E-11"); |
| 677 | check(&rn, 0.000000000002, "0.000000000002", "2.0E-12"); |
| 678 | check(&rn, 0.0000000000002, "0.0000000000002", "2.0E-13"); |
| 679 | check(&rn, 0.00000000000002, "0.00000000000002", "2.0E-14"); |
| 680 | check(&rn, 0.000000000000002, "0.000000000000002", "2.0E-15"); |
| 681 | check(&rn, 0.0000000000000002, "0.0", "2.0E-16"); |
Lev Walkin | ed46543 | 2004-09-27 20:52:36 +0000 | [diff] [blame] | 682 | check(&rn, 0.0000000000000000000001, "0.0", "1.0E-22"); |
| 683 | check(&rn, 0.000000000000000000000000000001, "0.0", "1.0E-30"); /* proved 2B a problem */ |
| 684 | check(&rn,-0.000000000000000000000000000001, "-0.0", "-1.0E-30"); /* proved 2B a problem */ |
| 685 | check(&rn, 0.0000000000010000000001000000000001, 0, 0); |
| 686 | check(&rn, 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 0, 0); |
| 687 | check(&rn, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 0, 0); |
| 688 | check(&rn,-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 0, 0); |
| 689 | check(&rn,-3.33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333, 0, 0); |
| 690 | check(&rn, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333, 0, 0); |
Lev Walkin | 8ca13c8 | 2016-01-24 22:40:00 -0800 | [diff] [blame] | 691 | check(&rn, 0.25, "0.25", "2.5E-1"); |
| 692 | check(&rn, -0.25, "-0.25", "-2.5E-1"); |
| 693 | check(&rn, 0.03, "0.03", "3.0E-2"); |
| 694 | check(&rn, -0.03, "-0.03", "-3.0E-2"); |
| 695 | |
| 696 | check(&rn, 4.01E-50, "0.0", "4.01E-50"); |
| 697 | check(&rn, -4.01E-50, "-0.0", "-4.01E-50"); |
| 698 | check(&rn, -4.9406564584124654E-324, "-0.0", "-4.940656458412465E-324"); /* MIN */ |
| 699 | check(&rn, DBL_MIN, "0.0", "2.225073858507201E-308"); /* MIN */ |
| 700 | check(&rn, -DBL_MIN, "-0.0", "-2.225073858507201E-308"); /* -MIN */ |
| 701 | check(&rn, DBL_MAX, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0", "1.797693134862316E308"); /* MAX */ |
| 702 | check(&rn, -DBL_MAX, "-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0", "-1.797693134862316E308"); /* MAX */ |
| 703 | check(&rn, -DBL_TRUE_MIN, "-0.0", "-4.940656458412465E-324"); /* subnorm */ |
| 704 | check(&rn, DBL_TRUE_MIN, "0.0", "4.940656458412465E-324"); /* subnorm */ |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 705 | |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 706 | |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 707 | #ifdef NAN |
| 708 | check_xer(0, NAN); /* "<NOT-A-NUMBER/>" */ |
| 709 | #else |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 710 | check_xer(0, zero/zero); /* "<NOT-A-NUMBER/>" */ |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 711 | #endif |
| 712 | #ifdef INFINITY |
| 713 | check_xer(0, INFINITY); /* "<PLUS-INFINITY/>" */ |
| 714 | check_xer(0, -INFINITY); /* "<MINUS-INFINITY/>" */ |
| 715 | #else |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 716 | check_xer(0, 1.0/zero); /* "<PLUS-INFINITY/>" */ |
| 717 | check_xer(0, -1.0/zero); /* "<MINUS-INFINITY/>" */ |
Lev Walkin | 1aea698 | 2004-10-26 09:35:25 +0000 | [diff] [blame] | 718 | #endif |
Lev Walkin | 5f56091 | 2004-10-21 13:37:57 +0000 | [diff] [blame] | 719 | check_xer(0, 1.0); |
| 720 | check_xer(0, -1.0); |
| 721 | check_xer(0, 1.5); |
| 722 | check_xer(0, 123); |
| 723 | check_xer(1, 0.0000000000000000000001); |
| 724 | check_xer(1, -0.0000000000000000000001); |
| 725 | |
Lev Walkin | 229ad00 | 2017-09-18 20:13:49 -0700 | [diff] [blame] | 726 | ASN_STRUCT_RESET(asn_DEF_REAL, &rn); |
Lev Walkin | 41ba1f2 | 2004-09-14 12:46:35 +0000 | [diff] [blame] | 727 | return 0; |
| 728 | } |