Commit 62258e25 authored by Lev Walkin's avatar Lev Walkin

extensibility in SEQUENCE uper writer

parent 788490db
...@@ -212,6 +212,35 @@ xer_encoding_equal(char *obuf, size_t osize, char *nbuf, size_t nsize) { ...@@ -212,6 +212,35 @@ xer_encoding_equal(char *obuf, size_t osize, char *nbuf, size_t nsize) {
return 1; return 1;
} }
static void
compare_with_data_out(const char *fname, char *buf, int size) {
char outName[256];
char fbuf[1024];
size_t rd;
FILE *f;
sprintf(outName, "../data-126/%s", fname);
strcpy(outName + strlen(outName) - 3, ".out");
fprintf(stderr, "Comparing PER output with [%s]\n", outName);
f = fopen(outName, "r");
if(f) {
assert(f);
rd = fread(fbuf, 1, sizeof(fbuf), f);
assert(rd);
fclose(f);
assert(rd == size);
assert(memcmp(fbuf, buf, rd) == 0);
fprintf(stderr, "XER->PER recoding .in->.out match.\n");
} else if(getenv("REGENERATE")) {
f = fopen(outName, "w");
fwrite(buf, 1, size, f);
fclose(f);
}
}
static void static void
process_XER_data(const char *fname, char *fbuf, int size) { process_XER_data(const char *fname, char *fbuf, int size) {
PDU_t *st; PDU_t *st;
...@@ -220,8 +249,9 @@ process_XER_data(const char *fname, char *fbuf, int size) { ...@@ -220,8 +249,9 @@ process_XER_data(const char *fname, char *fbuf, int size) {
st = load_object_from(fname, fbuf, size, AS_XER); st = load_object_from(fname, fbuf, size, AS_XER);
if(!st) return; if(!st) return;
/* Save and re-load as DER */ /* Save and re-load as PER */
save_object_as(st, AS_PER); save_object_as(st, AS_PER);
compare_with_data_out(fname, buf, buf_offset);
st = load_object_from("buffer", buf, buf_offset, AS_PER); st = load_object_from("buffer", buf, buf_offset, AS_PER);
assert(st); assert(st);
......
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
* All rights reserved. * All rights reserved.
* Redistribution and modifications are permitted subject to BSD license. * Redistribution and modifications are permitted subject to BSD license.
*/ */
...@@ -1162,12 +1162,87 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ...@@ -1162,12 +1162,87 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
return rv; return rv;
} }
/*
* #10.1, #10.2
*/
static int
uper_put_open_type(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
void *buf;
ssize_t size;
size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
if(size <= 0) return -1;
while(size) {
ssize_t maySave = uper_put_length(po, size);
if(maySave < 0) break;
if(per_put_many_bits(po, buf, maySave * 8)) break;
buf = (char *)buf + maySave;
size -= maySave;
}
if(size) {
FREEMEM(buf);
return -1;
}
return 0;
}
static int
SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr,
asn_per_outp_t *po1, asn_per_outp_t *po2) {
asn_SEQUENCE_specifics_t *specs
= (asn_SEQUENCE_specifics_t *)td->specifics;
int num = 0;
int edx;
if(specs->ext_before < 0)
return 0;
/* Find out which extensions are present */
for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) {
asn_TYPE_member_t *elm = &td->elements[edx];
void *memb_ptr; /* Pointer to the member */
void **memb_ptr2; /* Pointer to that pointer */
int present;
if(!IN_EXTENSION_GROUP(specs, edx))
continue;
/* Fetch the pointer to this member */
if(elm->flags & ATF_POINTER) {
memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
present = (*memb_ptr2 != 0);
} else {
memb_ptr = (void *)((char *)sptr + elm->memb_offset);
memb_ptr2 = &memb_ptr;
present = 1;
}
ASN_DEBUG("checking ext %d is present => %d", edx, present);
num += present;
/* Encode as presence marker */
if(po1 && per_put_few_bits(po1, present, 1))
return -1;
/* Encode as open type field */
if(po2 && present && uper_put_open_type(elm->type,
elm->per_constraints, *memb_ptr2, po2))
return -1;
}
return num;
}
asn_enc_rval_t asn_enc_rval_t
SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
asn_SEQUENCE_specifics_t *specs asn_SEQUENCE_specifics_t *specs
= (asn_SEQUENCE_specifics_t *)td->specifics; = (asn_SEQUENCE_specifics_t *)td->specifics;
asn_enc_rval_t er; asn_enc_rval_t er;
int n_extensions;
int edx; int edx;
int i; int i;
...@@ -1179,8 +1254,18 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1179,8 +1254,18 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
er.encoded = 0; er.encoded = 0;
ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name);
if(specs->ext_before >= 0)
_ASN_ENCODE_FAILED; /* We don't encode extensions yet */
/*
* X.691#18.1 Whether structure is extensible
* and whether to encode extensions
*/
if(specs->ext_before >= 0) {
n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0);
per_put_few_bits(po, n_extensions ? 1 : 0, 1);
} else {
n_extensions = 0; /* There are no extensions to encode */
}
/* Encode a presence bitmap */ /* Encode a presence bitmap */
for(i = 0; i < specs->roms_count; i++) { for(i = 0; i < specs->roms_count; i++) {
...@@ -1216,10 +1301,11 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1216,10 +1301,11 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
} }
/* /*
* Get the sequence ROOT elements. * Encode the sequence ROOT elements.
*/ */
ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before);
for(edx = 0; edx < ((specs->ext_before < 0) for(edx = 0; edx < ((specs->ext_before < 0)
? td->elements_count : specs->ext_before - 1); edx++) { ? td->elements_count : specs->ext_after); edx++) {
asn_TYPE_member_t *elm = &td->elements[edx]; asn_TYPE_member_t *elm = &td->elements[edx];
void *memb_ptr; /* Pointer to the member */ void *memb_ptr; /* Pointer to the member */
void **memb_ptr2; /* Pointer to that pointer */ void **memb_ptr2; /* Pointer to that pointer */
...@@ -1244,12 +1330,32 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -1244,12 +1330,32 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) if(elm->default_value && elm->default_value(0, memb_ptr2) == 1)
continue; continue;
ASN_DEBUG("encoding root %d", edx);
er = elm->type->uper_encoder(elm->type, elm->per_constraints, er = elm->type->uper_encoder(elm->type, elm->per_constraints,
*memb_ptr2, po); *memb_ptr2, po);
if(er.encoded == -1) if(er.encoded == -1)
return er; return er;
} }
/* No extensions to encode */
if(!n_extensions) _ASN_ENCODED_OK(er);
ASN_DEBUG("Length of %d bit-map", n_extensions);
/* #18.8. Write down the presence bit-map length. */
if(uper_put_nslength(po, n_extensions))
_ASN_ENCODE_FAILED;
ASN_DEBUG("Bit-map of %d elements", n_extensions);
/* #18.7. Encoding the extensions presence bit-map. */
/* TODO: act upon NOTE in #18.7 for canonical PER */
if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions)
_ASN_ENCODE_FAILED;
ASN_DEBUG("Writing %d extensions", n_extensions);
/* #18.9. Encode extensions as open type fields. */
if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions)
_ASN_ENCODE_FAILED;
_ASN_ENCODED_OK(er); _ASN_ENCODED_OK(er);
} }
...@@ -2,41 +2,11 @@ ...@@ -2,41 +2,11 @@
#include <asn_internal.h> #include <asn_internal.h>
#include <per_encoder.h> #include <per_encoder.h>
/* Flush partially filled buffer */ static 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);
static int _uper_encode_flush_outp(asn_per_outp_t *po);
asn_enc_rval_t asn_enc_rval_t
uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
asn_per_outp_t po; return uper_encode_internal(td, 0, sptr, cb, app_key);
asn_enc_rval_t er;
/*
* Invoke type-specific encoder.
*/
if(!td || !td->uper_encoder)
_ASN_ENCODE_FAILED; /* PER is not compiled in */
po.buffer = po.tmpspace;
po.nboff = 0;
po.nbits = 8 * sizeof(po.tmpspace);
po.outper = cb;
po.op_key = app_key;
po.flushed_bytes = 0;
er = td->uper_encoder(td, 0, sptr, &po);
if(er.encoded != -1) {
size_t bits_to_flush;
bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
/* Set number of bits encoded to a firm value */
er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
if(_uper_encode_flush_outp(&po))
_ASN_ENCODE_FAILED;
}
return er;
} }
/* /*
...@@ -63,20 +33,70 @@ asn_enc_rval_t ...@@ -63,20 +33,70 @@ asn_enc_rval_t
uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) {
enc_to_buf_arg key; enc_to_buf_arg key;
/*
* Invoke type-specific encoder.
*/
if(!td || !td->uper_encoder)
_ASN_ENCODE_FAILED; /* PER is not compiled in */
key.buffer = buffer; key.buffer = buffer;
key.left = buffer_size; key.left = buffer_size;
ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);
return uper_encode(td, sptr, encode_to_buffer_cb, &key); return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
} }
typedef struct enc_dyn_arg {
void *buffer;
size_t length;
size_t allocated;
} enc_dyn_arg;
static int
encode_dyn_cb(const void *buffer, size_t size, void *key) {
enc_dyn_arg *arg = key;
if(arg->length + size >= arg->allocated) {
void *p;
arg->allocated = arg->allocated ? (arg->allocated << 2) : size;
p = REALLOC(arg->buffer, arg->allocated);
if(!p) {
FREEMEM(arg->buffer);
memset(arg, 0, sizeof(*arg));
return -1;
}
arg->buffer = p;
}
memcpy(((char *)arg->buffer) + arg->length, buffer, size);
arg->length += size;
return 0;
}
ssize_t
uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) {
asn_enc_rval_t er;
enc_dyn_arg key;
memset(&key, 0, sizeof(key));
er = uper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key);
switch(er.encoded) {
case -1:
FREEMEM(key.buffer);
return -1;
case 0:
FREEMEM(key.buffer);
key.buffer = MALLOC(1);
if(key.buffer) {
*(char *)key.buffer = '\0';
*buffer_r = key.buffer;
return 1;
} else {
return -1;
}
default:
*buffer_r = key.buffer;
return ((er.encoded + 7) >> 3);
}
}
/*
* Internally useful functions.
*/
/* Flush partially filled buffer */
static int static int
_uper_encode_flush_outp(asn_per_outp_t *po) { _uper_encode_flush_outp(asn_per_outp_t *po) {
uint8_t *buf; uint8_t *buf;
...@@ -93,3 +113,38 @@ _uper_encode_flush_outp(asn_per_outp_t *po) { ...@@ -93,3 +113,38 @@ _uper_encode_flush_outp(asn_per_outp_t *po) {
return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
} }
static asn_enc_rval_t
uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
asn_per_outp_t po;
asn_enc_rval_t er;
/*
* Invoke type-specific encoder.
*/
if(!td || !td->uper_encoder)
_ASN_ENCODE_FAILED; /* PER is not compiled in */
po.buffer = po.tmpspace;
po.nboff = 0;
po.nbits = 8 * sizeof(po.tmpspace);
po.outper = cb;
po.op_key = app_key;
po.flushed_bytes = 0;
er = td->uper_encoder(td, constraints, sptr, &po);
if(er.encoded != -1) {
size_t bits_to_flush;
bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
/* Set number of bits encoded to a firm value */
er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
if(_uper_encode_flush_outp(&po))
_ASN_ENCODE_FAILED;
}
return er;
}
...@@ -16,6 +16,9 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ ...@@ -16,6 +16,9 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */
/* /*
* Unaligned PER encoder of any ASN.1 type. May be invoked by the application. * Unaligned PER encoder of any ASN.1 type. May be invoked by the application.
* WARNING: This function returns the number of encoded bits in the .encoded
* field of the return value. Use the following formula to convert to bytes:
* bytes = ((.encoded + 7) / 8)
*/ */
asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor,
void *struct_ptr, /* Structure to be encoded */ void *struct_ptr, /* Structure to be encoded */
...@@ -23,7 +26,11 @@ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, ...@@ -23,7 +26,11 @@ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor,
void *app_key /* Arbitrary callback argument */ void *app_key /* Arbitrary callback argument */
); );
/* A variant of uper_encode() which encodes data into the existing buffer */ /*
* A variant of uper_encode() which encodes data into the existing buffer
* WARNING: This function returns the number of encoded bits in the .encoded
* field of the return value.
*/
asn_enc_rval_t uper_encode_to_buffer( asn_enc_rval_t uper_encode_to_buffer(
struct asn_TYPE_descriptor_s *type_descriptor, struct asn_TYPE_descriptor_s *type_descriptor,
void *struct_ptr, /* Structure to be encoded */ void *struct_ptr, /* Structure to be encoded */
...@@ -31,6 +38,19 @@ asn_enc_rval_t uper_encode_to_buffer( ...@@ -31,6 +38,19 @@ asn_enc_rval_t uper_encode_to_buffer(
size_t buffer_size /* Initial buffer size (max) */ size_t buffer_size /* Initial buffer size (max) */
); );
/*
* A variant of uper_encode_to_buffer() which allocates buffer itself.
* Returns the number of bytes in the buffer or -1 in case of failure.
* WARNING: This function produces a "Production of the complete encoding",
* with length of at least one octet. Contrast this to precise bit-preserving
* encoding of uper_encode() and uper_encode_to_buffer().
*/
ssize_t uper_encode_to_new_buffer(
struct asn_TYPE_descriptor_s *type_descriptor,
asn_per_constraints_t *constraints,
void *struct_ptr, /* Structure to be encoded */
void **buffer_r /* Buffer allocated and returned */
);
/* /*
* Type of the generic PER encoder function. * Type of the generic PER encoder function.
......
...@@ -318,3 +318,26 @@ uper_put_length(asn_per_outp_t *po, size_t length) { ...@@ -318,3 +318,26 @@ uper_put_length(asn_per_outp_t *po, size_t length) {
? -1 : (ssize_t)(length << 14); ? -1 : (ssize_t)(length << 14);
} }
/*
* Put the normally small length "n" into the stream.
* This procedure used to encode length of extensions bit-maps
* for SET and SEQUENCE types.
*/
int
uper_put_nslength(asn_per_outp_t *po, size_t length) {
if(length <= 64) {
/* #10.9.3.4 */
if(length == 0) return -1;
return per_put_few_bits(po, length-1, 7) ? -1 : 0;
} else {
if(uper_put_length(po, length) != length) {
/* This might happen in case of >16K extensions */
return -1;
}
}
return 0;
}
...@@ -95,6 +95,12 @@ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); ...@@ -95,6 +95,12 @@ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits);
*/ */
ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length);
/*
* Put the normally small length "n" to the Unaligned PER stream.
* Returns 0 or -1.
*/
int uper_put_nslength(asn_per_outp_t *po, size_t length);
/* /*
* Put the normally small non-negative whole number. * Put the normally small non-negative whole number.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment