"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / tools / gsf.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 #include <gsf/gsf-infile-msole.h>
4 #include <gsf/gsf-infile-tar.h>
5 #include <gsf/gsf-infile-zip.h>
6 #include <gsf/gsf-infile.h>
7 #include <gsf/gsf-input-stdio.h>
8 #include <gsf/gsf-utils.h>
9 #include <gsf/gsf-doc-meta-data.h>
10 #include <gsf/gsf-msole-utils.h>
11 #include <glib/gi18n.h>
12 #include <string.h>
13
14 #define GETTEXT_PACKAGE NULL /* FIXME */
15
16 static gboolean show_version;
17
18 static GOptionEntry const gsf_options [] = { 
19         {
20                 "version", 'v',
21                 0, G_OPTION_ARG_NONE, &show_version,
22                 N_("Display program version"),
23                 NULL
24         },
25
26         /* ---------------------------------------- */
27
28         { NULL, 0, 0, 0, NULL, NULL, NULL} 
29 };
30
31 /* ------------------------------------------------------------------------- */
32
33 static GsfInfile *
34 open_archive (char const *filename)
35 {
36         GsfInfile *infile;
37         GError *error = NULL;   
38         GsfInput *src;
39         char *display_name;
40
41         src = gsf_input_stdio_new (filename, &error);
42         if (error) {
43                 display_name = g_filename_display_name (filename);
44                 g_printerr (_("%s: Failed to open %s: %s\n"),
45                             g_get_prgname (),
46                             display_name,
47                             error->message);
48                 g_free (display_name);
49                 return NULL;
50         }
51
52         infile = gsf_infile_zip_new (src, NULL);
53         if (infile)
54                 return infile;
55
56         infile = gsf_infile_msole_new (src, NULL);
57         if (infile)
58                 return infile;
59
60         infile = gsf_infile_tar_new (src, NULL);
61         if (infile)
62                 return infile;
63
64         display_name = g_filename_display_name (filename);
65         g_printerr (_("%s: Failed to recognize %s as an archive\n"),
66                     g_get_prgname (),
67                     display_name);
68         g_free (display_name);
69         return NULL;
70 }
71
72 /* ------------------------------------------------------------------------- */
73
74 static GsfInput *
75 find_member (GsfInfile *arch, char const *name)
76 {
77         char const *slash = strchr (name, '/');
78
79         if (slash) {
80                 char *dirname = g_strndup (name, slash - name);
81                 GsfInput *member;
82                 GsfInfile *dir;
83
84                 member = gsf_infile_child_by_name (arch, dirname);
85                 g_free (dirname);
86                 if (!member)
87                         return NULL;
88                 dir = GSF_INFILE (member);
89                 member = find_member (dir, slash + 1);
90                 g_object_unref (dir);
91                 return member;
92         } else {
93                 return gsf_infile_child_by_name (arch, name);
94         }
95 }
96
97 /* ------------------------------------------------------------------------- */
98
99 static int
100 gsf_help (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
101 {
102         g_print (_("Available subcommands are...\n"));
103         g_print (_("* cat        output one or more files in archive\n"));
104         g_print (_("* dump       dump one or more files in archive as hex\n"));
105         g_print (_("* help       list subcommands\n"));
106         g_print (_("* list       list files in archive\n"));
107         g_print (_("* listprops  list document properties in archive\n"));
108         g_print (_("* props      print specified document properties\n"));
109         return 0;
110 }
111
112 /* ------------------------------------------------------------------------- */
113
114 static void
115 ls_R (GsfInput *input, char const *prefix)
116 {
117         char const *name = gsf_input_name (input);
118         GsfInfile *infile = GSF_IS_INFILE (input) ? GSF_INFILE (input) : NULL;
119         gboolean is_dir = infile && gsf_infile_num_children (infile) > 0;
120         char *full_name;
121         char *new_prefix;
122
123         if (prefix) {
124                 char *display_name = name ?
125                         g_filename_display_name (name)
126                         : g_strdup ("?");
127                 full_name = g_strconcat (prefix,
128                                          display_name,
129                                          NULL);
130                 new_prefix = g_strconcat (full_name, "/", NULL);
131                 g_free (display_name);
132         } else {
133                 full_name = g_strdup ("*root*");
134                 new_prefix = g_strdup ("");
135         }
136
137         g_print ("%c %10" GSF_OFF_T_FORMAT " %s\n",
138                  (is_dir ? 'd' : 'f'),
139                  gsf_input_size (input),
140                  full_name);
141
142         if (is_dir) {
143                 int i;
144                 for (i = 0 ; i < gsf_infile_num_children (infile) ; i++) {
145                         GsfInput *child = gsf_infile_child_by_index (infile, i);
146                         /* We can get NULL here in case of file corruption.  */
147                         if (child) {
148                                 ls_R (child, new_prefix);
149                                 g_object_unref (child);
150                         }
151                 }
152         }
153
154         g_free (full_name);
155         g_free (new_prefix);
156 }
157
158 static int
159 gsf_list (int argc, char **argv)
160 {
161         int i;
162
163         for (i = 0; i < argc; i++) {
164                 char const *filename = argv[i];
165                 char *display_name;
166                 GsfInfile *infile = open_archive (filename);
167                 if (!infile)
168                         return 1;
169
170                 if (i > 0)
171                         g_print ("\n");
172
173                 display_name = g_filename_display_name (filename);
174                 g_print ("%s:\n", display_name);
175                 g_free (display_name);
176
177                 ls_R (GSF_INPUT (infile), NULL);
178                 g_object_unref (infile);
179         }
180
181         return 0;
182 }
183
184 /* ------------------------------------------------------------------------- */
185
186 static int
187 gsf_dump (int argc, char **argv, gboolean hex)
188 {
189         char const *filename;
190         GsfInfile *infile;
191         int i;
192         int res = 0;
193
194         if (argc < 2)
195                 return 1;
196
197         filename = argv[0];
198         infile = open_archive (filename);
199         if (!infile)
200                 return 1;
201
202         for (i = 1; i < argc; i++) {
203                 char const *name = argv[i];
204                 GsfInput *member = find_member (infile, name);
205                 if (!member) {
206                         char *display_name = g_filename_display_name (name);
207                         g_print ("%s: archive has no member %s\n",
208                                  g_get_prgname (), display_name);
209                         g_free (display_name);
210                         res = 1;
211                         break;
212                 }
213
214                 if (hex) {
215                         char *display_name = g_filename_display_name (name);
216                         g_print ("%s:\n", display_name);
217                         g_free (display_name);
218                 }
219                 gsf_input_dump (member, hex);
220                 g_object_unref (member);
221         }
222
223         g_object_unref (infile);
224         return res;
225 }
226
227 static GsfDocMetaData *
228 get_meta_data (GsfInfile *infile, const char *filename)
229 {
230         GsfDocMetaData *meta_data = gsf_doc_meta_data_new ();
231
232         if (GSF_IS_INFILE_MSOLE (infile)) {
233                 GsfInput *in;
234                 GError *err;
235
236                 in = gsf_infile_child_by_name (infile, "\05SummaryInformation");
237                 if (NULL != in) {
238                         err = gsf_msole_metadata_read (in, meta_data);
239                         if (err != NULL) {
240                                 g_warning ("'%s' error: %s", filename, err->message);
241                                 g_error_free (err);
242                                 err = NULL;
243                         }
244                         g_object_unref (G_OBJECT (in));
245                 }
246
247                 in = gsf_infile_child_by_name (infile, "\05DocumentSummaryInformation");
248                 if (NULL != in) {
249                         err = gsf_msole_metadata_read (in, meta_data);
250                         if (err != NULL) {
251                                 g_warning ("'%s' error: %s", filename, err->message);
252                                 g_error_free (err);
253                                 err = NULL;
254                         }
255
256                         g_object_unref (G_OBJECT (in));
257                 }
258         }
259
260         return meta_data;
261 }
262
263 static int
264 gsf_dump_props (int argc, char **argv)
265 {
266         GsfInfile *infile;
267         GsfDocMetaData *meta_data;
268         char const *filename;
269         int res = 0;
270         int i;
271
272         if (argc < 2)
273                 return 1;
274
275         filename = argv[0];
276         infile = open_archive (filename);
277         if (!infile)
278                 return 1;
279
280         meta_data = get_meta_data (infile, filename);
281
282         for (i = 1; i < argc; i++) {
283                 const char *name = argv[i];
284                 GsfDocProp const *prop =
285                         gsf_doc_meta_data_lookup (meta_data, name);
286                 if (prop) {
287                         if (argc > 2)
288                                 g_print ("%s: ", name);
289                         gsf_doc_prop_dump (prop);
290                 } else {
291                         g_printerr (_("No property named %s\n"), name);
292                 }
293         }
294
295         g_object_unref (meta_data);
296         g_object_unref (infile);
297         return res;
298 }
299
300 static void
301 cb_collect_names (gpointer key,
302                   G_GNUC_UNUSED gpointer value,
303                   gpointer user)
304 {
305         const char *name = key;
306         GSList **names = user;
307
308         *names = g_slist_prepend (*names, g_strdup (name));
309 }
310
311 static void
312 cb_print_names (const char *name)
313 {
314         g_print ("%s\n", name);
315 }
316
317 static int
318 gsf_list_props (int argc, char **argv)
319 {
320         GsfInfile *infile;
321         GsfDocMetaData *meta_data;
322         char const *filename;
323         GSList *names = NULL;
324
325         if (argc != 1)
326                 return 1;
327
328         filename = argv[0];
329         infile = open_archive (filename);
330         if (!infile)
331                 return 1;
332
333         meta_data = get_meta_data (infile, filename);
334         gsf_doc_meta_data_foreach (meta_data, cb_collect_names, &names);
335         names = g_slist_sort (names, (GCompareFunc)strcmp);
336         g_slist_foreach (names, (GFunc)cb_print_names, NULL);
337         g_slist_free (names);
338
339         g_object_unref (meta_data);
340         g_object_unref (infile);
341         return 0;
342 }
343
344 /* ------------------------------------------------------------------------- */
345
346 int
347 main (int argc, char **argv)
348 {
349         GOptionContext *ocontext;
350         GError *error = NULL;   
351         char const *usage;
352         char const *cmd;
353         char const *me = (argv[0] ? argv[0] : "gsf");
354
355         g_set_prgname (me);
356         gsf_init ();
357
358 #if 0
359         bindtextdomain (GETTEXT_PACKAGE, gnm_locale_dir ());
360         textdomain (GETTEXT_PACKAGE);
361         setlocale (LC_ALL, "");
362 #endif
363
364         usage = _("SUBCOMMAND ARCHIVE...");
365         ocontext = g_option_context_new (usage);
366         g_option_context_add_main_entries (ocontext, gsf_options, GETTEXT_PACKAGE);
367         g_option_context_parse (ocontext, &argc, &argv, &error);
368         g_option_context_free (ocontext);
369
370         if (error) {
371                 g_printerr (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
372                             error->message, me);
373                 g_error_free (error);
374                 return 1;
375         }
376
377         if (show_version) {
378                 g_print (_("gsf version %d.%d.%d\n"),
379                          libgsf_major_version, libgsf_minor_version, libgsf_micro_version);
380                 return 0;
381         }
382
383         if (argc <= 1) {
384                 g_printerr (_("Usage: %s %s\n"), me, usage);
385                 return 1;
386         }
387
388         cmd = argv[1];
389
390         if (strcmp (cmd, "help") == 0)
391                 return gsf_help (argc - 2, argv + 2);
392
393         if (strcmp (cmd, "list") == 0 || strcmp (cmd, "l") == 0)
394                 return gsf_list (argc - 2, argv + 2);
395
396         if (strcmp (cmd, "cat") == 0)
397                 return gsf_dump (argc - 2, argv + 2, FALSE);
398         if (strcmp (cmd, "dump") == 0)
399                 return gsf_dump (argc - 2, argv + 2, TRUE);
400         if (strcmp (cmd, "props") == 0)
401                 return gsf_dump_props (argc - 2, argv + 2);
402         if (strcmp (cmd, "listprops") == 0)
403                 return gsf_list_props (argc - 2, argv + 2);
404
405         g_printerr (_("Run '%s help' to see a list subcommands.\n"), me);
406         return 1;
407 }