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