Merge branch 'gbytes-compare-docs' into 'master'
[glib.git] / gio / gresource-tool.c
blobd1de026315f6e908dc3db62db32b63fe4f3a2017
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 #endif
36 #ifdef HAVE_MMAP
37 #include <sys/mman.h>
38 #endif
40 #include <gio/gio.h>
41 #include <glib/gstdio.h>
42 #include <gi18n.h>
44 #ifdef G_OS_WIN32
45 #include "glib/glib-private.h"
46 #endif
48 #if defined(HAVE_LIBELF) && defined(HAVE_MMAP)
49 #define USE_LIBELF
50 #endif
52 /* GResource functions {{{1 */
53 static GResource *
54 get_resource (const gchar *file)
56 gchar *content;
57 gsize size;
58 GResource *resource;
59 GBytes *data;
61 resource = NULL;
63 if (g_file_get_contents (file, &content, &size, NULL))
65 data = g_bytes_new_take (content, size);
66 resource = g_resource_new_from_data (data, NULL);
67 g_bytes_unref (data);
70 return resource;
73 static void
74 list_resource (GResource *resource,
75 const gchar *path,
76 const gchar *section,
77 const gchar *prefix,
78 gboolean details)
80 gchar **children;
81 gsize size;
82 guint32 flags;
83 gint i;
84 gchar *child;
85 GError *error = NULL;
86 gint len;
88 children = g_resource_enumerate_children (resource, path, 0, &error);
89 if (error)
91 g_printerr ("%s\n", error->message);
92 g_error_free (error);
93 return;
95 for (i = 0; children[i]; i++)
97 child = g_strconcat (path, children[i], NULL);
99 len = MIN (strlen (child), strlen (prefix));
100 if (strncmp (child, prefix, len) != 0)
102 g_free (child);
103 continue;
106 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
108 if (details)
109 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, (flags & G_RESOURCE_FLAGS_COMPRESSED) ? "c" : "u", child);
110 else
111 g_print ("%s\n", child);
113 else
114 list_resource (resource, child, section, prefix, details);
116 g_free (child);
118 g_strfreev (children);
121 static void
122 extract_resource (GResource *resource,
123 const gchar *path)
125 GBytes *bytes;
127 bytes = g_resource_lookup_data (resource, path, 0, NULL);
128 if (bytes != NULL)
130 gconstpointer data;
131 gsize size, written;
133 data = g_bytes_get_data (bytes, &size);
134 written = fwrite (data, 1, size, stdout);
135 if (written < size)
136 g_printerr ("Data truncated\n");
137 g_bytes_unref (bytes);
141 /* Elf functions {{{1 */
143 #ifdef USE_LIBELF
145 static Elf *
146 get_elf (const gchar *file,
147 gint *fd)
149 Elf *elf;
151 if (elf_version (EV_CURRENT) == EV_NONE )
152 return NULL;
154 *fd = g_open (file, O_RDONLY, 0);
155 if (*fd < 0)
156 return NULL;
158 elf = elf_begin (*fd, ELF_C_READ, NULL);
159 if (elf == NULL)
161 g_close (*fd, NULL);
162 *fd = -1;
163 return NULL;
166 if (elf_kind (elf) != ELF_K_ELF)
168 g_close (*fd, NULL);
169 *fd = -1;
170 return NULL;
173 return elf;
176 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
177 const gchar *name,
178 gpointer data);
180 static void
181 elf_foreach_resource_section (Elf *elf,
182 SectionCallback callback,
183 gpointer data)
185 size_t shstrndx, shnum;
186 size_t scnidx;
187 Elf_Scn *scn;
188 GElf_Shdr *shdr, shdr_mem;
189 const gchar *section_name;
191 elf_getshdrstrndx (elf, &shstrndx);
192 g_assert (shstrndx >= 0);
194 elf_getshdrnum (elf, &shnum);
195 g_assert (shnum >= 0);
197 for (scnidx = 1; scnidx < shnum; scnidx++)
199 scn = elf_getscn (elf, scnidx);
200 if (scn == NULL)
201 continue;
203 shdr = gelf_getshdr (scn, &shdr_mem);
204 if (shdr == NULL)
205 continue;
207 if (shdr->sh_type != SHT_PROGBITS)
208 continue;
210 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
211 if (section_name == NULL ||
212 !g_str_has_prefix (section_name, ".gresource."))
213 continue;
215 if (!callback (shdr, section_name + strlen (".gresource."), data))
216 break;
220 static GResource *
221 resource_from_section (GElf_Shdr *shdr,
222 int fd)
224 gsize page_size, page_offset;
225 char *contents;
226 GResource *resource;
228 resource = NULL;
230 page_size = sysconf(_SC_PAGE_SIZE);
231 page_offset = shdr->sh_offset % page_size;
232 contents = mmap (NULL, shdr->sh_size + page_offset,
233 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
234 if (contents != MAP_FAILED)
236 GBytes *bytes;
237 GError *error = NULL;
239 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
240 resource = g_resource_new_from_data (bytes, &error);
241 g_bytes_unref (bytes);
242 if (error)
244 g_printerr ("%s\n", error->message);
245 g_error_free (error);
248 else
250 g_printerr ("Can't mmap resource section");
253 return resource;
256 typedef struct
258 int fd;
259 const gchar *section;
260 const gchar *path;
261 gboolean details;
262 gboolean found;
263 } CallbackData;
265 static gboolean
266 list_resources_cb (GElf_Shdr *shdr,
267 const gchar *section,
268 gpointer data)
270 CallbackData *d = data;
271 GResource *resource;
273 if (d->section && strcmp (section, d->section) != 0)
274 return TRUE;
276 d->found = TRUE;
278 resource = resource_from_section (shdr, d->fd);
279 list_resource (resource, "/",
280 d->section ? "" : section,
281 d->path,
282 d->details);
283 g_resource_unref (resource);
285 if (d->section)
286 return FALSE;
288 return TRUE;
291 static void
292 elf_list_resources (Elf *elf,
293 int fd,
294 const gchar *section,
295 const gchar *path,
296 gboolean details)
298 CallbackData data;
300 data.fd = fd;
301 data.section = section;
302 data.path = path;
303 data.details = details;
304 data.found = FALSE;
306 elf_foreach_resource_section (elf, list_resources_cb, &data);
308 if (!data.found)
309 g_printerr ("Can't find resource section %s\n", section);
312 static gboolean
313 extract_resource_cb (GElf_Shdr *shdr,
314 const gchar *section,
315 gpointer data)
317 CallbackData *d = data;
318 GResource *resource;
320 if (d->section && strcmp (section, d->section) != 0)
321 return TRUE;
323 d->found = TRUE;
325 resource = resource_from_section (shdr, d->fd);
326 extract_resource (resource, d->path);
327 g_resource_unref (resource);
329 if (d->section)
330 return FALSE;
332 return TRUE;
335 static void
336 elf_extract_resource (Elf *elf,
337 int fd,
338 const gchar *section,
339 const gchar *path)
341 CallbackData data;
343 data.fd = fd;
344 data.section = section;
345 data.path = path;
346 data.found = FALSE;
348 elf_foreach_resource_section (elf, extract_resource_cb, &data);
350 if (!data.found)
351 g_printerr ("Can't find resource section %s\n", section);
354 static gboolean
355 print_section_name (GElf_Shdr *shdr,
356 const gchar *name,
357 gpointer data)
359 g_print ("%s\n", name);
360 return TRUE;
363 #endif /* USE_LIBELF */
365 /* Toplevel commands {{{1 */
367 static void
368 cmd_sections (const gchar *file,
369 const gchar *section,
370 const gchar *path,
371 gboolean details)
373 GResource *resource;
375 #ifdef USE_LIBELF
377 Elf *elf;
378 gint fd;
380 if ((elf = get_elf (file, &fd)))
382 elf_foreach_resource_section (elf, print_section_name, NULL);
383 elf_end (elf);
384 close (fd);
386 else
388 #endif
390 if ((resource = get_resource (file)))
392 /* No sections */
393 g_resource_unref (resource);
395 else
397 g_printerr ("Don't know how to handle %s\n", file);
398 #ifndef USE_LIBELF
399 g_printerr ("gresource is built without elf support\n");
400 #endif
404 static void
405 cmd_list (const gchar *file,
406 const gchar *section,
407 const gchar *path,
408 gboolean details)
410 GResource *resource;
412 #ifdef USE_LIBELF
413 Elf *elf;
414 int fd;
416 if ((elf = get_elf (file, &fd)))
418 elf_list_resources (elf, fd, section, path ? path : "", details);
419 elf_end (elf);
420 close (fd);
422 else
424 #endif
426 if ((resource = get_resource (file)))
428 list_resource (resource, "/", "", path ? path : "", details);
429 g_resource_unref (resource);
431 else
433 g_printerr ("Don't know how to handle %s\n", file);
434 #ifndef USE_LIBELF
435 g_printerr ("gresource is built without elf support\n");
436 #endif
440 static void
441 cmd_extract (const gchar *file,
442 const gchar *section,
443 const gchar *path,
444 gboolean details)
446 GResource *resource;
448 #ifdef USE_LIBELF
450 Elf *elf;
451 int fd;
453 if ((elf = get_elf (file, &fd)))
455 elf_extract_resource (elf, fd, section, path);
456 elf_end (elf);
457 close (fd);
459 else
461 #endif
463 if ((resource = get_resource (file)))
465 extract_resource (resource, path);
466 g_resource_unref (resource);
468 else
470 g_printerr ("Don't know how to handle %s\n", file);
471 #ifndef USE_LIBELF
472 g_printerr ("gresource is built without elf support\n");
473 #endif
477 static gint
478 cmd_help (gboolean requested,
479 const gchar *command)
481 const gchar *description;
482 const gchar *synopsis;
483 gchar *option;
484 GString *string;
486 option = NULL;
488 string = g_string_new (NULL);
490 if (command == NULL)
493 else if (strcmp (command, "help") == 0)
495 description = _("Print help");
496 synopsis = _("[COMMAND]");
499 else if (strcmp (command, "sections") == 0)
501 description = _("List sections containing resources in an elf FILE");
502 synopsis = _("FILE");
505 else if (strcmp (command, "list") == 0)
507 description = _("List resources\n"
508 "If SECTION is given, only list resources in this section\n"
509 "If PATH is given, only list matching resources");
510 synopsis = _("FILE [PATH]");
511 option = g_strdup_printf ("[--section %s]", _("SECTION"));
514 else if (strcmp (command, "details") == 0)
516 description = _("List resources with details\n"
517 "If SECTION is given, only list resources in this section\n"
518 "If PATH is given, only list matching resources\n"
519 "Details include the section, size and compression");
520 synopsis = _("FILE [PATH]");
521 option = g_strdup_printf ("[--section %s]", _("SECTION"));
524 else if (strcmp (command, "extract") == 0)
526 description = _("Extract a resource file to stdout");
527 synopsis = _("FILE PATH");
528 option = g_strdup_printf ("[--section %s]", _("SECTION"));
531 else
533 g_string_printf (string, _("Unknown command %s\n\n"), command);
534 requested = FALSE;
535 command = NULL;
538 if (command == NULL)
540 g_string_append (string,
541 _("Usage:\n"
542 " gresource [--section SECTION] COMMAND [ARGS…]\n"
543 "\n"
544 "Commands:\n"
545 " help Show this information\n"
546 " sections List resource sections\n"
547 " list List resources\n"
548 " details List resources with details\n"
549 " extract Extract a resource\n"
550 "\n"
551 "Use “gresource help COMMAND” to get detailed help.\n\n"));
553 else
555 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
556 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
558 g_string_append (string, _("Arguments:\n"));
560 if (option)
561 g_string_append (string,
562 _(" SECTION An (optional) elf section name\n"));
564 if (strstr (synopsis, _("[COMMAND]")))
565 g_string_append (string,
566 _(" COMMAND The (optional) command to explain\n"));
568 if (strstr (synopsis, _("FILE")))
570 if (strcmp (command, "sections") == 0)
571 g_string_append (string,
572 _(" FILE An elf file (a binary or a shared library)\n"));
573 else
574 g_string_append (string,
575 _(" FILE An elf file (a binary or a shared library)\n"
576 " or a compiled resource file\n"));
579 if (strstr (synopsis, _("[PATH]")))
580 g_string_append (string,
581 _(" PATH An (optional) resource path (may be partial)\n"));
582 else if (strstr (synopsis, _("PATH")))
583 g_string_append (string,
584 _(" PATH A resource path\n"));
586 g_string_append (string, "\n");
589 if (requested)
590 g_print ("%s", string->str);
591 else
592 g_printerr ("%s\n", string->str);
594 g_free (option);
595 g_string_free (string, TRUE);
597 return requested ? 0 : 1;
600 /* main {{{1 */
603 main (int argc, char *argv[])
605 gchar *section = NULL;
606 gboolean details = FALSE;
607 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
609 #ifdef G_OS_WIN32
610 gchar *tmp;
611 #endif
613 setlocale (LC_ALL, "");
614 textdomain (GETTEXT_PACKAGE);
616 #ifdef G_OS_WIN32
617 tmp = _glib_get_locale_dir ();
618 bindtextdomain (GETTEXT_PACKAGE, tmp);
619 g_free (tmp);
620 #else
621 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
622 #endif
624 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
625 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
626 #endif
628 if (argc < 2)
629 return cmd_help (FALSE, NULL);
631 if (argc > 3 && strcmp (argv[1], "--section") == 0)
633 section = argv[2];
634 argv = argv + 2;
635 argc -= 2;
638 if (strcmp (argv[1], "help") == 0)
639 return cmd_help (TRUE, argv[2]);
641 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
642 function = cmd_extract;
644 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
645 function = cmd_sections;
647 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
649 function = cmd_list;
650 details = FALSE;
652 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
654 function = cmd_list;
655 details = TRUE;
657 else
658 return cmd_help (FALSE, argv[1]);
660 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
662 return 0;
665 /* vim:set foldmethod=marker: */