Moving in e2sim originally from it/test/simulators
[sim/e2-interface.git] / e2sim / ASN1c / asn_codecs_prim.c
1 /*****************************************************************************
2 #                                                                            *
3 # Copyright 2019 AT&T Intellectual Property                                  *
4 #                                                                            *
5 # Licensed under the Apache License, Version 2.0 (the "License");            *
6 # you may not use this file except in compliance with the License.           *
7 # You may obtain a copy of the License at                                    *
8 #                                                                            *
9 #      http://www.apache.org/licenses/LICENSE-2.0                            *
10 #                                                                            *
11 # Unless required by applicable law or agreed to in writing, software        *
12 # distributed under the License is distributed on an "AS IS" BASIS,          *
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
14 # See the License for the specific language governing permissions and        *
15 # limitations under the License.                                             *
16 #                                                                            *
17 ******************************************************************************/
18
19 /*-
20  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
21  * Redistribution and modifications are permitted subject to BSD license.
22  */
23 #include <asn_internal.h>
24 #include <asn_codecs_prim.h>
25 #include <errno.h>
26
27 /*
28  * Decode an always-primitive type.
29  */
30 asn_dec_rval_t
31 ber_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
32                      const asn_TYPE_descriptor_t *td, void **sptr,
33                      const void *buf_ptr, size_t size, int tag_mode) {
34     ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
35         asn_dec_rval_t rval;
36         ber_tlv_len_t length = 0; /* =0 to avoid [incorrect] warning. */
37
38         /*
39          * If the structure is not there, allocate it.
40          */
41         if(st == NULL) {
42                 st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
43                 if(st == NULL) ASN__DECODE_FAILED;
44                 *sptr = (void *)st;
45         }
46
47         ASN_DEBUG("Decoding %s as plain primitive (tm=%d)",
48                 td->name, tag_mode);
49
50         /*
51          * Check tags and extract value length.
52          */
53         rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
54                         tag_mode, 0, &length, 0);
55         if(rval.code != RC_OK)
56                 return rval;
57
58         ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
59
60         /*
61          * Make sure we have this length.
62          */
63         buf_ptr = ((const char *)buf_ptr) + rval.consumed;
64         size -= rval.consumed;
65         if(length > (ber_tlv_len_t)size) {
66                 rval.code = RC_WMORE;
67                 rval.consumed = 0;
68                 return rval;
69         }
70
71         st->size = (int)length;
72         /* The following better be optimized away. */
73         if(sizeof(st->size) != sizeof(length)
74                         && (ber_tlv_len_t)st->size != length) {
75                 st->size = 0;
76                 ASN__DECODE_FAILED;
77         }
78
79         st->buf = (uint8_t *)MALLOC(length + 1);
80         if(!st->buf) {
81                 st->size = 0;
82                 ASN__DECODE_FAILED;
83         }
84
85         memcpy(st->buf, buf_ptr, length);
86         st->buf[length] = '\0';         /* Just in case */
87
88         rval.code = RC_OK;
89         rval.consumed += length;
90
91         ASN_DEBUG("Took %ld/%ld bytes to encode %s",
92                 (long)rval.consumed,
93                 (long)length, td->name);
94
95         return rval;
96 }
97
98 /*
99  * Encode an always-primitive type using DER.
100  */
101 asn_enc_rval_t
102 der_encode_primitive(const asn_TYPE_descriptor_t *td, const void *sptr,
103                      int tag_mode, ber_tlv_tag_t tag,
104                      asn_app_consume_bytes_f *cb, void *app_key) {
105         asn_enc_rval_t erval = {0,0,0};
106         const ASN__PRIMITIVE_TYPE_t *st = (const ASN__PRIMITIVE_TYPE_t *)sptr;
107
108         ASN_DEBUG("%s %s as a primitive type (tm=%d)",
109                 cb?"Encoding":"Estimating", td->name, tag_mode);
110
111         erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
112                 cb, app_key);
113         ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
114         if(erval.encoded == -1) {
115                 erval.failed_type = td;
116                 erval.structure_ptr = sptr;
117                 return erval;
118         }
119
120         if(cb && st->buf) {
121                 if(cb(st->buf, st->size, app_key) < 0) {
122                         erval.encoded = -1;
123                         erval.failed_type = td;
124                         erval.structure_ptr = sptr;
125                         return erval;
126                 }
127         } else {
128                 assert(st->buf || st->size == 0);
129         }
130
131         erval.encoded += st->size;
132         ASN__ENCODED_OK(erval);
133 }
134
135 void
136 ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr,
137                          enum asn_struct_free_method method) {
138     ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
139
140         if(!td || !sptr)
141                 return;
142
143         ASN_DEBUG("Freeing %s as a primitive type", td->name);
144
145         if(st->buf)
146                 FREEMEM(st->buf);
147
148     switch(method) {
149     case ASFM_FREE_EVERYTHING:
150         FREEMEM(sptr);
151         break;
152     case ASFM_FREE_UNDERLYING:
153         break;
154     case ASFM_FREE_UNDERLYING_AND_RESET:
155         memset(sptr, 0, sizeof(ASN__PRIMITIVE_TYPE_t));
156         break;
157     }
158 }
159
160
161 /*
162  * Local internal type passed around as an argument.
163  */
164 struct xdp_arg_s {
165     const asn_TYPE_descriptor_t *type_descriptor;
166     void *struct_key;
167         xer_primitive_body_decoder_f *prim_body_decoder;
168         int decoded_something;
169         int want_more;
170 };
171
172 /*
173  * Since some kinds of primitive values can be encoded using value-specific
174  * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
175  * be supplied with such tags to parse them as needed.
176  */
177 static int
178 xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
179         struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
180         enum xer_pbd_rval bret;
181
182         /*
183          * The chunk_buf is guaranteed to start at '<'.
184          */
185         assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
186
187         /*
188          * Decoding was performed once already. Prohibit doing it again.
189          */
190         if(arg->decoded_something)
191                 return -1;
192
193         bret = arg->prim_body_decoder(arg->type_descriptor,
194                 arg->struct_key, chunk_buf, chunk_size);
195         switch(bret) {
196         case XPBD_SYSTEM_FAILURE:
197         case XPBD_DECODER_LIMIT:
198         case XPBD_BROKEN_ENCODING:
199                 break;
200         case XPBD_BODY_CONSUMED:
201                 /* Tag decoded successfully */
202                 arg->decoded_something = 1;
203                 /* Fall through */
204         case XPBD_NOT_BODY_IGNORE:      /* Safe to proceed further */
205                 return 0;
206         }
207
208         return -1;
209 }
210
211 static ssize_t
212 xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
213         struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
214         enum xer_pbd_rval bret;
215         size_t lead_wsp_size;
216
217         if(arg->decoded_something) {
218                 if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
219                         /*
220                          * Example:
221                          * "<INTEGER>123<!--/--> </INTEGER>"
222                          *                      ^- chunk_buf position.
223                          */
224                         return chunk_size;
225                 }
226                 /*
227                  * Decoding was done once already. Prohibit doing it again.
228                  */
229                 return -1;
230         }
231
232         if(!have_more) {
233                 /*
234                  * If we've received something like "1", we can't really
235                  * tell whether it is really `1` or `123`, until we know
236                  * that there is no more data coming.
237                  * The have_more argument will be set to 1 once something
238                  * like this is available to the caller of this callback:
239                  * "1<tag_start..."
240                  */
241                 arg->want_more = 1;
242                 return -1;
243         }
244
245         lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
246         chunk_buf = (const char *)chunk_buf + lead_wsp_size;
247         chunk_size -= lead_wsp_size;
248
249         bret = arg->prim_body_decoder(arg->type_descriptor,
250                 arg->struct_key, chunk_buf, chunk_size);
251         switch(bret) {
252         case XPBD_SYSTEM_FAILURE:
253         case XPBD_DECODER_LIMIT:
254         case XPBD_BROKEN_ENCODING:
255                 break;
256         case XPBD_BODY_CONSUMED:
257                 /* Tag decoded successfully */
258                 arg->decoded_something = 1;
259                 /* Fall through */
260         case XPBD_NOT_BODY_IGNORE:      /* Safe to proceed further */
261                 return lead_wsp_size + chunk_size;
262         }
263
264         return -1;
265 }
266
267
268 asn_dec_rval_t
269 xer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
270                      const asn_TYPE_descriptor_t *td, void **sptr,
271                      size_t struct_size, const char *opt_mname,
272                      const void *buf_ptr, size_t size,
273                      xer_primitive_body_decoder_f *prim_body_decoder) {
274     const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
275         asn_struct_ctx_t s_ctx;
276         struct xdp_arg_s s_arg;
277         asn_dec_rval_t rc;
278
279         /*
280          * Create the structure if does not exist.
281          */
282         if(!*sptr) {
283                 *sptr = CALLOC(1, struct_size);
284                 if(!*sptr) ASN__DECODE_FAILED;
285         }
286
287         memset(&s_ctx, 0, sizeof(s_ctx));
288         s_arg.type_descriptor = td;
289         s_arg.struct_key = *sptr;
290         s_arg.prim_body_decoder = prim_body_decoder;
291         s_arg.decoded_something = 0;
292         s_arg.want_more = 0;
293
294         rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
295                 xml_tag, buf_ptr, size,
296                 xer_decode__unexpected_tag, xer_decode__primitive_body);
297         switch(rc.code) {
298         case RC_OK:
299                 if(!s_arg.decoded_something) {
300                         char ch;
301                         ASN_DEBUG("Primitive body is not recognized, "
302                                 "supplying empty one");
303                         /*
304                          * Decoding opportunity has come and gone.
305                          * Where's the result?
306                          * Try to feed with empty body, see if it eats it.
307                          */
308                         if(prim_body_decoder(s_arg.type_descriptor,
309                                 s_arg.struct_key, &ch, 0)
310                                         != XPBD_BODY_CONSUMED) {
311                                 /*
312                                  * This decoder does not like empty stuff.
313                                  */
314                                 ASN__DECODE_FAILED;
315                         }
316                 }
317                 break;
318         case RC_WMORE:
319                 /*
320                  * Redo the whole thing later.
321                  * We don't have a context to save intermediate parsing state.
322                  */
323                 rc.consumed = 0;
324                 break;
325         case RC_FAIL:
326                 rc.consumed = 0;
327                 if(s_arg.want_more)
328                         rc.code = RC_WMORE;
329                 else
330                         ASN__DECODE_FAILED;
331                 break;
332         }
333         return rc;
334 }
335