GIcon: add g_icon_[de]serialize()
[glib.git] / gio / gresource-tool.c
blobd4e5699bc782be828636c5f29157aea570e1c6d2
1 /*
2 * Copyright © 2012 Red Hat, Inc
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Matthias Clasen
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <locale.h>
33 #ifdef HAVE_LIBELF
34 #include <libelf.h>
35 #include <gelf.h>
36 #include <sys/mman.h>
37 #endif
39 #include <gio/gio.h>
40 #include <glib/gstdio.h>
41 #include <gi18n.h>
43 #ifdef G_OS_WIN32
44 #include "glib/glib-private.h"
45 #endif
47 /* GResource functions {{{1 */
48 static GResource *
49 get_resource (const gchar *file)
51 gchar *content;
52 gsize size;
53 GResource *resource;
54 GBytes *data;
56 resource = NULL;
58 if (g_file_get_contents (file, &content, &size, NULL))
60 data = g_bytes_new_take (content, size);
61 resource = g_resource_new_from_data (data, NULL);
62 g_bytes_unref (data);
65 return resource;
68 static void
69 list_resource (GResource *resource,
70 const gchar *path,
71 const gchar *section,
72 const gchar *prefix,
73 gboolean details)
75 gchar **children;
76 gsize size;
77 guint32 flags;
78 gint i;
79 gchar *child;
80 GError *error = NULL;
81 gint len;
83 children = g_resource_enumerate_children (resource, path, 0, &error);
84 if (error)
86 g_printerr ("%s\n", error->message);
87 g_error_free (error);
88 return;
90 for (i = 0; children[i]; i++)
92 child = g_strconcat (path, children[i], NULL);
94 len = MIN (strlen (child), strlen (prefix));
95 if (strncmp (child, prefix, len) != 0)
96 continue;
98 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
100 if (details)
101 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
102 else
103 g_print ("%s\n", child);
105 else
106 list_resource (resource, child, section, prefix, details);
108 g_free (child);
110 g_strfreev (children);
113 static void
114 extract_resource (GResource *resource,
115 const gchar *path)
117 GBytes *bytes;
119 bytes = g_resource_lookup_data (resource, path, 0, NULL);
120 if (bytes != NULL)
122 gconstpointer data;
123 gsize size, written;
125 data = g_bytes_get_data (bytes, &size);
126 written = fwrite (data, 1, size, stdout);
127 if (written < size)
128 g_printerr ("Data truncated\n");
129 g_bytes_unref (bytes);
131 else
133 g_printerr ("Can't find resource path %s\n", path);
137 /* Elf functions {{{1 */
139 #ifdef HAVE_LIBELF
141 static Elf *
142 get_elf (const gchar *file,
143 gint *fd)
145 Elf *elf;
147 if (elf_version (EV_CURRENT) == EV_NONE )
148 return NULL;
150 *fd = g_open (file, O_RDONLY, 0);
151 if (*fd < 0)
152 return NULL;
154 elf = elf_begin (*fd, ELF_C_READ, NULL);
155 if (elf == NULL)
156 return NULL;
158 if (elf_kind (elf) != ELF_K_ELF)
159 return NULL;
161 return elf;
164 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
165 const gchar *name,
166 gpointer data);
168 static void
169 elf_foreach_resource_section (Elf *elf,
170 SectionCallback callback,
171 gpointer data)
173 size_t shstrndx, shnum;
174 size_t scnidx;
175 Elf_Scn *scn;
176 GElf_Shdr *shdr, shdr_mem;
177 const gchar *section_name;
179 elf_getshdrstrndx (elf, &shstrndx);
180 g_assert (shstrndx >= 0);
182 elf_getshdrnum (elf, &shnum);
183 g_assert (shnum >= 0);
185 for (scnidx = 1; scnidx < shnum; scnidx++)
187 scn = elf_getscn (elf, scnidx);
188 if (scn == NULL)
189 continue;
191 shdr = gelf_getshdr (scn, &shdr_mem);
192 if (shdr == NULL)
193 continue;
195 if (shdr->sh_type != SHT_PROGBITS)
196 continue;
198 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
199 if (section_name == NULL ||
200 !g_str_has_prefix (section_name, ".gresource."))
201 continue;
203 if (!callback (shdr, section_name + strlen (".gresource."), data))
204 break;
208 static GResource *
209 resource_from_section (GElf_Shdr *shdr,
210 int fd)
212 gsize page_size, page_offset;
213 char *contents;
214 GResource *resource;
216 resource = NULL;
218 page_size = sysconf(_SC_PAGE_SIZE);
219 page_offset = shdr->sh_offset % page_size;
220 contents = mmap (NULL, shdr->sh_size + page_offset,
221 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
222 if (contents != MAP_FAILED)
224 GBytes *bytes;
226 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
227 resource = g_resource_new_from_data (bytes, NULL);
228 g_bytes_unref (bytes);
230 else
232 g_printerr ("Can't mmap resource section");
235 return resource;
238 typedef struct
240 int fd;
241 const gchar *section;
242 const gchar *path;
243 gboolean details;
244 gboolean found;
245 } CallbackData;
247 static gboolean
248 list_resources_cb (GElf_Shdr *shdr,
249 const gchar *section,
250 gpointer data)
252 CallbackData *d = data;
253 GResource *resource;
255 if (d->section && strcmp (section, d->section) != 0)
256 return TRUE;
258 d->found = TRUE;
260 resource = resource_from_section (shdr, d->fd);
261 list_resource (resource, "/",
262 d->section ? "" : section,
263 d->path,
264 d->details);
265 g_resource_unref (resource);
267 if (d->section)
268 return FALSE;
270 return TRUE;
273 static void
274 elf_list_resources (Elf *elf,
275 int fd,
276 const gchar *section,
277 const gchar *path,
278 gboolean details)
280 CallbackData data;
282 data.fd = fd;
283 data.section = section;
284 data.path = path;
285 data.details = details;
286 data.found = FALSE;
288 elf_foreach_resource_section (elf, list_resources_cb, &data);
290 if (!data.found)
291 g_printerr ("Can't find resource section %s\n", section);
294 static gboolean
295 extract_resource_cb (GElf_Shdr *shdr,
296 const gchar *section,
297 gpointer data)
299 CallbackData *d = data;
300 GResource *resource;
302 if (d->section && strcmp (section, d->section) != 0)
303 return TRUE;
305 d->found = TRUE;
307 resource = resource_from_section (shdr, d->fd);
308 extract_resource (resource, d->path);
309 g_resource_unref (resource);
311 return FALSE;
314 static void
315 elf_extract_resource (Elf *elf,
316 int fd,
317 const gchar *section,
318 const gchar *path)
320 CallbackData data;
322 data.fd = fd;
323 data.section = section;
324 data.path = path;
325 data.found = FALSE;
327 elf_foreach_resource_section (elf, extract_resource_cb, &data);
329 if (!data.found)
330 g_printerr ("Can't find resource section %s\n", section);
333 static gboolean
334 print_section_name (GElf_Shdr *shdr,
335 const gchar *name,
336 gpointer data)
338 g_print ("%s\n", name);
339 return TRUE;
342 #endif /* HAVE_LIBELF */
344 /* Toplevel commands {{{1 */
346 static void
347 cmd_sections (const gchar *file,
348 const gchar *section,
349 const gchar *path,
350 gboolean details)
352 GResource *resource;
354 #ifdef HAVE_LIBELF
356 Elf *elf;
357 gint fd;
359 if ((elf = get_elf (file, &fd)))
361 elf_foreach_resource_section (elf, print_section_name, NULL);
362 elf_end (elf);
363 close (fd);
365 else
367 #endif
369 if ((resource = get_resource (file)))
371 /* No sections */
372 g_resource_unref (resource);
374 else
376 g_printerr ("Don't know how to handle %s\n", file);
377 #ifndef HAVE_LIBELF
378 g_printerr ("gresource is built without elf support\n");
379 #endif
383 static void
384 cmd_list (const gchar *file,
385 const gchar *section,
386 const gchar *path,
387 gboolean details)
389 GResource *resource;
391 #ifdef HAVE_LIBELF
393 Elf *elf;
394 int fd;
396 if ((elf = get_elf (file, &fd)))
398 elf_list_resources (elf, fd, section, path ? path : "", details);
399 elf_end (elf);
400 close (fd);
402 else
404 #endif
406 if ((resource = get_resource (file)))
408 list_resource (resource, "/", "", path ? path : "", details);
409 g_resource_unref (resource);
411 else
413 g_printerr ("Don't know how to handle %s\n", file);
414 #ifndef HAVE_LIBELF
415 g_printerr ("gresource is built without elf support\n");
416 #endif
420 static void
421 cmd_extract (const gchar *file,
422 const gchar *section,
423 const gchar *path,
424 gboolean details)
426 GResource *resource;
428 #ifdef HAVE_LIBELF
430 Elf *elf;
431 int fd;
433 if ((elf = get_elf (file, &fd)))
435 elf_extract_resource (elf, fd, section, path);
436 elf_end (elf);
437 close (fd);
439 else
441 #endif
443 if ((resource = get_resource (file)))
445 extract_resource (resource, path);
446 g_resource_unref (resource);
448 else
450 g_printerr ("Don't know how to handle %s\n", file);
451 #ifndef HAVE_LIBELF
452 g_printerr ("gresource is built without elf support\n");
453 #endif
457 static gint
458 cmd_help (gboolean requested,
459 const gchar *command)
461 const gchar *description;
462 const gchar *synopsis;
463 gchar *option;
464 GString *string;
466 option = NULL;
468 string = g_string_new (NULL);
470 if (command == NULL)
473 else if (strcmp (command, "help") == 0)
475 description = _("Print help");
476 synopsis = _("[COMMAND]");
479 else if (strcmp (command, "sections") == 0)
481 description = _("List sections containing resources in an elf FILE");
482 synopsis = _("FILE");
485 else if (strcmp (command, "list") == 0)
487 description = _("List resources\n"
488 "If SECTION is given, only list resources in this section\n"
489 "If PATH is given, only list matching resources");
490 synopsis = _("FILE [PATH]");
491 option = g_strdup_printf ("[--section %s]", _("SECTION"));
494 else if (strcmp (command, "details") == 0)
496 description = _("List resources with details\n"
497 "If SECTION is given, only list resources in this section\n"
498 "If PATH is given, only list matching resources\n"
499 "Details include the section, size and compression");
500 synopsis = _("FILE [PATH]");
501 option = g_strdup_printf ("[--section %s]", _("SECTION"));
504 else if (strcmp (command, "extract") == 0)
506 description = _("Extract a resource file to stdout");
507 synopsis = _("FILE PATH");
508 option = g_strdup_printf ("[--section %s]", _("SECTION"));
511 else
513 g_string_printf (string, _("Unknown command %s\n\n"), command);
514 requested = FALSE;
515 command = NULL;
518 if (command == NULL)
520 g_string_append (string,
521 _("Usage:\n"
522 " gresource [--section SECTION] COMMAND [ARGS...]\n"
523 "\n"
524 "Commands:\n"
525 " help Show this information\n"
526 " sections List resource sections\n"
527 " list List resources\n"
528 " details List resources with details\n"
529 " extract Extract a resource\n"
530 "\n"
531 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
533 else
535 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
536 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
538 g_string_append (string, _("Arguments:\n"));
540 if (option)
541 g_string_append (string,
542 _(" SECTION An (optional) elf section name\n"));
544 if (strstr (synopsis, _("[COMMAND]")))
545 g_string_append (string,
546 _(" COMMAND The (optional) command to explain\n"));
548 if (strstr (synopsis, _("FILE")))
550 if (strcmp (command, "sections") == 0)
551 g_string_append (string,
552 _(" FILE An elf file (a binary or a shared library)\n"));
553 else
554 g_string_append (string,
555 _(" FILE An elf file (a binary or a shared library)\n"
556 " or a compiled resource file\n"));
559 if (strstr (synopsis, _("[PATH]")))
560 g_string_append (string,
561 _(" PATH An (optional) resource path (may be partial)\n"));
562 else if (strstr (synopsis, _("PATH")))
563 g_string_append (string,
564 _(" PATH A resource path\n"));
566 g_string_append (string, "\n");
569 if (requested)
570 g_print ("%s", string->str);
571 else
572 g_printerr ("%s\n", string->str);
574 g_free (option);
575 g_string_free (string, TRUE);
577 return requested ? 0 : 1;
580 /* main {{{1 */
583 main (int argc, char *argv[])
585 gchar *section = NULL;
586 gboolean details = FALSE;
587 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
589 #ifdef G_OS_WIN32
590 gchar *tmp;
591 #endif
593 setlocale (LC_ALL, "");
594 textdomain (GETTEXT_PACKAGE);
596 #ifdef G_OS_WIN32
597 tmp = _glib_get_locale_dir ();
598 bindtextdomain (GETTEXT_PACKAGE, tmp);
599 g_free (tmp);
600 #else
601 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
602 #endif
604 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
605 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
606 #endif
608 if (argc < 2)
609 return cmd_help (FALSE, NULL);
611 if (argc > 3 && strcmp (argv[1], "--section") == 0)
613 section = argv[2];
614 argv = argv + 2;
615 argc -= 2;
618 if (strcmp (argv[1], "help") == 0)
619 return cmd_help (TRUE, argv[2]);
621 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
622 function = cmd_extract;
624 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
625 function = cmd_sections;
627 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
629 function = cmd_list;
630 details = FALSE;
632 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
634 function = cmd_list;
635 details = TRUE;
637 else
638 return cmd_help (FALSE, argv[1]);
640 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
642 return 0;
645 /* vim:set foldmethod=marker: */