WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / gtk / src / appcast.c
blob43e45b6a99979536acdd0d3f96efb94c1f38376a
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * appcast.c
4 * Copyright (C) John Stebbins 2008-2015 <stebbins@stebbins>
6 * appcast.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
14 #include <stdio.h>
15 #include <string.h>
16 #include <glib.h>
17 #include <glib/gstdio.h>
18 #include "plist.h"
19 #include "values.h"
21 enum
23 A_NONE = 0,
24 A_DESCRIPTION,
25 A_ENCLOSURE,
26 A_ITEM,
29 typedef struct
31 gchar *tag;
32 gint id;
33 } tag_map_t;
35 static tag_map_t tag_map[] =
37 {"sparkle:releaseNotesLink", A_DESCRIPTION},
38 {"enclosure", A_ENCLOSURE},
39 {"item", A_ITEM},
41 #define TAG_MAP_SZ (sizeof(tag_map)/sizeof(tag_map_t))
43 typedef struct
45 gchar *key;
46 gchar *value;
47 GQueue *stack;
48 GQueue *tag_stack;
49 GString *description;
50 gchar *build;
51 gchar *version;
52 gboolean item;
53 } parse_data_t;
55 static const gchar*
56 lookup_attr_value(
57 const gchar *name,
58 const gchar **attr_names,
59 const gchar **attr_values)
61 gint ii;
63 if (attr_names == NULL) return NULL;
64 for (ii = 0; attr_names[ii] != NULL; ii++)
66 if (strcmp(name, attr_names[ii]) == 0)
67 return attr_values[ii];
69 return NULL;
72 static void
73 start_element(
74 GMarkupParseContext *ctx,
75 const gchar *tag,
76 const gchar **attr_names,
77 const gchar **attr_values,
78 gpointer ud,
79 GError **error)
81 parse_data_t *pd = (parse_data_t*)ud;
82 union
84 gint id;
85 gpointer pid;
86 } id;
87 gint ii;
89 for (ii = 0; ii < TAG_MAP_SZ; ii++)
91 if (strcmp(tag, tag_map[ii].tag) == 0)
93 id.id = tag_map[ii].id;
94 break;
97 if (ii == TAG_MAP_SZ)
99 g_debug("Unrecognized start tag (%s)", tag);
100 id.id = A_NONE;
102 g_queue_push_head(pd->tag_stack, id.pid);
103 switch (id.id)
105 case A_ITEM:
107 pd->item = TRUE;
108 } break;
109 case A_ENCLOSURE:
111 const gchar *build, *version;
112 build = lookup_attr_value(
113 "sparkle:version", attr_names, attr_values);
114 version = lookup_attr_value(
115 "sparkle:shortVersionString", attr_names, attr_values);
116 if (build)
117 pd->build = g_strdup(build);
118 if (version)
119 pd->version = g_strdup(version);
120 } break;
124 static void
125 end_element(
126 GMarkupParseContext *ctx,
127 const gchar *tag,
128 gpointer ud,
129 GError **error)
131 parse_data_t *pd = (parse_data_t*)ud;
132 gint id;
133 union
135 gint id;
136 gpointer pid;
137 } start_id;
138 gint ii;
140 for (ii = 0; ii < TAG_MAP_SZ; ii++)
142 if (strcmp(tag, tag_map[ii].tag) == 0)
144 id = tag_map[ii].id;
145 break;
148 if (ii == TAG_MAP_SZ)
150 g_debug("Unrecognized end tag (%s)", tag);
151 id = A_NONE;
153 start_id.pid = g_queue_pop_head(pd->tag_stack);
154 if (start_id.id != id)
155 g_warning("start tag != end tag: (%s %d) %d", tag, start_id.id, id);
156 switch (id)
158 case A_ITEM:
160 pd->item = FALSE;
161 } break;
162 default:
164 } break;
169 static void
170 text_data(
171 GMarkupParseContext *ctx,
172 const gchar *text,
173 gsize len,
174 gpointer ud,
175 GError **error)
177 parse_data_t *pd = (parse_data_t*)ud;
178 union
180 gint id;
181 gpointer pid;
182 } start_id;
184 start_id.pid = g_queue_peek_head(pd->tag_stack);
185 switch (start_id.id)
187 case A_DESCRIPTION:
189 if (pd->item)
191 g_string_append(pd->description, text);
193 } break;
194 default:
196 if (pd->value) g_free(pd->value);
197 pd->value = g_strdup(text);
198 } break;
202 static void
203 passthrough(
204 GMarkupParseContext *ctx,
205 const gchar *text,
206 gsize len,
207 gpointer ud,
208 GError **error)
210 //parse_data_t *pd = (parse_data_t*)ud;
212 //g_debug("passthrough %s", text);
215 static void
216 parse_error(GMarkupParseContext *ctx, GError *error, gpointer ud)
218 g_warning("Resource parse error: %s", error->message);
221 // This is required or the parser crashes
222 static void
223 destroy_notify(gpointer data)
224 { // Do nothing
225 //g_debug("destroy parser");
228 void
229 ghb_appcast_parse(gchar *buf, gchar **desc, gchar **build, gchar **version)
231 GMarkupParseContext *ctx;
232 GMarkupParser parser;
233 parse_data_t pd;
234 GError *err = NULL;
235 gint len;
236 gchar *start;
237 //gchar tmp[4096]
239 // Skip junk at beginning of buffer
240 start = strstr(buf, "<?xml ");
241 pd.description = g_string_new("");
242 pd.item = FALSE;
243 pd.build = NULL;
244 pd.version = NULL;
245 len = strlen(start);
246 pd.tag_stack = g_queue_new();
247 pd.key = NULL;
248 pd.value = NULL;
250 parser.start_element = start_element;
251 parser.end_element = end_element;
252 parser.text = text_data;
253 parser.passthrough = passthrough;
254 parser.error = parse_error;
255 ctx = g_markup_parse_context_new(
256 &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &pd, destroy_notify);
258 g_markup_parse_context_parse(ctx, start, len, &err);
259 g_markup_parse_context_end_parse(ctx, &err);
260 g_markup_parse_context_free(ctx);
261 g_queue_free(pd.tag_stack);
262 *desc = g_string_free(pd.description, FALSE);
263 // work around a bug to leaves the CDATA closing brakets on the string
264 gchar *glitch;
265 glitch = g_strrstr(*desc, "]]>");
266 if (glitch)
267 *glitch = 0;
268 *build = pd.build;
269 *version = pd.version;