/*---------------------------------------------------------------------------*/
/* asn1.cpp                                                                  */
/* copyright (c) innovaphone 1997, 1998                                      */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>
#include "../ilib/asn1.h"

NAMESPACE_BEGIN;

asn1_context::asn1_context(struct asn1_tag * tag_buffer, int tag_buffer_size, void * content_buffer, int content_buffer_size, bool trace)
{
    this->tag_buffer = tag_buffer;
    this->tag_buffer_size = tag_buffer_size;
    this->content_buffer = (byte *)content_buffer;
    this->content_buffer_size = content_buffer_size;
    this->trace = trace;
    tag_index = 0;
    content_index = 0;
    seq_of = 0;
    seq_mask = 0xffff;
    level = 0;
    fix_mask = 0;
}

struct asn1_tag * asn1_context::new_tag(word tag)
{
    if(tag_index>=(int)(tag_buffer_size/sizeof(asn1_tag))) {tag_index=(tag_buffer_size/sizeof(asn1_tag))+1;return 0;}
    tag_buffer[tag_index].tag = seq_of|tag;
    tag_buffer[tag_index].content = 0;
    return &tag_buffer[tag_index++];
}

struct asn1_tag * asn1_context::new_tag(word tag, int size, dword align)
{
    if(tag_index>=(int)(tag_buffer_size/sizeof(asn1_tag))) {tag_index=(tag_buffer_size/sizeof(asn1_tag))+1;return 0;}
    tag_buffer[tag_index].tag = seq_of|tag;
    content_index +=align;
    content_index &=~align;
    tag_buffer[tag_index].content = &content_buffer[content_index];
    content_index += size;
    if(content_index>=(int(content_buffer_size))) {content_index=content_buffer_size+1;return 0;}
    return &tag_buffer[tag_index++];
}

struct asn1_tag * asn1_context::find_tag(word tag)
{
    int i;
    for(i=tag_index; i && tag_buffer[i-1].tag!=(seq_of|tag); i--);
    if(i==0) return 0;
    return &tag_buffer[i-1];
}

void asn1_context::set_seq(int num)
{
    seq_of &=seq_mask;
    seq_of |= num * ((~seq_mask) & (seq_mask<<1));
}

dword asn1_context::get_mask()
{
    return seq_mask;
}

dword asn1_context::set_mask(dword mask)
{
    dword m = seq_mask;
    seq_mask = mask|0xffff;
    return m;
}

asn1::asn1(int & tag, const char * name)
{
    this->tag = tag++;
    this->name = name;
}

bool asn1::is_present(class asn1_context & context)
{
    if(context.find_tag(tag)) return true;
    return false;
}

/*---------------------------------------------------------------------------*/
/* NULL                                                                      */
/*---------------------------------------------------------------------------*/

asn1_null::asn1_null(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_NULL;
}

void asn1_null::put_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;
}

/*---------------------------------------------------------------------------*/
/* BOOLEAN                                                                   */
/*---------------------------------------------------------------------------*/

asn1_boolean::asn1_boolean(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_BOOLEAN;
}

bool asn1_boolean::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return false;

	bool * t = (bool *)&b->content;
	return *t;
}

void asn1_boolean::put_content(class asn1_context & context, bool content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

	bool * t = (bool *)&b->content;
    *t = content;
}

/*---------------------------------------------------------------------------*/
/* INT                                                                       */
/*---------------------------------------------------------------------------*/

asn1_int::asn1_int(int & tag, const char * name, byte count_bits) : asn1(tag,name)
{
    type = ASN1_TYPE_INT;
    this->count_bits = count_bits;
}

dword asn1_int::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_int::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* INT (signed)                                                              */
/*---------------------------------------------------------------------------*/

asn1_ints::asn1_ints(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_INTS;
}

int asn1_ints::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(int *)p;
}

void asn1_ints::put_content(class asn1_context & context, int content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(int *)p = content;
}

/*---------------------------------------------------------------------------*/
/* INTE                                                                      */
/*---------------------------------------------------------------------------*/

asn1_inte::asn1_inte(int & tag, const char * name, byte count_bits, dword max) : asn1(tag,name)
{
    type = ASN1_TYPE_INTE;
    this->count_bits = count_bits;
    this->max = max;
}

dword asn1_inte::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_inte::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* INT8                                                                      */
/*---------------------------------------------------------------------------*/

asn1_int8::asn1_int8(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_INT8;
}

dword asn1_int8::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_int8::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* INT16                                                                     */
/*---------------------------------------------------------------------------*/

asn1_int16::asn1_int16(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_INT16;
}

dword asn1_int16::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_int16::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* BITSTRING                                                                 */
/*---------------------------------------------------------------------------*/

asn1_bitstring::asn1_bitstring(int & tag, const char * name, int min_length, int max_length, int len_bits) : asn1(tag,name)
{
    type = ASN1_TYPE_BITSTRING;
    this->min_length = min_length;
    this->max_length = max_length;
    this->len_bits = len_bits;
}

byte * asn1_bitstring::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct octet_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_bitstring::put_content(class asn1_context & context, byte * s, int length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+(length+7)/8,3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    memcpy(c->b,s,(length+7)/8);

    c->len = length;
    c->b_ptr = c->b;
}

#if !defined(PLATFORM_NO_PACKET)
word asn1_bitstring::get_offset(class asn1_context & context, class packet * data)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) return 0;
    c = (struct octet_string_buffer *)b->content;
    class packet_ptr ptr;
    ptr.restore(c->in_buffer, c->in_offset);
    int left = data->read(&ptr, 0, 0xffff);
    return data->length() - left;
}
#endif

/*---------------------------------------------------------------------------*/
/* ENUMERATED                                                                */
/*---------------------------------------------------------------------------*/

asn1_enumerated::asn1_enumerated(int & tag, const char * name, byte properties, byte count, byte count_bits) : asn1(tag,name)
{
    type = ASN1_TYPE_ENUMERATED;
    this->properties = properties;
    this->count = count;
    this->count_bits = count_bits;
}

dword asn1_enumerated::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_enumerated::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* OCTET_ARRAY                                                               */
/*---------------------------------------------------------------------------*/

asn1_octet_array::asn1_octet_array(int & tag, const char * name, word length) : asn1(tag,name)
{
    type = ASN1_TYPE_OCTET_ARRAY;
    this->length=length;
}

byte * asn1_octet_array::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    return (byte *)b->content;
}

void asn1_octet_array::put_content(class asn1_context & context, byte * content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    b->content = content;
}

/*---------------------------------------------------------------------------*/
/* IA5_STRING                                                                */
/*---------------------------------------------------------------------------*/

asn1_ia5_string::asn1_ia5_string(int & tag, const char * name, int min_length, int max_length, byte len_bits, byte char_bits, const char * from) : asn1(tag,name)
{
    type = ASN1_TYPE_IA5_STRING;
    this->min_length = min_length;
    this->max_length = max_length;
    this->len_bits = len_bits;
    this->char_bits = char_bits;
    this->from = from;
}

byte * asn1_ia5_string::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct octet_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_ia5_string::put_content(class asn1_context & context, byte * s, int length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+length,3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    memcpy(c->b,s,length);

    c->len = length;
    c->b_ptr = c->b;
}

/*---------------------------------------------------------------------------*/
/* OCTET_STRING                                                              */
/*---------------------------------------------------------------------------*/

asn1_octet_string::asn1_octet_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : asn1(tag,name)
{
    std_tag = ASN1_TAG_UNIVERSAL_OCTETSTRING;
	type = ASN1_TYPE_OCTET_STRING;
	this->min_length = min_length;
    this->max_length = max_length;
    this->len_bits = len_bits;
}

byte * asn1_octet_string::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct octet_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_octet_string::put_content(class asn1_context & context, byte * s, int length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+length,3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    memcpy(c->b,s,length);

    c->len = length;
    c->b_ptr = c->b;
}

#if !defined(PLATFORM_NO_PACKET)
void asn1_octet_string::put_content(class asn1_context & context, class packet * data)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+data->length(),3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    data->look_head(c->b,data->length());

    c->len = data->length();
    c->b_ptr = c->b;
}
#endif

