blob: 8e604a492a4d199bed6bf107513028c53136efdb [file] [log] [blame]
Harald Welte43ab79f2018-10-03 23:34:21 +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
9/*
10 * Decode an always-primitive type.
11 */
12asn_dec_rval_t
13ber_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 */
83asn_enc_rval_t
84der_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
117void
118ASN__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 */
138struct 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 */
151static int
152xer_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
185static ssize_t
186xer_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
242asn_dec_rval_t
243xer_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