docs: Add GIOModuleScope and GIOModuleScopeFlags
[glib.git] / gio / gresource-tool.c
blob4bbc688bbf862040672ef26a2481b3bfa72998e6
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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Matthias Clasen
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <locale.h>
33 #ifdef HAVE_LIBELF
34 #include <libelf.h>
35 #include <gelf.h>
36 #include <sys/mman.h>
37 #endif
39 #include <gio/gio.h>
40 #include <gi18n.h>
42 /* GResource functions {{{1 */
43 static GResource *
44 get_resource (const gchar *file)
46 gchar *content;
47 gsize size;
48 GResource *resource;
49 GBytes *data;
51 resource = NULL;
53 if (g_file_get_contents (file, &content, &size, NULL))
55 data = g_bytes_new_take (content, size);
56 resource = g_resource_new_from_data (data, NULL);
57 g_bytes_unref (data);
60 return resource;
63 static void
64 list_resource (GResource *resource,
65 const gchar *path,
66 const gchar *section,
67 const gchar *prefix,
68 gboolean details)
70 gchar **children;
71 gsize size;
72 guint32 flags;
73 gint i;
74 gchar *child;
75 GError *error = NULL;
76 gint len;
78 children = g_resource_enumerate_children (resource, path, 0, &error);
79 if (error)
81 g_printerr ("%s\n", error->message);
82 g_error_free (error);
83 return;
85 for (i = 0; children[i]; i++)
87 child = g_strconcat (path, children[i], NULL);
89 len = MIN (strlen (child), strlen (prefix));
90 if (strncmp (child, prefix, len) != 0)
91 continue;
93 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
95 if (details)
96 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
97 else
98 g_print ("%s\n", child);
100 else
101 list_resource (resource, child, section, prefix, details);
103 g_free (child);
105 g_strfreev (children);
108 static void
109 extract_resource (GResource *resource,
110 const gchar *path)
112 GBytes *bytes;
114 bytes = g_resource_lookup_data (resource, path, 0, NULL);
115 if (bytes != NULL)
117 gconstpointer data;
118 gsize size, written;
120 data = g_bytes_get_data (bytes, &size);
121 written = fwrite (data, 1, size, stdout);
122 if (written < size)
123 g_printerr ("Data truncated\n");
124 g_bytes_unref (bytes);
126 else
128 g_printerr ("Can't find resource path %s\n", path);
132 /* Elf functions {{{1 */
134 #ifdef HAVE_LIBELF
136 static Elf *
137 get_elf (const gchar *file,
138 gint *fd)
140 Elf *elf;
142 if (elf_version (EV_CURRENT) == EV_NONE )
143 return NULL;
145 *fd = open (file, O_RDONLY);
146 if (*fd < 0)
147 return NULL;
149 elf = elf_begin (*fd, ELF_C_READ, NULL);
150 if (elf == NULL)
151 return NULL;
153 if (elf_kind (elf) != ELF_K_ELF)
154 return NULL;
156 return elf;
159 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
160 const gchar *name,
161 gpointer data);
163 static void
164 elf_foreach_resource_section (Elf *elf,
165 SectionCallback callback,
166 gpointer data)
168 size_t shstrndx, shnum;
169 size_t scnidx;
170 Elf_Scn *scn;
171 GElf_Shdr *shdr, shdr_mem;
172 const gchar *section_name;
174 elf_getshdrstrndx (elf, &shstrndx);
175 g_assert (shstrndx >= 0);
177 elf_getshdrnum (elf, &shnum);
178 g_assert (shnum >= 0);
180 for (scnidx = 1; scnidx < shnum; scnidx++)
182 scn = elf_getscn (elf, scnidx);
183 if (scn == NULL)
184 continue;
186 shdr = gelf_getshdr (scn, &shdr_mem);
187 if (shdr == NULL)
188 continue;
190 if (shdr->sh_type != SHT_PROGBITS)
191 continue;
193 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
194 if (section_name == NULL ||
195 !g_str_has_prefix (section_name, ".gresource."))
196 continue;
198 if (!callback (shdr, section_name + strlen (".gresource."), data))
199 break;
203 static GResource *
204 resource_from_section (GElf_Shdr *shdr,
205 int fd)
207 gsize page_size, page_offset;
208 char *contents;
209 GResource *resource;
211 resource = NULL;
213 page_size = sysconf(_SC_PAGE_SIZE);
214 page_offset = shdr->sh_offset % page_size;
215 contents = mmap (NULL, shdr->sh_size + page_offset,
216 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
217 if (contents != MAP_FAILED)
219 GBytes *bytes;
221 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
222 resource = g_resource_new_from_data (bytes, NULL);
223 g_bytes_unref (bytes);
225 else
227 g_printerr ("Can't mmap resource section");
230 return resource;
233 typedef struct
235 int fd;
236 const gchar *section;
237 const gchar *path;
238 gboolean details;
239 gboolean found;
240 } CallbackData;
242 static gboolean
243 list_resources_cb (GElf_Shdr *shdr,
244 const gchar *section,
245 gpointer data)
247 CallbackData *d = data;
248 GResource *resource;
250 if (d->section && strcmp (section, d->section) != 0)
251 return TRUE;
253 d->found = TRUE;
255 resource = resource_from_section (shdr, d->fd);
256 list_resource (resource, "/",
257 d->section ? "" : section,
258 d->path,
259 d->details);
260 g_resource_unref (resource);
262 if (d->section)
263 return FALSE;
265 return TRUE;
268 static void
269 elf_list_resources (Elf *elf,
270 int fd,
271 const gchar *section,
272 const gchar *path,
273 gboolean details)
275 CallbackData data;
277 data.fd = fd;
278 data.section = section;
279 data.path = path;
280 data.details = details;
281 data.found = FALSE;
283 elf_foreach_resource_section (elf, list_resources_cb, &data);
285 if (!data.found)
286 g_printerr ("Can't find resource section %s\n", section);
289 static gboolean
290 extract_resource_cb (GElf_Shdr *shdr,
291 const gchar *section,
292 gpointer data)
294 CallbackData *d = data;
295 GResource *resource;
297 if (d->section && strcmp (section, d->section) != 0)
298 return TRUE;
300 d->found = TRUE;
302 resource = resource_from_section (shdr, d->fd);
303 extract_resource (resource, d->path);
304 g_resource_unref (resource);
306 return FALSE;
309 static void
310 elf_extract_resource (Elf *elf,
311 int fd,
312 const gchar *section,
313 const gchar *path)
315 CallbackData data;
317 data.fd = fd;
318 data.section = section;
319 data.path = path;
320 data.found = FALSE;
322 elf_foreach_resource_section (elf, extract_resource_cb, &data);
324 if (!data.found)
325 g_printerr ("Can't find resource section %s\n", section);
328 static gboolean
329 print_section_name (GElf_Shdr *shdr,
330 const gchar *name,
331 gpointer data)
333 g_print ("%s\n", name);
334 return TRUE;
337 #endif /* HAVE_LIBELF */
339 /* Toplevel commands {{{1 */
341 static void
342 cmd_sections (const gchar *file,
343 const gchar *section,
344 const gchar *path,
345 gboolean details)
347 GResource *resource;
349 #ifdef HAVE_LIBELF
351 Elf *elf;
352 gint fd;
354 if ((elf = get_elf (file, &fd)))
356 elf_foreach_resource_section (elf, print_section_name, NULL);
357 elf_end (elf);
358 close (fd);
360 else
362 #endif
364 if ((resource = get_resource (file)))
366 /* No sections */
367 g_resource_unref (resource);
369 else
371 g_printerr ("Don't know how to handle %s\n", file);
372 #ifndef HAVE_LIBELF
373 g_printerr ("gresource is built without elf support\n");
374 #endif
378 static void
379 cmd_list (const gchar *file,
380 const gchar *section,
381 const gchar *path,
382 gboolean details)
384 GResource *resource;
386 #ifdef HAVE_LIBELF
388 Elf *elf;
389 int fd;
391 if ((elf = get_elf (file, &fd)))
393 elf_list_resources (elf, fd, section, path ? path : "", details);
394 elf_end (elf);
395 close (fd);
397 else
399 #endif
401 if ((resource = get_resource (file)))
403 list_resource (resource, "/", "", path ? path : "", details);
404 g_resource_unref (resource);
406 else
408 g_printerr ("Don't know how to handle %s\n", file);
409 #ifndef HAVE_LIBELF
410 g_printerr ("gresource is built without elf support\n");
411 #endif
415 static void
416 cmd_extract (const gchar *file,
417 const gchar *section,
418 const gchar *path,
419 gboolean details)
421 GResource *resource;
423 #ifdef HAVE_LIBELF
425 Elf *elf;
426 int fd;
428 if ((elf = get_elf (file, &fd)))
430 elf_extract_resource (elf, fd, section, path);
431 elf_end (elf);
432 close (fd);
434 else
436 #endif
438 if ((resource = get_resource (file)))
440 extract_resource (resource, path);
441 g_resource_unref (resource);
443 else
445 g_printerr ("Don't know how to handle %s\n", file);
446 #ifndef HAVE_LIBELF
447 g_printerr ("gresource is built without elf support\n");
448 #endif
452 static gint
453 cmd_help (gboolean requested,
454 const gchar *command)
456 const gchar *description;
457 const gchar *synopsis;
458 gchar *option;
459 GString *string;
461 option = NULL;
463 string = g_string_new (NULL);
465 if (command == NULL)
468 else if (strcmp (command, "help") == 0)
470 description = _("Print help");
471 synopsis = "[COMMAND]";
474 else if (strcmp (command, "sections") == 0)
476 description = _("List sections containing resources in an elf FILE");
477 synopsis = "FILE";
480 else if (strcmp (command, "list") == 0)
482 description = _("List resources\n"
483 "If SECTION is given, only list resources in this section\n"
484 "If PATH is given, only list matching resources");
485 synopsis = "FILE [PATH]";
486 option = g_strdup_printf ("[--section %s]", _("SECTION"));
489 else if (strcmp (command, "details") == 0)
491 description = _("List resources with details\n"
492 "If SECTION is given, only list resources in this section\n"
493 "If PATH is given, only list matching resources\n"
494 "Details include the section, size and compression");
495 synopsis = "FILE [PATH]";
496 option = g_strdup_printf ("[--section %s]", _("SECTION"));
499 else if (strcmp (command, "extract") == 0)
501 description = _("Extract a resource file to stdout");
502 synopsis = "FILE PATH";
503 option = g_strdup_printf ("[--section %s]", _("SECTION"));
506 else
508 g_string_printf (string, _("Unknown command %s\n\n"), command);
509 requested = FALSE;
510 command = NULL;
513 if (command == NULL)
515 g_string_append (string,
516 _("Usage:\n"
517 " gresource [--section SECTION] COMMAND [ARGS...]\n"
518 "\n"
519 "Commands:\n"
520 " help Show this information\n"
521 " sections List resource sections\n"
522 " list List resources\n"
523 " details List resources with details\n"
524 " extract Extract a resource\n"
525 "\n"
526 "Use 'gresource help COMMAND' to get detailed help.\n\n"));
528 else
530 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
531 option ? option : "", option ? " " : "", command, synopsis[0] ? _(synopsis) : "", description);
533 g_string_append (string, _("Arguments:\n"));
535 if (option)
536 g_string_append (string,
537 _(" SECTION An (optional) elf section name\n"));
539 if (strstr (synopsis, "[COMMAND]"))
540 g_string_append (string,
541 _(" COMMAND The (optional) command to explain\n"));
543 if (strstr (synopsis, "FILE"))
545 if (strcmp (command, "sections") == 0)
546 g_string_append (string,
547 _(" FILE An elf file (a binary or a shared library)\n"));
548 else
549 g_string_append (string,
550 _(" FILE An elf file (a binary or a shared library)\n"
551 " or a compiled resource file\n"));
554 if (strstr (synopsis, "[PATH"))
555 g_string_append (string,
556 _(" PATH An (optional) resource path (may be partial)\n"));
557 else if (strstr (synopsis, "PATH"))
558 g_string_append (string,
559 _(" PATH A resource path\n"));
561 g_string_append (string, "\n");
564 if (requested)
565 g_print ("%s", string->str);
566 else
567 g_printerr ("%s\n", string->str);
569 g_free (option);
570 g_string_free (string, TRUE);
572 return requested ? 0 : 1;
575 /* main {{{1 */
578 main (int argc, char *argv[])
580 gchar *section = NULL;
581 gboolean details = FALSE;
582 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
584 #ifdef G_OS_WIN32
585 extern gchar *_glib_get_locale_dir (void);
586 gchar *tmp;
587 #endif
589 setlocale (LC_ALL, "");
590 textdomain (GETTEXT_PACKAGE);
592 #ifdef G_OS_WIN32
593 tmp = _glib_get_locale_dir ();
594 bindtextdomain (GETTEXT_PACKAGE, tmp);
595 g_free (tmp);
596 #else
597 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
598 #endif
600 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
601 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
602 #endif
604 g_type_init ();
606 if (argc < 2)
607 return cmd_help (FALSE, NULL);
609 if (argc > 3 && strcmp (argv[1], "--section") == 0)
611 section = argv[2];
612 argv = argv + 2;
613 argc -= 2;
616 if (strcmp (argv[1], "help") == 0)
617 return cmd_help (TRUE, argv[2]);
619 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
620 function = cmd_extract;
622 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
623 function = cmd_sections;
625 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
627 function = cmd_list;
628 details = FALSE;
630 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
632 function = cmd_list;
633 details = TRUE;
635 else
636 return cmd_help (FALSE, argv[1]);
638 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
640 return 0;
643 /* vim:set foldmethod=marker: */