Make GSettingsSchemaKey public
[platform/upstream/glib.git] / gio / gresource-tool.c
1 /*
2  * Copyright © 2012 Red Hat, Inc
3  *
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.
8  *
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.
13  *
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.
18  *
19  * Author: Matthias Clasen
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <locale.h>
32
33 #ifdef HAVE_LIBELF
34 #include <libelf.h>
35 #include <gelf.h>
36 #include <sys/mman.h>
37 #endif
38
39 #include <gio/gio.h>
40 #include <glib/gstdio.h>
41 #include <gi18n.h>
42
43 #ifdef G_OS_WIN32
44 #include "glib/glib-private.h"
45 #endif
46
47 /* GResource functions {{{1 */
48 static GResource *
49 get_resource (const gchar *file)
50 {
51   gchar *content;
52   gsize size;
53   GResource *resource;
54   GBytes *data;
55
56   resource = NULL;
57
58   if (g_file_get_contents (file, &content, &size, NULL))
59     {
60       data = g_bytes_new_take (content, size);
61       resource = g_resource_new_from_data (data, NULL);
62       g_bytes_unref (data);
63     }
64
65   return resource;
66 }
67
68 static void
69 list_resource (GResource   *resource,
70                const gchar *path,
71                const gchar *section,
72                const gchar *prefix,
73                gboolean     details)
74 {
75   gchar **children;
76   gsize size;
77   guint32 flags;
78   gint i;
79   gchar *child;
80   GError *error = NULL;
81   gint len;
82
83   children = g_resource_enumerate_children (resource, path, 0, &error);
84   if (error)
85     {
86       g_printerr ("%s\n", error->message);
87       g_error_free (error);
88       return;
89     }
90   for (i = 0; children[i]; i++)
91     {
92       child = g_strconcat (path, children[i], NULL);
93
94       len = MIN (strlen (child), strlen (prefix));
95       if (strncmp (child, prefix, len) != 0)
96         continue;
97
98       if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
99         {
100           if (details)
101             g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
102           else
103             g_print ("%s\n", child);
104         }
105       else
106         list_resource (resource, child, section, prefix, details);
107
108       g_free (child);
109     }
110   g_strfreev (children);
111 }
112
113 static void
114 extract_resource (GResource   *resource,
115                   const gchar *path)
116 {
117   GBytes *bytes;
118
119   bytes = g_resource_lookup_data (resource, path, 0, NULL);
120   if (bytes != NULL)
121     {
122       gconstpointer data;
123       gsize size, written;
124
125       data = g_bytes_get_data (bytes, &size);
126       written = fwrite (data, 1, size, stdout);
127       if (written < size)
128         g_printerr ("Data truncated\n");
129       g_bytes_unref (bytes);
130     }
131   else
132     {
133       g_printerr ("Can't find resource path %s\n", path);
134     }
135 }
136
137 /* Elf functions {{{1 */
138
139 #ifdef HAVE_LIBELF
140
141 static Elf *
142 get_elf (const gchar *file,
143          gint        *fd)
144 {
145   Elf *elf;
146
147   if (elf_version (EV_CURRENT) == EV_NONE )
148     return NULL;
149
150   *fd = g_open (file, O_RDONLY, 0);
151   if (*fd < 0)
152     return NULL;
153
154   elf = elf_begin (*fd, ELF_C_READ, NULL);
155   if (elf == NULL)
156     return NULL;
157
158   if (elf_kind (elf) != ELF_K_ELF)
159     return NULL;
160
161   return elf;
162 }
163
164 typedef gboolean (*SectionCallback) (GElf_Shdr   *shdr,
165                                      const gchar *name,
166                                      gpointer     data);
167
168 static void
169 elf_foreach_resource_section (Elf             *elf,
170                               SectionCallback  callback,
171                               gpointer         data)
172 {
173   size_t shstrndx, shnum;
174   size_t scnidx;
175   Elf_Scn *scn;
176   GElf_Shdr *shdr, shdr_mem;
177   const gchar *section_name;
178
179   elf_getshdrstrndx (elf, &shstrndx);
180   g_assert (shstrndx >= 0);
181
182   elf_getshdrnum (elf, &shnum);
183   g_assert (shnum >= 0);
184
185   for (scnidx = 1; scnidx < shnum; scnidx++)
186     {
187       scn = elf_getscn (elf, scnidx);
188       if (scn == NULL)
189         continue;
190
191       shdr = gelf_getshdr (scn, &shdr_mem);
192       if (shdr == NULL)
193         continue;
194
195       if (shdr->sh_type != SHT_PROGBITS)
196         continue;
197
198       section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
199       if (section_name == NULL ||
200           !g_str_has_prefix (section_name, ".gresource."))
201         continue;
202
203       if (!callback (shdr, section_name + strlen (".gresource."), data))
204         break;
205     }
206 }
207
208 static GResource *
209 resource_from_section (GElf_Shdr *shdr,
210                        int        fd)
211 {
212   gsize page_size, page_offset;
213   char *contents;
214   GResource *resource;
215
216   resource = NULL;
217
218   page_size = sysconf(_SC_PAGE_SIZE);
219   page_offset = shdr->sh_offset % page_size;
220   contents = mmap (NULL,  shdr->sh_size + page_offset,
221                    PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
222   if (contents != MAP_FAILED)
223     {
224       GBytes *bytes;
225
226       bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
227       resource = g_resource_new_from_data (bytes, NULL);
228       g_bytes_unref (bytes);
229     }
230   else
231     {
232       g_printerr ("Can't mmap resource section");
233     }
234
235   return resource;
236 }
237
238 typedef struct
239 {
240   int fd;
241   const gchar *section;
242   const gchar *path;
243   gboolean details;
244   gboolean found;
245 } CallbackData;
246
247 static gboolean
248 list_resources_cb (GElf_Shdr   *shdr,
249                    const gchar *section,
250                    gpointer     data)
251 {
252   CallbackData *d = data;
253   GResource *resource;
254
255   if (d->section && strcmp (section, d->section) != 0)
256     return TRUE;
257
258   d->found = TRUE;
259
260   resource = resource_from_section (shdr, d->fd);
261   list_resource (resource, "/",
262                  d->section ? "" : section,
263                  d->path,
264                  d->details);
265   g_resource_unref (resource);
266
267   if (d->section)
268     return FALSE;
269
270   return TRUE;
271 }
272
273 static void
274 elf_list_resources (Elf         *elf,
275                     int          fd,
276                     const gchar *section,
277                     const gchar *path,
278                     gboolean     details)
279 {
280   CallbackData data;
281
282   data.fd = fd;
283   data.section = section;
284   data.path = path;
285   data.details = details;
286   data.found = FALSE;
287
288   elf_foreach_resource_section (elf, list_resources_cb, &data);
289
290   if (!data.found)
291     g_printerr ("Can't find resource section %s\n", section);
292 }
293
294 static gboolean
295 extract_resource_cb (GElf_Shdr   *shdr,
296                      const gchar *section,
297                      gpointer     data)
298 {
299   CallbackData *d = data;
300   GResource *resource;
301
302   if (d->section && strcmp (section, d->section) != 0)
303     return TRUE;
304
305   d->found = TRUE;
306
307   resource = resource_from_section (shdr, d->fd);
308   extract_resource (resource, d->path);
309   g_resource_unref (resource);
310
311   return FALSE;
312 }
313
314 static void
315 elf_extract_resource (Elf         *elf,
316                       int          fd,
317                       const gchar *section,
318                       const gchar *path)
319 {
320   CallbackData data;
321
322   data.fd = fd;
323   data.section = section;
324   data.path = path;
325   data.found = FALSE;
326
327   elf_foreach_resource_section (elf, extract_resource_cb, &data);
328
329   if (!data.found)
330     g_printerr ("Can't find resource section %s\n", section);
331 }
332
333 static gboolean
334 print_section_name (GElf_Shdr   *shdr,
335                     const gchar *name,
336                     gpointer     data)
337 {
338   g_print ("%s\n", name);
339   return TRUE;
340 }
341
342 #endif /* HAVE_LIBELF */
343
344   /* Toplevel commands {{{1 */
345
346 static void
347 cmd_sections (const gchar *file,
348               const gchar *section,
349               const gchar *path,
350               gboolean     details)
351 {
352   GResource *resource;
353
354 #ifdef HAVE_LIBELF
355
356   Elf *elf;
357   gint fd;
358
359   if ((elf = get_elf (file, &fd)))
360     {
361       elf_foreach_resource_section (elf, print_section_name, NULL);
362       elf_end (elf);
363       close (fd);
364     }
365   else
366
367 #endif
368
369   if ((resource = get_resource (file)))
370     {
371       /* No sections */
372       g_resource_unref (resource);
373     }
374   else
375     {
376       g_printerr ("Don't know how to handle %s\n", file);
377 #ifndef HAVE_LIBELF
378       g_printerr ("gresource is built without elf support\n");
379 #endif
380     }
381 }
382
383 static void
384 cmd_list (const gchar *file,
385           const gchar *section,
386           const gchar *path,
387           gboolean     details)
388 {
389   GResource *resource;
390
391 #ifdef HAVE_LIBELF
392
393   Elf *elf;
394   int fd;
395
396   if ((elf = get_elf (file, &fd)))
397     {
398       elf_list_resources (elf, fd, section, path ? path : "", details);
399       elf_end (elf);
400       close (fd);
401     }
402   else
403
404 #endif
405
406   if ((resource = get_resource (file)))
407     {
408       list_resource (resource, "/", "", path ? path : "", details);
409       g_resource_unref (resource);
410     }
411   else
412     {
413       g_printerr ("Don't know how to handle %s\n", file);
414 #ifndef HAVE_LIBELF
415       g_printerr ("gresource is built without elf support\n");
416 #endif
417     }
418 }
419
420 static void
421 cmd_extract (const gchar *file,
422              const gchar *section,
423              const gchar *path,
424              gboolean     details)
425 {
426   GResource *resource;
427
428 #ifdef HAVE_LIBELF
429
430   Elf *elf;
431   int fd;
432
433   if ((elf = get_elf (file, &fd)))
434     {
435       elf_extract_resource (elf, fd, section, path);
436       elf_end (elf);
437       close (fd);
438     }
439   else
440
441 #endif
442
443   if ((resource = get_resource (file)))
444     {
445       extract_resource (resource, path);
446       g_resource_unref (resource);
447     }
448   else
449     {
450       g_printerr ("Don't know how to handle %s\n", file);
451 #ifndef HAVE_LIBELF
452       g_printerr ("gresource is built without elf support\n");
453 #endif
454     }
455 }
456
457 static gint
458 cmd_help (gboolean     requested,
459           const gchar *command)
460 {
461   const gchar *description;
462   const gchar *synopsis;
463   gchar *option;
464   GString *string;
465
466   option = NULL;
467
468   string = g_string_new (NULL);
469
470   if (command == NULL)
471     ;
472
473   else if (strcmp (command, "help") == 0)
474     {
475       description = _("Print help");
476       synopsis = _("[COMMAND]");
477     }
478
479   else if (strcmp (command, "sections") == 0)
480     {
481       description = _("List sections containing resources in an elf FILE");
482       synopsis = _("FILE");
483     }
484
485   else if (strcmp (command, "list") == 0)
486     {
487       description = _("List resources\n"
488                       "If SECTION is given, only list resources in this section\n"
489                       "If PATH is given, only list matching resources");
490       synopsis = _("FILE [PATH]");
491       option = g_strdup_printf ("[--section %s]", _("SECTION"));
492     }
493
494   else if (strcmp (command, "details") == 0)
495     {
496       description = _("List resources with details\n"
497                       "If SECTION is given, only list resources in this section\n"
498                       "If PATH is given, only list matching resources\n"
499                       "Details include the section, size and compression");
500       synopsis = _("FILE [PATH]");
501       option = g_strdup_printf ("[--section %s]", _("SECTION"));
502     }
503
504   else if (strcmp (command, "extract") == 0)
505     {
506       description = _("Extract a resource file to stdout");
507       synopsis = _("FILE PATH");
508       option = g_strdup_printf ("[--section %s]", _("SECTION"));
509     }
510
511   else
512     {
513       g_string_printf (string, _("Unknown command %s\n\n"), command);
514       requested = FALSE;
515       command = NULL;
516     }
517
518   if (command == NULL)
519     {
520       g_string_append (string,
521       _("Usage:\n"
522         "  gresource [--section SECTION] COMMAND [ARGS...]\n"
523         "\n"
524         "Commands:\n"
525         "  help                      Show this information\n"
526         "  sections                  List resource sections\n"
527         "  list                      List resources\n"
528         "  details                   List resources with details\n"
529         "  extract                   Extract a resource\n"
530         "\n"
531         "Use 'gresource help COMMAND' to get detailed help.\n\n"));
532     }
533   else
534     {
535       g_string_append_printf (string, _("Usage:\n  gresource %s%s%s %s\n\n%s\n\n"),
536                               option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
537
538       g_string_append (string, _("Arguments:\n"));
539
540       if (option)
541         g_string_append (string,
542                          _("  SECTION   An (optional) elf section name\n"));
543
544       if (strstr (synopsis, _("[COMMAND]")))
545         g_string_append (string,
546                        _("  COMMAND   The (optional) command to explain\n"));
547
548       if (strstr (synopsis, _("FILE")))
549         {
550           if (strcmp (command, "sections") == 0)
551             g_string_append (string,
552                              _("  FILE      An elf file (a binary or a shared library)\n"));
553           else
554             g_string_append (string,
555                              _("  FILE      An elf file (a binary or a shared library)\n"
556                                "            or a compiled resource file\n"));
557         }
558
559       if (strstr (synopsis, _("[PATH]")))
560         g_string_append (string,
561                        _("  PATH      An (optional) resource path (may be partial)\n"));
562       else if (strstr (synopsis, _("PATH")))
563         g_string_append (string,
564                        _("  PATH      A resource path\n"));
565
566       g_string_append (string, "\n");
567     }
568
569   if (requested)
570     g_print ("%s", string->str);
571   else
572     g_printerr ("%s\n", string->str);
573
574   g_free (option);
575   g_string_free (string, TRUE);
576
577   return requested ? 0 : 1;
578 }
579
580 /* main {{{1 */
581
582 int
583 main (int argc, char *argv[])
584 {
585   gchar *section = NULL;
586   gboolean details = FALSE;
587   void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
588
589 #ifdef G_OS_WIN32
590   gchar *tmp;
591 #endif
592
593   setlocale (LC_ALL, "");
594   textdomain (GETTEXT_PACKAGE);
595
596 #ifdef G_OS_WIN32
597   tmp = _glib_get_locale_dir ();
598   bindtextdomain (GETTEXT_PACKAGE, tmp);
599   g_free (tmp);
600 #else
601   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
602 #endif
603
604 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
605   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
606 #endif
607
608   if (argc < 2)
609     return cmd_help (FALSE, NULL);
610
611   if (argc > 3 && strcmp (argv[1], "--section") == 0)
612     {
613       section = argv[2];
614       argv = argv + 2;
615       argc -= 2;
616     }
617
618   if (strcmp (argv[1], "help") == 0)
619     return cmd_help (TRUE, argv[2]);
620
621   else if (argc == 4 && strcmp (argv[1], "extract") == 0)
622     function = cmd_extract;
623
624   else if (argc == 3 && strcmp (argv[1], "sections") == 0)
625     function = cmd_sections;
626
627   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
628     {
629       function = cmd_list;
630       details = FALSE;
631     }
632   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
633     {
634       function = cmd_list;
635       details = TRUE;
636     }
637   else
638     return cmd_help (FALSE, argv[1]);
639
640   (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
641
642   return 0;
643 }
644
645 /* vim:set foldmethod=marker: */