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
27 #include <sys/types.h>
41 /* GResource functions {{{1 */
43 get_resource (const gchar *file)
52 if (g_file_get_contents (file, &content, &size, NULL))
54 data = g_bytes_new_take (content, size);
55 resource = g_resource_new_from_data (data, NULL);
63 list_resource (GResource *resource,
77 children = g_resource_enumerate_children (resource, path, 0, &error);
80 g_printerr ("%s\n", error->message);
84 for (i = 0; children[i]; i++)
86 child = g_strconcat (path, children[i], NULL);
88 len = MIN (strlen (child), strlen (prefix));
89 if (strncmp (child, prefix, len) != 0)
92 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
95 g_print ("%s%s%6ld %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
97 g_print ("%s\n", child);
100 list_resource (resource, child, section, prefix, details);
104 g_strfreev (children);
108 extract_resource (GResource *resource,
113 bytes = g_resource_lookup_data (resource, path, 0, NULL);
119 data = g_bytes_get_data (bytes, &size);
120 written = fwrite (data, 1, size, stdout);
122 g_printerr ("Data truncated\n");
123 g_bytes_unref (bytes);
127 g_printerr ("Can't find resource path %s\n", path);
131 /* Elf functions {{{1 */
136 get_elf (const gchar *file,
141 if (elf_version (EV_CURRENT) == EV_NONE )
144 *fd = open (file, O_RDONLY);
148 elf = elf_begin (*fd, ELF_C_READ, NULL);
152 if (elf_kind (elf) != ELF_K_ELF)
158 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
163 elf_foreach_resource_section (Elf *elf,
164 SectionCallback callback,
167 size_t shstrndx, shnum;
170 GElf_Shdr *shdr, shdr_mem;
171 const gchar *section_name;
173 elf_getshdrstrndx (elf, &shstrndx);
174 g_assert (shstrndx >= 0);
176 elf_getshdrnum (elf, &shnum);
177 g_assert (shnum >= 0);
179 for (scnidx = 1; scnidx < shnum; scnidx++)
181 scn = elf_getscn (elf, scnidx);
185 shdr = gelf_getshdr (scn, &shdr_mem);
189 if (shdr->sh_type != SHT_PROGBITS)
192 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
193 if (section_name == NULL ||
194 !g_str_has_prefix (section_name, ".gresource."))
197 if (!callback (shdr, section_name + strlen (".gresource."), data))
203 resource_from_section (GElf_Shdr *shdr,
206 gsize page_size, page_offset;
212 page_size = sysconf(_SC_PAGE_SIZE);
213 page_offset = shdr->sh_offset % page_size;
214 contents = mmap (NULL, shdr->sh_size + page_offset,
215 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
216 if (contents != MAP_FAILED)
220 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
221 resource = g_resource_new_from_data (bytes, NULL);
222 g_bytes_unref (bytes);
226 g_printerr ("Can't mmap resource section");
235 const gchar *section;
242 list_resources_cb (GElf_Shdr *shdr,
243 const gchar *section,
246 CallbackData *d = data;
249 if (d->section && strcmp (section, d->section) != 0)
254 resource = resource_from_section (shdr, d->fd);
255 list_resource (resource, "/",
256 d->section ? "" : section,
259 g_resource_unref (resource);
268 elf_list_resources (Elf *elf,
270 const gchar *section,
277 data.section = section;
279 data.details = details;
282 elf_foreach_resource_section (elf, list_resources_cb, &data);
285 g_printerr ("Can't find resource section %s\n", section);
289 extract_resource_cb (GElf_Shdr *shdr,
290 const gchar *section,
293 CallbackData *d = data;
296 if (d->section && strcmp (section, d->section) != 0)
301 resource = resource_from_section (shdr, d->fd);
302 extract_resource (resource, d->path);
303 g_resource_unref (resource);
309 elf_extract_resource (Elf *elf,
311 const gchar *section,
317 data.section = section;
321 elf_foreach_resource_section (elf, extract_resource_cb, &data);
324 g_printerr ("Can't find resource section %s\n", section);
328 print_section_name (GElf_Shdr *shdr,
332 g_print ("%s\n", name);
336 #endif /* HAVE_LIBELF */
338 /* Toplevel commands {{{1 */
341 cmd_sections (const gchar *file,
342 const gchar *section,
353 if ((elf = get_elf (file, &fd)))
355 elf_foreach_resource_section (elf, print_section_name, NULL);
363 if ((resource = get_resource (file)))
366 g_resource_unref (resource);
370 g_printerr ("Don't know how to handle %s\n", file);
372 g_printerr ("gresource is built without elf support\n");
378 cmd_list (const gchar *file,
379 const gchar *section,
390 if ((elf = get_elf (file, &fd)))
392 elf_list_resources (elf, fd, section, path ? path : "", details);
400 if ((resource = get_resource (file)))
402 list_resource (resource, "/", "", path ? path : "", details);
403 g_resource_unref (resource);
407 g_printerr ("Don't know how to handle %s\n", file);
409 g_printerr ("gresource is built without elf support\n");
415 cmd_extract (const gchar *file,
416 const gchar *section,
427 if ((elf = get_elf (file, &fd)))
429 elf_extract_resource (elf, fd, section, path);
437 if ((resource = get_resource (file)))
439 extract_resource (resource, path);
440 g_resource_unref (resource);
444 g_printerr ("Don't know how to handle %s\n", file);
446 g_printerr ("gresource is built without elf support\n");
452 cmd_help (gboolean requested,
453 const gchar *command)
455 const gchar *description;
456 const gchar *synopsis;
462 string = g_string_new (NULL);
467 else if (strcmp (command, "help") == 0)
469 description = _("Print help");
470 synopsis = "[COMMAND]";
473 else if (strcmp (command, "sections") == 0)
475 description = _("List sections containing resources in an elf FILE");
479 else if (strcmp (command, "list") == 0)
481 description = _("List resources\n"
482 "If SECTION is given, only list resources in this section\n"
483 "If PATH is given, only list matching resources");
484 synopsis = "FILE [PATH]";
485 option = g_strdup_printf ("[--section %s]", _("SECTION"));
488 else if (strcmp (command, "details") == 0)
490 description = _("List resources with details\n"
491 "If SECTION is given, only list resources in this section\n"
492 "If PATH is given, only list matching resources\n"
493 "Details include the section, size and compression");
494 synopsis = "FILE [PATH]";
495 option = g_strdup_printf ("[--section %s]", _("SECTION"));
498 else if (strcmp (command, "extract") == 0)
500 description = _("Extract a resource file to stdout");
501 synopsis = "FILE PATH";
502 option = g_strdup_printf ("[--section %s]", _("SECTION"));
507 g_string_printf (string, _("Unknown command %s\n\n"), command);
514 g_string_append (string,
516 " gresource [--section SECTION] COMMAND [ARGS...]\n"
519 " help Show this information\n"
520 " sections List resource sections\n"
521 " list List resources\n"
522 " details List resources with details\n"
523 " extract Extract a resource\n"
525 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
529 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
530 option ? option : "", option ? " " : "", command, synopsis[0] ? _(synopsis) : "", description);
532 g_string_append (string, _("Arguments:\n"));
535 g_string_append (string,
536 _(" SECTION An (optional) elf section name\n"));
538 if (strstr (synopsis, "[COMMAND]"))
539 g_string_append (string,
540 _(" COMMAND The (optional) command to explain\n"));
542 if (strstr (synopsis, "FILE"))
544 if (strcmp (command, "sections") == 0)
545 g_string_append (string,
546 _(" FILE An elf file (a binary or a shared library)\n"));
548 g_string_append (string,
549 _(" FILE An elf file (a binary or a shared library)\n"
550 " or a compiled resource file\n"));
553 if (strstr (synopsis, "[PATH"))
554 g_string_append (string,
555 _(" PATH An (optional) resource path (may be partial)\n"));
556 else if (strstr (synopsis, "PATH"))
557 g_string_append (string,
558 _(" PATH A resource path\n"));
560 g_string_append (string, "\n");
564 g_print ("%s", string->str);
566 g_printerr ("%s\n", string->str);
569 g_string_free (string, TRUE);
571 return requested ? 0 : 1;
577 main (int argc, char *argv[])
579 gchar *section = NULL;
580 gboolean details = FALSE;
581 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
586 return cmd_help (FALSE, NULL);
588 if (argc > 3 && strcmp (argv[1], "--section") == 0)
595 if (strcmp (argv[1], "help") == 0)
596 return cmd_help (TRUE, argv[2]);
598 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
599 function = cmd_extract;
601 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
602 function = cmd_sections;
604 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
609 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
615 return cmd_help (FALSE, argv[1]);
617 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
622 /* vim:set foldmethod=marker: */