1 #include <string.h>
2 #include <assert.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5
6 #include "ber.h"
7
8 /* berSequence - sequences are wrappers for other encoded pieces of data.
9 * basically all that they do is give mark their beginning and have a length.
10 * the tricky bit is that they can be recursive. This is the real reason for
11 * mbufs.
12 * You sort of insert the other information into the sequence. The ber encoded
13 * information that you insert into a sequence is assumed to be owned by the
14 * sequence. It actually throws it away very shortly and just keeps the mbufs.
15 */
16
~BerSequence()17 BerSequence::~BerSequence(){
18 for(BerBase *cur=head; cur!=NULL; ){
19 BerBase *tmp=cur;
20 cur=cur->next;
21 delete tmp;
22 }
23 }
24
BerSequence(unsigned char * str)25 BerSequence::BerSequence(unsigned char *str){
26 head=NULL;
27 tail=NULL;
28 assert(str[0]&CONSTRUCTOR_TAG);
29 unsigned char headlen;
30 tag=(Tags)str[0];
31 seqlen=unpack_len(str,headlen);
32
33 unsigned long myseqlen=0;
34 unsigned char junk; // used to store the headerlen and then dispose of it
35 for(unsigned char *curpos=str+headlen;curpos<str+headlen+seqlen;
36 curpos+=unpack_len(curpos,junk)+junk){
37 BerBase *newone;
38 // char tmpbuf[10240];
39 // int tmplen;
40 switch(*curpos){
41 case INT_TAG:
42 case COUNTER_TAG:
43 newone=new BerInt(curpos);
44 // tmplen=newone->print(tmpbuf,10239);
45 // tmpbuf[tmplen]=0;
46 // printf("%s\n\n",tmpbuf);
47 break;
48 case STRING_TAG:
49 newone=new BerString(curpos);
50 break;
51 case NULL_TAG:
52 newone=new BerNull(curpos);
53 break;
54 case OID_TAG:
55 newone=new BerOid(curpos);
56 break;
57 case TIME_TICK_TAG:
58 newone=new BerTimeTick(curpos);
59 break;
60 case IPADDR_TAG:
61 newone=new BerIPAddr(curpos);
62 break;
63 default:
64 newone=new BerSequence(curpos);
65 }
66 assert(newone);
67 if(head==NULL)
68 tail=head=newone;
69 else {
70 tail->next=newone;
71 tail=tail->next;
72 }
73 myseqlen+=newone->fulllen();
74 }
75 unsigned char *tempstr=start_data((Tags)str[0],myseqlen,headlen);
76 assert(edatacache=new BerEncodedData(tempstr,headlen));
77 // shorten the string because start_data creates a space big enough for the
78 // data as well.
79 edatacache->Data((unsigned char*)realloc(edatacache->Data(),headlen));
80 }
81
getdata()82 BerEncodedData *BerSequence::getdata(){
83 if(edatacache==NULL){
84 unsigned char headlen;
85 unsigned char *tmp=start_data(tag,seqlen,headlen);
86 tmp=(unsigned char*)realloc(tmp,headlen);
87 assert(edatacache=new BerEncodedData(tmp,headlen));
88 }
89 if(edatacache->next==NULL){
90 BerEncodedData *tail=edatacache;
91 for(BerBase *cur=head;cur!=NULL; cur=cur->next){
92 tail->next=cur->getdata();
93 while(tail->next)
94 tail=tail->next; // walk to the end of the list.
95 }
96 }
97 return edatacache;
98 }
99
encode()100 BerEncodedData *BerSequence::encode(){
101 BerEncodedData *datlisthead=NULL,*curdat=NULL,*bedtail=NULL;
102
103 // string up the data
104 for(BerBase *cur=head; cur!=NULL; cur=cur->next){
105 // go to the end of the list.
106 curdat=cur->getdata();
107 if(datlisthead==NULL){
108 datlisthead=bedtail=curdat;
109 }else{
110 bedtail->next=curdat;
111 bedtail=bedtail->next;
112 }
113 while(bedtail->next)
114 bedtail=bedtail->next;
115 }
116
117 // encode the data
118 unsigned char headerlen;
119 unsigned char *retval=start_data(tag,seqlen,headerlen);
120 unsigned char *curpos=retval+headerlen;
121 for(curdat=datlisthead; curdat!=NULL;
122 curpos+=curdat->Length(), curdat=curdat->next){
123 memcpy(curpos, curdat->Data(), curdat->Length());
124 }
125 return new BerEncodedData(retval,seqlen+headerlen);
126 }
127
BerSequence(Tags newtag,unsigned int entries...)128 BerSequence::BerSequence(Tags newtag, unsigned int entries ...){
129 va_list berObs;
130 va_start(berObs,entries);
131 tag=newtag;
132
133 if(entries==0){
134 head=tail=NULL;
135 return;
136 }
137 BerBase *curBer=va_arg(berObs,BerBase*);
138 assert(curBer);
139 head=tail=curBer;
140 seqlen=curBer->fulllen();
141
142 //only count down to one because we have already taken one.
143 for(;entries>1;entries--){
144 curBer=va_arg(berObs,BerBase*);
145 assert(curBer);
146 seqlen+=curBer->fulllen();
147 tail->next=curBer;
148 tail=tail->next;
149 }
150
151 va_end(berObs);
152 }
153
154 // /* never tested */
155 // BerSequence::prepend(unsigned int num ...){
156 // va_list newones;
157 // va_start(newones,num);
158
159 // BerBase *newlist,*newtail;
160 // newtail=newlist=va_arg(newones,BerBase*);
161 // assert(newlist);
162 // seqlen+=newlist->fulllen();
163 // for(;num>1;num--){
164 // BerBase *curber=va_arg(newones,BerBase*);
165 // assert(curber);x
166 // seqlen+=curber->fulllen();
167 // newtail->next=curber;
168 // newtail=newtail->next;
169 // }
170 // newtail->next=head;
171 // head=newlist;
172
173 // va_end(newones);
174 // }
175
176
append(unsigned int num...)177 void BerSequence::append(unsigned int num ...){
178 va_list newones;
179 va_start(newones,num);
180
181 if(head==NULL){
182 head=tail=va_arg(newones,BerBase*);
183 seqlen=tail->fulllen();
184 num--;
185 }
186
187 while(num--){
188 tail->next=va_arg(newones,BerBase*);
189 assert(tail->next);
190 tail=tail->next;
191 seqlen+=tail->fulllen();
192 }
193
194 if(edatacache){
195 delete edatacache;
196 edatacache=NULL;
197 }
198 va_end(newones);
199 }
200
peek(unsigned int num)201 BerBase *BerSequence::peek(unsigned int num){
202 BerBase *cur;
203 for(cur=head;num && cur!=NULL;num--,cur=cur->next);
204 return cur;
205 }
206
extract(unsigned int num)207 BerBase *BerSequence::extract(unsigned int num){
208 BerBase *cur,*prev=NULL;
209 for(cur=head;num && cur!=NULL;num--,cur=cur->next)
210 prev=cur;
211 if(cur==NULL) return NULL;
212
213 // remove its length
214 /* The inital approach was to just subtract the fulllen but fullen walks
215 the list of the encoded data and so in effect it returns the remainder
216 of the sequence. Thus the sequence is too short. This subtracts the
217 correct amount and leaves the semantics of fulllen the same. However, I
218 am not sure that is the right thing to do. It might be worth it to change
219 the functioning of fulllen but I didn't want to take the time to figure
220 out all the other ways that might affect the code. */
221 unsigned char headlen;
222 seqlen-=unpack_len(cur->edatacache->Data(),headlen);
223 seqlen-=headlen;
224
225 /* got to fix up edatacache so that it matches current data */
226 unsigned char *newdat=start_data((Tags)(edatacache->Data())[0],seqlen,
227 headlen);
228 assert(newdat=(unsigned char*)realloc(newdat,headlen));
229 BerEncodedData *oldedc=edatacache;
230 assert(edatacache=new BerEncodedData(newdat,headlen));
231 edatacache->next=oldedc->next;
232 delete oldedc;
233
234 BerEncodedData *oldend;
235 if(cur==head){
236 head=head->next;
237 } else {
238 prev->next=cur->next;
239 /* find the entry that is cur's edatacache
240 and set it to the value of cur->next->edatacache
241 kind of sew the lists together */
242 if(cur->next!=NULL){
243 for(oldend=prev->edatacache;oldend->next!=cur->edatacache;
244 oldend=oldend->next){
245 assert(oldend->next!=NULL); /* I don't know what this would mean. If
246 it ever comes up. I guess I will have
247 to deal with it. */
248 }
249 oldend->next=cur->next->edatacache;
250 }
251 }
252 // make is so that cur->edatacache list doesn't merge into this list
253 if(cur->next){
254 for(oldend=cur->edatacache; oldend->next!=cur->next->edatacache;
255 oldend=oldend->next);
256 oldend->next=NULL;
257 }
258
259 if(cur==tail){
260 tail=prev;
261 }
262 cur->next=NULL;
263
264 return cur;
265 }
266
print(char * buf,unsigned int len)267 int BerSequence::print(char *buf, unsigned int len){
268 len-=2;
269 if(!len) return -1;
270 buf[0]='(';
271 buf[1]=' ';
272 buf+=2;
273 int totlen=1;
274 for( BerBase *cur=head; cur!=NULL; cur=cur->next){
275 int i=cur->print(buf,len);
276 if(i==-1) return -1;
277 len-=i+1;
278 buf+=i;
279 buf[0]=' ';
280 buf++;
281 totlen+=i+1;
282 }
283 if(!--len) return -1;
284 buf[0]=')';
285 buf[1]=' ';
286 return totlen+2;
287 }
288
289
290
291