2  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
 
   3  * Redistribution and modifications are permitted subject to BSD license.
 
   5 #include <asn_internal.h>
 
   8 static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
 
   9         asn_app_consume_bytes_f *cb, void *app_key, int constructed);
 
  12  * The DER encoder of any type.
 
  15 der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
 
  16         asn_app_consume_bytes_f *consume_bytes, void *app_key) {
 
  18         ASN_DEBUG("DER encoder invoked for %s",
 
  19                 type_descriptor->name);
 
  22          * Invoke type-specific encoder.
 
  24         return type_descriptor->der_encoder(type_descriptor,
 
  25                 struct_ptr,     /* Pointer to the destination structure */
 
  27                 consume_bytes, app_key);
 
  31  * Argument type and callback necessary for der_encode_to_buffer().
 
  33 typedef struct enc_to_buf_arg {
 
  37 static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
 
  38         enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
 
  41                 return -1;      /* Data exceeds the available buffer size */
 
  43         memcpy(arg->buffer, buffer, size);
 
  44         arg->buffer = ((char *)arg->buffer) + size;
 
  51  * A variant of the der_encode() which encodes the data into the provided buffer
 
  54 der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
 
  55         void *buffer, size_t buffer_size) {
 
  60         arg.left = buffer_size;
 
  62         ec = type_descriptor->der_encoder(type_descriptor,
 
  63                 struct_ptr,     /* Pointer to the destination structure */
 
  64                 0, 0, encode_to_buffer_cb, &arg);
 
  65         if(ec.encoded != -1) {
 
  66                 assert(ec.encoded == (ssize_t)(buffer_size - arg.left));
 
  67                 /* Return the encoded contents size */
 
  74  * Write out leading TL[v] sequence according to the type definition.
 
  77 der_write_tags(asn_TYPE_descriptor_t *sd,
 
  79                 int tag_mode, int last_tag_form,
 
  80                 ber_tlv_tag_t tag,      /* EXPLICIT or IMPLICIT tag */
 
  81                 asn_app_consume_bytes_f *cb,
 
  83         ber_tlv_tag_t *tags;    /* Copy of tags stream */
 
  84         int tags_count;         /* Number of tags */
 
  85         size_t overall_length;
 
  89         ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
 
  90                 sd->name, tag_mode, sd->tags_count,
 
  91                 ber_tlv_tag_string(tag),
 
  94                                 -((tag_mode == -1) && sd->tags_count))
 
 100                  * Instead of doing shaman dance like we do in ber_check_tags(),
 
 101                  * allocate a small array on the stack
 
 102                  * and initialize it appropriately.
 
 105                 tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
 
 106                 if(!tags) {     /* Can fail on !x86 */
 
 110                 tags_count = sd->tags_count
 
 111                         + 1     /* EXPLICIT or IMPLICIT tag is given */
 
 112                         - ((tag_mode == -1) && sd->tags_count);
 
 115                 stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
 
 116                 for(i = 1; i < tags_count; i++)
 
 117                         tags[i] = sd->tags[i + stag_offset];
 
 120                 tags_count = sd->tags_count;
 
 123         /* No tags to write */
 
 127         lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
 
 134          * Array of tags is initialized.
 
 135          * Now, compute the size of the TLV pairs, from right to left.
 
 137         overall_length = struct_length;
 
 138         for(i = tags_count - 1; i >= 0; --i) {
 
 139                 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
 
 140                 if(lens[i] == -1) return -1;
 
 141                 overall_length += lens[i];
 
 142                 lens[i] = overall_length - lens[i];
 
 145         if(!cb) return overall_length - struct_length;
 
 147         ASN_DEBUG("%s %s TL sequence (%d elements)",
 
 148                 cb?"Encoding":"Estimating", sd->name, tags_count);
 
 151          * Encode the TL sequence for real.
 
 153         for(i = 0; i < tags_count; i++) {
 
 157                 /* Check if this tag happens to be constructed */
 
 158                 _constr = (last_tag_form || i < (tags_count - 1));
 
 160                 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
 
 161                 if(len == -1) return -1;
 
 164         return overall_length - struct_length;
 
 168 der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
 
 169                 asn_app_consume_bytes_f *cb, void *app_key,
 
 173         int buf_size = cb?sizeof(buf):0;
 
 176         /* Serialize tag (T from TLV) into possibly zero-length buffer */
 
 177         tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
 
 178         if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
 
 181         /* Serialize length (L from TLV) into possibly zero-length buffer */
 
 182         tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
 
 183         if(tmp == -1) return -1;
 
 186         if(size > sizeof(buf))
 
 190          * If callback is specified, invoke it, and check its return value.
 
 193                 if(constructed) *buf |= 0x20;
 
 194                 if(cb(buf, size, app_key) < 0)