blob: 42f5a40faca25d513207620e60beb4a993ef864f [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>
7#include <assert.h>
8#include <errno.h>
9
10/*
11 * Decode an always-primitive type.
12 */
13asn_dec_rval_t
14ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
15 asn_TYPE_descriptor_t *td,
16 void **sptr, void *buf_ptr, size_t size, int tag_mode) {
17 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
18 asn_dec_rval_t rval;
19 ber_tlv_len_t length;
20
21 /*
22 * If the structure is not there, allocate it.
23 */
24 if(st == NULL) {
Lev Walkin8484ed82004-12-14 13:31:01 +000025 st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
Lev Walkin4fd73182004-10-21 11:20:50 +000026 if(st == NULL) {
27 rval.code = RC_FAIL;
28 rval.consumed = 0;
29 return rval;
30 }
Lev Walkin8484ed82004-12-14 13:31:01 +000031 *sptr = (void *)st;
Lev Walkin4fd73182004-10-21 11:20:50 +000032 }
33
34 ASN_DEBUG("Decoding %s as plain primitive (tm=%d)",
35 td->name, tag_mode);
36
37 /*
38 * Check tags and extract value length.
39 */
40 rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
41 tag_mode, 0, &length, 0);
42 if(rval.code != RC_OK)
43 return rval;
44
45 ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
46
47 /*
48 * Make sure we have this length.
49 */
50 buf_ptr = ((char *)buf_ptr) + rval.consumed;
51 size -= rval.consumed;
52 if(length > (ber_tlv_len_t)size) {
53 rval.code = RC_WMORE;
54 rval.consumed = 0;
55 return rval;
56 }
57
Lev Walkin4efbfb72005-02-25 14:20:30 +000058 st->size = (int)length;
59 /* The following better be optimized away. */
60 if(sizeof(st->size) != sizeof(length)
61 && (ber_tlv_len_t)st->size != length) {
62 st->size = 0;
63 rval.code = RC_FAIL;
64 rval.consumed = 0;
65 return rval;
66 }
67
Lev Walkin4fd73182004-10-21 11:20:50 +000068 st->buf = (uint8_t *)MALLOC(length + 1);
Lev Walkin4efbfb72005-02-25 14:20:30 +000069 if(!st->buf) {
70 st->size = 0;
Lev Walkin4fd73182004-10-21 11:20:50 +000071 rval.code = RC_FAIL;
72 rval.consumed = 0;
73 return rval;
74 }
75
76 memcpy(st->buf, buf_ptr, length);
77 st->buf[length] = '\0'; /* Just in case */
78
79 rval.code = RC_OK;
80 rval.consumed += length;
81
82 ASN_DEBUG("Took %ld/%ld bytes to encode %s",
83 (long)rval.consumed,
84 (long)length, td->name);
85
86 return rval;
87}
88
89/*
90 * Encode an always-primitive type using DER.
91 */
92asn_enc_rval_t
93der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr,
94 int tag_mode, ber_tlv_tag_t tag,
95 asn_app_consume_bytes_f *cb, void *app_key) {
96 asn_enc_rval_t erval;
97 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
98
99 ASN_DEBUG("%s %s as a primitive type (tm=%d)",
100 cb?"Encoding":"Estimating", td->name, tag_mode);
101
102 erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
103 cb, app_key);
104 ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
105 if(erval.encoded == -1) {
106 erval.failed_type = td;
107 erval.structure_ptr = sptr;
108 return erval;
109 }
110
111 if(cb && st->buf) {
112 if(cb(st->buf, st->size, app_key) < 0) {
113 erval.encoded = -1;
114 erval.failed_type = td;
115 erval.structure_ptr = sptr;
116 return erval;
117 }
118 } else {
119 assert(st->buf || st->size == 0);
120 }
121
122 erval.encoded += st->size;
123
124 return erval;
125}
126
127void
128ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
129 int contents_only) {
130 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
131
132 if(!td || !sptr)
133 return;
134
135 ASN_DEBUG("Freeing %s as a primitive type", td->name);
136
137 if(st->buf)
138 FREEMEM(st->buf);
139
140 if(!contents_only)
141 FREEMEM(st);
142}
143
144
145/*
146 * Local internal type passed around as an argument.
147 */
148struct xdp_arg_s {
Lev Walkine0b56e02005-02-25 12:10:27 +0000149 asn_TYPE_descriptor_t *type_descriptor;
Lev Walkin8471cec2004-10-21 14:02:19 +0000150 void *struct_key;
Lev Walkine0b56e02005-02-25 12:10:27 +0000151 ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
152 void *struct_key, void *chunk_buf, size_t chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000153 int decoded_something;
154 int want_more;
155};
156
Lev Walkin0be3a992004-10-21 12:11:57 +0000157
Lev Walkin4efbfb72005-02-25 14:20:30 +0000158static ssize_t
Lev Walkin4fd73182004-10-21 11:20:50 +0000159xer_decode__unexpected_tag(void *key, void *chunk_buf, size_t chunk_size) {
160 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
161 ssize_t decoded;
162
163 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000164 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin4efbfb72005-02-25 14:20:30 +0000165 return 0; /* Skip it. */
Lev Walkin4fd73182004-10-21 11:20:50 +0000166 /*
167 * Decoding was done once already. Prohibit doing it again.
168 */
169 return -1;
170 }
171
Lev Walkine0b56e02005-02-25 12:10:27 +0000172 decoded = arg->prim_body_decode(arg->type_descriptor,
173 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000174 if(decoded < 0) {
175 return -1;
176 } else {
177 /* Tag decoded successfully */
178 arg->decoded_something = 1;
179 return 0;
180 }
181}
182
183static ssize_t
184xer_decode__body(void *key, void *chunk_buf, size_t chunk_size, int have_more) {
185 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
186 ssize_t decoded;
187
188 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000189 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin0be3a992004-10-21 12:11:57 +0000190 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000191 /*
192 * Decoding was done once already. Prohibit doing it again.
193 */
194 return -1;
195 }
196
197 if(!have_more) {
198 /*
199 * If we've received something like "1", we can't really
200 * tell whether it is really `1` or `123`, until we know
201 * that there is no more data coming.
202 * The have_more argument will be set to 1 once something
203 * like this is available to the caller of this callback:
204 * "1<tag_start..."
205 */
206 arg->want_more = 1;
207 return -1;
208 }
209
Lev Walkine0b56e02005-02-25 12:10:27 +0000210 decoded = arg->prim_body_decode(arg->type_descriptor,
211 arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000212 if(decoded < 0) {
213 return -1;
214 } else {
215 arg->decoded_something = 1;
216 return decoded;
217 }
218}
219
220
221asn_dec_rval_t
222xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
223 asn_TYPE_descriptor_t *td,
Lev Walkin8471cec2004-10-21 14:02:19 +0000224 void **sptr,
225 size_t struct_size,
Lev Walkin4fd73182004-10-21 11:20:50 +0000226 const char *opt_mname,
227 void *buf_ptr, size_t size,
Lev Walkine0b56e02005-02-25 12:10:27 +0000228 ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
229 void *struct_key, void *chunk_buf, size_t chunk_size)
Lev Walkin4fd73182004-10-21 11:20:50 +0000230) {
231 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
232 asn_struct_ctx_t s_ctx;
233 struct xdp_arg_s s_arg;
234 asn_dec_rval_t rc;
235
236 /*
237 * Create the structure if does not exist.
238 */
239 if(!*sptr) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000240 *sptr = CALLOC(1, struct_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000241 if(!*sptr) {
242 asn_dec_rval_t rval;
243 rval.code = RC_FAIL;
244 rval.consumed = 0;
245 return rval;
246 }
247 }
248
249 memset(&s_ctx, 0, sizeof(s_ctx));
Lev Walkine0b56e02005-02-25 12:10:27 +0000250 s_arg.type_descriptor = td;
Lev Walkin8471cec2004-10-21 14:02:19 +0000251 s_arg.struct_key = *sptr;
Lev Walkin4fd73182004-10-21 11:20:50 +0000252 s_arg.prim_body_decode = prim_body_decode;
253 s_arg.decoded_something = 0;
254 s_arg.want_more = 0;
255
256 rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
257 xml_tag, buf_ptr, size,
258 xer_decode__unexpected_tag, xer_decode__body);
259 switch(rc.code) {
260 case RC_OK:
261 if(!s_arg.decoded_something) {
Lev Walkin36b8b822004-10-23 11:19:43 +0000262 char ch;
Lev Walkin4fd73182004-10-21 11:20:50 +0000263 /* Opportunity has come and gone. Where's the result? */
Lev Walkine0b56e02005-02-25 12:10:27 +0000264 if(prim_body_decode(s_arg.type_descriptor,
265 s_arg.struct_key, &ch, 0) != 0) {
Lev Walkin28eee292004-10-23 10:17:34 +0000266 /*
267 * This decoder does not like empty stuff.
268 */
269 rc.code = RC_FAIL;
270 rc.consumed = 0;
271 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000272 }
273 break;
274 case RC_WMORE:
275 /*
276 * Redo the whole thing later.
277 * We don't have a context to save intermediate parsing state.
278 */
279 rc.consumed = 0;
280 break;
281 case RC_FAIL:
282 rc.consumed = 0;
283 if(s_arg.want_more)
284 rc.code = RC_WMORE;
285 break;
286 }
287 return rc;
288}
289