/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * The XER encoder of any type. May be invoked by the application. */ asn_enc_rval_t xer_encode(const asn_TYPE_descriptor_t *td, const void *sptr, enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *cb, void *app_key) { asn_enc_rval_t er = {0, 0, 0}; asn_enc_rval_t tmper; const char *mname; size_t mlen; int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; if(!td || !sptr) goto cb_failed; mname = td->xml_tag; mlen = strlen(mname); ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); tmper = td->op->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); if(tmper.encoded == -1) return tmper; er.encoded += tmper.encoded; ASN__CALLBACK3("\n", xcan); ASN__ENCODED_OK(er); cb_failed: ASN__ENCODE_FAILED; } /* * This is a helper function for xer_fprint, which directs all incoming data * into the provided file descriptor. */ static int xer__print2fp(const void *buffer, size_t size, void *app_key) { FILE *stream = (FILE *)app_key; if(fwrite(buffer, 1, size, stream) != size) return -1; return 0; } int xer_fprint(FILE *stream, const asn_TYPE_descriptor_t *td, const void *sptr) { asn_enc_rval_t er = {0,0,0}; if(!stream) stream = stdout; if(!td || !sptr) return -1; er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); if(er.encoded == -1) return -1; return fflush(stream); } struct xer_buffer { char *buffer; size_t buffer_size; size_t allocated_size; }; static int xer__buffer_append(const void *buffer, size_t size, void *app_key) { struct xer_buffer *xb = app_key; while(xb->buffer_size + size + 1 > xb->allocated_size) { size_t new_size = 2 * (xb->allocated_size ? xb->allocated_size : 64); char *new_buf = MALLOC(new_size); if(!new_buf) return -1; if (xb->buffer) { memcpy(new_buf, xb->buffer, xb->buffer_size); } FREEMEM(xb->buffer); xb->buffer = new_buf; xb->allocated_size = new_size; } memcpy(xb->buffer + xb->buffer_size, buffer, size); xb->buffer_size += size; xb->buffer[xb->buffer_size] = '\0'; return 0; } enum xer_equivalence_e xer_equivalent(const struct asn_TYPE_descriptor_s *td, const void *struct1, const void *struct2, FILE *opt_debug_stream) { struct xer_buffer xb1 = {0, 0, 0}; struct xer_buffer xb2 = {0, 0, 0}; asn_enc_rval_t e1, e2; asn_dec_rval_t rval; void *sptr = NULL; if(!td || !struct1 || !struct2) { if(opt_debug_stream) { if(!td) fprintf(opt_debug_stream, "Type descriptor missing\n"); if(!struct1) fprintf(opt_debug_stream, "Structure 1 missing\n"); if(!struct2) fprintf(opt_debug_stream, "Structure 2 missing\n"); } return XEQ_FAILURE; } e1 = xer_encode(td, struct1, XER_F_BASIC, xer__buffer_append, &xb1); if(e1.encoded == -1) { if(opt_debug_stream) { fprintf(stderr, "XER Encoding of %s failed\n", td->name); } FREEMEM(xb1.buffer); return XEQ_ENCODE1_FAILED; } e2 = xer_encode(td, struct2, XER_F_BASIC, xer__buffer_append, &xb2); if(e2.encoded == -1) { if(opt_debug_stream) { fprintf(stderr, "XER Encoding of %s failed\n", td->name); } FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_ENCODE1_FAILED; } if(xb1.buffer_size != xb2.buffer_size || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) { if(opt_debug_stream) { fprintf(opt_debug_stream, "Structures XER-encoded into different byte streams:\n=== " "Structure 1 ===\n%s\n=== Structure 2 ===\n%s\n", xb1.buffer, xb2.buffer); } FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_DIFFERENT; } else { if(opt_debug_stream) { fprintf(opt_debug_stream, "Both structures encoded into the same XER byte stream " "of size %" ASN_PRI_SIZE ":\n%s", xb1.buffer_size, xb1.buffer); } } rval = xer_decode(NULL, td, (void **)&sptr, xb1.buffer, xb1.buffer_size); switch(rval.code) { case RC_OK: break; case RC_WMORE: if(opt_debug_stream) { fprintf(opt_debug_stream, "Structure %s XER decode unexpectedly requires " "more data:\n%s\n", td->name, xb1.buffer); } /* Fall through */ case RC_FAIL: default: if(opt_debug_stream) { fprintf(opt_debug_stream, "Structure %s XER decoding resulted in failure.\n", td->name); } ASN_STRUCT_FREE(*td, sptr); FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_DECODE_FAILED; } if(rval.consumed != xb1.buffer_size && ((rval.consumed > xb1.buffer_size) || xer_whitespace_span(xb1.buffer + rval.consumed, xb1.buffer_size - rval.consumed) != (xb1.buffer_size - rval.consumed))) { if(opt_debug_stream) { fprintf(opt_debug_stream, "Round-trip decode of %s required less bytes (%" ASN_PRI_SIZE ") than " "encoded (%" ASN_PRI_SIZE ")\n", td->name, rval.consumed, xb1.buffer_size); } ASN_STRUCT_FREE(*td, sptr); FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_ROUND_TRIP_FAILED; } /* * Reuse xb2 to encode newly decoded structure. */ FREEMEM(xb2.buffer); memset(&xb2, 0, sizeof(xb2)); e2 = xer_encode(td, sptr, XER_F_BASIC, xer__buffer_append, &xb2); if(e2.encoded == -1) { if(opt_debug_stream) { fprintf(stderr, "XER Encoding of round-trip decode of %s failed\n", td->name); } ASN_STRUCT_FREE(*td, sptr); FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_ROUND_TRIP_FAILED; } ASN_STRUCT_FREE(*td, sptr); sptr = 0; if(xb1.buffer_size != xb2.buffer_size || memcmp(xb1.buffer, xb2.buffer, xb1.buffer_size) != 0) { if(opt_debug_stream) { fprintf(opt_debug_stream, "XER Encoding of round-trip decode of %s resulted in " "different byte stream:\n" "=== Original ===\n%s\n" "=== Round-tripped ===\n%s\n", xb1.buffer, xb2.buffer, td->name); } FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_ROUND_TRIP_FAILED; } FREEMEM(xb1.buffer); FREEMEM(xb2.buffer); return XEQ_SUCCESS; }