<commit_before>/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * GData Client
 * Copyright (C) <NAME> 2009–2010 <<EMAIL>>
 *
 * GData Client is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * GData Client 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * SECTION:gdata-media-group
 * @short_description: Media RSS group element
 * @stability: Stable
 * @include: gdata/media/gdata-media-group.h
 *
 * #GDataMediaGroup represents a "group" element from the
 * <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
 *
 * It is private API, since implementing classes are likely to proxy the properties and functions
 * of #GDataMediaGroup as appropriate; most entry types which implement #GDataMediaGroup have no use
 * for most of its properties, and it would be unnecessary and confusing to expose #GDataMediaGroup itself.
 *
 * For this reason, properties have not been implemented on #GDataMediaGroup (yet).
 */

#include <glib.h>
#include <libxml/parser.h>
#include <string.h>

#include "gdata-media-group.h"
#include "gdata-parsable.h"
#include "gdata-parser.h"
#include "gdata-private.h"
#include "media/gdata-media-category.h"
#include "media/gdata-media-credit.h"
#include "media/gdata-media-thumbnail.h"

static void gdata_media_group_dispose (GObject *object);
static void gdata_media_group_finalize (GObject *object);
static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
static void get_xml (GDataParsable *parsable, GString *xml_string);
static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);

struct _GDataMediaGroupPrivate {
	gchar **keywords;
	gchar *player_uri;
	GHashTable *restricted_countries;
	gchar *simple_rating;
	gchar *mpaa_rating;
	gchar *v_chip_rating;
	GList *thumbnails; /* GDataMediaThumbnail */
	gchar *title;
	GDataMediaCategory *category;
	GList *contents; /* GDataMediaContent */
	GDataMediaCredit *credit;
	gchar *description;
};

G_DEFINE_TYPE (GDataMediaGroup, gdata_media_group, GDATA_TYPE_PARSABLE)

static void
gdata_media_group_class_init (GDataMediaGroupClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);

	g_type_class_add_private (klass, sizeof (GDataMediaGroupPrivate));

	gobject_class->dispose = gdata_media_group_dispose;
	gobject_class->finalize = gdata_media_group_finalize;

	parsable_class->parse_xml = parse_xml;
	parsable_class->get_xml = get_xml;
	parsable_class->get_namespaces = get_namespaces;
	parsable_class->element_name = "group";
	parsable_class->element_namespace = "media";
}

static void
gdata_media_group_init (GDataMediaGroup *self)
{
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_MEDIA_GROUP, GDataMediaGroupPrivate);
	self->priv->restricted_countries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}

static void
gdata_media_group_dispose (GObject *object)
{
	GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;

	if (priv->category != NULL)
		g_object_unref (priv->category);
	priv->category = NULL;

	if (priv->credit != NULL)
		g_object_unref (priv->credit);
	priv->credit = NULL;

	g_list_free_full (priv->contents, g_object_unref);
	priv->contents = NULL;

	g_list_free_full (priv->thumbnails, g_object_unref);
	priv->thumbnails = NULL;

	/* Chain up to the parent class */
	G_OBJECT_CLASS (gdata_media_group_parent_class)->dispose (object);
}

static void
gdata_media_group_finalize (GObject *object)
{
	GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;

	g_strfreev (priv->keywords);
	g_free (priv->player_uri);
	g_free (priv->v_chip_rating);
	g_free (priv->mpaa_rating);
	g_free (priv->simple_rating);
	g_hash_table_destroy (priv->restricted_countries);
	g_free (priv->title);
	g_free (priv->description);

	/* Chain up to the parent class */
	G_OBJECT_CLASS (gdata_media_group_parent_class)->finalize (object);
}

