CMake: Allow setting per target compiler warnings
[metze/wireshark/wip.git] / wiretap / wtap_opttypes.c
1 /* wtap_opttypes.c
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 2001 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 #include "config.h"
22
23 #include <glib.h>
24 #include <string.h>
25
26 #include "wtap.h"
27 #include "wtap_opttypes.h"
28 #include "wtap-int.h"
29 #include "pcapng.h"
30 #include "pcapng_module.h"
31
32 #if 0
33 #define wtap_debug(...) g_warning(__VA_ARGS__)
34 #else
35 #define wtap_debug(...)
36 #endif
37
38 /*
39  * Structure describing a type of block.
40  */
41 typedef struct {
42     wtap_block_type_t block_type;    /**< internal type code for block */
43     const char *name;                /**< name of block */
44     const char *description;         /**< human-readable description of block */
45     wtap_block_create_func create;
46     wtap_mand_free_func free_mand;
47     wtap_mand_copy_func copy_mand;
48     GArray *options;                 /**< array of known options */
49 } wtap_blocktype_t;
50
51 typedef void *(*wtap_opttype_dup_custom_func)(void* src);
52 typedef void (*wtap_opttype_free_custom_func)(void* data);
53
54 /*
55  * Structure describing a type of option.
56  */
57 typedef struct {
58     const char *name;                        /**< name of option */
59     const char *description;                 /**< human-readable description of option */
60     wtap_opttype_e data_type;                /**< data type of that option */
61     guint flags;                             /**< flags for the option */
62     wtap_opttype_dup_custom_func dup_func;   /**< function to duplicate custom option data */
63     wtap_opttype_free_custom_func free_func; /**< function to free custom option data */
64 } wtap_opttype_t;
65
66 /* Flags */
67 #define WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED 0x00000001 /* multiple instances allowed */
68
69 struct wtap_block
70 {
71     wtap_blocktype_t* info;
72     void* mandatory_data;
73     GArray* options;
74 };
75
76 #define MAX_WTAP_BLOCK_CUSTOM    10
77 #define MAX_WTAP_BLOCK_TYPE_VALUE (WTAP_BLOCK_END_OF_LIST+MAX_WTAP_BLOCK_CUSTOM)
78
79 /* Keep track of wtap_blocktype_t's via their id number */
80 static wtap_blocktype_t* blocktype_list[MAX_WTAP_BLOCK_TYPE_VALUE];
81 static guint num_custom_blocks;
82 static wtap_blocktype_t custom_blocktype_list[MAX_WTAP_BLOCK_CUSTOM];
83
84 static void wtap_opttype_block_register(wtap_block_type_t block_type, wtap_blocktype_t *blocktype)
85 {
86     static const wtap_opttype_t opt_comment = {
87         "opt_comment",
88         "Comment",
89         WTAP_OPTTYPE_STRING, 
90         WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED,
91         NULL,
92         NULL
93     };
94
95     /* Check input */
96     g_assert(block_type < WTAP_BLOCK_END_OF_LIST);
97
98     /* Don't re-register. */
99     g_assert(blocktype_list[block_type] == NULL);
100
101     /* Sanity check */
102     g_assert(blocktype->name);
103     g_assert(blocktype->description);
104     g_assert(blocktype->create);
105
106     blocktype->block_type = block_type;
107
108     /*
109      * Initialize the set of supported options.
110      * All blocks that support options at all support OPT_COMMENT.
111      */
112     blocktype->options = g_array_sized_new(FALSE, TRUE, sizeof (wtap_opttype_t), OPT_COMMENT + 1);
113     if (OPT_COMMENT + 1 > blocktype->options->len)
114         g_array_set_size(blocktype->options, OPT_COMMENT + 1);
115     g_array_insert_val(blocktype->options, OPT_COMMENT, opt_comment);
116
117     blocktype_list[block_type] = blocktype;
118 }
119
120 int wtap_opttype_register_custom_block_type(const char* name, const char* description, wtap_block_create_func create,
121                                             wtap_mand_free_func free_mand, wtap_mand_copy_func copy_mand)
122 {
123     int block_type;
124
125     /* Ensure valid data/functions for required fields */
126     g_assert(name);
127     g_assert(description);
128     g_assert(create);
129
130     /* This shouldn't happen, so flag it for fixing */
131     g_assert(num_custom_blocks < MAX_WTAP_BLOCK_CUSTOM);
132
133     block_type = (wtap_block_type_t)(WTAP_BLOCK_END_OF_LIST+num_custom_blocks);
134
135     custom_blocktype_list[num_custom_blocks].name = name;
136     custom_blocktype_list[num_custom_blocks].description = description;
137     custom_blocktype_list[num_custom_blocks].create = create;
138     custom_blocktype_list[num_custom_blocks].free_mand = free_mand;
139     custom_blocktype_list[num_custom_blocks].copy_mand = copy_mand;
140     blocktype_list[block_type] = &custom_blocktype_list[num_custom_blocks];
141
142     num_custom_blocks++;
143     return block_type;
144 }
145
146 static void wtap_opttype_option_register(wtap_blocktype_t *blocktype, int opttype, wtap_opttype_t *option)
147 {
148     if ((guint)opttype + 1 > blocktype->options->len)
149         g_array_set_size(blocktype->options, opttype + 1);
150     g_array_insert_val(blocktype->options, opttype, *option);
151 }
152
153 void* wtap_block_get_mandatory_data(wtap_block_t block)
154 {
155     return block->mandatory_data;
156 }
157
158 static wtap_optval_t *
159 wtap_block_get_option(wtap_block_t block, guint option_id)
160 {
161     guint i;
162     wtap_option_t *opt;
163
164     for (i = 0; i < block->options->len; i++) {
165         opt = &g_array_index(block->options, wtap_option_t, i);
166         if (opt->option_id == option_id)
167             return &opt->value;
168     }
169
170     return NULL;
171 }
172
173 static wtap_optval_t *
174 wtap_block_get_nth_option(wtap_block_t block, guint option_id, guint idx)
175 {
176     guint i;
177     wtap_option_t *opt;
178     guint opt_idx;
179
180     opt_idx = 0;
181     for (i = 0; i < block->options->len; i++) {
182         opt = &g_array_index(block->options, wtap_option_t, i);
183         if (opt->option_id == option_id) {
184             if (opt_idx == idx)
185                 return &opt->value;
186             opt_idx++;
187         }
188     }
189
190     return NULL;
191 }
192
193 wtap_block_t wtap_block_create(wtap_block_type_t block_type)
194 {
195     wtap_block_t block;
196
197     if (block_type >= (wtap_block_type_t)(WTAP_BLOCK_END_OF_LIST+num_custom_blocks))
198         return NULL;
199
200     block = g_new(struct wtap_block, 1);
201     block->info = blocktype_list[block_type];
202     block->options = g_array_new(FALSE, FALSE, sizeof(wtap_option_t));
203     block->info->create(block);
204
205     return block;
206 }
207
208 static void wtap_block_free_option(wtap_block_t block, wtap_option_t *opt)
209 {
210     wtap_opttype_t *opttype;
211
212     opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
213     switch (opttype->data_type) {
214
215     case WTAP_OPTTYPE_STRING:
216         g_free(opt->value.stringval);
217         break;
218
219     case WTAP_OPTTYPE_CUSTOM:
220         opttype->free_func(opt->value.customval.data);
221         g_free(opt->value.customval.data);
222         break;
223
224     default:
225         break;
226     }
227 }
228
229 static void wtap_block_free_options(wtap_block_t block)
230 {
231     guint i;
232     wtap_option_t *opt;
233
234     for (i = 0; i < block->options->len; i++) {
235         opt = &g_array_index(block->options, wtap_option_t, i);
236         wtap_block_free_option(block, opt);
237     }
238 }
239
240 void wtap_block_free(wtap_block_t block)
241 {
242     if (block != NULL)
243     {
244         if (block->info->free_mand != NULL)
245             block->info->free_mand(block);
246
247         g_free(block->mandatory_data);
248         wtap_block_free_options(block);
249         g_array_free(block->options, TRUE);
250         g_free(block);
251     }
252 }
253
254 void wtap_block_array_free(GArray* block_array)
255 {
256     guint block;
257
258     if (block_array == NULL)
259         return;
260
261     for (block = 0; block < block_array->len; block++) {
262         wtap_block_free(g_array_index(block_array, wtap_block_t, block));
263     }
264     g_array_free(block_array, TRUE);
265 }
266
267 /*
268  * Make a copy of a block.
269  */
270 void
271 wtap_block_copy(wtap_block_t dest_block, wtap_block_t src_block)
272 {
273     guint i;
274     wtap_option_t *src_opt;
275     wtap_opttype_t *opttype;
276
277     /*
278      * Copy the mandatory data.
279      */
280     if (dest_block->info->copy_mand != NULL)
281         dest_block->info->copy_mand(dest_block, src_block);
282
283     /* Copy the options.  For now, don't remove any options that are in destination
284      * but not source.
285      */
286     for (i = 0; i < src_block->options->len; i++)
287     {
288         src_opt = &g_array_index(src_block->options, wtap_option_t, i);
289         opttype = &g_array_index(src_block->info->options, wtap_opttype_t, src_opt->option_id);
290
291         switch(opttype->data_type) {
292
293         case WTAP_OPTTYPE_UINT8:
294             wtap_block_add_uint8_option(dest_block, src_opt->option_id, src_opt->value.uint8val);
295             break;
296
297         case WTAP_OPTTYPE_UINT64:
298             wtap_block_add_uint64_option(dest_block, src_opt->option_id, src_opt->value.uint64val);
299             break;
300
301         case WTAP_OPTTYPE_IPv4:
302             wtap_block_add_ipv4_option(dest_block, src_opt->option_id, src_opt->value.ipv4val);
303             break;
304
305         case WTAP_OPTTYPE_IPv6:
306             wtap_block_add_ipv6_option(dest_block, src_opt->option_id, &src_opt->value.ipv6val);
307             break;
308
309         case WTAP_OPTTYPE_STRING:
310             wtap_block_add_string_option(dest_block, src_opt->option_id, src_opt->value.stringval, strlen(src_opt->value.stringval));
311             break;
312
313         case WTAP_OPTTYPE_CUSTOM:
314             wtap_block_add_custom_option(dest_block, src_opt->option_id, src_opt->value.customval.data, src_opt->value.customval.size);
315             break;
316         }
317     }
318 }
319
320 void wtap_block_foreach_option(wtap_block_t block, wtap_block_foreach_func func, void* user_data)
321 {
322     guint i;
323     wtap_option_t *opt;
324     wtap_opttype_t *opttype;
325
326     for (i = 0; i < block->options->len; i++) {
327         opt = &g_array_index(block->options, wtap_option_t, i);
328         opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
329         func(block, opt->option_id, opttype->data_type, &opt->value, user_data);
330     }
331 }
332
333 static wtap_opttype_return_val
334 wtap_block_add_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, wtap_option_t **optp)
335 {
336     wtap_option_t *opt;
337     wtap_opttype_t *opttype;
338     guint i;
339
340     if (option_id >= block->info->options->len) {
341         /* There's no option for this block with that option ID */
342         return WTAP_OPTTYPE_NO_SUCH_OPTION;
343     }
344     opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
345
346     /*
347      * Is this an option of the specified data type?
348      */
349     if (opttype->data_type != type) {
350         /*
351          * No.
352          */
353         return WTAP_OPTTYPE_TYPE_MISMATCH;
354     }
355
356     /*
357      * Can there be more than one instance of this option?
358      */
359     if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
360         /*
361          * No. Is there already an instance of this option?
362          */
363         if (wtap_block_get_option(block, option_id) != NULL) {
364             /*
365              * Yes. Fail.
366              */
367             return WTAP_OPTTYPE_ALREADY_EXISTS;
368         }
369     }
370
371     /*
372      * Add an instance.
373      */
374     i = block->options->len;
375     g_array_set_size(block->options, i + 1);
376     opt = &g_array_index(block->options, wtap_option_t, i);
377     opt->option_id = option_id;
378     *optp = opt;
379     return WTAP_OPTTYPE_SUCCESS;
380 }
381
382 static wtap_opttype_return_val
383 wtap_block_get_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, wtap_optval_t **optvalp)
384 {
385     wtap_opttype_t *opttype;
386     wtap_optval_t *optval;
387
388     if (option_id >= block->info->options->len) {
389         /* There's no option for this block with that option ID */
390         return WTAP_OPTTYPE_NO_SUCH_OPTION;
391     }
392
393     opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
394
395     /*
396      * Is this an option of the specified data type?
397      */
398     if (opttype->data_type != type) {
399         /*
400          * No.
401          */
402         return WTAP_OPTTYPE_TYPE_MISMATCH;
403     }
404
405     /*
406      * Can there be more than one instance of this option?
407      */
408     if (opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED) {
409         /*
410          * Yes.  You can't ask for "the" value.
411          */
412         return WTAP_OPTTYPE_NUMBER_MISMATCH;
413     }
414
415     optval = wtap_block_get_option(block, option_id);
416     if (optval == NULL) {
417         /* Didn't find the option */
418         return WTAP_OPTTYPE_NOT_FOUND;
419     }
420
421     *optvalp = optval;
422     return WTAP_OPTTYPE_SUCCESS;
423 }
424
425 static wtap_opttype_return_val
426 wtap_block_get_nth_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, guint idx, wtap_optval_t **optvalp)
427 {
428     wtap_opttype_t *opttype;
429     wtap_optval_t *optval;
430
431     if (option_id >= block->info->options->len) {
432         /* There's no option for this block with that option ID */
433         return WTAP_OPTTYPE_NO_SUCH_OPTION;
434     }
435
436     opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
437
438     /*
439      * Is this an option of the specified data type?
440      */
441     if (opttype->data_type != type) {
442         /*
443          * No.
444          */
445         return WTAP_OPTTYPE_TYPE_MISMATCH;
446     }
447
448     /*
449      * Can there be more than one instance of this option?
450      */
451     if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
452         /*
453          * No.
454          */
455         return WTAP_OPTTYPE_NUMBER_MISMATCH;
456     }
457
458     optval = wtap_block_get_nth_option(block, option_id, idx);
459     if (optval == NULL) {
460         /* Didn't find the option */
461         return WTAP_OPTTYPE_NOT_FOUND;
462     }
463
464     *optvalp = optval;
465     return WTAP_OPTTYPE_SUCCESS;
466 }
467
468 wtap_opttype_return_val
469 wtap_block_add_uint8_option(wtap_block_t block, guint option_id, guint8 value)
470 {
471     wtap_opttype_return_val ret;
472     wtap_option_t *opt;
473
474     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &opt);
475     if (ret != WTAP_OPTTYPE_SUCCESS)
476         return ret;
477     opt->value.uint8val = value;
478     return WTAP_OPTTYPE_SUCCESS;
479 }
480
481 wtap_opttype_return_val
482 wtap_block_set_uint8_option_value(wtap_block_t block, guint option_id, guint8 value)
483 {
484     wtap_opttype_return_val ret;
485     wtap_optval_t *optval;
486
487     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &optval);
488     if (ret != WTAP_OPTTYPE_SUCCESS)
489         return ret;
490     optval->uint8val = value;
491     return WTAP_OPTTYPE_SUCCESS;
492 }
493
494 wtap_opttype_return_val
495 wtap_block_get_uint8_option_value(wtap_block_t block, guint option_id, guint8* value)
496 {
497     wtap_opttype_return_val ret;
498     wtap_optval_t *optval;
499
500     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &optval);
501     if (ret != WTAP_OPTTYPE_SUCCESS)
502         return ret;
503     *value = optval->uint8val;
504     return WTAP_OPTTYPE_SUCCESS;
505 }
506
507 wtap_opttype_return_val
508 wtap_block_add_uint64_option(wtap_block_t block, guint option_id, guint64 value)
509 {
510     wtap_opttype_return_val ret;
511     wtap_option_t *opt;
512
513     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &opt);
514     if (ret != WTAP_OPTTYPE_SUCCESS)
515         return ret;
516     opt->value.uint64val = value;
517     return WTAP_OPTTYPE_SUCCESS;
518 }
519
520 wtap_opttype_return_val
521 wtap_block_set_uint64_option_value(wtap_block_t block, guint option_id, guint64 value)
522 {
523     wtap_opttype_return_val ret;
524     wtap_optval_t *optval;
525
526     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &optval);
527     if (ret != WTAP_OPTTYPE_SUCCESS)
528         return ret;
529     optval->uint64val = value;
530     return WTAP_OPTTYPE_SUCCESS;
531 }
532
533 wtap_opttype_return_val
534 wtap_block_get_uint64_option_value(wtap_block_t block, guint option_id, guint64 *value)
535 {
536     wtap_opttype_return_val ret;
537     wtap_optval_t *optval;
538
539     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &optval);
540     if (ret != WTAP_OPTTYPE_SUCCESS)
541         return ret;
542     *value = optval->uint64val;
543     return WTAP_OPTTYPE_SUCCESS;
544 }
545
546 wtap_opttype_return_val
547 wtap_block_add_ipv4_option(wtap_block_t block, guint option_id, guint32 value)
548 {
549     wtap_opttype_return_val ret;
550     wtap_option_t *opt;
551
552     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &opt);
553     if (ret != WTAP_OPTTYPE_SUCCESS)
554         return ret;
555     opt->value.ipv4val = value;
556     return WTAP_OPTTYPE_SUCCESS;
557 }
558
559 wtap_opttype_return_val
560 wtap_block_set_ipv4_option_value(wtap_block_t block, guint option_id, guint32 value)
561 {
562     wtap_opttype_return_val ret;
563     wtap_optval_t *optval;
564
565     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
566     if (ret != WTAP_OPTTYPE_SUCCESS)
567         return ret;
568     optval->ipv4val = value;
569     return WTAP_OPTTYPE_SUCCESS;
570 }
571
572 wtap_opttype_return_val
573 wtap_block_get_ipv4_option_value(wtap_block_t block, guint option_id, guint32* value)
574 {
575     wtap_opttype_return_val ret;
576     wtap_optval_t *optval;
577
578     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
579     if (ret != WTAP_OPTTYPE_SUCCESS)
580         return ret;
581     *value = optval->ipv4val;
582     return WTAP_OPTTYPE_SUCCESS;
583 }
584
585 wtap_opttype_return_val
586 wtap_block_add_ipv6_option(wtap_block_t block, guint option_id, struct e_in6_addr *value)
587 {
588     wtap_opttype_return_val ret;
589     wtap_option_t *opt;
590
591     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_IPv6, &opt);
592     if (ret != WTAP_OPTTYPE_SUCCESS)
593         return ret;
594     opt->value.ipv6val = *value;
595     return WTAP_OPTTYPE_SUCCESS;
596 }
597
598 wtap_opttype_return_val
599 wtap_block_set_ipv6_option_value(wtap_block_t block, guint option_id, struct e_in6_addr *value)
600 {
601     wtap_opttype_return_val ret;
602     wtap_optval_t *optval;
603
604     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv6, &optval);
605     if (ret != WTAP_OPTTYPE_SUCCESS)
606         return ret;
607     optval->ipv6val = *value;
608     return WTAP_OPTTYPE_SUCCESS;
609 }
610
611 wtap_opttype_return_val
612 wtap_block_get_ipv6_option_value(wtap_block_t block, guint option_id, struct e_in6_addr* value)
613 {
614     wtap_opttype_return_val ret;
615     wtap_optval_t *optval;
616
617     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
618     if (ret != WTAP_OPTTYPE_SUCCESS)
619         return ret;
620     *value = optval->ipv6val;
621     return WTAP_OPTTYPE_SUCCESS;
622 }
623
624 wtap_opttype_return_val
625 wtap_block_add_string_option(wtap_block_t block, guint option_id, const char *value, gsize value_length)
626 {
627     wtap_opttype_return_val ret;
628     wtap_option_t *opt;
629
630     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
631     if (ret != WTAP_OPTTYPE_SUCCESS)
632         return ret;
633     opt->value.stringval = g_strndup(value, value_length);
634     return WTAP_OPTTYPE_SUCCESS;
635 }
636
637 static wtap_opttype_return_val
638 wtap_block_add_string_option_vformat(wtap_block_t block, guint option_id, const char *format, va_list va)
639 {
640     wtap_opttype_return_val ret;
641     wtap_option_t *opt;
642
643     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
644     if (ret != WTAP_OPTTYPE_SUCCESS)
645         return ret;
646     opt->value.stringval = g_strdup_vprintf(format, va);
647     return WTAP_OPTTYPE_SUCCESS;
648 }
649
650 wtap_opttype_return_val
651 wtap_block_add_string_option_format(wtap_block_t block, guint option_id, const char *format, ...)
652 {
653     wtap_opttype_return_val ret;
654     wtap_option_t *opt;
655     va_list va;
656
657     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
658     if (ret != WTAP_OPTTYPE_SUCCESS)
659         return ret;
660     va_start(va, format);
661     opt->value.stringval = g_strdup_vprintf(format, va);
662     va_end(va);
663     return WTAP_OPTTYPE_SUCCESS;
664 }
665
666 wtap_opttype_return_val
667 wtap_block_set_string_option_value(wtap_block_t block, guint option_id, const char *value, size_t value_length)
668 {
669     wtap_opttype_return_val ret;
670     wtap_optval_t *optval;
671
672     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
673     if (ret != WTAP_OPTTYPE_SUCCESS) {
674         if (ret == WTAP_OPTTYPE_NOT_FOUND) {
675             /*
676              * There's no instance to set, so just try to create a new one
677              * with the value.
678              */
679             return wtap_block_add_string_option(block, option_id, value, value_length);
680         }
681         /* Otherwise fail. */
682         return ret;
683     }
684     g_free(optval->stringval);
685     optval->stringval = g_strndup(value, value_length);
686     return WTAP_OPTTYPE_SUCCESS;
687 }
688
689 wtap_opttype_return_val
690 wtap_block_set_nth_string_option_value(wtap_block_t block, guint option_id, guint idx, const char *value, size_t value_length)
691 {
692     wtap_opttype_return_val ret;
693     wtap_optval_t *optval;
694
695     ret = wtap_block_get_nth_option_common(block, option_id, WTAP_OPTTYPE_STRING, idx, &optval);
696     if (ret != WTAP_OPTTYPE_SUCCESS)
697         return ret;
698     g_free(optval->stringval);
699     optval->stringval = g_strndup(value, value_length);
700     return WTAP_OPTTYPE_SUCCESS;
701 }
702
703 wtap_opttype_return_val
704 wtap_block_set_string_option_value_format(wtap_block_t block, guint option_id, const char *format, ...)
705 {
706     wtap_opttype_return_val ret;
707     wtap_optval_t *optval;
708     va_list va;
709
710     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
711     if (ret != WTAP_OPTTYPE_SUCCESS) {
712         if (ret == WTAP_OPTTYPE_NOT_FOUND) {
713             /*
714              * There's no instance to set, so just try to create a new one
715              * with the formatted string.
716              */
717             va_start(va, format);
718             ret = wtap_block_add_string_option_vformat(block, option_id, format, va);
719             va_end(va);
720             return ret;
721         }
722         /* Otherwise fail. */
723         return ret;
724     }
725     g_free(optval->stringval);
726     va_start(va, format);
727     optval->stringval = g_strdup_vprintf(format, va);
728     va_end(va);
729     return WTAP_OPTTYPE_SUCCESS;
730 }
731
732 wtap_opttype_return_val
733 wtap_block_get_string_option_value(wtap_block_t block, guint option_id, char** value)
734 {
735     wtap_opttype_return_val ret;
736     wtap_optval_t *optval;
737
738     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
739     if (ret != WTAP_OPTTYPE_SUCCESS)
740         return ret;
741     *value = optval->stringval;
742     return WTAP_OPTTYPE_SUCCESS;
743 }
744
745 wtap_opttype_return_val
746 wtap_block_get_nth_string_option_value(wtap_block_t block, guint option_id, guint idx, char** value)
747 {
748     wtap_opttype_return_val ret;
749     wtap_optval_t *optval;
750
751     ret = wtap_block_get_nth_option_common(block, option_id, WTAP_OPTTYPE_STRING, idx, &optval);
752     if (ret != WTAP_OPTTYPE_SUCCESS)
753         return ret;
754     *value = optval->stringval;
755     return WTAP_OPTTYPE_SUCCESS;
756 }
757
758 wtap_opttype_return_val
759 wtap_block_add_custom_option(wtap_block_t block, guint option_id, void *value, size_t value_size)
760 {
761     wtap_opttype_return_val ret;
762     wtap_option_t *opt;
763     wtap_opttype_t *opttype;
764
765     ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &opt);
766     if (ret != WTAP_OPTTYPE_SUCCESS)
767         return ret;
768     opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
769     opt->value.customval.size = (guint)value_size;
770     opt->value.customval.data = opttype->dup_func(value);
771     return WTAP_OPTTYPE_SUCCESS;
772 }
773
774 wtap_opttype_return_val
775 wtap_block_get_custom_option_value(wtap_block_t block, guint option_id, void** value)
776 {
777     wtap_opttype_return_val ret;
778     wtap_optval_t *optval;
779
780     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &optval);
781     if (ret != WTAP_OPTTYPE_SUCCESS)
782         return ret;
783     *value = optval->customval.data;
784     return WTAP_OPTTYPE_SUCCESS;
785 }
786
787 wtap_opttype_return_val
788 wtap_block_set_custom_option_value(wtap_block_t block, guint option_id, void *value)
789 {
790     wtap_opttype_return_val ret;
791     wtap_optval_t *optval;
792     void *prev_value;
793
794     ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &optval);
795     if (ret != WTAP_OPTTYPE_SUCCESS)
796         return ret;
797     prev_value = optval->customval.data;
798     /*
799      * XXX - a custom value can be a structure that points to other data,
800      * but we're doing a shallow copy here.
801      */
802     optval->customval.data = g_memdup(value, optval->customval.size);
803     /* Free after memory is duplicated in case structure was manipulated with a "get then set" */
804     g_free(prev_value);
805
806     return WTAP_OPTTYPE_SUCCESS;
807 }
808
809 wtap_opttype_return_val
810 wtap_block_remove_option(wtap_block_t block, guint option_id)
811 {
812     wtap_opttype_t *opttype;
813     guint i;
814     wtap_option_t *opt;
815
816     if (option_id >= block->info->options->len) {
817         /* There's no option for this block with that option ID */
818         return WTAP_OPTTYPE_NO_SUCH_OPTION;
819     }
820
821     opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
822
823     /*
824      * Can there be more than one instance of this option?
825      */
826     if (opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED) {
827         /*
828          * Yes.  You can't remove "the" value.
829          */
830         return WTAP_OPTTYPE_NUMBER_MISMATCH;
831     }
832
833     for (i = 0; i < block->options->len; i++) {
834         opt = &g_array_index(block->options, wtap_option_t, i);
835         if (opt->option_id == option_id) {
836             /* Found it - free up the value */
837             wtap_block_free_option(block, opt);
838             /* Remove the option from the array of options */
839             g_array_remove_index(block->options, i);
840             return WTAP_OPTTYPE_SUCCESS;
841         }
842     }
843
844     /* Didn't find the option */
845     return WTAP_OPTTYPE_NOT_FOUND;
846 }
847
848 wtap_opttype_return_val
849 wtap_block_remove_nth_option_instance(wtap_block_t block, guint option_id,
850                                       guint idx)
851 {
852     wtap_opttype_t *opttype;
853     guint i;
854     wtap_option_t *opt;
855     guint opt_idx;
856
857     if (option_id >= block->info->options->len) {
858         /* There's no option for this block with that option ID */
859         return WTAP_OPTTYPE_NO_SUCH_OPTION;
860     }
861
862     opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
863
864     /*
865      * Can there be more than one instance of this option?
866      */
867     if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
868         /*
869          * No.
870          */
871         return WTAP_OPTTYPE_NUMBER_MISMATCH;
872     }
873
874     opt_idx = 0;
875     for (i = 0; i < block->options->len; i++) {
876         opt = &g_array_index(block->options, wtap_option_t, i);
877         if (opt->option_id == option_id) {
878             if (opt_idx == idx) {
879                 /* Found it - free up the value */
880                 wtap_block_free_option(block, opt);
881                 /* Remove the option from the array of options */
882                 g_array_remove_index(block->options, i);
883                 return WTAP_OPTTYPE_SUCCESS;
884             }
885             opt_idx++;
886         }
887     }
888
889     /* Didn't find the option */
890     return WTAP_OPTTYPE_NOT_FOUND;
891 }
892
893 static void shb_create(wtap_block_t block)
894 {
895     wtapng_mandatory_section_t* section_mand = g_new(wtapng_mandatory_section_t, 1);
896
897     section_mand->section_length = -1;
898
899     block->mandatory_data = section_mand;
900 }
901
902 static void shb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
903 {
904     memcpy(dest_block->mandatory_data, src_block->mandatory_data, sizeof(wtapng_mandatory_section_t));
905 }
906
907 static void nrb_create(wtap_block_t block)
908 {
909     block->mandatory_data = NULL;
910 }
911
912 static void isb_create(wtap_block_t block)
913 {
914     block->mandatory_data = g_new0(wtapng_if_stats_mandatory_t, 1);
915 }
916
917 static void isb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
918 {
919     memcpy(dest_block->mandatory_data, src_block->mandatory_data, sizeof(wtapng_if_stats_mandatory_t));
920 }
921
922 static void *idb_filter_dup(void* src)
923 {
924     wtapng_if_descr_filter_t* filter_src = (wtapng_if_descr_filter_t*)src;
925     wtapng_if_descr_filter_t* filter_dest;
926
927     /* Deep copy. */
928     filter_dest = g_new(wtapng_if_descr_filter_t, 1);
929     filter_dest->if_filter_str = g_strdup(filter_src->if_filter_str);
930     filter_dest->bpf_filter_len = filter_src->bpf_filter_len;
931     filter_dest->if_filter_bpf_bytes = (guint8 *)g_memdup(filter_src->if_filter_bpf_bytes, filter_src->bpf_filter_len);
932     return (void *)filter_dest;
933 }
934
935 static void idb_filter_free(void* data)
936 {
937     wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)data;
938     g_free(filter->if_filter_str);
939     g_free(filter->if_filter_bpf_bytes);
940 }
941
942 static void idb_create(wtap_block_t block)
943 {
944     block->mandatory_data = g_new0(wtapng_if_descr_mandatory_t, 1);
945 }
946
947 static void idb_free_mand(wtap_block_t block)
948 {
949     guint j;
950     wtap_block_t if_stats;
951     wtapng_if_descr_mandatory_t* mand = (wtapng_if_descr_mandatory_t*)block->mandatory_data;
952
953     for(j = 0; j < mand->num_stat_entries; j++) {
954         if_stats = g_array_index(mand->interface_statistics, wtap_block_t, j);
955         wtap_block_free(if_stats);
956     }
957
958     if (mand->interface_statistics)
959         g_array_free(mand->interface_statistics, TRUE);
960 }
961
962 static void idb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
963 {
964     guint j;
965     wtap_block_t src_if_stats, dest_if_stats;
966     wtapng_if_descr_mandatory_t *src_mand = (wtapng_if_descr_mandatory_t*)src_block->mandatory_data,
967                                 *dest_mand = (wtapng_if_descr_mandatory_t*)dest_block->mandatory_data;
968
969     /* Need special consideration for copying of the interface_statistics member */
970     if (dest_mand->num_stat_entries != 0)
971         g_array_free(dest_mand->interface_statistics, TRUE);
972
973     memcpy(dest_mand, src_mand, sizeof(wtapng_if_descr_mandatory_t));
974     if (src_mand->num_stat_entries != 0)
975     {
976         dest_mand->interface_statistics = g_array_new(FALSE, FALSE, sizeof(wtap_block_t));
977         for (j = 0; j < src_mand->num_stat_entries; j++)
978         {
979             src_if_stats = g_array_index(src_mand->interface_statistics, wtap_block_t, j);
980             dest_if_stats = wtap_block_create(WTAP_BLOCK_IF_STATS);
981             wtap_block_copy(dest_if_stats, src_if_stats);
982             dest_mand->interface_statistics = g_array_append_val(dest_mand->interface_statistics, dest_if_stats);
983         }
984     }
985 }
986
987 void wtap_opttypes_initialize(void)
988 {
989     static wtap_blocktype_t shb_block = {
990         WTAP_BLOCK_NG_SECTION,  /* block_type */
991         "SHB",                  /* name */
992         "Section Header Block", /* description */
993         shb_create,             /* create */
994         NULL,                   /* free_mand */
995         shb_copy_mand,          /* copy_mand */
996         NULL                    /* options */
997     };
998     static wtap_opttype_t shb_hardware = {
999         "hardware",
1000         "SHB Hardware",
1001         WTAP_OPTTYPE_STRING,
1002         0,
1003         NULL,
1004         NULL
1005     };
1006     static wtap_opttype_t shb_os = {
1007         "os",
1008         "SHB Operating System",
1009         WTAP_OPTTYPE_STRING,
1010         0,
1011         NULL,
1012         NULL
1013     };
1014     static wtap_opttype_t shb_userappl = {
1015         "user_appl",
1016         "SHB User Application",
1017         WTAP_OPTTYPE_STRING,
1018         0,
1019         NULL,
1020         NULL
1021     };
1022
1023     static wtap_blocktype_t idb_block = {
1024         WTAP_BLOCK_IF_DESCR,           /* block_type */
1025         "IDB",                         /* name */
1026         "Interface Description Block", /* description */
1027         idb_create,                    /* create */
1028         idb_free_mand,                 /* free_mand */
1029         idb_copy_mand,                 /* copy_mand */
1030         NULL                           /* options */
1031     };
1032     static wtap_opttype_t if_name = {
1033         "name",
1034         "IDB Name",
1035         WTAP_OPTTYPE_STRING,
1036         0,
1037         NULL,
1038         NULL
1039     };
1040     static wtap_opttype_t if_description = {
1041         "description",
1042         "IDB Description",
1043         WTAP_OPTTYPE_STRING,
1044         0,
1045         NULL,
1046         NULL
1047     };
1048     static wtap_opttype_t if_speed = {
1049         "speed",
1050         "IDB Speed",
1051         WTAP_OPTTYPE_UINT64,
1052         0,
1053         NULL,
1054         NULL
1055     };
1056     static wtap_opttype_t if_tsresol = {
1057         "tsresol",
1058         "IDB Time Stamp Resolution",
1059         WTAP_OPTTYPE_UINT8, /* XXX - signed? */
1060         0,
1061         NULL,
1062         NULL
1063     };
1064     static wtap_opttype_t if_filter = {
1065         "filter",
1066         "IDB Filter",
1067         WTAP_OPTTYPE_CUSTOM,
1068         0,
1069         idb_filter_dup,
1070         idb_filter_free
1071     };
1072     static wtap_opttype_t if_os = {
1073         "os",
1074         "IDB Operating System",
1075         WTAP_OPTTYPE_STRING,
1076         0,
1077         NULL,
1078         NULL
1079     };
1080     static wtap_opttype_t if_fcslen = {
1081         "fcslen",
1082         "IDB FCS Length",
1083         WTAP_OPTTYPE_UINT8,
1084         0,
1085         NULL,
1086         NULL
1087     };
1088
1089     static wtap_blocktype_t nrb_block = {
1090         WTAP_BLOCK_NG_NRB,       /* block_type */
1091         "NRB",                   /* name */
1092         "Name Resolution Block", /* description */
1093         nrb_create,              /* create */
1094         NULL,                    /* free_mand */
1095         NULL,                    /* copy_mand */
1096         NULL                     /* options */
1097     };
1098     static wtap_opttype_t ns_dnsname = {
1099         "dnsname",
1100         "NRB DNS server name",
1101         WTAP_OPTTYPE_STRING,
1102         0,
1103         NULL,
1104         NULL
1105     };
1106     static wtap_opttype_t ns_dnsIP4addr = {
1107         "dnsIP4addr",
1108         "NRB DNS server IPv4 address",
1109         WTAP_OPTTYPE_IPv4,
1110         0,
1111         NULL,
1112         NULL
1113     };
1114     static wtap_opttype_t ns_dnsIP6addr = {
1115         "dnsIP6addr",
1116         "NRB DNS server IPv6 address",
1117         WTAP_OPTTYPE_IPv6,
1118         0,
1119         NULL,
1120         NULL
1121     };
1122
1123     static wtap_blocktype_t isb_block = {
1124         WTAP_BLOCK_IF_STATS,          /* block_type */
1125         "ISB",                        /* name */
1126         "Interface Statistics Block", /* description */
1127         isb_create,                   /* create */
1128         NULL,                         /* free_mand */
1129         isb_copy_mand,                /* copy_mand */
1130         NULL                          /* options */
1131     };
1132     static wtap_opttype_t isb_starttime = {
1133         "starttime",
1134         "ISB Start Time",
1135         WTAP_OPTTYPE_UINT64,
1136         0,
1137         NULL,
1138         NULL
1139     };
1140     static wtap_opttype_t isb_endtime = {
1141         "endtime",
1142         "ISB End Time",
1143         WTAP_OPTTYPE_UINT64,
1144         0,
1145         NULL,
1146         NULL
1147     };
1148     static wtap_opttype_t isb_ifrecv = {
1149         "ifrecv",
1150         "ISB Received Packets",
1151         WTAP_OPTTYPE_UINT64,
1152         0,
1153         NULL,
1154         NULL
1155     };
1156     static wtap_opttype_t isb_ifdrop = {
1157         "ifdrop",
1158         "ISB Dropped Packets",
1159         WTAP_OPTTYPE_UINT64,
1160         0,
1161         NULL,
1162         NULL
1163     };
1164     static wtap_opttype_t isb_filteraccept = {
1165         "filteraccept",
1166         "ISB Packets Accepted By Filter",
1167         WTAP_OPTTYPE_UINT64,
1168         0,
1169         NULL,
1170         NULL
1171     };
1172     static wtap_opttype_t isb_osdrop = {
1173         "osdrop",
1174         "ISB Packets Dropped By The OS",
1175         WTAP_OPTTYPE_UINT64,
1176         0,
1177         NULL,
1178         NULL
1179     };
1180     static wtap_opttype_t isb_usrdeliv = {
1181         "usrdeliv",
1182         "ISB Packets Delivered To The User",
1183         WTAP_OPTTYPE_UINT64,
1184         0,
1185         NULL,
1186         NULL
1187     };
1188
1189     /* Initialize the custom block array.  This is for future proofing
1190        "outside registered" block types (for NULL checking) */
1191     memset(blocktype_list, 0, MAX_WTAP_BLOCK_TYPE_VALUE*sizeof(wtap_blocktype_t*));
1192     num_custom_blocks = 0;
1193
1194     /*
1195      * Registser the SHB and the options that can appear in it.
1196      */
1197     wtap_opttype_block_register(WTAP_BLOCK_NG_SECTION, &shb_block);
1198     wtap_opttype_option_register(&shb_block, OPT_SHB_HARDWARE, &shb_hardware);
1199     wtap_opttype_option_register(&shb_block, OPT_SHB_OS, &shb_os);
1200     wtap_opttype_option_register(&shb_block, OPT_SHB_USERAPPL, &shb_userappl);
1201
1202     /*
1203      * Register the IDB and the options that can appear in it.
1204      */
1205     wtap_opttype_block_register(WTAP_BLOCK_IF_DESCR, &idb_block);
1206     wtap_opttype_option_register(&idb_block, OPT_IDB_NAME, &if_name);
1207     wtap_opttype_option_register(&idb_block, OPT_IDB_DESCR, &if_description);
1208     wtap_opttype_option_register(&idb_block, OPT_IDB_SPEED, &if_speed);
1209     wtap_opttype_option_register(&idb_block, OPT_IDB_TSRESOL, &if_tsresol);
1210     wtap_opttype_option_register(&idb_block, OPT_IDB_FILTER, &if_filter);
1211     wtap_opttype_option_register(&idb_block, OPT_IDB_OS, &if_os);
1212     wtap_opttype_option_register(&idb_block, OPT_IDB_FCSLEN, &if_fcslen);
1213
1214     /*
1215      * Register the NRB and the options that can appear in it.
1216      */
1217     wtap_opttype_block_register(WTAP_BLOCK_NG_NRB, &nrb_block);
1218     wtap_opttype_option_register(&nrb_block, OPT_NS_DNSNAME, &ns_dnsname);
1219     wtap_opttype_option_register(&nrb_block, OPT_NS_DNSIP4ADDR, &ns_dnsIP4addr);
1220     wtap_opttype_option_register(&nrb_block, OPT_NS_DNSIP6ADDR, &ns_dnsIP6addr);
1221
1222     /*
1223      * Register the ISB and the options that can appear in it.
1224      */
1225     wtap_opttype_block_register(WTAP_BLOCK_IF_STATS, &isb_block);
1226     wtap_opttype_option_register(&isb_block, OPT_ISB_STARTTIME, &isb_starttime);
1227     wtap_opttype_option_register(&isb_block, OPT_ISB_ENDTIME, &isb_endtime);
1228     wtap_opttype_option_register(&isb_block, OPT_ISB_IFRECV, &isb_ifrecv);
1229     wtap_opttype_option_register(&isb_block, OPT_ISB_IFDROP, &isb_ifdrop);
1230     wtap_opttype_option_register(&isb_block, OPT_ISB_FILTERACCEPT, &isb_filteraccept);
1231     wtap_opttype_option_register(&isb_block, OPT_ISB_OSDROP, &isb_osdrop);
1232     wtap_opttype_option_register(&isb_block, OPT_ISB_USRDELIV, &isb_usrdeliv);
1233 }