blob: e6725b3710e265a28f4ef8c867ce8d9771d637e6 [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) {
25 (void *)st = *sptr = CALLOC(1, sizeof(*st));
26 if(st == NULL) {
27 rval.code = RC_FAIL;
28 rval.consumed = 0;
29 return rval;
30 }
31 }
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 */
49 buf_ptr = ((char *)buf_ptr) + rval.consumed;
50 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
57 st->buf = (uint8_t *)MALLOC(length + 1);
58 if(st->buf) {
59 st->size = length;
60 } else {
61 rval.code = RC_FAIL;
62 rval.consumed = 0;
63 return rval;
64 }
65
66 memcpy(st->buf, buf_ptr, length);
67 st->buf[length] = '\0'; /* Just in case */
68
69 rval.code = RC_OK;
70 rval.consumed += length;
71
72 ASN_DEBUG("Took %ld/%ld bytes to encode %s",
73 (long)rval.consumed,
74 (long)length, td->name);
75
76 return rval;
77}
78
79/*
80 * Encode an always-primitive type using DER.
81 */
82asn_enc_rval_t
83der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr,
84 int tag_mode, ber_tlv_tag_t tag,
85 asn_app_consume_bytes_f *cb, void *app_key) {
86 asn_enc_rval_t erval;
87 ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
88
89 ASN_DEBUG("%s %s as a primitive type (tm=%d)",
90 cb?"Encoding":"Estimating", td->name, tag_mode);
91
92 erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
93 cb, app_key);
94 ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
95 if(erval.encoded == -1) {
96 erval.failed_type = td;
97 erval.structure_ptr = sptr;
98 return erval;
99 }
100
101 if(cb && st->buf) {
102 if(cb(st->buf, st->size, app_key) < 0) {
103 erval.encoded = -1;
104 erval.failed_type = td;
105 erval.structure_ptr = sptr;
106 return erval;
107 }
108 } else {
109 assert(st->buf || st->size == 0);
110 }
111
112 erval.encoded += st->size;
113
114 return erval;
115}
116
117void
118ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
119 int contents_only) {
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 if(!contents_only)
131 FREEMEM(st);
132}
133
134
135/*
136 * Local internal type passed around as an argument.
137 */
138struct xdp_arg_s {
Lev Walkin8471cec2004-10-21 14:02:19 +0000139 void *struct_key;
140 ssize_t (*prim_body_decode)(void *struct_key,
Lev Walkin4fd73182004-10-21 11:20:50 +0000141 void *chunk_buf, size_t chunk_size);
142 int decoded_something;
143 int want_more;
144};
145
Lev Walkin0be3a992004-10-21 12:11:57 +0000146/*
147 * Check whether this buffer consists of entirely XER whitespace characters.
148 */
149static int
150xer_decode__check_whitespace(void *chunk_buf, size_t chunk_size) {
151 char *p = (char *)chunk_buf;
152 char *pend = p + chunk_size;
153 for(; p < pend; p++) {
154 switch(*p) {
155 /* X.693, #8.1.4
156 * HORISONTAL TAB (9)
157 * LINE FEED (10)
158 * CARRIAGE RETURN (13)
159 * SPACE (32)
160 */
161 case 0x09: case 0x0a: case 0x0d: case 0x20:
162 break;
163 default:
164 return 0;
165 }
166 }
167 return 1; /* All whitespace */
168}
169
Lev Walkin4fd73182004-10-21 11:20:50 +0000170static int
171xer_decode__unexpected_tag(void *key, void *chunk_buf, size_t chunk_size) {
172 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
173 ssize_t decoded;
174
175 if(arg->decoded_something) {
Lev Walkin0be3a992004-10-21 12:11:57 +0000176 if(xer_decode__check_whitespace(chunk_buf, chunk_size))
177 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000178 /*
179 * Decoding was done once already. Prohibit doing it again.
180 */
181 return -1;
182 }
183
Lev Walkin8471cec2004-10-21 14:02:19 +0000184 decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000185 if(decoded < 0) {
186 return -1;
187 } else {
188 /* Tag decoded successfully */
189 arg->decoded_something = 1;
190 return 0;
191 }
192}
193
194static ssize_t
195xer_decode__body(void *key, void *chunk_buf, size_t chunk_size, int have_more) {
196 struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
197 ssize_t decoded;
198
199 if(arg->decoded_something) {
Lev Walkin0be3a992004-10-21 12:11:57 +0000200 if(xer_decode__check_whitespace(chunk_buf, chunk_size))
201 return chunk_size;
Lev Walkin4fd73182004-10-21 11:20:50 +0000202 /*
203 * Decoding was done once already. Prohibit doing it again.
204 */
205 return -1;
206 }
207
208 if(!have_more) {
209 /*
210 * If we've received something like "1", we can't really
211 * tell whether it is really `1` or `123`, until we know
212 * that there is no more data coming.
213 * The have_more argument will be set to 1 once something
214 * like this is available to the caller of this callback:
215 * "1<tag_start..."
216 */
217 arg->want_more = 1;
218 return -1;
219 }
220
Lev Walkin8471cec2004-10-21 14:02:19 +0000221 decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000222 if(decoded < 0) {
223 return -1;
224 } else {
225 arg->decoded_something = 1;
226 return decoded;
227 }
228}
229
230
231asn_dec_rval_t
232xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
233 asn_TYPE_descriptor_t *td,
Lev Walkin8471cec2004-10-21 14:02:19 +0000234 void **sptr,
235 size_t struct_size,
Lev Walkin4fd73182004-10-21 11:20:50 +0000236 const char *opt_mname,
237 void *buf_ptr, size_t size,
Lev Walkin8471cec2004-10-21 14:02:19 +0000238 ssize_t (*prim_body_decode)(void *struct_key,
Lev Walkin4fd73182004-10-21 11:20:50 +0000239 void *chunk_buf, size_t chunk_size)
240) {
241 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
242 asn_struct_ctx_t s_ctx;
243 struct xdp_arg_s s_arg;
244 asn_dec_rval_t rc;
245
246 /*
247 * Create the structure if does not exist.
248 */
249 if(!*sptr) {
Lev Walkin8471cec2004-10-21 14:02:19 +0000250 *sptr = CALLOC(1, struct_size);
Lev Walkin4fd73182004-10-21 11:20:50 +0000251 if(!*sptr) {
252 asn_dec_rval_t rval;
253 rval.code = RC_FAIL;
254 rval.consumed = 0;
255 return rval;
256 }
257 }
258
259 memset(&s_ctx, 0, sizeof(s_ctx));
Lev Walkin8471cec2004-10-21 14:02:19 +0000260 s_arg.struct_key = *sptr;
Lev Walkin4fd73182004-10-21 11:20:50 +0000261 s_arg.prim_body_decode = prim_body_decode;
262 s_arg.decoded_something = 0;
263 s_arg.want_more = 0;
264
265 rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
266 xml_tag, buf_ptr, size,
267 xer_decode__unexpected_tag, xer_decode__body);
268 switch(rc.code) {
269 case RC_OK:
270 if(!s_arg.decoded_something) {
271 /* Opportunity has come and gone. Where's the result? */
272 rc.code = RC_FAIL;
273 rc.consumed = 0;
274 }
275 break;
276 case RC_WMORE:
277 /*
278 * Redo the whole thing later.
279 * We don't have a context to save intermediate parsing state.
280 */
281 rc.consumed = 0;
282 break;
283 case RC_FAIL:
284 rc.consumed = 0;
285 if(s_arg.want_more)
286 rc.code = RC_WMORE;
287 break;
288 }
289 return rc;
290}
291