summaryrefslogtreecommitdiff
path: root/gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c')
-rw-r--r--gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c b/gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c
new file mode 100644
index 00000000..183195e7
--- /dev/null
+++ b/gnome-2-24/daemon/gvfsbackendobexftp-cap-parser.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2004-2005 Nokia Corporation.
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
+ *
+ * This program 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; version 2 of the
+ * License.
+ *
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <expat.h>
+
+#include "gvfsbackendobexftp-cap-parser.h"
+
+#define d(x)
+
+struct _OvuCaps {
+ GList *memory_entries;
+
+ /* FIXME: Add "Services" and "Inbox" data here later. */
+};
+
+struct _OvuCapsMemory {
+ gchar *type;
+ goffset free;
+ goffset used;
+ guint has_free : 1;
+ guint has_used : 1;
+ guint case_sensitive : 1;
+};
+
+typedef enum {
+ PARSER_STATE_INVALID,
+
+ PARSER_STATE_START,
+ PARSER_STATE_CAPABILITY,
+
+ PARSER_STATE_GENERAL,
+
+ PARSER_STATE_MEMORY,
+ PARSER_STATE_MEMORY_TYPE,
+ PARSER_STATE_MEMORY_LOCATION,
+ PARSER_STATE_MEMORY_FREE,
+ PARSER_STATE_MEMORY_USED,
+ PARSER_STATE_MEMORY_SHARED,
+ PARSER_STATE_MEMORY_FILESIZE,
+ PARSER_STATE_MEMORY_FOLDERSIZE,
+ PARSER_STATE_MEMORY_FILELEN,
+ PARSER_STATE_MEMORY_FOLDERLEN,
+ PARSER_STATE_MEMORY_CASE,
+ PARSER_STATE_MEMORY_EXT,
+
+ PARSER_STATE_INBOX,
+ PARSER_STATE_SERVICE,
+
+ PARSER_STATE_SKIP
+} ParserState;
+
+
+typedef struct {
+ GList *state;
+
+ GList *memory_entries;
+
+ gchar *memory_type;
+ goffset memory_free;
+ goffset memory_used;
+ gboolean memory_has_free;
+ gboolean memory_has_used;
+ gboolean memory_case_sensitive;
+
+ GError **error;
+} ParserData;
+
+static void cap_parser_start_node_cb (void *user_data,
+ const char *node_name,
+ const char **attr);
+
+static void cap_parser_end_node_cb (void *user_data,
+ const char *node_name);
+static void cap_parser_text_cb (void *user_data,
+ const XML_Char *s,
+ int len);
+static XML_Parser
+cap_parser_create_parser (ParserData *data);
+
+
+static void
+cap_parser_push_state (ParserData *data, ParserState state)
+{
+ data->state = g_list_prepend (data->state,
+ GINT_TO_POINTER (state));
+}
+
+static ParserState
+cap_parser_pop_state (ParserData *data)
+{
+ ParserState state;
+
+ if (!data->state) {
+ return PARSER_STATE_INVALID;
+ }
+
+ state = GPOINTER_TO_INT (data->state->data);
+ data->state = g_list_delete_link (data->state, data->state);
+
+ return state;
+}
+
+static ParserState
+cap_parser_peek_state (ParserData *data)
+{
+ if (!data->state) {
+ return PARSER_STATE_START;
+ }
+
+ return GPOINTER_TO_INT (data->state->data);
+}
+
+static const char *
+cap_parser_get_attribute_value (const char *name, const char **attr)
+{
+ gint i = 0;
+
+ while (attr[i]) {
+ if (strcmp (name, attr[i]) == 0) {
+ return attr[i + 1];
+ }
+ i += 2;
+ }
+
+ return "";
+}
+
+static void
+cap_parser_start_node_cb (void *user_data,
+ const char *node_name,
+ const char **attr)
+{
+ ParserData *data;
+ ParserState state;
+ const gchar *version;
+
+ data = (ParserData *) user_data;
+
+ state = cap_parser_peek_state (data);
+
+ switch (state) {
+ case PARSER_STATE_START:
+ if (strcmp (node_name, "Capability") != 0) {
+ g_set_error (data->error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Outermost element must be a <Capability>, not <%s>",
+ node_name);
+ return;
+ }
+
+ version = cap_parser_get_attribute_value ("version", attr);
+ /* Assume an empty version is fine */
+ if (strcmp (version, "1.0") != 0 && version[0] != '\0') {
+ g_warning ("Version expected is '1.0', not '%s'\n", version);
+ }
+
+ cap_parser_push_state (data, PARSER_STATE_CAPABILITY);
+ break;
+
+ case PARSER_STATE_CAPABILITY:
+ if (strcmp (node_name, "General") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_GENERAL);
+ }
+ else if (strcmp (node_name, "Inbox") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_INBOX);
+ }
+ else if (strcmp (node_name, "Service") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_SERVICE);
+ } else {
+ g_set_error (data->error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Don't expect node '%s' as child of 'Cap'",
+ node_name);
+ return;
+ }
+ break;
+
+ case PARSER_STATE_GENERAL:
+ if (strcmp (node_name, "Memory") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY);
+ }
+ else if (strcmp (node_name, "Manufacturer") == 0 ||
+ strcmp (node_name, "Model") == 0 ||
+ strcmp (node_name, "SN") == 0 ||
+ strcmp (node_name, "OEM") == 0 ||
+ strcmp (node_name, "SW") == 0 ||
+ strcmp (node_name, "FW") == 0 ||
+ strcmp (node_name, "HW") == 0 ||
+ strcmp (node_name, "Language") == 0 ||
+ strcmp (node_name, "Ext") == 0) {
+
+ /* Skip these for now. */
+ cap_parser_push_state (data, PARSER_STATE_SKIP);
+ } else {
+ g_set_error (data->error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Don't expect node '%s' as child of 'General'",
+ node_name);
+ return;
+ }
+
+ break;
+
+ case PARSER_STATE_MEMORY:
+ if (strcmp (node_name, "MemType") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_TYPE);
+ }
+ else if (strcmp (node_name, "Location") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_LOCATION);
+ }
+ else if (strcmp (node_name, "Free") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_FREE);
+ }
+ else if (strcmp (node_name, "Used") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_USED);
+ }
+ else if (strcmp (node_name, "Shared") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_SHARED);
+ }
+ else if (strcmp (node_name, "FileSize") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_FILESIZE);
+ }
+ else if (strcmp (node_name, "FolderSize") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_FOLDERSIZE);
+ }
+ else if (strcmp (node_name, "FileNLen") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_FILELEN);
+ }
+ else if (strcmp (node_name, "FolderNLen") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_FOLDERLEN);
+ }
+ else if (strcmp (node_name, "CaseSenN") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_CASE);
+ data->memory_case_sensitive = TRUE;
+ }
+ else if (strcmp (node_name, "Ext") == 0) {
+ cap_parser_push_state (data, PARSER_STATE_MEMORY_EXT);
+ } else {
+ g_set_error (data->error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Don't expect node '%s' as child of 'Memory'",
+ node_name);
+ return;
+ }
+ break;
+
+ case PARSER_STATE_INBOX:
+ case PARSER_STATE_SERVICE:
+ /* Skip these for now. */
+ cap_parser_push_state (data, PARSER_STATE_SKIP);
+ break;
+
+ case PARSER_STATE_SKIP:
+ cap_parser_push_state (data, PARSER_STATE_SKIP);
+ break;
+
+ default:
+ g_warning ("Node not handled: '%s'\n", node_name);
+ cap_parser_push_state (data, PARSER_STATE_SKIP);
+ break;
+ }
+}
+
+static void
+cap_parser_reset_memory (ParserData *data)
+{
+ g_free (data->memory_type);
+ data->memory_type = NULL;
+ data->memory_free = 0;
+ data->memory_used = 0;
+ data->memory_has_free = FALSE;
+ data->memory_has_used = FALSE;
+ data->memory_case_sensitive = FALSE;
+}
+
+static void
+cap_parser_end_node_cb (void *user_data, const char *node_name)
+{
+ ParserData *data;
+ ParserState state;
+ OvuCapsMemory *memory;
+
+ data = (ParserData *) user_data;
+
+ state = cap_parser_pop_state (data);
+
+ switch (state) {
+ case PARSER_STATE_INVALID:
+ return;
+
+ case PARSER_STATE_MEMORY:
+ memory = ovu_caps_memory_new (data->memory_type,
+ data->memory_free,
+ data->memory_used,
+ data->memory_has_free,
+ data->memory_has_used,
+ data->memory_case_sensitive);
+
+ data->memory_entries = g_list_prepend (data->memory_entries,
+ memory);
+ cap_parser_reset_memory (data);
+ break;
+
+ case PARSER_STATE_CAPABILITY:
+ data->memory_entries = g_list_reverse (data->memory_entries);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Parse a long, return -1 if input is not strictly valid or null. */
+static goffset
+parse_long (const gchar *str, gboolean *success)
+{
+ gchar *endptr;
+ glong l;
+
+ *success = TRUE;
+
+ if (!str) {
+ *success = FALSE;
+ return 0;
+ }
+
+ l = strtol (str, &endptr, 10);
+ if (endptr[0] != '\0' || l < 0) {
+ *success = FALSE;
+ l = 0;
+ }
+
+ return l;
+}
+
+static void
+cap_parser_text_cb (void *user_data,
+ const XML_Char *s,
+ int len)
+{
+ ParserData *data;
+ ParserState state;
+ gchar *tmp;
+
+ data = (ParserData *) user_data;
+
+ /* text is not null terminated. */
+ tmp = g_strndup (s, len);
+
+ state = cap_parser_peek_state (data);
+
+ switch (state) {
+ case PARSER_STATE_MEMORY_TYPE:
+ data->memory_type = g_strdup (tmp);
+ break;
+ case PARSER_STATE_MEMORY_FREE:
+ data->memory_free = parse_long (tmp, &data->memory_has_free);
+ break;
+ case PARSER_STATE_MEMORY_USED:
+ data->memory_used = parse_long (tmp, &data->memory_has_used);
+ break;
+
+ default:
+ break;
+ }
+
+ g_free (tmp);
+}
+
+static XML_Parser
+cap_parser_create_parser (ParserData *data)
+{
+ XML_Parser parser;
+
+ parser = XML_ParserCreate (NULL);
+
+ XML_SetElementHandler (parser,
+ cap_parser_start_node_cb,
+ cap_parser_end_node_cb);
+
+ XML_SetCharacterDataHandler (parser, cap_parser_text_cb);
+
+ XML_SetUserData (parser, data);
+
+ return parser;
+}
+
+static void
+cap_parser_free (ParserData *data, gboolean free_data)
+{
+ cap_parser_reset_memory (data);
+
+ if (free_data) {
+ g_list_foreach (data->memory_entries,
+ (GFunc) ovu_caps_memory_free, NULL);
+ }
+
+ g_free (data);
+}
+
+OvuCaps *
+ovu_caps_parser_parse (const gchar *buf,
+ gint len,
+ GError **error)
+{
+ ParserData *data;
+ XML_Parser parser;
+ OvuCaps *caps;
+
+ data = g_new0 (ParserData, 1);
+
+ data->error = error;
+ parser = cap_parser_create_parser (data);
+
+ if (XML_Parse (parser, buf, len, TRUE) == 0) {
+ caps = NULL;
+
+ if (*error == NULL) {
+ g_set_error_literal (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Couldn't parse the incoming data");
+ }
+
+ cap_parser_free (data, TRUE);
+ } else {
+ caps = g_new0 (OvuCaps, 1);
+ caps->memory_entries = data->memory_entries;
+
+ cap_parser_free (data, FALSE);
+ }
+
+ XML_ParserFree (parser);
+
+ return caps;
+}
+
+OvuCapsMemory *
+ovu_caps_memory_new (const gchar *type,
+ goffset free,
+ goffset used,
+ gboolean has_free,
+ gboolean has_used,
+ gboolean case_sensitive)
+{
+ OvuCapsMemory *memory;
+
+ memory = g_new0 (OvuCapsMemory, 1);
+
+ memory->type = g_strdup (type);
+ memory->free = free;
+ memory->used = used;
+ memory->has_free = has_free;
+ memory->has_used = has_used;
+ memory->case_sensitive = case_sensitive;
+
+ return memory;
+}
+
+void
+ovu_caps_memory_free (OvuCapsMemory *memory)
+{
+ g_free (memory->type);
+ g_free (memory);
+}
+
+gboolean
+ovu_caps_memory_equal (OvuCapsMemory *m1, OvuCapsMemory *m2)
+{
+ if (strcmp (m1->type, m2->type) != 0) {
+ d(g_print ("type mismatch: %s %s\n",
+ m1->type, m2->type));
+ return FALSE;
+ }
+
+ if (m1->free != m2->free) {
+ d(g_print ("free mismatch: %d %d\n",
+ (int) m1->free, (int) m2->free));
+ return FALSE;
+ }
+
+ if (m1->used != m2->used) {
+ d(g_print ("used mismatch: %d %d\n",
+ (int) m1->used, (int) m2->used));
+ return FALSE;
+ }
+
+ if (m1->case_sensitive != m2->case_sensitive) {
+ d(g_print ("case mismatch: %d %d\n",
+ m1->case_sensitive,
+ m2->case_sensitive));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+ovu_caps_free (OvuCaps *caps)
+{
+ g_list_foreach (caps->memory_entries,
+ (GFunc) ovu_caps_memory_free, NULL);
+
+ g_list_free (caps->memory_entries);
+
+ g_free (caps);
+}
+
+GList *
+ovu_caps_get_memory_entries (OvuCaps *caps)
+{
+ g_return_val_if_fail (caps != NULL, NULL);
+
+ return caps->memory_entries;
+}
+
+OvuCapsMemory *
+ovu_caps_get_memory_type (OvuCaps *caps,
+ const gchar *mem_type)
+{
+ GList *tmp;
+
+ g_return_val_if_fail (caps != NULL, NULL);
+
+ for (tmp = caps->memory_entries; tmp != NULL; tmp = tmp->next) {
+ OvuCapsMemory *memory = tmp->data;
+
+ /* treat a NULL memory type as matching anything */
+ if (mem_type == NULL || (memory->type != NULL &&
+ !strcmp(mem_type, memory->type)))
+ return memory;
+ }
+ return NULL;
+}
+
+const gchar *
+ovu_caps_memory_get_type (OvuCapsMemory *memory)
+{
+ return memory->type;
+}
+
+goffset
+ovu_caps_memory_get_used (OvuCapsMemory *memory)
+{
+ return memory->used;
+}
+
+goffset
+ovu_caps_memory_get_free (OvuCapsMemory *memory)
+{
+ return memory->free;
+}
+
+gboolean
+ovu_caps_memory_has_used (OvuCapsMemory *memory)
+{
+ return memory->has_used;
+}
+
+gboolean
+ovu_caps_memory_has_free (OvuCapsMemory *memory)
+{
+ return memory->has_free;
+}
+
+gboolean
+ovu_caps_memory_get_case_sensitive (OvuCapsMemory *memory)
+{
+ return memory->case_sensitive;
+}