aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/CMakeLists.txt1
-rw-r--r--epan/Makefile.common2
-rw-r--r--epan/print.c368
-rw-r--r--epan/print.h39
-rw-r--r--epan/print_stream.c367
-rw-r--r--epan/print_stream.h73
6 files changed, 463 insertions, 387 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt
index 7183de42bc..9827d71679 100644
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -1586,6 +1586,7 @@ set(LIBWIRESHARK_FILES
packet-range.c
packet.c
print.c
+ print_stream.c
prefs.c
proto.c
ps.c
diff --git a/epan/Makefile.common b/epan/Makefile.common
index e0d4d333e9..7d193a40d4 100644
--- a/epan/Makefile.common
+++ b/epan/Makefile.common
@@ -74,6 +74,7 @@ LIBWIRESHARK_SRC = \
packet.c \
prefs.c \
print.c \
+ print_stream.c \
proto.c \
range.c \
reassemble.c \
@@ -226,6 +227,7 @@ LIBWIRESHARK_INCLUDES = \
params.h \
ppptypes.h \
print.h \
+ print_stream.h \
prefs.h \
prefs-int.h \
proto.h \
diff --git a/epan/print.c b/epan/print.c
index 4336c6ad00..b0e0f0c7be 100644
--- a/epan/print.c
+++ b/epan/print.c
@@ -40,10 +40,8 @@
#include <epan/expert.h>
#include <epan/packet-range.h>
-#include "print.h"
-#include "ps.h"
+#include <epan/print.h>
#include "version_info.h"
-#include <wsutil/file_util.h>
#include <epan/charsets.h>
#include <epan/dissectors/packet-data.h>
#include <epan/dissectors/packet-frame.h>
@@ -98,40 +96,12 @@ static const guint8 *get_field_data(GSList *src_list, field_info *fi);
static void write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi);
static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
guint length, packet_char_enc encoding);
-static void ps_clean_string(char *out, const char *in,
- int outbuf_size);
static void print_escaped_xml(FILE *fh, const char *unescaped_string);
static void print_pdml_geninfo(proto_tree *tree, FILE *fh);
static void proto_tree_get_node_field_values(proto_node *node, gpointer data);
-static FILE *
-open_print_dest(gboolean to_file, const char *dest)
-{
- FILE *fh;
-
- /* Open the file or command for output */
- if (to_file)
- fh = ws_fopen(dest, "w");
- else
- fh = popen(dest, "w");
-
- return fh;
-}
-
-static gboolean
-close_print_dest(gboolean to_file, FILE *fh)
-{
- /* Close the file or command */
- if (to_file)
- return (fclose(fh) == 0);
- else
- return (pclose(fh) == 0);
-}
-
-#define MAX_PS_LINE_LENGTH 256
-
gboolean
proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
print_stream_t *stream)
@@ -154,8 +124,6 @@ proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
return data.success;
}
-#define MAX_INDENT 160
-
/* Print a tree's data, and any child nodes. */
static void
proto_tree_print_node(proto_node *node, gpointer data)
@@ -1049,325 +1017,6 @@ print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
return TRUE;
}
-static
-void ps_clean_string(char *out, const char *in, int outbuf_size)
-{
- int rd, wr;
- char c;
-
- if (in == NULL) {
- out[0] = '\0';
- return;
- }
-
- for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
- c = in[rd];
- switch (c) {
- case '(':
- case ')':
- case '\\':
- out[wr] = '\\';
- out[++wr] = c;
- break;
-
- default:
- out[wr] = c;
- break;
- }
-
- if (c == 0) {
- break;
- }
- }
-}
-
-/* Some formats need stuff at the beginning of the output */
-gboolean
-print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
-{
- return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
-}
-
-gboolean
-print_line(print_stream_t *self, int indent, const char *line)
-{
- return (self->ops->print_line)(self, indent, line);
-}
-
-/* Insert bookmark */
-gboolean
-print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
-{
- return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
-}
-
-gboolean
-new_page(print_stream_t *self)
-{
- return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
-}
-
-/* Some formats need stuff at the end of the output */
-gboolean
-print_finale(print_stream_t *self)
-{
- return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
-}
-
-gboolean
-destroy_print_stream(print_stream_t *self)
-{
- return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
-}
-
-typedef struct {
- gboolean to_file;
- FILE *fh;
-} output_text;
-
-static gboolean
-print_line_text(print_stream_t *self, int indent, const char *line)
-{
- static char spaces[MAX_INDENT];
- size_t ret;
-
- output_text *output = (output_text *)self->data;
- unsigned int num_spaces;
-
- /* should be space, if NUL -> initialize */
- if (!spaces[0]) {
- int i;
-
- for (i = 0; i < MAX_INDENT; i++)
- spaces[i] = ' ';
- }
-
- /* Prepare the tabs for printing, depending on tree level */
- num_spaces = indent * 4;
- if (num_spaces > MAX_INDENT)
- num_spaces = MAX_INDENT;
-
- ret = fwrite(spaces, 1, num_spaces, output->fh);
- if (ret == num_spaces) {
- fputs(line, output->fh);
- putc('\n', output->fh);
- }
- return !ferror(output->fh);
-}
-
-static gboolean
-new_page_text(print_stream_t *self)
-{
- output_text *output = (output_text *)self->data;
-
- fputs("\f", output->fh);
- return !ferror(output->fh);
-}
-
-static gboolean
-destroy_text(print_stream_t *self)
-{
- output_text *output = (output_text *)self->data;
- gboolean ret;
-
- ret = close_print_dest(output->to_file, output->fh);
- g_free(output);
- g_free(self);
- return ret;
-}
-
-static const print_stream_ops_t print_text_ops = {
- NULL, /* preamble */
- print_line_text,
- NULL, /* bookmark */
- new_page_text,
- NULL, /* finale */
- destroy_text
-};
-
-static print_stream_t *
-print_stream_text_alloc(gboolean to_file, FILE *fh)
-{
- print_stream_t *stream;
- output_text *output;
-
- output = (output_text *)g_malloc(sizeof *output);
- output->to_file = to_file;
- output->fh = fh;
- stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
- stream->ops = &print_text_ops;
- stream->data = output;
-
- return stream;
-}
-
-print_stream_t *
-print_stream_text_new(gboolean to_file, const char *dest)
-{
- FILE *fh;
-
- fh = open_print_dest(to_file, dest);
- if (fh == NULL)
- return NULL;
-
- return print_stream_text_alloc(to_file, fh);
-}
-
-print_stream_t *
-print_stream_text_stdio_new(FILE *fh)
-{
- return print_stream_text_alloc(TRUE, fh);
-}
-
-typedef struct {
- gboolean to_file;
- FILE *fh;
-} output_ps;
-
-static gboolean
-print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
-{
- output_ps *output = (output_ps *)self->data;
- char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
- print_ps_preamble(output->fh);
-
- fputs("%% the page title\n", output->fh);
- ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
- fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
- fputs("\n", output->fh);
- return !ferror(output->fh);
-}
-
-static gboolean
-print_line_ps(print_stream_t *self, int indent, const char *line)
-{
- output_ps *output = (output_ps *)self->data;
- char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
- ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
- fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
- return !ferror(output->fh);
-}
-
-static gboolean
-print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
-{
- output_ps *output = (output_ps *)self->data;
- char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
-
- /*
- * See the Adobe "pdfmark reference":
- *
- * http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
- *
- * The pdfmark stuff tells code that turns PostScript into PDF
- * things that it should do.
- *
- * The /OUT stuff creates a bookmark that goes to the
- * destination with "name" as the name and "title" as the title.
- *
- * The "/DEST" creates the destination.
- */
- ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
- fprintf(output->fh, "[/Dest /%s /Title (%s) /OUT pdfmark\n", name,
- psbuffer);
- fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
- output->fh);
- fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
- output->fh);
- fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
- return !ferror(output->fh);
-}
-
-static gboolean
-new_page_ps(print_stream_t *self)
-{
- output_ps *output = (output_ps *)self->data;
-
- fputs("formfeed\n", output->fh);
- return !ferror(output->fh);
-}
-
-static gboolean
-print_finale_ps(print_stream_t *self)
-{
- output_ps *output = (output_ps *)self->data;
-
- print_ps_finale(output->fh);
- return !ferror(output->fh);
-}
-
-static gboolean
-destroy_ps(print_stream_t *self)
-{
- output_ps *output = (output_ps *)self->data;
- gboolean ret;
-
- ret = close_print_dest(output->to_file, output->fh);
- g_free(output);
- g_free(self);
- return ret;
-}
-
-static const print_stream_ops_t print_ps_ops = {
- print_preamble_ps,
- print_line_ps,
- print_bookmark_ps,
- new_page_ps,
- print_finale_ps,
- destroy_ps
-};
-
-static print_stream_t *
-print_stream_ps_alloc(gboolean to_file, FILE *fh)
-{
- print_stream_t *stream;
- output_ps *output;
-
- output = (output_ps *)g_malloc(sizeof *output);
- output->to_file = to_file;
- output->fh = fh;
- stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
- stream->ops = &print_ps_ops;
- stream->data = output;
-
- return stream;
-}
-
-print_stream_t *
-print_stream_ps_new(gboolean to_file, const char *dest)
-{
- FILE *fh;
-
- fh = open_print_dest(to_file, dest);
- if (fh == NULL)
- return NULL;
-
- return print_stream_ps_alloc(to_file, fh);
-}
-
-print_stream_t *
-print_stream_ps_stdio_new(FILE *fh)
-{
- return print_stream_ps_alloc(TRUE, fh);
-}
-
-output_fields_t* output_fields_new(void)
-{
- output_fields_t* fields = g_new(output_fields_t, 1);
- fields->print_header = FALSE;
- fields->separator = '\t';
- fields->occurrence = 'a';
- fields->aggregator = ',';
- fields->fields = NULL; /*Do lazy initialisation */
- fields->field_indicies = NULL;
- fields->field_values = NULL;
- fields->quote ='\0';
- fields->includes_col_fields = FALSE;
- return fields;
-}
-
gsize output_fields_num_fields(output_fields_t* fields)
{
g_assert(fields);
@@ -1851,6 +1500,21 @@ get_field_hex_value(GSList *src_list, field_info *fi)
}
}
+output_fields_t* output_fields_new(void)
+{
+ output_fields_t* fields = g_new(output_fields_t, 1);
+ fields->print_header = FALSE;
+ fields->separator = '\t';
+ fields->occurrence = 'a';
+ fields->aggregator = ',';
+ fields->fields = NULL; /*Do lazy initialisation */
+ fields->field_indicies = NULL;
+ fields->field_values = NULL;
+ fields->quote ='\0';
+ fields->includes_col_fields = FALSE;
+ return fields;
+}
+
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
diff --git a/epan/print.h b/epan/print.h
index 9832d575a4..816c401660 100644
--- a/epan/print.h
+++ b/epan/print.h
@@ -30,47 +30,16 @@
#include <epan/epan.h>
#include <epan/packet.h>
+#include <epan/print_stream.h>
+
#include <epan/packet-range.h>
+#include "ws_symbol_export.h"
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-/*
- * Print stream code; this provides a "print stream" class with subclasses
- * of various sorts. Additional subclasses might be implemented elsewhere.
- */
-struct print_stream;
-
-typedef struct print_stream_ops {
- gboolean (*print_preamble)(struct print_stream *self, gchar *filename, const char *version_string);
- gboolean (*print_line)(struct print_stream *self, int indent,
- const char *line);
- gboolean (*print_bookmark)(struct print_stream *self,
- const gchar *name, const gchar *title);
- gboolean (*new_page)(struct print_stream *self);
- gboolean (*print_finale)(struct print_stream *self);
- gboolean (*destroy)(struct print_stream *self);
-} print_stream_ops_t;
-
-typedef struct print_stream {
- const print_stream_ops_t *ops;
- void *data;
-} print_stream_t;
-
-WS_DLL_PUBLIC print_stream_t *print_stream_text_new(gboolean to_file, const char *dest);
-WS_DLL_PUBLIC print_stream_t *print_stream_text_stdio_new(FILE *fh);
-WS_DLL_PUBLIC print_stream_t *print_stream_ps_new(gboolean to_file, const char *dest);
-WS_DLL_PUBLIC print_stream_t *print_stream_ps_stdio_new(FILE *fh);
-
-WS_DLL_PUBLIC gboolean print_preamble(print_stream_t *self, gchar *filename, const char *version_string);
-WS_DLL_PUBLIC gboolean print_line(print_stream_t *self, int indent, const char *line);
-WS_DLL_PUBLIC gboolean print_bookmark(print_stream_t *self, const gchar *name,
- const gchar *title);
-WS_DLL_PUBLIC gboolean new_page(print_stream_t *self);
-WS_DLL_PUBLIC gboolean print_finale(print_stream_t *self);
-WS_DLL_PUBLIC gboolean destroy_print_stream(print_stream_t *self);
-
/* print output format */
typedef enum {
PR_FMT_TEXT, /* plain text */
diff --git a/epan/print_stream.c b/epan/print_stream.c
new file mode 100644
index 0000000000..5f93072c98
--- /dev/null
+++ b/epan/print_stream.c
@@ -0,0 +1,367 @@
+/* print.c
+ * Routines for printing packet analysis trees.
+ *
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <epan/print_stream.h>
+
+#include <epan/ps.h>
+
+#include <wsutil/file_util.h>
+
+static FILE *
+open_print_dest(gboolean to_file, const char *dest)
+{
+ FILE *fh;
+
+ /* Open the file or command for output */
+ if (to_file)
+ fh = ws_fopen(dest, "w");
+ else
+ fh = popen(dest, "w");
+
+ return fh;
+}
+
+static gboolean
+close_print_dest(gboolean to_file, FILE *fh)
+{
+ /* Close the file or command */
+ if (to_file)
+ return (fclose(fh) == 0);
+ else
+ return (pclose(fh) == 0);
+}
+
+/* Some formats need stuff at the beginning of the output */
+gboolean
+print_preamble(print_stream_t *self, gchar *filename, const char *version_string)
+{
+ return self->ops->print_preamble ? (self->ops->print_preamble)(self, filename, version_string) : TRUE;
+}
+
+gboolean
+print_line(print_stream_t *self, int indent, const char *line)
+{
+ return (self->ops->print_line)(self, indent, line);
+}
+
+/* Insert bookmark */
+gboolean
+print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
+{
+ return self->ops->print_bookmark ? (self->ops->print_bookmark)(self, name, title) : TRUE;
+}
+
+gboolean
+new_page(print_stream_t *self)
+{
+ return self->ops->new_page ? (self->ops->new_page)(self) : TRUE;
+}
+
+/* Some formats need stuff at the end of the output */
+gboolean
+print_finale(print_stream_t *self)
+{
+ return self->ops->print_finale ? (self->ops->print_finale)(self) : TRUE;
+}
+
+gboolean
+destroy_print_stream(print_stream_t *self)
+{
+ return self->ops->destroy ? (self->ops->destroy)(self) : TRUE;
+}
+
+typedef struct {
+ gboolean to_file;
+ FILE *fh;
+} output_text;
+
+#define MAX_INDENT 160
+
+static gboolean
+print_line_text(print_stream_t *self, int indent, const char *line)
+{
+ static char spaces[MAX_INDENT];
+ size_t ret;
+
+ output_text *output = (output_text *)self->data;
+ unsigned int num_spaces;
+
+ /* should be space, if NUL -> initialize */
+ if (!spaces[0]) {
+ int i;
+
+ for (i = 0; i < MAX_INDENT; i++)
+ spaces[i] = ' ';
+ }
+
+ /* Prepare the tabs for printing, depending on tree level */
+ num_spaces = indent * 4;
+ if (num_spaces > MAX_INDENT)
+ num_spaces = MAX_INDENT;
+
+ ret = fwrite(spaces, 1, num_spaces, output->fh);
+ if (ret == num_spaces) {
+ fputs(line, output->fh);
+ putc('\n', output->fh);
+ }
+ return !ferror(output->fh);
+}
+
+static gboolean
+new_page_text(print_stream_t *self)
+{
+ output_text *output = (output_text *)self->data;
+
+ fputs("\f", output->fh);
+ return !ferror(output->fh);
+}
+
+static gboolean
+destroy_text(print_stream_t *self)
+{
+ output_text *output = (output_text *)self->data;
+ gboolean ret;
+
+ ret = close_print_dest(output->to_file, output->fh);
+ g_free(output);
+ g_free(self);
+ return ret;
+}
+
+static const print_stream_ops_t print_text_ops = {
+ NULL, /* preamble */
+ print_line_text,
+ NULL, /* bookmark */
+ new_page_text,
+ NULL, /* finale */
+ destroy_text
+};
+
+static print_stream_t *
+print_stream_text_alloc(gboolean to_file, FILE *fh)
+{
+ print_stream_t *stream;
+ output_text *output;
+
+ output = (output_text *)g_malloc(sizeof *output);
+ output->to_file = to_file;
+ output->fh = fh;
+ stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
+ stream->ops = &print_text_ops;
+ stream->data = output;
+
+ return stream;
+}
+
+print_stream_t *
+print_stream_text_new(gboolean to_file, const char *dest)
+{
+ FILE *fh;
+
+ fh = open_print_dest(to_file, dest);
+ if (fh == NULL)
+ return NULL;
+
+ return print_stream_text_alloc(to_file, fh);
+}
+
+print_stream_t *
+print_stream_text_stdio_new(FILE *fh)
+{
+ return print_stream_text_alloc(TRUE, fh);
+}
+
+typedef struct {
+ gboolean to_file;
+ FILE *fh;
+} output_ps;
+
+#define MAX_PS_LINE_LENGTH 256
+
+static
+void ps_clean_string(char *out, const char *in, int outbuf_size)
+{
+ int rd, wr;
+ char c;
+
+ if (in == NULL) {
+ out[0] = '\0';
+ return;
+ }
+
+ for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
+ c = in[rd];
+ switch (c) {
+ case '(':
+ case ')':
+ case '\\':
+ out[wr] = '\\';
+ out[++wr] = c;
+ break;
+
+ default:
+ out[wr] = c;
+ break;
+ }
+
+ if (c == 0) {
+ break;
+ }
+ }
+}
+
+static gboolean
+print_preamble_ps(print_stream_t *self, gchar *filename, const char *version_string)
+{
+ output_ps *output = (output_ps *)self->data;
+ char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+ print_ps_preamble(output->fh);
+
+ fputs("%% the page title\n", output->fh);
+ ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
+ fprintf(output->fh, "/ws_pagetitle (%s - Wireshark %s) def\n", psbuffer, version_string);
+ fputs("\n", output->fh);
+ return !ferror(output->fh);
+}
+
+static gboolean
+print_line_ps(print_stream_t *self, int indent, const char *line)
+{
+ output_ps *output = (output_ps *)self->data;
+ char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+ ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
+ fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
+ return !ferror(output->fh);
+}
+
+static gboolean
+print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
+{
+ output_ps *output = (output_ps *)self->data;
+ char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
+
+ /*
+ * See the Adobe "pdfmark reference":
+ *
+ * http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
+ *
+ * The pdfmark stuff tells code that turns PostScript into PDF
+ * things that it should do.
+ *
+ * The /OUT stuff creates a bookmark that goes to the
+ * destination with "name" as the name and "title" as the title.
+ *
+ * The "/DEST" creates the destination.
+ */
+ ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
+ fprintf(output->fh, "[/Dest /%s /Title (%s) /OUT pdfmark\n", name,
+ psbuffer);
+ fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
+ output->fh);
+ fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
+ output->fh);
+ fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
+ return !ferror(output->fh);
+}
+
+static gboolean
+new_page_ps(print_stream_t *self)
+{
+ output_ps *output = (output_ps *)self->data;
+
+ fputs("formfeed\n", output->fh);
+ return !ferror(output->fh);
+}
+
+static gboolean
+print_finale_ps(print_stream_t *self)
+{
+ output_ps *output = (output_ps *)self->data;
+
+ print_ps_finale(output->fh);
+ return !ferror(output->fh);
+}
+
+static gboolean
+destroy_ps(print_stream_t *self)
+{
+ output_ps *output = (output_ps *)self->data;
+ gboolean ret;
+
+ ret = close_print_dest(output->to_file, output->fh);
+ g_free(output);
+ g_free(self);
+ return ret;
+}
+
+static const print_stream_ops_t print_ps_ops = {
+ print_preamble_ps,
+ print_line_ps,
+ print_bookmark_ps,
+ new_page_ps,
+ print_finale_ps,
+ destroy_ps
+};
+
+static print_stream_t *
+print_stream_ps_alloc(gboolean to_file, FILE *fh)
+{
+ print_stream_t *stream;
+ output_ps *output;
+
+ output = (output_ps *)g_malloc(sizeof *output);
+ output->to_file = to_file;
+ output->fh = fh;
+ stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
+ stream->ops = &print_ps_ops;
+ stream->data = output;
+
+ return stream;
+}
+
+print_stream_t *
+print_stream_ps_new(gboolean to_file, const char *dest)
+{
+ FILE *fh;
+
+ fh = open_print_dest(to_file, dest);
+ if (fh == NULL)
+ return NULL;
+
+ return print_stream_ps_alloc(to_file, fh);
+}
+
+print_stream_t *
+print_stream_ps_stdio_new(FILE *fh)
+{
+ return print_stream_ps_alloc(TRUE, fh);
+}
diff --git a/epan/print_stream.h b/epan/print_stream.h
new file mode 100644
index 0000000000..3a326c45e8
--- /dev/null
+++ b/epan/print_stream.h
@@ -0,0 +1,73 @@
+/* print.h
+ * Definitions for printing packet analysis trees.
+ *
+ * Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PRINT_STREAM_H__
+#define __PRINT_STREAM_H__
+
+#include "ws_symbol_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Print stream code; this provides a "print stream" class with subclasses
+ * of various sorts. Additional subclasses might be implemented elsewhere.
+ */
+struct print_stream;
+
+typedef struct print_stream_ops {
+ gboolean (*print_preamble)(struct print_stream *self, gchar *filename, const char *version_string);
+ gboolean (*print_line)(struct print_stream *self, int indent,
+ const char *line);
+ gboolean (*print_bookmark)(struct print_stream *self,
+ const gchar *name, const gchar *title);
+ gboolean (*new_page)(struct print_stream *self);
+ gboolean (*print_finale)(struct print_stream *self);
+ gboolean (*destroy)(struct print_stream *self);
+} print_stream_ops_t;
+
+typedef struct print_stream {
+ const print_stream_ops_t *ops;
+ void *data;
+} print_stream_t;
+
+WS_DLL_PUBLIC print_stream_t *print_stream_text_new(gboolean to_file, const char *dest);
+WS_DLL_PUBLIC print_stream_t *print_stream_text_stdio_new(FILE *fh);
+WS_DLL_PUBLIC print_stream_t *print_stream_ps_new(gboolean to_file, const char *dest);
+WS_DLL_PUBLIC print_stream_t *print_stream_ps_stdio_new(FILE *fh);
+
+WS_DLL_PUBLIC gboolean print_preamble(print_stream_t *self, gchar *filename, const char *version_string);
+WS_DLL_PUBLIC gboolean print_line(print_stream_t *self, int indent, const char *line);
+WS_DLL_PUBLIC gboolean print_bookmark(print_stream_t *self, const gchar *name,
+ const gchar *title);
+WS_DLL_PUBLIC gboolean new_page(print_stream_t *self);
+WS_DLL_PUBLIC gboolean print_finale(print_stream_t *self);
+WS_DLL_PUBLIC gboolean destroy_print_stream(print_stream_t *self);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* print_stream.h */