/* packet-dis-pdus.c
 * Routines and definitions for DIS PDU parsing.
 * Copyright 2005, Scientific Research Corporation
 * Initial implementation by Jeremy Ouellette <jouellet@scires.com>
 *
 * $Id$
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"

#include "packet-dis-pdus.h"
#include "packet-dis-fields.h"
#include "packet-dis-enums.h"

#define DIS_PDU_MAX_VARIABLE_PARAMETERS              16
#define DIS_PDU_MAX_VARIABLE_RECORDS                 16
#define DIS_PDU_MAX_ELECTROMAGNETIC_EMISSION_SYSTEMS 16
#define DIS_PDU_MAX_SHAFTS                           16
#define DIS_PDU_MAX_APAS                             16
#define DIS_PDU_MAX_UA_EMITTER_SYSTEMS               16
#define DIS_PDU_MAX_UA_BEAMS                         32

gint ettVariableParameters[DIS_PDU_MAX_VARIABLE_PARAMETERS];
gint ettVariableRecords[DIS_PDU_MAX_VARIABLE_RECORDS];

gint ettFixedData = -1;
gint ettVariableData = -1;

/* DIS Entity Information / Interaction PDUs
 */
DIS_ParserNode DIS_PARSER_ENTITY_STATE_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_FORCE_ID,                "Force ID",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_ARTICULATION_PARAMS, "Number of Articulation Parameters",0,0,0,&numVariable },
    { DIS_FIELDTYPE_ENTITY_TYPE,             "Entity Type",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_TYPE,             "Alternative Entity Type",0,0,0,0 },
    { DIS_FIELDTYPE_LINEAR_VELOCITY,         "Entity Linear Velocity",0,0,0,0 },
    { DIS_FIELDTYPE_LOCATION_WORLD,          "Entity Location",0,0,0,0 },
    { DIS_FIELDTYPE_ORIENTATION,             "Entity Orientation",0,0,0,0 },
    { DIS_FIELDTYPE_APPEARANCE,              "Entity Appearance",0,0,0,0 },
    { DIS_FIELDTYPE_DEAD_RECKONING_PARAMS,   "Dead Reckoning Parameters",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_MARKING,          "Entity Marking",0,0,0,0 },
    { DIS_FIELDTYPE_CAPABILITIES,            "Capabilities",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_PARAMETERS,     "Variable Parameter",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

/* DIS Distributed Emission Regeneration PDUs
 */
DIS_ParserNode DIS_PARSER_ELECTROMAGNETIC_EMISSION_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Emitting Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_EVENT_ID,                "Event ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "State Update Indicator",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_ELECTROMAGNETIC_EMISSION_SYSTEMS, "Number of Systems (N)",0,0,0,&numVariable },
    { DIS_FIELDTYPE_PAD16,                   "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_ELECTROMAGNETIC_EMISSION_SYSTEM, "Emission System",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};


/* DIS Underwater Acoustic PDUs
 */
DIS_ParserNode DIS_PARSER_UNDERWATER_ACOUSTIC_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Emitting Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_EVENT_ID,                "Event ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "State Update Indicator",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                    "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Passive Parameter Index", 0,0,0,0 }, /* !! enum !! */
    { DIS_FIELDTYPE_UINT8,                   "Propulsion Plant Configuration",0,0,0,0 }, /* !! enum !! */
    { DIS_FIELDTYPE_NUM_OF_SHAFTS,           "Number of Shafts",0,0,0,&numShafts },
    { DIS_FIELDTYPE_NUM_OF_APAS,             "Number of Additional Passive Activities (APA)",0,0,0,&numApas },
    { DIS_FIELDTYPE_NUM_OF_UA_EMITTER_SYSTEMS, "Number of UA Emitter Systems",0,0,0,&numUAEmitter },
    { DIS_FIELDTYPE_SHAFTS,                  "Shafts",0,0,0,0 },
    { DIS_FIELDTYPE_APA,                     "APAs",0,0,0,0 },
    { DIS_FIELDTYPE_UA_EMITTER_SYSTEMS,      "Underwater Acoustic Emission System",0,0,0,0 },
    { DIS_FIELDTYPE_UA_BEAMS,                "Beams",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};


/* DIS Radio Communications protocol (RCP) family PDUs
 */
DIS_ParserNode DIS_PARSER_TRANSMITTER_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_RADIO_ID,                     "Radio ID",0,0,0,&radioID },
    { DIS_FIELDTYPE_RADIO_ENTITY_TYPE,            "Radio Entity Type",0,0,0,0 },
    { DIS_FIELDTYPE_RADIO_TRANSMIT_STATE,         "Radio Transmit State",0,0,0,&disRadioTransmitState },
    { DIS_FIELDTYPE_RADIO_INPUT_SOURCE,           "Radio Input Source",0,0,0,0 },
    { DIS_FIELDTYPE_PAD16,                        "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_ANTENNA_LOCATION,             "Antenna Location",0,0,0,0 },
    { DIS_FIELDTYPE_REL_ANTENNA_LOCATON,          "Relative Antenna Location",0,0,0,0 },
    { DIS_FIELDTYPE_ANTENNA_PATTERN_TYPE,         "Antenna Pattern Type",0,0,0,&disAntennaPattern },
    { DIS_FIELDTYPE_ANTENNA_PATTERN_LENGTH,       "Antenna Pattern Length",0,0,0,0 },
    { DIS_FIELDTYPE_TRANSMIT_FREQUENCY,           "Transmit Frequency",0,0,0,0 },
    { DIS_FIELDTYPE_FLOAT32,                      "Transmit Frequency Bandwidth",0,0,0,0 },
    { DIS_FIELDTYPE_FLOAT32,                      "Transmit Power",0,0,0,0 },
    { DIS_FIELDTYPE_MODULATION_TYPE,              "Modulation Type",0,0,0,0 },
    { DIS_FIELDTYPE_CRYPTO_SYSTEM,                "Crypto System",0,0,0,0 },
    { DIS_FIELDTYPE_CRYPTO_KEY_ID,                "Crypto Key ID",0,0,0,0 },
    { DIS_FIELDTYPE_MODULATION_PARAMETER_LENGTH,  "Modulation Parameter Length",0,0,0,&modulationParamLength },
    { DIS_FIELDTYPE_PAD24,                        "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_MODULATION_PARAMETERS,        "Modulation Parameters",0,0,0,0 },
    /* need to finish decoding this PDU */
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_SIGNAL_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_RADIO_ID,                "Radio ID",0,0,0,&radioID },
    { DIS_FIELDTYPE_ENCODING_SCHEME,         "Encoding Scheme",0,0,0,&encodingScheme },
    { DIS_FIELDTYPE_TDL_TYPE,                "TDL Type",0,0,0,0 },
    { DIS_FIELDTYPE_SAMPLE_RATE,             "Sample Rate",0,0,0,0 },
    { DIS_FIELDTYPE_DATA_LENGTH,             "Data Length",0,0,0,0 },
    { DIS_FIELDTYPE_NUMBER_OF_SAMPLES,       "Number of Samples",0,0,0,&numSamples },
    { DIS_FIELDTYPE_RADIO_DATA,              "Radio Data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

/* DIS Warfare PDUs
 */
DIS_ParserNode DIS_PARSER_FIRE_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,        "Firing Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,        "Target Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,        "Munition ID",0,0,0,0 },
    { DIS_FIELDTYPE_EVENT_ID,         "Event ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,           "Fire Mission Index",0,0,0,0 },
    { DIS_FIELDTYPE_LOCATION_WORLD,   "Location in World Coordinates",0,0,0,0 },
    { DIS_FIELDTYPE_BURST_DESCRIPTOR, "Burst Descriptor",0,0,0,0 },
    { DIS_FIELDTYPE_LINEAR_VELOCITY,  "Velocity",0,0,0,0 },
    { DIS_FIELDTYPE_FLOAT32,          "Range",0,0,0,0 },
    { DIS_FIELDTYPE_END,              NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DETONATION_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Firing Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Target Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Munition ID",0,0,0,0 },
    { DIS_FIELDTYPE_EVENT_ID,                "Event ID",0,0,0,0 },
    { DIS_FIELDTYPE_LINEAR_VELOCITY,         "Velocity",0,0,0,0 },
    { DIS_FIELDTYPE_LOCATION_WORLD,          "Location in World Coordinates",0,0,0,0 },
    { DIS_FIELDTYPE_BURST_DESCRIPTOR,        "Burst Descriptor",0,0,0,0 },
    { DIS_FIELDTYPE_LOCATION_ENTITY,         "Location in Entity Coordinates",0,0,0,0 },
    { DIS_FIELDTYPE_DETONATION_RESULT,       "Detonation Result",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_ARTICULATION_PARAMS, "Number of Articulation Parameters",0,0,0,&numVariable },
    { DIS_FIELDTYPE_PAD16,                   "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_PARAMETERS,     "Variable Parameter",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

/* DIS Simulation Management PDUs
 */
DIS_ParserNode DIS_PARSER_START_RESUME_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,              "Real World Time",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,              "Simulation Time",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_STOP_FREEZE_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,              "Real World Time",0,0,0,0 },
    { DIS_FIELDTYPE_REASON,                  "Reason",0,0,0,0 },
    { DIS_FIELDTYPE_FROZEN_BEHAVIOR,         "Frozen Behavior",0,0,0,0 },
    { DIS_FIELDTYPE_PAD16,                   "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_ACKNOWLEDGE_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ACKNOWLEDGE_FLAG,        "Acknowledge Flag",0,0,0,0 },
    { DIS_FIELDTYPE_RESPONSE_FLAG,           "Response Flag",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_ACTION_REQUEST_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_ACTION_ID,               "Action ID",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,          "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,       "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,            "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,         "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_ACTION_RESPONSE_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_STATUS,          "Request Status",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,          "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,       "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,            "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,         "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DATA_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_PAD32,                   "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,          "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,       "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,            "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,         "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DATA_QUERY_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_TIME_INTERVAL,           "Time interval",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,          "Number of Fixed Datum Ids",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,       "Number of Variable Datum Ids",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUM_IDS,         "Fixed datum ids",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUM_IDS,      "Variable datum ids",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_COMMENT_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,          "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,       "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,            "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,         "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_SIMAN_ENTITY_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,               "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,              "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

/* DIS Simulation Management with Reliability PDUs
 */
DIS_ParserNode DIS_PARSER_START_RESUME_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,                   "Real World Time",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,                   "Simulation Time",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",3,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_STOP_FREEZE_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_CLOCK_TIME,                   "Real World Time",0,0,0,0 },
    { DIS_FIELDTYPE_REASON,                       "Reason",0,0,0,0 },
    { DIS_FIELDTYPE_FROZEN_BEHAVIOR,              "Frozen Behavior",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_ACTION_REQUEST_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",3,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_ACTION_ID,                    "Action ID",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,               "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,            "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,                 "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,              "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DATA_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",3,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,               "Number of Fixed Data Fields",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,            "Number of Variable Data Fields",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUMS,                 "Fixed data",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUMS,              "Variable data",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DATA_QUERY_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",3,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_TIME_INTERVAL,                "Time interval",0,0,0,0 },
    { DIS_FIELDTYPE_NUM_FIXED_DATA,               "Number of Fixed Datum Ids",0,0,0,&numFixed },
    { DIS_FIELDTYPE_NUM_VARIABLE_DATA,            "Number of Variable Datum Ids",0,0,0,&numVariable },
    { DIS_FIELDTYPE_FIXED_DATUM_IDS,              "Fixed datum ids",0,0,0,0 },
    { DIS_FIELDTYPE_VARIABLE_DATUM_IDS,           "Variable datum ids",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_SIMAN_ENTITY_R_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",3,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

/* DIS Experimental V-DIS PDUs
 */
DIS_ParserNode DIS_PARSER_APPLICATION_CONTROL_PDU[] =
{
    { DIS_FIELDTYPE_ENTITY_ID,                    "Originating Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,                    "Receiving Entity ID",0,0,0,0 },
    { DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE, "Reliability",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                        "Time Interval",0,0,0,0 },
    { DIS_FIELDTYPE_CONTROL_ID,                   "Control ID",0,0,0,0 },
    { DIS_FIELDTYPE_PAD8,                         "Padding",0,0,0,0 },
    { DIS_FIELDTYPE_APPLICATION_TYPE,             "Originating App Type",0,0,0,0 },
    { DIS_FIELDTYPE_APPLICATION_TYPE,             "Receiving App Type",0,0,0,0 },
    { DIS_FIELDTYPE_REQUEST_ID,                   "Request ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                        "Number of Parts",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                        "Current Part",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                       "Number of Variable Records",0,0,0,&numVariable },
    { DIS_FIELDTYPE_VARIABLE_RECORDS,             "Record",0,0,0,0 },
    { DIS_FIELDTYPE_END,                          NULL,0,0,0,0 }
};

/* Persistent Object (PO) Family PDU parsers
 */
DIS_ParserNode DIS_PARSER_SIMULATOR_PRESENT_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Simulator Type",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,                  "Database Sequence Number",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,                  "Simulator Load",0,0,0,0 },
    { DIS_FIELDTYPE_FLOAT32,                 "Simulation Load",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,                  "Time",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,                  "Packets Sent",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Unit Database Version",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Relative Battle Scheme",0,0,0,0 },
    { DIS_FIELDTYPE_FIXED_LEN_STR,           "Terrain Name",32,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Terrain Version",0,0,0,0 },
    { DIS_FIELDTYPE_FIXED_LEN_STR,           "Host Name",32,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DESCRIBE_OBJECT_PO_PDU[] =
{
    { DIS_FIELDTYPE_UINT32,                  "Database Sequence Number",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "Object ID",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "World State ID",0,0,0,0 },
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Owner",0,0,0,0 },
    { DIS_FIELDTYPE_UINT16,                  "Sequence Number",0,0,0,0 },
    { DIS_FIELDTYPE_PERSISTENT_OBJECT_CLASS, "Object Class",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "Missing From World State",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_OBJECTS_PRESENT_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Owner",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "World State ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "Object Count",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_OBJECT_REQUEST_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Requesting Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Object Owner",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "World State ID",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "Object Count",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_DELETE_OBJECTS_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Requesting Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_UINT8,                   "Object Count",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_SET_WORLD_STATE_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Requesting Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_FLOAT32,                 "Clock Rate",0,0,0,0 },
    { DIS_FIELDTYPE_UINT32,                  "Seconds Since 1970",0,0,0,0 },
    { DIS_FIELDTYPE_ENTITY_ID,               "World State ID",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

DIS_ParserNode DIS_PARSER_NOMINATION_PO_PDU[] =
{
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Nominated Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Nominating Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_SIMULATION_ADDRESS,      "Missing Simulator",0,0,0,0 },
    { DIS_FIELDTYPE_END,                     NULL,0,0,0,0 }
};

/* Initialize the parsers for each PDU type and the standard DIS header.
 */
void initializeParsers(void)
{
    gint *ett[DIS_PDU_MAX_VARIABLE_PARAMETERS+DIS_PDU_MAX_VARIABLE_RECORDS+2];
    int   i, ett_index;

    initializeParser(DIS_FIELDS_PDU_HEADER);

    /* DIS Entity Information / Interaction PDUs */
    initializeParser(DIS_PARSER_ENTITY_STATE_PDU);

    /* DIS Distributed Emission Regeneration PDUs */
    initializeParser(DIS_PARSER_ELECTROMAGNETIC_EMISSION_PDU);
    initializeParser(DIS_PARSER_UNDERWATER_ACOUSTIC_PDU);

    /* DIS Radio Communications protocol (RCP) family PDUs */
    initializeParser(DIS_PARSER_TRANSMITTER_PDU);
    initializeParser(DIS_PARSER_SIGNAL_PDU);

    /* DIS Warfare PDUs */
    initializeParser(DIS_PARSER_FIRE_PDU);
    initializeParser(DIS_PARSER_DETONATION_PDU);

    /* DIS Simulation Management PDUs */
    initializeParser(DIS_PARSER_START_RESUME_PDU);
    initializeParser(DIS_PARSER_STOP_FREEZE_PDU);
    initializeParser(DIS_PARSER_ACKNOWLEDGE_PDU);
    initializeParser(DIS_PARSER_ACTION_REQUEST_PDU);
    initializeParser(DIS_PARSER_ACTION_RESPONSE_PDU);
    initializeParser(DIS_PARSER_DATA_PDU);
    initializeParser(DIS_PARSER_DATA_QUERY_PDU);
    initializeParser(DIS_PARSER_COMMENT_PDU);
    initializeParser(DIS_PARSER_SIMAN_ENTITY_PDU);

    /* DIS Simulation Management with Reliability PDUs */
    initializeParser(DIS_PARSER_START_RESUME_R_PDU);
    initializeParser(DIS_PARSER_STOP_FREEZE_R_PDU);
    initializeParser(DIS_PARSER_ACTION_REQUEST_R_PDU);
    initializeParser(DIS_PARSER_DATA_R_PDU);
    initializeParser(DIS_PARSER_DATA_QUERY_R_PDU);
    initializeParser(DIS_PARSER_SIMAN_ENTITY_R_PDU);

    /* DIS Experimental V-DIS PDUs */
    initializeParser(DIS_PARSER_APPLICATION_CONTROL_PDU);

    /* Initialize the Persistent Object PDUs */
    initializeParser(DIS_FIELDS_PERSISTENT_OBJECT_HEADER);
    initializeParser(DIS_PARSER_DESCRIBE_OBJECT_PO_PDU);
    initializeParser(DIS_PARSER_SIMULATOR_PRESENT_PO_PDU);
    initializeParser(DIS_PARSER_OBJECTS_PRESENT_PO_PDU);
    initializeParser(DIS_PARSER_OBJECT_REQUEST_PO_PDU);
    initializeParser(DIS_PARSER_DELETE_OBJECTS_PO_PDU);
    initializeParser(DIS_PARSER_SET_WORLD_STATE_PO_PDU);
    initializeParser(DIS_PARSER_NOMINATION_PO_PDU);

    /* Initialize the ett array */
    ett_index = 0;
    for (i=0; i<DIS_PDU_MAX_VARIABLE_PARAMETERS; i++, ett_index++)
    {
        ettVariableParameters[i] = -1;
        ett[ett_index] = &ettVariableParameters[i];
    }
    for (i=0; i<DIS_PDU_MAX_VARIABLE_RECORDS; i++, ett_index++)
    {
        ettVariableRecords[i] = -1;
        ett[ett_index] = &ettVariableRecords[i];
    }
    ett[ett_index++] = &ettFixedData;
    ett[ett_index++] = &ettVariableData;
    proto_register_subtree_array(ett, array_length(ett));
}

/* Create a specific subtree for a PDU or a composite PDU field.
 */
DIS_ParserNode *createSubtree(DIS_ParserNode parserNodes[], gint *ettVar)
{
    guint fieldIndex = 0;
    guint fieldCount;
    gint *ett[1];
    DIS_ParserNode *newSubtree;

    while (parserNodes[fieldIndex].fieldType != DIS_FIELDTYPE_END)
    {
        ++fieldIndex;
    }

    fieldCount = fieldIndex + 1;

    newSubtree = (DIS_ParserNode*)g_malloc(sizeof(DIS_ParserNode) * fieldCount);

    memcpy(newSubtree, parserNodes, sizeof(DIS_ParserNode) * fieldCount);

    initializeParser(newSubtree);

    *ettVar = -1;
    ett[0] = ettVar;
    proto_register_subtree_array(ett, array_length(ett));

    return newSubtree;
}

/* Initialize an array of parser nodes.
 */
void initializeParser(DIS_ParserNode parserNodes[])
{
    guint parserIndex = 0;

    /* Create the parser subtrees for each of the composite field types.
     */
    while (parserNodes[parserIndex].fieldType != DIS_FIELDTYPE_END)
    {
        switch (parserNodes[parserIndex].fieldType)
        {
        /* Bit fields */
        case DIS_FIELDTYPE_APPEARANCE:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_NONE,
                &parserNodes[parserIndex].ettVar);
            break;

        /* Composite types */
        case DIS_FIELDTYPE_MOD_PARAMS_CCTT_SINCGARS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_MOD_PARAMS_CCTT_SINCGARS,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_MOD_PARAMS_JTIDS_MIDS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_MOD_PARAMS_JTIDS_MIDS,
                &parserNodes[parserIndex].ettVar);
            break;

        case DIS_FIELDTYPE_BURST_DESCRIPTOR:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_BURST_DESCRIPTOR,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_CLOCK_TIME:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_CLOCK_TIME,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_ENTITY_ID:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_ENTITY_ID,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_ENTITY_TYPE:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_ENTITY_TYPE,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_RADIO_ENTITY_TYPE:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_RADIO_ENTITY_TYPE,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_EVENT_ID:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_EVENT_ID,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_ORIENTATION:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_ORIENTATION,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_SIMULATION_ADDRESS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_SIMULATION_ADDRESS,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_LINEAR_VELOCITY:
        case DIS_FIELDTYPE_LOCATION_ENTITY:
        case DIS_FIELDTYPE_REL_ANTENNA_LOCATON:
        case DIS_FIELDTYPE_VECTOR_32:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VECTOR_FLOAT_32,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_LOCATION_WORLD:
        case DIS_FIELDTYPE_ANTENNA_LOCATION:
        case DIS_FIELDTYPE_VECTOR_64:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VECTOR_FLOAT_64,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_MODULATION_TYPE:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_MODULATION_TYPE,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_ELECTROMAGNETIC_EMISSION_SYSTEM_BEAM:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_ELECTROMAGNETIC_EMISSION_SYSTEM_BEAM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_ELECTROMAGNETIC_EMISSION_SYSTEM:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_ELECTROMAGNETIC_EMISSION_SYSTEM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_EMITTER_SYSTEM:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_EMITTER_SYSTEM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_FUNDAMENTAL_PARAMETER_DATA:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_FUNDAMENTAL_PARAMETER_DATA,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_TRACK_JAM:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_TRACK_JAM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_SHAFTS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_UA_SHAFT,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_APA:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_APA,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_UA_EMITTER_SYSTEMS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_UA_EMITTER_SYSTEM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_UA_EMITTER_SYSTEM:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_UA_EMITTER_SYSTEM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_UA_BEAMS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_UA_BEAM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_UA_BEAM_FUNDAMENTAL_PARAMETER_DATA:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_UA_BEAM_FUNDAMENTAL_PARAMETER_DATA,
                &parserNodes[parserIndex].ettVar);
            break;
        /* Array records */
        case DIS_FIELDTYPE_FIXED_DATUMS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_FIXED_DATUM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_VARIABLE_DATUMS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VARIABLE_DATUM,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_FIXED_DATUM_IDS:
        case DIS_FIELDTYPE_VARIABLE_DATUM_IDS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_DATUM_IDS,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_VARIABLE_PARAMETERS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VP_TYPE,
                &parserNodes[parserIndex].ettVar);
            break;
        case DIS_FIELDTYPE_VARIABLE_RECORDS:
            parserNodes[parserIndex].children = createSubtree(
                DIS_FIELDS_VR_TYPE,
                &parserNodes[parserIndex].ettVar);
            break;
        default:
            break;
        }
        ++parserIndex;
    }
}

/* Parse packet data based on a specified array of DIS_ParserNodes.
 */
gint parseFields(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNodes[])
{
    guint        fieldIndex     = 0;
    guint        fieldRepeatLen = 0;
    guint64      uintVal        = 0;
    proto_item  *pi             = NULL;
    proto_tree  *sub_tree       = NULL;
    tvbuff_t    *newtvb         = NULL;
    gint         length         = 0;
    guint16 spread_spectrum     = 0;


    /* Get the length while ensuring there's at least one byte for us to
     * decode (if not, throw an exception so as to prevent very long loops).
     */
    length = tvb_ensure_length_remaining(tvb, offset+1);

    while ((parserNodes[fieldIndex].fieldType != DIS_FIELDTYPE_END)
            && (length > 0 ) )
    {
        proto_item *newField = 0;

        fieldRepeatLen = (guint) ((parserNodes[fieldIndex].fieldRepeatLen > 1) ?
            parserNodes[fieldIndex].fieldRepeatLen : 1);

        switch(parserNodes[fieldIndex].fieldType)
        {
        /* basic numeric types */
        case DIS_FIELDTYPE_INT8:
            offset = parseField_Int(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_INT16:
            offset = parseField_Int(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;
        case DIS_FIELDTYPE_INT32:
            offset = parseField_Int(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_INT64:
            offset = parseField_Int(tvb, tree, offset,
                parserNodes[fieldIndex], 8);
            break;
        case DIS_FIELDTYPE_UINT8:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_UINT16:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;
        case DIS_FIELDTYPE_UINT32:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_UINT64:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 8);
            break;
        case DIS_FIELDTYPE_FLOAT32:
            offset = parseField_Float(tvb, tree, offset,
                parserNodes[fieldIndex]);
            break;
        case DIS_FIELDTYPE_FLOAT64:
            offset = parseField_Double(tvb, tree, offset,
                parserNodes[fieldIndex]);
            break;
        case DIS_FIELDTYPE_EXERCISE_ID:
            proto_tree_add_item(tree, hf_dis_exercise_id, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_NUM_ARTICULATION_PARAMS:
            uintVal = tvb_get_guint8(tvb, offset);
            proto_tree_add_item(tree, hf_dis_num_art_params, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            break;
        case DIS_FIELDTYPE_PDU_LENGTH:
            proto_tree_add_item(tree, hf_dis_pdu_length, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_SITE:
            proto_tree_add_item(tree, hf_dis_entity_id_site, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_APPLICATION:
            proto_tree_add_item(tree, hf_dis_entity_id_application, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_ENTITY:
            proto_tree_add_item(tree, hf_dis_entity_id_entity, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_RADIO_ID:
            uintVal = tvb_get_ntohs(tvb, offset);
            proto_tree_add_item(tree, hf_dis_radio_id, tvb, offset, 2, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;
        case DIS_FIELDTYPE_ENCODING_SCHEME:
            uintVal = tvb_get_ntohs(tvb, offset);
            pi = proto_tree_add_item(tree, hf_dis_ens, tvb, offset, 2, ENC_BIG_ENDIAN);
            sub_tree = proto_item_add_subtree(pi, ett_dis_ens);
            proto_tree_add_item(sub_tree, hf_dis_ens_class, tvb, offset, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item(sub_tree, hf_dis_ens_type, tvb, offset, 2, ENC_BIG_ENDIAN);
            proto_item_set_end(pi, tvb, offset);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;
        case DIS_FIELDTYPE_TDL_TYPE:
            proto_tree_add_item(tree, hf_dis_tdl_type, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_SAMPLE_RATE:
            proto_tree_add_item(tree, hf_dis_sample_rate, tvb, offset, 4, ENC_BIG_ENDIAN);
            offset += 4;
            break;
        case DIS_FIELDTYPE_DATA_LENGTH:
            proto_tree_add_item(tree, hf_dis_data_length, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_NUMBER_OF_SAMPLES:
            uintVal = tvb_get_ntohs(tvb, offset);
            proto_tree_add_item(tree, hf_dis_num_of_samples, tvb, offset, 2, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;

        case DIS_FIELDTYPE_RADIO_DATA:
            newtvb = tvb_new_subset_remaining(tvb, offset);
            proto_tree_add_item(tree, hf_dis_signal_data, newtvb, 0, -1, ENC_NA );
            /* ****ck******* need to look for padding bytes */
            break;
        case DIS_FIELDTYPE_RADIO_CATEGORY:
            proto_tree_add_item(tree, hf_dis_radio_category, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_NOMENCLATURE_VERSION:
            proto_tree_add_item(tree, hf_dis_nomenclature_version, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_NOMENCLATURE:
            proto_tree_add_item(tree, hf_dis_nomenclature, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_RADIO_TRANSMIT_STATE:
            uintVal = tvb_get_guint8(tvb, offset);
            proto_tree_add_item(tree, hf_dis_radio_transmit_state, tvb, offset, 1, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 1;
            break;
        case DIS_FIELDTYPE_RADIO_INPUT_SOURCE:
            proto_tree_add_item(tree, hf_dis_radio_input_source, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case  DIS_FIELDTYPE_ANTENNA_PATTERN_TYPE:
            uintVal = tvb_get_ntohs(tvb, offset);
            proto_tree_add_item(tree, hf_dis_antenna_pattern_type, tvb, offset, 2, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;
        case DIS_FIELDTYPE_ANTENNA_PATTERN_LENGTH:
            proto_tree_add_item(tree, hf_dis_antenna_pattern_length, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
         case DIS_FIELDTYPE_TRANSMIT_FREQUENCY:
            proto_tree_add_item(tree, hf_dis_transmit_frequency, tvb, offset, 8, ENC_BIG_ENDIAN);
            offset += 8;
            break;
        case  DIS_FIELDTYPE_SPREAD_SPECTRUM:
            spread_spectrum = tvb_get_ntohs(tvb, offset);
            proto_tree_add_boolean(tree, hf_dis_spread_spectrum_usage, tvb, offset,  2, spread_spectrum);
            proto_tree_add_boolean(tree, hf_dis_frequency_hopping, tvb, offset,  2, spread_spectrum);
            proto_tree_add_boolean(tree, hf_dis_pseudo_noise_modulation, tvb, offset,  2, spread_spectrum);
            proto_tree_add_boolean(tree, hf_dis_time_hopping, tvb, offset,  2, spread_spectrum);
            offset += 2;
            break;
        case DIS_FIELDTYPE_MODULATION_MAJOR:
            uintVal = tvb_get_ntohs(tvb, offset);
            proto_tree_add_item(tree, hf_dis_modulation_major, tvb, offset, 2, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;
        case DIS_FIELDTYPE_MODULATION_SYSTEM:
            uintVal = tvb_get_ntohs(tvb, offset);
            proto_tree_add_item(tree, hf_dis_modulation_system, tvb, offset, 2, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 2;
            break;
        case DIS_FIELDTYPE_CRYPTO_SYSTEM:
            proto_tree_add_item(tree, hf_dis_crypto_system, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_CRYPTO_KEY_ID:
            pi = proto_tree_add_item(tree, hf_dis_crypto_key, tvb, offset, 2, ENC_BIG_ENDIAN);
            sub_tree = proto_item_add_subtree(pi, ett_dis_crypto_key);
            proto_tree_add_item(sub_tree, hf_dis_encryption_mode, tvb, offset, 2, ENC_BIG_ENDIAN);
            proto_tree_add_item(sub_tree, hf_dis_key_identifier, tvb, offset, 2, ENC_BIG_ENDIAN);
            proto_item_set_end(pi, tvb, offset);
            offset += 2;
            break;
        case DIS_FIELDTYPE_MODULATION_PARAMETER_LENGTH:
            uintVal = tvb_get_guint8(tvb, offset);
            proto_tree_add_item(tree, hf_dis_modulation_parameter_length, tvb, offset, 1, ENC_BIG_ENDIAN);
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            offset += 1;
            break;
        case DIS_FIELDTYPE_FH_NETWORK_ID:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_net_id, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_FH_SET_ID:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_set_id, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_LO_SET_ID:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_lo_set_id, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_FH_MSG_START:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_msg_start, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_RESERVED:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_FH_SYNC_TIME_OFFSET:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_sync_time_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
            offset += 4;
            break;
        case DIS_FIELDTYPE_FH_SECURITY_KEY:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_security_key, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;
            break;
        case DIS_FIELDTYPE_FH_CLEAR_CHANNEL:
            proto_tree_add_item(tree, hf_dis_mod_param_fh_clear_channel, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_TS_ALLOCATION_MODE:
            proto_tree_add_item(tree, hf_dis_mod_param_ts_allocation_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_TRANSMITTER_PRIMARY_MODE:
            proto_tree_add_item(tree, hf_dis_mod_param_transmitter_prim_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_TRANSMITTER_SECONDARY_MODE:
            proto_tree_add_item(tree, hf_dis_mod_param_transmitter_second_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_JTIDS_SYNC_STATE:
            proto_tree_add_item(tree, hf_dis_mod_param_sync_state, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case DIS_FIELDTYPE_NETWORK_SYNC_ID:
            proto_tree_add_item(tree, hf_dis_mod_param_network_sync_id, tvb, offset, 4, ENC_BIG_ENDIAN);
            offset += 4;
            break;
        case DIS_FIELDTYPE_MODULATION_PARAMETERS:
            /* need to check to see if mod parms length > 0 */
            /* could get here when there are antenna pattern parameter but no mod params */
            if (modulationParamLength > 0 ) { /* we do have a mod param */
                if (systemModulation == DIS_SYSTEM_MOD_CCTT_SINCGARS)
                {
                    pi = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                                             parserNodes[fieldIndex].fieldLabel);
                    sub_tree = proto_item_add_subtree(pi, parserNodes[fieldIndex].ettVar);
                    offset = parseFields(tvb, sub_tree, offset, DIS_FIELDS_MOD_PARAMS_CCTT_SINCGARS);
                    proto_item_set_end(pi, tvb, offset);
                    break;
                }
                else if (systemModulation == DIS_SYSTEM_MOD_JTIDS_MIDS) {
                    pi = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                                             parserNodes[fieldIndex].fieldLabel);
                    sub_tree = proto_item_add_subtree(pi, parserNodes[fieldIndex].ettVar);
                    offset = parseFields(tvb, sub_tree, offset, DIS_FIELDS_MOD_PARAMS_JTIDS_MIDS);
                    proto_item_set_end(pi, tvb, offset);
                    break;
                }
                else {  /* just dump what is available */
                    newtvb = tvb_new_subset(tvb, offset,modulationParamLength, modulationParamLength);
                    proto_tree_add_item(tree, hf_dis_mod_param_dump, newtvb, 0, -1, ENC_NA );
                    offset += modulationParamLength;
                    break;
                }
            } /* else, leave offset alone, and then check antenna pattern param field */
            break;
        case DIS_FIELDTYPE_ANTENNA_PATTERN_PARAMETERS:
            /* just dump the bytes for now.  Need to do finish */
            newtvb = tvb_new_subset_remaining(tvb, offset);
            proto_tree_add_item(tree, hf_dis_antenna_pattern_parameter_dump, newtvb, 0, -1, ENC_NA );
            break;


        /* padding */
        case DIS_FIELDTYPE_PAD8:
            offset = parseField_Pad(tvb, tree, offset,
                parserNodes[fieldIndex], 1 * fieldRepeatLen);
            break;
        case DIS_FIELDTYPE_PAD16:
            offset = parseField_Pad(tvb, tree, offset,
                parserNodes[fieldIndex], 2 * fieldRepeatLen);
            break;
        case DIS_FIELDTYPE_PAD24:
            offset = parseField_Pad(tvb, tree, offset,
                parserNodes[fieldIndex], 3 * fieldRepeatLen);
            break;
        case DIS_FIELDTYPE_PAD32:
            offset = parseField_Pad(tvb, tree, offset,
                parserNodes[fieldIndex], 4 * fieldRepeatLen);
            break;

        /* enumerations (1-byte) */
        case DIS_FIELDTYPE_APPLICATION_GENERAL_STATUS:
        case DIS_FIELDTYPE_CATEGORY:
        case DIS_FIELDTYPE_CONTROL_ID:
        case DIS_FIELDTYPE_DETONATION_RESULT:
        case DIS_FIELDTYPE_DOMAIN:
        case DIS_FIELDTYPE_ENTITY_KIND:
        case DIS_FIELDTYPE_FROZEN_BEHAVIOR:
        case DIS_FIELDTYPE_PARAMETER_TYPE_DESIGNATOR:
        case DIS_FIELDTYPE_PDU_TYPE:
        case DIS_FIELDTYPE_PROTOCOL_FAMILY:
        case DIS_FIELDTYPE_PROTOCOL_VERSION:
        case DIS_FIELDTYPE_REASON:
        case DIS_FIELDTYPE_REQUIRED_RELIABILITY_SERVICE:
        case DIS_FIELDTYPE_PERSISTENT_OBJECT_CLASS:
        case DIS_FIELDTYPE_PERSISTENT_OBJECT_TYPE:
        case DIS_FIELDTYPE_EMISSION_FUNCTION:
        case DIS_FIELDTYPE_BEAM_FUNCTION:
            offset = parseField_Enum(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;

        /* enumerations (2-bytes) */
        case DIS_FIELDTYPE_ACKNOWLEDGE_FLAG:
        case DIS_FIELDTYPE_APPLICATION_STATUS_TYPE:
        case DIS_FIELDTYPE_APPLICATION_TYPE:
        case DIS_FIELDTYPE_RESPONSE_FLAG:
        case DIS_FIELDTYPE_MODULATION_DETAIL:
        case DIS_FIELDTYPE_EMITTER_NAME:
            offset = parseField_Enum(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;

        /* enumerations (4-bytes) */
        case DIS_FIELDTYPE_ACTION_ID:
        case DIS_FIELDTYPE_REQUEST_STATUS:
            offset = parseField_Enum(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;

        /* other atomic types */
        case DIS_FIELDTYPE_APPEARANCE:
            {
                proto_item *newSubtree;
                newField = proto_tree_add_text(tree, tvb, offset, 4, "%s",
                    parserNodes[fieldIndex].fieldLabel);
                newSubtree = proto_item_add_subtree(newField,
                    parserNodes[fieldIndex].ettVar);
                offset = parseField_Bitmask(tvb, newSubtree, offset,
                    parserNodes[fieldIndex], 4);
            }
            break;
        case DIS_FIELDTYPE_ARTIC_PARAM_TYPE:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_CAPABILITIES:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_COUNTRY:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;
        case DIS_FIELDTYPE_DATUM_ID:
        case DIS_FIELDTYPE_DATUM_LENGTH:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_DEAD_RECKONING_PARAMS:
            /* This is really a struct... needs a field parser.
             * For now, just skip the 12 bytes.
             */
            offset = parseField_Bytes(tvb, tree, offset,
                parserNodes[fieldIndex], 40);
            break;
        case DIS_FIELDTYPE_ENTITY_MARKING:
            /* This is really a struct... needs a field parser.
             * For now, just skip the 12 bytes.
             */
            offset = parseField_Bytes(tvb, tree, offset,
                parserNodes[fieldIndex], 12);
            break;
        case DIS_FIELDTYPE_EXTRA:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_FIXED_DATUM_VALUE:
            offset = parseField_Bytes(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_FIXED_LEN_STR:
            offset = parseField_Bytes(tvb, tree, offset,
                parserNodes[fieldIndex],
                parserNodes[fieldIndex].fieldRepeatLen);
            break;
        case DIS_FIELDTYPE_FORCE_ID:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_FUSE:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;
        case DIS_FIELDTYPE_NUM_FIXED_DATA:
        case DIS_FIELDTYPE_NUM_VARIABLE_DATA:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_REQUEST_ID:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_SPECIFIC:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_SUBCATEGORY:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 1);
            break;
        case DIS_FIELDTYPE_TIME_INTERVAL:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 4);
            break;
        case DIS_FIELDTYPE_TIMESTAMP:
            offset = parseField_Timestamp(tvb, tree, offset,
                parserNodes[fieldIndex]);
            break;
        case DIS_FIELDTYPE_WARHEAD:
            offset = parseField_UInt(tvb, tree, offset,
                parserNodes[fieldIndex], 2);
            break;

        /* composite types */
        case DIS_FIELDTYPE_BURST_DESCRIPTOR:
        case DIS_FIELDTYPE_CLOCK_TIME:
        case DIS_FIELDTYPE_ENTITY_ID:
        case DIS_FIELDTYPE_ENTITY_TYPE:
        case DIS_FIELDTYPE_RADIO_ENTITY_TYPE:
        case DIS_FIELDTYPE_ANTENNA_LOCATION:
        case DIS_FIELDTYPE_REL_ANTENNA_LOCATON:
        case DIS_FIELDTYPE_EVENT_ID:
        case DIS_FIELDTYPE_LINEAR_VELOCITY:
        case DIS_FIELDTYPE_LOCATION_ENTITY:
        case DIS_FIELDTYPE_LOCATION_WORLD:
        case DIS_FIELDTYPE_ORIENTATION:
        case DIS_FIELDTYPE_SIMULATION_ADDRESS:
        case DIS_FIELDTYPE_VECTOR_32:
        case DIS_FIELDTYPE_VECTOR_64:
        case DIS_FIELDTYPE_MODULATION_TYPE:
        case DIS_FIELDTYPE_EMITTER_SYSTEM:
        case DIS_FIELDTYPE_FUNDAMENTAL_PARAMETER_DATA:
        case DIS_FIELDTYPE_UA_EMITTER_SYSTEM:
        case DIS_FIELDTYPE_UA_BEAM_FUNDAMENTAL_PARAMETER_DATA:
            newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                parserNodes[fieldIndex].fieldLabel);
            if (parserNodes[fieldIndex].children != 0)
            {
                proto_item *newSubtree = proto_item_add_subtree(newField,
                    parserNodes[fieldIndex].ettVar);
                offset = parseFields(tvb, newSubtree, offset,
                    parserNodes[fieldIndex].children);
            }
            proto_item_set_end(newField, tvb, offset);
            break;
        case DIS_FIELDTYPE_VARIABLE_DATUM_VALUE:
            {
                guint lengthInBytes;
                lengthInBytes = variableDatumLength / 8;
                if (variableDatumLength % 8 > 0)
                {
                    lengthInBytes += (8 - (variableDatumLength % 8));
                }
                offset = parseField_Bytes(tvb, tree, offset,
                    parserNodes[fieldIndex], lengthInBytes);
            }
            break;

        /* arrays */
        case DIS_FIELDTYPE_FIXED_DATUMS:
            {
                guint i;
                if (numFixed > INT32_MAX)
                {
                    numFixed = INT32_MAX;
                }

                for (i = 0; i < numFixed; ++i)
                {
                    proto_item *newSubtree;

                    /* is remaining length large enough for another fixed datum (ID & value) */
                    /* XXX is this really necessary? */
                    tvb_ensure_length_remaining(tvb, offset+8);

                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                                                   parserNodes[fieldIndex].fieldLabel);
                    newSubtree = proto_item_add_subtree(newField, ettFixedData);
                    offset = parseFields (tvb, newSubtree, offset,
                         parserNodes[fieldIndex].children);
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_FIXED_DATUM_IDS:
            if (numFixed > 0)
            {
                guint       i;
                proto_item *newSubtree;

                newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                    parserNodes[fieldIndex].fieldLabel);
                newSubtree = proto_item_add_subtree(newField, ettFixedData);

                if (numFixed > INT32_MAX)
                {
                    numFixed = INT32_MAX;
                }

                for (i = 0; i < numFixed; ++i)
                {
                    /* is remaining length large enough for another fixed datum ID (32 bit int) */
                    /* XXX is this really necessary? */
                    tvb_ensure_length_remaining(tvb, offset+4);
                    offset = parseFields (tvb, newSubtree, offset,
                        parserNodes[fieldIndex].children);
                }
                proto_item_set_end(newField, tvb, offset);
            }
            break;
        case DIS_FIELDTYPE_VARIABLE_DATUMS:
            {
                guint i;
                if (numVariable > INT32_MAX)
                {
                    numVariable = INT32_MAX;
                }

                for (i = 0; i < numVariable; ++i)
                {
                    proto_item *newSubtree;
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                        parserNodes[fieldIndex].fieldLabel);
                    newSubtree = proto_item_add_subtree
                        (newField, ettVariableData);
                    offset = parseFields
                        (tvb, newSubtree, offset,
                         parserNodes[fieldIndex].children);
                    proto_item_set_end(newField, tvb, offset);
                }

            }
            break;
        case DIS_FIELDTYPE_VARIABLE_DATUM_IDS:
            if (numVariable > 0)
            {
                guint       i;
                proto_item *newSubtree;

                newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                    parserNodes[fieldIndex].fieldLabel);
                newSubtree = proto_item_add_subtree(newField, ettVariableData);

                if (numVariable > INT32_MAX)
                {
                    numVariable = INT32_MAX;
                }

                for (i = 0; i < numVariable; ++i)
                {
                    offset = parseFields
                        (tvb, newSubtree, offset,
                         parserNodes[fieldIndex].children);
                }
                proto_item_set_end(newField, tvb, offset);
            }
            break;
        case DIS_FIELDTYPE_VARIABLE_PARAMETERS:
            {
                guint i;

                if (numVariable > DIS_PDU_MAX_VARIABLE_PARAMETERS)
                {
                    numVariable = DIS_PDU_MAX_VARIABLE_PARAMETERS;
                }

                for (i = 0; i < numVariable; ++i)
                {
                    proto_item *newSubtree;
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                        parserNodes[fieldIndex].fieldLabel);
                    newSubtree = proto_item_add_subtree(newField,
                        ettVariableParameters[i]);
                    offset = parseFields
                        (tvb, newSubtree, offset,
                         parserNodes[fieldIndex].children);
                    offset = parseField_VariableParameter
                        (tvb, newSubtree, offset);
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_VARIABLE_RECORDS:
            {
                guint i;

                if (numVariable > DIS_PDU_MAX_VARIABLE_RECORDS)
                {
                    numVariable = DIS_PDU_MAX_VARIABLE_RECORDS;
                }

                for (i = 0; i < numVariable; ++i)
                {
                    proto_item *newSubtree;
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                                                   parserNodes[fieldIndex].fieldLabel);
                    newSubtree = proto_item_add_subtree(newField,
                                                        ettVariableRecords[i]);
                    offset = parseFields
                        (tvb, newSubtree, offset,
                         parserNodes[fieldIndex].children);
                    offset = parseField_VariableRecord
                        (tvb, newSubtree, offset);
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_ELECTROMAGNETIC_EMISSION_SYSTEM_BEAM:
            {
                guint i;

                for (i = 0; i < numBeams; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                        parserNodes[fieldIndex].fieldLabel);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_TRACK_JAM:
            {
                guint i;

                for (i = 0; i < numTrackJamTargets; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                        parserNodes[fieldIndex].fieldLabel);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_NUM_ELECTROMAGNETIC_EMISSION_SYSTEMS:
            uintVal = tvb_get_guint8(tvb, offset);
            proto_tree_add_item(tree, hf_dis_num_electromagnetic_emission_systems, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            break;
        case DIS_FIELDTYPE_ELECTROMAGNETIC_EMISSION_SYSTEM:
            {
                guint i;

                if (numVariable > DIS_PDU_MAX_ELECTROMAGNETIC_EMISSION_SYSTEMS)
                {
                    numVariable = DIS_PDU_MAX_ELECTROMAGNETIC_EMISSION_SYSTEMS;
                }

                for (i = 0; i < numVariable; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s",
                        parserNodes[fieldIndex].fieldLabel);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_NUM_OF_SHAFTS:
            {
                uintVal = tvb_get_guint8(tvb, offset);
                proto_tree_add_item(tree, hf_dis_num_shafts, tvb, offset, 1, ENC_BIG_ENDIAN);
                offset += 1;
                *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            }
            break;
        case DIS_FIELDTYPE_SHAFTS:
            {
                guint i;

                if (numShafts > DIS_PDU_MAX_SHAFTS)
                {
                    numShafts = DIS_PDU_MAX_SHAFTS;
                }

                for (i = 0; i < numShafts; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s [%d of %d]",
                                                   parserNodes[fieldIndex].fieldLabel, i+1, numShafts);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_NUM_OF_APAS:
            {
                uintVal = tvb_get_guint8(tvb, offset);
                proto_tree_add_item(tree, hf_dis_num_apas, tvb, offset, 1, ENC_BIG_ENDIAN);
                offset += 1;
                *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            }
            break;
        case DIS_FIELDTYPE_APA:
            {
                guint i;

                if (numApas > DIS_PDU_MAX_APAS)
                {
                    numApas = DIS_PDU_MAX_APAS;
                }

                for (i = 0; i < numApas; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s [%d of %d]",
                                                   parserNodes[fieldIndex].fieldLabel, i+1, numApas);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_NUM_OF_UA_EMITTER_SYSTEMS:
            {
                uintVal = tvb_get_guint8(tvb, offset);
                proto_tree_add_item(tree, hf_dis_num_ua_emitter_systems, tvb, offset, 1, ENC_BIG_ENDIAN);
                offset += 1;
                *(parserNodes[fieldIndex].outputVar) = (guint32)uintVal;
            }
            break;
        case DIS_FIELDTYPE_NUM_OF_UA_EMITTER_SYSTEM_BEAMS:
            {
                uintVal = tvb_get_guint8(tvb, offset);
                offset  = parseField_UInt(tvb, tree, offset, parserNodes[fieldIndex], 1);
                numUABeams += (guint32)uintVal;
            }
            break;
        case DIS_FIELDTYPE_UA_EMITTER_SYSTEMS:
            {
                guint i;

                if (numUAEmitter > DIS_PDU_MAX_UA_EMITTER_SYSTEMS)
                {
                    numUAEmitter = DIS_PDU_MAX_UA_EMITTER_SYSTEMS;
                }

                for (i = 0; i < numUAEmitter; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s [%d of %d]",
                                                   parserNodes[fieldIndex].fieldLabel, i+1, numUAEmitter);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
            }
            break;
        case DIS_FIELDTYPE_UA_BEAMS:
            {
                guint i;

                if (numUABeams > DIS_PDU_MAX_UA_BEAMS)
                {
                    numUABeams = DIS_PDU_MAX_UA_BEAMS;
                }

                for (i = 0; i < numUABeams; ++i)
                {
                    newField = proto_tree_add_text(tree, tvb, offset, -1, "%s [%d of %d]",
                                                   parserNodes[fieldIndex].fieldLabel, i+1, numUABeams);
                    if (parserNodes[fieldIndex].children != 0)
                    {
                        proto_item *newSubtree =
                            proto_item_add_subtree(newField,
                            parserNodes[fieldIndex].ettVar);
                        offset = parseFields(tvb, newSubtree, offset,
                            parserNodes[fieldIndex].children);
                    }
                    proto_item_set_end(newField, tvb, offset);
                }
                numUABeams = 0; /* reset beam count for this pdu */
            }
            break;
        default:
            break;
        }

        ++fieldIndex;
        length = tvb_length_remaining(tvb, offset);
    }

    return offset;
}
