2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
4 * Redistribution and modifications are permitted subject to BSD license.
6 #include <asn_internal.h>
7 #include <constr_SET_OF.h>
10 * Return a standardized complex structure.
13 #define RETURN(_code) \
16 rval.consumed = consumed_myself; \
21 #define XER_ADVANCE(num_bytes) \
23 size_t num = num_bytes; \
24 buf_ptr = ((const char *)buf_ptr) + num; \
26 consumed_myself += num; \
30 * Decode the XER (XML) data.
33 SET_OF_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
34 const asn_TYPE_descriptor_t *td, void **struct_ptr,
35 const char *opt_mname, const void *buf_ptr, size_t size) {
37 * Bring closer parts of structure description.
39 const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
40 const asn_TYPE_member_t *element = td->elements;
42 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
45 * ... and parts of the structure being constructed.
47 void *st = *struct_ptr; /* Target structure. */
48 asn_struct_ctx_t *ctx; /* Decoder context */
50 asn_dec_rval_t rval = {RC_OK, 0}; /* Return value from a decoder */
51 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
54 * Create the target structure if it is not present already.
57 st = *struct_ptr = CALLOC(1, specs->struct_size);
58 if(st == 0) RETURN(RC_FAIL);
61 /* Which tag is expected for the downstream */
62 if(specs->as_XMLValueList) {
63 elm_tag = (specs->as_XMLValueList == 1) ? 0 : "";
65 elm_tag = (*element->name)
66 ? element->name : element->type->xml_tag;
70 * Restore parsing context.
72 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
75 * Phases of XER/XML processing:
76 * Phase 0: Check that the opening tag matches our expectations.
77 * Phase 1: Processing body and reacting on closing tag.
78 * Phase 2: Processing inner type.
80 for(; ctx->phase <= 2;) {
81 pxer_chunk_type_e ch_type; /* XER chunk type */
82 ssize_t ch_size; /* Chunk size */
83 xer_check_tag_e tcv; /* Tag check value */
86 * Go inside the inner member of a set.
89 asn_dec_rval_t tmprval = {RC_OK, 0};
91 /* Invoke the inner type decoder, m.b. multiple times */
92 ASN_DEBUG("XER/SET OF element [%s]", elm_tag);
93 tmprval = element->type->op->xer_decoder(opt_codec_ctx,
97 if(tmprval.code == RC_OK) {
98 asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
99 if(ASN_SET_ADD(list, ctx->ptr) != 0)
102 XER_ADVANCE(tmprval.consumed);
104 XER_ADVANCE(tmprval.consumed);
105 RETURN(tmprval.code);
107 ctx->phase = 1; /* Back to body processing */
108 ASN_DEBUG("XER/SET OF phase => %d", ctx->phase);
113 * Get the next part of the XML stream.
115 ch_size = xer_next_token(&ctx->context,
116 buf_ptr, size, &ch_type);
123 case PXER_COMMENT: /* Got XML comment */
124 case PXER_TEXT: /* Ignore free-standing text */
125 XER_ADVANCE(ch_size); /* Skip silently */
128 break; /* Check the rest down there */
132 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
133 ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s",
134 tcv, ctx->phase, xml_tag);
137 if(ctx->phase == 0) break;
141 if(ctx->phase == 0) {
142 /* No more things to decode */
143 XER_ADVANCE(ch_size);
144 ctx->phase = 3; /* Phase out */
149 if(ctx->phase == 0) {
150 XER_ADVANCE(ch_size);
151 ctx->phase = 1; /* Processing body phase */
158 ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase);
159 if(ctx->phase == 1) {
161 * Process a single possible member.
171 ASN_DEBUG("Unexpected XML tag in SET OF");
175 ctx->phase = 3; /* "Phase out" on hard failure */
179 typedef struct xer_tmp_enc_s {
186 SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) {
187 xer_tmp_enc_t *t = (xer_tmp_enc_t *)key;
188 if(t->offset + size >= t->size) {
189 size_t newsize = (t->size << 2) + size;
190 void *p = REALLOC(t->buffer, newsize);
195 memcpy((char *)t->buffer + t->offset, buffer, size);
201 SET_OF_xer_order(const void *aptr, const void *bptr) {
202 const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr;
203 const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr;
204 size_t minlen = a->offset;
206 if(b->offset < minlen) minlen = b->offset;
207 /* Well-formed UTF-8 has this nice lexicographical property... */
208 ret = memcmp(a->buffer, b->buffer, minlen);
209 if(ret != 0) return ret;
210 if(a->offset == b->offset)
212 if(a->offset == minlen)
218 SET_OF_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
219 enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb,
221 asn_enc_rval_t er = {0,0,0};
222 const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
223 const asn_TYPE_member_t *elm = td->elements;
224 const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr);
225 const char *mname = specs->as_XMLValueList
226 ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag);
227 size_t mlen = mname ? strlen(mname) : 0;
228 int xcan = (flags & XER_F_CANONICAL);
229 xer_tmp_enc_t *encs = 0;
230 size_t encs_count = 0;
231 void *original_app_key = app_key;
232 asn_app_consume_bytes_f *original_cb = cb;
235 if(!sptr) ASN__ENCODE_FAILED;
238 encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0]));
239 if(!encs) ASN__ENCODE_FAILED;
240 cb = SET_OF_encode_xer_callback;
245 for(i = 0; i < list->count; i++) {
246 asn_enc_rval_t tmper = {0,0,0};
248 void *memb_ptr = list->array[i];
249 if(!memb_ptr) continue;
252 memset(&encs[encs_count], 0, sizeof(encs[0]));
253 app_key = &encs[encs_count];
258 if(!xcan) ASN__TEXT_INDENT(1, ilevel);
259 ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
262 if(!xcan && specs->as_XMLValueList == 1)
263 ASN__TEXT_INDENT(1, ilevel + 1);
264 tmper = elm->type->op->xer_encoder(elm->type, memb_ptr,
265 ilevel + (specs->as_XMLValueList != 2),
267 if(tmper.encoded == -1) return tmper;
268 er.encoded += tmper.encoded;
269 if(tmper.encoded == 0 && specs->as_XMLValueList) {
270 const char *name = elm->type->xml_tag;
271 size_t len = strlen(name);
272 ASN__CALLBACK3("<", 1, name, len, "/>", 2);
276 ASN__CALLBACK3("</", 2, mname, mlen, ">", 1);
281 if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1);
284 xer_tmp_enc_t *enc = encs;
285 xer_tmp_enc_t *end = encs + encs_count;
286 ssize_t control_size = 0;
290 app_key = original_app_key;
291 qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order);
293 for(; enc < end; enc++) {
294 ASN__CALLBACK(enc->buffer, enc->offset);
295 FREEMEM(enc->buffer);
297 control_size += enc->offset;
299 assert(control_size == er.encoded);
308 for(n = 0; n < encs_count; n++) {
309 FREEMEM(encs[n].buffer);