Index: gtk/gui_utils.c
===================================================================
--- gtk/gui_utils.c	(revision 20392)
+++ gtk/gui_utils.c	(working copy)
@@ -1062,6 +1062,82 @@
 #endif
 }
 
+
+typedef struct _copy_binary_t {
+    guint8* data;
+    int len;
+} copy_binary_t;
+
+static
+copy_binary_t* create_copy_binary_t(const guint8* data, int len)
+{
+    copy_binary_t* copy_data;
+
+    g_assert(len > 0);
+    copy_data = g_new(copy_binary_t,1);
+    copy_data->data = g_new(guint8,len);
+    copy_data->len = len;
+    memcpy(copy_data->data,data,len * sizeof(guint8));
+    return copy_data;
+}
+
+static void destroy_copy_binary_t(copy_binary_t* copy_data) {
+    g_free(copy_data->data);
+    g_free(copy_data);
+}
+
+#if (GTK_MAJOR_VERSION >= 2)
+
+static
+void copy_binary_free_cb(GtkClipboard *clipboard, gpointer user_data_or_owner)
+{
+    copy_binary_t* copy_data;
+    copy_data = user_data_or_owner;
+    destroy_copy_binary_t(copy_data);
+}
+
+static
+void copy_binary_get_cb(GtkClipboard *clipboard,GtkSelectionData *selection_data,guint info,gpointer user_data_or_owner)
+{
+    copy_binary_t* copy_data;
+
+    copy_data = user_data_or_owner;
+
+    /* Just do a dumb set as binary data */
+    gtk_selection_data_set(selection_data, GDK_NONE, 8, copy_data->data, copy_data->len);
+}
+
+void copy_binary_to_clipboard(const guint8* data_p, int len)
+{
+    static GtkTargetEntry target_entry[] = {
+         {"application/octet_stream", 0, 0}}; /* XXX - this not understood by most applications, 
+                                             * but can be pasted into the better hex editors - is
+                                             * there something better that we can do?
+                                             */
+
+    GtkClipboard    *cb;
+    copy_binary_t* copy_data;
+    gboolean ret;
+
+    if(len <= 0) {
+        return; /* XXX would it be better to clear the clipboard? */
+    }
+    cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);     /* Get the default clipboard */
+    copy_data = create_copy_binary_t(data_p,len);
+
+    ret = gtk_clipboard_set_with_data(cb,target_entry,1,
+        copy_binary_get_cb, copy_binary_free_cb,copy_data);
+
+    if(!ret) {
+        destroy_copy_binary_t(copy_data);
+    }                
+}
+#else
+void copy_binary_to_clipboard(const guint8* data_p, int len)
+{
+    /* XXX Bring up a warning dialog or else do an implementation */
+}
+#endif
 /*
  * Create a new window title string with user-defined title preference.
  * (Or ignore it if unspecified).
Index: gtk/gui_utils.h
===================================================================
--- gtk/gui_utils.h	(revision 20392)
+++ gtk/gui_utils.h	(working copy)
@@ -297,6 +297,15 @@
  */
 extern void copy_to_clipboard(GString *str);
 
