Merge branch '976-disable-assert-checks' into 'master'
[glib.git] / gio / gresource-tool.c
blobb25eebf3da50c4628c4e6e556814cf4bd1aab80b
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.1 of the License, 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
20 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <locale.h>
31 #ifdef HAVE_LIBELF
32 #include <libelf.h>
33 #include <gelf.h>
34 #include <sys/mman.h>
35 #endif
37 #include <gio/gio.h>
38 #include <glib/gstdio.h>
39 #include <gi18n.h>
41 #ifdef G_OS_WIN32
42 #include "glib/glib-private.h"
43 #endif
45 /* GResource functions {{{1 */
46 static GResource *
47 get_resource (const gchar *file)
49 gchar *content;
50 gsize size;
51 GResource *resource;
52 GBytes *data;
54 resource = NULL;
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);
60 g_bytes_unref (data);
63 return resource;
66 static void
67 list_resource (GResource *resource,
68 const gchar *path,
69 const gchar *section,
70 const gchar *prefix,
71 gboolean details)
73 gchar **children;
74 gsize size;
75 guint32 flags;
76 gint i;
77 gchar *child;
78 GError *error = NULL;
79 gint len;
81 children = g_resource_enumerate_children (resource, path, 0, &error);
82 if (error)
84 g_printerr ("%s\n", error->message);
85 g_error_free (error);
86 return;
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)
95 g_free (child);
96 continue;
99 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
101 if (details)
102 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, (flags & G_RESOURCE_FLAGS_COMPRESSED) ? "c" : "u", child);
103 else
104 g_print ("%s\n", child);
106 else
107 list_resource (resource, child, section, prefix, details);
109 g_free (child);
111 g_strfreev (children);
114 static void
115 extract_resource (GResource *resource,
116 const gchar *path)
118 GBytes *bytes;
120 bytes = g_resource_lookup_data (resource, path, 0, NULL);
121 if (bytes != NULL)
123 gconstpointer data;
124 gsize size, written;
126 data = g_bytes_get_data (bytes, &size);
127 written = fwrite (data, 1, size, stdout);
128 if (written < size)
129 g_printerr ("Data truncated\n");
130 g_bytes_unref (bytes);
134 /* Elf functions {{{1 */
136 #ifdef HAVE_LIBELF
138 static Elf *
139 get_elf (const gchar *file,
140 gint *fd)
142 Elf *elf;
144 if (elf_version (EV_CURRENT) == EV_NONE )
145 return NULL;
147 *fd = g_open (file, O_RDONLY, 0);
148 if (*fd < 0)
149 return NULL;
151 elf = elf_begin (*fd, ELF_C_READ, NULL);
152 if (elf == NULL)
154 g_close (*fd, NULL);
155 *fd = -1;
156 return NULL;
159 if (elf_kind (elf) != ELF_K_ELF)
161 g_close (*fd, NULL);
162 *fd = -1;
163 return NULL;
166 return elf;
169 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
170 const gchar *name,
171 gpointer data);
173 static void
174 elf_foreach_resource_section (Elf *elf,
175 SectionCallback callback,
176 gpointer data)
178 size_t shstrndx, shnum;
179 size_t scnidx;
180 Elf_Scn *scn;
181 GElf_Shdr *shdr, shdr_mem;
182 const gchar *section_name;
184 elf_getshdrstrndx (elf, &shstrndx);
185 g_assert (shstrndx >= 0);
187 elf_getshdrnum (elf, &shnum);
188 g_assert (shnum >= 0);
190 for (scnidx = 1; scnidx < shnum; scnidx++)
192 scn = elf_getscn (elf, scnidx);
193 if (scn == NULL)
194 continue;
196 shdr = gelf_getshdr (scn, &shdr_mem);
197 if (shdr == NULL)
198 continue;
200 if (shdr->sh_type != SHT_PROGBITS)
201 continue;
203 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
204 if (section_name == NULL ||
205 !g_str_has_prefix (section_name, ".gresource."))
206 continue;
208 if (!callback (shdr, section_name + strlen (".gresource."), data))
209 break;
213 static GResource *
214 resource_from_section (GElf_Shdr *shdr,
215 int fd)
217 gsize page_size, page_offset;
218 char *contents;
219 GResource *resource;
221 resource = NULL;
223 page_size = sysconf(_SC_PAGE_SIZE);
224 page_offset = shdr->sh_offset % page_size;
225 contents = mmap (NULL, shdr->sh_size + page_offset,
226 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
227 if (contents != MAP_FAILED)
229 GBytes *bytes;
230 GError *error = NULL;
232 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
233 resource = g_resource_new_from_data (bytes, &error);
234 g_bytes_unref (bytes);
235 if (error)
237 g_printerr ("%s\n", error->message);
238 g_error_free (error);
241 else
243 g_printerr ("Can't mmap resource section");
246 return resource;
249 typedef struct
251 int fd;
252 const gchar *section;
253 const gchar *path;
254 gboolean details;
255 gboolean found;
256 } CallbackData;
258 static gboolean
259 list_resources_cb (GElf_Shdr *shdr,
260 const gchar *section,
261 gpointer data)
263 CallbackData *d = data;
264 GResource *resource;
266 if (d->section && strcmp (section, d->section) != 0)
267 return TRUE;
269 d->found = TRUE;
271 resource = resource_from_section (shdr, d->fd);
272 list_resource (resource, "/",
273 d->section ? "" : section,
274 d->path,
275 d->details);
276 g_resource_unref (resource);
278 if (d->section)
279 return FALSE;
281 return TRUE;
284 static void
285 elf_list_resources (Elf *elf,
286 int fd,
287 const gchar *section,
288 const gchar *path,
289 gboolean details)
291 CallbackData data;
293 data.fd = fd;
294 data.section = section;
295 data.path = path;
296 data.details = details;
297 data.found = FALSE;
299 elf_foreach_resource_section (elf, list_resources_cb, &data);
301 if (!data.found)
302 g_printerr ("Can't find resource section %s\n", section);
305 static gboolean
306 extract_resource_cb (GElf_Shdr *shdr,
307 const gchar *section,
308 gpointer data)
310 CallbackData *d = data;
311 GResource *resource;
313 if (d->section && strcmp (section, d->section) != 0)
314 return TRUE;
316 d->found = TRUE;
318 resource = resource_from_section (shdr, d->fd);
319 extract_resource (resource, d->path);
320 g_resource_unref (resource);
322 if (d->section)
323 return FALSE;
325 return TRUE;
328 static void
329 elf_extract_resource (Elf *elf,
330 int fd,
331 const gchar *section,
332 const gchar *path)
334 CallbackData data;
336 data.fd = fd;
337 data.section = section;
338 data.path = path;
339 data.found = FALSE;
341 elf_foreach_resource_section (elf, extract_resource_cb, &data);
343 if (!data.found)
344 g_printerr ("Can't find resource section %s\n", section);
347 static gboolean
348 print_section_name (GElf_Shdr *shdr,
349 const gchar *name,
350 gpointer data)
352 g_print ("%s\n", name);
353 return TRUE;
356 #endif /* HAVE_LIBELF */
358 /* Toplevel commands {{{1 */
360 static void
361 cmd_sections (const gchar *file,
362 const gchar *section,
363 const gchar *path,
364 gboolean details)
366 GResource *resource;
368 #ifdef HAVE_LIBELF
370 Elf *elf;
371 gint fd;
373 if ((elf = get_elf (file, &fd)))
375 elf_foreach_resource_section (elf, print_section_name, NULL);
376 elf_end (elf);
377 close (fd);
379 else
381 #endif
383 if ((resource = get_resource (file)))
385 /* No sections */
386 g_resource_unref (resource);
388 else
390 g_printerr ("Don't know how to handle %s\n", file);
391 #ifndef HAVE_LIBELF
392 g_printerr ("gresource is built without elf support\n");
393 #endif
397 static void
398 cmd_list (const gchar *file,
399 const gchar *section,
400 const gchar *path,
401 gboolean details)
403 GResource *resource;
405 #ifdef HAVE_LIBELF
406 Elf *elf;
407 int fd;
409 if ((elf = get_elf (file, &fd)))
411 elf_list_resources (elf, fd, section, path ? path : "", details);
412 elf_end (elf);
413 close (fd);
415 else
417 #endif
419 if ((resource = get_resource (file)))
421 list_resource (resource, "/", "", path ? path : "", details);
422 g_resource_unref (resource);
424 else
426 g_printerr ("Don't know how to handle %s\n", file);
427 #ifndef HAVE_LIBELF
428 g_printerr ("gresource is built without elf support\n");
429 #endif
433 static void
434 cmd_extract (const gchar *file,
435 const gchar *section,
436 const gchar *path,
437 gboolean details)
439 GResource *resource;
441 #ifdef HAVE_LIBELF
443 Elf *elf;
444 int fd;
446 if ((elf = get_elf (file, &fd)))
448 elf_extract_resource (elf, fd, section, path);
449 elf_end (elf);
450 close (fd);
452 else
454 #endif
456 if ((resource = get_resource (file)))
458 extract_resource (resource, path);
459 g_resource_unref (resource);
461 else
463 g_printerr ("Don't know how to handle %s\n", file);
464 #ifndef HAVE_LIBELF
465 g_printerr ("gresource is built without elf support\n");
466 #endif
470 static gint
471 cmd_help (gboolean requested,
472 const gchar *command)
474 const gchar *description;
475 const gchar *synopsis;
476 gchar *option;
477 GString *string;
479 option = NULL;
481 string = g_string_new (NULL);
483 if (command == NULL)
486 else if (strcmp (command, "help") == 0)
488 description = _("Print help");
489 synopsis = _("[COMMAND]");
492 else if (strcmp (command, "sections") == 0)
494 description = _("List sections containing resources in an elf FILE");
495 synopsis = _("FILE");
498 else if (strcmp (command, "list") == 0)
500 description = _("List resources\n"
501 "If SECTION is given, only list resources in this section\n"
502 "If PATH is given, only list matching resources");
503 synopsis = _("FILE [PATH]");
504 option = g_strdup_printf ("[--section %s]", _("SECTION"));
507 else if (strcmp (command, "details") == 0)
509 description = _("List resources with details\n"
510 "If SECTION is given, only list resources in this section\n"
511 "If PATH is given, only list matching resources\n"
512 "Details include the section, size and compression");
513 synopsis = _("FILE [PATH]");
514 option = g_strdup_printf ("[--section %s]", _("SECTION"));
517 else if (strcmp (command, "extract") == 0)
519 description = _("Extract a resource file to stdout");
520 synopsis = _("FILE PATH");
521 option = g_strdup_printf ("[--section %s]", _("SECTION"));
524 else
526 g_string_printf (string, _("Unknown command %s\n\n"), command);
527 requested = FALSE;
528 command = NULL;
531 if (command == NULL)
533 g_string_append (string,
534 _("Usage:\n"
535 " gresource [--section SECTION] COMMAND [ARGS…]\n"
536 "\n"
537 "Commands:\n"
538 " help Show this information\n"
539 " sections List resource sections\n"
540 " list List resources\n"
541 " details List resources with details\n"
542 " extract Extract a resource\n"
543 "\n"
544 "Use “gresource help COMMAND” to get detailed help.\n\n"));
546 else
548 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
549 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
551 g_string_append (string, _("Arguments:\n"));
553 if (option)
554 g_string_append (string,
555 _(" SECTION An (optional) elf section name\n"));
557 if (strstr (synopsis, _("[COMMAND]")))
558 g_string_append (string,
559 _(" COMMAND The (optional) command to explain\n"));
561 if (strstr (synopsis, _("FILE")))
563 if (strcmp (command, "sections") == 0)
564 g_string_append (string,
565 _(" FILE An elf file (a binary or a shared library)\n"));
566 else
567 g_string_append (string,
568 _(" FILE An elf file (a binary or a shared library)\n"
569 " or a compiled resource file\n"));
572 if (strstr (synopsis, _("[PATH]")))
573 g_string_append (string,
574 _(" PATH An (optional) resource path (may be partial)\n"));
575 else if (strstr (synopsis, _("PATH")))
576 g_string_append (string,
577 _(" PATH A resource path\n"));
579 g_string_append (string, "\n");
582 if (requested)
583 g_print ("%s", string->str);
584 else
585 g_printerr ("%s\n", string->str);
587 g_free (option);
588 g_string_free (string, TRUE);
590 return requested ? 0 : 1;
593 /* main {{{1 */
596 main (int argc, char *argv[])
598 gchar *section = NULL;
599 gboolean details = FALSE;
600 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
602 #ifdef G_OS_WIN32
603 gchar *tmp;
604 #endif
606 setlocale (LC_ALL, "");
607 textdomain (GETTEXT_PACKAGE);
609 #ifdef G_OS_WIN32
610 tmp = _glib_get_locale_dir ();
611 bindtextdomain (GETTEXT_PACKAGE, tmp);
612 g_free (tmp);
613 #else
614 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
615 #endif
617 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
618 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
619 #endif
621 if (argc < 2)
622 return cmd_help (FALSE, NULL);
624 if (argc > 3 && strcmp (argv[1], "--section") == 0)
626 section = argv[2];
627 argv = argv + 2;
628 argc -= 2;
631 if (strcmp (argv[1], "help") == 0)
632 return cmd_help (TRUE, argv[2]);
634 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
635 function = cmd_extract;
637 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
638 function = cmd_sections;
640 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
642 function = cmd_list;
643 details = FALSE;
645 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
647 function = cmd_list;
648 details = TRUE;
650 else
651 return cmd_help (FALSE, argv[1]);
653 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
655 return 0;
658 /* vim:set foldmethod=marker: */