OSDN Git Service

LinGui: make it possible to build outside srcdir
[handbrake-jp/handbrake-jp-git.git] / gtk / src / create_resources.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <glib.h>
6 #include <glib/gstdio.h>
7 #include "icon_tools.h"
8 #include "plist.h"
9 #include "values.h"
10
11 enum
12 {
13         R_NONE = 0,
14         R_RESOURCES,
15         R_SECTION,
16         R_ICON,
17         R_PLIST,
18         R_STRING,
19 };
20
21 typedef struct
22 {
23         gchar *tag;
24         gint id;
25 } tag_map_t;
26
27 static tag_map_t tag_map[] =
28 {
29         {"resources", R_RESOURCES},
30         {"section", R_SECTION},
31         {"icon", R_ICON},
32         {"plist", R_PLIST},
33         {"string", R_STRING},
34 };
35 #define TAG_MAP_SZ      (sizeof(tag_map)/sizeof(tag_map_t))
36
37 typedef struct
38 {
39         gchar *key;
40         gchar *value;
41         GValue *plist;
42         GQueue *stack;
43         GQueue *tag_stack;
44         gboolean closed_top;
45 } parse_data_t;
46
47 GList *inc_list = NULL;
48
49 static gchar*
50 find_file(GList *list, const gchar *name)
51 {
52         gchar *str;
53         GList *link = list;
54
55         while (link != NULL)
56         {
57                 gchar *inc;
58
59                 inc = (gchar*)link->data;
60                 str = g_strdup_printf("%s/%s", inc, name);
61                 if (g_file_test(str, G_FILE_TEST_IS_REGULAR))
62                 {
63                         return str;
64                 }
65                 g_free(str);
66                 link = g_list_next(link);
67         }
68         if (g_file_test(name, G_FILE_TEST_IS_REGULAR))
69         {
70                 return g_strdup(name);
71         }
72         return NULL;
73 }
74
75 static const gchar*
76 lookup_attr_value(
77         const gchar *name, 
78         const gchar **attr_names, 
79         const gchar **attr_values)
80 {
81         gint ii;
82
83         if (attr_names == NULL) return NULL;
84         for (ii = 0; attr_names[ii] != NULL; ii++)
85         {
86                 if (strcmp(name, attr_names[ii]) == 0)
87                         return attr_values[ii];
88         }
89         return NULL;
90 }
91  
92 static GValue*
93 read_string_from_file(const gchar *filename)
94 {
95         gchar *buffer;
96         size_t size;
97         GValue *gval;
98         FILE *fd;
99
100         fd = g_fopen(filename, "r");
101         if (fd == NULL)
102                 return NULL;
103         fseek(fd, 0, SEEK_END);
104         size = ftell(fd);
105         fseek(fd, 0, SEEK_SET);
106         buffer = g_malloc(size+1);
107         size = fread(buffer, 1, size, fd);
108         buffer[size] = 0;
109         gval = ghb_value_new(G_TYPE_STRING);
110         g_value_take_string(gval, buffer);
111         fclose(fd);
112         return gval;
113 }
114
115 static void
116 start_element(
117         GMarkupParseContext *ctx, 
118         const gchar *tag, 
119         const gchar **attr_names,
120         const gchar **attr_values,
121         gpointer ud,
122         GError **error)
123 {
124         parse_data_t *pd = (parse_data_t*)ud;
125         union 
126         {
127                 gint id;
128                 gpointer pid;
129         } id;
130         gint ii;
131
132         // Check to see if the first element found has been closed
133         // If so, ignore any junk following it.
134         if (pd->closed_top)
135                 return;
136
137         for (ii = 0; ii < TAG_MAP_SZ; ii++)
138         {
139                 if (strcmp(tag, tag_map[ii].tag) == 0)
140                 {
141                         id.id = tag_map[ii].id;
142                         break;
143                 }
144         }
145         if (ii == TAG_MAP_SZ)
146         {
147                 g_warning("Unrecognized start tag (%s)", tag);
148                 return;
149         }
150         g_queue_push_head(pd->tag_stack, id.pid);
151         GType gtype = 0;
152         GValue *gval = NULL;
153         GValue *current = g_queue_peek_head(pd->stack);
154         switch (id.id)
155         {
156                 case R_SECTION:
157                 {
158                         const gchar *name;
159
160                         name = lookup_attr_value("name", attr_names, attr_values);
161                         if (name && strcmp(name, "icons") == 0)
162                         {
163                                 gval = ghb_dict_value_new();
164                                 if (pd->key) g_free(pd->key);
165                                 pd->key = g_strdup(name);
166                                 g_queue_push_head(pd->stack, gval);
167                         }
168                 } break;
169                 case R_ICON:
170                 {
171                         gchar *filename;
172                         const gchar *name;
173
174                         name = lookup_attr_value("file", attr_names, attr_values);
175                         filename = find_file(inc_list, name);
176                         name = lookup_attr_value("name", attr_names, attr_values);
177                         if (filename && name)
178                         {
179                                 ghb_rawdata_t *rd;
180                                 guint size;
181
182                                 rd = g_malloc(sizeof(ghb_rawdata_t));
183                                 rd->data = icon_file_serialize(filename, &size);
184                                 rd->size = size;
185                                 gval = ghb_rawdata_value_new(rd);
186                                 if (pd->key) g_free(pd->key);
187                                 pd->key = g_strdup(name);
188                                 g_free(filename);
189                         }
190                         else
191                         {
192                                 g_warning("%s:missing a requried attribute", name);
193                         exit(EXIT_FAILURE);
194                         }
195                 } break;
196                 case R_PLIST:
197                 {
198                         gchar *filename;
199                         const gchar *name;
200
201                         name = lookup_attr_value("file", attr_names, attr_values);
202                         filename = find_file(inc_list, name);
203                         name = lookup_attr_value("name", attr_names, attr_values);
204                         if (filename && name)
205                         {
206                                 gval = ghb_plist_parse_file(filename);
207                                 if (pd->key) g_free(pd->key);
208                                 pd->key = g_strdup(name);
209                                 g_free(filename);
210                         }
211                         else
212                         {
213                                 g_warning("%s:missing a requried attribute", name);
214                         exit(EXIT_FAILURE);
215                         }
216                 } break;
217                 case R_STRING:
218                 {
219                         gchar *filename;
220                         const gchar *name;
221
222                         name = lookup_attr_value("file", attr_names, attr_values);
223                         filename = find_file(inc_list, name);
224                         name = lookup_attr_value("name", attr_names, attr_values);
225                         if (filename && name)
226                         {
227                                 gval = read_string_from_file(filename);
228                                 if (pd->key) g_free(pd->key);
229                                 pd->key = g_strdup(name);
230                                 g_free(filename);
231                         }
232                         else
233                         {
234                                 g_warning("%s:missing a requried attribute", name);
235                         exit(EXIT_FAILURE);
236                         }
237                 } break;
238         }
239         // Add the element to the current container
240         if (gval)
241         { // There's an element to add
242                 if (current == NULL)
243                 {
244                         pd->plist = gval;
245                         return;
246                 }
247                 gtype = G_VALUE_TYPE(current);
248                 if (gtype == ghb_array_get_type())
249                 {
250                         ghb_array_append(current, gval);
251                 }
252                 else if (gtype == ghb_dict_get_type())
253                 {
254                         if (pd->key == NULL)
255                         {
256                                 g_warning("No key for dictionary item");
257                                 ghb_value_free(gval);
258                         }
259                         else
260                         {
261                                 ghb_dict_insert(current, g_strdup(pd->key), gval);
262                         }
263                 }
264                 else
265                 {
266                         g_error("Invalid container type. This shouldn't happen");
267                 }
268         }
269 }
270
271 static void
272 end_element(
273         GMarkupParseContext *ctx, 
274         const gchar *name, 
275         gpointer ud,
276         GError **error)
277 {
278         parse_data_t *pd = (parse_data_t*)ud;
279         gint id;
280         union 
281         {
282                 gint id;
283                 gpointer pid;
284         } start_id;
285         gint ii;
286
287         // Check to see if the first element found has been closed
288         // If so, ignore any junk following it.
289         if (pd->closed_top)
290                 return;
291
292         for (ii = 0; ii < TAG_MAP_SZ; ii++)
293         {
294                 if (strcmp(name, tag_map[ii].tag) == 0)
295                 {
296                         id = tag_map[ii].id;
297                         break;
298                 }
299         }
300         if (ii == TAG_MAP_SZ)
301         {
302                 g_warning("Unrecognized start tag (%s)", name);
303                 return;
304         }
305         start_id.pid = g_queue_pop_head(pd->tag_stack);
306         if (start_id.id != id)
307                 g_warning("start tag != end tag: (%s %d) %d", name, id, id);
308
309         GValue *gval = NULL;
310         GValue *current = g_queue_peek_head(pd->stack);
311         GType gtype = 0;
312         switch (id)
313         {
314                 case R_SECTION:
315                 {
316                         g_queue_pop_head(pd->stack);
317                 } break;
318         }
319         if (gval)
320         {
321                 // Get the top of the data structure stack and if it's an array
322                 // or dict, add the current element
323                 if (current == NULL)
324                 {
325                         pd->plist = gval;
326                         pd->closed_top = TRUE;
327                         return;
328                 }
329                 gtype = G_VALUE_TYPE(current);
330                 if (gtype == ghb_array_get_type())
331                 {
332                         ghb_array_append(current, gval);
333                 }
334                 else if (gtype == ghb_dict_get_type())
335                 {
336                         if (pd->key == NULL)
337                         {
338                                 g_warning("No key for dictionary item");
339                                 ghb_value_free(gval);
340                         }
341                         else
342                         {
343                                 ghb_dict_insert(current, g_strdup(pd->key), gval);
344                         }
345                 }
346                 else
347                 {
348                         g_error("Invalid container type. This shouldn't happen");
349                 }
350         }
351         if (g_queue_is_empty(pd->tag_stack))
352                 pd->closed_top = TRUE;
353 }
354
355 static void
356 text_data(
357         GMarkupParseContext *ctx, 
358         const gchar *text, 
359         gsize len,
360         gpointer ud,
361         GError **error)
362 {
363         parse_data_t *pd = (parse_data_t*)ud;
364         if (pd->value) g_free(pd->value);
365         pd->value = g_strdup(text);
366 }
367
368 static void
369 passthrough(
370         GMarkupParseContext *ctx, 
371         const gchar *text, 
372         gsize len,
373         gpointer ud,
374         GError **error)
375 {
376         //parse_data_t *pd = (parse_data_t*)ud;
377
378         //g_debug("passthrough %s", text);
379 }
380
381 static void
382 parse_error(GMarkupParseContext *ctx, GError *error, gpointer ud)
383 {
384         g_warning("Resource parse error: %s", error->message);
385 }
386
387 // This is required or the parser crashes
388 static void 
389 destroy_notify(gpointer data)
390 { // Do nothing
391         //g_debug("destroy parser");
392 }
393
394 GValue*
395 ghb_resource_parse(const gchar *buf, gssize len)
396 {
397         GMarkupParseContext *ctx;
398         GMarkupParser parser;
399         parse_data_t pd;
400         GError *err = NULL;
401
402         pd.stack = g_queue_new();
403         pd.tag_stack = g_queue_new();
404         pd.key = NULL;
405         pd.value = NULL;
406         pd.plist = ghb_dict_value_new();
407         g_queue_push_head(pd.stack, pd.plist);
408         pd.closed_top = FALSE;
409
410         parser.start_element = start_element;
411         parser.end_element = end_element;
412         parser.text = text_data;
413         parser.passthrough = passthrough;
414         parser.error = parse_error;
415         ctx = g_markup_parse_context_new(&parser, 0, &pd, destroy_notify);
416
417         g_markup_parse_context_parse(ctx, buf, len, &err);
418         g_markup_parse_context_end_parse(ctx, &err);
419         g_markup_parse_context_free(ctx);
420         g_queue_free(pd.stack);
421         g_queue_free(pd.tag_stack);
422         return pd.plist;
423 }
424
425 GValue*
426 ghb_resource_parse_file(FILE *fd)
427 {
428         gchar *buffer;
429         size_t size;
430         GValue *gval;
431
432         if (fd == NULL)
433                 return NULL;
434         fseek(fd, 0, SEEK_END);
435         size = ftell(fd);
436         fseek(fd, 0, SEEK_SET);
437         buffer = g_malloc(size+1);
438         size = fread(buffer, 1, size, fd);
439         buffer[size] = 0;
440         gval = ghb_resource_parse(buffer, (gssize)size);
441         g_free(buffer);
442         return gval;
443 }
444
445 static void
446 usage(char *cmd)
447 {
448     fprintf(stderr,
449 "Usage: %s [-I <inc path>] <in resource list> <out resource plist>\n"
450 "Summary:\n"
451 "    Creates a resource plist from a resource list\n"
452 "Options:\n"
453 "    I - Include path to search for files\n"
454 "    <in resource list>    Input resources file\n"
455 "    <out resource plist>  Output resources plist file\n"
456 , cmd);
457
458     exit(EXIT_FAILURE);
459 }
460
461 #define OPTS "I:"
462
463 gint
464 main(gint argc, gchar *argv[])
465 {
466         FILE *file;
467         GValue *gval;
468     int opt;
469         const gchar *src, *dst;
470
471     do
472     {
473         opt = getopt(argc, argv, OPTS);
474         switch (opt)
475         {
476         case -1: break;
477
478         case 'I':
479                         inc_list = g_list_prepend(inc_list, g_strdup(optarg));
480             break;
481         }
482     } while (opt != -1);
483
484         if (optind != argc - 2)
485         {
486                 usage(argv[0]);
487                 return EXIT_FAILURE;
488         }
489     src = argv[optind++];
490     dst = argv[optind++];
491
492         g_type_init();
493         file = g_fopen(src, "r");
494         if (file == NULL)
495         {
496                 fprintf(stderr, "Error: failed to open %s\n", src);
497                 return EXIT_FAILURE;
498         }
499
500         gval = ghb_resource_parse_file(file);
501         ghb_plist_write_file(dst, gval);
502         return 0;
503 }
504