/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

#ifndef ASN_CLASSES_H_
#define ASN_CLASSES_H_

#include <stdlib.h>
#include <string.h>
#include <asn1.h>

typedef enum {ASN_PUBLIC, ASN_SECRET} security_t;


EXPORTFN(void,
         AsnInitialize,
         (void));
// This routine must be called after the IniFile has been established.

// First, a couple of classes to handle reading and writing of
// octet strings


class EXPORTCLASS r_buffer_t {
protected:
  unsigned char * init_data;
  uint32 init_data_len;
  unsigned char harmless;
public:
  unsigned char * data;
  uint32 data_len;
  r_buffer_t(void);
  r_buffer_t(unsigned char * d, uint32 l);
  virtual void set(unsigned char * d, uint32 l);
  virtual void reset(void);
  r_buffer_t & operator = (const r_buffer_t & o);
  bool operator == (const r_buffer_t & o) const;
  const unsigned char & operator [] (unsigned i) const {
    if (i < data_len) return data[i];
    else return harmless;
  };
  unsigned char & operator [] (unsigned i) {
    if (i < data_len) return data[i];
    else return harmless;
  };
};

class EXPORTCLASS memory_funcs_t {
private:
  bool fnPresent;
  void * (*malloc_func) (uint32 Size);
  void (*free_func) (void *MemPtr);
  void * (*realloc_func) (void *MemPtr, uint32 Size);
  void * (*calloc_func) (uint32 Num, uint32 Size);

  bool xfnPresent;
  void * (*xmalloc_func) (uint32 handle, uint32 Size);
  void (*xfree_func) (uint32 handle, void *MemPtr);
  void * (*xrealloc_func) (uint32 handle, void *MemPtr, uint32 Size);
  void * (*xcalloc_func) (uint32 handle, uint32 Num, uint32 Size);
  uint32 handle;
public:
  memory_funcs_t(void) {
    malloc_func = NULL;
    free_func = NULL;
    realloc_func = NULL;
    calloc_func = NULL;
    fnPresent = false;
    xfnPresent = false;
  };
  memory_funcs_t(
    void * (*fMalloc) (uint32 Size),
    void (*fFree) (void *MemPtr),
    void * (*fRealloc) (void *MemPtr, uint32 Size),
    void * (*fCalloc) (uint32 Num, uint32 Size))
  {
    malloc_func = fMalloc;
    free_func = fFree;
    realloc_func = fRealloc;
    calloc_func = fCalloc;
    fnPresent = true;
    xfnPresent = false;
  };
  memory_funcs_t(
    uint32 fhandle,
    void * (*fMalloc) (uint32 handle, uint32 Size),
    void (*fFree) (uint32 handle, void *MemPtr),
    void * (*fRealloc) (uint32 handle, void *MemPtr, uint32 Size),
    void * (*fCalloc) (uint32 handle, uint32 Num, uint32 Size))
  {
    xmalloc_func = fMalloc;
    xfree_func = fFree;
    xrealloc_func = fRealloc;
    xcalloc_func = fCalloc;
    handle = fhandle;
    fnPresent = false;
    xfnPresent = true;
  };
  void * malloc(uint32 Size);
  void free(void *MemPtr);
  void * realloc(void *MemPtr, uint32 Size);
  void * calloc(uint32 Num, uint32 Size);
};
 

class EXPORTCLASS buffer_t : public r_buffer_t {
private:
  uint32 saved_offset;
  unsigned char * buf;
  buffer_t & operator =(const r_buffer_t & o) {
    throw "Assignment not supported by buffer_t objects";
    return *this;
  };
  buffer_t & operator =(const buffer_t & o) {
    throw "Assignment not supported by buffer_t objects";
    return *this;
  };
  buffer_t(const buffer_t & o) {
    throw "Copy not supported by buffer_t objects";
  };
  memory_funcs_t mem;
public:
  uint32 buf_len;
  security_t security;
  buffer_t(memory_funcs_t mems);

  buffer_t(security_t s = ASN_PUBLIC);
  