+/** Copy an array of bytes to the clipboard.
+ * Copies as mime-type application/octet_stream in GTK 2.
+ * Does not do anything for GTK 1.
+ *
+ * @param data_p Pointer to data to be copied.
+ * @param len Number of bytes in the data to be copied.
+ */
+extern void copy_binary_to_clipboard(const guint8* data_p, int len);
+
 /** Create a new window title that includes user-defined preference string.
  *
  * @param caption string you want included in title (appended to user-defined string)
Index: gtk/menu.c
===================================================================
--- gtk/menu.c	(revision 20392)
+++ gtk/menu.c	(working copy)
@@ -706,6 +706,20 @@
 
     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
 
+    ITEM_FACTORY_ENTRY("/Copy", NULL, NULL, 0, "<Branch>", NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Summary (Text)", NULL, packet_list_copy_summary_cb, CS_TEXT, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Summary (CSV)", NULL, packet_list_copy_summary_cb, CS_CSV, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Hex and Text", NULL, copy_hex_cb, CD_ALLINFO, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Text Only", NULL, copy_hex_cb, CD_TEXTONLY, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Hex Columns", NULL, copy_hex_cb, CD_HEXCOLUMNS, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Hex Stream", NULL, copy_hex_cb, CD_HEX, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/Base64 Stream", NULL, copy_hex_cb, CD_BASE64, NULL, NULL),
+#if GTK_MAJOR_VERSION >= 2
+    ITEM_FACTORY_ENTRY("/Copy/Binary Stream", NULL, copy_hex_cb, CD_BINARY, NULL, NULL),
+#endif
+
+    ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
+
     ITEM_FACTORY_STOCK_ENTRY("/Decode As...", NULL, decode_as_cb, 0, WIRESHARK_STOCK_DECODE_AS),
     ITEM_FACTORY_STOCK_ENTRY("/Print...", NULL, file_print_selected_cmd_cb, 0, GTK_STOCK_PRINT),
     ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
@@ -722,6 +736,15 @@
     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
 
     ITEM_FACTORY_ENTRY("/Copy", NULL, copy_selected_plist_cb, 0, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As", NULL, NULL, 0, "<Branch>", NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Hex and Text", NULL, copy_hex_cb, CD_ALLINFO | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Text Only", NULL, copy_hex_cb, CD_TEXTONLY | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Hex Columns", NULL, copy_hex_cb, CD_HEXCOLUMNS | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Hex Stream", NULL, copy_hex_cb, CD_HEX | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Base64 Stream", NULL, copy_hex_cb, CD_BASE64 | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+#if GTK_MAJOR_VERSION >= 2
+    ITEM_FACTORY_ENTRY("/Copy Selected Bytes As/Binary Stream", NULL, copy_hex_cb, CD_BINARY | CD_FLAGS_SELECTEDONLY, NULL, NULL),
+#endif
     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
 
     ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
@@ -775,9 +798,9 @@
 {
     ITEM_FACTORY_ENTRY("/Copy", NULL, NULL, 0, "<Branch>", NULL),
     ITEM_FACTORY_ENTRY("/Copy/All Information", NULL, copy_hex_cb,
-                       0, NULL, NULL),
+                       CD_ALLINFO, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Text Only", NULL, copy_hex_cb,
-                       1, NULL, NULL),
+                       CD_TEXTONLY, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
                        0, NULL, NULL),
 };
Index: gtk/packet_list.c
===================================================================
--- gtk/packet_list.c	(revision 20392)
+++ gtk/packet_list.c	(working copy)
@@ -91,6 +91,7 @@
 #define eth_clist_set_selection_mode		gtk_clist_set_selection_mode
 #define eth_clist_set_sort_column		gtk_clist_set_sort_column
 #define eth_clist_set_text			gtk_clist_set_text
+#define eth_clist_get_text			gtk_clist_get_text
 #define eth_clist_sort				gtk_clist_sort
 #define eth_clist_thaw				gtk_clist_thaw
 #define ETH_CLIST				GTK_CLIST
@@ -893,3 +894,29 @@
 {
     return ETH_CLIST(packet_list)->sort_column;
 }
+
+void packet_list_copy_summary_cb(GtkWidget * w _U_, gpointer data _U_, copy_summary_type copy_type)
+{
+    gint row;
+    gint col;
+    gchar separator;
+    gchar* celltext = NULL;
+
+    GString* text = g_string_new("");
+    separator = (CS_CSV == copy_type) ? ',' : '\t';
+    if (cfile.current_frame) {
+        /* XXX hum, should better have a "cfile->current_row" here ... */
+        row = eth_clist_find_row_from_data(ETH_CLIST(packet_list),
+			        cfile.current_frame);
+        for(col = 0; col < cfile.cinfo.num_cols; ++col) {
+            if(col != 0) {
+                g_string_append_c(text,separator);
+            }
+            if(0 != eth_clist_get_text(ETH_CLIST(packet_list),row,col,&celltext)) {
+                g_string_append(text,celltext);
+            }
+        }
+        copy_to_clipboard(text);
+    }
+    g_string_free(text,TRUE);
+}
Index: gtk/packet_list.h
===================================================================
--- gtk/packet_list.h	(revision 20392)
+++ gtk/packet_list.h	(working copy)
@@ -106,5 +106,17 @@
  */
 extern void packet_list_prev();
 
