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