  buffer_t(memory_funcs_t mems,
           security_t s);
  
  buffer_t(uint32 init_size, 
           security_t s = ASN_PUBLIC);
  
  buffer_t(uint32 init_size, 
           memory_funcs_t mems);

  buffer_t(uint32 init_size, 
           memory_funcs_t mems,
           security_t s);

  virtual ~buffer_t();
  int clear(void);
  int extend(uint32 delta = 64);
  int append(unsigned char c);
  int append(unsigned char * cp, uint32 len);
  int append(const char * c);
  int append(const r_buffer_t buf);
  int append_int(long v);
  void detach(void);
};


EXPORTFN(bool, check_EOC, (r_buffer_t buf));

typedef enum {INVALIDATE_CHILD, 
              INVALIDATE_PARENT, 
              INVALIDATE_BOTH} invalidate_t;

class asn_composite;

class EXPORTCLASS asn_object {
friend class asn_composite;
friend class asn_sorted;
friend class asn_any;

private:
  buffer_t encode_cache;
  asn_object * parent;
  asn_object * internalDefaultValue;

// These are critical state variables that should only be modified
// by their corresponding  access functions.
  bool value_optional;    // true if the object is OPTIONAL.
  bool value_defaultable; // true if the object has a default value.
  bool value_valid;       // true if the object has an explicit value.
  bool encoding_valid;    // true if the encoding cache contains the correct data.
private:
  asn_object & operator = (const asn_object & o);
  asn_object(const asn_object & o);
protected:
// Derived classes must provide decode_value and 
// encode_value member functions.
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length) = 0;
  virtual int encode_value(buffer_t & buf) const = 0;

  virtual void check_valid(void);
  virtual void invalidate_encoding(void) const;
  virtual void invalidate_value(invalidate_t dir = INVALIDATE_BOTH);
  virtual void set_value_valid(void);

  security_t security;

// These flags describe the ASN encountered while reading a value.
  bool constructed;
  bool indefinite_length;

// This flag controls whether the 'constructed' bit is set in generated encodings
  bool generate_constructed;

// These are dual-purpose members.  They describe the ASN.1 class
// and types in the incoming stream, and they are also used
// when constructing outgoing BER.
  int asn_class;
  uint32 asn_tag;

// These flags decribe the requirements placed on incoming
// ASN encodings by the object
  bool encoding_primitive;
  bool encoding_constructed;
  bool encoding_indefinite;
  
  void set_parent(asn_object * p);
  int write_type(buffer_t & buf) const;
  int write_length(buffer_t & buf) const;
  virtual bool check_type(uint32 tagRead, int classRead) const;


// Note: The asn_object passed to set_default_value becomes owned
// by the main object.
  virtual void set_default_value(asn_object * o);
  virtual int get_encoding(buffer_t & buf) const;
  virtual int get_encoding(void) const;
  virtual int emptyi(void);
  void (* preread_callback)(asn_object * o, r_buffer_t & buf);
  void (* postread_callback)(asn_object * o, r_buffer_t & buf, int status);
public:
  char objType[16]; // For debugging purposes
  int set_preread(void (* callback)(asn_object * o, r_buffer_t & buf));
  int set_postread(void (* callback)(asn_object * o, r_buffer_t & buf, int status));
  
  virtual void set_class(int the_class);
  virtual void set_tag(uint32 the_tag);
  virtual int display(buffer_t & s) const;  // Displays the object's value as a C string.
  virtual int empty(void);
  virtual int normalize(void);
  virtual bool is_optional(void) const; // true if the object is OPTIONAL
  virtual bool is_defaultable(void) const; // true if the object has a default value.
  virtual bool is_encoding_valid(void) const; // true if a cached encoding exists.
  virtual asn_object * get_default_value(void) const;
  virtual bool is_default_value(void) const;  
  asn_object(security_t s = ASN_PUBLIC);

// is_valid() is true if the object contains an explicit value, or a default 
// value, or is optional
  virtual bool is_valid(void) const;

