]> git.stg.codes - stg.git/blob - stglibs/smux.lib/asn_codecs_prim.c
Produce debug output only if SMUX_DEBUG is defined
[stg.git] / stglibs / smux.lib / 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;
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 static int
148 xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
149         struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
150         enum xer_pbd_rval bret;
151
152         if(arg->decoded_something) {
153                 if(xer_is_whitespace(chunk_buf, chunk_size))
154                         return 0;       /* Skip it. */
155                 /*
156                  * Decoding was done once already. Prohibit doing it again.
157                  */
158                 return -1;
159         }
160
161         bret = arg->prim_body_decoder(arg->type_descriptor,
162                 arg->struct_key, chunk_buf, chunk_size);
163         switch(bret) {
164         case XPBD_SYSTEM_FAILURE:
165         case XPBD_DECODER_LIMIT:
166         case XPBD_BROKEN_ENCODING:
167                 break;
168         case XPBD_BODY_CONSUMED:
169                 /* Tag decoded successfully */
170                 arg->decoded_something = 1;
171                 /* Fall through */
172         case XPBD_NOT_BODY_IGNORE:      /* Safe to proceed further */
173                 return 0;
174         }
175
176         return -1;
177 }
178
179 static ssize_t
180 xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
181         struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
182         enum xer_pbd_rval bret;
183
184         if(arg->decoded_something) {
185                 if(xer_is_whitespace(chunk_buf, chunk_size))
186                         return chunk_size;
187                 /*
188                  * Decoding was done once already. Prohibit doing it again.
189                  */
190                 return -1;
191         }
192
193         if(!have_more) {
194                 /*
195                  * If we've received something like "1", we can't really
196                  * tell whether it is really `1` or `123`, until we know
197                  * that there is no more data coming.
198                  * The have_more argument will be set to 1 once something
199                  * like this is available to the caller of this callback:
200                  * "1<tag_start..."
201                  */
202                 arg->want_more = 1;
203                 return -1;
204         }
205
206         bret = arg->prim_body_decoder(arg->type_descriptor,
207                 arg->struct_key, chunk_buf, chunk_size);
208         switch(bret) {
209         case XPBD_SYSTEM_FAILURE:
210         case XPBD_DECODER_LIMIT:
211         case XPBD_BROKEN_ENCODING:
212                 break;
213         case XPBD_BODY_CONSUMED:
214                 /* Tag decoded successfully */
215                 arg->decoded_something = 1;
216                 /* Fall through */
217         case XPBD_NOT_BODY_IGNORE:      /* Safe to proceed further */
218                 return chunk_size;
219         }
220
221         return -1;
222 }
223
224
225 asn_dec_rval_t
226 xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
227         asn_TYPE_descriptor_t *td,
228         void **sptr,
229         size_t struct_size,
230         const char *opt_mname,
231         const void *buf_ptr, size_t size,
232         xer_primitive_body_decoder_f *prim_body_decoder
233 ) {
234         const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
235         asn_struct_ctx_t s_ctx;
236         struct xdp_arg_s s_arg;
237         asn_dec_rval_t rc;
238
239         /*
240          * Create the structure if does not exist.
241          */
242         if(!*sptr) {
243                 *sptr = CALLOC(1, struct_size);
244                 if(!*sptr) _ASN_DECODE_FAILED;
245         }
246
247         memset(&s_ctx, 0, sizeof(s_ctx));
248         s_arg.type_descriptor = td;
249         s_arg.struct_key = *sptr;
250         s_arg.prim_body_decoder = prim_body_decoder;
251         s_arg.decoded_something = 0;
252         s_arg.want_more = 0;
253
254         rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
255                 xml_tag, buf_ptr, size,
256                 xer_decode__unexpected_tag, xer_decode__body);
257         switch(rc.code) {
258         case RC_OK:
259                 if(!s_arg.decoded_something) {
260                         char ch;
261                         ASN_DEBUG("Primitive body is not recognized, "
262                                 "supplying empty one");
263                         /*
264                          * Decoding opportunity has come and gone.
265                          * Where's the result?
266                          * Try to feed with empty body, see if it eats it.
267                          */
268                         if(prim_body_decoder(s_arg.type_descriptor,
269                                 s_arg.struct_key, &ch, 0)
270                                         != XPBD_BODY_CONSUMED) {
271                                 /*
272                                  * This decoder does not like empty stuff.
273                                  */
274                                 _ASN_DECODE_FAILED;
275                         }
276                 }
277                 break;
278         case RC_WMORE:
279                 /*
280                  * Redo the whole thing later.
281                  * We don't have a context to save intermediate parsing state.
282                  */
283                 rc.consumed = 0;
284                 break;
285         case RC_FAIL:
286                 rc.consumed = 0;
287                 if(s_arg.want_more)
288                         rc.code = RC_WMORE;
289                 else
290                         _ASN_DECODE_FAILED;
291                 break;
292         }
293         return rc;
294 }
295