Implement proto_tree_write_fields without using ep_strbufs.

- Fixes https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8348:
   "tshark -T fields can't print the full value of fields where the value,
    as a text string, is longer than 65535 bytes"
- Reduces ep memory allocation & string copies;


svn path=/trunk/; revision=47724
This commit is contained in:
Bill Meier 2013-02-18 00:51:59 +00:00
parent 4e27a8a034
commit e7ff4a79c0
1 changed files with 65 additions and 19 deletions

84
print.c
View File

@ -82,7 +82,7 @@ struct _output_fields {
gchar aggregator;
GPtrArray* fields;
GHashTable* field_indicies;
emem_strbuf_t** field_values;
GPtrArray** field_values;
gchar quote;
gboolean includes_col_fields;
};
@ -780,6 +780,12 @@ write_carrays_finale(FILE *fh _U_)
* Find the data source for a specified field, and return a pointer
* to the data in it. Returns NULL if the data is out of bounds.
*/
/* XXX: What am I missing ?
* Why bother searching for fi->ds_tvb for the matching tvb
* in the data_source list ?
* IOW: Why not just use fi->ds_tvb for the arg to tvb_get_ptr() ?
*/
static const guint8 *
get_field_data(GSList *src_list, field_info *fi)
{
@ -1354,6 +1360,14 @@ void output_fields_free(output_fields_t* fields)
*/
g_hash_table_destroy(fields->field_indicies);
}
if(NULL != fields->field_values) {
gsize i;
for(i = 0; i < fields->fields->len; ++i) {
GPtrArray* fv_p;
fv_p = fields->field_values[i];
g_ptr_array_free(fv_p, TRUE);
}
}
if(NULL != fields->fields) {
gsize i;
for(i = 0; i < fields->fields->len; ++i) {
@ -1537,21 +1551,47 @@ void write_fields_preamble(output_fields_t* fields, FILE *fh)
static void format_field_values(output_fields_t* fields, gpointer field_index, const gchar* value)
{
if(NULL != value && '\0' != *value) {
guint actual_index;
actual_index = GPOINTER_TO_UINT(field_index);
/* Unwrap change made to disambiguiate zero / null */
if (fields->field_values[actual_index - 1] == NULL ) {
fields->field_values[actual_index - 1] = ep_strbuf_new(value);
} else if (fields->occurrence == 'l' ) {
/* print only the value of the last occurrence of the field */
ep_strbuf_printf(fields->field_values[actual_index - 1],"%s",value);
} else if (fields->occurrence == 'a' ) {
/* print the value of all accurrences of the field */
ep_strbuf_append_printf(fields->field_values[actual_index - 1],
"%c%s",fields->aggregator,value);
}
guint index;
GPtrArray* fv_p;
if (NULL == value || '\0' == *value)
return;
/* Unwrap change made to disambiguiate zero / null */
index = GPOINTER_TO_UINT(field_index) - 1;
if (fields->field_values[index] == NULL) {
fields->field_values[index] = g_ptr_array_new();
}
/* Essentially: fieldvalues[index] is an array of (ghar *) with each entry */
/* pointing to a string which is (part of) the final output string. */
fv_p = fields->field_values[index];
switch (fields->occurrence) {
case 'f':
/* print the value of only the first occurrence of the field */
if (g_ptr_array_len(fv_p) != 0)
return;
break;
case 'l':
/* print the value of only the last occurrence of the field */
g_ptr_array_set_size(fv_p, 0);
break;
case 'a':
/* print the value of all accurrences of the field */
/* If not the first, add the 'aggregator' */
if (g_ptr_array_len(fv_p) > 0) {
g_ptr_array_add(fv_p, (gpointer)ep_strdup_printf("%c",fields->aggregator));
}
break;
default:
g_assert_not_reached();
break;
}
g_ptr_array_add(fv_p, (gpointer)value);
}
static void proto_tree_get_node_field_values(proto_node *node, gpointer data)
@ -1569,7 +1609,7 @@ static void proto_tree_get_node_field_values(proto_node *node, gpointer data)
field_index = g_hash_table_lookup(call_data->fields->field_indicies, fi->hfinfo->abbrev);
if(NULL != field_index) {
format_field_values(call_data->fields, field_index,
get_node_field_value(fi, call_data->edt) /* ep_alloced string */
get_node_field_value(fi, call_data->edt) /* static or ep_alloc'd string */
);
}
@ -1611,8 +1651,8 @@ void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, colum
}
}
/* Buffer to store values for this packet */
fields->field_values = ep_alloc_array0(emem_strbuf_t*, fields->fields->len);
/* Array buffer to store values for this packet */
fields->field_values = ep_alloc_array0(GPtrArray*, fields->fields->len);
proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values,
&data);
@ -1634,10 +1674,16 @@ void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, colum
fputc(fields->separator, fh);
}
if(NULL != fields->field_values[i]) {
GPtrArray *fv_p;
gsize j;
fv_p = fields->field_values[i];
if(fields->quote != '\0') {
fputc(fields->quote, fh);
}
fputs(fields->field_values[i]->str, fh);
for (j = 0; j < g_ptr_array_len(fv_p); j++ ) {
fputs((gchar *)g_ptr_array_index(fv_p, j), fh);
}
if(fields->quote != '\0') {
fputc(fields->quote, fh);
}