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, see <http://www.gnu.org/licenses/>.
17 * Author: Matthias Clasen
25 #include <sys/types.h>
38 #include <glib/gstdio.h>
42 #include "glib/glib-private.h"
45 /* GResource functions {{{1 */
47 get_resource (const gchar *file)
56 if (g_file_get_contents (file, &content, &size, NULL))
58 data = g_bytes_new_take (content, size);
59 resource = g_resource_new_from_data (data, NULL);
67 list_resource (GResource *resource,
81 children = g_resource_enumerate_children (resource, path, 0, &error);
84 g_printerr ("%s\n", error->message);
88 for (i = 0; children[i]; i++)
90 child = g_strconcat (path, children[i], NULL);
92 len = MIN (strlen (child), strlen (prefix));
93 if (strncmp (child, prefix, len) != 0)
96 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
99 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
101 g_print ("%s\n", child);
104 list_resource (resource, child, section, prefix, details);
108 g_strfreev (children);
112 extract_resource (GResource *resource,
117 bytes = g_resource_lookup_data (resource, path, 0, NULL);
123 data = g_bytes_get_data (bytes, &size);
124 written = fwrite (data, 1, size, stdout);
126 g_printerr ("Data truncated\n");
127 g_bytes_unref (bytes);
131 /* Elf functions {{{1 */
136 get_elf (const gchar *file,
141 if (elf_version (EV_CURRENT) == EV_NONE )
144 *fd = g_open (file, O_RDONLY, 0);
148 elf = elf_begin (*fd, ELF_C_READ, NULL);
156 if (elf_kind (elf) != ELF_K_ELF)
166 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
171 elf_foreach_resource_section (Elf *elf,
172 SectionCallback callback,
175 size_t shstrndx, shnum;
178 GElf_Shdr *shdr, shdr_mem;
179 const gchar *section_name;
181 elf_getshdrstrndx (elf, &shstrndx);
182 g_assert (shstrndx >= 0);
184 elf_getshdrnum (elf, &shnum);
185 g_assert (shnum >= 0);
187 for (scnidx = 1; scnidx < shnum; scnidx++)
189 scn = elf_getscn (elf, scnidx);
193 shdr = gelf_getshdr (scn, &shdr_mem);
197 if (shdr->sh_type != SHT_PROGBITS)
200 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
201 if (section_name == NULL ||
202 !g_str_has_prefix (section_name, ".gresource."))
205 if (!callback (shdr, section_name + strlen (".gresource."), data))
211 resource_from_section (GElf_Shdr *shdr,
214 gsize page_size, page_offset;
220 page_size = sysconf(_SC_PAGE_SIZE);
221 page_offset = shdr->sh_offset % page_size;
222 contents = mmap (NULL, shdr->sh_size + page_offset,
223 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
224 if (contents != MAP_FAILED)
227 GError *error = NULL;
229 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
230 resource = g_resource_new_from_data (bytes, &error);
231 g_bytes_unref (bytes);
234 g_printerr ("%s\n", error->message);
235 g_error_free (error);
240 g_printerr ("Can't mmap resource section");
249 const gchar *section;
256 list_resources_cb (GElf_Shdr *shdr,
257 const gchar *section,
260 CallbackData *d = data;
263 if (d->section && strcmp (section, d->section) != 0)
268 resource = resource_from_section (shdr, d->fd);
269 list_resource (resource, "/",
270 d->section ? "" : section,
273 g_resource_unref (resource);
282 elf_list_resources (Elf *elf,
284 const gchar *section,
291 data.section = section;
293 data.details = details;
296 elf_foreach_resource_section (elf, list_resources_cb, &data);
299 g_printerr ("Can't find resource section %s\n", section);
303 extract_resource_cb (GElf_Shdr *shdr,
304 const gchar *section,
307 CallbackData *d = data;
310 if (d->section && strcmp (section, d->section) != 0)
315 resource = resource_from_section (shdr, d->fd);
316 extract_resource (resource, d->path);
317 g_resource_unref (resource);
326 elf_extract_resource (Elf *elf,
328 const gchar *section,
334 data.section = section;
338 elf_foreach_resource_section (elf, extract_resource_cb, &data);
341 g_printerr ("Can't find resource section %s\n", section);
345 print_section_name (GElf_Shdr *shdr,
349 g_print ("%s\n", name);
353 #endif /* HAVE_LIBELF */
355 /* Toplevel commands {{{1 */
358 cmd_sections (const gchar *file,
359 const gchar *section,
370 if ((elf = get_elf (file, &fd)))
372 elf_foreach_resource_section (elf, print_section_name, NULL);
380 if ((resource = get_resource (file)))
383 g_resource_unref (resource);
387 g_printerr ("Don't know how to handle %s\n", file);
389 g_printerr ("gresource is built without elf support\n");
395 cmd_list (const gchar *file,
396 const gchar *section,
406 if ((elf = get_elf (file, &fd)))
408 elf_list_resources (elf, fd, section, path ? path : "", details);
416 if ((resource = get_resource (file)))
418 list_resource (resource, "/", "", path ? path : "", details);
419 g_resource_unref (resource);
423 g_printerr ("Don't know how to handle %s\n", file);
425 g_printerr ("gresource is built without elf support\n");
431 cmd_extract (const gchar *file,
432 const gchar *section,
443 if ((elf = get_elf (file, &fd)))
445 elf_extract_resource (elf, fd, section, path);
453 if ((resource = get_resource (file)))
455 extract_resource (resource, path);
456 g_resource_unref (resource);
460 g_printerr ("Don't know how to handle %s\n", file);
462 g_printerr ("gresource is built without elf support\n");
468 cmd_help (gboolean requested,
469 const gchar *command)
471 const gchar *description;
472 const gchar *synopsis;
478 string = g_string_new (NULL);
483 else if (strcmp (command, "help") == 0)
485 description = _("Print help");
486 synopsis = _("[COMMAND]");
489 else if (strcmp (command, "sections") == 0)
491 description = _("List sections containing resources in an elf FILE");
492 synopsis = _("FILE");
495 else if (strcmp (command, "list") == 0)
497 description = _("List resources\n"
498 "If SECTION is given, only list resources in this section\n"
499 "If PATH is given, only list matching resources");
500 synopsis = _("FILE [PATH]");
501 option = g_strdup_printf ("[--section %s]", _("SECTION"));
504 else if (strcmp (command, "details") == 0)
506 description = _("List resources with details\n"
507 "If SECTION is given, only list resources in this section\n"
508 "If PATH is given, only list matching resources\n"
509 "Details include the section, size and compression");
510 synopsis = _("FILE [PATH]");
511 option = g_strdup_printf ("[--section %s]", _("SECTION"));
514 else if (strcmp (command, "extract") == 0)
516 description = _("Extract a resource file to stdout");
517 synopsis = _("FILE PATH");
518 option = g_strdup_printf ("[--section %s]", _("SECTION"));
523 g_string_printf (string, _("Unknown command %s\n\n"), command);
530 g_string_append (string,
532 " gresource [--section SECTION] COMMAND [ARGS...]\n"
535 " help Show this information\n"
536 " sections List resource sections\n"
537 " list List resources\n"
538 " details List resources with details\n"
539 " extract Extract a resource\n"
541 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
545 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
546 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
548 g_string_append (string, _("Arguments:\n"));
551 g_string_append (string,
552 _(" SECTION An (optional) elf section name\n"));
554 if (strstr (synopsis, _("[COMMAND]")))
555 g_string_append (string,
556 _(" COMMAND The (optional) command to explain\n"));
558 if (strstr (synopsis, _("FILE")))
560 if (strcmp (command, "sections") == 0)
561 g_string_append (string,
562 _(" FILE An elf file (a binary or a shared library)\n"));
564 g_string_append (string,
565 _(" FILE An elf file (a binary or a shared library)\n"
566 " or a compiled resource file\n"));
569 if (strstr (synopsis, _("[PATH]")))
570 g_string_append (string,
571 _(" PATH An (optional) resource path (may be partial)\n"));
572 else if (strstr (synopsis, _("PATH")))
573 g_string_append (string,
574 _(" PATH A resource path\n"));
576 g_string_append (string, "\n");
580 g_print ("%s", string->str);
582 g_printerr ("%s\n", string->str);
585 g_string_free (string, TRUE);
587 return requested ? 0 : 1;
593 main (int argc, char *argv[])
595 gchar *section = NULL;
596 gboolean details = FALSE;
597 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
603 setlocale (LC_ALL, "");
604 textdomain (GETTEXT_PACKAGE);
607 tmp = _glib_get_locale_dir ();
608 bindtextdomain (GETTEXT_PACKAGE, tmp);
611 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
614 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
615 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
619 return cmd_help (FALSE, NULL);
621 if (argc > 3 && strcmp (argv[1], "--section") == 0)
628 if (strcmp (argv[1], "help") == 0)
629 return cmd_help (TRUE, argv[2]);
631 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
632 function = cmd_extract;
634 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
635 function = cmd_sections;
637 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
642 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
648 return cmd_help (FALSE, argv[1]);
650 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
655 /* vim:set foldmethod=marker: */