blob: 02dc3a22a1713dddb39cd057b747ce01a052c33a [file] [log] [blame]
Harald Welte43ab79f2018-10-03 23:34:21 +02001#include <asn_application.h>
2#include <asn_internal.h>
3#include <per_encoder.h>
4
5static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key);
6
7static asn_enc_rval_t aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key);
8asn_enc_rval_t
9uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
10 return uper_encode_internal(td, 0, sptr, cb, app_key);
11}
12
13/*
14 * Argument type and callback necessary for uper_encode_to_buffer().
15 */
16typedef struct enc_to_buf_arg {
17 void *buffer;
18 size_t left;
19} enc_to_buf_arg;
20static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
21 enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
22
23 if(arg->left < size)
24 return -1; /* Data exceeds the available buffer size */
25
26 memcpy(arg->buffer, buffer, size);
27 arg->buffer = ((char *)arg->buffer) + size;
28 arg->left -= size;
29
30 return 0;
31}
32
33asn_enc_rval_t
34uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) {
35 enc_to_buf_arg key;
36
37 key.buffer = buffer;
38 key.left = buffer_size;
39
40 if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);
41
42 return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
43}
44
45asn_enc_rval_t
46aper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) {
47 enc_to_buf_arg key;
48
49 key.buffer = buffer;
50 key.left = buffer_size;
51
52 if(td) ASN_DEBUG("Encoding \"%s\" using ALIGNED PER", td->name);
53
54 return aper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
55}
56
57typedef struct enc_dyn_arg {
58 void *buffer;
59 size_t length;
60 size_t allocated;
61} enc_dyn_arg;
62static int
63encode_dyn_cb(const void *buffer, size_t size, void *key) {
64 enc_dyn_arg *arg = key;
65 if(arg->length + size >= arg->allocated) {
66 void *p;
67 arg->allocated = arg->allocated ? (arg->allocated << 2) : size;
68 p = REALLOC(arg->buffer, arg->allocated);
69 if(!p) {
70 FREEMEM(arg->buffer);
71 memset(arg, 0, sizeof(*arg));
72 return -1;
73 }
74 arg->buffer = p;
75 }
76 memcpy(((char *)arg->buffer) + arg->length, buffer, size);
77 arg->length += size;
78 return 0;
79}
80ssize_t
81uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) {
82 asn_enc_rval_t er;
83 enc_dyn_arg key;
84
85 memset(&key, 0, sizeof(key));
86
87 er = uper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key);
88 switch(er.encoded) {
89 case -1:
90 FREEMEM(key.buffer);
91 return -1;
92 case 0:
93 FREEMEM(key.buffer);
94 key.buffer = MALLOC(1);
95 if(key.buffer) {
96 *(char *)key.buffer = '\0';
97 *buffer_r = key.buffer;
98 return 1;
99 } else {
100 return -1;
101 }
102 default:
103 *buffer_r = key.buffer;
104 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
105 return ((er.encoded + 7) >> 3);
106 }
107}
108
109ssize_t
110aper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) {
111 asn_enc_rval_t er;
112 enc_dyn_arg key;
113
114 memset(&key, 0, sizeof(key));
115
116 er = aper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key);
117 switch(er.encoded) {
118 case -1:
119 FREEMEM(key.buffer);
120 return -1;
121 case 0:
122 FREEMEM(key.buffer);
123 key.buffer = MALLOC(1);
124 if(key.buffer) {
125 *(char *)key.buffer = '\0';
126 *buffer_r = key.buffer;
127 return 1;
128 } else {
129 return -1;
130 }
131 default:
132 *buffer_r = key.buffer;
133 ASN_DEBUG("Complete encoded in %d bits", er.encoded);
134 return ((er.encoded + 7) >> 3);
135 }
136}
137
138/*
139 * Internally useful functions.
140 */
141
142/* Flush partially filled buffer */
143static int
144_uper_encode_flush_outp(asn_per_outp_t *po) {
145 uint8_t *buf;
146
147 if(po->nboff == 0 && po->buffer == po->tmpspace)
148 return 0;
149
150 buf = po->buffer + (po->nboff >> 3);
151 /* Make sure we account for the last, partially filled */
152 if(po->nboff & 0x07) {
153 buf[0] &= 0xff << (8 - (po->nboff & 0x07));
154 buf++;
155 }
156
157 return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
158}
159
160static int
161_aper_encode_flush_outp(asn_per_outp_t *po) {
162 uint8_t *buf;
163
164 if(po->nboff == 0 && po->buffer == po->tmpspace)
165 return 0;
166
167 buf = po->buffer + (po->nboff >> 3);
168 /* Make sure we account for the last, partially filled */
169 if(po->nboff & 0x07) {
170 buf[0] &= 0xff << (8 - (po->nboff & 0x07));
171 buf++;
172 }
173
174 return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
175}
176
177static asn_enc_rval_t
178uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
179 asn_per_outp_t po;
180 asn_enc_rval_t er;
181
182 /*
183 * Invoke type-specific encoder.
184 */
185 if(!td || !td->uper_encoder)
186 _ASN_ENCODE_FAILED; /* PER is not compiled in */
187
188 po.buffer = po.tmpspace;
189 po.nboff = 0;
190 po.nbits = 8 * sizeof(po.tmpspace);
191 po.outper = cb;
192 po.op_key = app_key;
193 po.flushed_bytes = 0;
194
195 er = td->uper_encoder(td, constraints, sptr, &po);
196 if(er.encoded != -1) {
197 size_t bits_to_flush;
198
199 bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
200
201 /* Set number of bits encoded to a firm value */
202 er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
203
204 if(_uper_encode_flush_outp(&po))
205 _ASN_ENCODE_FAILED;
206 }
207
208 return er;
209}
210
211static asn_enc_rval_t
212aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
213 asn_per_outp_t po;
214 asn_enc_rval_t er;
215
216 /*
217 * Invoke type-specific encoder.
218 */
219 if(!td || !td->aper_encoder)
220 _ASN_ENCODE_FAILED; /* PER is not compiled in */
221
222 po.buffer = po.tmpspace;
223 po.nboff = 0;
224 po.nbits = 8 * sizeof(po.tmpspace);
225 po.outper = cb;
226 po.op_key = app_key;
227 po.flushed_bytes = 0;
228
229 er = td->aper_encoder(td, constraints, sptr, &po);
230 if(er.encoded != -1) {
231 size_t bits_to_flush;
232
233 bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
234
235 /* Set number of bits encoded to a firm value */
236 er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
237
238 if(_aper_encode_flush_outp(&po))
239 _ASN_ENCODE_FAILED;
240 }
241
242 return er;
243}
244