blob: 78448a8ecb760a66f2405dac67bdf0c87aebe247 [file] [log] [blame]
Lev Walkin4fd73182004-10-21 11:20:50 +00001/*-
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>
Lev Walkin4fd73182004-10-21 11:20:50 +00007#include <errno.h>
8
9/*
10 * Decode an always-primitive type.
11 */
12asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070013ber_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -070014 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;
Lev Walkin4fd73182004-10-21 11:20:50 +000017 asn_dec_rval_t rval;
Lev Walkin104af192016-01-24 22:13:27 -080018 ber_tlv_len_t length = 0; /* =0 to avoid [incorrect] warning. */
Lev Walkin4fd73182004-10-21 11:20:50 +000019
20 /*
21 * If the structure is not there, allocate it.
22 */
23 if(st == NULL) {
Lev Walkin8484ed82004-12-14 13:31:01 +000024 st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
Lev Walkin7c1dc052016-03-14 03:08:15 -070025 if(st == NULL) ASN__DECODE_FAILED;
Lev Walkin8484ed82004-12-14 13:31:01 +000026 *sptr = (void *)st;
Lev Walkin4fd73182004-10-21 11:20:50 +000027 }
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 */
Lev Walkin8c3b8542005-03-10 18:52:02 +000045 buf_ptr = ((const char *)buf_ptr) + rval.consumed;
Lev Walkin4fd73182004-10-21 11:20:50 +000046 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
Lev Walkin4efbfb72005-02-25 14:20:30 +000053 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;
Lev Walkin7c1dc052016-03-14 03:08:15 -070058 ASN__DECODE_FAILED;
Lev Walkin4efbfb72005-02-25 14:20:30 +000059 }
60
Lev Walkin4fd73182004-10-21 11:20:50 +000061 st->buf = (uint8_t *)MALLOC(length + 1);
Lev Walkin4efbfb72005-02-25 14:20:30 +000062 if(!st->buf) {
63 st->size = 0;
Lev Walkin7c1dc052016-03-14 03:08:15 -070064 ASN__DECODE_FAILED;
Lev Walkin4fd73182004-10-21 11:20:50 +000065 }
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
Lev Walkin20696a42017-10-17 21:27:33 -070084der_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;
Lev Walkin4fd73182004-10-21 11:20:50 +000089
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;
Lev Walkin7c1dc052016-03-14 03:08:15 -0700114 ASN__ENCODED_OK(erval);
Lev Walkin4fd73182004-10-21 11:20:50 +0000115}
116
117void
Lev Walkinf6853ce2017-08-11 00:50:27 -0700118ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700119 enum asn_struct_free_method method) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700120 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
Lev Walkin4fd73182004-10-21 11:20:50 +0000121
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
Lev Walkin8d99d7b2017-08-25 01:06:00 -0700130 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 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000140}
141
142
143/*
144 * Local internal type passed around as an argument.
145 */
146struct xdp_arg_s {
Lev Walkin20696a42017-10-17 21:27:33 -0700147 const asn_TYPE_descriptor_t *type_descriptor;
148 void *struct_key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000149 xer_primitive_body_decoder_f *prim_body_decoder;
Lev Walkin4fd73182004-10-21 11:20:50 +0000150 int decoded_something;
151 int want_more;
152};
153
Lev Walkin30520ab2012-09-04 17:11:27 -0700154/*
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 */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000159static int
160xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
Lev Walkin4fd73182004-10-21 11:20:50 +0000161 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000162 enum xer_pbd_rval bret;
Lev Walkin4fd73182004-10-21 11:20:50 +0000163
Lev Walkin30520ab2012-09-04 17:11:27 -0700164 /*
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)
Lev Walkin4fd73182004-10-21 11:20:50 +0000173 return -1;
Lev Walkin4fd73182004-10-21 11:20:50 +0000174
Lev Walkin0fab1a62005-03-09 22:19:25 +0000175 bret = arg->prim_body_decoder(arg->type_descriptor,
Lev Walkine0b56e02005-02-25 12:10:27 +0000176 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000177 switch(bret) {
178 case XPBD_SYSTEM_FAILURE:
179 case XPBD_DECODER_LIMIT:
180 case XPBD_BROKEN_ENCODING:
181 break;
182 case XPBD_BODY_CONSUMED:
Lev Walkin4fd73182004-10-21 11:20:50 +0000183 /* Tag decoded successfully */
184 arg->decoded_something = 1;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000185 /* Fall through */
186 case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */
Lev Walkin4fd73182004-10-21 11:20:50 +0000187 return 0;
188 }
Lev Walkin0fab1a62005-03-09 22:19:25 +0000189
190 return -1;
Lev Walkin4fd73182004-10-21 11:20:50 +0000191}
192
193static ssize_t
Lev Walkin30520ab2012-09-04 17:11:27 -0700194xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
Lev Walkin4fd73182004-10-21 11:20:50 +0000195 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000196 enum xer_pbd_rval bret;
Lev Walkinf7982282013-03-16 07:01:42 -0700197 size_t lead_wsp_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000198
199 if(arg->decoded_something) {
Lev Walkinf7982282013-03-16 07:01:42 -0700200 if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
Lev Walkin30520ab2012-09-04 17:11:27 -0700201 /*
202 * Example:
203 * "<INTEGER>123<!--/--> </INTEGER>"
204 * ^- chunk_buf position.
205 */
Lev Walkin0be3a992004-10-21 12:11:57 +0000206 return chunk_size;
Lev Walkin30520ab2012-09-04 17:11:27 -0700207 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000208 /*
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
Lev Walkinf7982282013-03-16 07:01:42 -0700227 lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
Lev Walkinf01946e2013-03-24 02:13:08 -0700228 chunk_buf = (const char *)chunk_buf + lead_wsp_size;
Lev Walkinf7982282013-03-16 07:01:42 -0700229 chunk_size -= lead_wsp_size;
230
Lev Walkin0fab1a62005-03-09 22:19:25 +0000231 bret = arg->prim_body_decoder(arg->type_descriptor,
Lev Walkine0b56e02005-02-25 12:10:27 +0000232 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000233 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 */
Lev Walkin4fd73182004-10-21 11:20:50 +0000240 arg->decoded_something = 1;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000241 /* Fall through */
242 case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */
Lev Walkinf7982282013-03-16 07:01:42 -0700243 return lead_wsp_size + chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000244 }
Lev Walkin0fab1a62005-03-09 22:19:25 +0000245
246 return -1;
Lev Walkin4fd73182004-10-21 11:20:50 +0000247}
248
249
250asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700251xer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700252 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;
Lev Walkin4fd73182004-10-21 11:20:50 +0000257 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) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000265 *sptr = CALLOC(1, struct_size);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700266 if(!*sptr) ASN__DECODE_FAILED;
Lev Walkin4fd73182004-10-21 11:20:50 +0000267 }
268
269 memset(&s_ctx, 0, sizeof(s_ctx));
Lev Walkine0b56e02005-02-25 12:10:27 +0000270 s_arg.type_descriptor = td;
Lev Walkin8471cec2004-10-21 14:02:19 +0000271 s_arg.struct_key = *sptr;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000272 s_arg.prim_body_decoder = prim_body_decoder;
Lev Walkin4fd73182004-10-21 11:20:50 +0000273 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,
Lev Walkin30520ab2012-09-04 17:11:27 -0700278 xer_decode__unexpected_tag, xer_decode__primitive_body);
Lev Walkin4fd73182004-10-21 11:20:50 +0000279 switch(rc.code) {
280 case RC_OK:
281 if(!s_arg.decoded_something) {
Lev Walkin36b8b822004-10-23 11:19:43 +0000282 char ch;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000283 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) {
Lev Walkin28eee292004-10-23 10:17:34 +0000293 /*
294 * This decoder does not like empty stuff.
295 */
Lev Walkin7c1dc052016-03-14 03:08:15 -0700296 ASN__DECODE_FAILED;
Lev Walkin28eee292004-10-23 10:17:34 +0000297 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000298 }
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;
Lev Walkin00918812006-09-18 21:19:32 +0000311 else
Lev Walkin7c1dc052016-03-14 03:08:15 -0700312 ASN__DECODE_FAILED;
Lev Walkin4fd73182004-10-21 11:20:50 +0000313 break;
314 }
315 return rc;
316}
317