blob: 60c8e78c39167469a5cd21e130e74c66d1502209 [file] [log] [blame]
Lev Walkin6d46bc32017-09-12 21:34:00 -07001/*
2 * Copyright (c) 2017 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_application.h>
7#include <errno.h>
8
9static asn_enc_rval_t asn_encode_internal(
10 const asn_codec_ctx_t *opt_codec_parameters,
11 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
12 void *sptr, asn_app_consume_bytes_f *callback, void *callback_key);
13
14
15struct callback_count_bytes_key {
16 asn_app_consume_bytes_f *callback;
17 void *callback_key;
18 size_t computed_size;
19};
20
21/*
22 * Encoder which just counts bytes that come through it.
23 */
24static int
25callback_count_bytes_cb(const void *data, size_t size, void *keyp) {
26 struct callback_count_bytes_key *key = keyp;
27 int ret;
28
29 ret = key->callback(data, size, key->callback_key);
30 if(ret >= 0) {
31 key->computed_size += size;
32 }
33
34 return ret;
35}
36
37struct overrun_encoder_key {
38 void *buffer;
39 size_t buffer_size;
40 size_t computed_size;
41};
42
43struct callback_failure_catch_key {
44 asn_app_consume_bytes_f *callback;
45 void *callback_key;
46 int callback_failed;
47};
48
49/*
50 * Encoder which doesn't stop counting bytes
51 * even if it reaches the end of the buffer.
52 */
53static int
54overrun_encoder_cb(const void *data, size_t size, void *keyp) {
55 struct overrun_encoder_key *key = keyp;
56
57 if(key->computed_size + size > key->buffer_size) {
58 /*
59 * Avoid accident on the next call:
60 * stop adding bytes to the buffer.
61 */
62 key->buffer_size = 0;
63 } else {
64 memcpy((char *)key->buffer + key->computed_size, data, size);
65 key->computed_size += size;
66 }
67
68 return 0;
69}
70
71/*
72 * Encoder which help convert the application level encoder failure into EIO.
73 */
74static int
75callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
76 struct callback_failure_catch_key *key = keyp;
77 int ret;
78
79 ret = key->callback(data, size, key->callback_key);
80 if(ret < 0) {
81 key->callback_failed = 1;
82 }
83
84 return ret;
85}
86
87asn_enc_rval_t
88asn_encode(const asn_codec_ctx_t *opt_codec_parameters,
89 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
90 void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
91 struct callback_failure_catch_key cb_key;
92 asn_enc_rval_t er;
93
94 if(!callback) {
95 errno = EINVAL;
96 ASN__ENCODE_FAILED;
97 }
98
99 cb_key.callback = callback;
100 cb_key.callback_key = callback_key;
101 cb_key.callback_failed = 0;
102
103 er = asn_encode_internal(opt_codec_parameters, syntax, td, sptr,
104 callback_failure_catch_cb, &cb_key);
105 if(cb_key.callback_failed) {
106 assert(er.encoded == -1);
107 assert(errno == EBADF);
108 errno = EIO;
109 }
110
111 return er;
112}
113
114asn_enc_rval_t
115asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_parameters,
116 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
117 void *sptr, void *buffer, size_t buffer_size) {
118 struct overrun_encoder_key buf_key;
119 asn_enc_rval_t er;
120
121 if(buffer_size > 0 && !buffer) {
122 errno = EINVAL;
123 ASN__ENCODE_FAILED;
124 }
125
126 buf_key.buffer = buffer;
127 buf_key.buffer_size = buffer_size;
128 buf_key.computed_size = 0;
129
130 er = asn_encode_internal(opt_codec_parameters, syntax, td, sptr,
131 overrun_encoder_cb, &buf_key);
132
133 assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
134
135 return er;
136}
137
138static asn_enc_rval_t
139asn_encode_internal(const asn_codec_ctx_t *opt_codec_parameters,
140 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
141 void *sptr, asn_app_consume_bytes_f *callback,
142 void *callback_key) {
143 asn_enc_rval_t er;
144 enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
145
146 (void)opt_codec_parameters; /* Parameters are not checked on encode yet. */
147
148 if(!td || !sptr) {
149 errno = EINVAL;
150 ASN__ENCODE_FAILED;
151 }
152
153 switch(syntax) {
154 case ATS_BER:
155 /* BER is a superset of DER. */
156 /* Fall through. */
157 case ATS_DER:
158 if(td->op->der_encoder) {
159 er = der_encode(td, sptr, callback, callback_key);
160 if(er.encoded == -1) {
161 if(er.failed_type && er.failed_type->op->der_encoder) {
162 errno = EBADF; /* Structure has incorrect form. */
163 } else {
164 errno = ENOENT; /* DER is not defined for this type. */
165 }
166 }
167 } else {
168 errno = ENOENT; /* Transfer syntax is not defined for this type. */
169 ASN__ENCODE_FAILED;
170 }
171 break;
172 case ATS_CER:
173 errno = ENOENT; /* Transfer syntax is not defined for any type. */
174 ASN__ENCODE_FAILED;
175
176#ifdef ASN_DISABLE_OER_SUPPORT
177 case ATS_BASIC_OER:
178 case ATS_CANONICAL_OER:
179 errno = ENOENT; /* PER is not defined. */
180 ASN__ENCODE_FAILED;
181 break;
182#else /* ASN_DISABLE_OER_SUPPORT */
183 case ATS_BASIC_OER:
184 /* CANONICAL-OER is a superset of BASIC-OER. */
185 /* Fall through. */
186 case ATS_CANONICAL_OER:
187 if(td->op->oer_encoder) {
188 er = oer_encode(td, sptr, callback, callback_key);
189 if(er.encoded == -1) {
190 if(er.failed_type && er.failed_type->op->oer_encoder) {
191 errno = EBADF; /* Structure has incorrect form. */
192 } else {
193 errno = ENOENT; /* OER is not defined for this type. */
194 }
195 }
196 } else {
197 errno = ENOENT; /* Transfer syntax is not defined for this type. */
198 ASN__ENCODE_FAILED;
199 }
200 break;
201#endif /* ASN_DISABLE_OER_SUPPORT */
202
203#ifdef ASN_DISABLE_PER_SUPPORT
204 case ATS_UNALIGNED_BASIC_PER:
205 case ATS_UNALIGNED_CANONICAL_PER:
206 errno = ENOENT; /* PER is not defined. */
207 ASN__ENCODE_FAILED;
208 break;
209#else /* ASN_DISABLE_PER_SUPPORT */
210 case ATS_UNALIGNED_BASIC_PER:
211 /* CANONICAL-UPER is a superset of BASIC-UPER. */
212 /* Fall through. */
213 case ATS_UNALIGNED_CANONICAL_PER:
214 if(td->op->uper_encoder) {
215 er = uper_encode(td, sptr, callback, callback_key);
216 if(er.encoded == -1) {
217 if(er.failed_type && er.failed_type->op->uper_encoder) {
218 errno = EBADF; /* Structure has incorrect form. */
219 } else {
220 errno = ENOENT; /* UPER is not defined for this type. */
221 }
222 } else {
223 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
224 if(er.encoded == 0) {
225 /* Enforce "Complete Encoding" of X.691 #11.1 */
226 if(callback("\0", 1, callback_key) < 0) {
227 errno = EBADF;
228 ASN__ENCODE_FAILED;
229 }
230 er.encoded = 8; /* Exactly 8 zero bits is added. */
231 }
232 /* Convert bits into bytes */
233 er.encoded = (er.encoded + 7) >> 3;
234 }
235 } else {
236 errno = ENOENT; /* Transfer syntax is not defined for this type. */
237 ASN__ENCODE_FAILED;
238 }
239 break;
240#endif /* ASN_DISABLE_PER_SUPPORT */
241
242 case ATS_BASIC_XER:
243 /* CANONICAL-XER is a superset of BASIC-XER. */
244 xer_flags &= ~XER_F_CANONICAL;
245 xer_flags |= XER_F_BASIC;
246 /* Fall through. */
247 case ATS_CANONICAL_XER:
248 if(td->op->xer_encoder) {
249 er = xer_encode(td, sptr, xer_flags, callback, callback_key);
250 if(er.encoded == -1) {
251 if(er.failed_type && er.failed_type->op->xer_encoder) {
252 errno = EBADF; /* Structure has incorrect form. */
253 } else {
254 errno = ENOENT; /* XER is not defined for this type. */
255 }
256 }
257 } else {
258 errno = ENOENT; /* Transfer syntax is not defined for this type. */
259 ASN__ENCODE_FAILED;
260 }
261 break;
262
263 case ATS_NONSTANDARD_PLAINTEXT:
264 if(td->op->print_struct) {
265 struct callback_count_bytes_key cb_key;
266 cb_key.callback = callback;
267 cb_key.callback_key = callback_key;
268 cb_key.computed_size = 0;
269 if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
270 &cb_key)
271 < 0
272 || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
273 errno = EBADF; /* Structure has incorrect form. */
274 er.encoded = -1;
275 er.failed_type = td;
276 er.structure_ptr = sptr;
277 } else {
278 er.encoded = cb_key.computed_size;
279 er.failed_type = 0;
280 er.structure_ptr = 0;
281 }
282 } else {
283 errno = ENOENT; /* Transfer syntax is not defined for this type. */
284 ASN__ENCODE_FAILED;
285 }
286 break;
287
288 default:
289 errno = ENOENT;
290 ASN__ENCODE_FAILED;
291 }
292
293 return er;
294}