/*---------------------------------------------------------------------------*/
/* NUMERIC_STRING                                                            */
/*---------------------------------------------------------------------------*/

asn1_numeric_string::asn1_numeric_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : asn1(tag,name)
{
    type = ASN1_TYPE_NUMERIC_STRING;
    this->min_length = min_length;
    this->max_length = max_length;
    this->len_bits = len_bits;
}

byte * asn1_numeric_string::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct octet_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_numeric_string::put_content(class asn1_context & context, byte * s, int length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+length,3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    memcpy(c->b,s,length);

    c->len = length;
    c->b_ptr = c->b;
}

#if !defined(PLATFORM_NO_PACKET)
void asn1_numeric_string::put_content(class asn1_context & context, class packet * data)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+data->length(),3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    data->look_head(c->b,data->length());

    c->len = data->length();
    c->b_ptr = c->b;
}
#endif

/*---------------------------------------------------------------------------*/
/* WORD_STRING                                                               */
/*---------------------------------------------------------------------------*/

asn1_word_string::asn1_word_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : asn1(tag,name)
{
    type = ASN1_TYPE_WORD_STRING;
    this->min_length = min_length;
    this->max_length = max_length;
    this->len_bits = len_bits;
}

word * asn1_word_string::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct word_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct word_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_word_string::put_content(class asn1_context & context, word * s, int length)
{
    struct asn1_tag * b;
    struct word_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct word_string_buffer)+(length*2),3);
    if(!b) return;
    c = (struct word_string_buffer *)b->content;
    memcpy(c->b,s,length*2);

    c->len = length;
    c->b_ptr = c->b;
}

/*---------------------------------------------------------------------------*/
/* OBJECT_IDENTIFIER                                                         */
/*---------------------------------------------------------------------------*/

asn1_object_identifier::asn1_object_identifier(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_OBJECT_IDENTIFIER;
}

byte * asn1_object_identifier::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    return (byte *)b->content;
}

void asn1_object_identifier::put_content(class asn1_context & context, byte * content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    b->content = content;
}

/*---------------------------------------------------------------------------*/
/* SEQUENCE                                                                  */
/*---------------------------------------------------------------------------*/

asn1_sequence::asn1_sequence(int & tag, const char * name, byte properties, byte count, class asn1 ** table, byte * flags, byte ext_count, word * tag_table) : asn1(tag,name)
{
    type = ASN1_TYPE_SEQUENCE;
    this->properties = properties;
    this->count = count;
    this->table = table;
    this->flags = flags;
    this->tag_table = tag_table;
    this->ext_count = ext_count;
}

bool asn1_sequence::get_content(class asn1_context & context)
{
    struct asn1_tag * b;
    dword c;

    b = context.find_tag(tag);
    if(!b) return false;

    void ** p = &b->content;
    c = *(dword *)p;

    if(c &ASN1_EXTENDED) return true;
    return false;
}

void asn1_sequence::put_content(class asn1_context & context, bool content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    b->content = 0;
    if(content) b->content = (void *)ASN1_EXTENDED;
}

/*---------------------------------------------------------------------------*/
/* CHOICE                                                                    */
/*---------------------------------------------------------------------------*/

asn1_choice::asn1_choice(int & tag, const char * name, byte properties, byte count, byte count_bits, class asn1 ** table, byte ext_count, word * tag_table) : asn1(tag,name)
{
    type = ASN1_TYPE_CHOICE;
    this->properties = properties;
    this->count = count;
    this->count_bits = count_bits;
    this->table = table;
    this->ext_count = ext_count;
    this->tag_table = tag_table;
}

dword asn1_choice::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    return *(dword *)p;
}

void asn1_choice::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* SEQUENCE_OF                                                               */
/*---------------------------------------------------------------------------*/

asn1_sequence_of::asn1_sequence_of(int & tag, const char * name, byte count_bits, byte min_length, class asn1 * seq) : asn1(tag,name)
{
	type = ASN1_TYPE_SEQUENCE_OF;
    this->count_bits = count_bits;
    this->min_length = min_length;
    this->seq = seq;
}

