smb2-dissector: learn the "REPLAY_OPERATION" flag
[obnox/wireshark/wip.git] / plugins / asn1 / packet-asn1.c
1 /******************************************************************************************************/
2 /* packet-asn1.c
3  *
4  * Copyright (c) 2003 by Matthijs Melchior <matthijs.melchior@xs4all.nl>
5  *
6  * $Id$
7  *
8  * A plugin for:
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1999 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29
30 /**************************************************************************
31  * This plugin will dissect BER encoded ASN.1 messages in UDP packets or in
32  * a TCP stream. It relies on wireshark to do defragmentation and re-assembly
33  * to construct complete messages.
34  *
35  * To produce packet display with good annotations it needs to know about
36  * the ASN.1 definition of the messages it reads. To this end, it can read
37  * the 'type-table' output file of the ASN.1 to C compiler 'snacc'. The
38  * version I have used came from: http://packages.debian.org/testing/devel/snacc.html
39  *
40  * The type-table files produced by snacc are themselves ASN.1 BER encoded
41  * data structures. Knowledge of the structure of that table, as specified
42  * in the tbl.asn1 file in the snacc distribution, is hand coded in some
43  * functions in this plugin.
44  *
45  * This also means that this dissector can show its own specification.
46  * On a unix machine, do the following to see this in action:
47  *  - cd /tmp
48  *  - snacc -u /usr/include/snacc/asn1/asn-useful.asn1 -T tbl.tt /usr/include/snacc/asn1/tbl.asn1
49  *  - od -Ax -tx1 tbl.tt | text2pcap -T 801,801 - tbl.tt.pcap
50  *  - wireshark tbl.tt.pcap
51  *      GUI: Edit->Preferences->Protocols->ASN1
52  *             type table file: /tmp/tbl.tt
53  *             PDU name: TBL
54  *               [OK]
55  *  you can now browse the tbl.tt definition.
56  *
57  */
58
59
60 /* Include files */
61
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif
65
66 #include <errno.h>
67
68 #include <ctype.h>
69 #include <string.h>
70
71 #include <glib.h>
72 #include <glib/gprintf.h>
73
74 #include <epan/packet.h>
75 #include <epan/addr_resolv.h>
76 #include <epan/prefs.h>
77 #include <epan/filesystem.h>
78 #include <epan/report_err.h>
79 #include <epan/dissectors/packet-tcp.h>
80 #include <epan/oids.h>
81 #include <epan/emem.h>
82 #include <plugins/asn1/asn1.h>
83 #include <wsutil/file_util.h>
84
85 #ifdef DISSECTOR_WITH_GUI
86 #include <gtk/gtk.h>
87 #endif
88
89 #include <epan/ipproto.h>
90
91 /* buffer lengths */
92 #define BUFLS 32
93 #define BUFLM 64
94 #define BUFLL 128
95
96 /* Define default ports */
97
98 #define TCP_PORT_ASN1 0
99 #define UDP_PORT_ASN1 0
100 #define SCTP_PORT_ASN1 0
101
102 void proto_reg_handoff_asn1(void);
103
104 /* Define the asn1 proto */
105
106 static int proto_asn1 = -1;
107
108 /* Define the tree for asn1*/
109
110 static int ett_asn1 = -1;
111
112 #define MAXPDU 64               /* max # PDU's in one packet */
113 static int ett_pdu[MAXPDU];
114
115 #define MAX_NEST 32             /* max nesting level for ASN.1 elements */
116 static int ett_seq[MAX_NEST];
117
118 /*
119  * Global variables associated with the preferences for asn1
120  */
121
122 #ifdef JUST_ONE_PORT
123 static guint global_tcp_port_asn1 = TCP_PORT_ASN1;
124 static guint global_udp_port_asn1 = UDP_PORT_ASN1;
125 static guint global_sctp_port_asn1 = SCTP_PORT_ASN1;
126 #else
127 static range_t *global_tcp_ports_asn1;
128 static range_t *global_udp_ports_asn1;
129 static range_t *global_sctp_ports_asn1;
130 #endif /* JUST_ONE_PORT */
131
132 static gboolean asn1_desegment = TRUE;
133 static const char *asn1_filename = NULL;
134 static char *old_default_asn1_filename = NULL;
135 #define OLD_DEFAULT_ASN1FILE "asn1" G_DIR_SEPARATOR_S "default.tt"
136 #ifdef _WIN32
137 #define BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE "asn1/default.tt"
138 static char *bad_separator_old_default_asn1_filename = NULL;
139 #endif
140 static char *current_asn1 = NULL;
141 static const char *asn1_pduname = NULL;
142 static char *current_pduname = NULL;
143 static gboolean asn1_debug = FALSE;
144 static guint first_pdu_offset = 0;
145 static gboolean asn1_message_win = FALSE;
146 static gboolean asn1_verbose = FALSE; /* change to TRUE for logging the startup phase */
147 static gboolean asn1_full = FALSE; /* show full names */
148 static guint type_recursion_level = 1; /* eliminate 1 level of references */
149 static char *asn1_logfile = NULL;
150
151 #define ASN1LOGFILE "wireshark.log"
152
153 /* PDU counter, for correlation between GUI display and log file in debug mode */
154 static int pcount = 0;
155
156 static tvbuff_t *asn1_desc;             /* the PDU description */
157 static GNode *asn1_nodes = NULL;        /* GNode tree pointing to every asn1 data element */
158 static GNode *data_nodes = NULL;        /* GNode tree describing the syntax data */
159 static GNode *PDUtree = NULL;           /* GNode tree describing the expected PDU format */
160
161 static guint PDUerrcount = 0;           /* count of parse errors in one ASN.1 message */
162
163 #define NEL(x) (sizeof(x)/sizeof(*x))   /* # elements in static array */
164
165
166 static char pabbrev[] = "asn1"; /* field prefix */
167
168 static char fieldname[512];             /* for constructing full names */
169 static guint pabbrev_pdu_len;           /* length initial part of fieldname with 'abbrev.asn1pdu.' */
170
171 /*
172  * Text strings describing the standard, universal, ASN.1 names.
173  */
174
175 #define ASN1_EOI 4 /* this is in the class number space... */
176 #define ASN1_BEG 2 /* to be merged with constructed flag, first entry in sequence */
177
178 static const char tag_class[] = "UACPX";
179
180 static const char *asn1_cls[] = { "Universal", "Application", "Context", "Private" };
181
182 static const char *asn1_con[] = { "Primitive", "Constructed" };
183
184 static const char *asn1_tag[] = {
185         /*  0 */ "EOC",             "Boolean",        "Integer",          "BitString",
186         /*  4 */ "OctetString",     "Null",           "ObjectIdentifier", "ObjectDescriptor",
187         /*  8 */ "External",        "Real",           "Enumerated",       "tag11",
188         /* 12 */ "UTF8String",      "tag13",          "tag14",            "tag15",
189         /* 16 */ "Sequence",        "Set",            "NumericString",    "PrintableString",
190         /* 20 */ "TeletexString",   "VideotexString", "IA5String",        "UTCTime",
191         /* 24 */ "GeneralTime",     "GraphicString",  "ISO646String",     "GeneralString",
192         /* 28 */ "UniversalString", "tag29",          "BMPString",        "Long tag prefix"
193 /* TT61 == TELETEX */
194 /* ISO646 == VISIBLE*/
195 };
196
197 /* type names used in the output of the snacc ASN.1 compiler, the TBLTypeId enum */
198 static gboolean tbl_types_verified = FALSE;
199
200 typedef enum {  /* copied from .../snacc/c-lib/boot/tbl.h */
201         TBL_BOOLEAN = 0,
202         TBL_INTEGER = 1,
203         TBL_BITSTRING = 2,
204         TBL_OCTETSTRING = 3,
205         TBL_NULL = 4,
206         TBL_OID = 5,
207         TBL_REAL = 6,
208         TBL_ENUMERATED = 7,
209                 TBL__SIMPLE = 8,        /* values smaller than this can have a value */
210         TBL_SEQUENCE = 8,
211         TBL_SET = 9,
212         TBL_SEQUENCEOF = 10,
213         TBL_SETOF = 11,
214         TBL_CHOICE = 12,
215         TBL_TYPEREF = 13,
216
217         TBL_SEQUENCEOF_start,   /* to mark potential sequence-of repeat */
218         TBL_TYPEREF_nopop,      /* typeref has been handled immediately */
219         TBL_CHOICE_done,        /* choice is finished */
220         TBL_reserved,           /* this sequence has been visited */
221         TBL_CHOICE_immediate,   /* immediate choice, no next */
222
223         TBL_INVALID             /* incorrect value for this enum */
224 } TBLTypeId;
225
226 /* Universal tags mapped to snacc ASN.1 table types */
227 static int asn1_uni_type[] = {
228         /*  0 */ TBL_INVALID,     TBL_BOOLEAN,     TBL_INTEGER,     TBL_BITSTRING,
229         /*  4 */ TBL_OCTETSTRING, TBL_NULL,        TBL_OID,         TBL_INVALID,
230         /*  8 */ TBL_INVALID,     TBL_REAL,        TBL_ENUMERATED,  TBL_INVALID,
231         /* 12 */ TBL_OCTETSTRING, TBL_INVALID,     TBL_INVALID,     TBL_INVALID,
232         /* 16 */ TBL_SEQUENCE,    TBL_SET,         TBL_OCTETSTRING, TBL_OCTETSTRING,
233         /* 20 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
234         /* 24 */ TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING, TBL_OCTETSTRING,
235         /* 28 */ TBL_OCTETSTRING, TBL_INVALID,     TBL_OCTETSTRING, TBL_INVALID,
236 };
237
238
239 #define TBL_REPEAT              0x00010000 /* This type may be repeated, a flag in word TBLTypeId */
240 #define TBL_REPEAT_choice       0x00020000 /* repeating a choice */
241 #define TBL_CHOICE_made         0x00040000 /* This was a choice entry */
242 #define TBL_SEQUENCE_done       0x00080000 /* children have been processed */
243 #define TBL_CHOICE_repeat       0x00100000 /* a repeating choice */
244 #define TBL_REFERENCE           0x00200000 /* This entry is result of a typeref */
245 #define TBL_REFERENCE_pop       0x00400000 /* reference handled, do pop i.s.o. next */
246 #define TBL_SEQUENCE_choice     0x00800000 /* this sequence is a first of a repeating choice */
247 #define TBL_CONSTRUCTED         0x01000000 /* unexpectedly constructed entry */
248 #define TBL_TYPEmask            0x0000FFFF /* Mask just the type */
249
250 /* XXX - Should we use val_to_str here? */
251 #define TBLTYPE(x) (tbl_types[x&TBL_TYPEmask])
252
253 /* text tables for debugging and GUI */
254 static const char *tbl_types[] = {
255                        /*  0 */ "tbl-boolean",
256                        /*  1 */ "tbl-integer",
257                        /*  2 */ "tbl-bitstring",
258                        /*  2 */ "tbl-octetstring",
259                        /*  4 */ "tbl-null",
260                        /*  5 */ "tbl-oid",
261                        /*  6 */ "tbl-real",
262                        /*  7 */ "tbl-enumerated",
263                        /*  8 */ "tbl-sequence",
264                        /*  9 */ "tbl-set",
265                        /* 10 */ "tbl-sequenceof",
266                        /* 11 */ "tbl-setof",
267                        /* 12 */ "tbl-choice",
268                        /* 13 */ "tbl-typeref",
269
270                        /* 14 */ "tbl-sequenceof-start",
271                        /* 15 */ "tbl-typeref-nopop",
272                        /* 16 */ "tbl-choice-done",
273                        /* 17 */ "tbl-reserved",
274                        /* 18 */ "tbl-choice-immediate",
275
276                        /* 19 */ "tbl-invalid",
277 };
278 static const char *tbl_types_asn1[] = {
279                        /*  0 */ "BOOLEAN",
280                        /*  1 */ "INTEGER",
281                        /*  2 */ "BITSTRING",
282                        /*  2 */ "OCTET STRING",
283                        /*  4 */ "NULL",
284                        /*  5 */ "OBJECT IDENTIFIER",
285                        /*  6 */ "REAL",
286                        /*  7 */ "ENUMERATED",
287                        /*  8 */ "SEQUENCE",
288                        /*  9 */ "SET",
289                        /* 10 */ "SEQUENCE OF",
290                        /* 11 */ "SET OF",
291                        /* 12 */ "CHOICE",
292                        /* 13 */ "TYPEREF",
293
294                        /* 14 */ "start-SEQUENCE OF",
295                        /* 15 */ "TYPEREF nopop",
296                        /* 16 */ "CHOICE done",
297                        /* 17 */ "Reserved",
298                        /* 18 */ "CHOICE immediate",
299
300                        /* 19 */ "INVALID entry",
301 };
302 /* conversion from snacc type to appropriate wireshark type */
303 static guint tbl_types_wireshark[] = {
304                        /*  0 */ FT_BOOLEAN,     /* TBL_BOOLEAN */
305                        /*  1 */ FT_UINT32,      /* TBL_INTEGER */
306                        /*  2 */ FT_UINT32,      /* TBL_BITSTRING */
307                        /*  2 */ FT_STRINGZ,     /* TBL_OCTETSTRING */
308                        /*  4 */ FT_NONE,        /* TBL_NULL */
309                        /*  5 */ FT_BYTES,       /* TBL_OID */
310                        /*  6 */ FT_DOUBLE,      /* TBL_REAL */
311                        /*  7 */ FT_UINT32,      /* TBL_ENUMERATED */
312                        /*  8 */ FT_NONE,        /* TBL_SEQUENCE */
313                        /*  9 */ FT_NONE,        /* TBL_SET */
314                        /* 10 */ FT_NONE,        /* TBL_SEQUENCEOF */
315                        /* 11 */ FT_NONE,        /* TBL_SETOF */
316                        /* 12 */ FT_NONE,        /* TBL_CHOICE */
317                        /* 13 */ FT_NONE,        /* TBL_TYPEREF */
318
319                        /* 14 */ FT_NONE,        /* TBL_SEQUENCEOF_start */
320                        /* 15 */ FT_NONE,        /* TBL_TYPEREF_nopop */
321                        /* 16 */ FT_NONE,        /* TBL_CHOICE_done */
322                        /* 17 */ FT_NONE,        /* TBL_reserved */
323                        /* 18 */ FT_NONE,        /* TBL_CHOICE_immediate */
324
325                        /* 19 */ FT_NONE,        /* TBL_INVALID */
326 };
327
328 /* conversion from snacc type to appropriate wireshark display type */
329 static guint tbl_display_wireshark[] = {
330                        /*  0 */ BASE_DEC,       /* TBL_BOOLEAN */
331                        /*  1 */ BASE_DEC_HEX,   /* TBL_INTEGER */
332                        /*  2 */ BASE_HEX,       /* TBL_BITSTRING */
333                        /*  2 */ BASE_NONE,      /* TBL_OCTETSTRING */
334                        /*  4 */ BASE_NONE,      /* TBL_NULL */
335                        /*  5 */ BASE_DEC,       /* TBL_OID */
336                        /*  6 */ BASE_DEC,       /* TBL_REAL */
337                        /*  7 */ BASE_DEC,       /* TBL_ENUMERATED */
338                        /*  8 */ BASE_NONE,      /* TBL_SEQUENCE */
339                        /*  9 */ BASE_NONE,      /* TBL_SET */
340                        /* 10 */ BASE_NONE,      /* TBL_SEQUENCEOF */
341                        /* 11 */ BASE_NONE,      /* TBL_SETOF */
342                        /* 12 */ BASE_NONE,      /* TBL_CHOICE */
343                        /* 13 */ BASE_NONE,      /* TBL_TYPEREF */
344
345                        /* 14 */ BASE_NONE,      /* TBL_SEQUENCEOF_start */
346                        /* 15 */ BASE_NONE,      /* TBL_TYPEREF_nopop */
347                        /* 16 */ BASE_NONE,      /* TBL_CHOICE_done */
348                        /* 17 */ BASE_NONE,      /* TBL_reserved */
349                        /* 18 */ BASE_NONE,      /* TBL_CHOICE_immediate */
350
351                        /* 19 */ BASE_NONE,      /* TBL_INVALID */
352 };
353
354 static const char *tbl_types_wireshark_txt[] = {
355                        /*  0 */ "FT_BOOLEAN",   /* TBL_BOOLEAN */
356                        /*  1 */ "FT_UINT32",    /* TBL_INTEGER */
357                        /*  2 */ "FT_UINT32",    /* TBL_BITSTRING */
358                        /*  2 */ "FT_STRINGZ",   /* TBL_OCTETSTRING */
359                        /*  4 */ "FT_NONE",      /* TBL_NULL */
360                        /*  5 */ "FT_BYTES",     /* TBL_OID */
361                        /*  6 */ "FT_DOUBLE",    /* TBL_REAL */
362                        /*  7 */ "FT_UINT32",    /* TBL_ENUMERATED */
363                        /*  8 */ "FT_NONE",      /* TBL_SEQUENCE */
364                        /*  9 */ "FT_NONE",      /* TBL_SET */
365                        /* 10 */ "FT_NONE",      /* TBL_SEQUENCEOF */
366                        /* 11 */ "FT_NONE",      /* TBL_SETOF */
367                        /* 12 */ "FT_NONE",      /* TBL_CHOICE */
368                        /* 13 */ "FT_NONE",      /* TBL_TYPEREF */
369
370                        /* 14 */ "FT_NONE",      /* TBL_SEQUENCEOF_start */
371                        /* 15 */ "FT_NONE",      /* TBL_TYPEREF_nopop */
372                        /* 16 */ "FT_NONE",      /* TBL_CHOICE_done */
373                        /* 17 */ "FT_NONE",      /* TBL_reserved */
374                        /* 18 */ "FT_NONE",      /* TBL_CHOICE_immediate */
375
376                        /* 19 */ "FT_NONE",      /* TBL_INVALID */
377 };
378
379 typedef struct _PDUinfo PDUinfo;
380 struct _PDUinfo {
381         guint type;
382         const char *name;
383         const char *typename;
384         const char *fullname;
385         guchar tclass;
386         guint tag;
387         guint flags;
388         GNode *reference;
389         gint typenum;
390         gint basetype;          /* parent type */
391         gint mytype;            /* original type number, typenum may have gone through a reference */
392         gint value_id;          /* wireshark field id for the value in this PDU */
393         gint type_id;           /* wireshark field id for the type of this PDU */
394         hf_register_info value_hf; /* wireshark field info for this value */
395 };
396
397
398 /* bits in the flags collection */
399 #define PDU_OPTIONAL     1
400 #define PDU_IMPLICIT     2
401 #define PDU_NAMEDNUM     4
402 #define PDU_REFERENCE    8
403 #define PDU_TYPEDEF   0x10
404 #define PDU_ANONYMOUS 0x20
405 #define PDU_TYPETREE  0x40
406
407 #define PDU_CHOICE    0x08000000   /* manipulated by the PDUname routine */
408
409 static guint PDUinfo_initflags = 0;     /* default flags for newly allocated PDUinfo structs */
410
411 /* description of PDU properties as passed from the matching routine
412  * to the decoder and GUI.
413  */
414 typedef struct _PDUprops PDUprops;
415 struct _PDUprops {
416         guint type;     /* value from enum TBLTypeId */
417         const char *name;
418         const char *typename;
419         const char *fullname;
420         guint flags;
421         gpointer data;
422         gint value_id;
423         gint type_id;
424 };
425 /* flags defined in PDUprops.flags */
426 #define OUT_FLAG_type           1
427 #define OUT_FLAG_data           2
428 #define OUT_FLAG_typename       4
429 #define OUT_FLAG_dontshow       8
430 #define OUT_FLAG_noname      0x10
431 #define OUT_FLAG_constructed 0x20
432
433 static PDUprops *getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons);
434 static const char *getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value);
435
436 static const char empty[] = "";         /* address of the empt string, avoids many tests for NULL */
437 #define MAX_OTSLEN 256          /* max printed size for an octet string */
438
439
440 #undef NEST                     /* show nesting of asn.1 enties */
441
442 #ifdef NEST                     /* only for debugging */
443 /* show nesting, only for debugging... */
444 #define MAXTAGS MAX_NEST
445 static struct {
446         guchar cls;
447         guchar tag;
448 } taglist[MAXTAGS];
449
450 static char *showtaglist(guint level)
451 {
452         static char tagtxt[BUFLM];
453         char *p = tagtxt;
454         guint i;
455
456 #ifdef ALLTAGS
457         for(i=0; i<= level; i++) {
458                 switch(taglist[i].cls) {
459                 case BER_CLASS_UNI: *p++ = 'U'; break;
460                 case BER_CLASS_APP: *p++ = 'A'; break;
461                 case BER_CLASS_CON: *p++ = 'C'; break;
462                 case BER_CLASS_PRI: *p++ = 'P'; break;
463                 default:       *p++ = 'x'; break;
464                 }
465                 p += g_sprintf(p, "%d.", taglist[i].tag);
466         }
467 #else /* only context tags */
468         *p++ = 'C';
469         for(i=0; i<= level; i++) {
470                 if (taglist[i].cls == BER_CLASS_CON) {
471                         p += g_sprintf(p, "%d.", taglist[i].tag);
472                 }
473         }
474 #endif
475         *--p = 0;               /* remove trailing '.' */
476         return tagtxt;
477 }
478
479 static guint
480 get_context(guint level)
481 {
482         guint ctx = 0;
483         guint i;
484
485         for(i=0; i<=level; i++) {
486                 if (taglist[i].cls == BER_CLASS_CON)
487                         ctx = (ctx << 8) | taglist[i].tag;
488         }
489         return ctx;
490 }
491 #endif /* NEST, only for debugging */
492
493
494 /* Convert a bit string to an ascii representation for printing
495  * -- not thread safe ...
496  */
497 static const char *showbits(guchar *val, guint count)
498 {
499         static char str[BUFLM];
500         guint i;
501         char *p = str;
502
503         if (count > 32)
504                 return "*too many bits*";
505
506         if (val != 0) {
507                 for(i=0; i<count; i++) {
508                         if (i && ((i & 7) == 0)) *p++ = ' ';
509                         *p++ = (val[i>>3] & (0x80 >> (i & 7))) ? '1' : '0';
510                 }
511         }
512         *p = 0;
513         return str;
514 }
515
516 /* get bitnames string for bits set */
517 static const char *
518 showbitnames(guchar *val, guint count, PDUprops *props, guint offset)
519 {
520         static char str[BUFLL];
521         guint i;
522         char *p = str;
523
524         if (props->flags & OUT_FLAG_noname)
525                 return empty;
526
527         if (count > 32)
528                 return "*too many bits, no names...*";
529
530         if (val != NULL) {
531                 for(i=0; i<count; i++) {
532                         if (val[i>>3] & (0x80 >> (i & 7))) { /* bit i is set */
533                                 p += g_sprintf(p,"%s,", getPDUenum(props, offset, 0, 0, i));
534                         }
535                 }
536                 if (p > str)
537                         --p;    /* remove terminating , */
538         }
539         *p = 0;
540         return str;
541
542
543
544 }
545 /* Convert an oid to its conventional text representation
546  * -- not thread safe...
547  */
548 static char *showoid(subid_t *oid, guint len)
549 {
550         static char str[BUFLM];
551         guint i;
552         char *p = str;
553
554         if (oid != NULL) {
555                 for(i=0; i<len; i++) {
556                         if (i) *p++ = '.';
557                         p += g_sprintf(p, "%lu", (unsigned long)oid[i]);
558                 }
559         }
560         *p = 0;
561         return str;
562 }
563
564 /* show octetstring, if all ascii, show that, else hex [returnrd string must be freed by caller] */
565 static char *
566 showoctets(guchar *octets, guint len, guint hexlen) /* if len <= hexlen, always show hex */
567 {
568         guint dohex = 0;
569         guint i;
570         char *str, *p;
571         const char *endstr = empty;
572
573         if (len == 0) {
574                 str = g_malloc(1);
575                 str[0] = 0;
576         } else {
577                 for (i=0; i<len; i++) {
578                         if (!isprint(octets[i])) /* maybe isblank() as well ... */
579                                 dohex++;
580                 }
581                 if (len > MAX_OTSLEN) { /* limit the maximum output.... */
582                         len = MAX_OTSLEN;
583                         endstr = "...."; /* this is 5 bytes !! */
584                 }
585                 if (dohex) {
586                         str = p = g_malloc(len*2 + 5);
587                         for (i=0; i<len; i++) {
588                                 p += g_sprintf(p, "%2.2X", octets[i]);
589                         }
590                         strncpy(p, endstr, 5);
591                 } else {
592                         if (len <= hexlen) { /* show both hex and ascii, assume hexlen < MAX_OTSLEN */
593                                 str = p = g_malloc(len*3+2);
594                                 for (i=0; i<len; i++) {
595                                         p += g_sprintf(p, "%2.2X", octets[i]);
596                                 }
597                                 *p++ = ' '; /* insert space */
598                                 strncpy(p, octets, len);
599                                 p[len] = 0;
600                         } else {
601                                 /* g_strdup_printf("%*s%s", len, octets, endstr) does not work ?? */
602                                 str = g_malloc(len+5);
603                                 strncpy(str, octets, len);
604                                 strncpy(&str[len], endstr, 5);
605                         }
606                 }
607         }
608         return str;
609 }
610
611 /* allow NULL pointers in strcmp, handle them as empty strings */
612 static int
613 g_strcmp(gconstpointer a, gconstpointer b)
614 {
615         if (a == 0) a = empty;
616         if (b == 0) b = empty;
617         return strcmp(a, b);
618 }
619
620 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
621 /* WARNING   WARNING   WARNING   WARNING   WARNING   WARNING */
622 /*                                                           */
623 /* Most of the following routine is guesswork in order to    */
624 /* speed up resynchronisation if the dissector lost the      */
625 /* encoding due to incomplete captures, or a capture that    */
626 /* starts in the middle of a fragmented ip packet            */
627 /* If this poses to many problems, these settings can be     */
628 /* made part of the protocol settings in the user interface  */
629 /*************************************************************/
630
631 /* check length for a reasonable value, return a corrected value */
632 static int
633 checklength(int len, int def, int cls, int tag, char *lenstr, int strmax)
634 {
635         int newlen = len;
636
637         if ( ! def) {
638                 g_snprintf(lenstr, strmax, "indefinite");
639                 return len;
640         }
641
642         if (len < 0)            /* negative ..... */
643                 newlen = 4;
644
645         if (cls != BER_CLASS_UNI) {     /* don't know about the tags */
646                 if (len > 131071)
647                         newlen = 64;
648         } else {
649                 switch (tag) {
650                 case BER_UNI_TAG_EOC:   /* End Of Contents    */
651                 case BER_UNI_TAG_NULL:  /* Null               */
652                         newlen = 0;
653                         break;
654                 case BER_UNI_TAG_BOOLEAN:       /* Boolean            */
655                         newlen = 1;
656                         break;
657                 case BER_UNI_TAG_INTEGER:       /* Integer            */
658                 case BER_UNI_TAG_ENUMERATED:    /* Enumerated         */
659                         if (len > 8)
660                                 newlen = 4;
661                         break;
662                 case BER_UNI_TAG_BITSTRING:     /* Bit String         */
663                         if (len > 8)
664                                 newlen = 4;
665                         break;
666                 case BER_UNI_TAG_OCTETSTRING:   /* Octet String       */
667                 case BER_UNI_TAG_NumericString: /* Numerical String   */
668                 case BER_UNI_TAG_PrintableString: /* Printable String   */
669                 case BER_UNI_TAG_TeletexString: /* Teletext String    */
670                 case BER_UNI_TAG_VideotexString: /* Video String       */
671                 case BER_UNI_TAG_IA5String: /* IA5 String         */
672                 case BER_UNI_TAG_GraphicString: /* Graphical String   */
673                 case BER_UNI_TAG_VisibleString: /* Visible String     */
674                 case BER_UNI_TAG_GeneralString: /* General String     */
675                 if (len > 65535)
676                         newlen = 32;
677                 break;
678                 case BER_UNI_TAG_OID:           /* Object Identifier  */
679                 case BER_UNI_TAG_ObjectDescriptor:              /* Description        */
680                 case ASN1_EXT:          /* External           */
681                         if (len > 64)
682                                 newlen = 16;
683                         break;
684                 case BER_UNI_TAG_REAL:          /* Real               */
685                         if (len >16)
686                                 newlen = 8;
687                         break;
688                 case BER_UNI_TAG_SEQUENCE:              /* Sequence           */
689                 case BER_UNI_TAG_SET:           /* Set                */
690                         if (len > 65535)
691                                 newlen = 64;
692                         break;
693                 case BER_UNI_TAG_UTCTime:       /* Universal Time     */
694                 case BER_UNI_TAG_GeneralizedTime:       /* General Time       */
695                         if (len > 32)
696                                 newlen = 15;
697                         break;
698
699                 default:
700                         if (len > 131071)
701                                 newlen = 64;
702                         break;
703                 }
704         }
705
706         if (newlen != len) {
707                 /* a change was needed.... */
708                 g_snprintf(lenstr, strmax, "%d(changed from %d)", newlen, len);
709         } else {
710                 g_snprintf(lenstr, strmax, "%d", len);
711         }
712         return newlen;
713 }
714
715 static guint decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint len, proto_tree *pt, int level);
716 static void PDUreset(int count, int counr2);
717
718 static void
719 dissect_asn1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
720
721   ASN1_SCK asn1;
722   guint cls, con, tag, len, offset, reassembled;
723   gboolean def;
724   char lenstr[BUFLS];
725   char tagstr[BUFLS];
726   char headstr[BUFLL];
727   char offstr[BUFLS];
728   const char *name, *tname;
729   volatile guint boffset;
730   volatile int i = 0;           /* PDU counter */
731   proto_tree * volatile ti = 0, * volatile ti2 = 0, *asn1_tree, *tree2;
732   proto_item *hidden_item;
733   PDUprops props;
734   static guint lastseq;
735   struct tcpinfo *info;
736   gint delta;
737
738   pcount++;
739   boffset = 0;
740
741   reassembled = 1;              /* UDP is not a stream, and thus always reassembled .... */
742   if (pinfo->ipproto == IP_PROTO_TCP) { /* we have tcpinfo */
743           info = (struct tcpinfo *)pinfo->private_data;
744           delta = info->seq - lastseq;
745           reassembled = info->is_reassembled;
746           lastseq = info->seq;
747
748           if (asn1_verbose)
749                   g_message("dissect_asn1: tcp - seq=%u, delta=%d, reassembled=%d",
750                             info->seq, delta, reassembled);
751   } else {
752           if (asn1_verbose)
753                   g_message("dissect_asn1: udp");
754   }
755
756   /* Set the protocol column */
757   col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "ASN.1 %s", current_pduname);
758
759   col_clear(pinfo->cinfo, COL_INFO);
760
761
762   offstr[0] = 0;
763   if ((first_pdu_offset > 0) && !reassembled) {
764           boffset = first_pdu_offset;
765           g_snprintf(offstr, sizeof(offstr), " at %d", boffset);
766   }
767
768   /* open BER decoding */
769   asn1_open(&asn1, tvb, boffset);
770
771   asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
772
773   asn1_close(&asn1, &offset);
774
775   PDUreset(pcount, 0);          /* arguments are just for debugging */
776   getPDUprops(&props, boffset, cls, tag, con);
777   name = props.name;
778   tname = props.typename;
779
780   len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
781
782   if (asn1_debug) {
783
784           g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
785
786           g_snprintf(headstr, sizeof(headstr), "first%s: (%s)%s %d %s, %s, %s, len=%s, off=%d, size=%d ",
787                    offstr,
788                    tname,
789                    name,
790                    pcount,
791                    asn1_cls[cls],
792                    asn1_con[con],
793                    ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
794                    lenstr,
795                    boffset,
796                    tvb_length(tvb)
797                   );
798   } else {
799           if (props.flags & OUT_FLAG_noname) {
800                   g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
801                   name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
802           }
803           g_snprintf(headstr, sizeof(headstr), "first pdu%s: (%s)%s ", offstr, tname, name );
804   }
805
806   /* Set the info column */
807   col_add_str(pinfo->cinfo, COL_INFO, headstr );
808
809   /*
810    * If we have a non-null tree (ie we are building the proto_tree
811    * instead of just filling out the columns ), then add a BER
812    * tree node
813    */
814
815   /* ignore the tree here, must decode BER to know how to reassemble!! */
816 /* if(tree) { */
817
818     TRY {                       /* catch incomplete PDU's */
819
820         ti = proto_tree_add_protocol_format(tree, proto_asn1, tvb, boffset,
821                                             def? (int) (offset - boffset + len) :  -1,
822                                             "ASN.1 %s", current_pduname);
823
824         tree2 = proto_item_add_subtree(ti, ett_asn1);
825
826         hidden_item = proto_tree_add_item(tree2, ((PDUinfo *)PDUtree->data)->value_id, tvb, boffset,
827                                    def? (int) (offset - boffset + len) :  -1, TRUE);
828         PROTO_ITEM_SET_HIDDEN(hidden_item);
829
830         offset = boffset; /* the first packet */
831         while((i < MAXPDU) && (tvb_length_remaining(tvb, offset) > 0)) {
832             ti2 = 0;
833             boffset = offset;
834             /* open BER decoding */
835             asn1_open(&asn1, tvb, offset);
836             asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
837             asn1_close(&asn1, &offset);
838
839             PDUreset(pcount, i+1);
840             getPDUprops(&props, boffset, cls, tag, con);
841             name = props.name;
842             tname = props.typename;
843
844             if (!def)
845                     len = tvb_length_remaining(tvb, offset);
846
847             len = checklength(len, def, cls, tag, lenstr, sizeof(lenstr));
848
849             if (asn1_debug) {
850
851                     g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
852
853                     g_snprintf(headstr, sizeof(headstr), "%s, %s, %s, len=%s, off=%d, remaining=%d",
854                              asn1_cls[cls],
855                              asn1_con[con],
856                              ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr,
857                              lenstr,
858                              boffset,
859                              tvb_length_remaining(tvb, offset) );
860
861                     if (props.value_id == -1)
862                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
863                                                       def? (int) (offset - boffset + len) :  -1,
864                                                       "%s: (%s)%s %d-%d %s", current_pduname,
865                                                       tname, name, pcount, i+1, headstr);
866                     else {
867                             ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
868                                                       def? (int) (offset - boffset + len) :  -1,
869                                                       "%s: (%s)%s %d-%d %s ~", current_pduname,
870                                                       tname, name, pcount, i+1, headstr);
871
872                                 if (props.type_id != -1){
873                                  hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
874                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
875                                          PROTO_ITEM_SET_HIDDEN(hidden_item);
876                                 }
877
878                     }
879             } else {
880                     if (props.flags & OUT_FLAG_noname) {
881                             g_snprintf(tagstr, sizeof(tagstr), "%ctag%d", tag_class[cls], tag);
882                             name = ((cls == BER_CLASS_UNI) && (tag < 32)) ? asn1_tag[tag] : tagstr;
883                     }
884                     if (props.value_id == -1)
885                             ti2 = proto_tree_add_text(tree2, tvb, boffset,
886                                                       def? (int) (offset - boffset + len) :  -1,
887                                                       "%s: (%s)%s", current_pduname, tname, name);
888                     else {
889                             ti2 = proto_tree_add_none_format(tree2, props.value_id, tvb, boffset,
890                                                       def? (int) (offset - boffset + len) :  -1,
891                                                       "%s: (%s)%s ~", current_pduname, tname, name);
892                                 if (props.type_id != -1){
893                                 hidden_item = proto_tree_add_item(tree2, props.type_id, tvb, boffset,
894                                                       def? (int) (offset - boffset + len) :  -1, TRUE);
895                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
896                                 }
897                     }
898             }
899             asn1_tree = proto_item_add_subtree(ti2, ett_pdu[i]);
900
901 #ifdef NEST
902             taglist[0].cls = cls;
903             taglist[0].tag = tag;
904 #endif /* NEST */
905
906             if (!def) len++; /* make sure we get an exception if we run off the end! */
907
908             offset = decode_asn1_sequence(tvb, offset, len, asn1_tree, 1);
909
910             proto_item_set_len(ti2, offset - boffset); /* mark length for hex display */
911
912             i++; /* one more full message handled */
913
914             if (ti2 && PDUerrcount && asn1_debug) /* show error counts only when in debug mode.... */
915                     proto_item_append_text(ti2," (%d error%s)", PDUerrcount, (PDUerrcount>1)?"s":empty);
916         }
917         col_append_fstr(pinfo->cinfo, COL_INFO, "[%d msg%s]", i, (i>1)?"s":empty);
918         if (ti)
919                 proto_item_append_text(ti, ", %d msg%s", i, (i>1)?"s":empty);
920     }
921     CATCH(BoundsError) {
922             RETHROW;
923     }
924     CATCH(ReportedBoundsError) {
925             col_append_fstr(pinfo->cinfo, COL_INFO, "[%d+1 msg%s]", i, (i>0)?"s":empty);
926             if (ti)
927                     proto_item_append_text(ti, ", %d+1 msg%s", i, (i>1)?"s":empty);
928             if (ti2)
929                     proto_item_append_text(ti2, " (incomplete)");
930             if (asn1_desegment) {
931                     pinfo->desegment_offset = boffset;
932                     pinfo->desegment_len = 1;
933                     if (asn1_verbose)
934                             g_message("ReportedBoundsError: offset=%d len=%d can_desegment=%d",
935                                       boffset, 1, pinfo->can_desegment);
936             } else {
937                     RETHROW;
938             }
939     }
940     ENDTRY;
941 /* } */
942   if (asn1_verbose)
943         g_message("dissect_asn1 finished: desegment_offset=%d desegment_len=%d can_desegment=%d",
944                    pinfo->desegment_offset, pinfo->desegment_len, pinfo->can_desegment);
945 }
946
947 /* decode an ASN.1 sequence, until we have consumed the specified length */
948 static guint
949 decode_asn1_sequence(tvbuff_t *tvb, guint offset, guint tlen, proto_tree *pt, int level)
950 {
951   ASN1_SCK asn1;
952   guint ret, cls, con, tag, len, boffset, soffset, eos;
953   gboolean def;
954   guint value;
955   const char *clsstr, *constr, *tagstr;
956   char tagbuf[BUFLM];
957   char lenbuf[BUFLM];
958   char nnbuf[BUFLS];
959   proto_tree *ti, *pt2;
960   proto_item *hidden_item;
961   guchar *octets, *bits, unused;
962   subid_t *oid;
963   /* the debugging formats */
964   static char textfmt_d[] = "off=%d: [%s %s %s] (%s)%s: %d%s";          /* decimal */
965   static char textfmt_e[] = "off=%d: [%s %s %s] (%s)%s: %d:%s%s";       /* enum */
966   static char textfmt_s[] = "off=%d: [%s %s %s] (%s)%s: '%s'%s";        /* octet string */
967   static char textfmt_b[] = "off=%d: [%s %s %s] (%s)%s: %s:%s%s";       /* bit field */
968   static char textfmt_c[] = "off=%d: [%s %s %s] (%s)%s%s%s";            /* constructed */
969   static char matchind[] = " ~"; /* indication of possible match */
970   const char *name, *ename, *tname;
971   char *oname;
972   PDUprops props;
973
974   ti = 0;                       /* suppress gcc warning */
975
976   soffset = offset; /* where this sequence starts */
977   eos = offset + tlen;
978   while (offset < eos) {        /* while this entity has not ended... */
979           boffset = offset;
980           asn1_open(&asn1, tvb, offset);
981           ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
982           asn1_close(&asn1, &offset); /* mark current position */
983           if (ret != ASN1_ERR_NOERROR) {
984                 proto_tree_add_text(pt, tvb, offset, 1, "ASN1 ERROR: %s", asn1_err_to_str(ret) );
985                 break;
986           }
987
988           getPDUprops(&props, boffset, cls, tag, con);
989           name = props.name;
990           tname = props.typename;
991           if (asn1_full)
992                   name = &props.fullname[pabbrev_pdu_len];      /* no abbrev.pduname */
993           if (asn1_debug) {     /* show both names */
994                   g_sprintf(fieldname, "%s[%s]", props.name, props.fullname);
995                   name = fieldname;
996           }
997
998           clsstr = asn1_cls[cls];
999           constr = asn1_con[con];
1000           if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1001                   tagstr = asn1_tag[tag];
1002           } else {
1003                   g_snprintf(tagbuf, sizeof(tagbuf), "%ctag%d", tag_class[cls], tag);
1004                   tagstr = tagbuf;
1005           }
1006
1007           len = checklength(len, def, cls, tag, lenbuf, sizeof(lenbuf));
1008
1009           if (def) {
1010                   g_snprintf(nnbuf, sizeof(nnbuf), "NN%d", len);
1011           } else {
1012                   strncpy(nnbuf, "NN-", sizeof(nnbuf));
1013                                 /* make sure we get an exception if we run off the end! */
1014                   len = tvb_length_remaining(tvb, offset) + 1;
1015           }
1016           if ( ( ! asn1_debug) && (props.flags & OUT_FLAG_noname) ) {
1017                   /* just give type name if we don't know any better */
1018                   tname = tagstr;
1019                   name = nnbuf; /* this is better than just empty.... */
1020           }
1021
1022 #ifdef NEST
1023           taglist[level].cls = cls;
1024           taglist[level].tag = tag;
1025 #endif /* NEST */
1026
1027           oname  = 0;
1028           if (level >= MAX_NEST) { /* nesting too deep..., handle as general octet string */
1029                 cls = BER_CLASS_UNI;
1030                 tag = BER_UNI_TAG_GeneralString;
1031                 oname = g_malloc(strlen(name) + 32);
1032                 g_sprintf(oname, "%s ** nesting cut off **", name);
1033                 name = oname;
1034           }
1035           switch(cls) {
1036             case BER_CLASS_UNI: /* fprintf(stderr, "Universal\n"); */
1037               switch(tag) {
1038                 case BER_UNI_TAG_INTEGER:
1039                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1040                       asn1_close(&asn1, &offset); /* mark where we are now */
1041                       if (asn1_debug) {
1042                               if ( (props.value_id == -1) ||
1043                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1044                                         /* unknown or unexpected: just text */
1045                                         proto_tree_add_text(pt, tvb, boffset,
1046                                                         offset - boffset, textfmt_d, boffset,
1047                                                         clsstr, constr, tagstr, tname, name, value,
1048                                                         empty);
1049                               else {
1050                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1051                                                         offset - boffset, value, textfmt_d, boffset,
1052                                                         clsstr, constr, tagstr, tname, name, value,
1053                                                         matchind);
1054                                         if (props.type_id != -1) {
1055                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1056                                                                 boffset, offset - boffset, value);
1057                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1058                                         }
1059                               }
1060                       } else {
1061                               if ( (props.value_id == -1) ||
1062                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1063                                         /* unknown or unexpected, just text */
1064                                         proto_tree_add_text(pt, tvb, boffset,
1065                                                         offset - boffset,
1066                                                         "(%s)%s: %d", tname, name, value);
1067                               else {
1068                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1069                                                         offset - boffset, value,
1070                                                         "(%s)%s: %d ~", tname, name, value);
1071                                         if (props.type_id != -1){
1072                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1073                                                                 boffset, offset - boffset, value);
1074                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1075                                         }
1076                               }
1077                       }
1078                       break;
1079
1080                 case BER_UNI_TAG_ENUMERATED:
1081                       ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1082                       asn1_close(&asn1, &offset); /* mark where we are now */
1083                       ename = getPDUenum(&props, boffset, cls, tag, value);
1084                       if (asn1_debug) {
1085                               if ( (props.value_id == -1) ||
1086                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1087                                         /* unknown or unexpected, just text */
1088                                         proto_tree_add_text(pt, tvb, boffset,
1089                                                         offset - boffset,
1090                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1091                                                         tname, name, value, ename, empty);
1092                               else {
1093                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1094                                                         offset - boffset, value,
1095                                                         textfmt_e, boffset, clsstr, constr, tagstr,
1096                                                         tname, name, value, ename, matchind);
1097                                         if (props.type_id != -1){
1098                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1099                                                                 boffset, offset - boffset, value);
1100                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1101                                         }
1102                               }
1103                       } else {
1104                               if ( (props.value_id == -1) ||
1105                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1106                                         /* unknown or unexpected, just text */
1107                                         proto_tree_add_text(pt, tvb, boffset,
1108                                                         offset - boffset,
1109                                                         "(%s)%s: %d:%s", tname, name, value, ename);
1110                               else {
1111                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1112                                                         offset - boffset, value,
1113                                                         "(%s)%s: %d:%s ~", tname, name, value, ename);
1114                                         if (props.type_id != -1){
1115                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1116                                                                 boffset, offset - boffset, value);
1117                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1118                                         }
1119                               }
1120                       }
1121                       break;
1122
1123                 case BER_UNI_TAG_BOOLEAN:
1124                       ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1125                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1126                       if (asn1_debug) {
1127                               if ( (props.value_id == -1) ||
1128                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1129                                         /* unknown or unexpected, just text */
1130                                         proto_tree_add_text(pt, tvb, boffset,
1131                                                         offset - boffset,
1132                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1133                                                         tname, name, value? "true" : "false", empty);
1134                               else {
1135                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1136                                                         offset - boffset, value != 0,
1137                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1138                                                         tname, name, value? "true" : "false", matchind);
1139                                         if (props.type_id != -1){
1140                                                 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1141                                                                 boffset, offset - boffset, value != 0);
1142                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1143                                         }
1144                               }
1145                       } else {
1146                               if ( (props.value_id == -1) ||
1147                                    (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1148                                         /* unknown or unexpected, just text */
1149                                         proto_tree_add_text(pt, tvb, boffset,
1150                                                         offset - boffset,
1151                                                         "(%s)%s: %s", tname, name,
1152                                                         value? "true" : "false");
1153                               else {
1154                                         proto_tree_add_boolean_format(pt, props.value_id, tvb, boffset,
1155                                                         offset - boffset, value != 0,
1156                                                         "(%s)%s: %s ~", tname, name,
1157                                                         value? "true" : "false");
1158                                         if (props.type_id != -1){
1159                                                 hidden_item = proto_tree_add_boolean(pt, props.type_id, tvb,
1160                                                                 boffset, offset - boffset, value != 0);
1161                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1162                                         }
1163                               }
1164                       }
1165                       break;
1166
1167                 case BER_UNI_TAG_OCTETSTRING:
1168                 case BER_UNI_TAG_NumericString:
1169                 case BER_UNI_TAG_PrintableString:
1170                 case BER_UNI_TAG_TeletexString:
1171                 case BER_UNI_TAG_IA5String:
1172                 case BER_UNI_TAG_GeneralString:
1173                 case BER_UNI_TAG_UTCTime:
1174                 case BER_UNI_TAG_GeneralizedTime:
1175                         /* read value, \0 terminated */
1176                       ret = asn1_string_value_decode(&asn1, len, &octets);
1177                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1178                       ename = showoctets(octets, len, (tag == BER_UNI_TAG_OCTETSTRING) ? 4 : 0 );
1179                       if (asn1_debug) {
1180                               if ( (props.value_id == -1) ||
1181                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1182                                         /* unknown or unexpected, just text */
1183                                         proto_tree_add_text(pt, tvb, boffset,
1184                                                         offset - boffset,
1185                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1186                                                         tname, name, ename, empty);
1187                               else {
1188                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1189                                                         offset - boffset, octets, /* \0 termnated */
1190                                                         textfmt_s, boffset, clsstr, constr, tagstr,
1191                                                         tname, name, ename, matchind);
1192                                         if (props.type_id != -1){
1193                                                 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1194                                                                 boffset, offset - boffset, octets);
1195                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1196                                         }
1197                               }
1198                       } else {
1199                               if ( (props.value_id == -1) ||
1200                                    (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1201                                         /* unknown or unexpected, just text */
1202                                         proto_tree_add_text(pt, tvb, boffset,
1203                                                         offset - boffset,
1204                                                         "(%s)%s: %s", tname, name, ename);
1205                               else {
1206                                         proto_tree_add_string_format(pt, props.value_id, tvb, boffset,
1207                                                         offset - boffset, octets, /* \0 terminated */
1208                                                         "(%s)%s: %s ~", tname, name, ename);
1209                                         if (props.type_id != -1){
1210                                                 hidden_item = proto_tree_add_string(pt, props.type_id, tvb,
1211                                                                 boffset, offset - boffset, octets);
1212                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1213                                         }
1214                               }
1215                       }
1216                       g_free(octets);
1217                       g_free( (gpointer) ename);
1218                       break;
1219
1220                 case BER_UNI_TAG_BITSTRING:
1221                       ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused); /* read value */
1222                       asn1_close(&asn1, &offset); /* mark where we are now */
1223                       ename = showbitnames(bits, (con*8)-unused, &props, offset);
1224                       if (asn1_debug) {
1225                               if ( (props.value_id == -1) ||
1226                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1227                                         /* unknown or unexpected, just text */
1228                                         proto_tree_add_text(pt, tvb, boffset,
1229                                                         offset - boffset,
1230                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1231                                                         tname, name,
1232                                                         showbits(bits, (con*8)-unused), ename, empty);
1233                               else {
1234                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1235                                                         offset - boffset, *bits, /* XXX length ? XXX */
1236                                                         textfmt_b, boffset, clsstr, constr, tagstr,
1237                                                         tname, name,
1238                                                         showbits(bits, (con*8)-unused),ename, matchind);
1239                                         if (props.type_id != -1){
1240                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1241                                                                 boffset, offset - boffset, *bits);
1242                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1243                                         }
1244                               }
1245
1246                       } else {
1247                               if ( (props.value_id == -1) ||
1248                                    (tbl_types_wireshark[props.type] != FT_UINT32) )
1249                                         /* unknown or unexpected, just text */
1250                                         proto_tree_add_text(pt, tvb, boffset,
1251                                                         offset - boffset,
1252                                                         "(%s)%s: %s:%s", tname, name,
1253                                                         showbits(bits, (con*8)-unused), ename);
1254                               else {
1255                                         proto_tree_add_uint_format(pt, props.value_id, tvb, boffset,
1256                                                         offset - boffset, *bits, /* XXX length ? XXX */
1257                                                         "(%s)%s: %s:%s ~", tname, name,
1258                                                         showbits(bits, (con*8)-unused), ename);
1259                                         if (props.type_id != -1){
1260                                                 hidden_item = proto_tree_add_uint(pt, props.type_id, tvb,
1261                                                                 boffset, offset - boffset, *bits);
1262                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1263                                         }
1264                               }
1265                       }
1266                       g_free(bits);
1267                       break;
1268
1269                 case BER_UNI_TAG_SET:
1270                 case BER_UNI_TAG_SEQUENCE:
1271                                 /* show full sequence length */
1272                       if (asn1_debug) {
1273                               ename = empty;
1274                               if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1275                                       ename = ", noshow";
1276                               if ( (props.flags & OUT_FLAG_constructed))
1277                                       ename = ", unexpected constructed";
1278
1279                               if (props.value_id == -1)
1280                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1281                                                              textfmt_c, boffset, clsstr, constr, tagstr,
1282                                                              tname, name, ename, empty);
1283                               else {
1284                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1285                                                               boffset, 1, TRUE);
1286                                       /* change te text to to what I really want */
1287                                       proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1288                                                              tagstr, tname, name, ename, matchind);
1289                                           if (props.type_id != -1){
1290                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1291                                                               boffset, 1, TRUE);
1292                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1293                                           }
1294                               }
1295                       } else {
1296                               if (props.value_id == -1) {
1297                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1298                                               ti = proto_tree_add_text(pt, tvb, boffset,
1299                                                                        offset - boffset + len,
1300                                                                        "(%s)%s", tname, name);
1301                               } else {
1302                                       if ( (! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0) )
1303                                               ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1304                                                                        boffset, offset - boffset + len,
1305                                                                        "(%s)%s ~", tname, name);
1306                                       else {
1307                                               /* don't care about the text */
1308                                               ti = hidden_item = proto_tree_add_item(pt, props.value_id, tvb,
1309                                                           boffset, 1, TRUE);
1310                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1311                                       }
1312                                           if (props.type_id != -1){
1313                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1314                                                           boffset, 1, TRUE);
1315                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1316                                           }
1317                               }
1318                       }
1319                       if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1320
1321                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1322                               pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1323                       else
1324                               pt2 = pt;
1325
1326                       offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1327
1328                       if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1329                               proto_item_set_len(ti, offset - boffset);
1330
1331                       break;
1332
1333                 case BER_UNI_TAG_EOC:
1334                       if (asn1_debug) { /* don't show if not debugging */
1335                               proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_d,
1336                                                   boffset, clsstr, constr, tagstr, tname, name,
1337                                                   offset - soffset, empty);
1338                       }
1339                       getPDUprops(&props, soffset, ASN1_EOI, 1, 0); /* mark end of this sequence */
1340                       return offset;
1341
1342                 case BER_UNI_TAG_OID:
1343                       ret = asn1_oid_value_decode(&asn1, len, &oid, &con);
1344                       asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1345                       ename = showoid(oid, con);
1346                       if (asn1_debug) {
1347                               if ( (props.value_id == -1) ||
1348                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1349                                       /* unknown or unexpected, just text */
1350                                       proto_tree_add_text(pt, tvb, boffset, offset - boffset, textfmt_s,
1351                                                           boffset, clsstr, constr, tagstr, tname, name,
1352                                                           ename, empty);
1353                               else {
1354                                       proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1355                                                                  offset - boffset, ename,/* XXX length?*/
1356                                                                  "(%s)%s: %s ~", tname, name, ename);
1357                                           if (props.type_id != -1){
1358                                                   hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1359                                                                 boffset, offset - boffset, ename);
1360                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1361                                           }
1362                               }
1363                       } else {
1364                               if ( (props.value_id == -1) ||
1365                                    (tbl_types_wireshark[props.type] != FT_BYTES) )
1366                                         /* unknown or unexpected, just text */
1367                                         proto_tree_add_text(pt, tvb, boffset,
1368                                                         offset - boffset,
1369                                                         "(%s)%s: %s", tname, name, ename);
1370                               else {
1371                                         proto_tree_add_bytes_format(pt, props.value_id, tvb, boffset,
1372                                                         offset - boffset, ename, /* XXX length ? */
1373                                                         "(%s)%s: %s ~", tname, name, ename);
1374                                         if (props.type_id != -1){
1375                                                 hidden_item = proto_tree_add_bytes(pt, props.type_id, tvb,
1376                                                                 boffset, offset - boffset, ename);
1377                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1378                                         }
1379                               }
1380                       }
1381                       g_free(oid);
1382                       break;
1383
1384                 case BER_UNI_TAG_NULL:
1385                       if (asn1_debug) {
1386                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len, textfmt_s,
1387                                                   boffset, clsstr, constr, tagstr, tname, name,
1388                                                   "[NULL]", empty);
1389                       } else {
1390                               proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1391                                                   "(%s)%s: [NULL]", tname, name);
1392                       }
1393                       offset += len; /* skip value ... */
1394                       break;
1395
1396                 case BER_UNI_TAG_ObjectDescriptor:
1397                 case ASN1_EXT:
1398                 case BER_UNI_TAG_REAL:
1399                 case BER_UNI_TAG_VideotexString:
1400                 case BER_UNI_TAG_GraphicString:
1401                 case BER_UNI_TAG_VisibleString:
1402
1403                 default:
1404                       if (asn1_debug) {
1405                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1406                                                        textfmt_s, boffset, clsstr, constr, tagstr,
1407                                                        tname, name, lenbuf, empty);
1408                       } else {
1409                               ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1410                                                        "(%s)%s: %s bytes", tname, name, lenbuf);
1411                       }
1412                       proto_item_append_text(ti, " *"); /* indicate default is used */
1413                       offset += len; /* skip value ... */
1414                       break;
1415               };
1416               break;
1417
1418             case BER_CLASS_CON:         /* fprintf(stderr, "Context\n"); */
1419             case BER_CLASS_APP:         /* fprintf(stderr, "Application\n"); */
1420             case BER_CLASS_PRI:         /* fprintf(stderr, "Private\n"); */
1421
1422                   if (def && !con) {
1423                         if (props.value_id == -1) /* type unknown, handle as string */
1424                                 goto dostring;
1425                         switch(props.type) {
1426                                 /* this is via the asn1 description, don't trust the length */
1427                         case TBL_INTEGER:
1428                                 if (len > 4)
1429                                         goto dostring;
1430                                 ret = asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1431                                 asn1_close(&asn1, &offset); /* mark where we are now */
1432                                 if (asn1_debug) {
1433                                         if ( (props.value_id == -1) ||
1434                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1435                                                 /* unknown or unexpected, just text */
1436                                                 proto_tree_add_text(pt, tvb,
1437                                                             boffset, offset - boffset,
1438                                                             textfmt_d, boffset, clsstr, constr,
1439                                                             tagstr, tname, name, value, empty);
1440                                         else {
1441                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1442                                                             boffset, offset - boffset, value,
1443                                                             textfmt_d, boffset, clsstr, constr,
1444                                                             tagstr, tname, name, value, matchind);
1445                                                 if (props.type_id != -1){
1446                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1447                                                                 tvb, boffset, offset - boffset, value);
1448                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1449                                                 }
1450                                         }
1451                                 } else {
1452                                         if ( (props.value_id == -1) ||
1453                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1454                                                 /* unknown or unexpected, just text */
1455                                                 proto_tree_add_text(pt, tvb,
1456                                                             boffset, offset - boffset,
1457                                                             "(%s)%s: %d", tname, name, value);
1458                                         else {
1459                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1460                                                             boffset, offset - boffset, value,
1461                                                             "(%s)%s: %d ~", tname, name, value);
1462                                                 if (props.type_id != -1){
1463                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1464                                                                 tvb, boffset, offset - boffset, value);
1465                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1466                                                 }
1467                                         }
1468                                 }
1469                                 break;
1470
1471                         case TBL_ENUMERATED:
1472                                 if (len > 4)
1473                                         goto dostring;
1474                                 ret = asn1_int32_value_decode(&asn1, len, &value); /* read value */
1475                                 asn1_close(&asn1, &offset); /* mark where we are now */
1476                                 ename = getPDUenum(&props, boffset, cls, tag, value);
1477                                 if (asn1_debug) {
1478                                         if ( (props.value_id == -1) ||
1479                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1480                                                 /* unknown or unexpected, just text */
1481                                                 proto_tree_add_text(pt, tvb,
1482                                                            boffset, offset - boffset,
1483                                                            textfmt_e, boffset, clsstr, constr,
1484                                                            tagstr, tname, name, value, ename, empty);
1485                                         else {
1486                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1487                                                            boffset, offset - boffset, value,
1488                                                            textfmt_e, boffset, clsstr, constr,
1489                                                            tagstr, tname, name, value, ename, matchind);
1490                                                 if (props.type_id != -1){
1491                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1492                                                                 tvb, boffset, offset - boffset, value);
1493                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1494                                                 }
1495                                         }
1496                                 } else {
1497                                         if ( (props.value_id == -1) ||
1498                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1499                                                 /* unknown or unexpected, just text */
1500                                                 proto_tree_add_text(pt, tvb,
1501                                                            boffset, offset - boffset,
1502                                                            "(%s)%s: %d:%s", tname, name, value, ename);
1503                                         else {
1504                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1505                                                           boffset, offset - boffset, value,
1506                                                           "(%s)%s: %d:%s ~", tname, name, value, ename);
1507                                                 if (props.type_id != -1){
1508                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1509                                                                 tvb, boffset, offset - boffset, value);
1510                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1511                                                 }
1512                                         }
1513                                 }
1514                                 break;
1515                         case TBL_BITSTRING:
1516                                 if (len > (1+4)) /* max 32 bits ...?.. */
1517                                         goto dostring;
1518                                                                 /* read value */
1519                                 ret = asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1520                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1521                                 ename = showbitnames(bits, (con*8)-unused, &props, offset);
1522                                 if (asn1_debug) {
1523                                         if ( (props.value_id == -1) ||
1524                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1525                                                 /* unknown or unexpected, just text */
1526                                                 proto_tree_add_text(pt, tvb,
1527                                                             boffset, offset - boffset,
1528                                                             textfmt_b, boffset, clsstr, constr,
1529                                                             tagstr, tname, name,
1530                                                             showbits(bits, (con*8)-unused), ename,
1531                                                             empty);
1532                                         else {
1533                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1534                                                             boffset, offset - boffset, *bits,
1535                                                             textfmt_b, boffset, clsstr, constr,
1536                                                             tagstr, tname, name,
1537                                                             showbits(bits, (con*8)-unused), ename,
1538                                                             matchind);
1539                                                 if (props.type_id != -1){
1540                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1541                                                                  tvb, boffset, offset - boffset, *bits);
1542                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1543                                                 }
1544                                         }
1545                                 } else {
1546                                         if ( (props.value_id == -1) ||
1547                                              (tbl_types_wireshark[props.type] != FT_UINT32) )
1548                                                 /* unknown or unexpected, just text */
1549                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1550                                                             "(%s)%s: %s:%s", tname, name,
1551                                                             showbits(bits, (con*8)-unused), ename);
1552                                         else {
1553                                                 proto_tree_add_uint_format(pt, props.value_id, tvb,
1554                                                             boffset, offset - boffset, *bits,
1555                                                             "(%s)%s: %s:%s ~", tname, name,
1556                                                             showbits(bits, (con*8)-unused), ename);
1557                                                 if (props.type_id != -1){
1558                                                         hidden_item = proto_tree_add_uint(pt, props.type_id,
1559                                                                 tvb, boffset, offset - boffset, *bits);
1560                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1561                                                 }
1562                                         }
1563                                 }
1564                                 g_free(bits);
1565                                 break;
1566                         case TBL_BOOLEAN:
1567                                 if (len > 1)
1568                                         goto dostring;
1569                                 ret = asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1570                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1571                                 if (asn1_debug) {
1572                                         if ( (props.value_id == -1) ||
1573                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1574                                                 /* unknown or unexpected, just text */
1575                                                 proto_tree_add_text(pt, tvb,
1576                                                             boffset, offset - boffset,
1577                                                             textfmt_s, boffset, clsstr, constr,
1578                                                             tagstr, tname, name,
1579                                                             value? "true" : "false", empty);
1580                                         else {
1581                                                 proto_tree_add_boolean_format(pt, props.value_id,  tvb,
1582                                                             boffset, offset - boffset, value != 0,
1583                                                             textfmt_s, boffset, clsstr, constr,
1584                                                             tagstr, tname, name,
1585                                                             value? "true" : "false", matchind);
1586                                                 if (props.type_id != -1){
1587                                                         hidden_item = proto_tree_add_boolean(pt, props.type_id,
1588                                                           tvb, boffset, offset - boffset, value != 0);
1589                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1590                                                 }
1591                                         }
1592                                 } else {
1593                                         if ( (props.value_id == -1) ||
1594                                              (tbl_types_wireshark[props.type] != FT_BOOLEAN) )
1595                                                 /* unknown or unexpected, just text */
1596                                                 proto_tree_add_text(pt, tvb,
1597                                                             boffset, offset - boffset,
1598                                                             "(%s)%s: %s", tname, name,
1599                                                             value? "true" : "false");
1600                                         else {
1601                                                 proto_tree_add_boolean_format(pt, props.value_id, tvb,
1602                                                             boffset, offset - boffset, value != 0,
1603                                                             "(%s)%s: %s ~", tname, name,
1604                                                             value? "true" : "false");
1605                                                 if (props.type_id != -1){
1606                                                         hidden_item = proto_tree_add_boolean(pt, props.type_id,
1607                                                           tvb, boffset, offset - boffset, value != 0);
1608                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1609                                                 }
1610                                         }
1611                                 }
1612                                 break;
1613                         case TBL_NULL:
1614                                 if (len > 0)
1615                                         goto dostring;
1616                                 if (asn1_debug) {
1617                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1618                                                             textfmt_s, boffset, clsstr, constr,
1619                                                             tagstr, tname, name, "[NULL]", empty);
1620                                 } else {
1621                                         proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1622                                                             "(%s)%s: [NULL]", tname, name);
1623                                 }
1624                                 offset += len; /* skip value ... */
1625                                 break;
1626                         default:
1627                         dostring:
1628                                 props.value_id = -1; /* unlikely this is correct, dont use it */
1629                                 /* fallthrough */
1630                         case TBL_OCTETSTRING:
1631                                 /* defined length, not constructed, must be a string.... */
1632                                 ret = asn1_string_value_decode(&asn1, len, &octets); /* read value */
1633                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are now */
1634                                 ename = showoctets(octets, len, 2); /* convert octets to printable */
1635                                 if (asn1_debug) {
1636                                         if ( (props.value_id == -1) ||
1637                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1638                                                 /* unknown or unexpected, just text */
1639                                                 proto_tree_add_text(pt, tvb,
1640                                                             boffset, offset - boffset,
1641                                                             textfmt_s, boffset, clsstr, constr,
1642                                                             tagstr, tname, name, ename, empty);
1643                                         else {
1644                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1645                                                             boffset, offset - boffset, (gchar *)octets, /* XXX */
1646                                                             textfmt_s, boffset, clsstr, constr,
1647                                                             tagstr, tname, name, ename, matchind);
1648                                                 if (props.type_id != -1){
1649                                                         hidden_item = proto_tree_add_string(pt, props.type_id,
1650                                                                 tvb, boffset, offset - boffset, (gchar *)octets);
1651                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1652                                                 }
1653                                         }
1654                                 } else {
1655                                         if ( (props.value_id == -1) ||
1656                                              (tbl_types_wireshark[props.type] != FT_STRINGZ) )
1657                                                 /* unknown or unexpected, just text */
1658                                                 proto_tree_add_text(pt, tvb, boffset, offset - boffset,
1659                                                             "(%s)%s: %s", tname, name, ename);
1660                                         else {
1661                                                 proto_tree_add_string_format(pt, props.value_id, tvb,
1662                                                             boffset, offset - boffset, (gchar *)octets, /* XXX */
1663                                                             "(%s)%s: %s ~", tname, name, ename);
1664                                                 if (props.type_id != -1){
1665                                                         hidden_item = proto_tree_add_string(pt, props.type_id,
1666                                                                 tvb, boffset, offset - boffset, (gchar *)octets);
1667                                                         PROTO_ITEM_SET_HIDDEN(hidden_item);
1668                                                 }
1669                                         }
1670                                 }
1671                                 g_free(octets);
1672                                 g_free( (gpointer) ename);
1673                                 break;
1674                         }
1675                   } else {
1676                         /* indefinite length or constructed.... must be a sequence .... */
1677                         /* show full sequence length */
1678                         if (asn1_debug) {
1679                                 ename = empty;
1680                                 if ( (props.flags & OUT_FLAG_dontshow) || asn1_full)
1681                                         ename = ", noshow";
1682                                 if ( (props.flags & OUT_FLAG_constructed))
1683                                         ename = ", unexpected constructed";
1684
1685                                 if (props.value_id == -1)
1686                                       ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1687                                                                  textfmt_c, boffset, clsstr, constr,
1688                                                                  tagstr, tname, name, ename, empty);
1689                                 else {
1690                                       ti = proto_tree_add_item(pt, props.value_id, tvb,
1691                                                               boffset, 1, TRUE);
1692                                       /* change te text to to what I really want */
1693                                       if (ti) {
1694                                         proto_item_set_text(ti, textfmt_c, boffset, clsstr, constr,
1695                                                              tagstr, tname, name, ename, matchind);
1696                                         if (props.type_id != -1){
1697                                               hidden_item = proto_tree_add_item(pt, props.type_id, tvb,
1698                                                               boffset, 1, TRUE);
1699                                                   PROTO_ITEM_SET_HIDDEN(hidden_item);
1700                                         }
1701                                       } else {
1702                                         ti = proto_tree_add_text(pt, tvb, boffset,
1703                                                                  offset - boffset + len,
1704                                                                  textfmt_c, boffset, clsstr, constr,
1705                                                                  tagstr, tname, name, ename, empty);
1706                                       }
1707                                 }
1708                         } else {
1709                                 if (props.value_id == -1) {
1710                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1711                                                 ti = proto_tree_add_text(pt, tvb, boffset,
1712                                                          offset - boffset + len, "(%s)%s", tname, name);
1713                                 } else {
1714                                         if ( ( ! asn1_full) && ((props.flags & OUT_FLAG_dontshow) == 0))
1715                                                 ti = proto_tree_add_none_format(pt, props.value_id, tvb,
1716                                                                 boffset, 1,
1717                                                                 "(%s)%s ~", tname, name);
1718                                         else {
1719                                                 /* don't care about the text */
1720                                                 ti = proto_tree_add_item(pt, props.value_id,
1721                                                              tvb,  boffset, 1, TRUE);
1722                                                 PROTO_ITEM_SET_HIDDEN(ti);
1723                                         }
1724                                         if (props.type_id != -1){
1725                                                 hidden_item = proto_tree_add_item(pt, props.type_id,
1726                                                              tvb,  boffset, 1, TRUE);
1727                                                 PROTO_ITEM_SET_HIDDEN(hidden_item);
1728                                         }
1729                                 }
1730                         }
1731
1732                         if (len == 0) return offset; /* don't recurse if offset isn't going to change */
1733
1734                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1735                                 pt2 = proto_item_add_subtree(ti, ett_seq[level]);
1736                         else
1737                                 pt2 = pt;
1738
1739                         offset = decode_asn1_sequence(tvb, offset, len, pt2, level+1); /* recurse */
1740
1741                         if ( ( ! asn1_full) && (asn1_debug || ((props.flags & OUT_FLAG_dontshow) == 0)))
1742                                 proto_item_set_len(ti, offset - boffset);
1743                   }
1744               break;
1745
1746             default:            /* fprintf(stderr, "Other\n"); */
1747                   if (asn1_debug) {
1748                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1749                                                    textfmt_s, boffset, clsstr, constr, tagstr,
1750                                                    tname, name, lenbuf, empty);
1751                   } else {
1752                           ti = proto_tree_add_text(pt, tvb, boffset, offset - boffset + len,
1753                                                    "(%s)%s: %s bytes %s data", tname, name,
1754                                                    lenbuf, clsstr);
1755                   }
1756                   proto_item_append_text(ti, " *"); /* indicate default is used */
1757                   offset += len; /* skip value ... */
1758                   break;
1759           }
1760           g_free(oname); /* XXX, memory management ? */
1761   }
1762   /* proto_tree_add_text(pt, tvb, offset, 1, "Marker: offset=%d", offset); */
1763
1764   getPDUprops(&props, soffset, ASN1_EOI, 0, 0); /* mark end of this sequence */
1765
1766   return offset;
1767 }
1768 #define READSYNTAX
1769 #ifdef READSYNTAX
1770
1771 /************************************************************************************************/
1772 /*  search throug the ASN.1 description for appropriate names                                   */
1773 /************************************************************************************************/
1774
1775 guint lev_limit = G_MAXINT;
1776
1777 int icount = 0;                 /* item counter */
1778
1779 static guint
1780 parse_tt3(tvbuff_t *tvb, guint offset, guint size, guint level, GNode *ptr)
1781 {
1782         ASN1_SCK asn1;
1783         guint eos, cls, con, tag, len, value;
1784         gboolean def;
1785         guchar *octets, *bits, unused;
1786         subid_t *oid;
1787         GNode *cur_node = 0;
1788
1789         eos = offset + size;
1790
1791         if (level > lev_limit)
1792                 return eos;
1793
1794         while(offset < eos) {
1795                 if (ptr)        /* build pointer tree to all asn1 entities */
1796                         cur_node = g_node_append_data(ptr, GUINT_TO_POINTER(offset));
1797
1798                 asn1_open(&asn1, tvb, offset);
1799                 asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1800                 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1801                 icount++;
1802                 if (!def) {
1803                         len = tvb_length_remaining(tvb, offset);
1804                 }
1805
1806                 switch(cls) {
1807                 case BER_CLASS_UNI:     /* fprintf(stderr, "Universal\n"); */
1808                         switch(tag) {
1809                         case BER_UNI_TAG_INTEGER:
1810                         case BER_UNI_TAG_ENUMERATED:
1811                                 asn1_int32_value_decode(&asn1, len, (gint32 *)&value); /* read value */
1812                                 asn1_close(&asn1, (gint *)&offset); /* mark where we are */
1813                                 break;
1814
1815                         case BER_UNI_TAG_BOOLEAN:
1816                                 asn1_bool_decode(&asn1, len, (gboolean *)&value); /* read value */
1817                                 asn1_close(&asn1, &offset); /* mark where we are */
1818                                 break;
1819
1820                         case BER_UNI_TAG_OCTETSTRING:
1821                         case BER_UNI_TAG_NumericString:
1822                         case BER_UNI_TAG_PrintableString:
1823                         case BER_UNI_TAG_TeletexString:
1824                         case BER_UNI_TAG_IA5String:
1825                         case BER_UNI_TAG_GeneralString:
1826                         case BER_UNI_TAG_UTCTime:
1827                         case BER_UNI_TAG_GeneralizedTime:
1828                                 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1829                                 asn1_close(&asn1, &offset); /* mark where we are */
1830                                 g_free(octets);
1831                                 break;
1832
1833                         case BER_UNI_TAG_BITSTRING:
1834                                 asn1_bits_decode(&asn1, len, &bits, &con, &unused);
1835                                 asn1_close(&asn1, &offset); /* mark where we are */
1836                                 g_free(bits);
1837                                 break;
1838
1839                         case BER_UNI_TAG_SET:
1840                         case BER_UNI_TAG_SEQUENCE:
1841                                 if (len == 0) /* don't recurse if offset isn't going to change */
1842                                         return offset;
1843
1844                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1845                                 break;
1846
1847                         case BER_UNI_TAG_EOC:
1848                                 return offset;
1849
1850                         case BER_UNI_TAG_OID:
1851                                 asn1_oid_value_decode(&asn1, len, &oid, &con);
1852                                 asn1_close(&asn1, &offset); /* mark where we are */
1853                                 g_free(oid);
1854                                 break;
1855
1856                         case BER_UNI_TAG_NULL:
1857                                 offset += len;
1858                                 break;
1859
1860                         case BER_UNI_TAG_ObjectDescriptor:
1861                         case ASN1_EXT:
1862                         case BER_UNI_TAG_REAL:
1863                         case BER_UNI_TAG_VideotexString:
1864                         case BER_UNI_TAG_GraphicString:
1865                         case BER_UNI_TAG_VisibleString:
1866
1867                         default:
1868                                 if (asn1_verbose) g_message("%d skip1 %d", offset, len);
1869                                 offset += len; /* skip value ... */
1870                                 break;
1871                         };
1872                         break;
1873
1874                 case BER_CLASS_CON:             /* fprintf(stderr, "Context\n"); */
1875                         if (def && !con) {
1876                                 /* defined length, not constructed, must be a string.... */
1877                                 asn1_string_value_decode(&asn1, len, &octets); /* read value */
1878                                 asn1_close(&asn1, &offset); /* mark where we are */
1879                                 g_free(octets);
1880                         } else {
1881                                 /* indefinite length or constructed.... must be a sequence .... */
1882                                 if (len == 0) /* don't recurse if offset isn't going to change */
1883                                         return offset;
1884
1885                                 offset = parse_tt3(tvb, offset, len, level+1, cur_node); /* recurse */
1886                         }
1887                         break;
1888
1889                 default:                /* fprintf(stderr, "Other\n"); */
1890                         if (asn1_verbose) g_message("%d skip2 %d", offset, len);
1891                         offset += len; /* skip value ... */
1892                         break;
1893                 }
1894         }
1895         return offset;
1896 }
1897
1898 static void showGNodes(GNode *p, int n);
1899
1900 #if 0
1901 static gboolean
1902 myLeaf(GNode *node, gpointer data)
1903 {
1904         ASN1_SCK asn1;
1905         guint ret, cls, con, tag, def, len;
1906         char *clsstr, *constr, *tagstr;
1907         char tagbuf[BUFLM];
1908         char lenbuf[BUFLM];
1909
1910         (void) data;                    /* make a reference */
1911         asn1_open(&asn1, asn1_desc, (int)node->data);
1912
1913         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
1914
1915         clsstr = asn1_cls[cls];
1916         constr = asn1_con[con];
1917         if ((cls == BER_CLASS_UNI) && ( tag < 32 )) {
1918                 tagstr = asn1_tag[tag];
1919         } else {
1920                 g_snprintf(tagbuf, sizeof(tagbuf), "tag%d", tag);
1921                 tagstr = tagbuf;
1922         }
1923         if (def) {
1924                 g_snprintf(lenbuf, sizeof(lenbuf), "%d", len);
1925         } else {
1926                 strncpy(lenbuf, "indefinite", sizeof(lenbuf));
1927         }
1928
1929         if (asn1_verbose)
1930                 g_message("off=%d: [%s %s %s] len=%s", (int)node->data, clsstr, constr, tagstr, lenbuf);
1931
1932         return FALSE;
1933 }
1934
1935 static void
1936 list_modules(void)
1937 {
1938         if (asn1_verbose) g_message("build GNode tree:");
1939         showGNodes(g_node_first_child(asn1_nodes), 0);
1940         if (asn1_verbose) g_message("end of tree: %d nodes, %d deep, %d leafs, %d branches",
1941                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_ALL),
1942                   g_node_max_height (asn1_nodes),
1943                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_LEAFS),
1944                   g_node_n_nodes(asn1_nodes, G_TRAVERSE_NON_LEAFS) );
1945
1946         g_node_traverse(g_node_first_child(asn1_nodes), G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, myLeaf, 0);
1947
1948 }
1949 #endif
1950
1951 static void
1952 tt_build_tree(void)             /* build a GNode tree with all offset's to ASN.1 entities */
1953 {
1954         if (asn1_nodes)
1955                 g_node_destroy(asn1_nodes);
1956         asn1_nodes = g_node_new(0);
1957         icount = 0;
1958         parse_tt3(asn1_desc, 0, tvb_length(asn1_desc), 0, asn1_nodes);
1959 }
1960
1961
1962 /*****************************************************************************************************/
1963
1964 static guint anonCount;  /* for naming anonymous types */
1965
1966 typedef struct _TBLModule       TBLModule;
1967 typedef struct _TBLTypeDef      TBLTypeDef;
1968 typedef struct _TBLTag          TBLTag;
1969 typedef struct _TBLType         TBLType;
1970 typedef struct _TBLTypeRef      TBLTypeRef;
1971 typedef struct _TBLNamedNumber  TBLNamedNumber;
1972 typedef struct _TBLRange        TBLRange;
1973
1974 enum _tbl_t {
1975         TBLTYPE_Module,
1976         TBLTYPE_TypeDef,
1977         TBLTYPE_Tag,
1978         TBLTYPE_Type,
1979         TBLTYPE_TypeRef,
1980         TBLTYPE_NamedNumber,
1981         TBLTYPE_Range
1982 };
1983 typedef enum _tbl_t tbl_t;
1984 /* text for 'tbl_t' type for debugging */
1985 static const char *data_types[] = {
1986                         "Module",
1987                         "TypeDef",
1988                         "Tag",
1989                         "Type",
1990                         "TypeRef",
1991                         "NamedNumber",
1992                         "Range",
1993 };
1994
1995 enum _TBLTypeContent_t {
1996         TBLTYPETYPE_None,
1997         TBLTYPETYPE_Primitive,
1998         TBLTYPETYPE_Elements,
1999         TBLTYPETYPE_TypeRef
2000 };
2001 typedef enum _TBLTypeContent_t TBLTypeContent_t;
2002
2003 struct _TBLNamedNumber {
2004         tbl_t   type;
2005         guchar  *name;
2006         guint   value;
2007 };
2008
2009 struct _TBLRange {
2010         tbl_t   type;
2011         guint   from;
2012         guint   to;
2013 };
2014
2015 struct _TBLTypeRef {
2016         tbl_t   type;
2017         guint   typeDefId;
2018         gboolean implicit;
2019 };
2020
2021 struct _TBLTag {
2022         tbl_t   type;
2023         guint   tclass;
2024         guint   code;
2025 };
2026
2027 struct _TBLType {
2028         tbl_t   type;
2029         guint   typeId;
2030         gboolean        optional;
2031         TBLTypeContent_t content;
2032         guchar  *fieldName;
2033         gboolean anonymous;
2034         gboolean constraint;
2035 };
2036
2037 struct _TBLTypeDef {
2038         tbl_t   type;
2039         guint   typeDefId;
2040         guchar  *typeName;
2041         guchar  isPdu;
2042 };
2043
2044 struct _TBLModule {
2045         tbl_t   type;
2046         guchar  *name;
2047         subid_t *id;
2048         guint   isUseful;
2049 };
2050
2051 struct _TT {
2052         guint   totalNumModules;
2053         guint   totalNumTypeDefs;
2054         guint   totalNumTypes;
2055         guint   totalNumTags;
2056         guint   totalNumStrings;
2057         guint   totalLenStrings;
2058 } TT;
2059
2060 #define CHECKP(p) {if (p==0){g_warning("pointer==0, line %d **********", __LINE__);return;}}
2061
2062 static guint
2063 get_asn1_int(guint want_tag, guint offset)
2064 {
2065         ASN1_SCK asn1;
2066         guint ret, cls, con, tag, len;
2067         gboolean def;
2068         guint value;
2069
2070         /* g_message("%d get_asn1_int", offset); */
2071
2072         asn1_open(&asn1, asn1_desc, offset);
2073
2074         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2075         if (ret == ASN1_ERR_NOERROR) {
2076                          /* do not check class, both Unversal and Context are OK */
2077                 if (con == ASN1_PRI && tag == want_tag) {
2078                         if (def) {
2079                                 asn1_uint32_value_decode(&asn1, len, &value);
2080                                 return value;
2081                         } else
2082                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2083                 } else
2084                         ret = ASN1_ERR_WRONG_TYPE;
2085         }
2086         g_warning("ASN.1 int mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2087
2088         return 0;
2089 }
2090
2091 static subid_t *                        /* with prepended length ..... */
2092 get_asn1_oid(guint want_tag, guint offset)
2093 {
2094         ASN1_SCK asn1;
2095         guint ret, cls, con, tag, len;
2096         gboolean def;
2097         subid_t *oid;
2098
2099         /* g_message("%d get_asn1_oid", offset); */
2100
2101         asn1_open(&asn1, asn1_desc, offset);
2102
2103         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2104         if (ret == ASN1_ERR_NOERROR) {
2105                         /* do not check class, both Unversal and Context are OK */
2106                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2107                         if (def) {
2108                                 asn1_oid_value_decode(&asn1, len, &oid, &con);
2109                                 oid = g_realloc(oid, con + sizeof(guint)); /* prepend the length */
2110                                 memmove(&oid[1], oid, con*sizeof(guint));
2111                                 oid[0] = con;
2112                                 return oid;
2113                         } else
2114                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2115                 } else
2116                         ret = ASN1_ERR_WRONG_TYPE;
2117         }
2118         g_warning("ASN.1 oid mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2119
2120         return 0;
2121 }
2122
2123 static guchar *                 /* 0 terminated string */
2124 get_asn1_string(guint want_tag, guint offset)
2125 {
2126         ASN1_SCK asn1;
2127         guint ret, cls, con, tag, len;
2128         gboolean def;
2129         guchar *octets;
2130
2131         /* g_message("%d get_asn1_string", offset); */
2132
2133         asn1_open(&asn1, asn1_desc, offset);
2134
2135         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2136         if (ret == ASN1_ERR_NOERROR) {
2137                         /* do not check class, both Unversal and Context are OK */
2138                 if ((con == ASN1_PRI) && (tag == want_tag))     {
2139                         if (def) {
2140                                 asn1_string_value_decode(&asn1, len, &octets);
2141                                 octets = g_realloc(octets, len+1); /* need space for sentinel */
2142                                 octets[len] = 0;
2143                                 return octets;
2144                         } else
2145                                 ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
2146                 } else
2147                         ret = ASN1_ERR_WRONG_TYPE;
2148         }
2149         g_warning("ASN.1 string mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2150
2151         return 0;
2152 }
2153
2154 static guint
2155 get_asn1_uint(guint offset)
2156 {
2157         ASN1_SCK asn1;
2158         guint ret, len, value;
2159
2160         /* g_message( "%d get_asn1_uint", offset); */
2161
2162         asn1_open(&asn1, asn1_desc, offset);
2163
2164         ret = asn1_uint32_decode(&asn1, &value, &len);
2165
2166         if (ret != ASN1_ERR_NOERROR) {
2167                 g_warning("ASN.1 uint mismatch at offset %d, %s", offset, asn1_err_to_str(ret));
2168                 value = 0;
2169         }
2170         return value;
2171 }
2172
2173 static gboolean
2174 check_tag(guint want_tag, guint offset)
2175 {
2176         ASN1_SCK asn1;
2177         guint ret, cls, con, tag, len;
2178         gboolean def;
2179
2180         asn1_open(&asn1, asn1_desc, offset);
2181
2182         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2183         if (ret == ASN1_ERR_NOERROR) {
2184                 ret = (tag == want_tag) ? TRUE : FALSE;
2185                 /* g_message("%d check tag %d, %s", offset, want_tag, ret? "true" : "false"); */
2186                 return ret;
2187         }
2188         g_warning("ASN.1 check_tag at offset %d, %s", offset, asn1_err_to_str(ret));
2189
2190         return FALSE;
2191 }
2192
2193 #if 0
2194 static gboolean
2195 constructed(guint offset)
2196 {
2197         ASN1_SCK asn1;
2198         guint ret, cls, con, tag, def, len;
2199
2200         /* g_message("%d constructed?", offset); */
2201
2202         asn1_open(&asn1, asn1_desc, offset);
2203
2204         ret = asn1_header_decode(&asn1, &cls, &con, &tag, &def, &len);
2205         if (ret == ASN1_ERR_NOERROR) {
2206                 if (con) {
2207                         return TRUE;
2208                 }
2209                 return FALSE;
2210         }
2211         /* g_warning("ASN.1 constructed? at offset %d, %s", offset, asn1_err_to_str(ret)); */
2212
2213         return FALSE;
2214 }
2215 #endif
2216
2217 static void
2218 define_constraint(GNode *p, GNode *q)
2219 {
2220         TBLRange *range = g_malloc(sizeof(TBLRange));
2221         g_node_append_data(q, range);
2222
2223         range->type = TBLTYPE_Range;
2224
2225         /* g_message("define_constraint %p, %p", p, q); */
2226
2227         p = g_node_first_child(p);
2228
2229         if (!p) {
2230                 return;
2231         }
2232
2233         range->from = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2234         p = g_node_next_sibling(p);
2235
2236         if (!p) {
2237                 return;
2238         }
2239
2240         range->to = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2241
2242 }
2243
2244 static void
2245 define_namednumber(GNode *p, GNode *q)
2246 {
2247         TBLNamedNumber *num = g_malloc(sizeof(TBLNamedNumber));
2248         g_node_append_data(q, num);
2249
2250         num->type = TBLTYPE_NamedNumber;
2251
2252         /* g_message("define_namednumber %p, %p", p, q); */
2253
2254         p = g_node_first_child(p);
2255
2256         if (!p) {
2257                 return;
2258         }
2259
2260         num->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2261         p = g_node_next_sibling(p);
2262
2263         if (!p) {
2264                 return;
2265         }
2266
2267         num->value = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2268 }
2269
2270 static void
2271 define_typeref(GNode *p, GNode *q)
2272 {
2273         TBLTypeRef *ref = g_malloc(sizeof(TBLTypeRef));
2274         g_node_append_data(q, ref);
2275
2276         ref->type = TBLTYPE_TypeRef;
2277
2278         /* g_message("define_typeref %p, %p", p, q); */
2279
2280         p = g_node_first_child(p);
2281
2282         if (!p) {
2283                 return;
2284         }
2285
2286         ref->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2287         p = g_node_next_sibling(p);
2288
2289         if (!p) {
2290                 return;
2291         }
2292
2293         ref->implicit = get_asn1_int(BER_UNI_TAG_BOOLEAN, GPOINTER_TO_UINT(p->data));
2294 }
2295
2296 static void
2297 define_tag(GNode *p, GNode *q)
2298 {
2299         TBLTag *type = g_malloc(sizeof(TBLTag));
2300         g_node_append_data(q, type);
2301
2302         type->type = TBLTYPE_Tag;
2303
2304         /* g_message("define_tag %p, %p", p, q); */
2305
2306         p = g_node_first_child(p);
2307
2308         if (!p) {
2309                 return;
2310         }
2311
2312         type->tclass = get_asn1_int(BER_UNI_TAG_ENUMERATED, GPOINTER_TO_UINT(p->data));
2313         p = g_node_next_sibling(p);
2314
2315         if (!p) {
2316                 return;
2317         }
2318
2319         type->code = get_asn1_int(BER_UNI_TAG_INTEGER, GPOINTER_TO_UINT(p->data));
2320
2321 }
2322
2323 static void
2324 define_type(GNode *p, GNode *q)
2325 {
2326         GNode *r;
2327         TBLType *type = g_malloc(sizeof(TBLType));
2328
2329         GNode *t = g_node_append_data(q, type);
2330
2331         type->type = TBLTYPE_Type;
2332
2333         /* g_message("define_type %p, %p", p, q); */
2334
2335         type->typeId = get_asn1_int(0, GPOINTER_TO_UINT(p->data));
2336         p = g_node_next_sibling(p);
2337
2338         type->optional = get_asn1_int(1, GPOINTER_TO_UINT(p->data));
2339         p = g_node_next_sibling(p);
2340
2341         if (check_tag(2, GPOINTER_TO_UINT(p->data))) { /* optional, need empty node if not there ?*/
2342                 r = g_node_first_child(p);
2343                 while (r) {
2344                         define_tag(r, t);
2345                         r = g_node_next_sibling(r);
2346                 }
2347                 p = g_node_next_sibling(p);
2348         }
2349
2350         if (!check_tag(3, GPOINTER_TO_UINT(p->data))) {
2351                 g_warning("expect tag 3, ERROR");
2352         }
2353         r = g_node_first_child(p);
2354                 /* a choice ... */
2355         type->content = TBLTYPETYPE_None;
2356         if (check_tag(0, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Primitive;
2357         if (check_tag(1, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_Elements;
2358         if (check_tag(2, GPOINTER_TO_UINT(r->data))) type->content = TBLTYPETYPE_TypeRef;
2359         switch(type->content) {
2360                 case TBLTYPETYPE_Primitive:
2361                         break;
2362                 case TBLTYPETYPE_Elements:
2363                         r = g_node_first_child(r);
2364                         while (r) {
2365                                 define_type(g_node_first_child(r), t);
2366                                 r = g_node_next_sibling(r);
2367                         }
2368                         break;
2369                 case TBLTYPETYPE_TypeRef:
2370                         define_typeref(r, t);
2371                         break;
2372                 case TBLTYPETYPE_None:
2373                         g_warning("expected a contents choice, error");
2374                         break;
2375         }
2376         p = g_node_next_sibling(p);
2377
2378         type->fieldName = 0;
2379         type->anonymous = FALSE;
2380         if (p && check_tag(4, GPOINTER_TO_UINT(p->data))) {
2381                 type->fieldName = get_asn1_string(4, GPOINTER_TO_UINT(p->data));
2382                 p = g_node_next_sibling(p);
2383         } else {
2384                 type->anonymous = TRUE;
2385         }
2386
2387         type->constraint = FALSE;
2388         if (p && check_tag(5, GPOINTER_TO_UINT(p->data))) {
2389                 type->constraint = TRUE;
2390                 define_constraint(p, t);
2391                 p = g_node_next_sibling(p);
2392         }
2393
2394         if (p && check_tag(6, GPOINTER_TO_UINT(p->data))) {
2395                 r =  g_node_first_child(p);
2396                 while(r) {
2397                         define_namednumber(r, t);
2398                         r = g_node_next_sibling(r);
2399                 }
2400         }
2401 }
2402
2403 static void
2404 define_typedef(GNode *p, GNode *q)
2405 {
2406         TBLTypeDef *type_def = g_malloc(sizeof(TBLTypeDef));
2407
2408         GNode *t = g_node_append_data(q, type_def);
2409
2410         /* g_message("define_typedef %p, %p", p, q); */
2411
2412         type_def->type = TBLTYPE_TypeDef;
2413
2414         p = g_node_first_child(p);
2415
2416         if (!p) {
2417                 return;
2418         }
2419
2420         type_def->typeDefId = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2421         p = g_node_next_sibling(p);
2422
2423         if (!p) {
2424                 return;
2425         }
2426
2427         type_def->typeName = get_asn1_string(BER_UNI_TAG_PrintableString, GPOINTER_TO_UINT(p->data));
2428         p = g_node_next_sibling(p);
2429
2430         if (!p) {
2431                 return;
2432         }
2433
2434         define_type(g_node_first_child(p), t);
2435         p = g_node_next_sibling(p);
2436
2437         type_def->isPdu = (p != 0);  /* true if it exists, value ignored */
2438 }
2439
2440 static void
2441 define_module(GNode *p, GNode *q)
2442 {
2443         TBLModule *module = g_malloc(sizeof(TBLModule));
2444
2445         GNode *m = g_node_append_data(q, module);
2446
2447         /* g_message("define_module %p %p", p, q); */
2448
2449         module->type = TBLTYPE_Module;
2450
2451         p = g_node_first_child(p);
2452         
2453         if (!p) {
2454                 return;
2455         }
2456
2457         module->name = get_asn1_string(0, GPOINTER_TO_UINT(p->data));
2458         p = g_node_next_sibling(p);
2459
2460         module->id = 0;
2461         if (check_tag(1, GPOINTER_TO_UINT(p->data))) { /* optional */
2462                 module->id = get_asn1_oid(1, GPOINTER_TO_UINT(p->data));
2463                 p = g_node_next_sibling(p);
2464         }
2465
2466         module->isUseful = get_asn1_int(2, GPOINTER_TO_UINT(p->data));
2467         p = g_node_next_sibling(p);
2468
2469         p = g_node_first_child(p);
2470         while (p) {
2471                 define_typedef(p, m);
2472                 p = g_node_next_sibling(p);
2473         }
2474 }
2475
2476 typedef struct _SearchDef SearchDef;
2477 struct _SearchDef {
2478         const char *key;
2479         GNode *here;
2480 };
2481
2482 static gboolean
2483 is_typedef(GNode *node, gpointer data)
2484 {
2485         TBLTypeDef *d = (TBLTypeDef *)node->data;
2486         SearchDef *s = (SearchDef *)data;
2487
2488         if (d == 0) return FALSE;
2489         if (d->type != TBLTYPE_TypeDef) return FALSE;
2490         if (strcmp(s->key, d->typeName) == 0) {
2491                 s->here = node;
2492                 return TRUE;
2493         }
2494         return FALSE;
2495 }
2496
2497 typedef struct _TypeRef TypeRef;
2498 struct _TypeRef {
2499         GNode *type;
2500         char *name;
2501         guchar defclass;
2502         guint deftag;
2503         GNode *pdu;             /* location in PDU descriptor tree */
2504         guint level;            /* recursion counter */
2505         GNode *typetree;
2506         GPtrArray *refs;        /* pointers to PDUinfo structures teferencing this entry */
2507 };
2508
2509 typedef struct _NameDefs NameDefs;
2510 struct _NameDefs {
2511         guint max;
2512         guint used;
2513         TypeRef *info;
2514 };
2515 #define ALLOC_INCR 4
2516 #define CLASSREF (BER_CLASS_PRI+1)
2517
2518 static gboolean
2519 is_named(GNode *node, gpointer data)
2520 {
2521         TBLNamedNumber *num = (TBLNamedNumber *)node->data;
2522         NameDefs *n = (NameDefs *)data;
2523         guint oldmax;
2524
2525         if (num == 0) return FALSE;
2526         if (num->type != TBLTYPE_NamedNumber) return FALSE;
2527
2528         if (num->value >= n->max) { /* need larger array */
2529                 oldmax = n->max;
2530                 n->max = num->value + ALLOC_INCR;
2531                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2532                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2533         }
2534         if (num->value > n->used)  /* track max used value, there may be holes... */
2535                 n->used = num->value;
2536
2537         n->info[num->value].name = num->name;
2538
2539         return FALSE;
2540 }
2541
2542 static gboolean
2543 index_typedef(GNode *node, gpointer data)
2544 {
2545         TBLTypeDef *d = (TBLTypeDef *)node->data;
2546         NameDefs *n = (NameDefs *)data;
2547         TypeRef *t;
2548         TBLTag *tag;
2549         guint oldmax;
2550
2551         if (d == 0) return FALSE;
2552         if (d->type != TBLTYPE_TypeDef) return FALSE;
2553
2554         if (d->typeDefId >= n->max) { /* need larger array */
2555                 oldmax = n->max;
2556                 n->max = d->typeDefId + ALLOC_INCR;
2557                 n->info = g_realloc(n->info, n->max * sizeof(TypeRef));
2558                 memset(&n->info[oldmax], 0, (n->max - oldmax) * sizeof(TypeRef));
2559         }
2560         if (d->typeDefId > n->used)  /* track max used value, there may be holes... */
2561                 n->used = d->typeDefId;
2562
2563         t = &(n->info[d->typeDefId]);
2564         t->name = d->typeName;
2565         t->type = node;
2566         t->refs = g_ptr_array_new();    /* collect references here */
2567         node = g_node_first_child(node); /* the real type */
2568         tag = (TBLTag *)node->data;
2569         if ((tag->type == TBLTYPE_Type) && (((TBLType *)(void *)tag)->typeId == TBL_CHOICE)) {
2570                 /* no reasonable default... ! */
2571                 t->defclass = 3; /* Private .... */
2572                 t->deftag= 9999; /* a random value */
2573         } else {
2574                 node = g_node_first_child(node); /* the default tag */
2575                 tag = (TBLTag *)node->data;
2576                 switch(tag->type) {
2577                 case TBLTYPE_Tag:
2578                         t->defclass = tag->tclass;
2579                         t->deftag = tag->code;
2580                         break;
2581                 case TBLTYPE_TypeRef: /* take values from another one, may not be defined yet... */
2582                         t->defclass = CLASSREF; /* invalid class.. */
2583                         t->deftag = ((TBLTypeRef *)tag)->typeDefId;
2584                         break;
2585                 default:
2586                         g_warning("***** index_typedef: expecting a tag or typeref, found %s *****",
2587                                         data_types[tag->type]);
2588                         t->defclass = 3; /* Private .... */
2589                         t->deftag= 9998; /* another random value */
2590                         break;
2591                 }
2592         }
2593
2594         return FALSE;
2595 }
2596
2597 static TypeRef *typeDef_names = 0;
2598 static guint numTypedefs = 0;
2599
2600 static gboolean
2601 free_node_data(GNode *node, gpointer data _U_)
2602 {
2603         g_free(node->data);
2604         return FALSE;
2605 }
2606
2607 static void
2608 get_values(void)                /* collect values from ASN.1 tree */
2609                                 /* coded according to the tbl.asn1 description of snacc output */
2610 {                               /* This routine does not leave references to the tvbuff or */
2611                                 /* to the asn1_nodes, both can be freed by the caller of this.*/
2612         GNode *p;
2613         SearchDef sd;
2614         NameDefs nd;
2615         guint i;
2616         char X;
2617         const char *t, *s, *E;
2618         static char missing[] = "  **missing**  ";
2619
2620         if (asn1_verbose) g_message("interpreting tree");
2621         typeDef_names = 0;  /* just forget allocated any data .... */
2622
2623         if (data_nodes) {
2624                 g_node_traverse(data_nodes, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2625                     free_node_data, NULL);
2626                 g_node_destroy(data_nodes);
2627         }
2628
2629         data_nodes = g_node_new(0);
2630
2631         p = g_node_first_child(asn1_nodes); /* top of the data tree */
2632
2633         p = g_node_first_child(p);
2634         if (!p) return;
2635         TT.totalNumModules = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2636         p = g_node_next_sibling(p);
2637         if (!p) return;
2638         TT.totalNumTypeDefs = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2639         p = g_node_next_sibling(p);
2640         if (!p) return;
2641         TT.totalNumTypes = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2642         p = g_node_next_sibling(p);
2643         if (!p) return;
2644         TT.totalNumTags = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2645         p = g_node_next_sibling(p);
2646         if (!p) return;
2647         TT.totalNumStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2648         p = g_node_next_sibling(p);
2649         if (!p) return;
2650         TT.totalLenStrings = get_asn1_uint(GPOINTER_TO_UINT(p->data));
2651         p = g_node_next_sibling(p);
2652
2653         p = g_node_first_child(p);
2654         while (p) {
2655                 define_module(p, data_nodes);
2656                 p = g_node_next_sibling(p);
2657         }
2658
2659         /* g_message("finished with tree"); */
2660
2661         if (!tbl_types_verified) { /* verify snacc TBLTypeId contents */
2662                 sd.key = "TBLTypeId";
2663                 sd.here = 0;
2664                 g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
2665                 if (asn1_verbose) g_message("%s %sfound, %p", sd.key, sd.here?empty:"not ", (void *)sd.here);
2666                 if (sd.here) {
2667                         nd.max = 8;
2668                         nd.used = 0;
2669                         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2670                         g_node_traverse(sd.here, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_named,
2671                                                 (gpointer)&nd);
2672                         if (asn1_verbose) g_message("tbltypenames: max=%d, info=%p", nd.max, (void *)nd.info);
2673                         E = empty;
2674                         for (i=0; i<=nd.used; i++) { /* we have entries in addition to snacc's */
2675                                 X = 'X';
2676                                 t = TBLTYPE(i);
2677                                 s = nd.info[i].name;
2678                                 if (s == 0) s = missing;
2679                                 if (g_strcmp(t, s) == 0) { /* OK ! */
2680                                         X = ' ';
2681                                         t = empty;
2682                                 } else {
2683                                         E = ", X  with errors  X";
2684                                 }
2685                                 if (asn1_verbose) g_message(" %c %2d %s %s", X, i, s, t);
2686                         }
2687                         if (asn1_verbose) g_message("OK, TBLTypeId's index verified%s", E);
2688                 }
2689                 tbl_types_verified = TRUE;
2690         }
2691         /* build table with typedef names */
2692         nd.max = 8;
2693         nd.used = 0;
2694         nd.info = g_malloc0(nd.max * sizeof(TypeRef));
2695         g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, index_typedef, (gpointer)&nd);
2696         if (asn1_verbose) g_message("tbltypedefs: max=%d, info=%p", nd.max, (void *)nd.info);
2697
2698         for (i=0; i<=nd.used; i++) { /* show what we have in the index now */
2699                 TypeRef *ref = &(nd.info[i]);
2700                 t = ref->name;
2701                 if (t == 0) {
2702                         t = ref->name = missing;
2703                         if (asn1_verbose) g_message("  %3d %s", i, t);
2704                 } else {
2705                         if (asn1_verbose) g_message("  %3d %s, %c%d", i, t,
2706                                                     tag_class[ref->defclass], ref->deftag);
2707                 }
2708                 if (ref->pdu) { /* should be 0 */
2709                         if (asn1_verbose) g_message("* %3d %s pdu=%p", i, t, (void *)ref->pdu);
2710                 }
2711         }
2712         typeDef_names = nd.info;
2713         numTypedefs = i;
2714         if (asn1_verbose) g_message("OK, %d TBLTypeDef's index set up", numTypedefs);
2715
2716 }
2717
2718 static void
2719 showGNode(GNode *p, int n)
2720 {
2721
2722   const char *fn, *s = empty;
2723         if (p == 0) return;
2724         n *=2; /* 2 spaces per level */
2725         if (p->data) { /* show value ... */
2726                 /* g_message("show %p, type %d", p, ((TBLTag *)p->data)->type); */
2727                 switch (((TBLTag *)p->data)->type) {
2728                 case TBLTYPE_Module: {
2729                         TBLModule *m = (TBLModule *)p->data;
2730                         if (asn1_verbose)
2731                                 g_message("%*smodule %s%s", n, empty, m->name,
2732                                                 m->isUseful ? ", useful" : empty);
2733                         };
2734                         break;
2735                 case TBLTYPE_TypeDef: {
2736                         TBLTypeDef *t = (TBLTypeDef *)p->data;
2737                         if (asn1_verbose)
2738                                 g_message("%*stypedef %d %s%s", n, empty, t->typeDefId, t->typeName,
2739                                                 t->isPdu ? ", isPDU" : empty);
2740                         };
2741                         break;
2742                 case TBLTYPE_Type: {
2743                         TBLType *t = (TBLType *)p->data;
2744                         if (t->fieldName)
2745                                 s = t->fieldName;
2746                         /* typeId is a value from enum TBLTypeId */
2747                         fn = TBLTYPE(t->typeId);
2748                         if (asn1_verbose) g_message("%*stype %d[%s]%s [%s]", n, empty, t->typeId, fn,
2749                                         t->optional ? " opt" : empty, s );
2750                         };
2751                         break;
2752                 case TBLTYPE_Tag: {
2753                         TBLTag *t = (TBLTag *)p->data;
2754                         if ((t->tclass == BER_CLASS_UNI) && (t->code < 32))
2755                                 s = asn1_tag[t->code];
2756                         if (asn1_verbose) g_message("%*stag %c%d[%s]", n, empty,
2757                                                     tag_class[t->tclass], t->code, s);
2758                         };
2759                         break;
2760                 case TBLTYPE_NamedNumber: {
2761                         TBLNamedNumber *nn = (TBLNamedNumber *)p->data;
2762                         if (asn1_verbose) g_message("%*snamednumber %2d %s", n, empty,
2763                                                     nn->value, nn->name);
2764                         };
2765                         break;
2766                 case TBLTYPE_Range: {
2767                         TBLRange *r = (TBLRange *)p->data;
2768                         if (asn1_verbose) g_message("%*srange %d .. %d", n, empty,
2769                                                     r->from, r->to );
2770                         };
2771                         break;
2772                 case TBLTYPE_TypeRef: {
2773                         TBLTypeRef *r = (TBLTypeRef *)p->data;
2774                         if (typeDef_names)
2775                                 s = typeDef_names[r->typeDefId].name;
2776                         if (asn1_verbose) g_message("%*styperef %d[%s]%s", n, empty,
2777                                                   r->typeDefId, s, r->implicit ? ", implicit" : empty );
2778                         };
2779                         break;
2780                 default: {
2781                         TBLTag *x = (TBLTag *)p->data;
2782                         if (asn1_verbose) g_message("%*s--default-- type=%d", n, empty, x->type);
2783                         };
2784                         break;
2785                 }
2786         } else {        /* just show tree */
2787                 if (asn1_verbose)
2788                         g_message("%*snode=%p, data=%p, next=%p, prev=%p, parent=%p, child=%p",
2789                                   n, empty, (void *)p, (void *)p->data, (void *)p->next, (void *)p->prev, (void *)p->parent, (void *)p->children);
2790         }
2791 }
2792
2793 static void
2794 showGNodes(GNode *p, int n)
2795 {
2796         if (p == 0) return;
2797         showGNode(p, n);
2798         showGNodes(p->children, n+1);
2799         showGNodes(p->next, n);
2800 }
2801
2802 #if 0
2803 static void showGenv(GNode *p, int n, int m)
2804 {
2805         int i;
2806
2807         if (p == 0) return;
2808         if (n > m) {
2809                 if (asn1_verbose) g_message("%*s.....", n*2, empty);
2810                 return;
2811         }
2812
2813         for(i=0; p && (i < 3); p = p->next, i++) {
2814                 showGNode(p, n);
2815                 showGenv(p->children, n+1, m);
2816         }
2817         if (p && asn1_verbose) g_message("%*s.....", n*2, empty);
2818
2819 }
2820 #endif
2821
2822 static void
2823 debug_dump_TT(void)             /* dump contents of TT struct, for debugging */
2824 {
2825         if (asn1_verbose)
2826                 g_message("modules=%d, defs=%d, types=%d, tags=%d, strings=%d, lenstrings=%d",
2827                         TT.totalNumModules,
2828                         TT.totalNumTypeDefs,
2829                         TT.totalNumTypes,
2830                         TT.totalNumTags,
2831                         TT.totalNumStrings,
2832                         TT.totalLenStrings);
2833 }
2834
2835 static void
2836 my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
2837                 const gchar *message, gpointer user_data)
2838 {
2839 static FILE* logf = 0;
2840 static char eol[] = "\r\n";
2841
2842         (void) log_domain; (void) log_level; (void) user_data; /* make references */
2843
2844         if (logf == NULL && asn1_logfile) {
2845                 logf = ws_fopen(asn1_logfile, "w");
2846         }
2847         if (logf) {
2848         fputs(message, logf);
2849         fputs(eol, logf);
2850         fflush(logf);   /* debugging ... */
2851         }
2852 }
2853
2854 static void
2855 read_asn1_type_table(const char *filename)
2856 {
2857         FILE *f;
2858         guint size;
2859         guchar *data;
2860         struct stat file_stat;
2861         static guint mylogh = 0;
2862
2863         if ((filename == 0) || (strlen(filename) == 0))
2864                 return;         /* no filename provided */
2865
2866         f = ws_fopen(filename, "rb");
2867         if (f == 0) {
2868                 /*
2869                  * Ignore "file not found" errors if it's the old default
2870                  * ASN.1 file name, as we never shipped such a file.
2871                  * Also, on Win32, ignore the earlier default, which
2872                  * had a "/" rather than a "\" as the last pathname
2873                  * separator.
2874                  */
2875 #ifdef _WIN32
2876                 if (strcmp(filename, bad_separator_old_default_asn1_filename) != 0)
2877 #endif
2878                         if ((strcmp(filename, old_default_asn1_filename) != 0) || errno != ENOENT)
2879                                 report_open_failure(filename, errno, FALSE);
2880                 return;
2881         }
2882         fstat(fileno(f), &file_stat);
2883         size = (int)file_stat.st_size;
2884         if (size == 0) {
2885                 if (asn1_verbose) g_message("file %s is empty, ignored", filename);
2886                 fclose(f);
2887                 return;
2888         }
2889         if (asn1_verbose) g_message("reading %d bytes from %s", size, filename);
2890
2891         data = g_malloc(size);
2892         if (fread(data, size, 1, f) < 1) {
2893                 g_warning("error reading %s, %s", filename, g_strerror(errno));
2894         }
2895         fclose(f);
2896
2897         if (asn1_verbose) {
2898           /* ***** from the time when logging was just in a console... *****
2899            * g_message("******* Type ^S and change console buffer size to 9999 and type ^Q *******\n"
2900            *            "  Sleep 5 sec...");
2901            * Sleep(5 * 1000);
2902            */
2903
2904
2905                 g_message("logging to file %s", asn1_logfile);
2906
2907                 if (mylogh == 0) {
2908                         mylogh = g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
2909                                                     | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
2910                 }
2911         }
2912
2913         asn1_desc = tvb_new_real_data(data, size, size);
2914
2915         tt_build_tree();
2916         if (asn1_verbose) g_message("read %d items from %s", icount, filename);
2917
2918 #if 0
2919         list_modules();
2920 #endif
2921
2922         get_values();
2923
2924         g_node_destroy(asn1_nodes);
2925         asn1_nodes = NULL;
2926
2927         tvb_free(asn1_desc);
2928         asn1_desc = NULL;
2929
2930         g_free(data);
2931         data = NULL;
2932
2933         showGNodes(data_nodes, 0);
2934
2935         debug_dump_TT();
2936 }
2937
2938
2939 /* XXX - Shoudn't we make sure we're not dereferencing a NULL pointer here? */
2940 #define CHECKTYPE(p,x) {if (((TBLTag *)(p)->data)->type != (x)) \
2941         g_warning("**** unexpected type %s, want %s, at line %d", \
2942                         data_types[((TBLTag *)p->data)->type], data_types[(x)], __LINE__);}
2943
2944
2945 static void
2946 save_reference(PDUinfo *p)
2947 {
2948         gint i = p->mytype;
2949
2950         if (i == -1)
2951                 i = p->basetype;
2952
2953         g_ptr_array_add(typeDef_names[i].refs, (gpointer)p);
2954 }
2955
2956 static void
2957 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex);
2958
2959
2960
2961         /* evaluate typeref, pointer to current pdu node and typedef */
2962 static void
2963 tbl_typeref(gint n, GNode *pdu, GNode *tree, guint fullindex)
2964 {
2965         GNode *q;
2966         PDUinfo *p = (PDUinfo *)pdu->data, *p1;
2967         guint nvals;
2968         value_string *v;
2969         char ss[128];
2970         int i;
2971
2972         if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
2973                 g_warning("****tbl_typeref: n>40, return [recursion too deep] ****************");
2974                 return;
2975         }
2976
2977         CHECKTYPE(tree, TBLTYPE_TypeDef);
2978
2979         if (asn1_verbose) g_message("%*s+tbl_typeref %s [%s, tag %c%d]", n*2, empty,
2980                                     p->name, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
2981
2982         p->typenum = ((TBLTypeDef *)tree->data)->typeDefId; /* name of current type */
2983         p->flags |= PDU_TYPEDEF;
2984
2985         tree = g_node_first_child(tree);                /* move to its underlying type */
2986         CHECKTYPE(tree, TBLTYPE_Type);
2987         p->type = ((TBLType *)tree->data)->typeId;
2988
2989         q = g_node_first_child(tree);           /* the tag of this type entry ... is optional... */
2990         if (((TBLTag *)q->data)->type == TBLTYPE_Tag) {
2991                 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
2992                         guint xcls, xtag;
2993                         xcls = p->tclass;
2994                         xtag = p->tag;
2995                                 /* XXX -- hack -- hack -- hack -- hack -- hack --
2996                                  * only change tag when class+tag == EOC,
2997                                  * or class is a reference,
2998                                  * or new class is not universal.
2999                                  */
3000                         if ( ((xcls|xtag) == 0) || (xcls == CLASSREF) ||
3001                                         (((TBLTag *)q->data)->tclass != BER_CLASS_UNI) ) {
3002                                 p->tclass = ((TBLTag *)q->data)->tclass;
3003                                 p->tag = ((TBLTag *)q->data)->code;
3004                                 if (asn1_verbose)
3005                                         g_message("%*s*change typeref tag from %c%d to %c%d",
3006                                                   n*2, empty,
3007                                                   tag_class[xcls],
3008                                                   xtag,
3009                                                   tag_class[p->tclass],
3010                                                   p->tag);
3011                         } else {
3012                                 if (asn1_verbose)
3013                                         g_message("%*sNOT changing tag from %c%d to %c%d",
3014                                                   n*2, empty,
3015                                                   tag_class[xcls],
3016                                                   xtag,
3017                                                   tag_class[((TBLTag *)q->data)->tclass],
3018                                                   ((TBLTag *)q->data)->code);
3019
3020                         }
3021                 }
3022         } else {
3023
3024                 ss[0] = 0;
3025                 if (p->tclass==CLASSREF)
3026                         g_snprintf(ss, 128, ", CLASSREF %d", p->tag);
3027                 if (asn1_verbose) g_message("%*sno typeref tag%s", n*2, empty, ss);
3028
3029                 if (p->tclass==CLASSREF) {
3030                         TypeRef *tr;
3031                         i = p->basetype;
3032                         /* CLASSREF....., get it defined using type of the reference */
3033
3034                         /* p->basetype may be -1 .... ? XXX */
3035                         if (i == -1)
3036                                 i = p->tag;
3037                         tr = &typeDef_names[i];
3038                         if (asn1_verbose)
3039                                 g_message("%*s*refer2 to type#%d %s, %p", n*2, empty,
3040                                           p->tag, tr->name, (void *)tr->pdu);
3041
3042                         tbl_typeref(n+1, pdu, tr->type, fullindex);
3043
3044                         return;
3045                 }
3046         }
3047
3048         if (asn1_verbose)
3049                 g_message("%*sinclude typedef %d %s %s [%p:%s, tag %c%d]", n*2, empty, p->typenum,
3050                           p->name, p->typename, (void *)p, TBLTYPE(p->type), tag_class[p->tclass], p->tag);
3051
3052         switch(p->type) {
3053         case TBL_BITSTRING:
3054         case TBL_ENUMERATED:
3055                 /* names do not have a fullname */
3056                 if (asn1_verbose) g_message("%*s*collection T %s", n*2, empty, p->name);
3057                         /* read the enumeration [save min-max somewhere ?] */
3058                 p->value_hf.hfinfo.type = tbl_types_wireshark[p->type]; /* XXX change field type... */
3059                 p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3060
3061                 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3062
3063                 save_reference(p);
3064
3065                 if (asn1_verbose)
3066                         g_message("regtype1: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3067                                   p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3068                                   p->name, p->fullname,
3069                                   tbl_types_wireshark_txt[p->type], p->value_id);
3070                 p1 = p;
3071                 nvals = 0;
3072                 while((q = g_node_next_sibling(q))) {
3073                         CHECKTYPE(q, TBLTYPE_NamedNumber);
3074                         p = g_malloc0(sizeof(PDUinfo));
3075                         nvals++;
3076                         p->type = TBL_ENUMERATED;
3077                         p->name = (((TBLNamedNumber *)q->data)->name);
3078                         p->tag = (((TBLNamedNumber *)q->data)->value);
3079                         p->flags = PDU_NAMEDNUM;
3080                         if (asn1_verbose) g_message("%*s  %3d %s", n*2, empty, p->tag, p->name);
3081                         g_node_append_data(pdu, p);
3082                 }
3083
3084                 /* list all enum values in the field structure for matching */
3085                 p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3086                 q = g_node_first_child(pdu);
3087                 nvals = 0;
3088                 while(q) {
3089                         p = (PDUinfo *)q->data;
3090                         v[nvals].value = p->tag;
3091                         v[nvals].strptr = p->name;
3092 /* g_message("enumval2:  %d %s %d %s %s", nvals, p1->name, p->tag, p->name, tbl_types_asn1[p1->type]); */
3093                         nvals++;
3094                         q = g_node_next_sibling(q);
3095                 }
3096                 /* last entry is already initialized to { 0, NULL } */
3097
3098                 break;
3099
3100         case TBL_CHOICE:
3101                 if (p->value_id == -1) { /* not yet registered ..... */
3102                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3103                         p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3104                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3105
3106                         save_reference(p);
3107
3108                         if (asn1_verbose)
3109                                 g_message("regtype2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3110                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3111                                           p->name, p->fullname,
3112                                           tbl_types_wireshark_txt[p->type], p->value_id);
3113                 }
3114                 tbl_type(n, pdu, q, fullindex);
3115                 break;
3116
3117         default:
3118                 if (p->value_id == -1) { /* not yet registered ..... */
3119                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3120                         p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3121                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3122
3123                         save_reference(p);
3124
3125                         if (asn1_verbose)
3126                                 g_message("regtype3: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3127                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3128                                           p->name, p->fullname,
3129                                           tbl_types_wireshark_txt[p->type], p->value_id);
3130                 }
3131                 tbl_type(n, pdu, g_node_next_sibling(q), fullindex);
3132         }
3133 }
3134
3135 static void
3136 tbl_type(gint n, GNode *pdu, GNode *list, guint fullindex) /* indent, pdu, source type node list */
3137 {
3138         GNode *q, *pdu1;
3139         PDUinfo *p, *p1;
3140         guint ni;
3141         guint nvals;
3142         value_string *v;
3143
3144         if (n > 40) {  /* don't believe this....! ...... stop recursion ...... */
3145                 g_warning("****tbl_type: n>40, return [recursion too deep] ****************");
3146                 return;
3147         }
3148
3149         /* showGenv(list, n, n+1); */
3150
3151         ni = fullindex;
3152         pdu1 = pdu;             /* save start location for append */
3153         while (list) {          /* handle all entries */
3154                 if (asn1_verbose)
3155                         g_message("%*s+handle a %s, list=%p", n*2, empty,
3156                                   data_types[((TBLTag *)list->data)->type], (void *)list);
3157
3158                 if (((TBLTag *)list->data)->type == TBLTYPE_Range) { /* ignore this ..... */
3159                         list = g_node_next_sibling(list);
3160                         if (asn1_verbose) g_message("%*s*skip range", n*2, empty);
3161                         if (list == 0)
3162                                 break;
3163                 }
3164
3165                 /******* change to positive comparation, but leave comment for reference
3166                  * if (((TBLTag *)list->data)->type != TBLTYPE_TypeRef) {
3167                  *      CHECKTYPE(list, TBLTYPE_Type);
3168                  */
3169
3170                 if (((TBLTag *)list->data)->type == TBLTYPE_Type) {
3171                         CHECKTYPE(list, TBLTYPE_Type);
3172
3173                         p = g_malloc0(sizeof(PDUinfo));
3174                         pdu = g_node_append_data(pdu1, p);
3175
3176                         p->type = ((TBLType *)list->data)->typeId;
3177                         p->typename = tbl_types_asn1[p->type]; /* the default type */
3178                         p->typenum = -1;
3179                         p->mytype = -1;
3180                         p->basetype = ((PDUinfo *)pdu1->data)->typenum;
3181                         p->flags = PDUinfo_initflags;
3182                         p->flags |= (((TBLType *)list->data)->anonymous ? PDU_ANONYMOUS : 0);
3183                         p->flags |= (((TBLType *)list->data)->optional ? PDU_OPTIONAL : 0);
3184
3185                         if (((TBLType *)list->data)->fieldName == 0) { /* no name assigned */
3186                                 /* assign an anonymous name [XXX refer to parent typename...] */
3187                                 ((TBLType *)list->data)->fieldName =
3188                                                         g_strdup_printf("anon%d", anonCount++);
3189                         }
3190                         p->name = ((TBLType *)list->data)->fieldName;
3191
3192                         ni = fullindex;
3193                         ni += g_snprintf(&fieldname[ni], sizeof(fieldname) - ni, ".%s", p->name);
3194                         p->fullname = g_strdup(fieldname);
3195
3196                         /* initialize field info */
3197                         p->value_id = -1;
3198                         p->type_id = -1;
3199                         p->value_hf.p_id = &(p->value_id);
3200                         p->value_hf.hfinfo.name = p->fullname;
3201                         p->value_hf.hfinfo.abbrev = p->fullname;
3202                         p->value_hf.hfinfo.type = tbl_types_wireshark[p->type];
3203                         p->value_hf.hfinfo.display = tbl_display_wireshark[p->type];
3204                         p->value_hf.hfinfo.blurb = p->fullname;
3205                         /* all the other fields are already 0 ! */
3206
3207                         if (p->type < TBL__SIMPLE) {
3208                                 /* only register fields with a value here, postpone others */
3209                                 proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3210
3211                                 save_reference(p);
3212
3213                                 if (asn1_verbose)
3214                                         g_message("register: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3215                                                   p->mytype, p->typenum, p->basetype, p->flags,
3216                                                   p->typename, p->name, p->fullname,
3217                                                   tbl_types_wireshark_txt[p->type], p->value_id);
3218                         }
3219
3220                         q = g_node_first_child(list);
3221                 } else {
3222                         p = (PDUinfo *)pdu->data;
3223                         q = list;
3224                 }
3225
3226
3227                 if (asn1_verbose) g_message("%*s*switch %s %s", n*2, empty, p->name, TBLTYPE(p->type));
3228
3229                 switch (p->type) {
3230                 case TBL_BOOLEAN:
3231                 case TBL_INTEGER:
3232                 case TBL_OCTETSTRING:
3233                 case TBL_NULL:
3234                 case TBL_OID:
3235                 case TBL_REAL:
3236                         CHECKTYPE(q, TBLTYPE_Tag);
3237                         p->tclass = ((TBLTag *)q->data)->tclass;
3238                         p->tag = ((TBLTag *)q->data)->code;
3239                         break;
3240
3241                 case TBL_BITSTRING:
3242                 case TBL_ENUMERATED:
3243                         CHECKTYPE(q, TBLTYPE_Tag);
3244                         p->tclass = ((TBLTag *)q->data)->tclass;
3245                         p->tag = ((TBLTag *)q->data)->code;
3246                         if (asn1_verbose) g_message("%*s*collection %s", n*2, empty, p->name);
3247                                 /* read the enumeration [save min-max somewhere ?] */
3248                         nvals = 0;
3249                         p1 = p;
3250                         while((q = g_node_next_sibling(q))) {
3251                                 CHECKTYPE(q, TBLTYPE_NamedNumber);
3252                                 p = g_malloc0(sizeof(PDUinfo));
3253                                 nvals++;
3254                                 p->type = TBL_ENUMERATED;
3255                                 p->name = (gchar *)(((TBLNamedNumber *)q->data)->name);
3256                                 p->tag = (((TBLNamedNumber *)q->data)->value);
3257                                 p->flags = PDU_NAMEDNUM;
3258                                 if (asn1_verbose) g_message("%*s  %3d %s", n*2, empty, p->tag, p->name);
3259                                 g_node_append_data(pdu, p);
3260                         }
3261
3262                         /* list all enum values in the field structure for matching */
3263                         p1->value_hf.hfinfo.strings = v = g_malloc0((nvals+1) * sizeof(value_string));
3264                         q = g_node_first_child(pdu);
3265                         nvals = 0;
3266                         while(q) {
3267                                 p = (PDUinfo *)q->data;
3268                                 v[nvals].value = p->tag;
3269                                 v[nvals].strptr = p->name;
3270                         /* g_message("enumval1:  %d %s %d %s", nvals, p1->name, p->tag, p->name); */
3271                                 nvals++;
3272                                 q = g_node_next_sibling(q);
3273                         }
3274                         /* last entry is already initialized to { 0, NULL } */
3275
3276                         break;
3277
3278                 case TBL_SEQUENCE:
3279                 case TBL_SET:
3280                 case TBL_SEQUENCEOF:
3281                 case TBL_SETOF:
3282                 case TBL_CHOICE:
3283                         CHECKTYPE(q, TBLTYPE_Tag);
3284                         q = g_node_first_child(list);
3285                         tbl_type(n+1, pdu, q, ni);
3286                         break;
3287
3288                 case TBL_TYPEREF: {     /* may have a tag ... */
3289                         TypeRef *tr;
3290                         guint i;
3291                         if(!q){
3292                                 break;
3293                         }
3294                         if ( ((TBLTag *)q->data)->type == TBLTYPE_Tag) {
3295                                 if ((p->flags & PDU_IMPLICIT) == 0) { /* not implicit, use this tag */
3296                                         p->tclass = ((TBLTag *)q->data)->tclass;
3297                                         p->tag = ((TBLTag *)q->data)->code;
3298                                         if (asn1_verbose)
3299                                                 g_message("%*s*insert type tag %c%d", n*2, empty,
3300                                                           tag_class[p->tclass], p->tag);
3301                                 }
3302                                 q = g_node_next_sibling(q);
3303                         } else { /* use default tag for this type */
3304                                 tr = &typeDef_names[((TBLTypeRef *)q->data)->typeDefId];
3305                                 if ((((p->flags & PDU_IMPLICIT) == 0) && (tr->defclass != BER_CLASS_UNI)) ||
3306                                                                 ((p->tclass | p->tag) == 0 )) {
3307                                         /* not implicit, use this tag */
3308                                         p->tclass = tr->defclass;
3309                                         p->tag = tr->deftag;
3310                                         if (asn1_verbose) g_message("%*s*set tag %c%d", n*2, empty,
3311                                                                     tag_class[p->tclass], p->tag);
3312                                 }
3313                         }
3314                         CHECKTYPE(q, TBLTYPE_TypeRef);
3315                         i = ((TBLTypeRef *)q->data)->typeDefId;
3316                         p->mytype = i;
3317                         tr = &typeDef_names[i];
3318                         if (asn1_verbose)
3319                                 g_message("%*s*type#%d %s, %p", n*2, empty, i, tr->name, (void *)tr->pdu);
3320                         p->typename = tr->name;
3321
3322                         if (tr->defclass == CLASSREF) {
3323                                 if (tr->pdu == 0)
3324                                         tr->pdu = pdu;  /* remember this reference */
3325                                 i = tr->deftag;
3326                                 tr =  &typeDef_names[i];
3327                                 if (asn1_verbose)
3328                                         g_message("%*s*refer to type#%d %s, %p", n*2, empty,
3329                                                   i, tr->name, (void *)tr->pdu);
3330                         }
3331                         /* evaluate reference if not done before or when below recursion limit */
3332                         if ((tr->pdu == 0) || (tr->level < type_recursion_level)) {
3333                                 tr->level++;
3334                                 if (tr->pdu == 0) {
3335                                         tr->pdu = pdu; /* save for references we leave */
3336                                 }
3337                                 p->flags |= ((TBLTypeRef *)q->data)->implicit? PDU_IMPLICIT : 0;
3338                                 if (asn1_verbose)
3339                                         g_message("%*s*typeref %s > %s%s at %p", n*2, empty,
3340                                                   p->name,
3341                                                   ((TBLTypeRef *)q->data)->implicit?"implicit ":empty,
3342                                                   tr->name,
3343                                                   (void *)pdu);
3344                                 tbl_typeref(n+1, pdu, tr->type, ni);
3345                                 tr->level--;
3346                         } else {
3347                                 if (asn1_verbose)
3348                                         g_message("%*s*typeref %s > %s already at %p", n*2, empty,
3349                                                   p->name, tr->name, (void *)tr->pdu);
3350                                 p->flags |= PDU_REFERENCE;
3351                                 p->reference = tr->pdu;
3352                         }
3353                         };
3354                         break;
3355                 default:
3356                         g_warning("**** unknown tbl-type %d at line %d", p->type, __LINE__);
3357                         break;
3358                 }
3359
3360                 if (asn1_verbose)
3361                         g_message("%*sinclude type %s %s [%p:%s, tag %c%d]",
3362                                   n*2, empty, p->name, p->typename, (void *)p, TBLTYPE(p->type),
3363                                   tag_class[p->tclass], p->tag);
3364
3365                 if (p->value_id == -1) { /* not registered before, do it now */
3366                         proto_register_field_array(proto_asn1, &(p->value_hf) , 1);
3367
3368                         save_reference(p);
3369
3370                         if (asn1_verbose)
3371                                 g_message("regist-2: %3d %3d [%3d] F%2.2x (%s)%s %s %s -> id=%d",
3372                                           p->mytype, p->typenum, p->basetype, p->flags, p->typename,
3373                                           p->name, p->fullname,
3374                                           tbl_types_wireshark_txt[p->type], p->value_id);
3375                         }
3376                 list = g_node_next_sibling(list);
3377         }
3378 }
3379
3380 static void
3381 PDUtext(char *txt, PDUinfo *info) /* say everything we know about this entry */
3382 {
3383         PDUinfo *rinfo;
3384         const char *tt, *nn, *tn, *fn, *oo, *ii, *an, *tr, *ty;
3385
3386         if (info) {
3387                 tt = TBLTYPE(info->type);
3388                 nn = info->name;
3389                 tn = info->typename;
3390                 fn = info->fullname;
3391                 if (info->flags & PDU_NAMEDNUM)
3392                         txt += g_sprintf(txt, "name: %2d %s", info->tag, nn);
3393                 else {
3394                         if (info->flags & PDU_TYPEDEF)
3395                                 txt += g_sprintf(txt, "def %d: ", info->typenum);
3396                         else
3397                                 txt += g_sprintf(txt, "  ");
3398                         ty = (info->flags & PDU_TYPETREE) ? "typ" : "val";
3399                         txt += g_sprintf(txt, "%s %s (%s)%s [%s] tag %c%d hf=%d tf=%d",ty,tt, tn, nn, fn,
3400                                      tag_class[info->tclass], info->tag, info->value_id, info->type_id);
3401                         txt += g_sprintf(txt, ", mt=%d, bt=%d", info->mytype, info->basetype);
3402                         oo = (info->flags & PDU_OPTIONAL) ?  ", optional"  : empty;
3403                         ii = (info->flags & PDU_IMPLICIT) ?  ", implicit"  : empty;
3404                         nn = (info->flags & PDU_NAMEDNUM) ?  ", namednum"  : empty;
3405                         an = (info->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3406                         txt += g_sprintf(txt, "%s%s%s%s", oo, ii, nn, an);
3407                         if (info->flags & PDU_REFERENCE) {
3408                                 rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3409                                 tt = TBLTYPE(rinfo->type);
3410                                 nn = rinfo->name;
3411                                 tn = rinfo->typename;
3412                                 fn = rinfo->fullname;
3413                                 txt += g_sprintf(txt, ", reference to %s (%s)%s [%s]", tt, tn, nn, fn);
3414                                 if (rinfo->flags & PDU_TYPEDEF)
3415                                         txt += g_sprintf(txt, " T%d", rinfo->typenum);
3416                                 txt += g_sprintf(txt, " tag %c%d", tag_class[rinfo->tclass], rinfo->tag);
3417                                 oo = (rinfo->flags & PDU_OPTIONAL) ?  ", optional"  : empty;
3418                                 ii = (rinfo->flags & PDU_IMPLICIT) ?  ", implicit"  : empty;
3419                                 nn = (rinfo->flags & PDU_NAMEDNUM) ?  ", namednum"  : empty;
3420                                 tn = (rinfo->flags & PDU_REFERENCE) ? ", reference" : empty;
3421                                 tt = (rinfo->flags & PDU_TYPEDEF) ?   ", typedef"   : empty;
3422                                 an = (rinfo->flags & PDU_ANONYMOUS) ? ", anonymous" : empty;
3423                                 tr = (rinfo->flags & PDU_TYPETREE) ?  ", typetree"  : empty;
3424                                 txt += g_sprintf(txt, "%s%s%s%s%s%s%s", oo, ii, nn, tn, tt, an, tr);
3425                         }
3426                 }
3427         } else {
3428                 strncpy(txt, "no info available", 20);
3429         }
3430
3431         return;
3432 }
3433
3434
3435 static void
3436 showPDUtree(GNode *p, int n)
3437 {
3438         PDUinfo *info;
3439         char text[400];
3440
3441         while (p != 0) {
3442                 info = (PDUinfo *)p->data;
3443
3444                 PDUtext(text, info);
3445
3446                 if (asn1_verbose) g_message("%*s%s", n*2, empty, text);
3447
3448                 showPDUtree(g_node_first_child(p), n+1);
3449
3450                 p = g_node_next_sibling(p);
3451         }
3452
3453         return;
3454 }
3455
3456 static gboolean
3457 build_pdu_tree(const char *pduname)
3458 {
3459         SearchDef sd;
3460         guint pdudef, i, tcount;
3461         guint sav_len;
3462         PDUinfo *info;
3463         char text[400];
3464         guint j, k;
3465         gint defid;
3466         PDUinfo *p, *q;
3467         TypeRef *tr;
3468
3469         if (asn1_verbose) g_message("build msg tree from '%s' for '%s'", current_asn1, pduname);
3470
3471         if (!data_nodes) {
3472                 if (asn1_verbose) g_message("no data nodes");
3473                 return FALSE;
3474         }
3475         sd.key = pduname;
3476         sd.here = 0;
3477         g_node_traverse(data_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, is_typedef, (gpointer)&sd);
3478         if (sd.here) {
3479                 pdudef = ((TBLTypeDef *)(sd.here->data))->typeDefId;
3480                 if (asn1_verbose) g_message("%s found, %p, typedef %d", sd.key, (void *)sd.here, pdudef);
3481         } else {
3482                 if (asn1_verbose) g_message("%s not found, ignored", sd.key);
3483                 return FALSE;
3484         }
3485
3486         /* If there's an existing PDU tree, free it */
3487         if (PDUtree) {
3488                 g_node_traverse(PDUtree, G_POST_ORDER, G_TRAVERSE_ALL, -1,
3489                     free_node_data, NULL);
3490                 g_node_destroy(PDUtree);
3491         }
3492
3493         /* initialize the PDU tree, hand craft the root entry */
3494
3495         info = g_malloc0(sizeof(PDUinfo));
3496         info->name = pduname;
3497         info->typename = pduname;
3498         info->type = TBL_SEQUENCEOF;
3499         info->fullname = g_strdup_printf("%s.%s", pabbrev, pduname);
3500         info->flags = PDUinfo_initflags = 0;
3501         info->value_id = -1;
3502         info->type_id = -1;
3503         info->basetype = -1;
3504         info->mytype = pdudef;
3505
3506         info->value_hf.p_id = &(info->value_id);
3507         info->value_hf.hfinfo.name = info->fullname;
3508         info->value_hf.hfinfo.abbrev = info->fullname;
3509         info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3510         info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3511         info->value_hf.hfinfo.blurb = info->fullname;
3512
3513         anonCount = 0; /* anonymous types counter */
3514
3515         PDUtree = g_node_new(info);
3516         pabbrev_pdu_len = g_sprintf(fieldname, "%s.%s.", pabbrev, pduname);
3517         sav_len = pabbrev_pdu_len;
3518
3519         /* Now build the tree for this top level PDU */
3520         if (asn1_verbose)
3521                 g_message("******** Define main type %d, %s", pdudef, pduname);
3522         tbl_typeref(0, PDUtree, sd.here, pabbrev_pdu_len-1);    /* strip initial . for new names */
3523
3524         if (asn1_verbose)
3525                 g_message("%d anonymous types", anonCount);
3526
3527         /* Now make all types used available for matching */
3528         if (asn1_verbose)
3529                 g_message("Define the types that are actually referenced through the top level PDU");
3530         for (i=0, tcount=0; i<numTypedefs; i++) {
3531                 tr = &(typeDef_names[i]);
3532
3533                 if (tr->pdu) {  /* ignore if not used in main pdu */
3534                         tcount++;
3535                         if (i == pdudef)
3536                                 g_warning("pdu %d %s defined twice, TopLevel & type", pdudef, pduname);
3537                         if (asn1_verbose)
3538                                 g_message("******** Define type %d, %s", i, tr->name);
3539
3540                         /* .... do definition ..... */
3541                         info = g_malloc0(sizeof(PDUinfo));
3542                         info->name = tr->name;
3543                         info->typename = tr->name;
3544                         info->tclass = tr->defclass;
3545                         info->tag = tr->deftag;
3546                         info->type = TBL_TYPEREF;
3547                         info->fullname = g_strdup_printf("%s.--.%s", pabbrev, tr->name);
3548                         info->flags = PDUinfo_initflags = PDU_TYPETREE;
3549                         info->value_id = -1;
3550                         info->type_id = -1;
3551                         info->basetype = -1;
3552                         info->mytype = i;
3553
3554                         info->value_hf.p_id = &(info->value_id);
3555                         info->value_hf.hfinfo.name = info->fullname;
3556                         info->value_hf.hfinfo.abbrev = info->fullname;
3557                         info->value_hf.hfinfo.type = tbl_types_wireshark[info->type];
3558                         info->value_hf.hfinfo.display = tbl_display_wireshark[info->type];
3559                         info->value_hf.hfinfo.blurb = info->fullname;
3560
3561                         tr->typetree = g_node_new(info);
3562                         pabbrev_pdu_len = g_sprintf(fieldname, "%s.--.%s.", pabbrev, tr->name);
3563                         tbl_typeref(0, tr->typetree, tr->type, pabbrev_pdu_len-1);
3564                 }
3565         }
3566         if (asn1_verbose)
3567                 g_message("%d types used", tcount);
3568
3569         pabbrev_pdu_len = sav_len;
3570
3571         /* and show the result */
3572         if (asn1_verbose)
3573                 g_message("Type index:");
3574         for (i=0; i<numTypedefs; i++) {
3575                 tr = &(typeDef_names[i]);
3576
3577                 if (tr->pdu == 0) /* skip if not used */
3578                         continue;
3579
3580                 if (asn1_verbose)
3581                         g_message("  %3d %s, %c%d, refs: %d",
3582                                   i, tr->name, tag_class[tr->defclass], tr->deftag,
3583                                   g_ptr_array_len(tr->refs));
3584
3585                 /* get defining node for this type */
3586                 defid = -1;
3587                 if (tr->typetree) {
3588                         p = (PDUinfo *)(tr->typetree->data);
3589                         defid = p->value_id;
3590                         if (asn1_verbose)
3591                                 g_message("      -- defining id=%d", defid);
3592                 }
3593                 for(j=0; j < g_ptr_array_len(tr->refs); j++) {  /* show refs, and set type_id */
3594                         p = (PDUinfo *)g_ptr_array_index(tr->refs, j);
3595                         if (p->mytype == (gint)i)
3596                                 p->type_id = defid;     /* normal reference */
3597                         else {
3598                                 if ((p->flags & PDU_TYPETREE) == 0) {
3599                                         /* we have a primitive value, find its real type */
3600                                         for(k=0; k < g_ptr_array_len(tr->refs); k++) {
3601                                                         /* look at all refs */
3602                                                 q = (PDUinfo *)g_ptr_array_index(tr->refs, k);
3603                                                 if ((q->flags & PDU_TYPETREE) == 0)
3604                                                         continue; /* only type trees are interresting */
3605                                                 if (q->type != p->type)
3606                                                         continue; /* must be same types */
3607                                                 if (strcmp(q->name, p->name) == 0) {
3608                                                         /* OK, take the first we find, not entirely
3609                                                          * correct, it may be from a different
3610                                                          * base-base type...... XXX */
3611                                                         p->type_id = q->value_id;
3612                                                         break;
3613                                                 }
3614                                         }
3615                                 }
3616                         }
3617
3618                         if (asn1_verbose) {
3619                                 PDUtext(text, p);
3620                                 g_message("      %s", text);
3621                         }
3622                 }
3623         }
3624
3625         if (asn1_verbose)
3626                 g_message("The resulting PDU tree:");
3627         showPDUtree(PDUtree, 0);
3628
3629         return TRUE;
3630 }
3631
3632
3633 #ifdef DISSECTOR_WITH_GUI
3634 /* This cannot work in tshark.... don't include for now */
3635 #define SHOWPDU
3636 #endif /* DISSECTOR_WITH_GUI */
3637 #ifdef SHOWPDU
3638
3639 static GtkWidget *window = NULL;
3640
3641 /* the columns in the tree view */
3642 enum
3643 {
3644    TITLE_COLUMN,                /* text in this row */
3645    DEF_COLUMN,                  /* definition in this row, if any */
3646    REF_COLUMN,                  /* referennce from this column, if any */
3647    VALUE_COLUMN,                /* indicate this is a value */
3648    NAME_COLUMN,                 /* name of this row */
3649    N_COLUMNS
3650 };
3651
3652 static FILE *namelist = 0;
3653
3654 static void
3655 build_tree_view(GtkTreeStore *store, GNode *p, GtkTreeIter *iter)
3656 {
3657         GtkTreeIter iter2;
3658         PDUinfo *info, *rinfo;
3659         gint def, ref;
3660         guchar *pb;
3661
3662         char text[400];
3663
3664         while (p != 0) {
3665                 info = (PDUinfo *)p->data;
3666
3667                 gtk_tree_store_append (store, &iter2, iter);  /* Acquire iterator */
3668
3669                 PDUtext(text, info);
3670
3671                 def = ref = -1;
3672                 if (info->flags & PDU_TYPEDEF)
3673                         def = info->typenum;
3674
3675                 if (info->flags & PDU_REFERENCE) {
3676                         rinfo = (PDUinfo *)((GNode *)(info->reference))->data;
3677                         ref = rinfo->typenum;
3678                 }
3679                 pb = GTK_STOCK_CANCEL;
3680                 if (G_NODE_IS_LEAF(p)) {
3681                         if (info->flags & PDU_NAMEDNUM)
3682                                 pb = GTK_STOCK_BOLD;
3683                         else {
3684                                 pb = GTK_STOCK_YES;
3685                                 if (namelist)
3686                                         fprintf(namelist, "%16s %s\n",
3687                                                 &(TBLTYPE(info->type)[4]), info->fullname);
3688                         }
3689                 } else {
3690                         switch (info->type) {
3691                         case TBL_ENUMERATED:
3692                         case TBL_BITSTRING:
3693                                 pb = GTK_STOCK_ADD;
3694                                 if (namelist)
3695                                         fprintf(namelist, "%16s %s\n",
3696                                                 &(TBLTYPE(info->type)[4]), info->fullname);
3697                                 break;
3698                         default:
3699                                 break;
3700                         }
3701                 }
3702
3703                 gtk_tree_store_set (store, &iter2,
3704                                     TITLE_COLUMN, text,
3705                                     DEF_COLUMN, def,
3706                                     REF_COLUMN, ref,
3707                                     VALUE_COLUMN, pb,
3708                                     NAME_COLUMN, info->fullname,
3709                                     -1);
3710
3711                 build_tree_view(store, g_node_first_child(p), &iter2);
3712
3713                 p = g_node_next_sibling(p);
3714         }
3715
3716         return;
3717 }
3718
3719
3720 struct DefFind {
3721         gint def;
3722         GtkTreePath *path;
3723 };
3724
3725 #define PATHSTACKMAX 10
3726 static GtkTreePath *pathstack[PATHSTACKMAX];
3727 static gint pathstackp = 0;
3728
3729 static void add_path(GtkTreePath *p)
3730 {
3731         if (pathstackp >= PATHSTACKMAX) { /* shift old contents */
3732                 gtk_tree_path_free(pathstack[0]); /* we forget about this one */
3733                 memmove(&pathstack[0], &pathstack[1], (PATHSTACKMAX-1)*sizeof(GtkTreePath *));
3734                 pathstackp--;
3735         }
3736         pathstack[pathstackp++] = p;
3737 }
3738
3739 static GtkTreePath *pop_path(void)
3740 {
3741         if (pathstackp > 0)
3742                 return pathstack[--pathstackp];
3743         return 0;
3744 }
3745
3746 static gboolean
3747 find_definition(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
3748 {
3749         gint def;
3750
3751         struct DefFind *df = (struct DefFind *)data;
3752
3753         gtk_tree_model_get (model, iter, DEF_COLUMN, &def, -1);
3754
3755         if (def == df->def) {
3756                 df->path = gtk_tree_path_copy (path);
3757                 return TRUE;
3758         }
3759         return FALSE;
3760
3761 }
3762
3763 static void
3764 my_signal_handler(GtkTreeView *treeview, GtkTreePath *spath, GtkTreeViewColumn *arg2, gpointer model)
3765 {
3766         GtkTreeIter iter;
3767         GtkTreePath *path, *path2;
3768         gchar *text, *oldpath, *newpath;
3769         gint def, ref;
3770         struct DefFind df;
3771
3772         (void) arg2;
3773
3774         path = gtk_tree_path_copy (spath);
3775
3776         gtk_tree_model_get_iter (model, &iter, path);
3777         gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref, -1);
3778
3779         oldpath = gtk_tree_path_to_string(path);
3780         path2 = gtk_tree_path_copy (path);
3781
3782         add_path(gtk_tree_path_copy(path));
3783
3784         if (ref != -1) {        /* this is a reference, find matching definition */
3785                 df.def = ref;
3786                 df.path = 0;
3787                 gtk_tree_model_foreach (model, find_definition, &df);
3788                 if (df.path) {
3789                         gtk_tree_path_free(path);
3790                         path = df.path;
3791                 }
3792         } else {                /* just move to the next entry, if it exists */
3793                 gtk_tree_path_next(path2);
3794
3795                 if (gtk_tree_model_get_iter (model, &iter, path2)) {
3796                         gtk_tree_path_free(path);
3797                         path = path2;   /* OK */
3798                 } else {
3799                         if (gtk_tree_path_get_depth (path) > 1)
3800                                 gtk_tree_path_up (path);
3801                 }
3802         }
3803
3804         if (path != path2)
3805                 gtk_tree_path_free (path2);
3806
3807         gtk_tree_view_expand_to_path (treeview, path);
3808         gtk_tree_view_expand_row (treeview, path, FALSE);
3809
3810         gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3811
3812         gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3813
3814         newpath = gtk_tree_path_to_string(path);
3815
3816         if (asn1_debug)
3817                 g_message("my_signal_handler: treeview=%p, moving from %s to %s",
3818                           treeview, oldpath, newpath);
3819
3820         g_free(text);
3821         g_free(oldpath);
3822         g_free(newpath);
3823         /* if (df.path) */
3824         /*      gtk_tree_path_free(df.path); */
3825 }
3826
3827
3828 static void
3829 menuitem_cb (gpointer             callback_data,
3830              guint                callback_action,
3831              GtkWidget           *widget)
3832 {
3833   GtkWidget *dialog;
3834   GtkTreeModel *model;
3835   GtkTreeView *treeview = gtk_item_factory_popup_data_from_widget(widget);
3836   GtkTreeSelection *selection;
3837   GtkTreeIter iter;
3838   gchar *text, *name;
3839   gint def, ref;
3840   GtkTreePath *path;
3841   gchar *oldpath, *newpath;
3842   GtkTreeViewColumn *focus_column;
3843
3844   selection = gtk_tree_view_get_selection(treeview);
3845
3846   model = gtk_tree_view_get_model(treeview);
3847   gtk_tree_view_get_cursor (treeview, &path, &focus_column);
3848
3849   if (gtk_tree_model_get_iter (model, &iter, path)) {
3850
3851           gtk_tree_model_get (model, &iter, TITLE_COLUMN, &text, DEF_COLUMN, &def, REF_COLUMN, &ref,
3852                               NAME_COLUMN, &name, -1);
3853           oldpath = gtk_tree_path_to_string(path);
3854           newpath = empty;
3855
3856           switch (callback_action) {
3857           case 0:               /* Select */
3858                   gtk_tree_selection_select_path (selection, path);
3859                   break;
3860           case 1:               /* back */
3861                   path = pop_path();
3862                   if (path) {
3863                           gtk_tree_view_expand_to_path (treeview, path);
3864                           gtk_tree_view_expand_row (treeview, path, FALSE);
3865
3866                           gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.2, 0.0);
3867
3868                           gtk_tree_view_set_cursor (treeview, path, NULL, FALSE);
3869
3870                           newpath = gtk_tree_path_to_string(path);
3871
3872                           gtk_tree_path_free(path);
3873                   } else
3874                           newpath = g_strdup("** no path **");
3875                   if (asn1_debug)
3876                           g_message("menueitem_cb: treeview=%p, moving from %s to %s",
3877                                     treeview, oldpath, newpath);
3878                   break;
3879
3880           case 2:               /* Find */
3881                   /* get all non anonymous names to the root */
3882
3883           default:
3884                   dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data),
3885                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
3886                                                    GTK_MESSAGE_INFO,
3887                                                    GTK_BUTTONS_CLOSE,
3888                                 "You selected the menu item: \"%s\" [%d]\n%s\npath=%s, %s\nname='%s'",
3889                                                    gtk_item_factory_path_from_widget (widget),
3890                                                    callback_action, text, oldpath, newpath, name);
3891
3892                   /* Close dialog on user response */
3893                   g_signal_connect (dialog,
3894                                     "response",
3895                                     G_CALLBACK (gtk_widget_destroy),
3896                                     NULL);
3897
3898                   gtk_widget_show (dialog);
3899                   break;
3900           }
3901           g_free(text);
3902           g_free(name);
3903           if (newpath != empty)
3904                   g_free(newpath);
3905           g_free(oldpath);
3906   } else
3907           g_message("menuitem_cb: no iterator...");
3908 }
3909
3910 static GtkItemFactoryEntry menu_items[] = {
3911   { "/Select",  NULL,         menuitem_cb, 0, NULL, 0 },
3912   { "/Back",    "<control>B", menuitem_cb, 1, NULL, 0 },
3913   { "/Find",    "<control>F", menuitem_cb, 2, NULL, 0 },
3914   { "/Save",    "<control>S", menuitem_cb, 3, NULL, 0 },
3915 };
3916
3917 static gint button_press_callback( GtkWidget      *widget,
3918                                    GdkEventButton *event,
3919                                    gpointer        data )
3920 {
3921         GtkTreeView *treeview = GTK_TREE_VIEW(widget);
3922
3923         /* g_message("button_press_callback, widget=%p, button=%d, type=%d, x=%g, y=%g, x_root=%g,"
3924          *   " y_root=%g", widget, event->button, event->type, event->x, event->y, event->x_root,
3925          *                 event->y_root );
3926          */
3927         if (event->button == 3) {
3928                 gtk_item_factory_popup_with_data ((GtkItemFactory *)data, treeview, NULL,
3929                                              event->x_root,
3930                                              event->y_root,
3931                                              event->button,
3932                                              event->time);
3933                 return TRUE;
3934         }
3935         return FALSE;           /* continue handling this event */
3936 }
3937
3938
3939 static void
3940 create_message_window(void)
3941 {
3942         GtkCellRenderer *renderer;
3943         GtkTreeStore *model;
3944         GtkWidget *vbox;
3945         GtkWidget *sw;
3946         GtkWidget *treeview;
3947         gchar *text;
3948         GtkItemFactory *item_factory;
3949         GtkAccelGroup *accel_group;
3950         gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
3951
3952     if ( ! window) {
3953
3954         /* create window, etc */
3955         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3956         gtk_window_set_title (GTK_WINDOW (window), current_pduname);
3957         g_signal_connect (window, "destroy",
3958                           G_CALLBACK (gtk_widget_destroyed), &window);
3959
3960         vbox = gtk_vbox_new (FALSE, 8);
3961         gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3962         gtk_container_add (GTK_CONTAINER (window), vbox);
3963
3964         text = g_strdup_printf("ASN.1 message structure from %s, %s", current_asn1, current_pduname);
3965
3966         gtk_box_pack_start (GTK_BOX (vbox),
3967                             gtk_label_new (text),
3968                             FALSE, FALSE, 0);
3969         g_free(text);
3970
3971         sw = gtk_scrolled_window_new (NULL, NULL);
3972         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
3973                                              GTK_SHADOW_ETCHED_IN);
3974         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
3975                                         GTK_POLICY_AUTOMATIC,
3976                                         GTK_POLICY_AUTOMATIC);
3977         gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3978
3979         model = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3980                                    G_TYPE_STRING, G_TYPE_STRING);
3981
3982         namelist = ws_fopen("namelist.txt", "w");
3983         build_tree_view(model, PDUtree, NULL);
3984         fclose(namelist);
3985         namelist = 0;
3986
3987         /* create tree view */
3988         treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
3989         g_object_unref (model);
3990         gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
3991         gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
3992                                      GTK_SELECTION_MULTIPLE);
3993
3994         renderer = gtk_cell_renderer_text_new ();
3995
3996 #if 0 /* testing pango attributes */
3997 {
3998         PangoAttribute* bg;
3999         PangoAttrList* attr;
4000
4001         attr = pango_attr_list_new();
4002         bg = pango_attr_background_new(50000,55000,50000);
4003         bg->start_index = 0;
4004         bg->end_index = 10000;
4005         pango_attr_list_insert(attr, bg);
4006
4007         g_object_set(renderer, "attributes", attr, NULL);
4008 }
4009 #endif /* testing pango attributes */
4010
4011         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4012                                                      TITLE_COLUMN, "asn1 entities", renderer,
4013                                                      "text", TITLE_COLUMN, NULL );
4014
4015         /* renderer = gtk_cell_renderer_text_new ();
4016          * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4017          *                                           DEF_COLUMN, "type definition", renderer,
4018          *                                           "text", DEF_COLUMN, NULL );
4019          *
4020          * renderer = gtk_cell_renderer_text_new ();
4021          * gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4022          *                                           REF_COLUMN, "reference", renderer,
4023          *                                           "text", REF_COLUMN, NULL );
4024          */
4025         renderer = gtk_cell_renderer_pixbuf_new ();
4026         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4027                                                      VALUE_COLUMN, "value", renderer,
4028                                                      "stock_id", VALUE_COLUMN, NULL );
4029
4030         renderer = gtk_cell_renderer_text_new ();
4031         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW(treeview),
4032                                                      NAME_COLUMN, "fieldname", renderer,
4033                                                      "text", NAME_COLUMN, NULL );
4034
4035         gtk_container_add (GTK_CONTAINER (sw), treeview);
4036
4037         /* gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); */
4038
4039         /* create menu */
4040
4041         accel_group = gtk_accel_group_new ();
4042
4043         /* This function initializes the item factory.
4044          * Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
4045          *          or GTK_TYPE_OPTION_MENU.
4046          * Param 2: The path of the menu.
4047          * Param 3: A pointer to a gtk_accel_group.  The item factory sets up
4048          *          the accelerator table while generating menus.
4049          */
4050
4051         item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<menu>", accel_group);
4052
4053         /* This function generates the menu items. Pass the item factory,
4054            the number of items in the array, the array itself, and any
4055            callback data for the the menu items. */
4056         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
4057
4058         /* Attach the new accelerator group to the window. */
4059         gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
4060
4061
4062         /* expand all rows after the treeview widget has been realized */
4063         g_signal_connect (treeview, "realize",
4064                           G_CALLBACK (gtk_tree_view_expand_all), NULL);
4065         g_signal_connect (treeview, "row-activated",
4066                           G_CALLBACK (my_signal_handler), (gpointer)model);
4067
4068         g_signal_connect (treeview, "button_press_event",
4069                           G_CALLBACK (button_press_callback), item_factory);
4070
4071         /* g_signal_connect_swapped (treeview, "event",
4072          *                               G_CALLBACK (button_press_handler),
4073          *                              menu);
4074          */
4075         gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
4076     }
4077
4078     if (!GTK_WIDGET_VISIBLE (window))
4079             gtk_widget_show_all (window);
4080     else
4081             {
4082                     gtk_widget_destroy (window);
4083                     window = NULL;
4084             }
4085 }
4086 #endif /* SHOWPDU */
4087
4088 /************************************************************************************************
4089  *    routines to find names to go with the decoded data stream                                 *
4090  ************************************************************************************************/
4091 #define PDUSTATE_STACK_SIZE 1024
4092 typedef struct _statestack statestack;
4093 static struct _statestack {
4094         GNode *node;
4095         guint type;
4096         guint offset;
4097         const char *name;
4098 } PDUstate[PDUSTATE_STACK_SIZE];
4099 static gint PDUstatec = 0;
4100
4101 /* XXX - Shouldn't we do bounds checking here? */
4102 #define PUSHNODE(x)   { PDUstate[PDUstatec++] = (x); }
4103 #define POPSTATE      PDUstate[--PDUstatec]
4104
4105 static const char *
4106 getname(GNode *node) {
4107         if (node == NULL || node->data == NULL)
4108                 THROW(ReportedBoundsError);
4109
4110         return ((PDUinfo *)node->data)->name;
4111 }
4112
4113 static guint
4114 gettype(GNode *node) {
4115         if (node == NULL || node->data == NULL)
4116                 THROW(ReportedBoundsError);
4117
4118         return ((PDUinfo *)node->data)->type & TBL_TYPEmask;
4119 }
4120
4121 static gpointer
4122 getinfo(GNode *node) {
4123         if (node == NULL)
4124                 THROW(ReportedBoundsError);
4125
4126         return node->data;
4127 }
4128
4129 #define NEXT          {pos.node = g_node_next_sibling(pos.node);pos.type=0;}
4130 #define CHILD         {pos.node = g_node_first_child(pos.node);pos.type=0;}
4131 #define MATCH         (info && (class == info->tclass) && (tag == info->tag))
4132 #define ISOPTIONAL    (info && (info->flags & PDU_OPTIONAL))
4133 #define ISIMPLICIT    (info && (info->flags & PDU_IMPLICIT))
4134 #define ISREFERENCE   (info && (info->flags & PDU_REFERENCE))
4135 #define ISCHOICE      (info && (info->flags & PDU_CHOICE))
4136 #define ISANONYMOUS   (info && (info->flags & PDU_ANONYMOUS))
4137
4138 #undef CHECKP
4139 #define CHECKP(p) {if ((p==0)||(PDUstatec<0)){g_warning("pointer==0, line %d **********", __LINE__);\
4140                                 pos.node=NULL;PUSHNODE(pos);return ret;}}
4141
4142
4143 static void
4144 showstack(statestack *pos, char *txt, int n)
4145 {
4146         char buf[1024];
4147         const char /* *name, *type,*/ *stype;
4148         const char *rep, *chs, *done, *ref, *pop, *chr, *rch, *sch, *con;
4149         int i, j;
4150         /* GNode *g;*/
4151         statestack *p;
4152         guint typef;
4153
4154         if ( ! asn1_verbose)
4155                 return;
4156
4157         if (n>PDUstatec)
4158                 n = PDUstatec;
4159         if (n<0) {
4160                 g_message("==underflow");
4161                 return;
4162         }
4163         rep = chs = done = ref = pop = chr = rch = sch = con = empty;
4164
4165 #if 0  /* XXX: not used ??? */
4166         g = pos->node;
4167         if (g) {
4168                 name = ((PDUinfo *)g->data)->name;
4169                 type = TBLTYPE(((PDUinfo *)g->data)->type);
4170         } else {
4171                 name = "node<null>";
4172                 type = "?";
4173         }
4174 #endif
4175         typef = pos->type;
4176         stype = TBLTYPE(typef);
4177         if (typef & TBL_REPEAT)         rep  = "[repeat]";
4178         if (typef & TBL_CHOICE_made)    chs  = "[choice]";
4179         if (typef & TBL_SEQUENCE_done)  done = "[done]";
4180         if (typef & TBL_REFERENCE)      ref  = "[ref]";
4181         if (typef & TBL_REFERENCE_pop)  pop  = "[ref-pop]";
4182         if (typef & TBL_CHOICE_repeat)  chr  = "[chs-rep]";
4183         if (typef & TBL_REPEAT_choice)  rch  = "[rep-chs]";
4184         if (typef & TBL_SEQUENCE_choice)sch  = "[seq-chs]";
4185         if (typef & TBL_CONSTRUCTED)    con  = "[constr]";
4186
4187         i = g_sprintf(buf, "%s sp=%d,pos=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", txt, PDUstatec,
4188                     (void *)pos->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4189                     pos->name, pos->offset);
4190
4191         for(j=1, n--; n>0; j++, n--) {
4192                 p = &PDUstate[PDUstatec-j];
4193                 typef = p->type;
4194                 stype = TBLTYPE(typef);
4195                 rep  = (typef & TBL_REPEAT)         ? "[repeat]"  : empty;
4196                 chs  = (typef & TBL_CHOICE_made)    ? "[choice]"  : empty;
4197                 done = (typef & TBL_SEQUENCE_done)  ? "[done]"    : empty;
4198                 ref  = (typef & TBL_REFERENCE)      ? "[ref]"     : empty;
4199                 pop  = (typef & TBL_REFERENCE_pop)  ? "[ref-pop]" : empty;
4200                 chr  = (typef & TBL_CHOICE_repeat)  ? "[chs-rep]" : empty;
4201                 rch  = (typef & TBL_REPEAT_choice)  ? "[rep-chs]" : empty;
4202                 sch  = (typef & TBL_SEQUENCE_choice)? "[seq-chs]" : empty;
4203                 con  = (typef & TBL_CONSTRUCTED)    ? "[constr]"  : empty;
4204
4205                 i += g_sprintf(&buf[i], "| sp=%d,st=%p,%s%s%s%s%s%s%s%s%s%s:%s,%d", PDUstatec-j,
4206                         (void *)p->node, stype, rep, chs, done, ref, pop, chr, rch, sch, con,
4207                         p->name, p->offset);
4208         }
4209         g_message("%s", buf);
4210 }
4211
4212 #if 0
4213 static void
4214 showrefNode(GNode *node, int n)
4215 {
4216         const char *name = empty, *type = empty, *tname = empty;
4217         int cls = 0, tag = 0;
4218         PDUinfo *info;
4219         GNode *ref = 0;
4220
4221         if (n > 10) {
4222                 g_message("%*sstop, nesting too deep", 2*n, empty);
4223                 return;
4224         }
4225         if (node->data) {
4226                 info = (PDUinfo *)(node->data);
4227                 type = TBLTYPE(info->type);
4228                 name = info->name;
4229                 tname = info->typename;
4230                 ref  = info->reference;
4231                 cls = info->tclass;
4232                 tag = info->tag;
4233         }
4234         g_message("%*sreference '(%s)%s:%s' at %p: data=%p, reference=%p, %c%d",
4235                  2*n, empty, tname, type, name, node, node->data,
4236                   ref, tag_class[cls], tag);
4237
4238         if (ref)
4239                 showrefNode(ref, n+1);
4240 }
4241 #endif
4242
4243 #if 0
4244 static void
4245 showNode(GNode *node, int n, int m)
4246 {
4247         const char *name = empty, *type = empty;
4248         GNode *ref = 0;
4249
4250         if (n > m)
4251                 return;
4252
4253         if (node->data) {
4254                 type = TBLTYPE(((PDUinfo *)(node->data))->type);
4255                 name = ((PDUinfo *)(node->data))->name;
4256                 ref  = ((PDUinfo *)(node->data))->reference;
4257         }
4258         g_message("%*snode '%s:%s' at %p: data=%p, next=%p, prev=%p, parent=%p, child=%p",
4259                  2*n, empty, type, name, node, node->data, node->next, node->prev,
4260                                                         node->parent, node->children);
4261
4262         if (m > 10) {
4263                 g_message("%*sstop, nesting too deep", 2*n, empty);
4264                 return;
4265         }
4266
4267         if (ref) showrefNode(ref, n+2);
4268
4269         if (node->children) showNode(node->children, n+1, m);
4270         if (node->next) showNode(node->next, n, m);
4271 }
4272 #endif
4273
4274 static void
4275 PDUreset(int count, int count2)
4276 {
4277         statestack pos;
4278
4279         if (asn1_verbose) g_message("PDUreset %d-%d", count, count2);
4280
4281         PDUstatec = 0; /* stackpointer */
4282         PDUerrcount = 0; /* error counter per asn.1 message */
4283
4284         pos.node = NULL; /* sentinel */
4285         pos.name = "sentinel";
4286         pos.type = TBL_SEQUENCEOF;
4287         pos.offset = 0;
4288         PUSHNODE(pos);
4289
4290         if (PDUtree) {
4291                 pos.node = PDUtree; /* root of the tree */
4292                 pos.name = getname(pos.node);
4293                 pos.type = gettype(pos.node) | TBL_REPEAT;
4294                 pos.offset = 0;
4295                 PUSHNODE(pos);
4296         }
4297 }
4298
4299 static GNode *                  /* find GNode for a choice element, 0 if none */
4300 makechoice(GNode *p, guint class, guint tag)
4301 {
4302         GNode *q;
4303         PDUinfo *info;
4304
4305         p = g_node_first_child(p); /* the list of choices */
4306         info = 0;               /* avoid gcc warning */
4307
4308         while (p) {
4309                 info = ((PDUinfo *)p->data);
4310
4311                 if (info->type == TBL_CHOICE) {
4312                         if (asn1_verbose)
4313                                 g_message("    using sub choice (%s)%s", info->typename, info->name);
4314
4315                         q = makechoice(p, class, tag);
4316                         if (q) { /* found it */
4317                                 p = q;
4318                                 info = ((PDUinfo *)p->data);
4319                                 break;
4320                         } /* continue with this level */
4321
4322                 } else {
4323                         if (asn1_verbose)
4324                                 g_message("    have %c%d, found %c%d, %s", tag_class[class], tag,
4325                                             tag_class[info->tclass], info->tag, info->name);
4326
4327                         if ((class == info->tclass) && (tag == info->tag))
4328                                 break;  /* found it */
4329                 }
4330
4331                 p = g_node_next_sibling(p);
4332         }
4333         if (asn1_verbose) {
4334                 if (p) g_message("    OK, '%s:(%s)%s' chosen", tbl_types[info->type], info->typename,
4335                                  info->name);
4336                 else   g_message("    ...no matching choice...");
4337         }
4338         return p;
4339 }
4340
4341                 /* offset is for debugging only, a reference to output on screen */
4342 static PDUprops *
4343 getPDUprops(PDUprops *out, guint offset, guint class, guint tag, guint cons)
4344 {
4345         statestack pos, pos2, save_pos;
4346         PDUinfo *info;
4347         const char *ret, *tmp;
4348         int typeflags = 0, donext = 0, pushed = 0, cons_handled = 0;
4349         static char namestr[64]; /* enough ? */
4350         static char posstr[40];
4351         static char noname[] = "*noname*";
4352         static PDUprops constructed_save; /* for unexpectedly constructed entities */
4353
4354         if (PDUstatec > 0)      /* don't read from below the stack */
4355                 pos = POPSTATE;
4356         /* pos refers to the last asn1 node handled */
4357
4358         /* a very simple, too simple??, way to handle constructed entities */
4359         if ((PDUstatec > 0) && (pos.type & TBL_CONSTRUCTED)) {
4360                         /* unexpectedly constructed, return same info as last time */
4361                 g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4362                 showstack(&pos, posstr, 3);
4363                 pos.offset = offset;
4364                 pos.type &= ~TBL_CONSTRUCTED; /* remove the flag */
4365                 PUSHNODE(pos);  /* push extra, to match with a EOI operation */
4366                 PUSHNODE(pos);  /* restore the stack */
4367                 *out = constructed_save;
4368                 if (asn1_verbose)
4369                         g_message("  return for constructed %s (%s)%s",
4370                                   TBLTYPE(out->type), out->typename, out->name);
4371                 return out;
4372         }
4373
4374         save_pos = pos; /* may need it again */
4375
4376         out->type = 0;
4377         out->name = 0;
4378         out->typename = "*error*";
4379         out->fullname = 0;
4380         out->flags = 0;
4381         out->data = 0;
4382         out->value_id = -1;
4383         out->type_id = -1;
4384
4385         if (PDUstatec <= 0) {
4386                 if (PDUstatec > -10) {
4387                         if (asn1_verbose)
4388                                 g_message(">>off=%d stack underflow, return", offset);
4389                 }
4390                 if (PDUstatec == -10) {
4391                         if (asn1_verbose)
4392                                 g_message(">>off=%d stack underflow, return, no more messages", offset);
4393                 }
4394                 out->name = "*underflow*";
4395                 out->flags |= OUT_FLAG_noname;
4396                 PDUerrcount++;
4397                 return out;
4398         }
4399         g_sprintf(posstr, "==off=%d %c%d%c", offset, tag_class[class], tag, cons?'c':'p');
4400
4401         showstack(&pos, posstr, 3);
4402
4403         ret = noname;
4404
4405         if (class == ASN1_EOI) { /* end of this input sequence */
4406
4407                 if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4408                         if (asn1_verbose) g_message("    EOI: reference pop");
4409                         pos = POPSTATE;
4410                 } else
4411                 switch(pos.type & TBL_TYPEmask) {
4412                 case TBL_TYPEREF:
4413                         if (asn1_verbose) g_message("    EOI: pop typeref");
4414                         pos = POPSTATE; /* remove typeref */
4415                         break;
4416                 case TBL_CHOICE_done:
4417                         if (asn1_verbose) g_message("    EOI: mark choice");
4418                         pos = POPSTATE;
4419                         pos.type |= TBL_CHOICE_made; /* poropagate this up the stack */
4420                         PUSHNODE(pos);
4421                         break;
4422                 default:
4423                         break;
4424                 }
4425
4426
4427                 pos = POPSTATE; /* this is pushed back on the stack later */
4428                 if (pos.node == NULL) {
4429                         if (asn1_verbose) g_message("  EOI, pos.node == NULL");
4430                         out->name = "*no-name-EOI*";
4431                         out->flags |= OUT_FLAG_noname;
4432                         PDUerrcount++;
4433                         return out;
4434                 }
4435
4436                 info = getinfo(pos.node);
4437                 ret = info->name;
4438                 tmp = TBLTYPE(info->type);
4439                 if (offset != pos.offset) {
4440                         if (asn1_verbose)
4441                                 g_message("  *EOI %s:%s mismatch, EOIoffset=%d, stack=%d",
4442                                           tmp, ret, offset, pos.offset);
4443                         while ((offset < pos.offset) && (PDUstatec > 0)) {
4444                                 pos = POPSTATE;
4445                                 if (asn1_verbose)
4446                                         g_message("  EOI extra pop, EOIoffset=%d, stack=%d",
4447                                                   offset, pos.offset);
4448                         }
4449                         if (offset != pos.offset)
4450                                 PDUerrcount++; /* only count if still unequal */
4451                 } else {
4452                         if (asn1_verbose) g_message("  EOI %s:%s OK, offset=%d", tmp, ret, offset);
4453                 }
4454         } else {
4455                 /* EOC is only present for indefinite length sequences, etc. end of sequence is always
4456                  * indicated by the synthetic EOI call. */
4457                 if ((class == BER_CLASS_UNI) && (tag == BER_UNI_TAG_EOC)) { /* explicit EOC never has a name */
4458                         PUSHNODE(pos); /* restore stack */
4459                         ret = "explicit-EOC";
4460                         if (asn1_verbose) g_message("  return '%s', ignore", ret);
4461                         out->name = ret;
4462                         out->typename = "ASN1";
4463                         return out;
4464                 }
4465
4466                 /* find appropriate node for this tag */
4467
4468                 if (pos.node == NULL) {
4469                         if (asn1_verbose) g_message("  pos.node == NULL");
4470                         out->name = "*no-name*";
4471                         out->flags |= OUT_FLAG_noname;
4472                         PDUerrcount++;
4473                         return out;
4474                 }
4475
4476                 /* showNode(pos.node, 3, 4); */
4477
4478                 switch (pos.type & TBL_TYPEmask) {
4479                 case TBL_SEQUENCE: /* avoid finishing a choice when we have to do a sequence first */
4480                 case TBL_SET:
4481                         break;
4482                 default:
4483                         if (pos.type & TBL_CHOICE_made) {
4484                                 if (asn1_verbose) g_message("    finish choice");
4485                                 donext = 1;
4486                         }
4487                         break;
4488                 }
4489
4490                 info = getinfo(pos.node);
4491
4492                 if (pos.type & TBL_REPEAT) { /* start of a repeat */
4493                         switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4494                         case TBL_CHOICE:
4495                                 if (asn1_verbose) g_message("    repeating choice"); /* ignore repeat */
4496                                 break;
4497                         default:
4498                                 if (asn1_verbose) g_message("    seqof: repeat start");
4499                                 /* decide how to continue, CHILD for next instance of sequence
4500                                  * or NEXT for end of repeated sequence.
4501                                  * use the tag to make a descision */
4502                                 if (asn1_verbose) g_message("    seqof: first got %c%d, found %c%d",
4503                                                         tag_class[class], tag,
4504                                                         tag_class[info->tclass], info->tag);
4505                                 if ( MATCH ) {
4506                                         /* This is the start of repeating */
4507                                         PUSHNODE(pos);
4508                                         ret = getname(pos.node);
4509                                         if (asn1_verbose) g_message("  return for repeat '%s'", ret);
4510                                         out->type = (pos.type & TBL_TYPEmask);
4511                                         out->typename = info->typename;
4512                                         out->name = ret;
4513                                         out->value_id = info->value_id;
4514                                         out->type_id = info->type_id;
4515                                         if (ISANONYMOUS) {
4516                                                 if (asn1_verbose) g_message("    anonymous: dontshow");
4517                                                 if (asn1_debug)
4518                                                         out->flags |= OUT_FLAG_dontshow;
4519                                                 else
4520                                                         out->name = empty;
4521                                         }
4522                                         return out;
4523                                 } else {
4524                                         /* find out where to go .... */
4525                                         pos2 = pos;
4526                                         CHILD;  /* assume sequence is repeated */
4527                                         if (pos.node) {
4528                                                 info = getinfo(pos.node);       /* needed for MATCH to look ahead */
4529                                                 if (asn1_verbose)
4530                                                     g_message("    seqof: child: got %c%d, found %c%d",
4531                                                               tag_class[class], tag,
4532                                                               tag_class[info->tclass], info->tag);
4533                                         }
4534                                         if (pos2.type & TBL_CHOICE_repeat) {
4535                                                 pos = POPSTATE;
4536                                                 if (asn1_verbose)
4537                                                         g_message("    repeating a choice, %s",
4538                                                                   getname(pos.node));
4539                                                 pos.type = TBL_CHOICE_immediate;
4540                                         } else {
4541                                                 if ( pos.node && ! MATCH) { /* no, repeat ends, */
4542                                                         donext = 1;     /* move on */
4543                                                         if (asn1_verbose)
4544                                                           g_message("    seqof: no repeat, force next");
4545                                                 }
4546                                                 /* following code will take the child again */
4547                                                 pos = pos2;
4548                                         }
4549                                 }
4550                                 break;
4551                         }
4552                 } else  if (pos.type & TBL_REFERENCE_pop) { /* reference finished, return to caller */
4553                         if (asn1_verbose) g_message("    reference pop, donext");
4554                         pos = POPSTATE;
4555                         donext = 1;
4556                 } else if (pos.type & TBL_SEQUENCE_done) { /* Children have been processed */
4557                         if (pos.type & TBL_SEQUENCE_choice) {
4558                                 pos = POPSTATE; /* expect to find a repeat here */
4559                         } else {
4560                                 donext = 1;
4561                                 if (asn1_verbose) g_message("    sequence done, donext");
4562                         }
4563                 }
4564
4565                 if (pos.type & TBL_REFERENCE) {
4566                         if (asn1_verbose) g_message("    reference change ref -> pop");
4567                         pos.type ^= (TBL_REFERENCE | TBL_REFERENCE_pop);
4568                 }
4569
4570                 pos.offset = offset;
4571
4572                 ret = pos.name; /* for the debug messages */
4573
4574                 if (donext) {
4575                         if (asn1_verbose) g_message("    donext");
4576                         NEXT;
4577                 } else {
4578                         switch(pos.type & TBL_TYPEmask) { /* type of previous node */
4579                         case TBL_SETOF:         /* ?? */
4580                         case TBL_SEQUENCEOF:
4581                                 if ((pos.type & TBL_REPEAT) == 0) { /* start repeating */
4582                                         pos.type |= TBL_REPEAT;
4583                                         PUSHNODE(pos);
4584                                         CHILD;
4585                                         pushed++;
4586                                                 /* remember this is the start of a repeat cycle */
4587                                         typeflags |= TBL_REPEAT;
4588                                         if (asn1_verbose)
4589                                                 g_message("    seqof: set repeat mark [push,child]");
4590                                 } else {
4591                                         if (asn1_verbose)
4592                                                 g_message("    seqof: end of repeat loop [next]");
4593                                         NEXT;
4594                                 }
4595                                 break;
4596                         case TBL_SET:           /* ?? */
4597                         case TBL_SEQUENCE:
4598                                 pos.type |= TBL_SEQUENCE_done;
4599                                 PUSHNODE(pos);
4600                                 CHILD;
4601                                 pushed++;
4602                                 if (asn1_verbose) g_message("    seq [push,child]");
4603                                 break;
4604                         case TBL_CHOICE:
4605                                                 /* no more choice */
4606                                 pos.type = (TBL_CHOICE_done | (pos.type & ~TBL_TYPEmask));
4607                                 PUSHNODE(pos);
4608
4609                                 pos.type = 0; /* clear all type flags */
4610                                 if (asn1_verbose)
4611                                         g_message("    choice [push], %c%d, %s",
4612                                                   tag_class[info->tclass], info->tag, getname(pos.node));
4613                                 pos.node = makechoice(pos.node, class, tag);
4614                                 if (pos.node == NULL) {
4615                                         pos = POPSTATE;
4616                                         out->flags |= OUT_FLAG_noname;
4617                                         PDUerrcount++;
4618                                 }
4619                                 info = getinfo(pos.node);
4620
4621                                 ret = getname(pos.node);
4622                                 if (asn1_verbose)
4623                                         g_message("    '%s' %c%d will be used",
4624                                                   ret, tag_class[info->tclass], info->tag);
4625                                 break;
4626                         case TBL_CHOICE_done:
4627                                 NEXT;
4628                                 break;
4629                         case TBL_TYPEREF:
4630                                 pos = POPSTATE;
4631                                 NEXT;
4632                                 if (asn1_verbose) g_message("    typeref [pop,next]");
4633                                 break;
4634                         case TBL_ENUMERATED:
4635                         case TBL_BITSTRING:
4636                                 /* skip named numbers now, call to PDUenum() will retrieve a name */
4637                                 NEXT;
4638                                 break;
4639                         case TBL_CHOICE_immediate:
4640                                 if (asn1_verbose) g_message("    immediate choice [no next]");
4641                                 /* nothing */
4642                                 break;
4643                         default:
4644                                 NEXT;
4645                                 break;
4646                         }
4647                 }
4648
4649                 if (pos.node == NULL) {
4650                         ret = "*no-name-2*";
4651                         if (asn1_verbose) g_message("  return '%s'", ret);
4652                         out->name = ret;
4653                         out->flags |= OUT_FLAG_noname;
4654                         PDUerrcount++;
4655                         return out;
4656                 }
4657                 ret = pos.name = getname(pos.node);
4658                 pos.type = gettype(pos.node) | (pos.type & ~TBL_TYPEmask);
4659                 info = getinfo(pos.node);
4660
4661                 /* pos now points to the prospective current node, go check it ********************/
4662                 if (asn1_verbose && info) g_message("  candidate %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4663                                 (ISOPTIONAL)?", optional":empty,
4664                                 (ISIMPLICIT)?", implicit":empty,
4665                                 tag_class[info->tclass], info->tag );
4666
4667                 if (ISOPTIONAL) { /* must check the tag */
4668                         while(! MATCH) {   /* check optional here again...? */
4669                                 if (asn1_verbose)
4670                                         g_message("    got %c%d, found %c%d", tag_class[class], tag,
4671                                                         tag_class[info->tclass], info->tag);
4672                                 NEXT;
4673                                 if (pos.node == NULL) {
4674                                         ret = "------";
4675                                         if (cons) {
4676                                                 pos = save_pos; /* reset for next time */
4677                                                 pos.type |= TBL_SEQUENCE_done;
4678                                                 PUSHNODE(pos);
4679                                                 pos.type &= ~TBL_SEQUENCE_done;
4680                                                 cons_handled = 1;
4681                                                 out->flags |= OUT_FLAG_dontshow;
4682                                                 if (asn1_verbose)
4683                         g_message("    end of optional list, constructed, expect value next time");
4684                                         } else {
4685                                                 PDUerrcount++;
4686                                                 out->flags |= OUT_FLAG_noname;
4687                                                 if (asn1_verbose)
4688                                                         g_message("    *end of optional list...");
4689                                                 info = 0; /* this is not valid any more... */
4690                                         }
4691                                         break;  /* end of list */
4692                                 }
4693                                 info = getinfo(pos.node);
4694                                 if (asn1_verbose) g_message("  optional, %s", getname(pos.node));
4695                         }
4696                         if (pos.node && ! cons_handled) {
4697                                 ret = pos.name = getname(pos.node);
4698                                 pos.type = gettype(pos.node);
4699                         }
4700                         /* pos now refers to node with name we want, optional nodes skipped */
4701                 }
4702
4703                 if (pos.type == TBL_CHOICE) { /* may be an immediate choice */
4704                         pos2 = pos; /* save current state */
4705                         if ( ! MATCH) {
4706                                 if (! pushed) {
4707                                         if (asn1_verbose)
4708                                                 g_message("    already pushed, skip next push");
4709                                         PUSHNODE(pos);
4710                                         typeflags &= ~TBL_CHOICE_made;
4711                                 }
4712
4713                                 if (asn1_verbose && info)
4714                                         g_message("    immediate choice [push], %c%d, %s",
4715                                                   tag_class[info->tclass], info->tag, getname(pos.node));
4716                                 if (pos.node) {
4717                                         pos.node = makechoice(pos.node, class, tag);
4718                                 }
4719                                 if (pos.node == NULL) {
4720                                         pos = POPSTATE;
4721                                         PDUerrcount++;
4722                                 }
4723                                 info = getinfo(pos.node);
4724                                 pos.type = gettype(pos.node);
4725                                 out->type = (pos.type & TBL_TYPEmask);
4726                                 out->flags |= OUT_FLAG_type;
4727
4728                                 g_sprintf(namestr, "%s!%s", ret, getname(pos.node));
4729                                 ret = namestr;
4730                                 if (asn1_verbose)
4731                                         g_message("    %s:%s will be used", TBLTYPE(pos.type), ret);
4732                                 if (typeflags & TBL_REPEAT) {
4733                                         pos2.type |= TBL_REPEAT | TBL_REPEAT_choice;
4734                                         PUSHNODE(pos2);
4735                                         pos.type |= TBL_SEQUENCE_choice;
4736                                         PUSHNODE(pos);
4737                                         if (asn1_verbose)
4738                                                 g_message("  return from immediate choice [%s] '%s'",
4739                                                                 TBLTYPE(pos.type), ret);
4740
4741                                         out->data = pos.node; /* for access to named numbers... */
4742
4743                                         out->type = (pos.type & TBL_TYPEmask);
4744                                         out->name = ret;
4745                                         if (info) {
4746                                                 out->typename = info->typename;
4747                                                 out->fullname = info->fullname;
4748                                                 out->value_id = info->value_id;
4749                                                 out->type_id = info->type_id;
4750                                         }
4751
4752                                         return out;
4753                                 } else {
4754                                         typeflags |= TBL_CHOICE_made;
4755                                 }
4756                         } else {
4757                                 if (asn1_verbose) g_message("    matching choice '%s'", ret);
4758                         }
4759                         if ( ! cons ) { /* ISIMPLICIT was not OK for all */
4760                                 pos = pos2; /* reset for continuation */
4761                         }
4762                 }
4763                 if (asn1_verbose) {
4764                         if (info)
4765                                 g_message("  using: %s '%s'%s%s, %c%d", TBLTYPE(pos.type), ret,
4766                                           (ISOPTIONAL)?", optional":empty,
4767                                           (ISIMPLICIT)?", implicit":empty,
4768                                           tag_class[info->tclass], info->tag );
4769                         else
4770                                 g_message("  using: unknown '%s'", ret);
4771                 }
4772
4773                 /* must follow references now */
4774                 if (pos.type == TBL_TYPEREF && info) {
4775                         out->typename = info->typename;
4776                         out->type_id = info->typenum;
4777                         out->flags |= OUT_FLAG_typename;
4778                         pos2 = pos;
4779                         PUSHNODE(pos);  /* remember where we were */
4780                         if (asn1_verbose) g_message("   typeref [push]");
4781                         typeflags |= TBL_REFERENCE;
4782                         if (info->reference == 0) { /* resolved ref to universal type.... */
4783                                 /* showNode(pos.node, 3, 4); */
4784                                 pos.type = gettype(pos.node); /* the resulting type */
4785                                 info = getinfo(pos.node);
4786                                 tmp = "inknown tag";
4787                                 if ((info->tclass == BER_CLASS_UNI) && (info->tag < 31)) {
4788                                         tmp = asn1_tag[info->tag];
4789                                         pos.type = asn1_uni_type[info->tag]; /* get univsrsal type */
4790                                 }
4791                                 if (asn1_verbose && info)
4792                                         g_message("  indirect typeref to %s:%s, %s [%c%d]",
4793                                                   TBLTYPE(pos.type), info->typename, tmp,
4794                                                   tag_class[info->tclass], info->tag );
4795                         } else {
4796                                 out->fullname = info->fullname;
4797                                 donext = (ISANONYMOUS); /* refereing entity has no name ? */
4798                                 pos.node = info->reference;
4799                                 pos.type = gettype(pos.node);
4800                                 info = getinfo(pos.node);
4801                                 if (asn1_verbose)
4802                                         g_message("  typeref %s %s", TBLTYPE(pos.type), getname(pos.node));
4803                         /* keep name from before going through the reference, unless anonymous */
4804                                 if (donext) /* refering entity has no name */
4805                                         ret = getname(pos.node); /* a better name */
4806
4807                                 /* handle choice here ? !!mm!! */
4808
4809                                 out->type = (pos.type & TBL_TYPEmask);
4810                                 out->flags |= OUT_FLAG_type;
4811                                 /* showNode(pos.node, 3, 4); */
4812                                 /* ret = getname(pos.node);*/
4813
4814                                 out->data = pos.node;
4815                                 out->flags |= OUT_FLAG_data;
4816                                 if (asn1_verbose)
4817                                         g_message("  typeref set named number list node %p", (void *)pos.node);
4818
4819                                 if ( ! cons) {
4820                                         pos = POPSTATE;
4821                                         pos.type = TBL_TYPEREF_nopop;
4822                                         if (asn1_verbose) g_message("    typeref pop");
4823                                 } else if ((pos.type == TBL_ENUMERATED) || (pos.type == TBL_BITSTRING)){
4824                                                 /* do not enter the named-number list */
4825                                         pos = POPSTATE;
4826                                         pos.type = TBL_TYPEREF_nopop;
4827                                         if (asn1_verbose) g_message("    typeref [pop]");
4828                                 } else {
4829                                         typeflags |= TBL_REFERENCE;
4830                                 }
4831                         }
4832                 }
4833
4834                 if (cons && ! cons_handled) {   /* This entity is constructed, expected ? */
4835                         switch(pos.type) {
4836                         case TBL_BOOLEAN: /* these are not expected to be constructed */
4837                         case TBL_INTEGER:
4838                         case TBL_OCTETSTRING:
4839                         case TBL_NULL:
4840                         case TBL_OID:
4841                         case TBL_REAL:
4842                         case TBL_ENUMERATED:
4843                         case TBL_TYPEREF:
4844                                 typeflags |= TBL_CONSTRUCTED;
4845                                         /* this entry has no extra info, next is the same */
4846                                 out->flags |= (OUT_FLAG_dontshow | OUT_FLAG_constructed);
4847                                 if (asn1_verbose) g_message("    dontshow and set constructed flag");
4848                                 break;
4849                         default: /* others, such as sequences, are expected to be constructed */
4850                                 break;
4851                         }
4852                 }
4853         }
4854
4855         if (ISANONYMOUS) {
4856                 if (asn1_verbose) g_message("    anonymous: dontshow");
4857                 if (asn1_debug) /* this entry has no extra info, next is the same */
4858                         out->flags |= OUT_FLAG_dontshow;
4859                 else
4860                         out->name = empty; /* show it, but no name */
4861         }
4862
4863         if (out->name != empty)
4864                 out->name = ret;
4865
4866         if ( ! (out->flags & OUT_FLAG_data))
4867                 out->data = pos.node; /* for access to named numbers... */
4868
4869         pos.type |= typeflags;
4870         PUSHNODE(pos);
4871
4872         if ( ! (out->flags & OUT_FLAG_type))
4873                 out->type = pos.type;
4874
4875         out->type &= TBL_TYPEmask;
4876
4877         if (ret == noname) {
4878                 PDUerrcount++;
4879                 out->flags |= OUT_FLAG_noname;
4880         }
4881
4882         if (info && ((out->flags & OUT_FLAG_typename) == 0)) {
4883                 out->typename = info->typename;
4884                 out->type_id = info->typenum;
4885         }
4886
4887         if (info && (out->value_id == -1)) {
4888                 out->value_id = info->value_id;
4889                 out->type_id = info->type_id;
4890         }
4891
4892         if ((out->fullname == 0) && info)
4893                 out->fullname = info->fullname;
4894
4895         if (typeflags & TBL_CONSTRUCTED)
4896                 constructed_save = *out;
4897
4898         if (asn1_verbose)
4899                 g_message("  return [%s] '%s' vid=%d, tid=%d", TBLTYPE(out->type), out->name,
4900                                                 out->value_id, out->type_id);
4901
4902         return out;
4903 }
4904
4905 static const char *
4906 getPDUenum(PDUprops *props, guint offset, guint cls, guint tag, guint value)
4907 {
4908         GNode *list;
4909         PDUinfo *info;
4910         const char *ret, *name;
4911         static char unnamed[] = "*unnamed*";
4912
4913         (void) cls; (void) tag;         /* make a reference */
4914
4915         if (props->flags & OUT_FLAG_noname)
4916                 return empty;
4917
4918         ret = unnamed;
4919         list = (GNode *)props->data;
4920
4921         if (list == 0) {
4922                 if (asn1_verbose) g_message("--off=%d named number list not initialized", offset);
4923                 PDUerrcount++;
4924                 return "*list-still-0*";
4925         }
4926
4927         if ((PDUinfo *)list->data)
4928                 name = ((PDUinfo *)list->data)->name;
4929         else
4930                 name = ret;
4931
4932         for(list = g_node_first_child(list); list; list = g_node_next_sibling(list)) {
4933                 info = (PDUinfo *)list->data;
4934                 if (value == info->tag) {
4935                         ret = info->name;
4936                         break;
4937                 }
4938         }
4939         if (ret == unnamed)
4940                 PDUerrcount++;
4941
4942         if (asn1_verbose)
4943                 g_message("--off=%d namednumber %d=%s from list %s", offset, value, ret, name);
4944         return ret;
4945 }
4946
4947 #endif /* READSYNTAX */
4948
4949 void
4950 proto_register_asn1(void) {
4951
4952   static const enum_val_t type_recursion_opts[] = {
4953           { "0", "0", 0 },
4954           { "1", "1", 1 },
4955           { "2", "2", 2 },
4956           { "3", "3", 3 },
4957           { "4", "4", 4 },
4958           { "4", "5", 5 },
4959           { "6", "6", 6 },
4960           { "7", "7", 7 },
4961           { "8", "8", 8 },
4962           { "9", "9", 9 },
4963           { NULL, NULL, -1},
4964   };
4965
4966   gint *ett[1+MAX_NEST+MAXPDU];
4967
4968   module_t *asn1_module;
4969   int i, j;
4970   const char *orig_ptr;
4971
4972   asn1_logfile = get_tempfile_path(ASN1LOGFILE);
4973
4974   current_asn1 = g_strdup("");
4975   asn1_filename = g_strdup(current_asn1);
4976
4977   current_pduname = g_strdup("ASN1");
4978   asn1_pduname = g_strdup(current_pduname);
4979
4980   proto_asn1 = proto_register_protocol("ASN.1 decoding",
4981                                        "ASN1", pabbrev);
4982
4983   ett[0] = &ett_asn1;
4984   for (i=0, j=1; i<MAX_NEST; i++, j++) {
4985           ett[j] = &ett_seq[i];
4986           ett_seq[i] = -1;
4987   }
4988   for(i=0; i<MAXPDU; i++, j++) {
4989           ett[j] = &ett_pdu[i];
4990           ett_pdu[i] = -1;
4991   }
4992
4993   proto_register_subtree_array(ett, array_length(ett));
4994
4995   asn1_module = prefs_register_protocol(proto_asn1,
4996                                         proto_reg_handoff_asn1);
4997 #ifdef JUST_ONE_PORT
4998   prefs_register_uint_preference(asn1_module, "tcp_port",
4999                                  "ASN.1 TCP Port",
5000                                  "The TCP port on which "
5001                                  "ASN.1 messages will be read",
5002                                  10, &global_tcp_port_asn1);
5003   prefs_register_uint_preference(asn1_module, "udp_port",
5004                                  "ASN.1 UDP Port",
5005                                  "The UDP port on which "
5006                                  "ASN.1 messages will be read",
5007                                  10, &global_udp_port_asn1);
5008   prefs_register_uint_preference(asn1_module, "sctp_port",
5009                                  "ASN.1 SCTP Port",
5010                                  "The SCTP port on which "
5011                                  "ASN.1 messages will be read",
5012                                  10, &global_sctp_port_asn1);
5013 #else
5014   range_convert_str(&global_tcp_ports_asn1,  ep_strdup_printf("%u", TCP_PORT_ASN1),  65535);
5015   range_convert_str(&global_udp_ports_asn1,  ep_strdup_printf("%u", UDP_PORT_ASN1),  65535);
5016   range_convert_str(&global_sctp_ports_asn1, ep_strdup_printf("%u", SCTP_PORT_ASN1), 65535);
5017
5018   prefs_register_range_preference(asn1_module, "tcp_ports",
5019                                  "ASN.1 TCP Ports",
5020                                  "The TCP ports on which "
5021                                  "ASN.1 messages will be read",
5022                                  &global_tcp_ports_asn1, 65535);
5023   prefs_register_range_preference(asn1_module, "udp_ports",
5024                                  "ASN.1 UDP Ports",
5025                                  "The UDP ports on which "
5026                                  "ASN.1 messages will be read",
5027                                  &global_udp_ports_asn1, 65535);
5028   prefs_register_range_preference(asn1_module, "sctp_ports",
5029                                  "ASN.1 SCTP Ports",
5030                                  "The SCTP ports on which "
5031                                  "ASN.1 messages will be read",
5032                                  &global_sctp_ports_asn1, 65535);
5033 #endif /* JUST_ONE_PORT */
5034
5035   prefs_register_bool_preference(asn1_module, "desegment_messages",
5036                                  "Desegment TCP",
5037                                  "Desegment ASN.1 messages that span TCP segments",
5038                                  &asn1_desegment);
5039
5040   old_default_asn1_filename = get_datafile_path(OLD_DEFAULT_ASN1FILE);
5041 #ifdef _WIN32
5042   bad_separator_old_default_asn1_filename = get_datafile_path(BAD_SEPARATOR_OLD_DEFAULT_ASN1FILE);
5043 #endif
5044
5045   orig_ptr = asn1_filename;
5046   prefs_register_string_preference(asn1_module, "file",
5047                                    "ASN.1 type table file",
5048                                    "Compiled ASN.1 description of ASN.1 types",
5049                                    &asn1_filename);
5050   /* prefs_register_string_preference just overwrite our pointer with a pointer
5051    *  to a _copy_ of our string.  Free the original string.
5052    */
5053   g_free((char *)orig_ptr);
5054
5055   orig_ptr = asn1_pduname;
5056   prefs_register_string_preference(asn1_module, "pdu_name",
5057                                    "ASN.1 PDU name",
5058                                    "Name of top level PDU",
5059                                    &asn1_pduname);
5060   g_free((char *)orig_ptr);
5061
5062   prefs_register_uint_preference(asn1_module, "first_pdu_offset",
5063                                  "Offset to first PDU in first tcp packet",
5064                                  "Offset for non-reassembled packets, "
5065                                  "wrong if this happens on other than the first packet!",
5066                                  10, &first_pdu_offset);
5067   prefs_register_bool_preference(asn1_module, "flat",
5068                                  "Show full names",
5069                                  "Show full names for all values",
5070                                  &asn1_full);
5071   prefs_register_enum_preference(asn1_module, "type_recursion",
5072                                  "Eliminate references to level",
5073                                  "Allow this recursion level for eliminated type references",
5074                                  &type_recursion_level,
5075                                  type_recursion_opts, FALSE);
5076   prefs_register_bool_preference(asn1_module, "debug",
5077                                  "ASN.1 debug mode",
5078                                  "Extra output useful for debugging",
5079                                  &asn1_debug);
5080 #if 0
5081   prefs_register_bool_preference(asn1_module, "message_win",
5082                                  "Show ASN.1 tree",
5083                                  "show full message description",
5084                                  &asn1_message_win);
5085 #else
5086   prefs_register_obsolete_preference(asn1_module, "message_win");
5087 #endif
5088   prefs_register_bool_preference(asn1_module, "verbose_log",
5089                                  "Write very verbose log",
5090                                  "log to file $TMP/" ASN1LOGFILE,
5091                                  &asn1_verbose);
5092 }
5093
5094 /* The registration hand-off routing */
5095
5096 static dissector_handle_t asn1_handle;
5097
5098 static void
5099 register_tcp_port(guint32 port)
5100 {
5101   if (port != 0)
5102     dissector_add_uint("tcp.port", port, asn1_handle);
5103 }
5104
5105 static void
5106 unregister_tcp_port(guint32 port)
5107 {
5108   if (port != 0)
5109     dissector_delete_uint("tcp.port", port, asn1_handle);
5110 }
5111
5112 static void
5113 register_udp_port(guint32 port)
5114 {
5115   if (port != 0)
5116     dissector_add_uint("udp.port", port, asn1_handle);
5117 }
5118
5119 static void
5120 unregister_udp_port(guint32 port)
5121 {
5122   if (port != 0)
5123     dissector_delete_uint("udp.port", port, asn1_handle);
5124 }
5125
5126 static void
5127 register_sctp_port(guint32 port)
5128 {
5129   if (port != 0)
5130     dissector_add_uint("sctp.port", port, asn1_handle);
5131 }
5132
5133 static void
5134 unregister_sctp_port(guint32 port)
5135 {
5136   if (port != 0)
5137     dissector_delete_uint("sctp.port", port, asn1_handle);
5138 }
5139
5140 void
5141 proto_reg_handoff_asn1(void) {
5142   static gboolean asn1_initialized = FALSE;
5143 /* XXX: Note that the "saved" ports [or port ranges] will not be initialized the first time */
5144 /*      thru pro_reg_handoff_asn1 if no PDUtree is built; So: we init with the definition.  */
5145 #ifdef JUST_ONE_PORT
5146   static guint tcp_port_asn1  = 0;
5147   static guint udp_port_asn1  = 0;
5148   static guint sctp_port_asn1 = 0;
5149 #else
5150   static range_t *tcp_ports_asn1  = NULL;
5151   static range_t *udp_ports_asn1  = NULL;
5152   static range_t *sctp_ports_asn1 = NULL;
5153 #endif
5154
5155   pcount = 0;
5156
5157 #ifdef JUST_ONE_PORT
5158   if (asn1_verbose) g_message("prefs change: tcpport=%u, udpport=%u, sctpport=%u, desegnment=%d, "
5159                 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5160           global_tcp_port_asn1, global_udp_port_asn1, global_sctp_port_asn1, asn1_desegment,
5161           asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5162 #else
5163   if (asn1_verbose) {
5164     char *tcp_ports_asn1_string, *udp_ports_asn1_string, *sctp_ports_asn1_string;
5165     tcp_ports_asn1_string = range_convert_range(global_tcp_ports_asn1);
5166     udp_ports_asn1_string = range_convert_range(global_udp_ports_asn1);
5167     sctp_ports_asn1_string = range_convert_range(global_sctp_ports_asn1);
5168     g_message("prefs change: tcpports=%s, udpports=%s, sctpports=%s, desegnment=%d, "
5169                 "asn1file=%s, pduname=%s, first_offset=%d, debug=%d, msg_win=%d, verbose=%d",
5170           tcp_ports_asn1_string, udp_ports_asn1_string, sctp_ports_asn1_string, asn1_desegment,
5171           asn1_filename, asn1_pduname, first_pdu_offset, asn1_debug, asn1_message_win, asn1_verbose);
5172   }
5173 #endif /* JUST_ONE_PORT */
5174
5175   if(!asn1_initialized) {
5176     asn1_handle = create_dissector_handle(dissect_asn1,proto_asn1);
5177     asn1_initialized = TRUE;
5178   } else {      /* clean up ports and their lists */
5179 #ifdef JUST_ONE_PORT
5180     unregister_tcp_port(tcp_port_asn1);
5181     unregister_udp_port(udp_port_asn1);
5182     unregister_sctp_port(sctp_port_asn1);
5183 #else
5184     if (tcp_ports_asn1 != NULL) {
5185       range_foreach(tcp_ports_asn1, unregister_tcp_port);
5186       g_free(tcp_ports_asn1);
5187     }
5188
5189     if (udp_ports_asn1 != NULL) {
5190       range_foreach(udp_ports_asn1, unregister_udp_port);
5191       g_free(udp_ports_asn1);
5192     }
5193
5194     if (sctp_ports_asn1 != NULL) {
5195       range_foreach(sctp_ports_asn1, unregister_sctp_port);
5196       g_free(sctp_ports_asn1);
5197     }
5198 #endif /* JUST_ONE_PORT */
5199   }
5200
5201   if (strcmp(asn1_filename, current_asn1) != 0) {
5202           /* new definitions, parse the file if we have one */
5203           /* !!! should be postponed until we really need it !!! */
5204 #ifdef READSYNTAX
5205           read_asn1_type_table(asn1_filename);
5206 #endif /* READSYNTAX */
5207           g_free(current_asn1);
5208           current_asn1 = g_strdup(asn1_filename);
5209   }
5210   if (!PDUtree ||       /* no tree built yet for PDU type */
5211       strcmp(asn1_pduname, current_pduname) != 0) { /* new PDU type, build tree for it */
5212           if (build_pdu_tree(asn1_pduname)) {
5213                   g_free(current_pduname);
5214                   current_pduname = g_strdup(asn1_pduname);
5215           }
5216   }
5217 #ifdef SHOWPDU
5218   if (asn1_message_win) {       /* show what we are prepared to recognize */
5219           if (window) {
5220                   gtk_widget_destroy (window);
5221                   window = NULL;
5222           }
5223           create_message_window();
5224   }
5225 #endif /* SHOWPDU */
5226
5227   /* If we now have a PDU tree, register for the port or ports we have */
5228   if (PDUtree) {
5229 #ifdef JUST_ONE_PORT
5230     tcp_port_asn1 = global_tcp_port_asn1;
5231     udp_port_asn1 = global_udp_port_asn1;
5232     sctp_port_asn1 = global_sctp_port_asn1;
5233
5234     register_tcp_port(tcp_port_asn1);
5235     register_udp_port(udp_port_asn1);
5236     register_sctp_port(sctp_port_asn1);
5237 #else
5238     tcp_ports_asn1 = range_copy(global_tcp_ports_asn1);
5239     udp_ports_asn1 = range_copy(global_udp_ports_asn1);
5240     sctp_ports_asn1 = range_copy(global_sctp_ports_asn1);
5241
5242     range_foreach(tcp_ports_asn1, register_tcp_port);
5243     range_foreach(udp_ports_asn1, register_udp_port);
5244     range_foreach(sctp_ports_asn1, register_sctp_port);
5245 #endif /* JUST_ONE_PORT */
5246   }
5247 }