Add initial support for string buffers - ep_allocated, growable strings
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 27 Mar 2009 23:05:37 +0000 (23:05 +0000)
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 27 Mar 2009 23:05:37 +0000 (23:05 +0000)
similar to GLib's GStrings. Use them to create the list of TCP flags.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@27872 f5534014-38df-0310-8fa8-9805f1628bb7

doc/README.developer
doc/README.malloc
epan/dissectors/packet-tcp.c
epan/emem.c
epan/emem.h
epan/libwireshark.def

index be0279452ee563ecf14524706c0fbb035dcfd48c..5e0b28d94acbd6cb6f25a02302d6abb17d207588 100644 (file)
@@ -399,8 +399,15 @@ buffer overflows for large strings.
 When using a buffer to create a string, do not use a buffer stored on the stack.
 I.e. do not use a buffer declared as
    char buffer[1024];
-instead allocate a buffer dynamically using the emem routines (see
-README.malloc) such as
+instead allocate a buffer dynamically using the string-specific or plain emem
+routines (see README.malloc) such as
+
+   emem_strbuf_t *strbuf;
+   strbuf = ep_strbuf_new_label("");
+   ep_strbuf_append_printf(strbuf, ...
+
+or
+
    char *buffer=NULL;
    ...
    #define MAX_BUFFER 1024
index 7fbdf3ba5f162aba789a0c3a6f31c328ee8806f7..9224bb15954acd744a0017cf657b7540b745d73f 100644 (file)
@@ -76,4 +76,16 @@ ep_stack_peek() : returns the top element of the stack without popping it.
 
 ep_tvb_memdup(): create an ephemeral duplicate of part of the tvbuff.
 
-
+3.4 String buffers
+
+The ep_strbuf_... functions create and modify growable strings, similar to GLib's
+GStrings.
+
+ep_strbuf_new(s) : Creates a new strbuf, initialized to s.
+ep_strbuf_new_label(s) : Like ep_strbuf_new, but with a max length suitable for
+  protocol tree items.
+ep_strbuf_sized_new() : Creates a new strbuf with explicit sizes.
+ep_strbuf_append_vprintf() : Appends an argument list to a strbuf.
+ep_strbuf_append_printf() : Appends to a strbuf in the style of printf.
+ep_strbuf_append() : Appends a string to a strbuf.
+ep_strbuf_truncate() : Shortens a strbuf.
index e9c9c30a6c223c10e0babf85fa6aed06c22136b7..a4ad27684a329de1580d3bdfcd608f5b7f140bf8 100644 (file)
@@ -2927,9 +2927,8 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   proto_tree *tcp_tree = NULL, *field_tree = NULL;
   proto_item *ti = NULL, *tf, *hidden_item;
   int        offset = 0;
-  gchar      *flags = "<None>";
+  emem_strbuf_t *flags_strbuf = ep_strbuf_new_label("<None>");
   const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR"};
-  gint       fpos = 0, returned_length;
   gint       i;
   guint      bpos;
   guint      optlen;
@@ -3130,22 +3129,21 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     tcph->th_have_seglen = FALSE;
 
   if (check_col(pinfo->cinfo, COL_INFO) || tree) {
-#define MAX_FLAGS_LEN 64
-    flags=ep_alloc(MAX_FLAGS_LEN);
-    flags[0]=0;
+    gboolean first_flag = TRUE;
     for (i = 0; i < 8; i++) {
       bpos = 1 << i;
       if (tcph->th_flags & bpos) {
-        returned_length = g_snprintf(&flags[fpos], MAX_FLAGS_LEN-fpos, "%s%s",
-               fpos?", ":"",
-               fstr[i]);
-       fpos += MIN(returned_length, MAX_FLAGS_LEN-fpos);
+        if (first_flag) {
+          ep_strbuf_truncate(flags_strbuf, 0);
+        }
+        ep_strbuf_append_printf(flags_strbuf, "%s%s", first_flag ? "" : ", ", fstr[i]);
+        first_flag = FALSE;
       }
     }
   }
 
   if (check_col(pinfo->cinfo, COL_INFO)) {
-    col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] Seq=%u", flags, tcph->th_seq);
+    col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] Seq=%u", flags_strbuf->str, tcph->th_seq);
     if (tcph->th_flags&TH_ACK) {
       col_append_fstr(pinfo->cinfo, COL_INFO, " Ack=%u", tcph->th_ack);
     }
@@ -3217,7 +3215,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     proto_tree_add_uint_format(tcp_tree, hf_tcp_hdr_len, tvb, offset + 12, 1, tcph->th_hlen,
        "Header length: %u bytes", tcph->th_hlen);
     tf = proto_tree_add_uint_format(tcp_tree, hf_tcp_flags, tvb, offset + 13, 1,
-       tcph->th_flags, "Flags: 0x%02x (%s)", tcph->th_flags, flags);
+       tcph->th_flags, "Flags: 0x%02x (%s)", tcph->th_flags, flags_strbuf->str);
     field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
     proto_tree_add_boolean(field_tree, hf_tcp_flags_cwr, tvb, offset + 13, 1, tcph->th_flags);
     proto_tree_add_boolean(field_tree, hf_tcp_flags_ecn, tvb, offset + 13, 1, tcph->th_flags);
