SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / INTEGER_xer.c
1 /*
2  * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_internal.h>
7 #include <INTEGER.h>
8
9 struct e2v_key {
10     const char *start;
11     const char *stop;
12     const asn_INTEGER_enum_map_t *vemap;
13     const unsigned int *evmap;
14 };
15 static int
16 INTEGER__compar_enum2value(const void *kp, const void *am) {
17     const struct e2v_key *key = (const struct e2v_key *)kp;
18     const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
19     const char *ptr, *end, *name;
20
21     /* Remap the element (sort by different criterion) */
22     el = key->vemap + key->evmap[el - key->vemap];
23
24     /* Compare strings */
25     for(ptr = key->start, end = key->stop, name = el->enum_name;
26             ptr < end; ptr++, name++) {
27         if(*ptr != *name || !*name)
28             return *(const unsigned char *)ptr - *(const unsigned char *)name;
29     }
30     return name[0] ? -1 : 0;
31 }
32
33 static const asn_INTEGER_enum_map_t *
34 INTEGER_map_enum2value(const asn_INTEGER_specifics_t *specs, const char *lstart,
35                        const char *lstop) {
36     const asn_INTEGER_enum_map_t *el_found;
37     int count = specs ? specs->map_count : 0;
38     struct e2v_key key;
39     const char *lp;
40
41     if(!count) return NULL;
42
43     /* Guaranteed: assert(lstart < lstop); */
44     /* Figure out the tag name */
45     for(lstart++, lp = lstart; lp < lstop; lp++) {
46         switch(*lp) {
47         case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */
48         case 0x2f: /* '/' */ case 0x3e: /* '>' */
49             break;
50         default:
51             continue;
52         }
53         break;
54     }
55     if(lp == lstop) return NULL;  /* No tag found */
56     lstop = lp;
57
58     key.start = lstart;
59     key.stop = lstop;
60     key.vemap = specs->value2enum;
61     key.evmap = specs->enum2value;
62     el_found = (asn_INTEGER_enum_map_t *)bsearch(&key,
63         specs->value2enum, count, sizeof(specs->value2enum[0]),
64         INTEGER__compar_enum2value);
65     if(el_found) {
66         /* Remap enum2value into value2enum */
67         el_found = key.vemap + key.evmap[el_found - key.vemap];
68     }
69     return el_found;
70 }
71
72 static int
73 INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
74     void *p = MALLOC(min_size + 1);
75     if(p) {
76         void *b = st->buf;
77         st->size = 0;
78         st->buf = p;
79         FREEMEM(b);
80         return 0;
81     } else {
82         return -1;
83     }
84 }
85
86 /*
87  * Decode the chunk of XML text encoding INTEGER.
88  */
89 static enum xer_pbd_rval
90 INTEGER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,
91                          const void *chunk_buf, size_t chunk_size) {
92     const asn_INTEGER_specifics_t *specs =
93         (const asn_INTEGER_specifics_t *)td->specifics;
94     INTEGER_t *st = (INTEGER_t *)sptr;
95     intmax_t dec_value;
96     intmax_t hex_value = 0;
97     const char *lp;
98     const char *lstart = (const char *)chunk_buf;
99     const char *lstop = lstart + chunk_size;
100     enum {
101         ST_LEADSPACE,
102         ST_SKIPSPHEX,
103         ST_WAITDIGITS,
104         ST_DIGITS,
105         ST_DIGITS_TRAILSPACE,
106         ST_HEXDIGIT1,
107         ST_HEXDIGIT2,
108         ST_HEXDIGITS_TRAILSPACE,
109         ST_HEXCOLON,
110         ST_END_ENUM,
111         ST_UNEXPECTED
112     } state = ST_LEADSPACE;
113     const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */
114     const char *dec_value_end = 0;
115
116     if(chunk_size)
117         ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",
118                   (long)chunk_size, *lstart, lstop[-1]);
119
120     if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
121         return XPBD_SYSTEM_FAILURE;
122
123     /*
124      * We may have received a tag here. It will be processed inline.
125      * Use strtoul()-like code and serialize the result.
126      */
127     for(lp = lstart; lp < lstop; lp++) {
128         int lv = *lp;
129         switch(lv) {
130         case 0x09: case 0x0a: case 0x0d: case 0x20:
131             switch(state) {
132             case ST_LEADSPACE:
133             case ST_DIGITS_TRAILSPACE:
134             case ST_HEXDIGITS_TRAILSPACE:
135             case ST_SKIPSPHEX:
136                 continue;
137             case ST_DIGITS:
138                 dec_value_end = lp;
139                 state = ST_DIGITS_TRAILSPACE;
140                 continue;
141             case ST_HEXCOLON:
142                 state = ST_HEXDIGITS_TRAILSPACE;
143                 continue;
144             default:
145                 break;
146             }
147             break;
148         case 0x2d:  /* '-' */
149             if(state == ST_LEADSPACE) {
150                 dec_value = 0;
151                 dec_value_start = lp;
152                 state = ST_WAITDIGITS;
153                 continue;
154             }
155             break;
156         case 0x2b:  /* '+' */
157             if(state == ST_LEADSPACE) {
158                 dec_value = 0;
159                 dec_value_start = lp;
160                 state = ST_WAITDIGITS;
161                 continue;
162             }
163             break;
164         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
165         case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
166             switch(state) {
167             case ST_DIGITS: continue;
168             case ST_SKIPSPHEX:  /* Fall through */
169             case ST_HEXDIGIT1:
170                 hex_value = (lv - 0x30) << 4;
171                 state = ST_HEXDIGIT2;
172                 continue;
173             case ST_HEXDIGIT2:
174                 hex_value += (lv - 0x30);
175                 state = ST_HEXCOLON;
176                 st->buf[st->size++] = (uint8_t)hex_value;
177                 continue;
178             case ST_HEXCOLON:
179                 return XPBD_BROKEN_ENCODING;
180             case ST_LEADSPACE:
181                 dec_value = 0;
182                 dec_value_start = lp;
183                 /* FALL THROUGH */
184             case ST_WAITDIGITS:
185                 state = ST_DIGITS;
186                 continue;
187             default:
188                 break;
189             }
190             break;
191         case 0x3c:  /* '<', start of XML encoded enumeration */
192             if(state == ST_LEADSPACE) {
193                 const asn_INTEGER_enum_map_t *el;
194                 el = INTEGER_map_enum2value(
195                     (const asn_INTEGER_specifics_t *)
196                     td->specifics, lstart, lstop);
197                 if(el) {
198                     ASN_DEBUG("Found \"%s\" => %ld",
199                               el->enum_name, el->nat_value);
200                     dec_value = el->nat_value;
201                     state = ST_END_ENUM;
202                     lp = lstop - 1;
203                     continue;
204                 }
205                 ASN_DEBUG("Unknown identifier for INTEGER");
206             }
207             return XPBD_BROKEN_ENCODING;
208         case 0x3a:  /* ':' */
209             if(state == ST_HEXCOLON) {
210                 /* This colon is expected */
211                 state = ST_HEXDIGIT1;
212                 continue;
213             } else if(state == ST_DIGITS) {
214                 /* The colon here means that we have
215                  * decoded the first two hexadecimal
216                  * places as a decimal value.
217                  * Switch decoding mode. */
218                 ASN_DEBUG("INTEGER re-evaluate as hex form");
219                 state = ST_SKIPSPHEX;
220                 dec_value_start = 0;
221                 lp = lstart - 1;
222                 continue;
223             } else {
224                 ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));
225                 break;
226             }
227         /* [A-Fa-f] */
228         case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:
229         case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:
230             switch(state) {
231             case ST_SKIPSPHEX:
232             case ST_LEADSPACE: /* Fall through */
233             case ST_HEXDIGIT1:
234                 hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);
235                 hex_value += 10;
236                 hex_value <<= 4;
237                 state = ST_HEXDIGIT2;
238                 continue;
239             case ST_HEXDIGIT2:
240                 hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);
241                 hex_value += 10;
242                 st->buf[st->size++] = (uint8_t)hex_value;
243                 state = ST_HEXCOLON;
244                 continue;
245             case ST_DIGITS:
246                 ASN_DEBUG("INTEGER re-evaluate as hex form");
247                 state = ST_SKIPSPHEX;
248                 dec_value_start = 0;
249                 lp = lstart - 1;
250                 continue;
251             default:
252                 break;
253             }
254             break;
255         }
256
257         /* Found extra non-numeric stuff */
258         ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",
259                   lv, (long)(lp - lstart));
260         state = ST_UNEXPECTED;
261         break;
262     }
263
264     switch(state) {
265     case ST_END_ENUM:
266         /* Got a complete and valid enumeration encoded as a tag. */
267         break;
268     case ST_DIGITS:
269         dec_value_end = lstop;
270         /* FALL THROUGH */
271     case ST_DIGITS_TRAILSPACE:
272         /* The last symbol encountered was a digit. */
273         switch(asn_strtoimax_lim(dec_value_start, &dec_value_end, &dec_value)) {
274         case ASN_STRTOX_OK:
275             if(specs && specs->field_unsigned && (uintmax_t) dec_value <= ULONG_MAX) {
276                 break;
277             } else if(dec_value >= LONG_MIN && dec_value <= LONG_MAX) {
278                 break;
279             } else {
280                 /*
281                  * We model INTEGER on long for XER,
282                  * to avoid rewriting all the tests at once.
283                  */
284                 ASN_DEBUG("INTEGER exceeds long range");
285             }
286             /* Fall through */
287         case ASN_STRTOX_ERROR_RANGE:
288             ASN_DEBUG("INTEGER decode %s hit range limit", td->name);
289             return XPBD_DECODER_LIMIT;
290         case ASN_STRTOX_ERROR_INVAL:
291         case ASN_STRTOX_EXPECT_MORE:
292         case ASN_STRTOX_EXTRA_DATA:
293             return XPBD_BROKEN_ENCODING;
294         }
295         break;
296     case ST_HEXCOLON:
297     case ST_HEXDIGITS_TRAILSPACE:
298         st->buf[st->size] = 0;  /* Just in case termination */
299         return XPBD_BODY_CONSUMED;
300     case ST_HEXDIGIT1:
301     case ST_HEXDIGIT2:
302     case ST_SKIPSPHEX:
303         return XPBD_BROKEN_ENCODING;
304     case ST_LEADSPACE:
305         /* Content not found */
306         return XPBD_NOT_BODY_IGNORE;
307     case ST_WAITDIGITS:
308     case ST_UNEXPECTED:
309         ASN_DEBUG("INTEGER: No useful digits (state %d)", state);
310         return XPBD_BROKEN_ENCODING;  /* No digits */
311     }
312
313     /*
314      * Convert the result of parsing of enumeration or a straight
315      * decimal value into a BER representation.
316      */
317     if(asn_imax2INTEGER(st, dec_value)) {
318                 ASN_DEBUG("INTEGER decode %s conversion failed", td->name);
319         return XPBD_SYSTEM_FAILURE;
320         }
321
322     return XPBD_BODY_CONSUMED;
323 }
324
325 asn_dec_rval_t
326 INTEGER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
327                    const asn_TYPE_descriptor_t *td, void **sptr,
328                    const char *opt_mname, const void *buf_ptr, size_t size) {
329     return xer_decode_primitive(opt_codec_ctx, td,
330         sptr, sizeof(INTEGER_t), opt_mname,
331         buf_ptr, size, INTEGER__xer_body_decode);
332 }
333
334 asn_enc_rval_t
335 INTEGER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
336                    int ilevel, enum xer_encoder_flags_e flags,
337                    asn_app_consume_bytes_f *cb, void *app_key) {
338     const INTEGER_t *st = (const INTEGER_t *)sptr;
339     asn_enc_rval_t er = {0,0,0};
340
341     (void)ilevel;
342     (void)flags;
343
344     if(!st || !st->buf)
345         ASN__ENCODE_FAILED;
346
347     er.encoded = INTEGER__dump(td, st, cb, app_key, 1);
348     if(er.encoded < 0) ASN__ENCODE_FAILED;
349
350     ASN__ENCODED_OK(er);
351 }