#ifndef __BER_H__
#define __BER_H__

#include <stdlib.h>

#include "compat.h"


enum Tags {INT_TAG=0x02,STRING_TAG=0x04,NULL_TAG=0x05,OID_TAG=0x06,
	   CONSTRUCTOR_TAG=0x20,SEQUENCE_TAG=0x30,IPADDR_TAG=0x40,
	   COUNTER_TAG=0x41,TIME_TICK_TAG=0x43,GET_REQ_TAG=0xa0,
	   GET_NEXT_TAG=0xa1,GET_RESP_TAG=0xa2,SET_REQ_TAG=0xa3};

class BerEncodedData {
  unsigned char *data;
  unsigned long length; // this is the length of the data as it appears in the 
                       // packet not just the length of the data part of the
                       // packet. In other words this includes the header 
                       // length.
public:
  BerEncodedData *next;

  BerEncodedData(unsigned char *dat, unsigned long len);
  ~BerEncodedData(){delete data;}
  inline unsigned char *Data(){return data;}
  inline void Data(unsigned char* dat){data=dat;}
  inline unsigned int Length(){return length;}
};

class BerBase {
protected:
  // used for decoding the wire format
  BerBase(unsigned char* data); 

public: 
  // head of the linked list that holds private copy of the data
  BerEncodedData *edatacache; 

  // simple linkage field
  BerBase *next; 

  inline BerBase():edatacache(NULL),next(NULL){}
  inline ~BerBase(){if(edatacache!=NULL) delete edatacache;}

  // returns a char* of malloced data that the application can use
  virtual BerEncodedData *encode(); 

  // returns the head to the list of the data still owned by datastructure.
  virtual BerEncodedData *getdata(); 

  /* return the full length basically to overcome the problems with seqences 
   * where their edatacache->Length() is just the length of the header not 
   * the length of the whole sequence. */
  unsigned long fulllen(); 
  
  // makes an ascii representation of the string and then puts it in buf
  // then returns the lenth it used up. -1 if it won't fit.
  virtual int print(char *buf, unsigned int len)=0;

  Tags type(){ return (Tags) *(edatacache->Data()); }
};

class BerNull: public BerBase{
public:
  BerNull(unsigned char *);
  inline BerNull(){}
  virtual BerEncodedData *encode();
  virtual int print(char *buf, unsigned int len);
};

class BerInt: public BerBase {
  long val;
public:
  BerInt(unsigned char *str);
  inline BerInt(long value): val(value){}
  virtual BerEncodedData *encode();
  virtual int print(char *buf, unsigned int len);
  
  inline long value(){ return val;}
};

class BerTimeTick: public BerBase {
  unsigned long val;
public:
  BerTimeTick(unsigned char *str);
  virtual int print(char *buf, unsigned int len);
  virtual BerEncodedData *encode();

  inline unsigned long value(){ return val;}
};

class BerString: public BerBase {
  char *str;
  unsigned int stringlen;
public:
  // this one is for decoding the wire format of the string only. It is not 
  // for a typical initialization of the class.
  BerString(unsigned char *strng); 

  // this one is for normal use
  BerString(CONST char *strng,unsigned int length); 
  virtual BerEncodedData *encode();
  virtual int print(char *buf, unsigned int len);
  int copy(char *buf, unsigned int len);
  inline const char *Str(){ return str; } // Warning: no terminator!
  inline unsigned int strlen(){ return stringlen; }
};

class BerIPAddr: public BerBase {
  unsigned char *ipaddr;
  unsigned int len;
public:
  BerIPAddr(unsigned char *strng);
  BerIPAddr(CONST char *addr,int len);
  virtual BerEncodedData *encode();
  virtual int print(char *buf, unsigned int len);
  inline unsigned char *IPaddr(){return ipaddr;}
  inline unsigned int Len(){return len;}
};

class BerOid: public BerBase {
  unsigned char *eoid;
  unsigned int oidbytes;
public:
  BerOid(unsigned char *str); //decoding wire protocol only
  BerOid(CONST char *oidstr,unsigned int len);

  int operator==(BerOid & other);

  virtual BerEncodedData *encode();
  virtual int print(char *buf, unsigned int len);
};

class BerSequence: public BerBase{
  BerBase *head,*tail;
  Tags tag;
  unsigned long seqlen;

public:
  BerSequence(unsigned char *str);
  BerSequence(Tags tag,unsigned int entries ...);
  ~BerSequence();
  BerEncodedData *encode();
  BerEncodedData *getdata();

  //  void prepend(unsigned int num ...);
  void append(unsigned int num ...);
  BerBase *peek(unsigned int num); // look at the num'd entry in the list
  BerBase *extract(unsigned int num);  // remove the num'd entry in the list
  virtual int print(char *buf, unsigned int len);
};

unsigned char *start_data(Tags type,unsigned int len, unsigned char &headlen);
unsigned long unpack_len(unsigned char *start,unsigned char &headerlen);

#endif //__BER_H__



syntax highlighted by Code2HTML, v. 0.9.1