// is_present() is true if the object contains an explicit value.
  virtual bool is_present(void) const;

  virtual ~asn_object();
  int get_class(void) const;
  uint32 get_tag(void) const;

  virtual void set_secure(security_t s = ASN_PUBLIC);

  virtual int read(r_buffer_t & buf);
  virtual int write(buffer_t & buf) const;

  virtual bool operator == (const asn_object & o) const;
  const asn_object * get_parent(void);
  virtual int set_optional(bool opt = true);

// A couple of functions for debugging...
  virtual bool check_encode_flags(bool expected) const;
  virtual bool check_encode_flags(void) const;
  virtual int display_state_flags(buffer_t & buf, int inset=0) const;
};


class EXPORTCLASS asn_primitive : public asn_object {
public:
  asn_primitive(security_t s = ASN_PUBLIC) : asn_object(s) {
// The following settings are correct for most primitive objects, although string types
// will override them.  Allow primitive encoding, forbid constructed encoding...
    encoding_primitive = true;
    encoding_constructed = false;
    encoding_indefinite = false;
  };
};

class EXPORTCLASS asn_composite : public asn_object {
protected:
  unsigned child_count;
  unsigned children_size;
  asn_object ** child;
  virtual void check_valid(void);
  virtual void invalidate_value(invalidate_t dir = INVALIDATE_BOTH);
  virtual int emptyi(void);
public:
  virtual int display(buffer_t & s) const;  // Displays the object's value as a C string.
  virtual int normalize(void);
  virtual ~asn_composite();
  asn_composite(security_t s = ASN_PUBLIC);
  asn_composite(unsigned children,
                security_t s = ASN_PUBLIC);
  virtual int register_child(asn_object * c);
  virtual int register_child_before(asn_object * c);
  virtual int get_child_count(void) const { return child_count; };
  asn_object * get_child(unsigned i) const;
  asn_object * operator [] (unsigned i) const;
  virtual bool check_encode_flags(bool expected) const;
  virtual bool check_encode_flags(void) const;
  virtual int display_state_flags(buffer_t & buf, int inset = 0) const;
};


class EXPORTCLASS asn_integer : public asn_primitive {
private:
  void update_int_val(void);
protected:
  long int_val;
  buffer_t str_val;
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  bool is_int;
  asn_integer(security_t s = ASN_PUBLIC) : asn_primitive(s) {
    strcpy(objType, "INTEGER");
    is_int = false;
    str_val.security = s;
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 2;
  };
  virtual ~asn_integer() {
    int_val = 0;
  };
  virtual void set_secure(security_t s = ASN_PUBLIC);
  int get_value(long & val) const;
  int set_value(long val);
  int get_value(unsigned char * &p, uint32 & s) const;
  int set_value(unsigned char * p, uint32 s);
  int set_default_value(long val);
  int set_default_value(unsigned char *p, uint32 s);
};

class EXPORTCLASS asn_bitstring : public asn_primitive {
protected:
  buffer_t str_val;
  unsigned char unused_bits;
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  asn_bitstring(security_t s = ASN_PUBLIC) : asn_primitive(s) {
// Allow the parser to accept constructed encodings...
    strcpy(objType, "BITSTRING");
    encoding_constructed = true; 
    str_val.security = s;
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 3;
  };
  int get_value(unsigned char * &p, uint32 & bc) const;
  int set_value(unsigned char * p, uint32 bc);
  int set_default_value(unsigned char * p, uint32 bc);
  virtual void set_secure(security_t s = ASN_PUBLIC);
};

class EXPORTCLASS asn_namedbits : public asn_bitstring {
public:
  virtual int write(buffer_t & buf) const;  // Remove trailing zeros prior to writing

  asn_namedbits(security_t s = ASN_PUBLIC) : asn_bitstring(s) {
  };
  int set_bit(unsigned bitNum, bool value = true);
  int clear_bit(unsigned bitNum) { return set_bit(bitNum, false); };
  const uint32 get_bit(unsigned bitNum, bool & value);
};