static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
	gboolean success;
	GDataMediaGroup *self = GDATA_MEDIA_GROUP (parsable);

	if (gdata_parser_is_namespace (node, "http://search.yahoo.com/mrss/") == TRUE) {
		if (gdata_parser_string_from_element (node, "title", P_NONE, &(self->priv->title), &success, error) == TRUE ||
		    gdata_parser_string_from_element (node, "description", P_NONE, &(self->priv->description), &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_MEDIA_CATEGORY,
		                                             gdata_media_group_set_category, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "content", P_REQUIRED, GDATA_TYPE_MEDIA_CONTENT,
		                                             _gdata_media_group_add_content, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "thumbnail", P_REQUIRED, GDATA_TYPE_MEDIA_THUMBNAIL,
		                                             _gdata_media_group_add_thumbnail, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element (node, "credit", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_MEDIA_CREDIT,
		                                      &(self->priv->credit), &success, error) == TRUE) {
			return success;
		} else if (xmlStrcmp (node->name, (xmlChar*) "keywords") == 0) {
			/* media:keywords */
			guint i;
			xmlChar *text = xmlNodeListGetString (node->doc, node->children, TRUE);

			g_strfreev (self->priv->keywords);
			if (text == NULL) {
				self->priv->keywords = NULL;
				return TRUE;
			}

			self->priv->keywords = g_strsplit ((gchar*) text, ",", -1);
			xmlFree (text);

			for (i = 0; self->priv->keywords[i] != NULL; i++) {
				gchar *comma, *start = self->priv->keywords[i];
				gchar *end = start + strlen (start);

				/* Strip any whitespace from the ends of the keyword */
				g_strstrip (start);

				/* Unescape any %2Cs in the keyword to commas in-place */
				while ((comma = g_strstr_len (start, -1, "%2C")) != NULL) {
					/* Unescape the comma */
					*comma = ',';

					/* Move forwards, skipping the comma */
					comma++;
					end -= 2;

					/* Shift the remainder of the string downwards */
					g_memmove (comma, comma + 2, end - comma);
					*end = '\0';
				}
			}
		} else if (xmlStrcmp (node->name, (xmlChar*) "player") == 0) {
			/* media:player */
			xmlChar *player_uri = xmlGetProp (node, (xmlChar*) "url");
			g_free (self->priv->player_uri);
			self->priv->player_uri = (gchar*) player_uri;
		} else if (xmlStrcmp (node->name, (xmlChar*) "rating") == 0) {
			/* media:rating */
			xmlChar *scheme;

			/* The possible schemes are defined here:
			 *  • http://video.search.yahoo.com/mrss
			 *  • http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating
			 */
			scheme = xmlGetProp (node, (xmlChar*) "scheme");

			if (scheme == NULL || xmlStrcmp (scheme, (xmlChar*) "urn:simple") == 0) {
				/* Options: adult, nonadult */<commit_msg>media: Use memmove() instead of deprecated g_memmove()<commit_after>/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * GData Client
 * Copyright (C) <NAME> 2009–2010 <<EMAIL>>
 *
 * GData Client is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * GData Client 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * SECTION:gdata-media-group
 * @short_description: Media RSS group element
 * @stability: Stable
 * @include: gdata/media/gdata-media-group.h
 *
 * #GDataMediaGroup represents a "group" element from the
 * <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
 *
 * It is private API, since implementing classes are likely to proxy the properties and functions
 * of #GDataMediaGroup as appropriate; most entry types which implement #GDataMediaGroup have no use
 * for most of its properties, and it would be unnecessary and confusing to expose #GDataMediaGroup itself.
 *
 * For this reason, properties have not been implemented on #GDataMediaGroup (yet).
 */

#include <glib.h>
#include <libxml/parser.h>
#include <string.h>

#include "gdata-media-group.h"
#include "gdata-parsable.h"
#include "gdata-parser.h"
#include "gdata-private.h"
#include "media/gdata-media-category.h"
#include "media/gdata-media-credit.h"
#include "media/gdata-media-thumbnail.h"

static void gdata_media_group_dispose (GObject *object);
static void gdata_media_group_finalize (GObject *object);
static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
static void get_xml (GDataParsable *parsable, GString *xml_string);
static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);

struct _GDataMediaGroupPrivate {
	gchar **keywords;
	gchar *player_uri;
	GHashTable *restricted_countries;
	gchar *simple_rating;
	gchar *mpaa_rating;
	gchar *v_chip_rating;
	GList *thumbnails; /* GDataMediaThumbnail */
	gchar *title;
	GDataMediaCategory *category;
	GList *contents; /* GDataMediaContent */
	GDataMediaCredit *credit;
	gchar *description;
};

G_DEFINE_TYPE (GDataMediaGroup, gdata_media_group, GDATA_TYPE_PARSABLE)

static void
gdata_media_group_class_init (GDataMediaGroupClass *klass)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);

	g_type_class_add_private (klass, sizeof (GDataMediaGroupPrivate));

	gobject_class->dispose = gdata_media_group_dispose;
	gobject_class->finalize = gdata_media_group_finalize;

	parsable_class->parse_xml = parse_xml;
	parsable_class->get_xml = get_xml;
	parsable_class->get_namespaces = get_namespaces;
	parsable_class->element_name = "group";
	parsable_class->element_namespace = "media";
}

static void
gdata_media_group_init (GDataMediaGroup *self)
{
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_MEDIA_GROUP, GDataMediaGroupPrivate);
	self->priv->restricted_countries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}

