OSDN Git Service

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