class EXPORTCLASS asn_boolean : public asn_primitive {
protected:
  bool value;
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  asn_boolean(security_t s = ASN_PUBLIC) : asn_primitive(s) {
// Allow the parser to accept constructed encodings...
    strcpy(objType, "BOOLEAN");
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 1;
  };
  int get_value(bool &b) const;
  int set_value(bool b);
  int set_default_value(bool b);
};


class EXPORTCLASS asn_octetstring : public asn_primitive {
protected:
  buffer_t str_val;
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  asn_octetstring(security_t s = ASN_PUBLIC) : asn_primitive(s) {
// Allow the parser to accept constructed encodings...
    strcpy(objType, "OCTETSTRING");
    encoding_constructed = true; 
    encoding_indefinite = true;
    str_val.security = s;
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 4;
  };
  int get_value(unsigned char * &p, uint32 & bc) const;
  int set_value(unsigned char * p, uint32 bc);
  int set_default_value(unsigned char * p, uint32 bc);
  virtual void set_secure(security_t s = ASN_PUBLIC);
};


class EXPORTCLASS asn_null : public asn_primitive {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  asn_null(void) {
    strcpy(objType, "NULL");
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 5;
  };
};

// An asn_nothing contributes nothing to the DER bytestream on writing,
// and consumes nothing on reading.  It can be used as a placeholder in,
// for example, an asn_any object, if "nothing" is one permitted syntax.

class EXPORTCLASS asn_nothing : public asn_primitive {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length) {
    return 0;
  };
  virtual int encode_value(buffer_t & buf) const {
    return 0;
  };
public:
  virtual bool is_present(void) const {
// Nothing values are always present
    return true;
  };
  asn_nothing(void) {
    strcpy(objType, "NOTHING");
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 0;
  };
  virtual int read(r_buffer_t & buf) {
    return 0;
  };
  virtual int write(buffer_t & buf) const {
    return 0;
  };
};

class EXPORTCLASS asn_oid : public asn_primitive {
  unsigned long * id;
  unsigned id_count;
  unsigned id_size;
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
  virtual int emptyi(void);
public:
  virtual int display(buffer_t & s) const;  // Displays the object's value as a C string.
  virtual int display_printable(buffer_t & s) const;  // Displays the object's value as a printable string.
  virtual int display_name(buffer_t & s) const;  // Displays the OID's name as a C string if possible,
                                                 // otherwise returns failure.
  virtual int display_name_printable(buffer_t & s) const;  // Displays the OID's name as a printable string 
                                                           //if possible, otherwise returns failure.
  asn_oid(security_t s = ASN_PUBLIC) : asn_primitive(s) {
    strcpy(objType, "OID");
    asn_class = CLASS_UNIVERSAL;
    asn_tag = 6;
    id = NULL;
    id_count = 0;
    id_size = 0;
  };
  virtual ~asn_oid();
// get/set value as an array of long integers
  int get_value(unsigned long *&p, unsigned &n) const;  
  int set_value(unsigned long *p, unsigned n);
  int set_default_value(unsigned long *p, unsigned n);
// get/set value as a DER value-portion (e.g. a gss_OID or om_objectidentifier)
  int get_value(buffer_t & buffer) const;
  int set_value(unsigned char *p, unsigned n);
  
  int set_value(char * s);
// Set value as a named OID

  int append_subident(unsigned long p);
  bool is_equal(const unsigned long *p, unsigned n) const;
  bool operator == (const asn_oid & o) const;
  bool operator != (const asn_oid & o) const;
};