static void
gdata_media_group_dispose (GObject *object)
{
	GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;

	if (priv->category != NULL)
		g_object_unref (priv->category);
	priv->category = NULL;

	if (priv->credit != NULL)
		g_object_unref (priv->credit);
	priv->credit = NULL;

	g_list_free_full (priv->contents, g_object_unref);
	priv->contents = NULL;

	g_list_free_full (priv->thumbnails, g_object_unref);
	priv->thumbnails = NULL;

	/* Chain up to the parent class */
	G_OBJECT_CLASS (gdata_media_group_parent_class)->dispose (object);
}

static void
gdata_media_group_finalize (GObject *object)
{
	GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;

	g_strfreev (priv->keywords);
	g_free (priv->player_uri);
	g_free (priv->v_chip_rating);
	g_free (priv->mpaa_rating);
	g_free (priv->simple_rating);
	g_hash_table_destroy (priv->restricted_countries);
	g_free (priv->title);
	g_free (priv->description);

	/* Chain up to the parent class */
	G_OBJECT_CLASS (gdata_media_group_parent_class)->finalize (object);
}

static gboolean
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
{
	gboolean success;
	GDataMediaGroup *self = GDATA_MEDIA_GROUP (parsable);

	if (gdata_parser_is_namespace (node, "http://search.yahoo.com/mrss/") == TRUE) {
		if (gdata_parser_string_from_element (node, "title", P_NONE, &(self->priv->title), &success, error) == TRUE ||
		    gdata_parser_string_from_element (node, "description", P_NONE, &(self->priv->description), &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_MEDIA_CATEGORY,
		                                             gdata_media_group_set_category, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "content", P_REQUIRED, GDATA_TYPE_MEDIA_CONTENT,
		                                             _gdata_media_group_add_content, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element_setter (node, "thumbnail", P_REQUIRED, GDATA_TYPE_MEDIA_THUMBNAIL,
		                                             _gdata_media_group_add_thumbnail, self, &success, error) == TRUE ||
		    gdata_parser_object_from_element (node, "credit", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_MEDIA_CREDIT,
		                                      &(self->priv->credit), &success, error) == TRUE) {
			return success;
		} else if (xmlStrcmp (node->name, (xmlChar*) "keywords") == 0) {
			/* media:keywords */
			guint i;
			xmlChar *text = xmlNodeListGetString (node->doc, node->children, TRUE);

			g_strfreev (self->priv->keywords);
			if (text == NULL) {
				self->priv->keywords = NULL;
				return TRUE;
			}

			self->priv->keywords = g_strsplit ((gchar*) text, ",", -1);
			xmlFree (text);

			for (i = 0; self->priv->keywords[i] != NULL; i++) {
				gchar *comma, *start = self->priv->keywords[i];
				gchar *end = start + strlen (start);

				/* Strip any whitespace from the ends of the keyword */
				g_strstrip (start);

				/* Unescape any %2Cs in the keyword to commas in-place */
				while ((comma = g_strstr_len (start, -1, "%2C")) != NULL) {
					/* Unescape the comma */
					*comma = ',';

					/* Move forwards, skipping the comma */
					comma++;
					end -= 2;

					/* Shift the remainder of the string downwards */
					memmove (comma, comma + 2, end - comma);
					*end = '\0';
				}
			}
		} else if (xmlStrcmp (node->name, (xmlChar*) "player") == 0) {
			/* media:player */
			xmlChar *player_uri = xmlGetProp (node, (xmlChar*) "url");
			g_free (self->priv->player_uri);
			self->priv->player_uri = (gchar*) player_uri;
		} else if (xmlStrcmp (node->name, (xmlChar*) "rating") == 0) {
			/* media:rating */
			xmlChar *scheme;

			/* The possible schemes are defined here:
			 *  • http://video.search.yahoo.com/mrss
			 *  • http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating
			 */
			scheme = xmlGetProp (node, (xmlChar*) "scheme");

			if (scheme == NULL || xmlStrcmp (scheme, (xmlChar*) "urn:simple") == 0) {
				/* Options: adult, nonadult */
{'fraction_non_alphanumeric': 0.12321253672869735, 'fraction_numerical': 0.003395364022200457, 'mean_word_length': 4.204213387699626, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 60}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6177885', 'n_tokens_mistral': 5463, 'n_tokens_neox': 5065, 'n_words': 1298}