index be64881b04a578a1d31cb750408ffbb165811c7b..38ab1005a6abbdf9bc24ea015da1ee1119d78069 100644 (file)
@@ -1652,3 +1652,156 @@ emem_print_tree(emem_tree_t* emem_tree)
        if(emem_tree->tree)
                emem_tree_print_nodes(emem_tree->tree, 0);
 }
+
+/*
+ * String buffers
+ */
+
+/*
+ * Presumably we're using these routines for building strings for the tree.
+ * Use ITEM_LABEL_LENGTH as the basis for our default lengths.
+ */
+
+#define DEFAULT_STRBUF_LEN (ITEM_LABEL_LENGTH / 10)
+#define MAX_STRBUF_LEN 65536
+
+static gsize
+next_size(gsize cur_len, gsize wanted_len, gsize max_len) {
+       if (max_len < 1 || max_len > MAX_STRBUF_LEN) {
+               max_len = MAX_STRBUF_LEN;
+       }
+       
+       if (cur_len < 1) {
+               cur_len = DEFAULT_STRBUF_LEN;
+       }
+       
+       while (cur_len < wanted_len) { 
+               cur_len *= 2;
+       }
+       
+       return cur_len < max_len ? cur_len : max_len;
+}
+
+static void
+ep_strbuf_grow(emem_strbuf_t *strbuf, gsize wanted_len) {
+       gsize new_alloc_len;
+       gchar *new_str;
+        
+       if (!strbuf || strbuf->alloc_len >= strbuf->max_len) {
+               return;
+       }
+       
+       new_alloc_len = next_size(strbuf->len, wanted_len, strbuf->max_len);
+        new_str = ep_alloc(new_alloc_len);
+        g_strlcpy(new_str, strbuf->str, new_alloc_len);
+        
+        strbuf->alloc_len = new_alloc_len;
+        strbuf->str = new_str;
+}
+
+emem_strbuf_t *
+ep_strbuf_sized_new(gsize len, gsize max_len) {
+       emem_strbuf_t *strbuf;
+       
+       strbuf = ep_alloc(sizeof(emem_strbuf_t));
+       
+       if (len > 0) {
+               strbuf->str = ep_alloc(len);
+               strbuf->str[0] = '\0';
+       } else {
+               strbuf->str = ep_strdup("");
+       }
+       
+       strbuf->len = len;
+       strbuf->alloc_len = len;
+       strbuf->max_len = max_len;
+       return strbuf;
+}
+
+emem_strbuf_t *
+ep_strbuf_new(const gchar *init) {
+       emem_strbuf_t *strbuf;
+       
+       strbuf = ep_strbuf_sized_new(next_size(0, strlen(init), 0), 0);
+
+       g_strlcpy(strbuf->str, init, strbuf->alloc_len);        
+       return strbuf;
+}
+
+emem_strbuf_t *
+ep_strbuf_new_label(const gchar *init) {
+       emem_strbuf_t *strbuf;
+       gsize init_size;
+       
+       if (!init) {
+               init = "";
+       }
+       
+       init_size = strlen(init);
+       strbuf = ep_strbuf_sized_new(init_size > DEFAULT_STRBUF_LEN ? init_size : DEFAULT_STRBUF_LEN,
+                                    ITEM_LABEL_LENGTH);
+
+       g_strlcpy(strbuf->str, init, strbuf->alloc_len);
+       strbuf->len = MIN(init_size, strbuf->alloc_len);
+       return strbuf;
+}
+
+void
+ep_strbuf_append(emem_strbuf_t *strbuf, const gchar *str) {
+       gsize add_len;
+       
+       if (!strbuf || !str) {
+               return;
+       }
+               
+       add_len = strlen(str);
+       
+       if (strbuf->len + add_len > strbuf->alloc_len) {
+               ep_strbuf_grow(strbuf, strbuf->len + add_len);
+       }
+       
+       g_strlcpy(&strbuf->str[strbuf->len], str, strbuf->alloc_len - add_len);
+       strbuf->len += add_len;
+}
+
+void
+ep_strbuf_append_vprintf(emem_strbuf_t *strbuf, const gchar *format, va_list ap) {
+       va_list ap2;
+       gsize add_len, full_len;
+
+       G_VA_COPY(ap2, ap);
+
+       add_len = g_printf_string_upper_bound(format, ap);
+
+       if (strbuf->len + add_len > strbuf->alloc_len) {
+               ep_strbuf_grow(strbuf, strbuf->len + add_len);
+       }
+
+       if (strbuf->len + add_len > strbuf->alloc_len) {
+               add_len = strbuf->alloc_len - strbuf->len;
+       }
+
+       full_len = g_vsnprintf(&strbuf->str[strbuf->len], add_len, format, ap2);
+       strbuf->len += MIN(add_len, full_len);
+       va_end(ap2);
+
+}
+
+void
+ep_strbuf_append_printf(emem_strbuf_t *strbuf, const gchar *format, ...) {
+       va_list ap;
+       
+       va_start(ap, format);
+       ep_strbuf_append_vprintf(strbuf, format, ap);
+       va_end(ap);
+}
+
+void
+ep_strbuf_truncate(emem_strbuf_t *strbuf, gsize len) {
+       if (!strbuf || len >= strbuf->len) {
+               return;
+       }
+
+       strbuf->str[len] = '\0';        
+       strbuf->len = len;
+}
index 99bbe384b838d94bb7c2ef649290bc4e91ddc1f4..c75ca71693cd170de309356ee9e7f2360df0ceb5 100644 (file)
@@ -364,6 +364,88 @@ typedef gboolean (*tree_foreach_func)(void *value, void *userdata);
 gboolean emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data);
 
 
