Moving in e2sim originally from it/test/simulators
[sim/e2-interface.git] / e2sim / ASN1c / per_encoder.c
1 /*****************************************************************************
2 #                                                                            *
3 # Copyright 2019 AT&T Intellectual Property                                  *
4 #                                                                            *
5 # Licensed under the Apache License, Version 2.0 (the "License");            *
6 # you may not use this file except in compliance with the License.           *
7 # You may obtain a copy of the License at                                    *
8 #                                                                            *
9 #      http://www.apache.org/licenses/LICENSE-2.0                            *
10 #                                                                            *
11 # Unless required by applicable law or agreed to in writing, software        *
12 # distributed under the License is distributed on an "AS IS" BASIS,          *
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
14 # See the License for the specific language governing permissions and        *
15 # limitations under the License.                                             *
16 #                                                                            *
17 ******************************************************************************/
18
19 #include <asn_application.h>
20 #include <asn_internal.h>
21 #include <per_encoder.h>
22
23 static int _uper_encode_flush_outp(asn_per_outp_t *po);
24
25 static int
26 ignore_output(const void *data, size_t size, void *app_key) {
27     (void)data;
28     (void)size;
29     (void)app_key;
30     return 0;
31 }
32
33 asn_enc_rval_t
34 uper_encode(const asn_TYPE_descriptor_t *td,
35             const asn_per_constraints_t *constraints, const void *sptr,
36             asn_app_consume_bytes_f *cb, void *app_key) {
37     asn_per_outp_t po;
38     asn_enc_rval_t er = {0,0,0};
39
40     /*
41      * Invoke type-specific encoder.
42      */
43     if(!td || !td->op->uper_encoder)
44         ASN__ENCODE_FAILED;     /* PER is not compiled in */
45
46     po.buffer = po.tmpspace;
47     po.nboff = 0;
48     po.nbits = 8 * sizeof(po.tmpspace);
49     po.output = cb ? cb : ignore_output;
50     po.op_key = app_key;
51     po.flushed_bytes = 0;
52
53     er = td->op->uper_encoder(td, constraints, sptr, &po);
54     if(er.encoded != -1) {
55         size_t bits_to_flush;
56
57         bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
58
59         /* Set number of bits encoded to a firm value */
60         er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
61
62         if(_uper_encode_flush_outp(&po)) ASN__ENCODE_FAILED;
63     }
64
65     return er;
66 }
67
68 /*
69  * Argument type and callback necessary for uper_encode_to_buffer().
70  */
71 typedef struct enc_to_buf_arg {
72         void *buffer;
73         size_t left;
74 } enc_to_buf_arg;
75 static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
76         enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
77
78         if(arg->left < size)
79                 return -1;      /* Data exceeds the available buffer size */
80
81         memcpy(arg->buffer, buffer, size);
82         arg->buffer = ((char *)arg->buffer) + size;
83         arg->left -= size;
84
85         return 0;
86 }
87
88 asn_enc_rval_t
89 uper_encode_to_buffer(const asn_TYPE_descriptor_t *td,
90                       const asn_per_constraints_t *constraints,
91                       const void *sptr, void *buffer, size_t buffer_size) {
92     enc_to_buf_arg key;
93
94     key.buffer = buffer;
95     key.left = buffer_size;
96
97     if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);
98
99     return uper_encode(td, constraints, sptr, encode_to_buffer_cb, &key);
100 }
101
102 typedef struct enc_dyn_arg {
103         void *buffer;
104         size_t length;
105         size_t allocated;
106 } enc_dyn_arg;
107 static int
108 encode_dyn_cb(const void *buffer, size_t size, void *key) {
109     enc_dyn_arg *arg = key;
110     if(arg->length + size >= arg->allocated) {
111         size_t new_size = arg->allocated ? arg->allocated : 8;
112         void *p;
113
114         do {
115             new_size <<= 2;
116         } while(arg->length + size >= new_size);
117
118         p = REALLOC(arg->buffer, new_size);
119         if(!p) {
120             FREEMEM(arg->buffer);
121             memset(arg, 0, sizeof(*arg));
122             return -1;
123         }
124         arg->buffer = p;
125         arg->allocated = new_size;
126     }
127     memcpy(((char *)arg->buffer) + arg->length, buffer, size);
128     arg->length += size;
129     return 0;
130 }
131 ssize_t
132 uper_encode_to_new_buffer(const asn_TYPE_descriptor_t *td,
133                           const asn_per_constraints_t *constraints,
134                           const void *sptr, void **buffer_r) {
135     asn_enc_rval_t er = {0,0,0};
136         enc_dyn_arg key;
137
138         memset(&key, 0, sizeof(key));
139
140         er = uper_encode(td, constraints, sptr, encode_dyn_cb, &key);
141         switch(er.encoded) {
142         case -1:
143                 FREEMEM(key.buffer);
144                 return -1;
145         case 0:
146                 FREEMEM(key.buffer);
147                 key.buffer = MALLOC(1);
148                 if(key.buffer) {
149                         *(char *)key.buffer = '\0';
150                         *buffer_r = key.buffer;
151                         return 1;
152                 } else {
153                         return -1;
154                 }
155         default:
156                 *buffer_r = key.buffer;
157                 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
158                 return ((er.encoded + 7) >> 3);
159         }
160 }
161
162 /*
163  * Internally useful functions.
164  */
165
166 /* Flush partially filled buffer */
167 static int
168 _uper_encode_flush_outp(asn_per_outp_t *po) {
169         uint8_t *buf;
170
171         if(po->nboff == 0 && po->buffer == po->tmpspace)
172                 return 0;
173
174         buf = po->buffer + (po->nboff >> 3);
175         /* Make sure we account for the last, partially filled */
176         if(po->nboff & 0x07) {
177                 buf[0] &= 0xff << (8 - (po->nboff & 0x07));
178                 buf++;
179         }
180
181         return po->output(po->tmpspace, buf - po->tmpspace, po->op_key);
182 }
183
184 asn_enc_rval_t
185 aper_encode_to_buffer(const asn_TYPE_descriptor_t *td,
186                       const asn_per_constraints_t *constraints,
187                       const void *sptr, void *buffer, size_t buffer_size) {
188     enc_to_buf_arg key;
189
190     key.buffer = buffer;
191     key.left = buffer_size;
192
193     if(td) ASN_DEBUG("Encoding \"%s\" using ALIGNED PER", td->name);
194
195     return aper_encode(td, constraints, sptr, encode_to_buffer_cb, &key);
196 }
197
198 ssize_t
199 aper_encode_to_new_buffer(const asn_TYPE_descriptor_t *td,
200                           const asn_per_constraints_t *constraints,
201                           const void *sptr, void **buffer_r) {
202     asn_enc_rval_t er = {0,0,0};
203         enc_dyn_arg key;
204
205         memset(&key, 0, sizeof(key));
206
207         er = aper_encode(td, constraints, sptr, encode_dyn_cb, &key);
208         switch(er.encoded) {
209         case -1:
210                 FREEMEM(key.buffer);
211                 return -1;
212         case 0:
213                 FREEMEM(key.buffer);
214                 key.buffer = MALLOC(1);
215                 if(key.buffer) {
216                         *(char *)key.buffer = '\0';
217                         *buffer_r = key.buffer;
218                         return 1;
219                 } else {
220                         return -1;
221                 }
222         default:
223                 *buffer_r = key.buffer;
224                 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
225                 return ((er.encoded + 7) >> 3);
226         }
227 }
228
229 static int
230 _aper_encode_flush_outp(asn_per_outp_t *po) {
231         uint8_t *buf;
232
233         if(po->nboff == 0 && po->buffer == po->tmpspace)
234                 return 0;
235
236         buf = po->buffer + (po->nboff >> 3);
237         /* Make sure we account for the last, partially filled */
238         if(po->nboff & 0x07) {
239                 buf[0] &= 0xff << (8 - (po->nboff & 0x07));
240                 buf++;
241         }
242
243         if (po->output) {
244                 return po->output(po->tmpspace, buf - po->tmpspace, po->op_key);
245         }
246         return 0;
247 }
248
249 asn_enc_rval_t
250 aper_encode(const asn_TYPE_descriptor_t *td,
251         const asn_per_constraints_t *constraints,
252         const void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
253         asn_per_outp_t po;
254         asn_enc_rval_t er = {0,0,0};
255
256         /*
257          * Invoke type-specific encoder.
258          */
259         if(!td || !td->op->aper_encoder)
260                 ASN__ENCODE_FAILED;      /* PER is not compiled in */
261
262         po.buffer = po.tmpspace;
263         po.nboff = 0;
264         po.nbits = 8 * sizeof(po.tmpspace);
265         po.output = cb;
266         po.op_key = app_key;
267         po.flushed_bytes = 0;
268
269         er = td->op->aper_encoder(td, constraints, sptr, &po);
270         if(er.encoded != -1) {
271                 size_t bits_to_flush;
272
273                 bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
274
275                 /* Set number of bits encoded to a firm value */
276                 er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
277
278                 if(_aper_encode_flush_outp(&po))
279                         ASN__ENCODE_FAILED;
280         }
281
282         return er;
283 }