/* drange.c * Routines for providing general range support to the dfilter library * * Copyright (c) 2000 by Ed Warnicke * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1999 Gerald Combs * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include "drange.h" #include #include /* drange_node constructor */ drange_node* drange_node_new(void) { drange_node* new_range_node; new_range_node = g_new(drange_node,1); new_range_node->start_offset = 0; new_range_node->length = 0; new_range_node->end_offset = 0; new_range_node->ending = DRANGE_NODE_END_T_UNINITIALIZED; return new_range_node; } static bool drange_str_to_gint32(const char *s, int32_t *pint, char **endptr, char **err_ptr) { long integer; errno = 0; integer = strtol(s, endptr, 0); if (errno == EINVAL || *endptr == s) { /* This isn't a valid number. */ *err_ptr = ws_strdup_printf("\"%s\" is not a valid number.", s); return false; } if (errno == ERANGE || integer > INT32_MAX || integer < INT32_MIN) { *err_ptr = ws_strdup_printf("\"%s\" causes an integer overflow.", s); return false; } *pint = (int32_t)integer; return true; } /* drange_node constructor from string */ drange_node* drange_node_from_str(const char *range_str, char **err_ptr) { const char *str; char *endptr; int32_t lower, upper = 0; drange_node_end_t end = DRANGE_NODE_END_T_UNINITIALIZED; drange_node *dn; bool ok; /* * The following syntax governs slices: * [i:j] i = start_offset, j = length * [i-j] i = start_offset, j = end_offset, inclusive. * [i] i = start_offset, length = 1 * [:j] start_offset = 0, length = j * [i:] start_offset = i, end_offset = end_of_field */ str = range_str; if (*str == ':') { lower = 0; /* Do not advance 'str' here. */ } else { if (!drange_str_to_gint32(str, &lower, &endptr, err_ptr)) return NULL; str = endptr; } while (*str != '\0' && g_ascii_isspace(*str)) str++; if (*str == '-') { str++; end = DRANGE_NODE_END_T_OFFSET; ok = drange_str_to_gint32(str, &upper, &endptr, err_ptr); str = endptr; } else if (*str == ':') { str++; if (*str == '\0') { end = DRANGE_NODE_END_T_TO_THE_END; ok = true; } else { end = DRANGE_NODE_END_T_LENGTH; ok = drange_str_to_gint32(str, &upper, &endptr, err_ptr); str = endptr; } } else if (*str == '\0') { end = DRANGE_NODE_END_T_LENGTH; upper = 1; ok = true; } else { ok = false; } while (*str != '\0' && g_ascii_isspace(*str)) str++; if (!ok || *str != '\0') { *err_ptr = ws_strdup_printf("\"%s\" is not a valid range.", range_str); return NULL; } dn = drange_node_new(); drange_node_set_start_offset(dn, lower); switch (end) { case DRANGE_NODE_END_T_LENGTH: if (upper <= 0) { *err_ptr = ws_strdup_printf("Range %s isn't valid " "because length %d isn't positive", range_str, upper); drange_node_free(dn); return NULL; } drange_node_set_length(dn, upper); break; case DRANGE_NODE_END_T_OFFSET: if ((lower < 0 && upper > 0) || (lower > 0 && upper < 0)) { *err_ptr = ws_strdup_printf("Range %s isn't valid " "because %d and %d have different signs", range_str, lower, upper); drange_node_free(dn); return NULL; } if (upper <= lower) { *err_ptr = ws_strdup_printf("Range %s isn't valid " "because %d is greater or equal than %d", range_str, lower, upper); drange_node_free(dn); return NULL; } drange_node_set_end_offset(dn, upper); break; case DRANGE_NODE_END_T_TO_THE_END: drange_node_set_to_the_end(dn); break; default: ws_assert_not_reached(); break; } return dn; } static drange_node* drange_node_dup(drange_node *org) { drange_node *new_range_node; if (!org) return NULL; new_range_node = g_new(drange_node,1); new_range_node->start_offset = org->start_offset; new_range_node->length = org->length; new_range_node->end_offset = org->end_offset; new_range_node->ending = org->ending; return new_range_node; } /* drange_node destructor */ void drange_node_free(drange_node* drnode) { g_free(drnode); } /* drange_node accessors */ int drange_node_get_start_offset(drange_node* drnode) { ws_assert(drnode->ending != DRANGE_NODE_END_T_UNINITIALIZED); return drnode->start_offset; } int drange_node_get_length(drange_node* drnode) { ws_assert(drnode->ending == DRANGE_NODE_END_T_LENGTH); return drnode->length; } int drange_node_get_end_offset(drange_node* drnode) { ws_assert(drnode->ending == DRANGE_NODE_END_T_OFFSET); return drnode->end_offset; } drange_node_end_t drange_node_get_ending(drange_node* drnode) { ws_assert(drnode->ending != DRANGE_NODE_END_T_UNINITIALIZED); return drnode->ending; } /* drange_node mutators */ void drange_node_set_start_offset(drange_node* drnode, int offset) { drnode->start_offset = offset; } void drange_node_set_length(drange_node* drnode, int length) { drnode->length = length; drnode->ending = DRANGE_NODE_END_T_LENGTH; } void drange_node_set_end_offset(drange_node* drnode, int offset) { drnode->end_offset = offset; drnode->ending = DRANGE_NODE_END_T_OFFSET; } void drange_node_set_to_the_end(drange_node* drnode) { drnode->ending = DRANGE_NODE_END_T_TO_THE_END; } /* drange constructor */ drange_t * drange_new(drange_node* drnode) { drange_t * new_drange; new_drange = g_new(drange_t,1); new_drange->range_list = NULL; new_drange->has_total_length = true; new_drange->total_length = 0; new_drange->min_start_offset = INT_MAX; new_drange->max_start_offset = INT_MIN; if (drnode) drange_append_drange_node(new_drange, drnode); return new_drange; } static void drange_append_wrapper(void *data, void *user_data) { drange_node *drnode = (drange_node *)data; drange_t *dr = (drange_t *)user_data; drange_append_drange_node(dr, drnode); } drange_t * drange_new_from_list(GSList *list) { drange_t *new_drange; new_drange = drange_new(NULL); g_slist_foreach(list, drange_append_wrapper, new_drange); return new_drange; } drange_t * drange_dup(drange_t *org) { drange_t *new_drange; GSList *p; if (!org) return NULL; new_drange = drange_new(NULL); for (p = org->range_list; p; p = p->next) { drange_node *drnode = (drange_node *)p->data; drange_append_drange_node(new_drange, drange_node_dup(drnode)); } return new_drange; } /* drange destructor */ void drange_free(drange_t * dr) { drange_node_free_list(dr->range_list); g_free(dr); } /* Call drange_node destructor on all list items */ void drange_node_free_list(GSList* list) { g_slist_free_full(list, g_free); } /* drange accessors */ bool drange_has_total_length(drange_t * dr) { return dr->has_total_length; } int drange_get_total_length(drange_t * dr) { return dr->total_length; } int drange_get_min_start_offset(drange_t * dr) { return dr->min_start_offset; } int drange_get_max_start_offset(drange_t * dr) { return dr->max_start_offset; } static void update_drange_with_node(drange_t *dr, drange_node *drnode) { if(drnode->ending == DRANGE_NODE_END_T_TO_THE_END){ dr->has_total_length = false; } else if(dr->has_total_length){ dr->total_length += drnode->length; } if(drnode->start_offset < dr->min_start_offset){ dr->min_start_offset = drnode->start_offset; } if(drnode->start_offset > dr->max_start_offset){ dr->max_start_offset = drnode->start_offset; } } /* drange mutators */ void drange_prepend_drange_node(drange_t * dr, drange_node* drnode) { if(drnode != NULL){ dr->range_list = g_slist_prepend(dr->range_list,drnode); update_drange_with_node(dr, drnode); } } void drange_append_drange_node(drange_t * dr, drange_node* drnode) { if(drnode != NULL){ dr->range_list = g_slist_append(dr->range_list,drnode); update_drange_with_node(dr, drnode); } } void drange_foreach_drange_node(drange_t * dr, GFunc func, void *funcdata) { g_slist_foreach(dr->range_list,func,funcdata); } char * drange_node_tostr(const drange_node *rn) { if (rn->ending == DRANGE_NODE_END_T_TO_THE_END) return ws_strdup_printf("%d:", rn->start_offset); else if(rn->ending == DRANGE_NODE_END_T_OFFSET) return ws_strdup_printf("%d-%d", rn->start_offset, rn->end_offset); else if (rn->ending == DRANGE_NODE_END_T_LENGTH) return ws_strdup_printf("%d:%d", rn->start_offset, rn->length); else return ws_strdup_printf("%d/%d/%d/U", rn->start_offset, rn->length, rn->end_offset); } char * drange_tostr(const drange_t *dr) { GString *repr = g_string_new(""); GSList *range_list = dr->range_list; char *s; while (range_list) { s = drange_node_tostr(range_list->data); g_string_append(repr, s); g_free(s); range_list = g_slist_next(range_list); if (range_list != NULL) { g_string_append_c(repr, ','); } } return g_string_free(repr, false); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */