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