#50209 - need a G_TYPE_ for nun-nul terminated strings



Text of bug

===
Some signals have string arguments that are not nul-terminated;
instead, a length is passed in. This breaks because G_TYPE_STRING
assumes nul termination and copies the string with g_strdup().
As with boxed types, we need to be able to pass a string to a signal
without copying it; e.g. insert_text can take extremely long strings,
which would be quite a performance hit to copy.
===

Currently, GtkEntry, GtkOldeditable just copy the text and nul-terminate.
GtkText uses G_TYPE_STRING for a potentially non-nul terminated
string.

I took a stab at an implementation of a G_TYPE_BYTES to fix
this; I'm not completely happy with the result, for two
reasons:

 - It doesn't seem really seem that general purpose.
 
 - It reintroduces arguments collected as multiple arguments,
   which it was sort of nice to avoid. (The glib-genmarshal.c
   changes are, in particularly fairly hacky for this reason)

Its possible that simply eating the copying hit is OK, though
Havoc points out, the text here could be an entire document.

My patch follows. The extra API, along with G_TYPE_BYTES, is:

===
void                  g_value_set_bytes        (GValue                *value,
						const gchar           *v_string,
						guint                  v_length);
void                  g_value_set_static_bytes (GValue                *value,
						const gchar           *v_string,
						guint                  v_length);
G_CONST_RETURN gchar *g_value_get_bytes_str    (GValue                *value);
guint                 g_value_get_bytes_len    (GValue                *value);
void                  g_value_dup_bytes        (GValue                *value,
						gchar                **v_string,
						guint                 *v_length);
===

Most likely g_value_dup_bytes should be replaced with
g_value_dup_bytes_str() to match g_value_get_bytes_str(). Probably
str/len should be spelled out.  Possible guint here should be gint and
it should support -1 == nul-terminated.

Regards,
                                        Owen


Index: glib-genmarshal.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/glib-genmarshal.c,v
retrieving revision 1.7
diff -u -r1.7 glib-genmarshal.c
--- glib-genmarshal.c	2001/03/09 14:02:30	1.7
+++ glib-genmarshal.c	2001/03/28 00:33:16
@@ -128,7 +128,9 @@
 static gboolean		 skip_ploc = FALSE;
 static gboolean		 std_includes = TRUE;
 
+static const gchar bytes_ctype[] = "gpointer,gint";
 
+
 /* --- functions --- */
 static gboolean
 complete_in_arg (InArgument *iarg)
@@ -148,6 +150,7 @@
     { "FLOAT",		"FLOAT",	"gfloat",	"g_value_get_float",	},
     { "DOUBLE",		"DOUBLE",	"gdouble",	"g_value_get_double",	},
     { "STRING",		"STRING",	"gpointer",	"(char*) g_value_get_string",	},
+    { "BYTES",		"BYTES",	bytes_ctype,	NULL,	                }, /* Special cased */
     { "PARAM",		"PARAM",	"gpointer",	"g_value_get_param",	},
     { "BOXED",		"BOXED",	"gpointer",	"g_value_get_boxed",	},
     { "POINTER",	"POINTER",	"gpointer",	"g_value_get_pointer",	},
@@ -319,7 +322,7 @@
     }
   if (gen_cbody && !have_std_marshaller)
     {
-      /* cfile marhsal header */
+      /* cfile marshal header */
       fprintf (fout, "void\n");
       ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
       fprintf (fout,   "GClosure     *closure,\n");
@@ -339,6 +342,11 @@
 
 	  if (iarg->getter)
 	    fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++);
+	  else if (iarg->ctype == bytes_ctype)
+	    {
+	      fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad ("gpointer"), a);
+	      fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad ("gint"),     a++);
+	    }
 	}
       fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
 
@@ -361,7 +369,7 @@
 		{
 		  InArgument *iarg = node->data;
 
-		  if (iarg->getter)
+		  if (iarg->getter || iarg->ctype == bytes_ctype)
 		    a++;
 		}
 	      fprintf (fout, "  g_return_if_fail (n_param_values == %u);\n", 1 + a);
@@ -389,6 +397,11 @@
 
 	  if (iarg->getter)
 	    fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++);
+	  else if (iarg->ctype == bytes_ctype)
+	    {
+	      fprintf (fout, "%s(gchar *)g_value_get_bytes_str (param_values + %d),\n", indent (ind), a);
+	      fprintf (fout, "%sg_value_get_bytes_len (param_values + %d),\n", indent (ind), a++);
+	    }
 	}
       fprintf (fout, "%sdata2);\n", indent (ind));
 
Index: gtype.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.h,v
retrieving revision 1.24
diff -u -r1.24 gtype.h
--- gtype.h	2001/03/18 04:44:37	1.24
+++ gtype.h	2001/03/28 00:33:16
@@ -55,6 +55,7 @@
   G_TYPE_FLOAT,
   G_TYPE_DOUBLE,
   G_TYPE_STRING,
+  G_TYPE_BYTES,
   G_TYPE_POINTER,
   G_TYPE_BOXED,
   G_TYPE_PARAM,
@@ -89,7 +90,8 @@
   G_TYPE_PARAM_POINTER		= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 15),
   G_TYPE_PARAM_VALUE_ARRAY	= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 16),
   G_TYPE_PARAM_CLOSURE		= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 17),
