OSDN Git Service

import 0.9.3
[handbrake-jp/handbrake-jp.git] / gtk / src / appcast.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * appcast.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * appcast.c is free software.
7  * 
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.
12  */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <glib.h>
17 #include <glib/gstdio.h>
18 #include "icon_tools.h"
19 #include "plist.h"
20 #include "values.h"
21
22 enum
23 {
24         A_NONE = 0,
25         A_DESCRIPTION,
26         A_ENCLOSURE,
27         A_ITEM,
28 };
29
30 typedef struct
31 {
32         gchar *tag;
33         gint id;
34 } tag_map_t;
35
36 static tag_map_t tag_map[] =
37 {
38         {"description", A_DESCRIPTION},
39         {"enclosure", A_ENCLOSURE},
40         {"item", A_ITEM},
41 };
42 #define TAG_MAP_SZ      (sizeof(tag_map)/sizeof(tag_map_t))
43
44 typedef struct
45 {
46         gchar *key;
47         gchar *value;
48         GQueue *stack;
49         GQueue *tag_stack;
50         GString *description;
51         gchar *build;
52         gchar *version;
53         gboolean item;
54 } parse_data_t;
55
56 static const gchar*
57 lookup_attr_value(
58         const gchar *name, 
59         const gchar **attr_names, 
60         const gchar **attr_values)
61 {
62         gint ii;
63
64         if (attr_names == NULL) return NULL;
65         for (ii = 0; attr_names[ii] != NULL; ii++)
66         {
67                 if (strcmp(name, attr_names[ii]) == 0)
68                         return attr_values[ii];
69         }
70         return NULL;
71 }
72  
73 static void
74 start_element(
75         GMarkupParseContext *ctx, 
76         const gchar *tag, 
77         const gchar **attr_names,
78         const gchar **attr_values,
79         gpointer ud,
80         GError **error)
81 {
82         parse_data_t *pd = (parse_data_t*)ud;
83         union 
84         {
85                 gint id;
86                 gpointer pid;
87         } id;
88         gint ii;
89
90         for (ii = 0; ii < TAG_MAP_SZ; ii++)
91         {
92                 if (strcmp(tag, tag_map[ii].tag) == 0)
93                 {
94                         id.id = tag_map[ii].id;
95                         break;
96                 }
97         }
98         if (ii == TAG_MAP_SZ)
99         {
100                 g_debug("Unrecognized start tag (%s)", tag);
101                 id.id = A_NONE;
102         }
103         g_queue_push_head(pd->tag_stack, id.pid);
104         switch (id.id)
105         {
106                 case A_ITEM:
107                 {
108                         pd->item = TRUE;
109                 } break;
110                 case A_ENCLOSURE:
111                 {
112                         const gchar *build, *version;
113                         build = lookup_attr_value(
114                                                 "sparkle:version", attr_names, attr_values);
115                         version = lookup_attr_value(
116                                                 "sparkle:shortVersionString", attr_names, attr_values);
117                         if (build)
118                                 pd->build = g_strdup(build);
119                         if (version)
120                                 pd->version = g_strdup(version);
121                 } break;
122         }
123 }
124
125 static void
126 end_element(
127         GMarkupParseContext *ctx, 
128         const gchar *tag, 
129         gpointer ud,
130         GError **error)
131 {
132         parse_data_t *pd = (parse_data_t*)ud;
133         gint id;
134         union 
135         {
136                 gint id;
137                 gpointer pid;
138         } start_id;
139         gint ii;
140
141         for (ii = 0; ii < TAG_MAP_SZ; ii++)
142         {
143                 if (strcmp(tag, tag_map[ii].tag) == 0)
144                 {
145                         id = tag_map[ii].id;
146                         break;
147                 }
148         }
149         if (ii == TAG_MAP_SZ)
150         {
151                 g_debug("Unrecognized end tag (%s)", tag);
152                 id = A_NONE;
153         }
154         start_id.pid = g_queue_pop_head(pd->tag_stack);
155         if (start_id.id != id)
156                 g_warning("start tag != end tag: (%s %d) %d", tag, start_id.id, id);
157         switch (id)
158         {
159                 case A_ITEM:
160                 {
161                         pd->item = FALSE;
162                 } break;
163                 default:
164                 {
165                 } break;
166         }
167
168 }
169
170 static void
171 text_data(
172         GMarkupParseContext *ctx, 
173         const gchar *text, 
174         gsize len,
175         gpointer ud,
176         GError **error)
177 {
178         parse_data_t *pd = (parse_data_t*)ud;
179         union 
180         {
181                 gint id;
182                 gpointer pid;
183         } start_id;
184
185         start_id.pid = g_queue_peek_head(pd->tag_stack);
186         switch (start_id.id)
187         {
188                 case A_DESCRIPTION:
189                 {
190                         if (pd->item)
191                         {
192                                 g_string_append(pd->description, text);
193                         }
194                 } break;
195                 default:
196                 {
197                         if (pd->value) g_free(pd->value);
198                         pd->value = g_strdup(text);
199                 } break;
200         }
201 }
202
203 static void
204 passthrough(
205         GMarkupParseContext *ctx, 
206         const gchar *text, 
207         gsize len,
208         gpointer ud,
209         GError **error)
210 {
211         //parse_data_t *pd = (parse_data_t*)ud;
212
213         //g_debug("passthrough %s", text);
214 }
215
216 static void
217 parse_error(GMarkupParseContext *ctx, GError *error, gpointer ud)
218 {
219         g_warning("Resource parse error: %s", error->message);
220 }
221
222 // This is required or the parser crashes
223 static void 
224 destroy_notify(gpointer data)
225 { // Do nothing
226         //g_debug("destroy parser");
227 }
228
229 void
230 ghb_appcast_parse(gchar *buf, gchar **desc, gchar **build, gchar **version)
231 {
232         GMarkupParseContext *ctx;
233         GMarkupParser parser;
234         parse_data_t pd;
235         GError *err = NULL;
236         gint len;
237         gchar *start;
238         //gchar tmp[4096]
239
240         // Skip junk at beginning of buffer
241         start = strstr(buf, "<?xml ");
242         pd.description = g_string_new("");
243         pd.item = FALSE;
244         pd.build = NULL;
245         pd.version = NULL;
246         len = strlen(start);
247         pd.tag_stack = g_queue_new();
248         pd.key = NULL;
249         pd.value = NULL;
250
251         parser.start_element = start_element;
252         parser.end_element = end_element;
253         parser.text = text_data;
254         parser.passthrough = passthrough;
255         parser.error = parse_error;
256         ctx = g_markup_parse_context_new(
257                         &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &pd, destroy_notify);
258
259         g_markup_parse_context_parse(ctx, start, len, &err);
260         g_markup_parse_context_end_parse(ctx, &err);
261         g_markup_parse_context_free(ctx);
262         g_queue_free(pd.tag_stack);
263         *desc = g_string_free(pd.description, FALSE);
264         // work around a bug to leaves the CDATA closing brakets on the string
265         gchar *glitch;
266         glitch = g_strrstr(*desc, "]]>");
267         if (glitch)
268                 *glitch = 0;
269         *build = pd.build;
270         *version = pd.version;
271 }