+/* Different modes of copying summary data */
+typedef enum {
+    CS_TEXT, /* Packet summary data (tab separated) */
+    CS_CSV   /* Packet summary data (comma separated) */
+} copy_summary_type;
 
+/** Called when user clicks on menu item to copy summary data.
+ *
+ *  @param w Not used.
+ *  @param data Not used.
+ *  @param copy_type Mode in which to copy data (e.g. tab-separated, CSV)
+ */
+extern void packet_list_copy_summary_cb(GtkWidget * w _U_, gpointer data _U_, copy_summary_type copy_type);
 #endif /* __PACKET_LIST_H__ */
Index: gtk/proto_draw.c
===================================================================
--- gtk/proto_draw.c	(revision 20392)
+++ gtk/proto_draw.c	(working copy)
@@ -819,17 +819,143 @@
         savehex_dlg = NULL;
 }
 
+
+static void copy_hex_all_info(GString* copy_buffer, const guint8* data_p, int data_len, gboolean append_text)
+{
+    const int byte_line_length = 16; /* Print out data for 16 bytes on one line */
+    int i, j;
+    gboolean end_of_line = TRUE; /* Initial state is end of line */
+    int byte_line_part_length;
+
+    GString* hex_str;
+    GString* char_str;
+
+    /* Write hex data for a line, then ascii data, then concatenate and add to buffer */
+    hex_str = g_string_new("");
+    char_str= g_string_new("");
+
+    i = 0;
+	while (i<data_len){
+        if(end_of_line) {
+            g_string_append_printf(hex_str,"%04x  ",i); /* Offset - note that we _append_ here */
+        }
+
+        g_string_append_printf(hex_str," %02x",*data_p);
+        if(append_text) {
+            g_string_append_printf(char_str,"%c",isprint(*data_p) ? *data_p : '.');
+        }
+
+        ++data_p;
+
+        /* Look ahead to see if this is the end of the data */
+        byte_line_part_length = (++i) % byte_line_length;
+        if(i == data_len){
+            /* End of data - need to fill in spaces in hex string and then do "end of line".
+             * 
+             */
+            for(j = 0; append_text && (j < (byte_line_length - byte_line_part_length)); ++j) {
+                g_string_append(hex_str,"   "); /* Three spaces for each missing byte */
+            }
+            end_of_line = TRUE;
+        } else {
+            end_of_line = (byte_line_part_length == 0 ? TRUE : FALSE);
+        }
+        
+
+        if (end_of_line){
+            /* End of line */
+            g_string_append_len(copy_buffer, hex_str->str, hex_str->len);
+            if(append_text) {
+                /* Two spaces between hex and text */
+                g_string_append_c(copy_buffer, ' ');
+                g_string_append_c(copy_buffer, ' ');
+                g_string_append_len(copy_buffer, char_str->str, char_str->len);
+            }
+            /* Setup ready for next line */
+            g_string_assign(char_str,"");
+            g_string_assign(hex_str, "\n");
+        }
+	}
+
+	g_string_free(hex_str, TRUE);
+	g_string_free(char_str, TRUE);
+}
+
+static 
+int copy_hex_bytes_text_only(GString* copy_buffer, const guint8* data_p, int data_len)
+{
+
+    gchar to_append;
+
+    if(g_ascii_isprint(*data_p)) {
+        to_append = *data_p;
+    } else if(*data_p==0x0a) {
+        to_append = '\n'; /* Copied from old copy_hex_cb function; not sure why this is needed - portablity?*/
+    } else {
+        return 1; /* Just ignore non-printable bytes */
+    }
+    g_string_append_c(copy_buffer,to_append);
+    return 1;
+}
+
+static 
+int copy_hex_bytes_hex(GString* copy_buffer, const guint8* data_p, int data_len)
+{
+    g_string_append_printf(copy_buffer, "%02x", *data_p);
+    return 1;
+}
+
+static 
+int copy_hex_bytes_base64(GString* copy_buffer, const guint8* data_p, int data_len)
+{
+    gsize written;
+    int state = 0;
+    int save = 0;
+    int len;
+    int i;
+
+    gchar destination[10]; /* Guaranteed to be enough for Base64 encoding 3 bytes */
+    guchar source[3];   /* Cope with platforms where guchar is not guint8 */
+
+
+    if(data_len < 3) {
+        len = data_len;    
+    }
+    else {
+        len = 3;
+    }
+
+    for(i=0; i < len; ++i) {
+        source[i]=data_p[i];
+    }
+    written = g_base64_encode_step(source,len,FALSE,destination,&state,&save);
+    g_string_append_len(copy_buffer,destination,written);
+
+
+    if(data_len <= 3) {
+        written = g_base64_encode_close(FALSE,destination,&state,&save);
+        g_string_append_len(copy_buffer,destination,written);    
+    }
+
+    return len;
+}
+
+
+
 void
-copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, int data_type)
+copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, copy_data_type data_type)
 {
 	GtkWidget *bv;
-	int len;
-	int i=0;
-	const guint8 *data_p = NULL;
-	GString *ASCII_representation = g_string_new("");
-	GString *byte_str = g_string_new("");
-	GString *text_str = g_string_new("");
 
+    int len;
+    int i = 0;
+    int bytes_consumed;
+    int flags;
+
+    const guint8* data_p;
+
+	GString* copy_buffer = g_string_new(""); /* String to copy to clipboard */
+
 	bv = get_notebook_bv_ptr(byte_nb_ptr);
 	if (bv == NULL) {
 		/* shouldn't happen */
@@ -840,50 +966,69 @@
 	data_p = get_byte_view_data_and_length(bv, &len);
 	g_assert(data_p != NULL);
 
-    g_string_sprintfa(byte_str,"%04x  ",i); /* Offset 0000 */
-	for (i=0; i<len; i++){
-        if (data_type==1) {
-            if (isprint(*data_p)) {
-                g_string_sprintfa(ASCII_representation,"%c", *data_p);
-            }
-            else
-            {
-                if (*data_p==0x0a) {
-                    g_string_sprintfa(ASCII_representation,"\n");
-                }
-            }
+    flags = data_type & CD_FLAGSMASK;
+    data_type = data_type & CD_TYPEMASK;
+
+    if(flags & CD_FLAGS_SELECTEDONLY) {
+        int start, end;
+        
+        /* Get the start and end of the highlighted bytes.
+         * XXX The keys appear to be REVERSED start <-> end throughout this file!
+         * Should this be fixed? There is one exception - packet_hex_reprint,
+         * so can't just change it round without functional change.
+         */
+	    end = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_START_KEY));
+	    start = GPOINTER_TO_INT(OBJECT_GET_DATA(bv, E_BYTE_VIEW_END_KEY));
+
+        if(start >= 0 && end > start && (end - start <= len)) {
+            len = end - start;
+            data_p += start;
         }
-        else
-        {
-            g_string_sprintfa(ASCII_representation,"%c",isprint(*data_p) ? *data_p : '.');
-        }
-        g_string_sprintfa(byte_str," %02x",*data_p++);
-        if ((i+1)%16==0 && i!=0){
-            g_string_sprintfa(byte_str,"  %s\n%04x  ",ASCII_representation->str,i+1);
-            g_string_sprintfa(text_str,"%s",ASCII_representation->str);
+    }
 
-            g_string_assign (ASCII_representation,"");
+    switch(data_type) {
+    case(CD_ALLINFO):
+        /* This is too different from other text formats - handle separately */
+        copy_hex_all_info(copy_buffer, data_p, len, TRUE);
+        break;
+    case(CD_HEXCOLUMNS):
+        /* This could be done incrementally, but it is easier to mingle with the code for CD_ALLINFO */
+        copy_hex_all_info(copy_buffer, data_p, len, FALSE);
+        break;
+    case(CD_BINARY):
+        /* Completely different logic to text copies - leave copy buffer alone */
+        copy_binary_to_clipboard(data_p,len);
+        break;
+    default:
+        /* Incrementally write to text buffer in various formats */
+	    while (len > 0){
+            switch(data_type) {
+            case (CD_TEXTONLY):
+                bytes_consumed = copy_hex_bytes_text_only(copy_buffer, data_p, len);
+                break;
+            case (CD_HEX):
+                bytes_consumed = copy_hex_bytes_hex(copy_buffer, data_p, len);
+                break;
+            case (CD_BASE64):
+                bytes_consumed = copy_hex_bytes_base64(copy_buffer, data_p, len);
+                break;
+            default:
+                g_assert_not_reached();
+                break;
+            }
+
+            g_assert(bytes_consumed>0);
+            data_p += bytes_consumed;
+            len -= bytes_consumed;
         }
-	}
-
-	if(ASCII_representation->len){
-	  for (i=ASCII_representation->len; i<16; i++){
-	    g_string_sprintfa(byte_str,"   ");
-	  }
-	  g_string_sprintfa(byte_str,"  %s\n",ASCII_representation->str);
-	  g_string_sprintfa(text_str,"%s",ASCII_representation->str);
-	}
-	/* Now that we have the byte data, copy it into the default clipboard */
-    if (data_type==1) {
-        copy_to_clipboard(text_str);
+        break;
     }
-    else
-    {
-        copy_to_clipboard(byte_str);
+    
+    if(copy_buffer->len > 0) {
+        copy_to_clipboard(copy_buffer);
     }
-	g_string_free(byte_str, TRUE);                       /* Free the memory */
-	g_string_free(text_str, TRUE);                       /* Free the memory */
-	g_string_free(ASCII_representation, TRUE);           /* Free the memory */
+
+	g_string_free(copy_buffer, TRUE);  
 }
 
 /* save the current highlighted hex data */
Index: gtk/proto_draw.h
===================================================================
--- gtk/proto_draw.h	(revision 20392)
+++ gtk/proto_draw.h	(working copy)
@@ -127,12 +127,30 @@
  */
 extern void savehex_cb(GtkWidget * w, gpointer data);
 
+/** Format of packet data to copy to clipboard.
+ *  Lower nibble holds data type, next nibble holds flags.
+ */
+typedef enum {
+    CD_ALLINFO,     /* All information - columated hex with text in separate column */
+    CD_TEXTONLY,    /* Printable characters */
+    CD_HEX,         /* Hex, space separated, no linebreaks */
+    CD_HEXCOLUMNS,  /* Like "All Information" but with no ASCII */
+    CD_BASE64,      /* Base 64 encoded binary */
+    CD_BINARY,      /* Raw binary octets */
+
+    CD_TYPEMASK = 0x0000FFFF,          /* Mask for extracting type */
+    CD_FLAGSMASK = 0xFFFF0000,         /* Mask for extracting flags */
+
+    CD_FLAGS_SELECTEDONLY = 0x00010000 /* Copy only selected bytes */
+} copy_data_type;
+
+
 /** Callback for "Copy packet bytes to clipboard" operation.
  *
  * @param w unused
  * @param data unused
  */
-extern void copy_hex_cb(GtkWidget * w, gpointer data, int data_type);
+extern void copy_hex_cb(GtkWidget * w, gpointer data, copy_data_type data_type);
 
 /** Redraw a given byte view window.
  *
@@ -228,4 +246,5 @@
 extern GdkColor	expert_color_warn;
 extern GdkColor	expert_color_error;
 
+
 #endif
