New protocol: PKCS#1 (rfc2313 pplus some extra oid's)
[obnox/wireshark/wip.git] / range.c
1 /* range.c
2  * Packet range routines (save, print, ...)
3  *
4  * $Id$
5  *
6  * Dick Gooris <gooris@lucent.com>
7  * Ulf Lamping <ulf.lamping@web.de>
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <string.h>
33 #include <ctype.h>
34
35 #include <glib.h>
36
37 #include <epan/frame_data.h>
38
39
40 #include "range.h"
41
42 #include "globals.h"
43
44
45 static gboolean packet_is_in_range(packet_range_t *range, guint32 val);
46
47
48 /* (re-)calculate the packet counts (except the user specified range) */
49 void packet_range_calc(packet_range_t *range) {
50   guint32       current_count;
51   guint32       mark_low;
52   guint32       mark_high;
53   guint32       displayed_mark_low;
54   guint32       displayed_mark_high;
55   frame_data    *packet;
56
57
58   range->selected_packet        = 0L;
59
60   mark_low                      = 0L;
61   mark_high                     = 0L;
62   range->mark_range_cnt         = 0L;
63
64   displayed_mark_low            = 0L;
65   displayed_mark_high           = 0L;
66   range->displayed_cnt          = 0L;
67   range->displayed_marked_cnt   = 0L;
68   range->displayed_mark_range_cnt=0L;
69
70   /* The next for-loop is used to obtain the amount of packets to be processed
71    * and is used to present the information in the Save/Print As widget.
72    * We have different types of ranges: All the packets, the number
73    * of packets of a marked range, a single packet, and a user specified 
74    * packet range. The last one is not calculated here since this
75    * data must be entered in the widget by the user.
76    */
77
78   current_count = 0;
79   for(packet = cfile.plist; packet != NULL; packet = packet->next) {
80       current_count++;
81       if (cfile.current_frame == packet) {
82           range->selected_packet = current_count;
83       }
84       if (packet->flags.passed_dfilter) {
85           range->displayed_cnt++;
86       }
87       if (packet->flags.marked) {
88             if (packet->flags.passed_dfilter) {
89                 range->displayed_marked_cnt++;
90                 if (displayed_mark_low == 0) {
91                    displayed_mark_low = current_count;
92                 }
93                 if (current_count > displayed_mark_high) {
94                    displayed_mark_high = current_count;
95                 }
96             }
97
98             if (mark_low == 0) {
99                mark_low = current_count;
100             }
101             if (current_count > mark_high) {
102                mark_high = current_count;
103             }
104       }
105   }
106         
107   current_count = 0;
108   for(packet = cfile.plist; packet != NULL; packet = packet->next) {
109       current_count++;
110
111       if (current_count >= mark_low && 
112           current_count <= mark_high)
113       {
114           range->mark_range_cnt++;
115       }
116
117       if (current_count >= displayed_mark_low && 
118           current_count <= displayed_mark_high)
119       {
120           if (packet->flags.passed_dfilter) {
121             range->displayed_mark_range_cnt++;
122           }
123       }
124   }
125
126   /* in case we marked just one packet, we add 1. */
127   /*if (cfile.marked_count != 0) {
128     range->mark_range = mark_high - mark_low + 1;
129   }*/
130         
131   /* in case we marked just one packet, we add 1. */
132   /*if (range->displayed_marked_cnt != 0) {
133     range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1;
134   }*/
135 }
136
137
138 /* (re-)calculate the user specified packet range counts */
139 void packet_range_calc_user(packet_range_t *range) {
140   guint32       current_count;
141   frame_data    *packet;
142
143   range->user_range_cnt             = 0L;
144   range->displayed_user_range_cnt   = 0L;
145
146   current_count = 0;
147   for(packet = cfile.plist; packet != NULL; packet = packet->next) {
148       current_count++;
149
150       if (packet_is_in_range(range, current_count)) {
151           range->user_range_cnt++;
152           if (packet->flags.passed_dfilter) {
153             range->displayed_user_range_cnt++;
154           }
155       }
156   }
157 }
158
159
160 /* init the range struct */
161 void packet_range_init(packet_range_t *range) {
162
163   range->process            = range_process_all;
164   range->process_filtered   = FALSE;
165   range->nranges            = 0;
166   range->ranges[range->nranges].low  = 0L;
167   range->ranges[range->nranges].high = 0L;
168
169   /* calculate all packet range counters */
170   packet_range_calc(range);
171   packet_range_calc_user(range);
172 }
173
174 /* init the processing run */
175 void packet_range_process_init(packet_range_t *range) {
176   /* "enumeration" values */
177   range->marked_range_active    = FALSE;
178   range->selected_done          = FALSE;
179
180   if (range->process_filtered == FALSE) {
181     range->marked_range_left = range->mark_range_cnt;
182   } else {
183     range->marked_range_left = range->displayed_mark_range_cnt;
184   }
185 }
186
187 /* do we have to process all packets? */
188 gboolean packet_range_process_all(packet_range_t *range) {
189     return range->process == range_process_all && !range->process_filtered;
190 }
191
192 /* do we have to process this packet? */
193 range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) {
194
195     switch(range->process) {
196     case(range_process_all):
197         break;
198     case(range_process_selected):
199         if (range->selected_done) {
200           return range_processing_finished;
201         }
202         if (fdata->num != cfile.current_frame->num) {
203           return range_process_next;
204         }
205         range->selected_done = TRUE;
206         break;
207     case(range_process_marked):
208         if (fdata->flags.marked == FALSE) {
209           return range_process_next;
210         }
211         break;
212     case(range_process_marked_range):
213         if (range->marked_range_left == 0) {
214           return range_processing_finished;
215         }
216         if (fdata->flags.marked == TRUE) {
217           range->marked_range_active = TRUE;
218         }
219         if (range->marked_range_active == FALSE ) {
220           return range_process_next;
221         }
222         if (!range->process_filtered ||
223           (range->process_filtered && fdata->flags.passed_dfilter == TRUE))
224         {
225           range->marked_range_left--;
226         }
227         break;
228     case(range_process_user_range):
229         if (packet_is_in_range(range, fdata->num) == FALSE) {
230           return range_process_next;
231         }
232         break;
233     default:
234         g_assert_not_reached();
235     }
236
237     /* this packet has to pass the display filter but didn't? -> try next */
238     if (range->process_filtered && fdata->flags.passed_dfilter == FALSE) {
239         return range_process_next;
240     }
241
242     /* We fell through the conditions above, so we accept this packet */
243     return range_process_this;
244 }
245
246
247 /******************** Range Entry Parser *********************************/
248
249 /* Converts a range string to a fast comparable array of ranges.
250  * The parameter 'es' points to the string to be converted, and is defined in
251  * the Save/Print-As widget.
252  *
253  * This function fills the array ranges containing low and high values indexed 
254  * by a global variable nranges. After having called this function, the function 
255  * packet_is_in_range() determines whether a given (packet) number is within 
256  * the range or not. 
257  *
258  * In case of a single packet number, we make a range where low is equal to high. 
259  * We strip any characters other than commas, digits, or hyphens. We take care 
260  * on wrongly entered ranges; opposite order will be taken care of.
261  * 
262  * The following syntax is accepted :
263  *
264  *   1-20,30-40     Range from 1 to 20, and packets 30 to 40
265  *   -20,30         Range from 1 to 20, and packet 30
266  *   20,30,40-      Packet number 20, 30, and the range from 40 to the end
267  *   20-10,30-25    Range from 10 to 20, and from 25 to 30
268  *   -              All packets
269  */
270
271 void packet_range_convert_str(packet_range_t *range, const gchar *es)
272 {
273     gchar     EntryStr[255], OrgStr[255], value[255], p;
274     guint     i, j=0;
275     guint32   tmp, val;
276     gboolean  hyphenseen;
277
278     /* Reset the number of ranges we are going to find */
279     range->nranges = 0;
280     range->ranges[range->nranges].low  = 0L;
281     range->ranges[range->nranges].high = 0L;
282
283     /* Make a copy of the string, and check the validity of the input */
284     strcpy(OrgStr,es);
285     if (strlen(OrgStr) == 0 ) {
286         return;
287     }
288
289     /* Only keep digits, commas, and hyphens. */
290     for (i=0; i<=strlen(OrgStr); i++) {
291       if ( isdigit((guchar)OrgStr[i]) || OrgStr[i] == '-' || OrgStr[i] == ',' ) {
292          EntryStr[j++] = OrgStr[i];
293       }
294     }
295     EntryStr[j] = '\0';
296
297     /* Remove any starting commas */
298     strcpy(OrgStr,EntryStr);
299     i = 0;
300     while (OrgStr[i] == ',') {
301        i++;
302     }
303     strcpy(EntryStr,OrgStr+i);
304
305     /* Remove any double commas */
306     strcpy(OrgStr,EntryStr);
307     p = ',';
308     j = 0;
309     for (i=0; i<=strlen(OrgStr); i++) {
310       if ( OrgStr[i] != ',' || p != ',') {
311          EntryStr[j++] = OrgStr[i];
312       }
313       p = OrgStr[i];
314     }
315     EntryStr[j] = '\0';
316
317     /* Remove any double hyphens */
318     strcpy(OrgStr,EntryStr);
319     p = '-';
320     j = 0;
321     for (i=0; i<=strlen(OrgStr); i++) {
322       if (OrgStr[i] != '-' || p != '-' || i == 0) {
323          EntryStr[j++] = OrgStr[i];
324       }
325       p = OrgStr[i];
326     }
327     EntryStr[j] = '\0';
328
329     /* Remove any trailing commas */
330     i = strlen(EntryStr) - 1;
331     while (EntryStr[i] == ',') {
332        EntryStr[i] = '\0';
333        i--;
334     }
335
336     /* The entry string is now filtered, and ready for further parsing */
337     /* printf("Function : packet_range_convert_str EntryStr = %s\n",EntryStr); */
338
339     /* Now we are going to process the ranges separately until we get a comma,
340      * or end of string.
341      *
342      * We build a structure array called ranges of high and low values. After the
343      * following loop, we have the nranges variable which tells how many ranges
344      * were found. The number of individual ranges is limited to 'MaxRanges'
345      */
346
347     j = 0;
348     hyphenseen = FALSE;
349     for (i=0; i<=strlen(EntryStr);i++) {
350
351        /* Copy the digit string until a no-digit character is seen */
352        if (isdigit((guchar)EntryStr[i])) {
353           value[j++] = EntryStr[i];
354           continue;
355        }
356
357        /* Terminate the digit string, and convert it */
358        value[j] = '\0';
359        val=atol(value);
360        j=0;
361
362        /* In case we see a hyphen, store the value we read in the low part 
363         * of ranges. In case it is a trailer hyphen, store the low value, and
364         * set the high value to the maximum of packets captured.
365         */
366        if (EntryStr[i] == '-') {
367           /* If this is a trailer hyphen, then treat it in a different
368            * way, then the high value is the maximum number of packets counted
369            * and we are ready 
370            */
371           if (i == strlen(EntryStr)-1) {
372              range->ranges[range->nranges].low  = val;
373              range->ranges[range->nranges].high = cfile.count;
374              range->nranges++;
375              break;
376           } else {
377              /* Store the low value of the range */
378              range->ranges[range->nranges].low  = val;
379           }
380           hyphenseen=TRUE;
381           continue;
382        }
383
384        /* In case we see a comma, or end of string */
385        if (EntryStr[i] == ',' || i == strlen(EntryStr)) {
386           if (hyphenseen) {
387              /* Normal treatment: store the high value range in ranges */
388              range->ranges[range->nranges].high = val;
389           } else {
390              /* We did not see a hyphen and we get a comma, then this must
391               * be a single packet number */
392              range->ranges[range->nranges].low  = val;
393              range->ranges[range->nranges].high = val;
394           }
395           hyphenseen=FALSE;
396        }
397
398        /* Increase the index for the number of ranges we found, and protect
399         * against wildly outside array bound jumps */
400        range->nranges++;
401        if (range->nranges > MaxRange) {
402            range->nranges--;
403        }
404     }
405     range->nranges--;
406
407     /*  Now we are going through the low and high values, and check
408      *  whether they are in a proper order. Low should be equal or lower
409      *  than high. So, go through the loop and swap if needed.
410      */
411     for (i=0; i <= range->nranges; i++) {
412        if (range->ranges[i].low > range->ranges[i].high) {
413           tmp = range->ranges[i].low;
414           range->ranges[i].low  = range->ranges[i].high;
415           range->ranges[i].high = tmp;
416        }
417     }
418
419     /* In case we want to know what the result ranges are :
420      *
421      * for (i=0; i <= nranges; i++) {
422      *  printf("Function : packet_range_convert_str L=%u \t H=%u\n",ranges[i].low,ranges[i].high);
423      * }
424      *
425      */
426
427     /* calculate new user specified packet range counts */
428     packet_range_calc_user(range);
429 } /* packet_range_convert_str */
430
431 /* This function returns TRUE if a given value is within one of the ranges
432  * stored in the ranges array.
433  */
434 static gboolean packet_is_in_range(packet_range_t *range, guint32 val)
435 {
436    guint i;
437
438    for (i=0; i <= range->nranges; i++) {
439       if (val >= range->ranges[i].low && val <= range->ranges[i].high)
440          return TRUE;
441    }
442    return(FALSE);
443 }
444
445 #if 0
446 /* This is a debug function to check the range functionality */
447 static void packet_is_in_range_check(packet_range_t *range, guint32 val)
448 {
449
450   /* Print the result for a given value */
451   printf("Function : packet_is_in_range_check Number %u\t",val);
452
453   if (packet_is_in_range(range, val)) {
454      printf("is in range\n");
455   } else {
456      printf("is not in range\n");
457   }
458 }
459 #endif