blob: 03f107b658eefe9e47ca9cc3eccfe09f434c11da [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
58 st->buf = (uint8_t *)MALLOC(length + 1);
59 if(st->buf) {
60 st->size = length;
61 } else {
62 rval.code = RC_FAIL;
63 rval.consumed = 0;
64 return rval;
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
115 return erval;
116}
117
118void
119ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
120 int contents_only) {
121 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
122
123 if(!td || !sptr)
124 return;
125
126 ASN_DEBUG("Freeing %s as a primitive type", td->name);
127
128 if(st->buf)
129 FREEMEM(st->buf);
130
131 if(!contents_only)
132 FREEMEM(st);
133}
134
135
136/*
137 * Local internal type passed around as an argument.
138 */
139struct xdp_arg_s {
Lev Walkin8471cec2004-10-21 14:02:19 +0000140 void *struct_key;
141 ssize_t (*prim_body_decode)(void *struct_key,
Lev Walkin4fd73182004-10-21 11:20:50 +0000142 void *chunk_buf, size_t chunk_size);
143 int decoded_something;
144 int want_more;
145};
146
Lev Walkin0be3a992004-10-21 12:11:57 +0000147
Lev Walkin4fd73182004-10-21 11:20:50 +0000148static int
149xer_decode__unexpected_tag(void *key, void *chunk_buf, size_t chunk_size) {
150 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
151 ssize_t decoded;
152
153 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000154 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin0be3a992004-10-21 12:11:57 +0000155 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000156 /*
157 * Decoding was done once already. Prohibit doing it again.
158 */
159 return -1;
160 }
161
Lev Walkin8471cec2004-10-21 14:02:19 +0000162 decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000163 if(decoded < 0) {
164 return -1;
165 } else {
166 /* Tag decoded successfully */
167 arg->decoded_something = 1;
168 return 0;
169 }
170}
171
172static ssize_t
173xer_decode__body(void *key, void *chunk_buf, size_t chunk_size, int have_more) {
174 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
175 ssize_t decoded;
176
177 if(arg->decoded_something) {
Lev Walkindde25b32004-10-22 08:17:16 +0000178 if(xer_is_whitespace(chunk_buf, chunk_size))
Lev Walkin0be3a992004-10-21 12:11:57 +0000179 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000180 /*
181 * Decoding was done once already. Prohibit doing it again.
182 */
183 return -1;
184 }
185
186 if(!have_more) {
187 /*
188 * If we've received something like "1", we can't really
189 * tell whether it is really `1` or `123`, until we know
190 * that there is no more data coming.
191 * The have_more argument will be set to 1 once something
192 * like this is available to the caller of this callback:
193 * "1<tag_start..."
194 */
195 arg->want_more = 1;
196 return -1;
197 }
198
Lev Walkin8471cec2004-10-21 14:02:19 +0000199 decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000200 if(decoded < 0) {
201 return -1;
202 } else {
203 arg->decoded_something = 1;
204 return decoded;
205 }
206}
207
208
209asn_dec_rval_t
210xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
211 asn_TYPE_descriptor_t *td,
Lev Walkin8471cec2004-10-21 14:02:19 +0000212 void **sptr,
213 size_t struct_size,
Lev Walkin4fd73182004-10-21 11:20:50 +0000214 const char *opt_mname,
215 void *buf_ptr, size_t size,
Lev Walkin8471cec2004-10-21 14:02:19 +0000216 ssize_t (*prim_body_decode)(void *struct_key,
Lev Walkin4fd73182004-10-21 11:20:50 +0000217 void *chunk_buf, size_t chunk_size)
218) {
219 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
220 asn_struct_ctx_t s_ctx;
221 struct xdp_arg_s s_arg;
222 asn_dec_rval_t rc;
223
224 /*
225 * Create the structure if does not exist.
226 */
227 if(!*sptr) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000228 *sptr = CALLOC(1, struct_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000229 if(!*sptr) {
230 asn_dec_rval_t rval;
231 rval.code = RC_FAIL;
232 rval.consumed = 0;
233 return rval;
234 }
235 }
236
237 memset(&s_ctx, 0, sizeof(s_ctx));
Lev Walkin8471cec2004-10-21 14:02:19 +0000238 s_arg.struct_key = *sptr;
Lev Walkin4fd73182004-10-21 11:20:50 +0000239 s_arg.prim_body_decode = prim_body_decode;
240 s_arg.decoded_something = 0;
241 s_arg.want_more = 0;
242
243 rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
244 xml_tag, buf_ptr, size,
245 xer_decode__unexpected_tag, xer_decode__body);
246 switch(rc.code) {
247 case RC_OK:
248 if(!s_arg.decoded_something) {
Lev Walkin36b8b822004-10-23 11:19:43 +0000249 char ch;
Lev Walkin4fd73182004-10-21 11:20:50 +0000250 /* Opportunity has come and gone. Where's the result? */
Lev Walkin36b8b822004-10-23 11:19:43 +0000251 if(prim_body_decode(s_arg.struct_key, &ch, 0) != 0) {
Lev Walkin28eee292004-10-23 10:17:34 +0000252 /*
253 * This decoder does not like empty stuff.
254 */
255 rc.code = RC_FAIL;
256 rc.consumed = 0;
257 }
Lev Walkin4fd73182004-10-21 11:20:50 +0000258 }
259 break;
260 case RC_WMORE:
261 /*
262 * Redo the whole thing later.
263 * We don't have a context to save intermediate parsing state.
264 */
265 rc.consumed = 0;
266 break;
267 case RC_FAIL:
268 rc.consumed = 0;
269 if(s_arg.want_more)
270 rc.code = RC_WMORE;
271 break;
272 }
273 return rc;
274}
275