+/* Print info for a 'geninfo' pseudo-protocol. This is required by
+ * the PDML spec. The information is contained in Ethereal's 'frame' protocol,
+ * but we produce a 'geninfo' protocol in the PDML to conform to spec.
+ * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
+static void
+print_pdml_geninfo(proto_tree *tree, FILE *fh)
+{
+ guint32 num, len, caplen;
+ nstime_t *timestamp;
+ GPtrArray *finfo_array;
+ field_info *frame_finfo;
+
+ /* Get frame protocol's finfo. */
+ finfo_array = proto_find_finfo(tree, proto_frame);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ frame_finfo = finfo_array->pdata[0];
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.number --> geninfo.num */
+ finfo_array = proto_find_finfo(tree, hf_frame_number);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ num = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.pkt_len --> geninfo.len */
+ finfo_array = proto_find_finfo(tree, hf_frame_packet_len);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ len = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.cap_len --> geninfo.caplen */
+ finfo_array = proto_find_finfo(tree, hf_frame_capture_len);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ caplen = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.time --> geninfo.timestamp */
+ finfo_array = proto_find_finfo(tree, hf_frame_arrival_time);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ timestamp = fvalue_get(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* Print geninfo start */
+ fprintf(fh,
+" <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%u\">\n",
+ frame_finfo->length);
+
+ /* Print geninfo.num */
+ fprintf(fh,
+" <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
+ num, num, frame_finfo->length);
+
+ /* Print geninfo.len */
+ fprintf(fh,
+" <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Packet Length\" value=\"%x\" size=\"%u\"/>\n",
+ len, len, frame_finfo->length);
+
+ /* Print geninfo.caplen */
+ fprintf(fh,
+" <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
+ caplen, caplen, frame_finfo->length);
+
+ /* Print geninfo.timestamp */
+ fprintf(fh,
+" <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
+ abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
+
+ /* Print geninfo end */
+ fprintf(fh,
+" </proto>\n");
+}
+
+void
+write_pdml_finale(FILE *fh)
+{
+ fputs("</pdml>\n", fh);
+}
+
+void
+write_psml_preamble(FILE *fh)
+{
+ fputs("<?xml version=\"1.0\"?>\n", fh);
+ fputs("<psml version=\"" PSML_VERSION "\" ", fh);
+ fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
+}
+
+void
+proto_tree_write_psml(epan_dissect_t *edt, FILE *fh)
+{
+ gint i;
+
+ /* if this is the first packet, we have to create the PSML structure output */
+ if(edt->pi.fd->num == 1) {
+ fprintf(fh, "<structure>\n");
+
+ for(i=0; i < edt->pi.cinfo->num_cols; i++) {
+ fprintf(fh, "<section>");
+ print_escaped_xml(fh, edt->pi.cinfo->col_title[i]);
+ fprintf(fh, "</section>\n");
+ }
+
+ fprintf(fh, "</structure>\n\n");
+ }
+
+ fprintf(fh, "<packet>\n");
+
+ for(i=0; i < edt->pi.cinfo->num_cols; i++) {
+ fprintf(fh, "<section>");
+ print_escaped_xml(fh, edt->pi.cinfo->col_data[i]);
+ fprintf(fh, "</section>\n");
+ }
+
+ fprintf(fh, "</packet>\n\n");
+}
+
+void
+write_psml_finale(FILE *fh)
+{
+ fputs("</psml>\n", fh);
+}
+
+/*
+ * Find the data source for a specified field, and return a pointer
+ * to the data in it. Returns NULL if the data is out of bounds.
+ */
+static const guint8 *
+get_field_data(GSList *src_list, field_info *fi)
+{
+ GSList *src_le;
+ data_source *src;
+ tvbuff_t *src_tvb;
+ gint length, tvbuff_length;
+
+ for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
+ src = src_le->data;
+ src_tvb = src->tvb;
+ if (fi->ds_tvb == src_tvb) {
+ /*
+ * Found it.
+ *
+ * XXX - a field can have a length that runs past
+ * the end of the tvbuff. Ideally, that should
+ * be fixed when adding an item to the protocol
+ * tree, but checking the length when doing
+ * that could be expensive. Until we fix that,
+ * we'll do the check here.
+ */
+ tvbuff_length = tvb_length_remaining(src_tvb,
+ fi->start);
+ if (tvbuff_length < 0) {
+ return NULL;
+ }
+ length = fi->length;
+ if (length > tvbuff_length)
+ length = tvbuff_length;
+ return tvb_get_ptr(src_tvb, fi->start, length);
+ }
+ }
+ g_assert_not_reached();
+ return NULL; /* not found */
+}
+
+/* Print a string, escaping out certain characters that need to
+ * escaped out for XML. */
+static void
+print_escaped_xml(FILE *fh, char *unescaped_string)
+{
+ unsigned char *p;
+
+ for (p = unescaped_string; *p != '\0'; p++) {
+ switch (*p) {
+ case '&':
+ fputs("&", fh);
+ break;
+ case '<':
+ fputs("<", fh);
+ break;
+ case '>':
+ fputs(">", fh);
+ break;
+ case '"':
+ fputs(""", fh);
+ break;
+ case '\'':
+ fputs("'", fh);
+ break;
+ default:
+ fputc(*p, fh);
+ }
+ }
+}
+
+static void
+write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi)
+{
+ int i;
+ const guint8 *pd;
+
+ if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) {
+ fprintf(pdata->fh, "field length invalid!");
+ return;
+ }
+
+ /* Find the data for this field. */
+ pd = get_field_data(pdata->src_list, fi);
+
+ if (pd) {
+ /* Print a simple hex dump */
+ for (i = 0 ; i < fi->length; i++) {
+ fprintf(pdata->fh, "%02x", pd[i]);
+ }
+ }
+}
+
+gboolean
+print_hex_data(print_stream_t *stream, epan_dissect_t *edt)