class EXPORTCLASS asn_sequence : public asn_composite {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
public:
  asn_sequence(security_t s = ASN_PUBLIC) : asn_composite(s) {
    strcpy(objType, "SEQUENCE");
    set_tag(16);
    set_class(CLASS_UNIVERSAL);
  };
  asn_sequence(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_composite(children, s) {
    strcpy(objType, "SEQUENCE");
    set_tag(16);
    set_class(CLASS_UNIVERSAL);
  };
};

template<class o> class asn_sequenceof : public asn_sequence {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length) {
    r_buffer_t temp_buf = buf;
    o * new_member;
    int result = 0;
    bool done = false;

    empty();
    if (!indefinite_length) {
// Restrict the length of the data stream while parsing the SEQOF
      temp_buf.data_len = value_length;
    };
    while (!done) {
      if (indefinite_length) {
        if (check_EOC(temp_buf)) done = 1;
      } else if (temp_buf.data_len == 0)  done = 1;
      if (!done) {
        new_member = new o(security);
        if ((result = new_member->read(temp_buf)) != 0) {
          delete new_member;
          return result;
        };
        register_child(new_member);
      };
    };
    if (!indefinite_length) {
// Restore the length of the unparsed data stream 
      temp_buf.data_len = buf.data_len - value_length;
    };
    buf = temp_buf;
    return 0;
  };
  virtual int emptyi(void) {
    unsigned i;
    for (i=0; i<child_count; i++) {
      delete child[i];
      child[i] = NULL;
    };
    child_count = 0;
    return 0;
  };
public:
  virtual o * add_child(void) {
    o * new_member = new o(security);
    if (register_child(new_member) != 0) {
      delete new_member;
      return NULL;
    } else return new_member;
  };
  virtual o * add_child_before(void) {
    o * new_member = new o(security);
    if (register_child_before(new_member) != 0) {
      delete new_member;
      return NULL;
    } else return new_member;
  };
  asn_sequenceof(security_t s = ASN_PUBLIC) : asn_sequence(s) {
    strcpy(objType, "SEQUENCEOF");
    set_value_valid();   // An empty sequence is valid
  };
  asn_sequenceof(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_sequence(children, s) {
    strcpy(objType, "SEQUENCEOF");
    set_value_valid();   // An empty sequence is valid
  };
  virtual ~asn_sequenceof() {
    emptyi();
  };
  o * get_child(unsigned i) const { return (o *)asn_sequence::get_child(i); };
  o * operator [] (unsigned i) const {
    return get_child(i);
  };
};


class EXPORTCLASS asn_sorted : public asn_composite {
protected:
  bool is_sorted;
  asn_object ** sorted_child;
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
  virtual int sort_children(void) const;
  virtual void invalidate_value(invalidate_t dir = INVALIDATE_BOTH);
public:
  asn_sorted(security_t s = ASN_PUBLIC) : asn_composite(s) {
    strcpy(objType, "SORTED");
    sorted_child = NULL;
    is_sorted = false;
  };
  asn_sorted(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_composite(children, s) {
    strcpy(objType, "SORTED");
    sorted_child = NULL;
    is_sorted = false;
  };
  virtual ~asn_sorted();
};


class EXPORTCLASS asn_set : public asn_sorted {
public:
  asn_set(security_t s = ASN_PUBLIC) : asn_sorted(s) {
    strcpy(objType, "SET");
    set_tag(17);
    set_class(CLASS_UNIVERSAL);
  };
  asn_set(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_sorted(children, s) {
    strcpy(objType, "SET");
    set_tag(17);
    set_class(CLASS_UNIVERSAL);
  };
};

template<class o> class asn_setof : public asn_set {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length) {
    r_buffer_t temp_buf = buf;
    o * new_member;
    int result = 0;
    bool done = false;

    empty();
    if (!indefinite_length) {
      temp_buf.data_len = value_length;
    };
    while (!done) {
      if (indefinite_length) {
        if (check_EOC(temp_buf)) done = 1;
      } else if (temp_buf.data_len == 0)  done = 1;
      if (!done) {
        new_member = new o(security);
        if ((result = new_member->read(temp_buf)) != 0) {
          delete new_member;
          return result;
        };
        register_child(new_member);
      };
    };
    if (!indefinite_length) {
      temp_buf.data_len = buf.data_len - value_length;
    };
    buf = temp_buf;
    return 0;
  };
  virtual int emptyi(void) {
    unsigned i;
    for (i=0; i<child_count; i++) {
      delete child[i];
      child[i] = NULL;
    };
    child_count = 0;
    return 0;
  };
public:
  virtual o * add_child(void) {
    o * new_member = new o(security);
    if (register_child(new_member) != 0) {
      delete new_member;
      return NULL;
    } else return new_member;
  };
  virtual o * add_child_before(void) {
    o * new_member = new o(security);
    if (register_child_before(new_member) != 0) {
      delete new_member;
      return NULL;
    } else return new_member;
  };
  asn_setof(security_t s = ASN_PUBLIC) : asn_set(s) {
    strcpy(objType, "SETOF");
    set_value_valid();   // An empty set is valid
  };
  asn_setof(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_set(children, s) {
    strcpy(objType, "SETOF");
    set_value_valid();   // An empty set is valid
  };
  virtual ~asn_setof() {
    emptyi();
  };
  o * get_child_sorted(unsigned i) const { 
    sort_children();
    if (i < child_count) return (o *)(sorted_child[i]); else return NULL; 
  };
  o * get_child(unsigned i) const { 
    return (o *)(asn_set::get_child(i));
  };
  o * operator [] (unsigned i) const {
    return get_child(i);
  };
};


class EXPORTCLASS asn_UTCtime : public asn_octetstring {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
public:
  asn_UTCtime(security_t s = ASN_PUBLIC) : asn_octetstring(s) {
    strcpy(objType, "UTCTIME");
    set_class(CLASS_UNIVERSAL);
    set_tag(23);
  };
  virtual int normalize(void);
// In the routines below, tz_hour and tz_min will always have the same sign.
  int get_value(unsigned & year,    // 1950..2049
                unsigned & month,   // 1..12
                unsigned & day,     // 0..31
                unsigned & hour,    // 0..23
                unsigned & minute,  // 0..59
                unsigned & second,  // 0..59
                int & tz_hour,      // -12..+12
                int & tz_min) const; // -59..+59
  int set_value(unsigned year,    // 1950..2049
                unsigned month,   // 1..12
                unsigned day,     // 0..31
                unsigned hour,    // 0..23
                unsigned minute,  // 0..59
                unsigned second,  // 0..59
                int tz_hour,      // -12..+12
                int tz_min);      // -59..+59
};

class EXPORTCLASS asn_generalizedtime : public asn_octetstring {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
public:
  asn_generalizedtime(security_t s = ASN_PUBLIC) : asn_octetstring(s) {
    strcpy(objType, "GENERALTIME");
    set_class(CLASS_UNIVERSAL);
    set_tag(24);
  };
  virtual int normalize(void);
// In the routines below, tz_hour and tz_min will always have the same sign.
  int get_value(unsigned & year,    // 0..9999
                unsigned & month,   // 1..12
                unsigned & day,     // 0..31
                unsigned & hour,    // 0..23
                unsigned & minute,  // 0..59
                unsigned & second,  // 0..59
                unsigned & millisecond, // 0..999
                int & tz_hour,      // -12..+12, 100 -> local time
                int & tz_min) const;      // -59..+59
  int set_value(unsigned year,    // 0..9999
                unsigned month,   // 1..12
                unsigned day,     // 0..31
                unsigned hour,    // 0..23
                unsigned minute,  // 0..59
                unsigned second,  // 0..59
                unsigned millisecond, // 0..999
                int tz_hour,      // -12..+12, local time not supported
                int tz_min);      // -59..+59

};

class EXPORTCLASS asn_choice : public asn_composite {
protected:
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
  int selected_child;
  virtual void check_valid(void) ;
public:
  virtual int normalize(void);
  int select(unsigned i);
  int selected(void) const;
  virtual int read(r_buffer_t & buf);
  virtual int write(buffer_t & buf) const;
  asn_choice(security_t s = ASN_PUBLIC) : asn_composite(s) {
    strcpy(objType, "CHOICE");
    selected_child = -1;
  };
  asn_choice(unsigned children, security_t s = ASN_PUBLIC) 
  : asn_composite(children, s) {
    strcpy(objType, "CHOICE");
    selected_child = -1;
  };
  virtual bool is_encoding_valid(void) const; // true if a cached encoding exists.
  virtual bool check_encode_flags(bool expected) const;
  virtual bool check_encode_flags(void) const;
  virtual int display_state_flags(buffer_t & buf, int inset = 0) const;
};


class EXPORTCLASS asn_any : public asn_object {
// asn_any can deal with two distinct sorts of ANY value:
// an ANY DEFINED BY (which should use the set_preparse method to
// establish a call-out that will set the actual syntax immediately
// prior to parsing), and a definite length encoded arbitary value of
// unknown syntax, which isn't parsed, but is simply stored within the
// asn_any object.  If a preparse routine isn't set, or if it doesn't
// establish an expected syntax, then this unparsed version is used.
private:
  bool parsedValue;
  buffer_t unparsedValue;
protected:
  asn_object * specific_syntax;
  int (* preParse)(asn_any * o);
  int (* preEncode)(asn_any * o);
  virtual void invalidate_value(invalidate_t dir = INVALIDATE_BOTH);
  virtual void check_valid(void);
  virtual int decode_value(r_buffer_t & buf, 
                           uint32 value_length);
  virtual int encode_value(buffer_t & buf) const;
  virtual bool check_type(uint32 tagRead, int classRead) const;
public:
  virtual void set_secure(security_t s = ASN_PUBLIC);
  virtual int read(r_buffer_t & buf);
  virtual int write(buffer_t & buf) const;
  asn_any(security_t s = ASN_PUBLIC);
  virtual ~asn_any();

// Set_syntax() provides an object to parse the ANY value.  
// The asn_any object doesn't own the value-parsing object.
  int set_syntax(asn_object * o);  

// Allows an external routine to be called immediately prior to parsing an ANY
// value.  For an ANY DEFINED BY ... syntax, this allows the user to set the asn_any's
// syntax member based on some already-parsed value.  If the callback routine returns
// a non-zero status, parsing will be aborted and the status returned to the caller.
// the preencode callback is similar, although in practice the encode syntax would
// usually be set prior to starting the top-level encode, and not changed on-the-fly.
  int set_preparse(int (* callback)(asn_any * o));
  int set_preencode(int (* callback)(asn_any * o));

// Allows the raw, unparsed value encoding to be read or set.  These methods may only
// be used if a specific syntax has not been set; if a syntax has been specified, the
// get/set_value methods of that syntax object should be used to manipulate the value.
  int get_value(unsigned char * &p, uint32 & bc) const;
  int set_value(unsigned char * p, uint32 bc);

// Set the value of the ANY from another object.
//  int set_value(const asn_object * o);

};


// EXPLICITly-tagged objects are implemented as single-membered
// sequences, with some kludgery to handle default values
template <class c, 
          int theClass, 
          uint32 theTag> class asn_explicit : public asn_sequence {
public:
  c value;
  asn_explicit(security_t s = ASN_PUBLIC) : asn_sequence(s) {
    set_tag(theTag);
    set_class(theClass);
    if (s == ASN_SECRET) value.set_secure();
    register_child(&value);
  };
  virtual bool is_default_value(void) const { return value.is_default_value(); };
  virtual asn_object * get_default_value(void) const { return value.get_default_value(); };
  virtual bool is_optional(void) const { return value.is_optional(); };
  virtual bool is_defaultable(void) const { return value.is_defaultable(); };
  virtual int set_optional(bool opt = true) {
    asn_sequence::set_optional();
    return value.set_optional(opt);
  };
};



// IMPLICIT objects are created simply by deriving from the base,
// and changing the class/tag in the derived constructor.
// In practice, implicitly-tagged objects will often be derived directly, 
// without using this template.
template <class c,
          int theClass,
          uint32 theTag> class asn_implicit : public c {
public:
  asn_implicit(security_t s = ASN_PUBLIC) : c(s) {
    strcat(objType, "-I");
    set_tag(theTag);
    set_class(theClass);
  };
};

#endif
