162bedaef3819dfe54d2fbb05443d2d7f07c3470
[metze/wireshark/wip.git] / epan / print_stream.c
1 /* print_stream.c
2  * Routines for print streams.
3  *
4  * Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #ifdef _WIN32
30 #include <windows.h>
31 #endif
32
33 #include <glib.h>
34
35 #include <epan/print_stream.h>
36
37 #include <epan/ps.h>
38
39 #include <wsutil/file_util.h>
40
41 static FILE *
42 open_print_dest(gboolean to_file, const char *dest)
43 {
44     FILE *fh;
45
46     /* Open the file or command for output */
47     if (to_file)
48         fh = ws_fopen(dest, "w");
49     else
50         fh = popen(dest, "w");
51
52     return fh;
53 }
54
55 static gboolean
56 close_print_dest(gboolean to_file, FILE *fh)
57 {
58     /* Close the file or command */
59     if (to_file)
60         return (fclose(fh) == 0);
61     else
62         return (pclose(fh) == 0);
63 }
64
65 /* Some formats need stuff at the beginning of the output */
66 gboolean
67 print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
68 {
69     return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
70 }
71
72 gboolean
73 print_line(print_stream_t *self, int indent, const char *line)
74 {
75     return (self->ops->print_line)(self, indent, line);
76 }
77
78 /* Insert bookmark */
79 gboolean
80 print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
81 {
82     return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
83 }
84
85 gboolean
86 new_page(print_stream_t *self)
87 {
88     return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
89 }
90
91 /* Some formats need stuff at the end of the output */
92 gboolean
93 print_finale(print_stream_t *self)
94 {
95     return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
96 }
97
98 gboolean
99 destroy_print_stream(print_stream_t *self)
100 {
101     return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
102 }
103
104 typedef struct {
105     gboolean  to_file;
106     FILE     *fh;
107 } output_text;
108
109 #define MAX_INDENT    160
110
111 #ifdef _WIN32
112 static char *to_codeset = "UTF-16LE";
113 #else
114 static char *tty_codeset = NULL;
115 static char *to_codeset = NULL;
116 #endif
117
118 static gboolean
119 print_line_text(print_stream_t *self, int indent, const char *line)
120 {
121     static char  spaces[MAX_INDENT];
122     size_t ret;
123
124     output_text *output = (output_text *)self->data;
125     unsigned int num_spaces;
126
127     /* should be space, if NUL -> initialize */
128     if (!spaces[0]) {
129         int i;
130
131         for (i = 0; i < MAX_INDENT; i++)
132             spaces[i] = ' ';
133     }
134
135     /* Prepare the tabs for printing, depending on tree level */
136     num_spaces = indent * 4;
137     if (num_spaces > MAX_INDENT)
138         num_spaces = MAX_INDENT;
139
140     ret = fwrite(spaces, 1, num_spaces, output->fh);
141     if (ret == num_spaces) {
142         gchar *tty_out = NULL;
143
144 #ifndef _WIN32
145         /* Is there a more reliable way to do this? */
146         if (!tty_codeset) {
147             const gchar *charset;
148             gboolean is_utf8;
149
150             is_utf8 = g_get_charset(&charset);
151             tty_codeset = g_strdup(charset);
152             if (!is_utf8) {
153                 to_codeset = tty_codeset;
154             }
155         }
156 #endif
157
158         if (ws_isatty(ws_fileno(output->fh)) && to_codeset) {
159             /* XXX Allocating a fresh buffer every line probably isn't the
160              * most efficient way to do this. However, this has the side
161              * effect of scrubbing invalid output.
162              */
163             tty_out = g_convert_with_fallback(line, -1, to_codeset, "UTF-8", "?", NULL, NULL, NULL);
164         }
165
166         if (tty_out) {
167 #ifdef _WIN32
168             DWORD out_len = (DWORD) wcslen((wchar_t *) tty_out);
169             WriteConsoleW((HANDLE)_get_osfhandle(_fileno(output->fh)), tty_out, out_len, &out_len, NULL);
170 #else
171             fputs(tty_out, output->fh);
172 #endif
173             g_free(tty_out);
174         } else {
175             fputs(line, output->fh);
176         }
177         putc('\n', output->fh);
178     }
179     return !ferror(output->fh);
180 }
181
182 static gboolean
183 new_page_text(print_stream_t *self)
184 {
185     output_text *output = (output_text *)self->data;
186
187     fputs("\f", output->fh);
188     return !ferror(output->fh);
189 }
190
191 static gboolean
192 destroy_text(print_stream_t *self)
193 {
194     output_text *output = (output_text *)self->data;
195     gboolean     ret;
196
197     ret = close_print_dest(output->to_file, output->fh);
198     g_free(output);
199     g_free(self);
200     return ret;
201 }
202
203 static const print_stream_ops_t print_text_ops = {
204     NULL,            /* preamble */
205     print_line_text,
206     NULL,            /* bookmark */
207     new_page_text,
208     NULL,            /* finale */
209     destroy_text
210 };
211
212 static print_stream_t *
213 print_stream_text_alloc(gboolean to_file, FILE *fh)
214 {
215     print_stream_t *stream;
216     output_text    *output;
217
218     output          = (output_text *)g_malloc(sizeof *output);
219     output->to_file = to_file;
220     output->fh      = fh;
221     stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
222     stream->ops     = &print_text_ops;
223     stream->data    = output;
224
225     return stream;
226 }
227
228 print_stream_t *
229 print_stream_text_new(gboolean to_file, const char *dest)
230 {
231     FILE *fh;
232
233     fh = open_print_dest(to_file, dest);
234     if (fh == NULL)
235         return NULL;
236
237     return print_stream_text_alloc(to_file, fh);
238 }
239
240 print_stream_t *
241 print_stream_text_stdio_new(FILE *fh)
242 {
243     return print_stream_text_alloc(TRUE, fh);
244 }
245
246 typedef struct {
247     gboolean  to_file;
248     FILE     *fh;
249 } output_ps;
250
251 #define MAX_PS_LINE_LENGTH 256
252
253 static
254 void ps_clean_string(char *out, const char *in, int outbuf_size)
255 {
256     int  rd, wr;
257     char c;
258
259     if (in == NULL) {
260         out[0] = '\0';
261         return;
262     }
263
264     for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
265         c = in[rd];
266         switch (c) {
267         case '(':
268         case ')':
269         case '\\':
270             out[wr] = '\\';
271             out[++wr] = c;
272             break;
273
274         default:
275             out[wr] = c;
276             break;
277         }
278
279         if (c == 0) {
280             break;
281         }
282     }
283 }
284
285 static gboolean
286 print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
287 {
288     output_ps *output = (output_ps *)self->data;
289     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
290
291     print_ps_preamble(output->fh);
292
293     fputs("%% the page title\n", output->fh);
294     ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
295     fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
296     fputs("\n", output->fh);
297     return !ferror(output->fh);
298 }
299
300 static gboolean
301 print_line_ps(print_stream_t *self, int indent, const char *line)
302 {
303     output_ps *output = (output_ps *)self->data;
304     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
305
306     ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
307     fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
308     return !ferror(output->fh);
309 }
310
311 static gboolean
312 print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
313 {
314     output_ps *output = (output_ps *)self->data;
315     char       psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
316
317     /*
318      * See the Adobe "pdfmark reference":
319      *
320      *  http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
321      *
322      * The pdfmark stuff tells code that turns PostScript into PDF
323      * things that it should do.
324      *
325      * The /OUT stuff creates a bookmark that goes to the
326      * destination with "name" as the name and "title" as the title.
327      *
328      * The "/DEST" creates the destination.
329      */
330     ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
331     fprintf(output->fh, "[/Dest /%s /Title (%s)   /OUT pdfmark\n", name,
332           psbuffer);
333     fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
334           output->fh);
335     fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
336           output->fh);
337     fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
338     return !ferror(output->fh);
339 }
340
341 static gboolean
342 new_page_ps(print_stream_t *self)
343 {
344     output_ps *output = (output_ps *)self->data;
345
346     fputs("formfeed\n", output->fh);
347     return !ferror(output->fh);
348 }
349
350 static gboolean
351 print_finale_ps(print_stream_t *self)
352 {
353     output_ps *output = (output_ps *)self->data;
354
355     print_ps_finale(output->fh);
356     return !ferror(output->fh);
357 }
358
359 static gboolean
360 destroy_ps(print_stream_t *self)
361 {
362     output_ps *output = (output_ps *)self->data;
363     gboolean   ret;
364
365     ret = close_print_dest(output->to_file, output->fh);
366     g_free(output);
367     g_free(self);
368     return ret;
369 }
370
371 static const print_stream_ops_t print_ps_ops = {
372     print_preamble_ps,
373     print_line_ps,
374     print_bookmark_ps,
375     new_page_ps,
376     print_finale_ps,
377     destroy_ps
378 };
379
380 static print_stream_t *
381 print_stream_ps_alloc(gboolean to_file, FILE *fh)
382 {
383     print_stream_t *stream;
384     output_ps      *output;
385
386     output          = (output_ps *)g_malloc(sizeof *output);
387     output->to_file = to_file;
388     output->fh      = fh;
389     stream          = (print_stream_t *)g_malloc(sizeof (print_stream_t));
390     stream->ops     = &print_ps_ops;
391     stream->data    = output;
392
393     return stream;
394 }
395
396 print_stream_t *
397 print_stream_ps_new(gboolean to_file, const char *dest)
398 {
399     FILE *fh;
400
401     fh = open_print_dest(to_file, dest);
402     if (fh == NULL)
403         return NULL;
404
405     return print_stream_ps_alloc(to_file, fh);
406 }
407
408 print_stream_t *
409 print_stream_ps_stdio_new(FILE *fh)
410 {
411     return print_stream_ps_alloc(TRUE, fh);
412 }
413
414 /*
415  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
416  *
417  * Local variables:
418  * c-basic-offset: 4
419  * tab-width: 8
420  * indent-tabs-mode: nil
421  * End:
422  *
423  * vi: set shiftwidth=4 tabstop=8 expandtab:
424  * :indentSize=4:tabSize=8:noTabs=true:
425  */