#include #include #include #include #include "ber.h" /* berSequence - sequences are wrappers for other encoded pieces of data. * basically all that they do is give mark their beginning and have a length. * the tricky bit is that they can be recursive. This is the real reason for * mbufs. * You sort of insert the other information into the sequence. The ber encoded * information that you insert into a sequence is assumed to be owned by the * sequence. It actually throws it away very shortly and just keeps the mbufs. */ BerSequence::~BerSequence(){ for(BerBase *cur=head; cur!=NULL; ){ BerBase *tmp=cur; cur=cur->next; delete tmp; } } BerSequence::BerSequence(unsigned char *str){ head=NULL; tail=NULL; assert(str[0]&CONSTRUCTOR_TAG); unsigned char headlen; tag=(Tags)str[0]; seqlen=unpack_len(str,headlen); unsigned long myseqlen=0; unsigned char junk; // used to store the headerlen and then dispose of it for(unsigned char *curpos=str+headlen;curposprint(tmpbuf,10239); // tmpbuf[tmplen]=0; // printf("%s\n\n",tmpbuf); break; case STRING_TAG: newone=new BerString(curpos); break; case NULL_TAG: newone=new BerNull(curpos); break; case OID_TAG: newone=new BerOid(curpos); break; case TIME_TICK_TAG: newone=new BerTimeTick(curpos); break; case IPADDR_TAG: newone=new BerIPAddr(curpos); break; default: newone=new BerSequence(curpos); } assert(newone); if(head==NULL) tail=head=newone; else { tail->next=newone; tail=tail->next; } myseqlen+=newone->fulllen(); } unsigned char *tempstr=start_data((Tags)str[0],myseqlen,headlen); assert(edatacache=new BerEncodedData(tempstr,headlen)); // shorten the string because start_data creates a space big enough for the // data as well. edatacache->Data((unsigned char*)realloc(edatacache->Data(),headlen)); } BerEncodedData *BerSequence::getdata(){ if(edatacache==NULL){ unsigned char headlen; unsigned char *tmp=start_data(tag,seqlen,headlen); tmp=(unsigned char*)realloc(tmp,headlen); assert(edatacache=new BerEncodedData(tmp,headlen)); } if(edatacache->next==NULL){ BerEncodedData *tail=edatacache; for(BerBase *cur=head;cur!=NULL; cur=cur->next){ tail->next=cur->getdata(); while(tail->next) tail=tail->next; // walk to the end of the list. } } return edatacache; } BerEncodedData *BerSequence::encode(){ BerEncodedData *datlisthead=NULL,*curdat=NULL,*bedtail=NULL; // string up the data for(BerBase *cur=head; cur!=NULL; cur=cur->next){ // go to the end of the list. curdat=cur->getdata(); if(datlisthead==NULL){ datlisthead=bedtail=curdat; }else{ bedtail->next=curdat; bedtail=bedtail->next; } while(bedtail->next) bedtail=bedtail->next; } // encode the data unsigned char headerlen; unsigned char *retval=start_data(tag,seqlen,headerlen); unsigned char *curpos=retval+headerlen; for(curdat=datlisthead; curdat!=NULL; curpos+=curdat->Length(), curdat=curdat->next){ memcpy(curpos, curdat->Data(), curdat->Length()); } return new BerEncodedData(retval,seqlen+headerlen); } BerSequence::BerSequence(Tags newtag, unsigned int entries ...){ va_list berObs; va_start(berObs,entries); tag=newtag; if(entries==0){ head=tail=NULL; return; } BerBase *curBer=va_arg(berObs,BerBase*); assert(curBer); head=tail=curBer; seqlen=curBer->fulllen(); //only count down to one because we have already taken one. for(;entries>1;entries--){ curBer=va_arg(berObs,BerBase*); assert(curBer); seqlen+=curBer->fulllen(); tail->next=curBer; tail=tail->next; } va_end(berObs); } // /* never tested */ // BerSequence::prepend(unsigned int num ...){ // va_list newones; // va_start(newones,num); // BerBase *newlist,*newtail; // newtail=newlist=va_arg(newones,BerBase*); // assert(newlist); // seqlen+=newlist->fulllen(); // for(;num>1;num--){ // BerBase *curber=va_arg(newones,BerBase*); // assert(curber);x // seqlen+=curber->fulllen(); // newtail->next=curber; // newtail=newtail->next; // } // newtail->next=head; // head=newlist; // va_end(newones); // } void BerSequence::append(unsigned int num ...){ va_list newones; va_start(newones,num); if(head==NULL){ head=tail=va_arg(newones,BerBase*); seqlen=tail->fulllen(); num--; } while(num--){ tail->next=va_arg(newones,BerBase*); assert(tail->next); tail=tail->next; seqlen+=tail->fulllen(); } if(edatacache){ delete edatacache; edatacache=NULL; } va_end(newones); } BerBase *BerSequence::peek(unsigned int num){ BerBase *cur; for(cur=head;num && cur!=NULL;num--,cur=cur->next); return cur; } BerBase *BerSequence::extract(unsigned int num){ BerBase *cur,*prev=NULL; for(cur=head;num && cur!=NULL;num--,cur=cur->next) prev=cur; if(cur==NULL) return NULL; // remove its length /* The inital approach was to just subtract the fulllen but fullen walks the list of the encoded data and so in effect it returns the remainder of the sequence. Thus the sequence is too short. This subtracts the correct amount and leaves the semantics of fulllen the same. However, I am not sure that is the right thing to do. It might be worth it to change the functioning of fulllen but I didn't want to take the time to figure out all the other ways that might affect the code. */ unsigned char headlen; seqlen-=unpack_len(cur->edatacache->Data(),headlen); seqlen-=headlen; /* got to fix up edatacache so that it matches current data */ unsigned char *newdat=start_data((Tags)(edatacache->Data())[0],seqlen, headlen); assert(newdat=(unsigned char*)realloc(newdat,headlen)); BerEncodedData *oldedc=edatacache; assert(edatacache=new BerEncodedData(newdat,headlen)); edatacache->next=oldedc->next; delete oldedc; BerEncodedData *oldend; if(cur==head){ head=head->next; } else { prev->next=cur->next; /* find the entry that is cur's edatacache and set it to the value of cur->next->edatacache kind of sew the lists together */ if(cur->next!=NULL){ for(oldend=prev->edatacache;oldend->next!=cur->edatacache; oldend=oldend->next){ assert(oldend->next!=NULL); /* I don't know what this would mean. If it ever comes up. I guess I will have to deal with it. */ } oldend->next=cur->next->edatacache; } } // make is so that cur->edatacache list doesn't merge into this list if(cur->next){ for(oldend=cur->edatacache; oldend->next!=cur->next->edatacache; oldend=oldend->next); oldend->next=NULL; } if(cur==tail){ tail=prev; } cur->next=NULL; return cur; } int BerSequence::print(char *buf, unsigned int len){ len-=2; if(!len) return -1; buf[0]='('; buf[1]=' '; buf+=2; int totlen=1; for( BerBase *cur=head; cur!=NULL; cur=cur->next){ int i=cur->print(buf,len); if(i==-1) return -1; len-=i+1; buf+=i; buf[0]=' '; buf++; totlen+=i+1; } if(!--len) return -1; buf[0]=')'; buf[1]=' '; return totlen+2; }