1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * GData Client
4  * Copyright (C) Philip Withnall 2009–2010 <philip@tecnocode.co.uk>
5  *
6  * GData Client is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * GData Client is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * SECTION:gdata-media-category
22  * @short_description: Media RSS category element
23  * @stability: Stable
24  * @include: gdata/media/gdata-media-category.h
25  *
26  * #GDataMediaCategory represents a "category" element from the
27  * <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
28  *
29  * Since: 0.4.0
30  */
31 
32 #include <glib.h>
33 #include <libxml/parser.h>
34 
35 #include "gdata-media-category.h"
36 #include "gdata-parsable.h"
37 #include "gdata-parser.h"
38 #include "gdata-types.h"
39 
40 static void gdata_media_category_finalize (GObject *object);
41 static void gdata_media_category_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
42 static void gdata_media_category_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
43 static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
44 static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
45 static void pre_get_xml (GDataParsable *parsable, GString *xml_string);
46 static void get_xml (GDataParsable *parsable, GString *xml_string);
47 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
48 
49 struct _GDataMediaCategoryPrivate {
50 	gchar *category;
51 	gchar *scheme;
52 	gchar *label;
53 };
54 
55 enum {
56 	PROP_CATEGORY = 1,
57 	PROP_SCHEME,
58 	PROP_LABEL
59 };
60 
G_DEFINE_TYPE(GDataMediaCategory,gdata_media_category,GDATA_TYPE_PARSABLE)61 G_DEFINE_TYPE (GDataMediaCategory, gdata_media_category, GDATA_TYPE_PARSABLE)
62 
63 static void
64 gdata_media_category_class_init (GDataMediaCategoryClass *klass)
65 {
66 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
67 	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
68 
69 	g_type_class_add_private (klass, sizeof (GDataMediaCategoryPrivate));
70 
71 	gobject_class->get_property = gdata_media_category_get_property;
72 	gobject_class->set_property = gdata_media_category_set_property;
73 	gobject_class->finalize = gdata_media_category_finalize;
74 
75 	parsable_class->pre_parse_xml = pre_parse_xml;
76 	parsable_class->parse_xml = parse_xml;
77 	parsable_class->pre_get_xml = pre_get_xml;
78 	parsable_class->get_xml = get_xml;
79 	parsable_class->get_namespaces = get_namespaces;
80 	parsable_class->element_name = "category";
81 	parsable_class->element_namespace = "media";
82 
83 	/**
84 	 * GDataMediaCategory:category:
85 	 *
86 	 * The category name.
87 	 *
88 	 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
89 	 *
90 	 * Since: 0.4.0
91 	 */
92 	g_object_class_install_property (gobject_class, PROP_CATEGORY,
93 	                                 g_param_spec_string ("category",
94 	                                                      "Category", "The category name.",
95 	                                                      NULL,
96 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
97 
98 	/**
99 	 * GDataMediaCategory:scheme:
100 	 *
101 	 * A URI that identifies the categorization scheme.
102 	 *
103 	 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
104 	 *
105 	 * Since: 0.4.0
106 	 */
107 	g_object_class_install_property (gobject_class, PROP_SCHEME,
108 	                                 g_param_spec_string ("scheme",
109 	                                                      "Scheme", "A URI that identifies the categorization scheme.",
110 	                                                      NULL,
111 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112 
113 	/**
114 	 * GDataMediaCategory:label:
115 	 *
116 	 * A human-readable label that can be displayed in end-user applications.
117 	 *
118 	 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
119 	 *
120 	 * Since: 0.4.0
121 	 */
122 	g_object_class_install_property (gobject_class, PROP_LABEL,
123 	                                 g_param_spec_string ("label",
124 	                                                      "Label", "A human-readable label that can be displayed in end-user applications.",
125 	                                                      NULL,
126 	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127 }
128 
129 static void
gdata_media_category_init(GDataMediaCategory * self)130 gdata_media_category_init (GDataMediaCategory *self)
131 {
132 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_MEDIA_CATEGORY, GDataMediaCategoryPrivate);
133 }
134 
135 static void
gdata_media_category_finalize(GObject * object)136 gdata_media_category_finalize (GObject *object)
137 {
138 	GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (object)->priv;
139 
140 	g_free (priv->category);
141 	g_free (priv->scheme);
142 	g_free (priv->label);
143 
144 	/* Chain up to the parent class */
145 	G_OBJECT_CLASS (gdata_media_category_parent_class)->finalize (object);
146 }
147 
148 static void
gdata_media_category_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)149 gdata_media_category_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
150 {
151 	GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (object)->priv;
152 
153 	switch (property_id) {
154 		case PROP_CATEGORY:
155 			g_value_set_string (value, priv->category);
156 			break;
157 		case PROP_SCHEME:
158 			g_value_set_string (value, priv->scheme);
159 			break;
160 		case PROP_LABEL:
161 			g_value_set_string (value, priv->label);
162 			break;
163 		default:
164 			/* We don't have any other property... */
165 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
166 			break;
167 	}
168 }
169 
170 static void
gdata_media_category_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)171 gdata_media_category_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
172 {
173 	GDataMediaCategory *self = GDATA_MEDIA_CATEGORY (object);
174 
175 	switch (property_id) {
176 		case PROP_CATEGORY:
177 			gdata_media_category_set_category (self, g_value_get_string (value));
178 			break;
179 		case PROP_SCHEME:
180 			gdata_media_category_set_scheme (self, g_value_get_string (value));
181 			break;
182 		case PROP_LABEL:
183 			gdata_media_category_set_label (self, g_value_get_string (value));
184 			break;
185 		default:
186 			/* We don't have any other property... */
187 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
188 			break;
189 	}
190 }
191 
192 static gboolean
pre_parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * root_node,gpointer user_data,GError ** error)193 pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
194 {
195 	GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (parsable)->priv;
196 	xmlChar *category, *scheme;
197 
198 	category = xmlNodeListGetString (doc, root_node->children, TRUE);
199 	if (category == NULL || *category == '\0') {
200 		xmlFree (category);
201 		return gdata_parser_error_required_content_missing (root_node, error);
202 	}
203 
204 	scheme = xmlGetProp (root_node, (xmlChar*) "scheme");
205 	if (scheme != NULL && *scheme == '\0') {
206 		xmlFree (scheme);
207 		xmlFree (category);
208 		return gdata_parser_error_required_property_missing (root_node, "scheme", error);
209 	} else if (scheme == NULL) {
210 		/* Default */
211 		scheme = xmlStrdup ((xmlChar*) "http://video.search.yahoo.com/mrss/category_schema");
212 	}
213 
214 	priv->category = (gchar*) category;
215 	priv->scheme = (gchar*) scheme;
216 	priv->label = (gchar*) xmlGetProp (root_node, (xmlChar*) "label");
217 
218 	return TRUE;
219 }
220 
221 static gboolean
parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * node,gpointer user_data,GError ** error)222 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
223 {
224 	/* Textual content's handled in pre_parse_xml */
225 	if (node->type != XML_ELEMENT_NODE)
226 		return TRUE;
227 
228 	return GDATA_PARSABLE_CLASS (gdata_media_category_parent_class)->parse_xml (parsable, doc, node, user_data, error);
229 }
230 
231 static void
pre_get_xml(GDataParsable * parsable,GString * xml_string)232 pre_get_xml (GDataParsable *parsable, GString *xml_string)
233 {
234 	GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (parsable)->priv;
235 
236 	if (priv->scheme != NULL)
237 		gdata_parser_string_append_escaped (xml_string, " scheme='", priv->scheme, "'");
238 	if (priv->label != NULL)
239 		gdata_parser_string_append_escaped (xml_string, " label='", priv->label, "'");
240 }
241 
242 static void
get_xml(GDataParsable * parsable,GString * xml_string)243 get_xml (GDataParsable *parsable, GString *xml_string)
244 {
245 	gdata_parser_string_append_escaped (xml_string, NULL, GDATA_MEDIA_CATEGORY (parsable)->priv->category, NULL);
246 }
247 
248 static void
get_namespaces(GDataParsable * parsable,GHashTable * namespaces)249 get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
250 {
251 	g_hash_table_insert (namespaces, (gchar*) "media", (gchar*) "http://search.yahoo.com/mrss/");
252 }
253 
254 /**
255  * gdata_media_category_new:
256  * @category: a category describing the content
257  * @scheme: (allow-none): a URI identifying the categorisation scheme, or %NULL
258  * @label: (allow-none): a human-readable name for the category, or %NULL
259  *
260  * Creates a new #GDataMediaCategory. More information is available in the <ulink type="http"
261  * url="http://search.yahoo.com/mrss/">Media RSS specification</ulink>.
262  *
263  * Return value: a new #GDataMediaCategory, or %NULL; unref with g_object_unref()
264  */
265 GDataMediaCategory *
gdata_media_category_new(const gchar * category,const gchar * scheme,const gchar * label)266 gdata_media_category_new (const gchar *category, const gchar *scheme, const gchar *label)
267 {
268 	g_return_val_if_fail (category != NULL && *category != '\0', NULL);
269 	g_return_val_if_fail (scheme == NULL || *scheme != '\0', NULL);
270 	return g_object_new (GDATA_TYPE_MEDIA_CATEGORY, "category", category, "scheme", scheme, "label", label, NULL);
271 }
272 
273 /**
274  * gdata_media_category_get_category:
275  * @self: a #GDataMediaCategory
276  *
277  * Gets the #GDataMediaCategory:category property.
278  *
279  * Return value: the actual category
280  *
281  * Since: 0.4.0
282  */
283 const gchar *
gdata_media_category_get_category(GDataMediaCategory * self)284 gdata_media_category_get_category (GDataMediaCategory *self)
285 {
286 	g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
287 	return self->priv->category;
288 }
289 
290 /**
291  * gdata_media_category_set_category:
292  * @self: a #GDataMediaCategory
293  * @category: the new category
294  *
295  * Sets the #GDataMediaCategory:category property to @category.
296  *
297  * Since: 0.4.0
298  */
299 void
gdata_media_category_set_category(GDataMediaCategory * self,const gchar * category)300 gdata_media_category_set_category (GDataMediaCategory *self, const gchar *category)
301 {
302 	g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
303 	g_return_if_fail (category != NULL && *category != '\0');
304 
305 	g_free (self->priv->category);
306 	self->priv->category = g_strdup (category);
307 	g_object_notify (G_OBJECT (self), "category");
308 }
309 
310 /**
311  * gdata_media_category_get_scheme:
312  * @self: a #GDataMediaCategory
313  *
314  * Gets the #GDataMediaCategory:scheme property.
315  *
316  * Return value: the category's scheme, or %NULL
317  *
318  * Since: 0.4.0
319  */
320 const gchar *
gdata_media_category_get_scheme(GDataMediaCategory * self)321 gdata_media_category_get_scheme (GDataMediaCategory *self)
322 {
323 	g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
324 	return self->priv->scheme;
325 }
326 
327 /**
328  * gdata_media_category_set_scheme:
329  * @self: a #GDataMediaCategory
330  * @scheme: (allow-none): the category's new scheme, or %NULL
331  *
332  * Sets the #GDataMediaCategory:scheme property to @scheme.
333  *
334  * Set @scheme to %NULL to unset the property.
335  *
336  * Since: 0.4.0
337  */
338 void
gdata_media_category_set_scheme(GDataMediaCategory * self,const gchar * scheme)339 gdata_media_category_set_scheme (GDataMediaCategory *self, const gchar *scheme)
340 {
341 	g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
342 	g_return_if_fail (scheme == NULL || *scheme != '\0');
343 
344 	if (scheme == NULL)
345 		scheme = "http://video.search.yahoo.com/mrss/category_schema";
346 
347 	g_free (self->priv->scheme);
348 	self->priv->scheme = g_strdup (scheme);
349 	g_object_notify (G_OBJECT (self), "scheme");
350 }
351 
352 /**
353  * gdata_media_category_get_label:
354  * @self: a #GDataMediaCategory
355  *
356  * Gets the #GDataMediaCategory:label property.
357  *
358  * Return value: the category's label, or %NULL
359  *
360  * Since: 0.4.0
361  */
362 const gchar *
gdata_media_category_get_label(GDataMediaCategory * self)363 gdata_media_category_get_label (GDataMediaCategory *self)
364 {
365 	g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
366 	return self->priv->label;
367 }
368 
369 /**
370  * gdata_media_category_set_label:
371  * @self: a #GDataMediaCategory
372  * @label: (allow-none): the category's new label, or %NULL
373  *
374  * Sets the #GDataMediaCategory:label property to @label.
375  *
376  * Set @label to %NULL to unset the property.
377  *
378  * Since: 0.4.0
379  */
380 void
gdata_media_category_set_label(GDataMediaCategory * self,const gchar * label)381 gdata_media_category_set_label (GDataMediaCategory *self, const gchar *label)
382 {
383 	g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
384 
385 	g_free (self->priv->label);
386 	self->priv->label = g_strdup (label);
387 	g_object_notify (G_OBJECT (self), "label");
388 }
389