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 "asn1/asn1c/asn_internal.h"
6 #include "asn1/asn1c/asn_codecs_prim.h"
7 #include <errno.h>
8 
9 /*
10  * Decode an always-primitive type.
11  */
12 asn_dec_rval_t
ber_decode_primitive(const asn_codec_ctx_t * opt_codec_ctx,const asn_TYPE_descriptor_t * td,void ** sptr,const void * buf_ptr,size_t size,int tag_mode)13 ber_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
14                      const asn_TYPE_descriptor_t *td, void **sptr,
15                      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
der_encode_primitive(const asn_TYPE_descriptor_t * td,const void * sptr,int tag_mode,ber_tlv_tag_t tag,asn_app_consume_bytes_f * cb,void * app_key)84 der_encode_primitive(const asn_TYPE_descriptor_t *td, const 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 	const ASN__PRIMITIVE_TYPE_t *st = (const 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
ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t * td,void * sptr,enum asn_struct_free_method method)118 ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr,
119                          enum asn_struct_free_method method) {
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     switch(method) {
131     case ASFM_FREE_EVERYTHING:
132         FREEMEM(sptr);
133         break;
134     case ASFM_FREE_UNDERLYING:
135         break;
136     case ASFM_FREE_UNDERLYING_AND_RESET:
137         memset(sptr, 0, sizeof(ASN__PRIMITIVE_TYPE_t));
138         break;
139     }
140 }
141 
142 
143 /*
144  * Local internal type passed around as an argument.
145  */
146 struct xdp_arg_s {
147     const asn_TYPE_descriptor_t *type_descriptor;
148     void *struct_key;
149 	xer_primitive_body_decoder_f *prim_body_decoder;
150 	int decoded_something;
151 	int want_more;
152 };
153 
154 /*
155  * Since some kinds of primitive values can be encoded using value-specific
156  * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
157  * be supplied with such tags to parse them as needed.
158  */
159 static int
xer_decode__unexpected_tag(void * key,const void * chunk_buf,size_t chunk_size)160 xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
161 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
162 	enum xer_pbd_rval bret;
163 
164 	/*
165 	 * The chunk_buf is guaranteed to start at '<'.
166 	 */
167 	assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
168 
169 	/*
170 	 * Decoding was performed once already. Prohibit doing it again.
171 	 */
172 	if(arg->decoded_something)
173 		return -1;
174 
175 	bret = arg->prim_body_decoder(arg->type_descriptor,
176 		arg->struct_key, chunk_buf, chunk_size);
177 	switch(bret) {
178 	case XPBD_SYSTEM_FAILURE:
179 	case XPBD_DECODER_LIMIT:
180 	case XPBD_BROKEN_ENCODING:
181 		break;
182 	case XPBD_BODY_CONSUMED:
183 		/* Tag decoded successfully */
184 		arg->decoded_something = 1;
185 		/* Fall through */
186 	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
187 		return 0;
188 	}
189 
190 	return -1;
191 }
192 
193 static ssize_t
xer_decode__primitive_body(void * key,const void * chunk_buf,size_t chunk_size,int have_more)194 xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
195 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
196 	enum xer_pbd_rval bret;
197 	size_t lead_wsp_size;
198 
199 	if(arg->decoded_something) {
200 		if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
201 			/*
202 			 * Example:
203 			 * "<INTEGER>123<!--/--> </INTEGER>"
204 			 *                      ^- chunk_buf position.
205 			 */
206 			return chunk_size;
207 		}
208 		/*
209 		 * Decoding was done once already. Prohibit doing it again.
210 		 */
211 		return -1;
212 	}
213 
214 	if(!have_more) {
215 		/*
216 		 * If we've received something like "1", we can't really
217 		 * tell whether it is really `1` or `123`, until we know
218 		 * that there is no more data coming.
219 		 * The have_more argument will be set to 1 once something
220 		 * like this is available to the caller of this callback:
221 		 * "1<tag_start..."
222 		 */
223 		arg->want_more = 1;
224 		return -1;
225 	}
226 
227 	lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
228 	chunk_buf = (const char *)chunk_buf + lead_wsp_size;
229 	chunk_size -= lead_wsp_size;
230 
231 	bret = arg->prim_body_decoder(arg->type_descriptor,
232 		arg->struct_key, chunk_buf, chunk_size);
233 	switch(bret) {
234 	case XPBD_SYSTEM_FAILURE:
235 	case XPBD_DECODER_LIMIT:
236 	case XPBD_BROKEN_ENCODING:
237 		break;
238 	case XPBD_BODY_CONSUMED:
239 		/* Tag decoded successfully */
240 		arg->decoded_something = 1;
241 		/* Fall through */
242 	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
243 		return lead_wsp_size + chunk_size;
244 	}
245 
246 	return -1;
247 }
248 
249 
250 asn_dec_rval_t
xer_decode_primitive(const asn_codec_ctx_t * opt_codec_ctx,const asn_TYPE_descriptor_t * td,void ** sptr,size_t struct_size,const char * opt_mname,const void * buf_ptr,size_t size,xer_primitive_body_decoder_f * prim_body_decoder)251 xer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
252                      const asn_TYPE_descriptor_t *td, void **sptr,
253                      size_t struct_size, const char *opt_mname,
254                      const void *buf_ptr, size_t size,
255                      xer_primitive_body_decoder_f *prim_body_decoder) {
256     const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
257 	asn_struct_ctx_t s_ctx;
258 	struct xdp_arg_s s_arg;
259 	asn_dec_rval_t rc;
260 
261 	/*
262 	 * Create the structure if does not exist.
263 	 */
264 	if(!*sptr) {
265 		*sptr = CALLOC(1, struct_size);
266 		if(!*sptr) ASN__DECODE_FAILED;
267 	}
268 
269 	memset(&s_ctx, 0, sizeof(s_ctx));
270 	s_arg.type_descriptor = td;
271 	s_arg.struct_key = *sptr;
272 	s_arg.prim_body_decoder = prim_body_decoder;
273 	s_arg.decoded_something = 0;
274 	s_arg.want_more = 0;
275 
276 	rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
277 		xml_tag, buf_ptr, size,
278 		xer_decode__unexpected_tag, xer_decode__primitive_body);
279 	switch(rc.code) {
280 	case RC_OK:
281 		if(!s_arg.decoded_something) {
282 			char ch;
283 			ASN_DEBUG("Primitive body is not recognized, "
284 				"supplying empty one");
285 			/*
286 			 * Decoding opportunity has come and gone.
287 			 * Where's the result?
288 			 * Try to feed with empty body, see if it eats it.
289 			 */
290 			if(prim_body_decoder(s_arg.type_descriptor,
291 				s_arg.struct_key, &ch, 0)
292 					!= XPBD_BODY_CONSUMED) {
293 				/*
294 				 * This decoder does not like empty stuff.
295 				 */
296 				ASN__DECODE_FAILED;
297 			}
298 		}
299 		break;
300 	case RC_WMORE:
301 		/*
302 		 * Redo the whole thing later.
303 		 * We don't have a context to save intermediate parsing state.
304 		 */
305 		rc.consumed = 0;
306 		break;
307 	case RC_FAIL:
308 		rc.consumed = 0;
309 		if(s_arg.want_more)
310 			rc.code = RC_WMORE;
311 		else
312 			ASN__DECODE_FAILED;
313 		break;
314 	}
315 	return rc;
316 }
317 
318