gtypemodule: use G_GNUC_UNUSED in G_DEFINE_DYNAMIC_TYPE_EXTENDED
[glib.git] / gio / gresource-tool.c
blobcc4e78b9ff5c373d8021820713bd21d44df973fd
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 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
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)
94 continue;
96 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
98 if (details)
99 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
100 else
101 g_print ("%s\n", child);
103 else
104 list_resource (resource, child, section, prefix, details);
106 g_free (child);
108 g_strfreev (children);
111 static void
112 extract_resource (GResource *resource,
113 const gchar *path)
115 GBytes *bytes;
117 bytes = g_resource_lookup_data (resource, path, 0, NULL);
118 if (bytes != NULL)
120 gconstpointer data;
121 gsize size, written;
123 data = g_bytes_get_data (bytes, &size);
124 written = fwrite (data, 1, size, stdout);
125 if (written < size)
126 g_printerr ("Data truncated\n");
127 g_bytes_unref (bytes);
131 /* Elf functions {{{1 */
133 #ifdef HAVE_LIBELF
135 static Elf *
136 get_elf (const gchar *file,
137 gint *fd)
139 Elf *elf;
141 if (elf_version (EV_CURRENT) == EV_NONE )
142 return NULL;
144 *fd = g_open (file, O_RDONLY, 0);
145 if (*fd < 0)
146 return NULL;
148 elf = elf_begin (*fd, ELF_C_READ, NULL);
149 if (elf == NULL)
151 g_close (*fd, NULL);
152 *fd = -1;
153 return NULL;
156 if (elf_kind (elf) != ELF_K_ELF)
158 g_close (*fd, NULL);
159 *fd = -1;
160 return NULL;
163 return elf;
166 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
167 const gchar *name,
168 gpointer data);
170 static void
171 elf_foreach_resource_section (Elf *elf,
172 SectionCallback callback,
173 gpointer data)
175 size_t shstrndx, shnum;
176 size_t scnidx;
177 Elf_Scn *scn;
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);
190 if (scn == NULL)
191 continue;
193 shdr = gelf_getshdr (scn, &shdr_mem);
194 if (shdr == NULL)
195 continue;
197 if (shdr->sh_type != SHT_PROGBITS)
198 continue;
200 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
201 if (section_name == NULL ||
202 !g_str_has_prefix (section_name, ".gresource."))
203 continue;
205 if (!callback (shdr, section_name + strlen (".gresource."), data))
206 break;
210 static GResource *
211 resource_from_section (GElf_Shdr *shdr,
212 int fd)
214 gsize page_size, page_offset;
215 char *contents;
216 GResource *resource;
218 resource = NULL;
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)
226 GBytes *bytes;
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);
232 if (error)
234 g_printerr ("%s\n", error->message);
235 g_error_free (error);
238 else
240 g_printerr ("Can't mmap resource section");
243 return resource;
246 typedef struct
248 int fd;
249 const gchar *section;
250 const gchar *path;
251 gboolean details;
252 gboolean found;
253 } CallbackData;
255 static gboolean
256 list_resources_cb (GElf_Shdr *shdr,
257 const gchar *section,
258 gpointer data)
260 CallbackData *d = data;
261 GResource *resource;
263 if (d->section && strcmp (section, d->section) != 0)
264 return TRUE;
266 d->found = TRUE;
268 resource = resource_from_section (shdr, d->fd);
269 list_resource (resource, "/",
270 d->section ? "" : section,
271 d->path,
272 d->details);
273 g_resource_unref (resource);
275 if (d->section)
276 return FALSE;
278 return TRUE;
281 static void
282 elf_list_resources (Elf *elf,
283 int fd,
284 const gchar *section,
285 const gchar *path,
286 gboolean details)
288 CallbackData data;
290 data.fd = fd;
291 data.section = section;
292 data.path = path;
293 data.details = details;
294 data.found = FALSE;
296 elf_foreach_resource_section (elf, list_resources_cb, &data);
298 if (!data.found)
299 g_printerr ("Can't find resource section %s\n", section);
302 static gboolean
303 extract_resource_cb (GElf_Shdr *shdr,
304 const gchar *section,
305 gpointer data)
307 CallbackData *d = data;
308 GResource *resource;
310 if (d->section && strcmp (section, d->section) != 0)
311 return TRUE;
313 d->found = TRUE;
315 resource = resource_from_section (shdr, d->fd);
316 extract_resource (resource, d->path);
317 g_resource_unref (resource);
319 if (d->section)
320 return FALSE;
322 return TRUE;
325 static void
326 elf_extract_resource (Elf *elf,
327 int fd,
328 const gchar *section,
329 const gchar *path)
331 CallbackData data;
333 data.fd = fd;
334 data.section = section;
335 data.path = path;
336 data.found = FALSE;
338 elf_foreach_resource_section (elf, extract_resource_cb, &data);
340 if (!data.found)
341 g_printerr ("Can't find resource section %s\n", section);
344 static gboolean
345 print_section_name (GElf_Shdr *shdr,
346 const gchar *name,
347 gpointer data)
349 g_print ("%s\n", name);
350 return TRUE;
353 #endif /* HAVE_LIBELF */
355 /* Toplevel commands {{{1 */
357 static void
358 cmd_sections (const gchar *file,
359 const gchar *section,
360 const gchar *path,
361 gboolean details)
363 GResource *resource;
365 #ifdef HAVE_LIBELF
367 Elf *elf;
368 gint fd;
370 if ((elf = get_elf (file, &fd)))
372 elf_foreach_resource_section (elf, print_section_name, NULL);
373 elf_end (elf);
374 close (fd);
376 else
378 #endif
380 if ((resource = get_resource (file)))
382 /* No sections */
383 g_resource_unref (resource);
385 else
387 g_printerr ("Don't know how to handle %s\n", file);
388 #ifndef HAVE_LIBELF
389 g_printerr ("gresource is built without elf support\n");
390 #endif
394 static void
395 cmd_list (const gchar *file,
396 const gchar *section,
397 const gchar *path,
398 gboolean details)
400 GResource *resource;
402 #ifdef HAVE_LIBELF
403 Elf *elf;
404 int fd;
406 if ((elf = get_elf (file, &fd)))
408 elf_list_resources (elf, fd, section, path ? path : "", details);
409 elf_end (elf);
410 close (fd);
412 else
414 #endif
416 if ((resource = get_resource (file)))
418 list_resource (resource, "/", "", path ? path : "", details);
419 g_resource_unref (resource);
421 else
423 g_printerr ("Don't know how to handle %s\n", file);
424 #ifndef HAVE_LIBELF
425 g_printerr ("gresource is built without elf support\n");
426 #endif
430 static void
431 cmd_extract (const gchar *file,
432 const gchar *section,
433 const gchar *path,
434 gboolean details)
436 GResource *resource;
438 #ifdef HAVE_LIBELF
440 Elf *elf;
441 int fd;
443 if ((elf = get_elf (file, &fd)))
445 elf_extract_resource (elf, fd, section, path);
446 elf_end (elf);
447 close (fd);
449 else
451 #endif
453 if ((resource = get_resource (file)))
455 extract_resource (resource, path);
456 g_resource_unref (resource);
458 else
460 g_printerr ("Don't know how to handle %s\n", file);
461 #ifndef HAVE_LIBELF
462 g_printerr ("gresource is built without elf support\n");
463 #endif
467 static gint
468 cmd_help (gboolean requested,
469 const gchar *command)
471 const gchar *description;
472 const gchar *synopsis;
473 gchar *option;
474 GString *string;
476 option = NULL;
478 string = g_string_new (NULL);
480 if (command == 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"));
521 else
523 g_string_printf (string, _("Unknown command %s\n\n"), command);
524 requested = FALSE;
525 command = NULL;
528 if (command == NULL)
530 g_string_append (string,
531 _("Usage:\n"
532 " gresource [--section SECTION] COMMAND [ARGS...]\n"
533 "\n"
534 "Commands:\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"
540 "\n"
541 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
543 else
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"));
550 if (option)
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"));
563 else
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");
579 if (requested)
580 g_print ("%s", string->str);
581 else
582 g_printerr ("%s\n", string->str);
584 g_free (option);
585 g_string_free (string, TRUE);
587 return requested ? 0 : 1;
590 /* main {{{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);
599 #ifdef G_OS_WIN32
600 gchar *tmp;
601 #endif
603 setlocale (LC_ALL, "");
604 textdomain (GETTEXT_PACKAGE);
606 #ifdef G_OS_WIN32
607 tmp = _glib_get_locale_dir ();
608 bindtextdomain (GETTEXT_PACKAGE, tmp);
609 g_free (tmp);
610 #else
611 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
612 #endif
614 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
615 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
616 #endif
618 if (argc < 2)
619 return cmd_help (FALSE, NULL);
621 if (argc > 3 && strcmp (argv[1], "--section") == 0)
623 section = argv[2];
624 argv = argv + 2;
625 argc -= 2;
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)
639 function = cmd_list;
640 details = FALSE;
642 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
644 function = cmd_list;
645 details = TRUE;
647 else
648 return cmd_help (FALSE, argv[1]);
650 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
652 return 0;
655 /* vim:set foldmethod=marker: */