gstreamer/gst/gststructure.c
David Schleef ea1135ec9f Add gst_strtoi().
Original commit message from CVS:
Add gst_strtoi().
2004-01-11 23:25:02 +00:00

1552 lines
36 KiB
C

/* GStreamer
* Copyright (C) 2003 David A. Schleef <ds@schleef.org>
*
* gststructure.c: lists of { GQuark, GValue } tuples
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gobject/gvaluecollector.h>
static GType _gst_structure_type;
typedef struct _GstStructureField GstStructureField;
struct _GstStructureField {
GQuark name;
GValue value;
};
#define GST_STRUCTURE_FIELD(structure, index) \
&g_array_index((structure)->fields, GstStructureField, (index))
static void gst_structure_set_field (GstStructure *structure,
GstStructureField *field);
static GstStructureField *gst_structure_get_field(const GstStructure *structure,
const gchar *fieldname);
static GstStructureField *gst_structure_id_get_field(const GstStructure *structure,
GQuark fieldname);
static void _gst_structure_transform_to_string(const GValue *src_value,
GValue *dest_value);
static void _gst_structure_value_init (GValue *value);
static void _gst_structure_value_free (GValue *value);
static void _gst_structure_value_copy (const GValue *src, GValue *dest);
static gpointer _gst_structure_value_peek_pointer (const GValue *value);
GType gst_structure_get_type(void)
{
return _gst_structure_type;
}
void _gst_structure_initialize(void)
{
static const GTypeValueTable type_value_table = {
_gst_structure_value_init,
_gst_structure_value_free,
_gst_structure_value_copy,
_gst_structure_value_peek_pointer,
NULL,
NULL,
NULL,
NULL,
};
static const GTypeInfo structure_info = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0, /* sizeof(GstStructure), */
0,
NULL, /* _gst_structure_init, */
&type_value_table,
};
_gst_structure_type = g_type_register_static(G_TYPE_BOXED, "GstStructure",
&structure_info, 0);
#if 0
_gst_structure_type = g_boxed_type_register_static("GstStructure",
(GBoxedCopyFunc) gst_structure_copy,
(GBoxedFreeFunc) gst_structure_free);
#endif
g_value_register_transform_func(_gst_structure_type, G_TYPE_STRING,
_gst_structure_transform_to_string);
}
/**
* gst_structure_id_empty_new:
* @name: name of new structure
*
* Creates a new, empty #GstStructure with the given name.
*
* Returns: a new, empty #GstStructure
*/
GstStructure *gst_structure_id_empty_new(GQuark quark)
{
GstStructure *structure;
g_return_val_if_fail(quark != 0, NULL);
structure = g_new0(GstStructure, 1);
structure->name = quark;
structure->fields = g_array_new(FALSE,TRUE,sizeof(GstStructureField));
return structure;
}
/**
* gst_structure_empty_new:
* @name: name of new structure
*
* Creates a new, empty #GstStructure with the given name.
*
* Returns: a new, empty #GstStructure
*/
GstStructure *gst_structure_empty_new(const gchar *name)
{
GstStructure *structure;
g_return_val_if_fail(name != NULL, NULL);
structure = g_new0(GstStructure, 1);
structure->name = g_quark_from_string(name);
structure->fields = g_array_new(FALSE,TRUE,sizeof(GstStructureField));
return structure;
}
/**
* gst_structure_new:
* @name: name of new structure
* @firstfield: name of first field to set
* @...: additional arguments
*
* Creates a new #GstStructure with the given name. Parses the
* list of variable arguments and sets fields to the values listed.
* Variable arguments should be passed as field name, field type,
* and value. Last variable argument should be NULL.
*
* Returns: a new #GstStructure
*/
GstStructure *gst_structure_new(const gchar *name,
const gchar *firstfield, ...)
{
GstStructure *structure;
va_list varargs;
g_return_val_if_fail(name != NULL, NULL);
va_start(varargs, firstfield);
structure = gst_structure_new_valist(name,firstfield,varargs);
va_end(varargs);
return structure;
}
/**
* gst_structure_new_valist:
* @name: name of new structure
* @firstfield: name of first field to set
* @varags: variable argument list
*
* Creates a new #GstStructure with the given name. Structure fields
* are set according to the varargs in a manner similar to
* @gst_structure_new.
*
* Returns: a new #GstStructure
*/
GstStructure *gst_structure_new_valist(const gchar *name,
const gchar *firstfield, va_list varargs)
{
GstStructure *structure;
g_return_val_if_fail(name != NULL, NULL);
structure = gst_structure_empty_new(name);
gst_structure_set_valist(structure, firstfield, varargs);
return structure;
}
/**
* gst_structure_copy:
* @structure: a #GstStructure to duplicate
*
* Duplicates a #GstStructure and all its fields and values.
*
* Returns: a new #GstStructure.
*/
GstStructure *gst_structure_copy(GstStructure *structure)
{
GstStructure *new_structure;
GstStructureField *field;
int i;
g_return_val_if_fail(structure != NULL, NULL);
new_structure = gst_structure_empty_new(g_quark_to_string(structure->name));
new_structure->name = structure->name;
for(i=0;i<structure->fields->len;i++){
GstStructureField new_field = { 0 };
field = GST_STRUCTURE_FIELD(structure, i);
new_field.name = field->name;
gst_value_init_and_copy (&new_field.value, &field->value);
g_array_append_val(new_structure->fields, new_field);
}
return new_structure;
}
/**
* gst_structure_free:
* @structure: the #GstStructure to free
*
* Frees a #GstStructure and all its fields and values.
*/
void gst_structure_free(GstStructure *structure)
{
GstStructureField *field;
int i;
return;
g_return_if_fail(structure != NULL);
for(i=0;i<structure->fields->len;i++){
field = GST_STRUCTURE_FIELD(structure, i);
if(G_IS_VALUE(&field->value)){
g_value_unset(&field->value);
}
}
#ifdef USE_POISONING
memset (structure, 0xff, sizeof(GstStructure));
#endif
g_free(structure);
}
/**
* gst_structure_get_name:
* @structure: a #GstStructure
*
* Accessor fuction.
*
* Returns: the name of the structure.
*/
const gchar *gst_structure_get_name(const GstStructure *structure)
{
g_return_val_if_fail(structure != NULL, NULL);
return g_quark_to_string(structure->name);
}
/**
* gst_structure_set_name:
* @structure: a #GstStructure
* @name: the new name of the structure
*
* Sets the name of the structure to the given name. The string
* provided is copied before being used.
*/
void gst_structure_set_name(GstStructure *structure, const gchar *name)
{
g_return_if_fail(structure != NULL);
g_return_if_fail(name != NULL);
structure->name = g_quark_from_string(name);
}
/**
* gst_structure_id_set_value:
* @structure: a #GstStructure
* @field_id: a #GQuark representing a field
* @value: the new value of the field
*
* Sets the field with the given ID to the provided value. If the field
* does not exist, it is created. If the field exists, the previous
* value is freed.
*/
void gst_structure_id_set_value(GstStructure *structure, GQuark fieldname,
const GValue *value)
{
GstStructureField field = { 0, { 0, } };
g_return_if_fail(structure != NULL);
g_return_if_fail(G_IS_VALUE(value));
field.name = fieldname;
gst_value_init_and_copy (&field.value, value);
gst_structure_set_field(structure, &field);
}
/**
* gst_structure_set_value:
* @structure: a #GstStructure
* @field: the name of the field to set
* @value: the new value of the field
*
* Sets the field with the given name to the provided value. If the field
* does not exist, it is created. If the field exists, the previous
* value is freed.
*/
void gst_structure_set_value(GstStructure *structure, const gchar *field,
const GValue *value)
{
g_return_if_fail(structure != NULL);
g_return_if_fail(field != NULL);
g_return_if_fail(G_IS_VALUE(value));
gst_structure_id_set_value(structure, g_quark_from_string(field), value);
}
/**
* gst_structure_set:
* @structure: a #GstStructure
* @field: the name of the field to set
* @...: variable arguments
*
* Parses the variable arguments and sets fields accordingly.
* Variable arguments should be in the form field name, field type
* (as a GType), value. The last variable argument should be NULL.
*/
void gst_structure_set(GstStructure *structure, const gchar *field, ...)
{
va_list varargs;
g_return_if_fail(structure != NULL);
va_start(varargs, field);
gst_structure_set_valist(structure,field,varargs);
va_end(varargs);
}
/**
* gst_structure_set_valist:
* @structure: a #GstStructure
* @field: the name of the field to set
* @varargs: variable arguments
*
* va_list form of #gst_structure_set.
*/
void gst_structure_set_valist(GstStructure *structure, const gchar *fieldname,
va_list varargs)
{
GType type;
int i;
double d;
char *s;
g_return_if_fail(structure != NULL);
while(fieldname){
GstStructureField field = { 0 };
field.name = g_quark_from_string(fieldname);
type = va_arg (varargs, GType);
switch(type){
case G_TYPE_INT:
i = va_arg(varargs, int);
g_value_init(&field.value, G_TYPE_INT);
g_value_set_int(&field.value, i);
break;
case G_TYPE_DOUBLE:
d = va_arg(varargs, double);
g_value_init(&field.value, G_TYPE_DOUBLE);
g_value_set_double(&field.value, d);
break;
case G_TYPE_BOOLEAN:
i = va_arg(varargs, int);
g_value_init(&field.value, G_TYPE_BOOLEAN);
g_value_set_boolean(&field.value, i);
break;
case G_TYPE_STRING:
s = va_arg(varargs, char *);
g_value_init(&field.value, G_TYPE_STRING);
g_value_set_string(&field.value, s);
break;
default:
if(type == GST_TYPE_FOURCC){
i = va_arg(varargs, int);
g_value_init(&field.value, GST_TYPE_FOURCC);
gst_value_set_fourcc(&field.value, i);
} else if (type == GST_TYPE_INT_RANGE){
int min, max;
min = va_arg(varargs, int);
max = va_arg(varargs, int);
g_value_init(&field.value, GST_TYPE_INT_RANGE);
gst_value_set_int_range(&field.value, min, max);
} else if (type == GST_TYPE_DOUBLE_RANGE){
double min, max;
min = va_arg(varargs, double);
max = va_arg(varargs, double);
g_value_init(&field.value, GST_TYPE_DOUBLE_RANGE);
gst_value_set_double_range(&field.value, min, max);
} else {
g_critical("unimplemented vararg field type %d\n", (int)type);
return;
}
break;
}
gst_structure_set_field(structure, &field);
fieldname = va_arg (varargs, gchar *);
}
}
/**
* gst_structure_set_field:
* @structure: a #GstStructure
* @field: the #GstStructureField to set
*
* Sets a field in the structure. If the structure currently contains
* a field with the same name, it is replaced with the provided field.
* Otherwise, the field is added to the structure. The field's value
* is not deeply copied.
*
* This function is intended mainly for internal use. The function
* #gst_structure_set() is recommended instead of this one.
*/
static void gst_structure_set_field(GstStructure *structure, GstStructureField *field)
{
GstStructureField *f;
int i;
for(i=0;i<structure->fields->len;i++){
f = GST_STRUCTURE_FIELD(structure, i);
if(f->name == field->name){
g_value_unset(&f->value);
memcpy(f,field,sizeof(GstStructureField));
return;
}
}
g_array_append_val(structure->fields, *field);
}
/**
* gst_structure_id_get_field:
* @structure: a #GstStructure
* @field_id: the GQuark of the field to get
*
* Gets the specified field from the structure. If there is no
* field with the given ID, NULL is returned.
*
* Returns: the #GstStructureField with the given ID
*/
static GstStructureField *gst_structure_id_get_field(const GstStructure *structure,
GQuark field_id)
{
GstStructureField *field;
int i;
g_return_val_if_fail(structure != NULL, NULL);
for(i=0;i<structure->fields->len;i++){
field = GST_STRUCTURE_FIELD(structure, i);
if(field->name == field_id) return field;
}
return NULL;
}
/**
* gst_structure_get_field:
* @structure: a #GstStructure
* @fieldname: the name of the field to get
*
* Gets the specified field from the structure. If there is no
* field with the given ID, NULL is returned.
*
* Returns: the #GstStructureField with the given name
*/
static GstStructureField *
gst_structure_get_field(const GstStructure *structure, const gchar *fieldname)
{
g_return_val_if_fail(structure != NULL, NULL);
g_return_val_if_fail(fieldname != NULL, NULL);
return gst_structure_id_get_field(structure,
g_quark_from_string(fieldname));
}
/**
* gst_structure_get_value:
* @structure: a #GstStructure
* @fieldname: the name of the field to get
*
* Accessor function.
*
* Returns: the #GValue corresponding to the field with the given name.
*/
const GValue *
gst_structure_get_value(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, NULL);
g_return_val_if_fail(fieldname != NULL, NULL);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return NULL;
return &field->value;
}
/**
* gst_structure_id_get_value:
* @structure: a #GstStructure
* @id: the #GQuark of the field to get
*
* Accessor function.
*
* Returns: the #GValue corresponding to the field with the given name
* identifier.
*/
const GValue *
gst_structure_id_get_value(const GstStructure *structure, GQuark id)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, NULL);
field = gst_structure_id_get_field(structure, id);
if(field == NULL) return NULL;
return &field->value;
}
#if 0
void gst_structure_get(GstStructure *structure, const gchar *fieldname, ...)
{
}
#endif
/**
* gst_structure_remove_field:
* @structure: a #GstStructure
* @fieldname: the name of the field to remove
*
* Removes the field with the given name. If the field with the given
* name does not exist, the structure is unchanged.
*/
void
gst_structure_remove_field(GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
GQuark id;
int i;
g_return_if_fail(structure != NULL);
g_return_if_fail(fieldname != NULL);
id = g_quark_from_string(fieldname);
for(i=0;i<structure->fields->len;i++){
field = GST_STRUCTURE_FIELD(structure, i);
if(field->name == id){
if(G_IS_VALUE(&field->value)){
g_value_unset(&field->value);
}
structure->fields = g_array_remove_index(structure->fields, i);
return;
}
}
}
/**
* gst_structure_remove_all_fields:
* @structure: a #GstStructure
*
* Removes all fields in a GstStructure.
*/
void
gst_structure_remove_all_fields(GstStructure *structure)
{
GstStructureField *field;
int i;
g_return_if_fail(structure != NULL);
for (i = structure->fields->len - 1; i >= 0; i-- ) {
field = GST_STRUCTURE_FIELD(structure, i);
if (G_IS_VALUE (&field->value)) {
g_value_unset(&field->value);
}
structure->fields = g_array_remove_index (structure->fields, i);
}
}
/**
* gst_structure_get_field_type:
* @structure: a #GstStructure
* @fieldname: the name of the field
*
* Finds the field with the given name, and returns the type of the
* value it contains. If the field is not found, G_TYPE_INVALID is
* returned.
*
* Returns: the #GValue of the field
*/
GType
gst_structure_get_field_type(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, G_TYPE_INVALID);
g_return_val_if_fail(fieldname != NULL, G_TYPE_INVALID);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return G_TYPE_INVALID;
return G_VALUE_TYPE(&field->value);
}
/**
* gst_structure_n_fields:
* @structure: a #GstStructure
*
* Accessor function.
*
* Returns: the number of fields in the structure
*/
gint
gst_structure_n_fields(const GstStructure *structure)
{
g_return_val_if_fail(structure != NULL, 0);
return structure->fields->len;
}
/**
* gst_structure_foreach:
* @structure: a #GstStructure
* @func: a function to call for each field
* @user_data: private data
*
* Calls the provided function once for each field in the #GstStructure.
*/
gboolean
gst_structure_foreach (GstStructure *structure,
GstStructureForeachFunc func, gpointer user_data)
{
int i;
GstStructureField *field;
gboolean ret;
for(i=0;i<structure->fields->len;i++){
field = GST_STRUCTURE_FIELD(structure, i);
ret = func (field->name, &field->value, user_data);
if (!ret) return FALSE;
}
return TRUE;
}
/**
* gst_structure_has_field:
* @structure: a #GstStructure
* @fieldname: the name of a field
*
* Accessor function.
*
* Returns: TRUE if the structure contains a field with the given name
*/
gboolean
gst_structure_has_field(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, 0);
g_return_val_if_fail(fieldname != NULL, 0);
field = gst_structure_get_field(structure, fieldname);
return (field != NULL);
}
/**
* gst_structure_has_field:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @type: the type of a value
*
* Accessor function.
*
* Returns: TRUE if the structure contains a field with the given name and type
*/
gboolean
gst_structure_has_field_typed(const GstStructure *structure, const gchar *fieldname,
GType type)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, 0);
g_return_val_if_fail(fieldname != NULL, 0);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
return (G_VALUE_TYPE(&field->value) == type);
}
/* utility functions */
/**
* gst_structure_get_boolean:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @ptr: a pointer to a #gboolean to set
*
* Sets the boolean pointed to by @ptr corresponding to the value of the
* given field. Caller is responsible for making sure the field exists
* and has the correct type.
*
* Returns: TRUE if the value could be set correctly
*/
gboolean
gst_structure_get_boolean(const GstStructure *structure, const gchar *fieldname,
gboolean *value)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, FALSE);
g_return_val_if_fail(fieldname != NULL, FALSE);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
if(!G_VALUE_HOLDS_BOOLEAN(&field->value))return FALSE;
*value = g_value_get_boolean(&field->value);
return TRUE;
}
/**
* gst_structure_get_int:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @ptr: a pointer to an int to set
*
* Sets the int pointed to by @ptr corresponding to the value of the
* given field. Caller is responsible for making sure the field exists
* and has the correct type.
*
* Returns: TRUE if the value could be set correctly
*/
gboolean
gst_structure_get_int(const GstStructure *structure, const gchar *fieldname,
gint *value)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, FALSE);
g_return_val_if_fail(fieldname != NULL, FALSE);
g_return_val_if_fail(value != NULL, FALSE);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
if(!G_VALUE_HOLDS_INT(&field->value))return FALSE;
*value = g_value_get_int(&field->value);
return TRUE;
}
/**
* gst_structure_get_fourcc:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @ptr: a pointer to a #GstFourcc to set
*
* Sets the #GstFourcc pointed to by @ptr corresponding to the value of the
* given field. Caller is responsible for making sure the field exists
* and has the correct type.
*
* Returns: TRUE if the value could be set correctly
*/
gboolean
gst_structure_get_fourcc(const GstStructure *structure, const gchar *fieldname,
guint32 *value)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, FALSE);
g_return_val_if_fail(fieldname != NULL, FALSE);
g_return_val_if_fail(value != NULL, FALSE);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
if(!GST_VALUE_HOLDS_FOURCC(&field->value))return FALSE;
*value = gst_value_get_fourcc (&field->value);
return TRUE;
}
/**
* gst_structure_get_double:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @ptr: a pointer to a #GstFourcc to set
*
* Sets the double pointed to by @ptr corresponding to the value of the
* given field. Caller is responsible for making sure the field exists
* and has the correct type.
*
* Returns: TRUE if the value could be set correctly
*/
gboolean gst_structure_get_double(const GstStructure *structure,
const gchar *fieldname, gdouble *value)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, FALSE);
g_return_val_if_fail(fieldname != NULL, FALSE);
g_return_val_if_fail(value != NULL, FALSE);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
if(!G_VALUE_HOLDS_DOUBLE(&field->value))return FALSE;
*value = g_value_get_double(&field->value);
return TRUE;
}
/**
* gst_structure_get_string:
* @structure: a #GstStructure
* @fieldname: the name of a field
* @ptr: a pointer to a #GstFourcc to set
*
* Finds the field corresponding to @fieldname, and returns the string
* contained in the field's value. Caller is responsible for making
* sure the field exists and has the correct type.
*
* The string should not be modified, and remains valid until the next
* call to a gst_structure_*() function with the given structure.
*
* Returns: a pointer to the string
*/
const gchar *
gst_structure_get_string(const GstStructure *structure, const gchar *fieldname)
{
GstStructureField *field;
g_return_val_if_fail(structure != NULL, NULL);
g_return_val_if_fail(fieldname != NULL, NULL);
field = gst_structure_get_field(structure, fieldname);
if(field == NULL) return FALSE;
if(!G_VALUE_HOLDS_STRING(&field->value))return FALSE;
return g_value_get_string(&field->value);
}
typedef struct _GstStructureAbbreviation {
char *type_name;
GType type;
} GstStructureAbbreviation;
static GstStructureAbbreviation _gst_structure_abbrs[] = {
{ "int", G_TYPE_INT },
{ "i", G_TYPE_INT },
{ "float", G_TYPE_FLOAT },
{ "f", G_TYPE_FLOAT },
{ "double", G_TYPE_DOUBLE },
{ "d", G_TYPE_DOUBLE },
//{ "fourcc", GST_TYPE_FOURCC },
{ "boolean", G_TYPE_BOOLEAN },
{ "bool", G_TYPE_BOOLEAN },
{ "b", G_TYPE_BOOLEAN },
{ "string", G_TYPE_STRING },
{ "str", G_TYPE_STRING },
{ "s", G_TYPE_STRING }
};
static GType _gst_structure_from_abbr(const char *type_name)
{
int i;
g_return_val_if_fail(type_name != NULL, G_TYPE_INVALID);
for(i=0;i<G_N_ELEMENTS(_gst_structure_abbrs);i++){
if(strcmp(type_name,_gst_structure_abbrs[i].type_name)==0){
return _gst_structure_abbrs[i].type;
}
}
/* FIXME shouldn't be a special case */
if (strcmp (type_name,"fourcc") == 0 || strcmp (type_name, "4") == 0) {
return GST_TYPE_FOURCC;
}
return g_type_from_name (type_name);
}
static const char *_gst_structure_to_abbr(GType type)
{
int i;
g_return_val_if_fail(type != G_TYPE_INVALID, NULL);
for(i=0;i<G_N_ELEMENTS(_gst_structure_abbrs);i++){
if(type == _gst_structure_abbrs[i].type){
return _gst_structure_abbrs[i].type_name;
}
}
/* FIXME shouldn't be a special case */
if (type == GST_TYPE_FOURCC) {
return "fourcc";
}
return g_type_name(type);
}
#define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
((c) == '.'))
static gchar *
_gst_structure_wrap_string(gchar *s)
{
gchar *t;
int len;
gchar *d, *e;
gboolean wrap = FALSE;
len = 0;
t = s;
while (*t) {
if(GST_ASCII_IS_STRING(*t)) {
len++;
} else if(*t < 0x20 || *t >= 0x7f) {
wrap = TRUE;
len += 4;
} else {
wrap = TRUE;
len += 2;
}
t++;
}
if (!wrap) return s;
e = d = g_malloc(len + 3);
*e++ = '\"';
t = s;
while (*t) {
if(GST_ASCII_IS_STRING(*t)) {
*e++ = *t++;
} else if(*t < 0x20 || *t >= 0x7f) {
*e++ = '\\';
*e++ = '0' + ((*t)>>6);
*e++ = '0' + (((*t)>>3)&0x7);
*e++ = '0' + ((*t++)&0x7);
} else {
*e++ = '\\';
*e++ = *t++;
}
}
*e++ = '\"';
*e = 0;
g_free(s);
return d;
}
/**
* gst_structure_to_string:
* @structure: a #GstStructure
*
* Converts @structure to a human-readable representation.
*
* Returns: a pointer to string allocated by g_malloc()
*/
gchar *
gst_structure_to_string(const GstStructure *structure)
{
GstStructureField *field;
GString *s;
char *t;
int i;
g_return_val_if_fail(structure != NULL, NULL);
s = g_string_new("");
/* FIXME this string may need to be escaped */
g_string_append_printf(s, "%s", g_quark_to_string(structure->name));
for(i=0;i<structure->fields->len;i++) {
GValue s_val = { 0 };
GType type;
field = GST_STRUCTURE_FIELD(structure, i);
g_value_init(&s_val, G_TYPE_STRING);
g_value_transform (&field->value, &s_val);
type = G_VALUE_TYPE (&field->value);
if (type == GST_TYPE_LIST) {
GArray *array = g_value_peek_pointer (&field->value);
if (array->len > 0){
GValue *value = &g_array_index (array, GValue, 0);
type = G_VALUE_TYPE (value);
} else {
type = G_TYPE_INT;
}
t = g_strdup(g_value_get_string(&s_val));
} else if (G_VALUE_TYPE(&field->value) == GST_TYPE_INT_RANGE) {
type = G_TYPE_INT;
t = g_strdup(g_value_get_string(&s_val));
} else if (G_VALUE_TYPE(&field->value) == GST_TYPE_DOUBLE_RANGE) {
type = G_TYPE_DOUBLE;
t = g_strdup(g_value_get_string(&s_val));
} else {
t = _gst_structure_wrap_string(g_strdup(g_value_get_string(&s_val)));
}
g_string_append_printf(s, ", %s=(%s)%s", g_quark_to_string(field->name),
_gst_structure_to_abbr(type), t);
g_free(t);
g_value_unset (&s_val);
}
return g_string_free(s, FALSE);
}
/*
* r will still point to the string. if end == next, the string will not be
* null-terminated. In all other cases it will be.
* end = pointer to char behind end of string, next = pointer to start of
* unread data.
* THIS FUNCTION MODIFIES THE STRING AND DETECTS INSIDE A NONTERMINATED STRING
*/
static gboolean _gst_structure_parse_simple_string (gchar *s, gchar **end);
static gboolean
_gst_structure_parse_string (gchar *s, gchar **end, gchar **next)
{
gchar *w;
if (*s == 0) return FALSE;
if (*s != '"') {
int ret;
ret = _gst_structure_parse_simple_string (s, end);
*next = *end;
return ret;
}
w = s;
s++;
while (*s != '"') {
if (*s == 0) return FALSE;
if (*s == '\\') {
s++;
}
*w = *s;
w++;
s++;
}
s++;
*end = w;
*next = s;
return TRUE;
}
static int
gst_strtoi (const char *s, char **end, int base)
{
int i;
if (s[0] == '-') {
i = - (int) strtoul (s + 1, end, base);
} else {
i = strtoul (s, end, base);
}
return i;
}
static gboolean
gst_value_from_string (GValue *value, const char *s)
{
gboolean ret = FALSE;
gchar *end;
GType type = G_VALUE_TYPE (value);
if (type == G_TYPE_INVALID) return FALSE;
switch (type) {
case G_TYPE_INT:
{
int x;
x = gst_strtoi (s, &end, 0);
if (*end == 0) {
ret = TRUE;
} else {
if (g_ascii_strcasecmp (s, "little_endian") == 0) {
x = G_LITTLE_ENDIAN;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
x = G_BIG_ENDIAN;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
x = G_BYTE_ORDER;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "min") == 0) {
x = G_MININT;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "max") == 0) {
x = G_MAXINT;
ret = TRUE;
}
}
if (ret) {
g_value_set_int (value, x);
}
}
break;
case G_TYPE_FLOAT:
{
double x;
x = g_ascii_strtod (s, &end);
if (*end == 0) {
g_value_set_float (value, x);
ret = TRUE;
}
}
break;
case G_TYPE_DOUBLE:
{
double x;
x = g_ascii_strtod (s, &end);
if (*end == 0) {
ret = TRUE;
} else {
if (g_ascii_strcasecmp (s, "min") == 0) {
x = -G_MAXDOUBLE;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "max") == 0) {
x = G_MAXDOUBLE;
ret = TRUE;
}
}
if (ret) {
g_value_set_double (value, x);
}
}
break;
case G_TYPE_BOOLEAN:
{
if (g_ascii_strcasecmp (s, "true") == 0 ||
g_ascii_strcasecmp (s, "yes") == 0 ||
g_ascii_strcasecmp (s, "t") == 0 ||
strcmp (s, "1") == 0) {
g_value_set_boolean (value, TRUE);
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "false") == 0 ||
g_ascii_strcasecmp (s, "no") == 0 ||
g_ascii_strcasecmp (s, "f") == 0 ||
strcmp (s, "0") == 0) {
g_value_set_boolean (value, FALSE);
ret = TRUE;
}
}
break;
case G_TYPE_STRING:
{
g_value_set_string (value, s);
ret = TRUE;
}
break;
default:
/* FIXME: make more general */
if (type == GST_TYPE_FOURCC) {
guint32 fourcc = 0;
if (strlen(s) == 4) {
fourcc = GST_MAKE_FOURCC(s[0], s[1], s[2], s[3]);
ret = TRUE;
} else if (g_ascii_isdigit (*s)) {
fourcc = strtoul (s, &end, 0);
if (*end == 0) {
ret = TRUE;
}
}
gst_value_set_fourcc (value, fourcc);
} else {
g_critical("type %s not handled", g_type_name(type));
}
break;
}
return ret;
}
static gboolean _gst_structure_parse_value (gchar *str, gchar **after,
GValue *value, GType default_type);
static gboolean
_gst_structure_parse_range (gchar *s, gchar **after, GValue *value, GType type)
{
GValue value1 = { 0 };
GValue value2 = { 0 };
GType range_type;
gboolean ret;
if (*s != '[') return FALSE;
s++;
ret = _gst_structure_parse_value(s, &s, &value1, type);
if (ret == FALSE) return FALSE;
while (g_ascii_isspace (*s)) s++;
if (*s != ',') return FALSE;
s++;
while (g_ascii_isspace (*s)) s++;
ret = _gst_structure_parse_value(s, &s, &value2, type);
if (ret == FALSE) return FALSE;
while (g_ascii_isspace (*s)) s++;
if (*s != ']') return FALSE;
s++;
if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2)) return FALSE;
if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
range_type = GST_TYPE_DOUBLE_RANGE;
} else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
range_type = GST_TYPE_INT_RANGE;
} else {
return FALSE;
}
g_value_init(value, range_type);
if (range_type == GST_TYPE_DOUBLE_RANGE) {
gst_value_set_double_range(value, g_value_get_double(&value1),
g_value_get_double(&value2));
} else {
gst_value_set_int_range(value, g_value_get_int(&value1),
g_value_get_int(&value2));
}
*after = s;
return TRUE;
}
static gboolean
_gst_structure_parse_list (gchar *s, gchar **after, GValue *value, GType type)
{
GValue list_value = { 0 };
gboolean ret;
GArray *array;
g_value_init(value, GST_TYPE_LIST);
array = g_value_peek_pointer (value);
if (*s != '{') return FALSE;
s++;
while (g_ascii_isspace (*s)) s++;
if (*s == '}') {
s++;
*after = s;
return TRUE;
}
ret = _gst_structure_parse_value(s, &s, &list_value, type);
if (ret == FALSE) return FALSE;
g_array_append_val (array, list_value);
while (g_ascii_isspace (*s)) s++;
while (*s != '}') {
if (*s != ',') return FALSE;
s++;
while (g_ascii_isspace (*s)) s++;
memset (&list_value, 0, sizeof (list_value));
ret = _gst_structure_parse_value(s, &s, &list_value, type);
if (ret == FALSE) return FALSE;
g_array_append_val (array, list_value);
while (g_ascii_isspace (*s)) s++;
}
s++;
*after = s;
return TRUE;
}
static gboolean
_gst_structure_parse_simple_string (gchar *str, gchar **end)
{
char *s = str;
while(GST_ASCII_IS_STRING(*s)){
s++;
}
*end = s;
return (s != str);
}
static gboolean
_gst_structure_parse_field (gchar *str, gchar **after, GstStructureField *field)
{
gchar *name;
gchar *name_end;
gchar *s;
gchar c;
s = str;
while(g_ascii_isspace (*s)) s++;
name = s;
if (!_gst_structure_parse_simple_string (s, &name_end)) return FALSE;
s = name_end;
while(g_ascii_isspace (*s)) s++;
if (*s != '=') return FALSE;
s++;
c = *name_end;
*name_end = 0;
field->name = g_quark_from_string (name);
*name_end = c;
if (!_gst_structure_parse_value (s, &s, &field->value, G_TYPE_INVALID))
return FALSE;
*after = s;
return TRUE;
}
static gboolean
_gst_structure_parse_value (gchar *str, gchar **after, GValue *value,
GType default_type)
{
gchar *type_name;
gchar *type_end;
gchar *value_s;
gchar *value_end;
gchar *s;
gchar c;
int ret = 0;
GType type = default_type;
s = str;
while(g_ascii_isspace (*s)) s++;
type_name = NULL;
if (*s == '(') {
type = G_TYPE_INVALID;
s++;
while(g_ascii_isspace (*s)) s++;
type_name = s;
if (!_gst_structure_parse_simple_string (s, &type_end)) return FALSE;
s = type_end;
while(g_ascii_isspace (*s)) s++;
if (*s != ')') return FALSE;
s++;
while(g_ascii_isspace (*s)) s++;
c = *type_end;
*type_end = 0;
type = _gst_structure_from_abbr(type_name);
*type_end = c;
if (type == G_TYPE_INVALID) return FALSE;
}
while(g_ascii_isspace (*s)) s++;
if (*s == '[') {
ret = _gst_structure_parse_range (s, &s, value, type);
} else if (*s == '{') {
ret = _gst_structure_parse_list (s, &s, value, type);
} else {
value_s = s;
if (!_gst_structure_parse_string (s, &value_end, &s)) return FALSE;
c = *value_end;
*value_end = 0;
if (type == G_TYPE_INVALID) {
GType try_types[] = { G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_STRING };
int i;
for(i=0;i<3;i++) {
g_value_init(value, try_types[i]);
ret = gst_value_from_string (value, value_s);
if (ret) break;
g_value_unset(value);
}
} else {
g_value_init(value, type);
ret = gst_value_from_string (value, value_s);
}
*value_end = c;
}
*after = s;
return ret;
}
/**
* gst_structure_from_string:
* @structure: a #GstStructure
*
* Creates a #GstStructure from a string representation.
*
* Returns: a new #GstStructure
*/
GstStructure *
gst_structure_from_string (const gchar *string, gchar **end)
{
char *name;
char *copy;
char *w;
char *r;
char save;
GstStructure *structure;
GstStructureField field = { 0 };
gboolean res;
g_return_val_if_fail(string != NULL, NULL);
copy = g_strdup(string);
r = copy;
name = r;
res = _gst_structure_parse_string (r, &w, &r);
if (!res) return NULL;
while (g_ascii_isspace(*r)) r++;
if(*r != 0 && *r != ';' && *r != ',') return NULL;
save = *w;
*w = 0;
structure = gst_structure_empty_new(name);
*w = save;
while (*r && (*r != ';')){
if(*r != ',') {
return NULL;
}
r++;
while (*r && g_ascii_isspace(*r)) r++;
memset(&field,0,sizeof(field));
res = _gst_structure_parse_field (r, &r, &field);
if (!res) {
gst_structure_free (structure);
return NULL;
}
gst_structure_set_field(structure, &field);
while (*r && g_ascii_isspace(*r)) r++;
}
if (end) *end = (char *)string + (r - copy);
return structure;
}
static void
_gst_structure_transform_to_string(const GValue *src_value, GValue *dest_value)
{
g_return_if_fail(src_value != NULL);
g_return_if_fail(dest_value != NULL);
dest_value->data[0].v_pointer =
gst_structure_to_string (src_value->data[0].v_pointer);
}
static void _gst_structure_value_init (GValue *value)
{
value->data[0].v_pointer = gst_structure_empty_new("");
}
static void _gst_structure_value_free (GValue *value)
{
gst_structure_free(value->data[0].v_pointer);
}
static void _gst_structure_value_copy (const GValue *src, GValue *dest)
{
dest->data[0].v_pointer = gst_structure_copy(src->data[0].v_pointer);
}
static gpointer _gst_structure_value_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}