dword asn1_sequence_of::set_mask(class asn1_context & context)
{
    struct asn1_tag * b;
    dword s;
    dword x;

    x = context.seq_of;
    context.seq_of &=context.seq_mask;
    b = context.find_tag(tag);
    context.seq_of = x;

        // if we don't know the actual number in this sequence_of, we set
        // the mask for the minimum        
    if(!b) {
        s = context.seq_mask<<SEQ_OF_MIN_MASK;
    }
    else {
        s = (dword)(uintp)b->content;
    }
    s &=0xffff0000;
    s |=0xffff;
    return context.set_mask(s);
}

dword asn1_sequence_of::get_content(class asn1_context & context)
{
    struct asn1_tag * b;
    dword c;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    c = *(dword *)p;
    c &=0xffff;
    return c;
}

void asn1_sequence_of::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;
    dword i;
    dword m;

    b = context.new_tag(tag);
    if(!b) return;

    for(i=16,m=0x8000; m && !(content&m); i--,m>>=1);

        // even if the actual number is lower we set a minimum mask. This allows
        // set the number is set after content up to the minimum length
    if(i<SEQ_OF_MIN_MASK) i=SEQ_OF_MIN_MASK;
    content |=((context.seq_mask<<i) &0xffff0000);

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* SET_OF                                                               */
/*---------------------------------------------------------------------------*/

asn1_set_of::asn1_set_of(int & tag, const char * name, byte count_bits, byte min_length, class asn1 * seq) : asn1(tag,name)
{
	type = ASN1_TYPE_SET_OF;
    this->count_bits = count_bits;
    this->min_length = min_length;
    this->seq = seq;
}

dword asn1_set_of::set_mask(class asn1_context & context)
{
    struct asn1_tag * b;
    dword s;
    dword x;

    x = context.seq_of;
    context.seq_of &=context.seq_mask;
    b = context.find_tag(tag);
    context.seq_of = x;

        // if we don't know the actual number in this sequence_of, we set
        // the mask for the minimum        
    if(!b) {
        s = context.seq_mask<<SEQ_OF_MIN_MASK;
    }
    else {
        s = (dword)(uintp)b->content;
    }
    s &=0xffff0000;
    s |=0xffff;
    return context.set_mask(s);
}

dword asn1_set_of::get_content(class asn1_context & context)
{
    struct asn1_tag * b;
    dword c;

    b = context.find_tag(tag);
    if(!b) return 0;

    void ** p = &b->content;
    c = *(dword *)p;
    c &=0xffff;
    return c;
}

void asn1_set_of::put_content(class asn1_context & context, dword content)
{
    struct asn1_tag * b;
    dword i;
    dword m;

    b = context.new_tag(tag);
    if(!b) return;

    for(i=16,m=0x8000; m && !(content&m); i--,m>>=1);

        // even if the actual number is lower we set a minimum mask. This allows
        // set the number is set after content up to the minimum length
    if(i<SEQ_OF_MIN_MASK) i=SEQ_OF_MIN_MASK;
    content |=((context.seq_mask<<i) &0xffff0000);

    void ** p = &b->content;
    *(dword *)p = content;
}

/*---------------------------------------------------------------------------*/
/* ANY                                                                       */
/*---------------------------------------------------------------------------*/

asn1_any::asn1_any(int & tag, const char * name) : asn1(tag,name)
{
    type = ASN1_TYPE_ANY;
}

bool asn1_any::get_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.find_tag(tag);
    if(!b) return false;

    return true;
}

void asn1_any::put_content(class asn1_context & context)
{
    struct asn1_tag * b;

    b = context.new_tag(tag);
    if(!b) return;

    b->content = 0;
}

/*---------------------------------------------------------------------------*/
/* INNO DUMMY                                                                */
/*---------------------------------------------------------------------------*/

asn1_inno_dummy::asn1_inno_dummy(int & tag, const char * name)  : asn1(tag,name)
{
	type = ASN1_TYPE_INNO_DUMMY;
}

byte * asn1_inno_dummy::get_content(class asn1_context & context, int * length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.find_tag(tag);
    if(!b) {
        *length = 0;
        return 0;
    }
    c = (struct octet_string_buffer *)b->content;

    *length = c->len;
    return c->b_ptr;
}

