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,
116 GError *error = NULL;
118 bytes = g_resource_lookup_data (resource, path, 0, &error);
124 data = g_bytes_get_data (bytes, &size);
125 written = fwrite (data, 1, size, stdout);
127 g_printerr ("Data truncated\n");
128 g_bytes_unref (bytes);
132 g_printerr ("%s\n", error->message);
133 g_error_free (error);
137 /* Elf functions {{{1 */
142 get_elf (const gchar *file,
147 if (elf_version (EV_CURRENT) == EV_NONE )
150 *fd = g_open (file, O_RDONLY, 0);
154 elf = elf_begin (*fd, ELF_C_READ, NULL);
162 if (elf_kind (elf) != ELF_K_ELF)
172 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
177 elf_foreach_resource_section (Elf *elf,
178 SectionCallback callback,
181 size_t shstrndx, shnum;
184 GElf_Shdr *shdr, shdr_mem;
185 const gchar *section_name;
187 elf_getshdrstrndx (elf, &shstrndx);
188 g_assert (shstrndx >= 0);
190 elf_getshdrnum (elf, &shnum);
191 g_assert (shnum >= 0);
193 for (scnidx = 1; scnidx < shnum; scnidx++)
195 scn = elf_getscn (elf, scnidx);
199 shdr = gelf_getshdr (scn, &shdr_mem);
203 if (shdr->sh_type != SHT_PROGBITS)
206 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
207 if (section_name == NULL ||
208 !g_str_has_prefix (section_name, ".gresource."))
211 if (!callback (shdr, section_name + strlen (".gresource."), data))
217 resource_from_section (GElf_Shdr *shdr,
220 gsize page_size, page_offset;
226 page_size = sysconf(_SC_PAGE_SIZE);
227 page_offset = shdr->sh_offset % page_size;
228 contents = mmap (NULL, shdr->sh_size + page_offset,
229 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
230 if (contents != MAP_FAILED)
234 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
235 resource = g_resource_new_from_data (bytes, NULL);
236 g_bytes_unref (bytes);
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);
323 elf_extract_resource (Elf *elf,
325 const gchar *section,
331 data.section = section;
335 elf_foreach_resource_section (elf, extract_resource_cb, &data);
338 g_printerr ("Can't find resource section %s\n", section);
342 print_section_name (GElf_Shdr *shdr,
346 g_print ("%s\n", name);
350 #endif /* HAVE_LIBELF */
352 /* Toplevel commands {{{1 */
355 cmd_sections (const gchar *file,
356 const gchar *section,
367 if ((elf = get_elf (file, &fd)))
369 elf_foreach_resource_section (elf, print_section_name, NULL);
377 if ((resource = get_resource (file)))
380 g_resource_unref (resource);
384 g_printerr ("Don't know how to handle %s\n", file);
386 g_printerr ("gresource is built without elf support\n");
392 cmd_list (const gchar *file,
393 const gchar *section,
404 if ((elf = get_elf (file, &fd)))
406 elf_list_resources (elf, fd, section, path ? path : "", details);
414 if ((resource = get_resource (file)))
416 list_resource (resource, "/", "", path ? path : "", details);
417 g_resource_unref (resource);
421 g_printerr ("Don't know how to handle %s\n", file);
423 g_printerr ("gresource is built without elf support\n");
429 cmd_extract (const gchar *file,
430 const gchar *section,
441 if ((elf = get_elf (file, &fd)))
443 elf_extract_resource (elf, fd, section, path);
451 if ((resource = get_resource (file)))
453 extract_resource (resource, path);
454 g_resource_unref (resource);
458 g_printerr ("Don't know how to handle %s\n", file);
460 g_printerr ("gresource is built without elf support\n");
466 cmd_help (gboolean requested,
467 const gchar *command)
469 const gchar *description;
470 const gchar *synopsis;
476 string = g_string_new (NULL);
481 else if (strcmp (command, "help") == 0)
483 description = _("Print help");
484 synopsis = _("[COMMAND]");
487 else if (strcmp (command, "sections") == 0)
489 description = _("List sections containing resources in an elf FILE");
490 synopsis = _("FILE");
493 else if (strcmp (command, "list") == 0)
495 description = _("List resources\n"
496 "If SECTION is given, only list resources in this section\n"
497 "If PATH is given, only list matching resources");
498 synopsis = _("FILE [PATH]");
499 option = g_strdup_printf ("[--section %s]", _("SECTION"));
502 else if (strcmp (command, "details") == 0)
504 description = _("List resources with details\n"
505 "If SECTION is given, only list resources in this section\n"
506 "If PATH is given, only list matching resources\n"
507 "Details include the section, size and compression");
508 synopsis = _("FILE [PATH]");
509 option = g_strdup_printf ("[--section %s]", _("SECTION"));
512 else if (strcmp (command, "extract") == 0)
514 description = _("Extract a resource file to stdout");
515 synopsis = _("FILE PATH");
516 option = g_strdup_printf ("[--section %s]", _("SECTION"));
521 g_string_printf (string, _("Unknown command %s\n\n"), command);
528 g_string_append (string,
530 " gresource [--section SECTION] COMMAND [ARGS...]\n"
533 " help Show this information\n"
534 " sections List resource sections\n"
535 " list List resources\n"
536 " details List resources with details\n"
537 " extract Extract a resource\n"
539 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
543 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
544 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
546 g_string_append (string, _("Arguments:\n"));
549 g_string_append (string,
550 _(" SECTION An (optional) elf section name\n"));
552 if (strstr (synopsis, _("[COMMAND]")))
553 g_string_append (string,
554 _(" COMMAND The (optional) command to explain\n"));
556 if (strstr (synopsis, _("FILE")))
558 if (strcmp (command, "sections") == 0)
559 g_string_append (string,
560 _(" FILE An elf file (a binary or a shared library)\n"));
562 g_string_append (string,
563 _(" FILE An elf file (a binary or a shared library)\n"
564 " or a compiled resource file\n"));
567 if (strstr (synopsis, _("[PATH]")))
568 g_string_append (string,
569 _(" PATH An (optional) resource path (may be partial)\n"));
570 else if (strstr (synopsis, _("PATH")))
571 g_string_append (string,
572 _(" PATH A resource path\n"));
574 g_string_append (string, "\n");
578 g_print ("%s", string->str);
580 g_printerr ("%s\n", string->str);
583 g_string_free (string, TRUE);
585 return requested ? 0 : 1;
591 main (int argc, char *argv[])
593 gchar *section = NULL;
594 gboolean details = FALSE;
595 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
601 setlocale (LC_ALL, "");
602 textdomain (GETTEXT_PACKAGE);
605 tmp = _glib_get_locale_dir ();
606 bindtextdomain (GETTEXT_PACKAGE, tmp);
609 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
612 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
613 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
617 return cmd_help (FALSE, NULL);
619 if (argc > 3 && strcmp (argv[1], "--section") == 0)
626 if (strcmp (argv[1], "help") == 0)
627 return cmd_help (TRUE, argv[2]);
629 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
630 function = cmd_extract;
632 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
633 function = cmd_sections;
635 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
640 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
646 return cmd_help (FALSE, argv[1]);
648 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
653 /* vim:set foldmethod=marker: */