cfdcf8e6c721a89d7f077d415dfb9931b3a82f6c
[o-du/l2.git] / src / codec_utils / common / xer_encoder.c
1 /*-
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 <stdio.h>
7 #include <errno.h>
8
9 /*
10  * The XER encoder of any type. May be invoked by the application.
11  */
12 asn_enc_rval_t
13 xer_encode(const asn_TYPE_descriptor_t *td, const void *sptr,
14            enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *cb,
15            void *app_key) {
16     asn_enc_rval_t er = {0, 0, 0};
17         asn_enc_rval_t tmper;
18         const char *mname;
19         size_t mlen;
20         int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2;
21
22         if(!td || !sptr) goto cb_failed;
23
24         mname = td->xml_tag;
25         mlen = strlen(mname);
26
27         ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
28
29         tmper = td->op->xer_encoder(td, sptr, 1, xer_flags, cb, app_key);
30         if(tmper.encoded == -1) return tmper;
31         er.encoded += tmper.encoded;
32
33         ASN__CALLBACK3("</", 2, mname, mlen, ">\n", xcan);
34
35         ASN__ENCODED_OK(er);
36 cb_failed:
37         ASN__ENCODE_FAILED;
38 }
39
40 /*
41  * This is a helper function for xer_fprint, which directs all incoming data
42  * into the provided file descriptor.
43  */
44 static int
45 xer__print2fp(const void *buffer, size_t size, void *app_key) {
46         FILE *stream = (FILE *)app_key;
47
48         if(fwrite(buffer, 1, size, stream) != size)
49                 return -1;
50
51         return 0;
52 }
53
54 int
55 xer_fprint(FILE *stream, const asn_TYPE_descriptor_t *td, const void *sptr) {
56         asn_enc_rval_t er = {0,0,0};
57
58 #ifndef DEBUG_ASN_PRINT
59         return 0;
60 #endif
61         if(!stream) stream = stdout;
62         if(!td || !sptr)
63                 return -1;
64
65         er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream);
66         if(er.encoded == -1)
67                 return -1;
68
69         return fflush(stream);
70 }
71
72 struct xer_buffer {
73     char *buffer;
74     size_t buffer_size;
75     size_t allocated_size;
76 };
77
78 static int
79 xer__buffer_append(const void *buffer, size_t size, void *app_key) {
80     struct xer_buffer *xb = app_key;
81
82     while(xb->buffer_size + size + 1 > xb->allocated_size) {
83         size_t new_size = 2 * (xb->allocated_size ? xb->allocated_size : 64);
84         char *new_buf = MALLOC(new_size);
85         if(!new_buf) return -1;
86         if (xb->buffer) {
87             memcpy(new_buf, xb->buffer, xb->buffer_size);
88         }
89         FREEMEM(xb->buffer);
90         xb->buffer = new_buf;
91         xb->allocated_size = new_size;
92     }
93
94     memcpy(xb->buffer + xb->buffer_size, buffer, size);
95     xb->buffer_size += size;
96     xb->buffer[xb->buffer_size] = '\0';
97     return 0;
98 }
99
100 enum xer_equivalence_e
101 xer_equivalent(const struct asn_TYPE_descriptor_s *td, const void *struct1,
102                const void *struct2, FILE *opt_debug_stream) {
103     struct xer_buffer xb1 = {0, 0, 0};
104     struct xer_buffer xb2 = {0, 0, 0};
105     asn_enc_rval_t e1, e2;
106     asn_dec_rval_t rval;
107     void *sptr = NULL;
108
109     if(!td || !struct1 || !struct2) {
110         if(opt_debug_stream) {
111             if(!td) fprintf(opt_debug_stream, "Type descriptor missing\n");
112             if(!struct1) fprintf(opt_debug_stream, "Structure 1 missing\n");
113             if(!struct2) fprintf(opt_debug_stream, "Structure 2 missing\n");
114         }
115         return XEQ_FAILURE;
116     }
117
118     e1 = xer_encode(td, struct1, XER_F_BASIC, xer__buffer_append, &xb1);
119     if(e1.encoded == -1) {
120         if(opt_debug_stream) {
121             fprintf(stderr, "XER Encoding of %s failed\n", td->name);
122         }
123         FREEMEM(xb1.buffer);
124         return XEQ_ENCODE1_FAILED;
125     }
126
127     e2 = xer_encode(td, struct2, XER_F_BASIC, xer__buffer_append, &xb2);
128     if(e2.encoded == -1) {
129         if(opt_debug_stream) {
130             fprintf(stderr, "XER Encoding of %s failed\n", td->name);
131         }
132         FREEMEM(xb1.buffer);
133         FREEMEM(xb2.buffer);
134         return XEQ_ENCODE1_FAILED;
135     }
136
137     if(xb1.buffer_size != xb2.buffer_size
138        || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) {
139         if(opt_debug_stream) {
140             fprintf(opt_debug_stream,
141                     "Structures XER-encoded into different byte streams:\n=== "
142                     "Structure 1 ===\n%s\n=== Structure 2 ===\n%s\n",
143                     xb1.buffer, xb2.buffer);
144         }
145         FREEMEM(xb1.buffer);
146         FREEMEM(xb2.buffer);
147         return XEQ_DIFFERENT;
148     } else {
149         if(opt_debug_stream) {
150             fprintf(opt_debug_stream,
151                     "Both structures encoded into the same XER byte stream "
152                     "of size %" ASN_PRI_SIZE ":\n%s",
153                     xb1.buffer_size, xb1.buffer);
154         }
155     }
156
157     rval = xer_decode(NULL, td, (void **)&sptr, xb1.buffer,
158                xb1.buffer_size);
159     switch(rval.code) {
160     case RC_OK:
161         break;
162     case RC_WMORE:
163         if(opt_debug_stream) {
164             fprintf(opt_debug_stream,
165                     "Structure %s XER decode unexpectedly requires "
166                     "more data:\n%s\n",
167                     td->name, xb1.buffer);
168         }
169         /* Fall through */
170     case RC_FAIL:
171     default:
172         if(opt_debug_stream) {
173             fprintf(opt_debug_stream,
174                     "Structure %s XER decoding resulted in failure.\n",
175                     td->name);
176         }
177         ASN_STRUCT_FREE(*td, sptr);
178         FREEMEM(xb1.buffer);
179         FREEMEM(xb2.buffer);
180         return XEQ_DECODE_FAILED;
181     }
182
183     if(rval.consumed != xb1.buffer_size
184        && ((rval.consumed > xb1.buffer_size)
185            || xer_whitespace_span(xb1.buffer + rval.consumed,
186                                   xb1.buffer_size - rval.consumed)
187                   != (xb1.buffer_size - rval.consumed))) {
188         if(opt_debug_stream) {
189             fprintf(opt_debug_stream,
190                     "Round-trip decode of %s required less bytes (%" ASN_PRI_SIZE ") than "
191                     "encoded (%" ASN_PRI_SIZE ")\n",
192                     td->name, rval.consumed, xb1.buffer_size);
193         }
194         ASN_STRUCT_FREE(*td, sptr);
195         FREEMEM(xb1.buffer);
196         FREEMEM(xb2.buffer);
197         return XEQ_ROUND_TRIP_FAILED;
198     }
199
200     /*
201      * Reuse xb2 to encode newly decoded structure.
202      */
203     FREEMEM(xb2.buffer);
204     memset(&xb2, 0, sizeof(xb2));
205
206     e2 = xer_encode(td, sptr, XER_F_BASIC, xer__buffer_append, &xb2);
207     if(e2.encoded == -1) {
208         if(opt_debug_stream) {
209             fprintf(stderr, "XER Encoding of round-trip decode of %s failed\n",
210                     td->name);
211         }
212         ASN_STRUCT_FREE(*td, sptr);
213         FREEMEM(xb1.buffer);
214         FREEMEM(xb2.buffer);
215         return XEQ_ROUND_TRIP_FAILED;
216     }
217
218     ASN_STRUCT_FREE(*td, sptr);
219     sptr = 0;
220
221     if(xb1.buffer_size != xb2.buffer_size
222        || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) {
223         if(opt_debug_stream) {
224             fprintf(opt_debug_stream,
225                     "XER Encoding of round-trip decode of %s resulted in "
226                     "different byte stream:\n"
227                     "=== Original ===\n%s\n"
228                     "=== Round-tripped ===\n%s\n",
229                     xb1.buffer, xb2.buffer, td->name);
230         }
231         FREEMEM(xb1.buffer);
232         FREEMEM(xb2.buffer);
233         return XEQ_ROUND_TRIP_FAILED;
234     }
235
236         FREEMEM(xb1.buffer);
237         FREEMEM(xb2.buffer);
238         return XEQ_SUCCESS;
239 }
240