void asn1_inno_dummy::put_content(class asn1_context & context, byte * s, int length)
{
    struct asn1_tag * b;
    struct octet_string_buffer * c;

    b = context.new_tag(tag,sizeof(struct octet_string_buffer)+length,3);
    if(!b) return;
    c = (struct octet_string_buffer *)b->content;
    memcpy(c->b,s,length);

    c->len = length;
    c->b_ptr = c->b;
}

/*---------------------------------------------------------------------------*/
/* String types                                                              */
/*---------------------------------------------------------------------------*/

asn1_utf8_string::asn1_utf8_string(int & tag, const char * name, int min_length, int max_length, int len_bits) :
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_UTF8STRING;
	type = ASN1_TYPE_UTF8STRING;
}

asn1_printable_string::asn1_printable_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_PRINTABLESTRING;
	type = ASN1_TYPE_PRINTABLESTRING;
}

asn1_teletex_string::asn1_teletex_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_TELETEXSTRING;
	type = ASN1_TYPE_TELETEXSTRING;
}

asn1_videotex_string::asn1_videotex_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_VIDEOTEXSTRING;
	type = ASN1_TYPE_VIDEOTEXSTRING;
}

asn1_graphic_string::asn1_graphic_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_GRAPHICSTRING;
	type = ASN1_TYPE_GRAPHICSTRING;
}

asn1_visible_string::asn1_visible_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_VISIBLESTRING;
	type = ASN1_TYPE_VISIBLESTRING;
}

asn1_general_string::asn1_general_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_GENERALSTRING;
	type = ASN1_TYPE_GENERALSTRING;
}

asn1_universal_string::asn1_universal_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_UNIVERSALSTRING;
	type = ASN1_TYPE_UNIVERSALSTRING;
}

asn1_bmp_string::asn1_bmp_string(int & tag, const char * name, int min_length, int max_length, int len_bits) : 
	asn1_octet_string(tag, name, min_length, max_length, len_bits)
{
	std_tag = ASN1_TAG_UNIVERSAL_BMPSTRING;
	type = ASN1_TYPE_BMPSTRING;
}

/*---------------------------------------------------------------------------*/
/* Time types                                                                */
/*---------------------------------------------------------------------------*/

asn1_utc_time::asn1_utc_time(int & tag, const char * name) :
	asn1_universal_string(tag, name, 11, 17, 136)
{
	std_tag = ASN1_TAG_UNIVERSAL_UTCTIME;
	type = ASN1_TYPE_UTCTIME;
}

asn1_generalized_time::asn1_generalized_time(int & tag, const char * name) :
	asn1_universal_string(tag, name, 10, 19, 152)
{
	std_tag = ASN1_TAG_UNIVERSAL_GENERALIZEDTIME;
	type = ASN1_TYPE_GENERALIZEDTIME;
}

/*---------------------------------------------------------------------------*/

void write_object_identifier(dword * in, byte * out)
{
    int i;

    out[0] = 0;
    for(i=0;in[i]!=0xffffffff;i++) {
        dword sub_id;
        int j;
        byte t[5];

        if(i==0) {
            sub_id = in[0]*40+in[1];
            i++;
        }
        else {
            sub_id = in[i];
        }
        for(j=0; j<5; j++) {
            t[j] = (byte)(sub_id |0x80);
            sub_id >>=7;
        }
        t[0] &=0x7f;
        for(j=4;t[j]==0x80;j--);
        for(;j>=0;j--) {
            out[1+out[0]++] = t[j];
        }
    }
}

void read_object_identifier(byte * in, dword * out)
{
    int n;
    int o = 0;
    dword sub_id = 0;
    byte length = in[0];

    for(n=0;n<length;n++) {
        sub_id <<=7;
        sub_id |=in[1+n]&0x7f;

        if(!(in[1+n]&0x80)) {
            if(o==0) {
                out[o++] = sub_id/40;
                out[o++] = sub_id%40;
            }
            else {
                out[o++] = sub_id;
            }
            sub_id = 0;
        }
    }
    out[o] = 0xffffffff;
}
NAMESPACE_END
