blob: 4c66f39aeb4548af0cacc32f2081ca5632124f4a [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
13ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
14 asn_TYPE_descriptor_t *td,
Lev Walkin8c3b8542005-03-10 18:52:02 +000015 void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkin4fd73182004-10-21 11:20:50 +000016 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) {
Lev Walkin8484ed82004-12-14 13:31:01 +000024 st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
Lev Walkin4fd73182004-10-21 11:20:50 +000025 if(st == NULL) {
26 rval.code = RC_FAIL;
27 rval.consumed = 0;
28 return rval;
29 }
Lev Walkin8484ed82004-12-14 13:31:01 +000030 *sptr = (void *)st;
Lev Walkin4fd73182004-10-21 11:20:50 +000031 }
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 */
Lev Walkin8c3b8542005-03-10 18:52:02 +000049 buf_ptr = ((const char *)buf_ptr) + rval.consumed;
Lev Walkin4fd73182004-10-21 11:20:50 +000050 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
Lev Walkin4efbfb72005-02-25 14:20:30 +000057 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 rval.code = RC_FAIL;
63 rval.consumed = 0;
64 return rval;
65 }
66
Lev Walkin4fd73182004-10-21 11:20:50 +000067 st->buf = (uint8_t *)MALLOC(length + 1);
Lev Walkin4efbfb72005-02-25 14:20:30 +000068 if(!st->buf) {
69 st->size = 0;
Lev Walkin4fd73182004-10-21 11:20:50 +000070 rval.code = RC_FAIL;
71 rval.consumed = 0;
72 return rval;
73 }
74
75 memcpy(st->buf, buf_ptr, length);
76 st->buf[length] = '\0'; /* Just in case */
77
78 rval.code = RC_OK;
79 rval.consumed += length;
80
81 ASN_DEBUG("Took %ld/%ld bytes to encode %s",
82 (long)rval.consumed,
83 (long)length, td->name);
84
85 return rval;
86}
87
88/*
89 * Encode an always-primitive type using DER.
90 */
91asn_enc_rval_t
92der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr,
93 int tag_mode, ber_tlv_tag_t tag,
94 asn_app_consume_bytes_f *cb, void *app_key) {
95 asn_enc_rval_t erval;
96 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
97
98 ASN_DEBUG("%s %s as a primitive type (tm=%d)",
99 cb?"Encoding":"Estimating", td->name, tag_mode);
100
101 erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
102 cb, app_key);
103 ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
104 if(erval.encoded == -1) {
105 erval.failed_type = td;
106 erval.structure_ptr = sptr;
107 return erval;
108 }
109
110 if(cb && st->buf) {
111 if(cb(st->buf, st->size, app_key) < 0) {
112 erval.encoded = -1;
113 erval.failed_type = td;
114 erval.structure_ptr = sptr;
115 return erval;
116 }
117 } else {
118 assert(st->buf || st->size == 0);
119 }
120
121 erval.encoded += st->size;
122
123 return erval;
124}
125
126void
127ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
128 int contents_only) {
129 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
130
131 if(!td || !sptr)
132 return;
133
134 ASN_DEBUG("Freeing %s as a primitive type", td->name);
135
136 if(st->buf)
137 FREEMEM(st->buf);
138
139 if(!contents_only)
140 FREEMEM(st);
141}
142
143
144/*
145 * Local internal type passed around as an argument.
146 */
147struct xdp_arg_s {
Lev Walkine0b56e02005-02-25 12:10:27 +0000148 asn_TYPE_descriptor_t *type_descriptor;
Lev Walkin8471cec2004-10-21 14:02:19 +0000149 void *struct_key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000150 xer_primitive_body_decoder_f *prim_body_decoder;
Lev Walkin4fd73182004-10-21 11:20:50 +0000151 int decoded_something;
152 int want_more;
153};
154
Lev Walkin0be3a992004-10-21 12:11:57 +0000155
Lev Walkin0fab1a62005-03-09 22:19:25 +0000156static int
157xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
Lev Walkin4fd73182004-10-21 11:20:50 +0000158 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000159 enum xer_pbd_rval bret;
Lev Walkin4fd73182004-10-21 11:20:50 +0000160
161 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000162 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin4efbfb72005-02-25 14:20:30 +0000163 return 0; /* Skip it. */
Lev Walkin4fd73182004-10-21 11:20:50 +0000164 /*
165 * Decoding was done once already. Prohibit doing it again.
166 */
167 return -1;
168 }
169
Lev Walkin0fab1a62005-03-09 22:19:25 +0000170 bret = arg->prim_body_decoder(arg->type_descriptor,
Lev Walkine0b56e02005-02-25 12:10:27 +0000171 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000172 switch(bret) {
173 case XPBD_SYSTEM_FAILURE:
174 case XPBD_DECODER_LIMIT:
175 case XPBD_BROKEN_ENCODING:
176 break;
177 case XPBD_BODY_CONSUMED:
Lev Walkin4fd73182004-10-21 11:20:50 +0000178 /* Tag decoded successfully */
179 arg->decoded_something = 1;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000180 /* Fall through */
181 case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */
Lev Walkin4fd73182004-10-21 11:20:50 +0000182 return 0;
183 }
Lev Walkin0fab1a62005-03-09 22:19:25 +0000184
185 return -1;
Lev Walkin4fd73182004-10-21 11:20:50 +0000186}
187
188static ssize_t
Lev Walkin0fab1a62005-03-09 22:19:25 +0000189xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
Lev Walkin4fd73182004-10-21 11:20:50 +0000190 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000191 enum xer_pbd_rval bret;
Lev Walkin4fd73182004-10-21 11:20:50 +0000192
193 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000194 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin0be3a992004-10-21 12:11:57 +0000195 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000196 /*
197 * Decoding was done once already. Prohibit doing it again.
198 */
199 return -1;
200 }
201
202 if(!have_more) {
203 /*
204 * If we've received something like "1", we can't really
205 * tell whether it is really `1` or `123`, until we know
206 * that there is no more data coming.
207 * The have_more argument will be set to 1 once something
208 * like this is available to the caller of this callback:
209 * "1<tag_start..."
210 */
211 arg->want_more = 1;
212 return -1;
213 }
214
Lev Walkin0fab1a62005-03-09 22:19:25 +0000215 bret = arg->prim_body_decoder(arg->type_descriptor,
Lev Walkine0b56e02005-02-25 12:10:27 +0000216 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000217 switch(bret) {
218 case XPBD_SYSTEM_FAILURE:
219 case XPBD_DECODER_LIMIT:
220 case XPBD_BROKEN_ENCODING:
221 break;
222 case XPBD_BODY_CONSUMED:
223 /* Tag decoded successfully */
Lev Walkin4fd73182004-10-21 11:20:50 +0000224 arg->decoded_something = 1;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000225 /* Fall through */
226 case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */
227 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000228 }
Lev Walkin0fab1a62005-03-09 22:19:25 +0000229
230 return -1;
Lev Walkin4fd73182004-10-21 11:20:50 +0000231}
232
233
234asn_dec_rval_t
235xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
236 asn_TYPE_descriptor_t *td,
Lev Walkin8471cec2004-10-21 14:02:19 +0000237 void **sptr,
238 size_t struct_size,
Lev Walkin4fd73182004-10-21 11:20:50 +0000239 const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000240 const void *buf_ptr, size_t size,
Lev Walkin0fab1a62005-03-09 22:19:25 +0000241 xer_primitive_body_decoder_f *prim_body_decoder
Lev Walkin4fd73182004-10-21 11:20:50 +0000242) {
243 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
244 asn_struct_ctx_t s_ctx;
245 struct xdp_arg_s s_arg;
246 asn_dec_rval_t rc;
247
248 /*
249 * Create the structure if does not exist.
250 */
251 if(!*sptr) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000252 *sptr = CALLOC(1, struct_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000253 if(!*sptr) {
254 asn_dec_rval_t rval;
255 rval.code = RC_FAIL;
256 rval.consumed = 0;
257 return rval;
258 }
259 }
260
261 memset(&s_ctx, 0, sizeof(s_ctx));
Lev Walkine0b56e02005-02-25 12:10:27 +0000262 s_arg.type_descriptor = td;
Lev Walkin8471cec2004-10-21 14:02:19 +0000263 s_arg.struct_key = *sptr;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000264 s_arg.prim_body_decoder = prim_body_decoder;
Lev Walkin4fd73182004-10-21 11:20:50 +0000265 s_arg.decoded_something = 0;
266 s_arg.want_more = 0;
267
268 rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
269 xml_tag, buf_ptr, size,
270 xer_decode__unexpected_tag, xer_decode__body);
271 switch(rc.code) {
272 case RC_OK:
273 if(!s_arg.decoded_something) {
Lev Walkin36b8b822004-10-23 11:19:43 +0000274 char ch;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000275 ASN_DEBUG("Primitive body is not recognized, "
276 "supplying empty one");
277 /*
278 * Decoding opportunity has come and gone.
279 * Where's the result?
280 * Try to feed with empty body, see if it eats it.
281 */
282 if(prim_body_decoder(s_arg.type_descriptor,
283 s_arg.struct_key, &ch, 0)
284 != XPBD_BODY_CONSUMED) {
Lev Walkin28eee292004-10-23 10:17:34 +0000285 /*
286 * This decoder does not like empty stuff.
287 */
288 rc.code = RC_FAIL;
289 rc.consumed = 0;
290 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000291 }
292 break;
293 case RC_WMORE:
294 /*
295 * Redo the whole thing later.
296 * We don't have a context to save intermediate parsing state.
297 */
298 rc.consumed = 0;
299 break;
300 case RC_FAIL:
301 rc.consumed = 0;
302 if(s_arg.want_more)
303 rc.code = RC_WMORE;
304 break;
305 }
306 return rc;
307}
308