+/* ******************************************************************
+ * String buffers - Growable strings similar to GStrings
+ * ****************************************************************** */
+
+typedef struct _emem_strbuf_t {
+    gchar *str;
+    gsize len;
+    gsize alloc_len;
+    gsize max_len;
+} emem_strbuf_t;
+
+/*
+ * The maximum length is limited to 64K. If you need something bigger, you
+ * should probably use an actual GString or GByteArray.
+ */
+
+/**
+ * Allocate an ephemeral string buffer with "unlimited" size.
+ *
+ * @param init The initial string for the buffer, or NULL.
+ *
+ * @return A newly-allocated string buffer.
+ */
+emem_strbuf_t *ep_strbuf_new(const gchar *init);
+
+/**
+ * Allocate an ephemeral string buffer suitable for the protocol tree.
+ * The string will never grow beyond the maximum tree item length.
+ *
+ * @param init The initial string for the buffer, or NULL.
+ *
+ * @return A newly-allocated string buffer.
+ */
+emem_strbuf_t *ep_strbuf_new_label(const gchar *init);
+
+/**
+ * Allocate an ephemeral string buffer with enough initial space for @len bytes
+ * and a maximum of @max_len bytes.
+ *
+ * @param len The initial size of the buffer. This value can be 0, but a nonzero
+ * value is recommended.
+ * @param max_len The maximum size of the buffer. 0 means "unlimited" (within
+ * reason).
+ *
+ * @return A newly-allocated string buffer. @str will be empty.
+ */
+emem_strbuf_t *ep_strbuf_sized_new(gsize len, gsize max_len);
+
+/**
+ * Append vprintf-style formatted text to a string buffer.
+ *
+ * @param strbuf The ep_strbuf-allocated string buffer to append to.
+ * @param format A printf-style string format.
+ * @param args The list of arguments to append.
+ */
+void ep_strbuf_append_vprintf(emem_strbuf_t *strbuf, const gchar *format, va_list ap);
+
+/**
+ * Append printf-style formatted text to a string buffer.
+ *
+ * @param strbuf The ep_strbuf-allocated string buffer to append to.
+ * @param format A printf-style string format.
+ */
+void ep_strbuf_append_printf(emem_strbuf_t *strbuf, const gchar *format, ...)
+    GNUC_FORMAT_CHECK(printf, 2, 3);
+
+/**
+ * Append a string to a string buffer.
+ *
+ * @param strbuf The ep_strbuf-allocated string buffer to append to.
+ * @param str A null-terminated string.
+ */
+void ep_strbuf_append(emem_strbuf_t *strbuf, const gchar *str);
+
+/**
+ * Chop off the end of a string buffer.
+ *
+ * @param strbuf The ep_strbuf-allocated string buffer to append to.
+ * @param len The new string length.
+ */
+void ep_strbuf_truncate(emem_strbuf_t *strbuf, gsize len);
+
 
 /* #define DEBUG_INTENSE_CANARY_CHECKS */
 /* Helper to troubleshoot ep memory corruption
index f84d14d7e0168991fe8688df61b771a0907f6c81..9bbd25b1ef1119c64f800bcfa82f77e8df31415b 100644 (file)
@@ -333,6 +333,13 @@ ep_memdup
 ep_stack_new
 ep_stack_pop
 ep_stack_push
+ep_strbuf_append
+ep_strbuf_append_printf
+ep_strbuf_append_vprintf
+ep_strbuf_new
+ep_strbuf_new_label
+ep_strbuf_sized_new
+ep_strbuf_truncate
 ep_strdup
 ep_strdup_printf
 ep_strdup_vprintf