-  G_TYPE_PARAM_OBJECT		= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 18)
+  G_TYPE_PARAM_OBJECT		= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 18),
+  G_TYPE_PARAM_UNICHAR		= G_TYPE_DERIVE_ID (G_TYPE_PARAM, 19)
 } GTypeFundamentals;
 
 
Index: gvaluetypes.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gvaluetypes.c,v
retrieving revision 1.11
diff -u -r1.11 gvaluetypes.c
--- gvaluetypes.c	2001/03/18 04:44:38	1.11
+++ gvaluetypes.c	2001/03/28 00:33:16
@@ -269,6 +269,82 @@
 }
 
 static void
+value_init_bytes (GValue *value)
+{
+  value->data[0].v_pointer = NULL;
+  value->data[1].v_uint = 0;
+  value->data[2].v_uint = 0;
+}
+
+static void
+value_free_bytes (GValue *value)
+{
+  if (!(value->data[2].v_uint & G_VALUE_NOCOPY_CONTENTS))
+    g_free (value->data[0].v_pointer);
+}
+
+static void
+value_copy_bytes (const GValue *src_value,
+		  GValue       *dest_value)
+{
+  dest_value->data[0].v_pointer = g_memdup (src_value->data[0].v_pointer, src_value->data[1].v_uint);
+  dest_value->data[1].v_uint = src_value->data[1].v_uint;
+  dest_value->data[2].v_uint = 0;
+}
+
+static gchar*
+value_collect_bytes (GValue      *value,
+		     guint        n_collect_values,
+		     GTypeCValue *collect_values,
+		     guint        collect_flags)
+{
+  if (!collect_values[0].v_pointer)
+    {
+      value->data[0].v_pointer = NULL;
+      value->data[1].v_uint = 0;
+    }
+  else
+    {
+      if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+	{
+	  value->data[0].v_pointer = collect_values[0].v_pointer;
+	  value->data[2].v_uint = G_VALUE_NOCOPY_CONTENTS;
+	}
+      else
+	{
+	  value->data[0].v_pointer = g_memdup (collect_values[0].v_pointer, collect_values[1].v_int);
+	  value->data[2].v_uint = 0;
+	}
+      
+      value->data[1].v_uint = collect_values[1].v_int;
+    }
+
+  return NULL;
+}
+
+static gchar*
+value_lcopy_bytes (const GValue *value,
+		   guint         n_collect_values,
+		   GTypeCValue  *collect_values,
+		   guint         collect_flags)
+{
+  gchar **string_p = collect_values[0].v_pointer;
+  guint *uint_p = collect_values[1].v_pointer;
+
+  if (!string_p || !uint_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+  
+  if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+    *string_p = value->data[0].v_pointer;
+  else
+    *string_p = g_memdup (value->data[0].v_pointer, value->data[1].v_uint);
+
+  *uint_p = value->data[1].v_uint;
+  
+  return NULL;
+}
+
+static void
 value_init_pointer (GValue *value)
 {
   value->data[0].v_pointer = NULL;
@@ -466,6 +542,24 @@
     g_assert (type == G_TYPE_STRING);
   }
 
+  /* G_TYPE_BYTES
+   */
+  {
+    static const GTypeValueTable value_table = {
+      value_init_bytes,	      /* value_init */
+      value_free_bytes,	      /* value_free */
+      value_copy_bytes,       /* value_copy */
+      NULL,                   /* value_peek_pointer */
+      "pi",		      /* collect_format */
+      value_collect_bytes,    /* collect_value */
+      "pp",		      /* lcopy_format */
+      value_lcopy_bytes,      /* lcopy_value */
+    };
+    info.value_table = &value_table;
+    type = g_type_register_fundamental (G_TYPE_BYTES, "gbytes", &info, &finfo, 0);
+    g_assert (type == G_TYPE_POINTER);
+  }
+
   /* G_TYPE_POINTER
    */
   {
Index: gvaluetypes.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gvaluetypes.h,v
retrieving revision 1.10
diff -u -r1.10 gvaluetypes.h
--- gvaluetypes.h	2001/03/18 04:44:38	1.10
+++ gvaluetypes.h	2001/03/28 00:33:17
@@ -37,6 +37,7 @@
 #define G_VALUE_HOLDS_FLOAT(value)	 (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT))
 #define G_VALUE_HOLDS_DOUBLE(value)	 (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_DOUBLE))
 #define G_VALUE_HOLDS_STRING(value)	 (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_STRING))
+#define G_VALUE_HOLDS_BYTES(value)	 (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_BYTES))
 #define G_VALUE_HOLDS_POINTER(value)	 (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_POINTER))
 
 
@@ -74,5 +75,21 @@
 						 const gchar  *v_string);
 G_CONST_RETURN gchar* g_value_get_string	(const GValue *value);
 gchar*		      g_value_dup_string	(const GValue *value);
+
+void                  g_value_set_bytes        (GValue                *value,
+						const gchar           *v_string,
+						guint                  v_length);
+void                  g_value_set_static_bytes (GValue                *value,
+						const gchar           *v_string,
+						guint                  v_length);
+G_CONST_RETURN gchar *g_value_get_bytes_str    (GValue                *value);
+guint                 g_value_get_bytes_len    (GValue                *value);
+void                  g_value_dup_bytes        (GValue                *value,
+						gchar                **v_string,
+						guint                 *v_length);
+
 void		      g_value_set_pointer	(GValue	      *value,
 						 gpointer      v_pointer);
 gpointer	      g_value_get_pointer	(const GValue *value);
 
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]