Logo Search packages:      
Sourcecode: wireshark version File versions  Download package

sigcomp-udvm.c

/* sigcomp-udvm.c
 * Routines making up the Universal Decompressor Virtual Machine (UDVM) used for
 * Signaling Compression (SigComp) dissection.
 * Copyright 2004, Anders Broman <anders.broman@ericsson.com>
 *
 * $Id: sigcomp-udvm.c 21253 2007-03-28 21:55:11Z sfisher $
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * References:
 * http://www.ietf.org/rfc/rfc3320.txt?number=3320
 * http://www.ietf.org/rfc/rfc3321.txt?number=3321
 * Useful links :
 * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-05.txt
 * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>

#include "packet.h"
#include "strutil.h"
#include "sigcomp-udvm.h"
#include "sigcomp_state_hdlr.h"
#include "crypt/crypt-sha1.h"
#include "crc16.h"
#include "except.h"

#define     SIGCOMP_INSTR_DECOMPRESSION_FAILURE     0
#define SIGCOMP_INSTR_AND                       1
#define SIGCOMP_INSTR_OR                        2
#define SIGCOMP_INSTR_NOT                       3
#define SIGCOMP_INSTR_LSHIFT                    4
#define SIGCOMP_INSTR_RSHIFT                    5
#define SIGCOMP_INSTR_ADD                       6
#define SIGCOMP_INSTR_SUBTRACT                  7
#define SIGCOMP_INSTR_MULTIPLY                  8
#define SIGCOMP_INSTR_DIVIDE                    9
#define SIGCOMP_INSTR_REMAINDER                 10
#define SIGCOMP_INSTR_SORT_ASCENDING            11
#define SIGCOMP_INSTR_SORT_DESCENDING           12
#define SIGCOMP_INSTR_SHA_1                     13
#define SIGCOMP_INSTR_LOAD                      14
#define SIGCOMP_INSTR_MULTILOAD                 15
#define SIGCOMP_INSTR_PUSH                      16
#define SIGCOMP_INSTR_POP                       17
#define SIGCOMP_INSTR_COPY                      18
#define SIGCOMP_INSTR_COPY_LITERAL              19
#define SIGCOMP_INSTR_COPY_OFFSET               20
#define SIGCOMP_INSTR_MEMSET                    21
#define SIGCOMP_INSTR_JUMP                      22
#define SIGCOMP_INSTR_COMPARE                   23
#define SIGCOMP_INSTR_CALL                      24
#define SIGCOMP_INSTR_RETURN                    25
#define SIGCOMP_INSTR_SWITCH                    26
#define SIGCOMP_INSTR_CRC                       27
#define SIGCOMP_INSTR_INPUT_BYTES               28
#define SIGCOMP_INSTR_INPUT_BITS                29
#define SIGCOMP_INSTR_INPUT_HUFFMAN             30
#define SIGCOMP_INSTR_STATE_ACCESS              31
#define SIGCOMP_INSTR_STATE_CREATE              32
#define SIGCOMP_INSTR_STATE_FREE                33
#define SIGCOMP_INSTR_OUTPUT                    34
#define SIGCOMP_INSTR_END_MESSAGE               35


static gboolean print_level_1;
static gboolean print_level_2;
static gboolean print_level_3;
static gint show_instr_detail_level;

/* Internal result code values of decompression failures */
const value_string result_code_vals[] = {
      { 0,  "No decompression failure" },
      { 1,  "Partial state length less than 6 or greater than 20 bytes long" },
      { 2,  "No state match" },
      { 3,  "state_begin + state_length > size of state" },
      { 4,  "Operand_2 is Zero" },
      { 5,  "Switch statement failed j >= n" },
      { 6,  "Atempt to jump outside of UDVM memory" },
      { 7,  "L in input-bits > 16" },
      { 8,  "input_bit_order > 7" },
      { 9,  "Instruction Decompression failure encountered" },
      {10,  "Input huffman failed j > n" },
      {11,  "Input bits requested beyond end of message" },
      {12,  "more than four state creation requests are made before the END-MESSAGE instruction" },
      {13,  "state_retention_priority is 65535" },
      {14,  "Input bytes requested beond end of message" },
      {15,  "Maximum number of UDVM cycles reached" },
      {16,  "UDVM stack underflow" },
      { 255,      "This branch isn't coded yet" },
      { 0,    NULL }
};

static int decode_udvm_literal_operand(guint8 *buff,guint operand_address, guint16 *value);
static int dissect_udvm_reference_operand(guint8 *buff,guint operand_address, guint16 *value, guint *result_dest);
static int decode_udvm_multitype_operand(guint8 *buff,guint operand_address,guint16 *value);
static int decode_udvm_address_operand(guint8 *buff,guint operand_address, guint16 *value,guint current_address);
static int decomp_dispatch_get_bits(tvbuff_t *message_tvb,proto_tree *udvm_tree,guint8 bit_order,
                  guint8 *buff,guint16 *old_input_bit_order, guint16 *remaining_bits,
                  guint16     *input_bits, guint *input_address, guint16 length, guint16 *result_code,guint msg_end);


tvbuff_t*
decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo,
                                       proto_tree *udvm_tree, gint udvm_mem_dest,
                                       gint print_flags, gint hf_id,
                                       gint header_len,
                                       gint byte_code_state_len, gint byte_code_id_len,
                                       gint udvm_start_ip)
{
      tvbuff_t    *decomp_tvb;
      guint8            buff[UDVM_MEMORY_SIZE];
      char        string[2];
      guint8            *out_buff;        /* Largest allowed size for a message is 65535  */
      guint32           i = 0;
      guint16           n = 0;
      guint16           m = 0;
      guint16           x;
      guint       k = 0;
      guint16           H;
      guint16           oldH;
      guint       offset = 0;
      guint       result_dest;
      guint       code_length =0;
      guint8            current_instruction;
      guint       current_address;
      guint       operand_address;
      guint       input_address;
      guint16           output_address = 0;
      guint       next_operand_address;
      guint8            octet;
      guint8            msb;
      guint8            lsb;
      guint16           byte_copy_right;
      guint16           byte_copy_left;
      guint16           input_bit_order;
      guint16           stack_location;
      guint16           stack_fill;
      guint16           result;
      guint             msg_end = tvb_reported_length_remaining(message_tvb, 0);
      guint16           result_code = 0;
      guint16           old_input_bit_order = 0;
      guint16           remaining_bits = 0;
      guint16           input_bits = 0;
      guint8            bit_order = 0;
      gboolean    outside_huffman_boundaries = TRUE;
      gboolean    print_in_loop = FALSE;
      guint16           instruction_address;
      guint8            no_of_state_create = 0;
      guint16           state_length_buff[5];
      guint16           state_address_buff[5];
      guint16           state_instruction_buff[5];
      guint16           state_minimum_access_length_buff[5];
      guint16           state_state_retention_priority_buff[5];
      guint32           used_udvm_cycles = 0;
      guint       cycles_per_bit;
      guint       maximum_UDVM_cycles;
      guint8            *sha1buff;
      unsigned char sha1_digest_buf[STATE_BUFFER_SIZE];
      sha1_context ctx;


      /* UDVM operand variables */
      guint16 length;
      guint16 at_address;
      guint16 destination;
      guint16 address;
      guint16 value;
      guint16 p_id_start;
      guint16 p_id_length;
      guint16 state_begin;
      guint16 state_length;
      guint16 state_address;
      guint16 state_instruction;
      guint16 operand_1;
      guint16 operand_2;
      guint16 value_1;
      guint16 value_2;
      guint16 at_address_1;
      guint16 at_address_2;
      guint16 at_address_3;
      guint16 j;
      guint16 bits_n;
      guint16 lower_bound_n;
      guint16 upper_bound_n;
      guint16 uncompressed_n;
      guint16 position;
      guint16 ref_destination; /* could I have used $destination ? */
      guint16 multy_offset;
      guint16 output_start;
      guint16 output_length;
      guint16 minimum_access_length;
      guint16 state_retention_priority;
      guint16 requested_feedback_location;
      guint16 returned_parameters_location;
      guint16 start_value;


      /* Set print parameters */
      print_level_1 = FALSE;
      print_level_2 = FALSE;
      print_level_3 = FALSE;
      show_instr_detail_level = 0;



      switch( print_flags ) {
            case 0:
                  break;

            case 1:
                  print_level_1 = TRUE;
                  show_instr_detail_level = 1;
                  break;
            case 2:
                  print_level_1 = TRUE;
                  print_level_2 = TRUE;
                  show_instr_detail_level = 1;
                  break;
            case 3:
                  print_level_1 = TRUE;
                  print_level_2 = TRUE;
                  print_level_3 = TRUE;
                  show_instr_detail_level = 2;
                  break;
            default:
                  print_level_1 = TRUE;
                  show_instr_detail_level = 1;
                  break;
      }





      /* UDVM memory must be initialised to zero */
      memset(buff, 0, UDVM_MEMORY_SIZE);
      /* Set initial UDVM data
       *  The first 32 bytes of UDVM memory are then initialized to special
       *  values as illustrated in Figure 5.
       *
       *                      0             7 8            15
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |       UDVM_memory_size        |  0 - 1
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |        cycles_per_bit         |  2 - 3
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |        SigComp_version        |  4 - 5
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |    partial_state_ID_length    |  6 - 7
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |         state_length          |  8 - 9
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *                     |                               |
       *                     :           reserved            :  10 - 31
       *                     |                               |
       *                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       *
       *            Figure 5: Initializing Useful Values in UDVM memory
       */
      /* UDVM_memory_size  */
      buff[0] = (UDVM_MEMORY_SIZE >> 8) & 0x00FF;
      buff[1] = UDVM_MEMORY_SIZE & 0x00FF;
      /* cycles_per_bit */
      buff[2] = 0;
      buff[3] = 16;
      /* SigComp_version */
      buff[4] = 0;
      buff[5] = 1;
      /* partial_state_ID_length */
      buff[6] = (byte_code_id_len >> 8) & 0x00FF;
      buff[7] = byte_code_id_len & 0x00FF;
      /* state_length  */
      buff[8] = (byte_code_state_len >> 8) & 0x00FF;
      buff[9] = byte_code_state_len & 0x00FF;

      code_length = tvb_reported_length_remaining(bytecode_tvb, 0);

      cycles_per_bit = buff[2] << 8;
      cycles_per_bit = cycles_per_bit | buff[3];
      /*
       * maximum_UDVM_cycles = (8 * n + 1000) * cycles_per_bit
       */
      maximum_UDVM_cycles = (( 8 * (header_len + msg_end) ) + 1000) * cycles_per_bit;

      proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"maximum_UDVM_cycles(%u) = (( 8 * msg_end(%u) ) + 1000) * cycles_per_bit(%u)",maximum_UDVM_cycles,msg_end,cycles_per_bit);
      proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"Message Length: %u,Byte code length: %u, Maximum UDVM cycles: %u",msg_end,code_length,maximum_UDVM_cycles);

      /* Load bytecode into UDVM starting at "udvm_mem_dest" */
      i = udvm_mem_dest;
      if ( print_level_3 )
            proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"Load bytecode into UDVM starting at %u",i);
      while ( code_length > offset && i < UDVM_MEMORY_SIZE ) {
            buff[i] = tvb_get_guint8(bytecode_tvb, offset);
            if ( print_level_3 )
                  proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,
                                    "              Addr: %u Instruction code(0x%0x) ", i, buff[i]);

            i++;
            offset++;

      }
      /* Largest allowed size for a message is 65535  */
      out_buff = g_malloc(65535);
      /* Start executing code */
      current_address = udvm_start_ip;
      input_address = 0;
      operand_address = 0;

      proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"UDVM EXECUTION STARTED at Address: %u Message size %u",
            current_address, msg_end);

execute_next_instruction:

      if ( used_udvm_cycles > maximum_UDVM_cycles ){
            result_code = 15;
            goto decompression_failure;
      }
      current_instruction = buff[current_address];

      switch ( current_instruction ) {
      case SIGCOMP_INSTR_DECOMPRESSION_FAILURE:
            used_udvm_cycles++;
            if ( result_code == 0 )
                  result_code = 9;
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                  "Addr: %u ## DECOMPRESSION-FAILURE(0)",
                  current_address);
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Wireshark UDVM diagnostic: %s.",
                            val_to_str(result_code, result_code_vals,"Unknown (%u)"));
            if ( output_address > 0 ){
                  /* At least something got decompressed, show it */
                  decomp_tvb = tvb_new_real_data(out_buff,output_address,output_address);
                  /* Arrange that the allocated packet data copy be freed when the
                   * tvbuff is freed.
                   */
                  tvb_set_free_cb( decomp_tvb, g_free );
                  /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
                   * were handed refers, so it'll get cleaned up when that tvbuff
                   * is cleaned up.
                   */
                  tvb_set_child_real_data_tvbuff(message_tvb,decomp_tvb);
                  add_new_data_source(pinfo, decomp_tvb, "Decompressed SigComp message(Incomplete)");
                  proto_tree_add_text(udvm_tree, decomp_tvb, 0, -1,"SigComp message Decompression failure");
            return decomp_tvb;
            }
            g_free(out_buff);
            return NULL;
            break;

      case SIGCOMP_INSTR_AND: /* 1 AND ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## AND(1) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## AND (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 & operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_OR: /* 2 OR ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## OR(2) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## OR (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 | operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_NOT: /* 3 NOT ($operand_1) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## NOT(3) ($operand_1)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## NOT (operand_1=%u)",
                        current_address, operand_1);
            }
            /* execute the instruction */
            result = operand_1 ^ 0xffff;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_LSHIFT: /* 4 LSHIFT ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## LSHIFT(4) ($operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## LSHIFT (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 << operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;

            break;
      case SIGCOMP_INSTR_RSHIFT: /* 5 RSHIFT ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## RSHIFT(5) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## RSHIFT (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 >> operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_ADD: /* 6 ADD ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## ADD(6) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## ADD (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 + operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"               Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;

      case SIGCOMP_INSTR_SUBTRACT: /* 7 SUBTRACT ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SUBTRACT(7) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SUBTRACT (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /* execute the instruction */
            result = operand_1 - operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"               Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_MULTIPLY: /* 8 MULTIPLY ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ##MULTIPLY(8) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## MULTIPLY (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /*
             * execute the instruction
             * MULTIPLY (m, n)  := m * n (modulo 2^16)
             */
            if ( operand_2 == 0){
                  result_code = 4;
                  goto decompression_failure;
            }
            result = operand_1 * operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_DIVIDE: /* 9 DIVIDE ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## DIVIDE(9) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## DIVIDE (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /*
             * execute the instruction
             * DIVIDE (m, n)    := floor(m / n)
             * Decompression failure occurs if a DIVIDE or REMAINDER instruction
             * encounters an operand_2 that is zero.
             */
            if ( operand_2 == 0){
                  result_code = 4;
                  goto decompression_failure;
            }
            result = operand_1 / operand_2;
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_REMAINDER: /* 10 REMAINDER ($operand_1, %operand_2) */
            used_udvm_cycles++;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## REMAINDER(10) (operand_1, operand_2)",
                        current_address);
            }
            /* $operand_1*/
            operand_address = current_address + 1;
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_1 %u",
                        operand_address, operand_1);
            }
            operand_address = next_operand_address;
            /* %operand_2*/
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      operand_2 %u",
                        operand_address, operand_2);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## REMAINDER (operand_1=%u, operand_2=%u)",
                        current_address, operand_1, operand_2);
            }
            /*
             * execute the instruction
             * REMAINDER (m, n) := m - n * floor(m / n)
             * Decompression failure occurs if a DIVIDE or REMAINDER instruction
             * encounters an operand_2 that is zero.
             */
            if ( operand_2 == 0){
                  result_code = 4;
                  goto decompression_failure;
            }
            result = operand_1 - operand_2 * (operand_1 / operand_2);
            lsb = result & 0xff;
            msb = result >> 8;
            buff[result_dest] = msb;
            buff[result_dest+1] = lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading result %u at %u",
                        result, result_dest);
            }
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_SORT_ASCENDING: /* 11 SORT-ASCENDING (%start, %n, %k) */
            /*
             *    used_udvm_cycles =  1 + k * (ceiling(log2(k)) + n)
             */
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SORT-ASCENDING(11) (start, n, k))",
                        current_address);
            }
            operand_address = current_address + 1;
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
            /*
             *    used_udvm_cycles =  1 + k * (ceiling(log2(k)) + n)
             */
            break;

      case SIGCOMP_INSTR_SORT_DESCENDING: /* 12 SORT-DESCENDING (%start, %n, %k) */
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SORT-DESCENDING(12) (start, n, k))",
                        current_address);
            }
            operand_address = current_address + 1;
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
            /*
             *    used_udvm_cycles =  1 + k * (ceiling(log2(k)) + n)
             */
            break;
      case SIGCOMP_INSTR_SHA_1: /* 13 SHA-1 (%position, %length, %destination) */
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SHA-1(13) (position, length, destination)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %position */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
                        operand_address, position);
            }
            operand_address = next_operand_address;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;

            /* $destination */
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      $destination %u",
                        operand_address, ref_destination);
            }
            current_address = next_operand_address;
            used_udvm_cycles = used_udvm_cycles + 1 + length;

            n = 0;
            k = position;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];

            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
                              "byte_copy_right = %u", byte_copy_right);
            }

            sha1_starts( &ctx );

            while (n<length) {
                  guint16 handle_now = length;

                  if ( k < byte_copy_right && byte_copy_right <= k + (length-n) ){
                        handle_now = byte_copy_right - position;
                  }

                  if (k + handle_now >= UDVM_MEMORY_SIZE)
                        goto decompression_failure;
                  sha1_update( &ctx, &buff[k], handle_now );

                  k = ( k + handle_now ) & 0xffff;
                  n = ( n + handle_now ) & 0xffff;

                  if ( k >= byte_copy_right ) {
                        k = byte_copy_left;
                  }
            }

            sha1_finish( &ctx, sha1_digest_buf );

            k = ref_destination;

            for ( n=0; n< STATE_BUFFER_SIZE; n++ ) {

                  buff[k] = sha1_digest_buf[n];

                  k = ( k + 1 ) & 0xffff;
                  n++;

                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
            }

            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
                              "Calculated SHA-1: %s",
                              bytes_to_str(sha1_digest_buf, STATE_BUFFER_SIZE));
            }

            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_LOAD: /* 14 LOAD (%address, %value) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## LOAD(14) (%%address, %%value)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %address */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Address %u",
                        operand_address, address);
            }
            operand_address = next_operand_address;
            /* %value */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## LOAD (%%address=%u, %%value=%u)",
                        current_address, address, value);
            }
            lsb = value & 0xff;
            msb = value >> 8;

            buff[address] = msb;
            buff[address + 1] = lsb;

            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                        operand_address, value);
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"     Loading bytes at %u Value %u 0x%x",
                              address, value, value);
            }
            used_udvm_cycles++;
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_MULTILOAD: /* 15 MULTILOAD (%address, #n, %value_0, ..., %value_n-1) */
            /* RFC 3320:
             * The MULTILOAD instruction sets a contiguous block of 2-byte words in
             * the UDVM memory to specified values.
             * Hmm what if the value to load only takes one byte ? Chose to always load two bytes.
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## MULTILOAD(15) (%%address, #n, value_0, ..., value_n-1)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %address */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Address %u",
                        operand_address, address);
            }
            operand_address = next_operand_address;

            /* #n */
            next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      n %u",
                        operand_address, n);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## MULTILOAD (%%address=%u, #n=%u, value_0, ..., value_%d)",
                        current_address, address, n, n-1);
            }
            operand_address = next_operand_address;
            used_udvm_cycles = used_udvm_cycles + 1 + n;
            while ( n > 0) {
                  n = n - 1;
                  /* %value */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
                  lsb = value & 0xff;
                  msb = value >> 8;

                  if (address >= UDVM_MEMORY_SIZE - 1)
                        goto decompression_failure;

                  buff[address] = msb;
                  buff[address + 1] = lsb;
                  /* debug
                  */
                  length = next_operand_address - operand_address;

                  if (print_level_1 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1, "Addr: %u      Value %5u      - Loading bytes at %5u Value %5u 0x%x",
                        operand_address, value, address, value, value);
                  }
                  address = address + 2;
                  operand_address = next_operand_address;
            }
            current_address = next_operand_address;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_PUSH: /* 16 PUSH (%value) */
            if (show_instr_detail_level == 2){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## PUSH(16) (value)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %value */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
            if (show_instr_detail_level == 2){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                        operand_address, value);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## PUSH (value=%u)",
                        current_address, value);
            }
            current_address = next_operand_address;

            /* Push the value address onto the stack */
            stack_location = (buff[70] << 8) | buff[71];
            stack_fill = (buff[stack_location] << 8)
                     | buff[(stack_location+1) & 0xFFFF];
            address = (stack_location + stack_fill * 2 + 2) & 0xFFFF;

            if (address >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;

            buff[address] = (value >> 8) & 0x00FF;
            buff[(address+1) & 0xFFFF] = value & 0x00FF;

            if (stack_location >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;

            stack_fill = (stack_fill + 1) & 0xFFFF;
            buff[stack_location] = (stack_fill >> 8) & 0x00FF;
            buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;

            used_udvm_cycles++;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_POP: /* 17 POP (%address) */
            if (show_instr_detail_level == 2){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## POP(16) (value)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %value */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
            if (show_instr_detail_level == 2){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                        operand_address, destination);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## POP (address=%u)",
                        current_address, destination);
            }
            current_address = next_operand_address;

            /* Pop value from the top of the stack */
            stack_location = (buff[70] << 8) | buff[71];
            stack_fill = (buff[stack_location] << 8)
                     | buff[(stack_location+1) & 0xFFFF];
            if (stack_fill == 0)
            {
                result_code = 16;
                goto decompression_failure;
            }

            if (stack_location >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;

            stack_fill = (stack_fill - 1) & 0xFFFF;
            buff[stack_location] = (stack_fill >> 8) & 0x00FF;
            buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;

            address = (stack_location + stack_fill * 2 + 2) & 0xFFFF;

            if (address >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;

            value = (buff[address] << 8)
                     | buff[(address+1) & 0xFFFF];

            /* ... and store the popped value. */
            if (destination >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;
            buff[destination] = (value >> 8) & 0x00FF;
            buff[(destination+1) & 0xFFFF] = value & 0x00FF;

            used_udvm_cycles++;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_COPY: /* 18 COPY (%position, %length, %destination) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY(18) (position, length, destination)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %position */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
                        operand_address, position);
            }
            operand_address = next_operand_address;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;

            /* %destination */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                        operand_address, destination);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY (position=%u, length=%u, destination=%u)",
                        current_address, position, length, destination);
            }
            current_address = next_operand_address;
            /*
             * 8.4.  Byte copying
             * :
             * The string of bytes is copied in ascending order of memory address,
             * respecting the bounds set by byte_copy_left and byte_copy_right.
             * More precisely, if a byte is copied from/to Address m then the next
             * byte is copied from/to Address n where n is calculated as follows:
             *
             * Set k := m + 1 (modulo 2^16)
             * If k = byte_copy_right then set n := byte_copy_left, else set n := k
             *
             */

            n = 0;
            k = destination;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                                    "               byte_copy_right = %u", byte_copy_right);
            }

            while ( n < length ){
                  buff[k] = buff[position];
                  if (print_level_2 ){
                        proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               Copying value: %u (0x%x) to Addr: %u",
                              buff[position], buff[position], k);
                  }
                  position = ( position + 1 ) & 0xffff;
                  k = ( k + 1 ) & 0xffff;
                  n++;

                  /*
                   * Check for circular buffer wrapping after the positions are
                   * incremented. If either started at BCR then they should continue
                   * to increment beyond BCR.
                   */
                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  if ( position == byte_copy_right ){
                        position = byte_copy_left;
                  }
            }
            used_udvm_cycles = used_udvm_cycles + 1 + length;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_COPY_LITERAL: /* 19 COPY-LITERAL (%position, %length, $destination) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY-LITERAL(19) (position, length, $destination)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %position */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
                        operand_address, position);
            }
            operand_address = next_operand_address;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;


            /* $destination */
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      destination %u",
                        operand_address, ref_destination);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY-LITERAL (position=%u, length=%u, $destination=%u)",
                        current_address, position, length, destination);
            }
            current_address = next_operand_address;


            /*
             * 8.4.  Byte copying
             * :
             * The string of bytes is copied in ascending order of memory address,
             * respecting the bounds set by byte_copy_left and byte_copy_right.
             * More precisely, if a byte is copied from/to Address m then the next
             * byte is copied from/to Address n where n is calculated as follows:
             *
             * Set k := m + 1 (modulo 2^16)
             * If k = byte_copy_right then set n := byte_copy_left, else set n := k
             *
             */

            n = 0;
            k = ref_destination;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_right = %u", byte_copy_right);
            }
            while ( n < length ){

                  buff[k] = buff[position];
                  if (print_level_2 ){
                        proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               Copying value: %u (0x%x) to Addr: %u",
                              buff[position], buff[position], k);
                  }
                  position = ( position + 1 ) & 0xffff;
                  k = ( k + 1 ) & 0xffff;
                  n++;

                  /*
                   * Check for circular buffer wrapping after the positions are
                   * incremented. It is important that k cannot be left set
                   * to BCR. Also, if either started at BCR then they should continue
                   * to increment beyond BCR.
                   */
                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  if ( position == byte_copy_right ){
                        position = byte_copy_left;
                  }
            }
            buff[result_dest] = k >> 8;
            buff[result_dest + 1] = k & 0x00ff;

            used_udvm_cycles = used_udvm_cycles + 1 + length;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_COPY_OFFSET: /* 20 COPY-OFFSET (%offset, %length, $destination) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY-OFFSET(20) (offset, length, $destination)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %offset */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      offset %u",
                        operand_address, multy_offset);
            }
            operand_address = next_operand_address;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;


            /* $destination */
            next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      $destination %u",
                        operand_address, ref_destination);
            }

            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COPY-OFFSET (offset=%u, length=%u, $destination=%u)",
                        current_address, multy_offset, length, result_dest);
            }
            current_address = next_operand_address;

            /* Execute the instruction:
             * To derive the value of the position operand, starting at the memory
             * address specified by destination, the UDVM counts backwards a total
             * of offset memory addresses.
             *
             * If the memory address specified in byte_copy_left is reached, the
             * next memory address is taken to be (byte_copy_right - 1) modulo 2^16.
             */
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];

            /*
             * In order to work out the position, simple arithmetic is tricky
             * to apply because there some nasty corner cases. A simple loop
             * is inefficient but the logic is simple.
             *
             * FUTURE: This could be optimised.
             */
            for (position = ref_destination, i = 0; i < multy_offset; i++)
            {
                  if ( position == byte_copy_left )
                  {
                        position = (byte_copy_right - 1) & 0xffff;
                  }
                  else
                  {
                        position = (position - 1) & 0xffff;
                  }
            }

            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_left = %u byte_copy_right = %u position= %u",
                              byte_copy_left, byte_copy_right, position);
                  }
            /* The COPY-OFFSET instruction then behaves as a COPY-LITERAL
             * instruction, taking the value of the position operand to be the last
             * memory address reached in the above step.
             */

            /*
             * 8.4.  Byte copying
             * :
             * The string of bytes is copied in ascending order of memory address,
             * respecting the bounds set by byte_copy_left and byte_copy_right.
             * More precisely, if a byte is copied from/to Address m then the next
             * byte is copied from/to Address n where n is calculated as follows:
             *
             * Set k := m + 1 (modulo 2^16)
             * If k = byte_copy_right then set n := byte_copy_left, else set n := k
             *
             */

            n = 0;
            k = ref_destination;
            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_left = %u byte_copy_right = %u", byte_copy_left, byte_copy_right);
            }
            while ( n < length ){
                  buff[k] = buff[position];
                  if (print_level_2 ){
                        proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               Copying value: %5u (0x%x) from Addr: %u to Addr: %u",
                              buff[position], buff[position],(position), k);
                  }
                  n++;
                  k = ( k + 1 ) & 0xffff;
                  position = ( position + 1 ) & 0xffff;

                  /*
                   * Check for circular buffer wrapping after the positions are
                   * incremented. It is important that k cannot be left set
                   * to BCR. Also, if either started at BCR then they should continue
                   * to increment beyond BCR.
                   */
                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  if ( position == byte_copy_right ){
                        position = byte_copy_left;
                  }
            }
            buff[result_dest] = k >> 8;
            buff[result_dest + 1] = k & 0x00ff;
            used_udvm_cycles = used_udvm_cycles + 1 + length;
            goto execute_next_instruction;

            break;
      case SIGCOMP_INSTR_MEMSET: /* 21 MEMSET (%address, %length, %start_value, %offset) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## MEMSET(21) (address, length, start_value, offset)",
                        current_address);
            }
            operand_address = current_address + 1;

            /* %address */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Address %u",
                        operand_address, address);
            }
            operand_address = next_operand_address;

            /*  %length, */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;
            /* %start_value */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &start_value);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      start_value %u",
                        operand_address, start_value);
            }
            operand_address = next_operand_address;

            /* %offset */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      offset %u",
                        operand_address, multy_offset);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## MEMSET (address=%u, length=%u, start_value=%u, offset=%u)",
                        current_address, address, length, start_value, multy_offset);
            }
            current_address = next_operand_address;
            /* exetute the instruction
             * The sequence of values used by the MEMSET instruction is specified by
             * the following formula:
             *
             * Seq[n] := (start_value + n * offset) modulo 256
             */
            n = 0;
            k = address;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_left = %u byte_copy_right = %u", byte_copy_left, byte_copy_right);
            }
            while ( n < length ){
                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  buff[k] = (start_value + ( n * multy_offset)) & 0xff;
                  if (print_level_2 ){
                        proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "     Storing value: %u (0x%x) at Addr: %u",
                              buff[k], buff[k], k);
                  }
                  k = ( k + 1 ) & 0xffff;
                  n++;
            }/* end while */
            used_udvm_cycles = used_udvm_cycles + 1 + length;
            goto execute_next_instruction;
            break;


      case SIGCOMP_INSTR_JUMP: /* 22 JUMP (@address) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## JUMP(22) (@address)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* @address */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## JUMP (@address=%u)",
                        current_address, at_address);
            }
            current_address = at_address;
            used_udvm_cycles++;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_COMPARE: /* 23 */
            /* COMPARE (%value_1, %value_2, @address_1, @address_2, @address_3)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COMPARE(23) (value_1, value_2, @address_1, @address_2, @address_3)",
                        current_address);
            }
            operand_address = current_address + 1;

            /* %value_1 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_1);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                              operand_address, value_1);
            }
            operand_address = next_operand_address;

            /* %value_2 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_2);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                              operand_address, value_2);
            }
            operand_address = next_operand_address;

            /* @address_1 */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_1);
            at_address_1 = ( current_address + at_address_1) & 0xffff;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address_1);
            }
            operand_address = next_operand_address;


            /* @address_2 */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_2);
            at_address_2 = ( current_address + at_address_2) & 0xffff;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address_2);
            }
            operand_address = next_operand_address;

            /* @address_3 */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_3);
            at_address_3 = ( current_address + at_address_3) & 0xffff;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address_3);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## COMPARE (value_1=%u, value_2=%u, @address_1=%u, @address_2=%u, @address_3=%u)",
                        current_address, value_1, value_2, at_address_1, at_address_2, at_address_3);
            }
            /* execute the instruction
             * If value_1 < value_2 then the UDVM continues instruction execution at
             * the memory address specified by address 1. If value_1 = value_2 then
             * it jumps to the address specified by address_2. If value_1 > value_2
             * then it jumps to the address specified by address_3.
             */
            if ( value_1 < value_2 )
                  current_address = at_address_1;
            if ( value_1 == value_2 )
                  current_address = at_address_2;
            if ( value_1 > value_2 )
                  current_address = at_address_3;
            used_udvm_cycles++;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_CALL: /* 24 CALL (@address) (PUSH addr )*/
            if (show_instr_detail_level == 2){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## CALL(24) (@address) (PUSH addr )",
                        current_address);
            }
            operand_address = current_address + 1;
            /* @address */
            next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## CALL (@address=%u)",
                        current_address, at_address);
            }
            current_address = next_operand_address;

            /* Push the current address onto the stack */
            stack_location = (buff[70] << 8) | buff[71];
            stack_fill = (buff[stack_location] << 8)
                     | buff[(stack_location+1) & 0xFFFF];
            address = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
            if (address >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;
            buff[address] = (current_address >> 8) & 0x00FF;
            buff[(address+1) & 0xFFFF] = current_address & 0x00FF;

            stack_fill = (stack_fill + 1) & 0xFFFF;
            if (stack_location >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;
            buff[stack_location] = (stack_fill >> 8) & 0x00FF;
            buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;

            /* ... and jump to the destination address */
            current_address = at_address;

            used_udvm_cycles++;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_RETURN: /* 25 POP and return */
            if (print_level_1 || show_instr_detail_level == 1){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## POP(25) and return",
                        current_address);
            }

            /* Pop value from the top of the stack */
            stack_location = (buff[70] << 8) | buff[71];
            stack_fill = (buff[stack_location] << 8)
                     | buff[(stack_location+1) & 0xFFFF];
            if (stack_fill == 0)
            {
                result_code = 16;
                goto decompression_failure;
            }

            stack_fill = (stack_fill - 1) & 0xFFFF;
            if (stack_location >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;
            buff[stack_location] = (stack_fill >> 8) & 0x00FF;
            buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;

            address = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
            at_address = (buff[address] << 8)
                     | buff[(address+1) & 0xFFFF];

            /* ... and set the PC to the popped value */
            current_address = at_address;

            used_udvm_cycles++;
            goto execute_next_instruction;

            break;

      case SIGCOMP_INSTR_SWITCH: /* 26 SWITCH (#n, %j, @address_0, @address_1, ... , @address_n-1) */
            /*
             * When a SWITCH instruction is encountered the UDVM reads the value of
             * j. It then continues instruction execution at the address specified
             * by address j.
             *
             * Decompression failure occurs if j specifies a value of n or more, or
             * if the address lies beyond the overall UDVM memory size.
             */
            instruction_address = current_address;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## SWITCH (#n, j, @address_0, @address_1, ... , @address_n-1))",
                        current_address);
            }
            operand_address = current_address + 1;
            /* #n
             * Number of addresses in the instruction
             */
            next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      n %u",
                        operand_address, n);
            }
            operand_address = next_operand_address;
            /* %j */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &j);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      j %u",
                              operand_address, j);
            }
            operand_address = next_operand_address;
            m = 0;
            while ( m < n ){
                  /* @address_n-1 */
                  /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_1);
                  at_address_1 = ( instruction_address + at_address_1) & 0xffff;
                  if (print_level_1 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                              operand_address, at_address_1);
                  }
                  if ( j == m ){
                        current_address = at_address_1;
                  }
                  operand_address = next_operand_address;
                  m++;
            }
            /* Check decompression failure */
            if ( ( j == n ) || ( j > n )){
                  result_code = 5;
                  goto decompression_failure;
            }
            if ( current_address > UDVM_MEMORY_SIZE ){
                  result_code = 6;
                  goto decompression_failure;
            }
            used_udvm_cycles = used_udvm_cycles + 1 + n;

            goto execute_next_instruction;

            break;
      case SIGCOMP_INSTR_CRC: /* 27 CRC (%value, %position, %length, @address) */
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## CRC (value, position, length, @address)",
                        current_address);
            }

            operand_address = current_address + 1;

            /* %value */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                        operand_address, value);
            }
            operand_address = next_operand_address;

            /* %position */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
                        operand_address, position);
            }
            operand_address = next_operand_address;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;

            /* @address */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address);
            at_address = ( current_address + at_address) & 0xffff;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            used_udvm_cycles = used_udvm_cycles + 1 + length;

            n = 0;
            k = position;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            result = 0;

            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
                              "byte_copy_right = %u", byte_copy_right);
            }

            while (n<length) {

                  guint16 handle_now = length - n;

                  if ( k < byte_copy_right && byte_copy_right <= k + (length-n) ){
                        handle_now = byte_copy_right - k;
                  }

                  if (k + handle_now >= UDVM_MEMORY_SIZE)
                        goto decompression_failure;
                  result = crc16_ccitt_seed(&buff[k], handle_now, (guint16) (result ^ 0xffff));

                  k = ( k + handle_now ) & 0xffff;
                  n = ( n + handle_now ) & 0xffff;

                  if ( k >= byte_copy_right ) {
                        k = byte_copy_left;
                  }
            }

            result = result ^ 0xffff;

            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1, "Calculated CRC %u", result);
            }
            if (result != value){
                  current_address = at_address;
            }
            else {
                  current_address = next_operand_address;
            }
            goto execute_next_instruction;
            break;


      case SIGCOMP_INSTR_INPUT_BYTES: /* 28 INPUT-BYTES (%length, %destination, @address) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-BYTES(28) length, destination, @address)",
                        current_address);
            }
            operand_address = current_address + 1;
            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;

            /* %destination */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                        operand_address, destination);
            }
            operand_address = next_operand_address;

            /* @address */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address);
            at_address = ( current_address + at_address) & 0xffff;
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-BYTES length=%u, destination=%u, @address=%u)",
                        current_address, length, destination, at_address);
            }
            /* execute the instruction TODO insert checks
             * RFC 3320 :
             *
             *    0             7 8            15
             *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *   |        byte_copy_left         |  64 - 65
             *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *   |        byte_copy_right        |  66 - 67
             *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *   |        input_bit_order        |  68 - 69
             *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *   |        stack_location         |  70 - 71
             *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *
             * Figure 7: Memory addresses of the UDVM registers
             * :
             * 8.4.  Byte copying
             * :
             * The string of bytes is copied in ascending order of memory address,
             * respecting the bounds set by byte_copy_left and byte_copy_right.
             * More precisely, if a byte is copied from/to Address m then the next
             * byte is copied from/to Address n where n is calculated as follows:
             *
             * Set k := m + 1 (modulo 2^16)
             * If k = byte_copy_right then set n := byte_copy_left, else set n := k
             *
             */

            n = 0;
            k = destination;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_right = %u", byte_copy_right);
            }
            /* clear out remaining bits if any */
            remaining_bits = 0;
            input_bits=0;
            /* operand_address used as dummy */
            while ( n < length ){
                  if (input_address > ( msg_end - 1)){
                        current_address = at_address;
                        result_code = 14;
                        goto execute_next_instruction;
                  }

                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  octet = tvb_get_guint8(message_tvb, input_address);
                  buff[k] = octet;
                  if (print_level_1 ){
                        proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               Loading value: %u (0x%x) at Addr: %u", octet, octet, k);
                  }
                  input_address++;
                  /*
                   * If the instruction requests data that lies beyond the end of the
                   * SigComp message, no data is returned.  Instead the UDVM moves program
                   * execution to the address specified by the address operand.
                   */


                  k = ( k + 1 ) & 0xffff;
                  n++;
            }
            used_udvm_cycles = used_udvm_cycles + 1 + length;
            current_address = next_operand_address;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_INPUT_BITS:/* 29   INPUT-BITS (%length, %destination, @address) */
            /*
             * The length operand indicates the requested number of bits.
             * Decompression failure occurs if this operand does not lie between 0
             * and 16 inclusive.
             *
             * The destination operand specifies the memory address to which the
             * compressed data should be copied.  Note that the requested bits are
             * interpreted as a 2-byte integer ranging from 0 to 2^length - 1, as
             * explained in Section 8.2.
             *
             * If the instruction requests data that lies beyond the end of the
             * SigComp message, no data is returned.  Instead the UDVM moves program
             * execution to the address specified by the address operand.
             */

            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-BITS(29) (length, destination, @address)",
                        current_address);
            }
            operand_address = current_address + 1;

            /* %length */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      length %u",
                        operand_address, length);
            }
            operand_address = next_operand_address;
            /* %destination */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                        operand_address, destination);
            }
            operand_address = next_operand_address;

            /* @address */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-BITS length=%u, destination=%u, @address=%u)",
                        current_address, length, destination, at_address);
            }
            current_address = next_operand_address;

            /*
             * Execute actual instr.
             * The input_bit_order register contains the following three flags:
             *
             *            0             7 8            15
             *           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *           |         reserved        |F|H|P|  68 - 69
             *           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             */
            input_bit_order = buff[68] << 8;
            input_bit_order = input_bit_order | buff[69];
            /*
             * If the instruction requests data that lies beyond the end of the
             * SigComp message, no data is returned.  Instead the UDVM moves program
             * execution to the address specified by the address operand.
             */

            if ( length > 16 ){
                  result_code = 7;
                  goto decompression_failure;
            }
            if ( input_bit_order > 7 ){
                  result_code = 8;
                  goto decompression_failure;
            }

            /*
             * Transfer F bit to bit_order to tell decomp dispatcher which bit order to use
             */
            bit_order = ( input_bit_order & 0x0004 ) >> 2;
            value = decomp_dispatch_get_bits( message_tvb, udvm_tree, bit_order,
                        buff, &old_input_bit_order, &remaining_bits,
                        &input_bits, &input_address, length, &result_code, msg_end);
            if ( result_code == 11 ){
                  used_udvm_cycles = used_udvm_cycles + 1;
                  current_address = at_address;
                  goto execute_next_instruction;
            }
            msb = value >> 8;
            lsb = value & 0x00ff;
            if (destination >= UDVM_MEMORY_SIZE - 1)
                  goto decompression_failure;
            buff[destination] = msb;
            buff[destination + 1]=lsb;
            if (print_level_1 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                  "               Loading value: %u (0x%x) at Addr: %u, remaining_bits: %u", value, value, destination, remaining_bits);
            }

            used_udvm_cycles = used_udvm_cycles + 1;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_INPUT_HUFFMAN: /* 30 */
            /*
             * INPUT-HUFFMAN (%destination, @address, #n, %bits_1, %lower_bound_1,
             *  %upper_bound_1, %uncompressed_1, ... , %bits_n, %lower_bound_n,
             *  %upper_bound_n, %uncompressed_n)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-HUFFMAN (destination, @address, #n, bits_1, lower_bound_1,upper_bound_1, uncompressed_1, ... , bits_n, lower_bound_n,upper_bound_n, uncompressed_n)",
                        current_address);
            }
            operand_address = current_address + 1;

            /* %destination */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                        operand_address, destination);
            }
            operand_address = next_operand_address;

            /* @address */
             /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
            next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                        operand_address, at_address);
            }
            operand_address = next_operand_address;

            /* #n */
            next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      n %u",
                        operand_address, n);
            }
            operand_address = next_operand_address;
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## INPUT-HUFFMAN (destination=%u, @address=%u, #n=%u, bits_1, lower_1,upper_1, unc_1, ... , bits_%d, lower_%d,upper_%d, unc_%d)",
                        current_address, destination, at_address, n, n, n, n, n);
            }

            used_udvm_cycles = used_udvm_cycles + 1 + n;

            /*
             * Note that if n = 0 then the INPUT-HUFFMAN instruction is ignored and
             * program execution resumes at the following instruction.
             * Decompression failure occurs if (bits_1 + ... + bits_n) > 16.
             *
             * In all other cases, the behavior of the INPUT-HUFFMAN instruction is
             * defined below:
             *
             * 1. Set j := 1 and set H := 0.
             *
             * 2. Request bits_j compressed bits.  Interpret the returned bits as an
             * integer k from 0 to 2^bits_j - 1, as explained in Section 8.2.
             *
             * 3. Set H := H * 2^bits_j + k.
             *
             * 4. If data is requested that lies beyond the end of the SigComp
             * message, terminate the INPUT-HUFFMAN instruction and move program
             * execution to the memory address specified by the address operand.
             *
             * 5. If (H < lower_bound_j) or (H > upper_bound_j) then set j := j + 1.
             * Then go back to Step 2, unless j > n in which case decompression
             * failure occurs.
             *
             * 6. Copy (H + uncompressed_j - lower_bound_j) modulo 2^16 to the
             * memory address specified by the destination operand.
             *
             */
            /*
             * The input_bit_order register contains the following three flags:
             *
             *            0             7 8            15
             *           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *           |         reserved        |F|H|P|  68 - 69
             *           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *
             * Transfer H bit to bit_order to tell decomp dispatcher which bit order to use
             */
            input_bit_order = buff[68] << 8;
            input_bit_order = input_bit_order | buff[69];
            bit_order = ( input_bit_order & 0x0002 ) >> 1;

            j = 1;
            H = 0;
            m = n;
            outside_huffman_boundaries = TRUE;
            print_in_loop = print_level_3;
            while ( m > 0 ){
                  /* %bits_n */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &bits_n);
                  if (print_in_loop ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      bits_n %u",
                              operand_address, bits_n);
                  }
                  operand_address = next_operand_address;

                  /* %lower_bound_n */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &lower_bound_n);
                  if (print_in_loop ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      lower_bound_n %u",
                              operand_address, lower_bound_n);
                  }
                  operand_address = next_operand_address;
                  /* %upper_bound_n */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &upper_bound_n);
                  if (print_in_loop ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      upper_bound_n %u",
                              operand_address, upper_bound_n);
                  }
                  operand_address = next_operand_address;
                  /* %uncompressed_n */
                  next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &uncompressed_n);
                  if (print_in_loop ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      uncompressed_n %u",
                              operand_address, uncompressed_n);
                  }
                  operand_address = next_operand_address;
                  /* execute instruction */
                  if ( outside_huffman_boundaries ) {
                        /*
                         * 2. Request bits_j compressed bits.  Interpret the returned bits as an
                         *    integer k from 0 to 2^bits_j - 1, as explained in Section 8.2.
                         */
                        k = decomp_dispatch_get_bits( message_tvb, udvm_tree, bit_order,
                                    buff, &old_input_bit_order, &remaining_bits,
                                    &input_bits, &input_address, bits_n, &result_code, msg_end);
                        if ( result_code == 11 ){
                              /*
                              * 4. If data is requested that lies beyond the end of the SigComp
                              * message, terminate the INPUT-HUFFMAN instruction and move program
                              * execution to the memory address specified by the address operand.
                              */
                              current_address = at_address;
                              goto execute_next_instruction;
                        }

                        /*
                         * 3. Set H := H * 2^bits_j + k.
                         * [In practice is a shift+OR operation.]
                         */
                        oldH = H;
                        H = (H << bits_n) | k;
                        if (print_level_3 ){
                              proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"               Set H(%u) := H(%u) * 2^bits_j(%u) + k(%u)",
                                     H ,oldH, 1<<bits_n,k);
                        }

                        /*
                         * 5. If (H < lower_bound_j) or (H > upper_bound_j) then set j := j + 1.
                         * Then go back to Step 2, unless j > n in which case decompression
                         * failure occurs.
                         */
                        if ((H < lower_bound_n) || (H > upper_bound_n)){
                              outside_huffman_boundaries = TRUE;
                        }else{
                              outside_huffman_boundaries = FALSE;
                              print_in_loop = FALSE;
                              /*
                               * 6. Copy (H + uncompressed_j - lower_bound_j) modulo 2^16 to the
                               * memory address specified by the destination operand.
                               */
                              if (print_level_2 ){
                                    proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                                          "               H(%u) = H(%u) + uncompressed_n(%u) - lower_bound_n(%u)",
                                    (H + uncompressed_n - lower_bound_n ),H, uncompressed_n, lower_bound_n);
                              }
                              H = H + uncompressed_n - lower_bound_n;
                              msb = H >> 8;
                              lsb = H & 0x00ff;
                              if (destination >= UDVM_MEMORY_SIZE - 1)
                                    goto decompression_failure;
                              buff[destination] = msb;
                              buff[destination + 1]=lsb;
                              if (print_level_1 ){
                                    proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               Loading H: %u (0x%x) at Addr: %u,j = %u remaining_bits: %u",
                                    H, H, destination,( n - m + 1 ), remaining_bits);
                              }

                        }


                  }
                  m = m - 1;
            }
            if ( outside_huffman_boundaries ) {
                  result_code = 10;
                  goto decompression_failure;
            }

            current_address = next_operand_address;
            goto execute_next_instruction;
            break;

      case SIGCOMP_INSTR_STATE_ACCESS: /* 31 */
            /*   STATE-ACCESS (%partial_identifier_start, %partial_identifier_length,
             * %state_begin, %state_length, %state_address, %state_instruction)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-ACCESS(31) (partial_identifier_start, partial_identifier_length,state_begin, state_length, state_address, state_instruction)",
                        current_address);
            }
            operand_address = current_address + 1;

            /*
             * %partial_identifier_start
             */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_start);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       partial_identifier_start %u",
                        operand_address, p_id_start);
            }
            operand_address = next_operand_address;

            /*
             * %partial_identifier_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       partial_identifier_length %u",
                        operand_address, p_id_length);
            }
            /*
             * %state_begin
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_begin);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_begin %u",
                        operand_address, state_begin);
            }
            /*
             * %state_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_length %u",
                        operand_address, state_length);
            }
            /*
             * %state_address
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_address %u",
                        operand_address, state_address);
            }
            /*
             * %state_instruction
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_instruction %u",
                        operand_address, state_instruction);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-ACCESS(31) (partial_identifier_start=%u, partial_identifier_length=%u,state_begin=%u, state_length=%u, state_address=%u, state_instruction=%u)",
                        current_address, p_id_start, p_id_length, state_begin, state_length, state_address, state_instruction);
            }
            current_address = next_operand_address;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_2 ){
                  proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
                              "               byte_copy_right = %u, byte_copy_left = %u", byte_copy_right,byte_copy_left);
            }

            result_code = udvm_state_access(message_tvb, udvm_tree, buff, p_id_start, p_id_length, state_begin, &state_length,
                  &state_address, &state_instruction, hf_id);
            if ( result_code != 0 ){
                  goto decompression_failure;
            }
            used_udvm_cycles = used_udvm_cycles + 1 + state_length;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_STATE_CREATE: /* 32 */
            /*
             * STATE-CREATE (%state_length, %state_address, %state_instruction,
             * %minimum_access_length, %state_retention_priority)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-CREATE(32) (state_length, state_address, state_instruction,minimum_access_length, state_retention_priority)",
                        current_address);
            }
            operand_address = current_address + 1;

            /*
             * %state_length
             */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_length %u",
                        operand_address, state_length);
            }
            /*
             * %state_address
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_address %u",
                        operand_address, state_address);
            }
            /*
             * %state_instruction
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_instruction %u",
                        operand_address, state_instruction);
            }
            operand_address = next_operand_address;
            /*
             * %minimum_access_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &minimum_access_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       minimum_access_length %u",
                        operand_address, minimum_access_length);
            }
            operand_address = next_operand_address;
            /*
             * %state_retention_priority
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_retention_priority);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       state_retention_priority %u",
                        operand_address, state_retention_priority);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-CREATE(32) (state_length=%u, state_address=%u, state_instruction=%u,minimum_access_length=%u, state_retention_priority=%u)",
                        current_address, state_length, state_address, state_instruction,minimum_access_length, state_retention_priority);
            }
            current_address = next_operand_address;
            /* Execute the instruction
             * TODO Implement the instruction
             * RFC3320:
             *    Note that the new state item cannot be created until a valid
             *    compartment identifier has been returned by the application.
             *    Consequently, when a STATE-CREATE instruction is encountered the UDVM
             *    simply buffers the five supplied operands until the END-MESSAGE
             *    instruction is reached.  The steps taken at this point are described
             *    in Section 9.4.9.
             *
             *   Decompression failure MUST occur if more than four state creation
             *   requests are made before the END-MESSAGE instruction is encountered.
             *   Decompression failure also occurs if the minimum_access_length does
             *   not lie between 6 and 20 inclusive, or if the
             *   state_retention_priority is 65535.
             */
            no_of_state_create++;
            if ( no_of_state_create > 4 ){
                  result_code = 12;
                  goto decompression_failure;
            }
            if (( minimum_access_length < 6 ) || ( minimum_access_length > STATE_BUFFER_SIZE )){
                  result_code = 1;
                  goto decompression_failure;
            }
            if ( state_retention_priority == 65535 ){
                  result_code = 13;
                  goto decompression_failure;
            }
            state_length_buff[no_of_state_create] = state_length;
            state_address_buff[no_of_state_create] = state_address;
            state_instruction_buff[no_of_state_create] = state_instruction;
            state_minimum_access_length_buff[no_of_state_create] = minimum_access_length;
            state_state_retention_priority_buff[no_of_state_create] = state_retention_priority;
            used_udvm_cycles = used_udvm_cycles + 1 + state_length;
            /* Debug */
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            n = 0;
            k = state_address;
            while ( n < state_length ){
                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  string[0]= buff[k];
                  string[1]= '\0';
                  if (print_level_3 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                              "               Addr: %5u State value: %u (0x%x) ASCII(%s)",
                              k,buff[k],buff[k],format_text(string, 1));
                  }
                  k = ( k + 1 ) & 0xffff;
                  n++;
            }
            /* End debug */

            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_STATE_FREE: /* 33 */
            /*
             * STATE-FREE (%partial_identifier_start, %partial_identifier_length)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-FREE (partial_identifier_start, partial_identifier_length)",
                        current_address);
            }
            operand_address = current_address + 1;
            /*
             * %partial_identifier_start
             */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_start);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       partial_identifier_start %u",
                        operand_address, p_id_start);
            }
            operand_address = next_operand_address;

            /*
             * %partial_identifier_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u       partial_identifier_length %u",
                        operand_address, p_id_length);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## STATE-FREE (partial_identifier_start=%u, partial_identifier_length=%u)",
                        current_address, p_id_start, p_id_length);
            }
            current_address = next_operand_address;

            /* Execute the instruction:
             * TODO implement it
             */
            udvm_state_free(buff,p_id_start,p_id_length);
            used_udvm_cycles++;

            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_OUTPUT: /* 34 OUTPUT (%output_start, %output_length) */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## OUTPUT(34) (output_start, output_length)",
                        current_address);
            }
            operand_address = current_address + 1;
            /*
             * %output_start
             */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &output_start);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      output_start %u",
                        operand_address, output_start);
            }
            operand_address = next_operand_address;
            /*
             * %output_length
             */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &output_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      output_length %u",
                        operand_address, output_length);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## OUTPUT (output_start=%u, output_length=%u)",
                        current_address, output_start, output_length);
            }
            current_address = next_operand_address;

            /*
             * Execute instruction
             * 8.4.  Byte copying
             * :
             * The string of bytes is copied in ascending order of memory address,
             * respecting the bounds set by byte_copy_left and byte_copy_right.
             * More precisely, if a byte is copied from/to Address m then the next
             * byte is copied from/to Address n where n is calculated as follows:
             *
             * Set k := m + 1 (modulo 2^16)
             * If k = byte_copy_right then set n := byte_copy_left, else set n := k
             *
             */

            n = 0;
            k = output_start;
            byte_copy_right = buff[66] << 8;
            byte_copy_right = byte_copy_right | buff[67];
            byte_copy_left = buff[64] << 8;
            byte_copy_left = byte_copy_left | buff[65];
            if (print_level_3 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                              "               byte_copy_right = %u", byte_copy_right);
            }
            while ( n < output_length ){

                  if ( k == byte_copy_right ){
                        k = byte_copy_left;
                  }
                  out_buff[output_address] = buff[k];
                  string[0]= buff[k];
                  string[1]= '\0';
                  if (print_level_3 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                              "               Output value: %u (0x%x) ASCII(%s) from Addr: %u ,output to dispatcher position %u",
                              buff[k],buff[k],format_text(string,1), k,output_address);
                  }
                  k = ( k + 1 ) & 0xffff;
                  output_address ++;
                  n++;
            }
            used_udvm_cycles = used_udvm_cycles + 1 + output_length;
            goto execute_next_instruction;
            break;
      case SIGCOMP_INSTR_END_MESSAGE: /* 35 */
            /*
             * END-MESSAGE (%requested_feedback_location,
             * %returned_parameters_location, %state_length, %state_address,
             * %state_instruction, %minimum_access_length,
             * %state_retention_priority)
             */
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## END-MESSAGE (requested_feedback_location,state_instruction, minimum_access_length,state_retention_priority)",
                        current_address);
            }
            operand_address = current_address + 1;

            /* %requested_feedback_location */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &requested_feedback_location);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      requested_feedback_location %u",
                        operand_address, requested_feedback_location);
            }
            operand_address = next_operand_address;
            /* returned_parameters_location */
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &returned_parameters_location);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      returned_parameters_location %u",
                        operand_address, returned_parameters_location);
            }
            operand_address = next_operand_address;
            /*
             * %state_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      state_length %u",
                        operand_address, state_length);
            }
            /*
             * %state_address
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      state_address %u",
                        operand_address, state_address);
            }
            /*
             * %state_instruction
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      state_instruction %u",
                        operand_address, state_instruction);
            }

            /*
             * %minimum_access_length
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &minimum_access_length);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      minimum_access_length %u",
                        operand_address, minimum_access_length);
            }

            /*
             * %state_retention_priority
             */
            operand_address = next_operand_address;
            next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_retention_priority);
            if (show_instr_detail_level == 2 ){
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      state_retention_priority %u",
                        operand_address, state_retention_priority);
            }
            if (show_instr_detail_level == 1)
            {
                  proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                        "Addr: %u ## END-MESSAGE (requested_feedback_location=%u, returned_parameters_location=%u, state_length=%u, state_address=%u, state_instruction=%u, minimum_access_length=%u, state_retention_priority=%u)",
                        current_address, requested_feedback_location, returned_parameters_location, state_length, state_address, state_instruction, minimum_access_length,state_retention_priority);
            }
            current_address = next_operand_address;
            /* TODO: This isn't currently totaly correct as END_INSTRUCTION might not create state */
            no_of_state_create++;
            if ( no_of_state_create > 4 ){
                  result_code = 12;
                  goto decompression_failure;
            }
            state_length_buff[no_of_state_create] = state_length;
            state_address_buff[no_of_state_create] = state_address;
            state_instruction_buff[no_of_state_create] = state_instruction;
            /* Not used ? */
            state_minimum_access_length_buff[no_of_state_create] = minimum_access_length;
            state_state_retention_priority_buff[no_of_state_create] = state_retention_priority;

            /* Execute the instruction
             */
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"no_of_state_create %u",no_of_state_create);
            if ( no_of_state_create != 0 ){
                  memset(sha1_digest_buf, 0, STATE_BUFFER_SIZE);
                  n = 1;
                  byte_copy_right = buff[66] << 8;
                  byte_copy_right = byte_copy_right | buff[67];
                  byte_copy_left = buff[64] << 8;
                  byte_copy_left = byte_copy_left | buff[65];
                  while ( n < no_of_state_create + 1 ){
                        sha1buff = g_malloc(state_length_buff[n]+8);
                        sha1buff[0] = state_length_buff[n] >> 8;
                        sha1buff[1] = state_length_buff[n] & 0xff;
                        sha1buff[2] = state_address_buff[n] >> 8;
                        sha1buff[3] = state_address_buff[n] & 0xff;
                        sha1buff[4] = state_instruction_buff[n] >> 8;
                        sha1buff[5] = state_instruction_buff[n] & 0xff;
                        sha1buff[6] = state_minimum_access_length_buff[n] >> 8;
                        sha1buff[7] = state_minimum_access_length_buff[n] & 0xff;
                        if (print_level_3 ){
                              for( x=0; x < 8; x++){
                                    proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"sha1buff %u 0x%x",
                                          x,sha1buff[x]);
                              }
                        }
                        k = state_address_buff[n];
                        for( x=0; x < state_length_buff[n]; x++)
                              {
                              if ( k == byte_copy_right ){
                                    k = byte_copy_left;
                              }
                              sha1buff[8+x] = buff[k];
                              k = ( k + 1 ) & 0xffff;
                              }

                        sha1_starts( &ctx );
                        sha1_update( &ctx, (guint8 *) sha1buff, state_length_buff[n] + 8);
                        sha1_finish( &ctx, sha1_digest_buf );
                        if (print_level_3 ){
                              proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"SHA1 digest %s",bytes_to_str(sha1_digest_buf, STATE_BUFFER_SIZE));

                        }
/* begin partial state-id change cco@iptel.org */
#if 0
                        udvm_state_create(sha1buff, sha1_digest_buf, state_minimum_access_length_buff[n]);
#endif
                        udvm_state_create(sha1buff, sha1_digest_buf, STATE_MIN_ACCESS_LEN);
/* end partial state-id change cco@iptel.org */
                        proto_tree_add_text(udvm_tree,bytecode_tvb, 0, -1,"### Creating state ###");
                        proto_tree_add_string(udvm_tree,hf_id, bytecode_tvb, 0, 0, bytes_to_str(sha1_digest_buf, state_minimum_access_length_buff[n]));

                        n++;

                  }
            }



            /* At least something got decompressed, show it */
            decomp_tvb = tvb_new_real_data(out_buff,output_address,output_address);
            /* Arrange that the allocated packet data copy be freed when the
             * tvbuff is freed.
             */
            tvb_set_free_cb( decomp_tvb, g_free );

            tvb_set_child_real_data_tvbuff(message_tvb,decomp_tvb);
            add_new_data_source(pinfo, decomp_tvb, "Decompressed SigComp message");
            /*
            proto_tree_add_text(udvm_tree, decomp_tvb, 0, -1,"SigComp message Decompressed");
            */
            used_udvm_cycles = used_udvm_cycles + 1 + state_length;
            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"maximum_UDVM_cycles %u used_udvm_cycles %u",
                  maximum_UDVM_cycles, used_udvm_cycles);
            return decomp_tvb;
            break;

      default:
          proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," ### Addr %u Invalid instruction: %u (0x%x)",
                  current_address,current_instruction,current_instruction);
            break;
            }
            g_free(out_buff);
            return NULL;
decompression_failure:

            proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"DECOMPRESSION FAILURE: %s",
                            val_to_str(result_code, result_code_vals,"Unknown (%u)"));
            THROW(ReportedBoundsError);
            g_free(out_buff);
            return NULL;

}

 /*  The simplest operand type is the literal (#), which encodes a
  * constant integer from 0 to 65535 inclusive.  A literal operand may
  * require between 1 and 3 bytes depending on its value.
  * Bytecode:                       Operand value:      Range:
  * 0nnnnnnn                        N                   0 - 127
  * 10nnnnnn nnnnnnnn               N                   0 - 16383
  * 11000000 nnnnnnnn nnnnnnnn      N                   0 - 65535
  *
  *            Figure 8: Bytecode for a literal (#) operand
  *
  */
static int
decode_udvm_literal_operand(guint8 *buff,guint operand_address, guint16 *value)
{
      guint bytecode;
      guint16 operand;
      guint test_bits;
      guint offset = operand_address;
      guint8      temp_data;

      bytecode = buff[operand_address];
      test_bits = bytecode >> 7;
      if (test_bits == 1){
            test_bits = bytecode >> 6;
            if (test_bits == 2){
                  /*
                   * 10nnnnnn nnnnnnnn               N                   0 - 16383
                   */
                  temp_data = buff[operand_address] & 0x1f;
                  operand = temp_data << 8;
                  temp_data = buff[operand_address + 1];
                  operand = operand | temp_data;
                  *value = operand;
                  offset = offset + 2;

            }else{
                  /*
                   * 111000000 nnnnnnnn nnnnnnnn      N                   0 - 65535
                   */
                  offset ++;
                  temp_data = buff[operand_address] & 0x1f;
                  operand = temp_data << 8;
                  temp_data = buff[operand_address + 1];
                  operand = operand | temp_data;
                  *value = operand;
                  offset = offset + 2;

            }
      }else{
            /*
             * 0nnnnnnn                        N                   0 - 127
             */
            operand = ( bytecode & 0x7f);
            *value = operand;
            offset ++;
      }

      return offset;

}

/*
 * The second operand type is the reference ($), which is always used to
 * access a 2-byte value located elsewhere in the UDVM memory.  The
 * bytecode for a reference operand is decoded to be a constant integer
 * from 0 to 65535 inclusive, which is interpreted as the memory address
 * containing the actual value of the operand.
 * Bytecode:                       Operand value:      Range:
 *
 * 0nnnnnnn                        memory[2 * N]       0 - 65535
 * 10nnnnnn nnnnnnnn               memory[2 * N]       0 - 65535
 * 11000000 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
 *
 *            Figure 9: Bytecode for a reference ($) operand
 */
static int
dissect_udvm_reference_operand(guint8 *buff,guint operand_address, guint16 *value,guint *result_dest)
{
      guint bytecode;
      guint16 operand;
      guint offset = operand_address;
      guint test_bits;
      guint8      temp_data;
      guint16 temp_data16;

      bytecode = buff[operand_address];
      test_bits = bytecode >> 7;
      if (test_bits == 1){
            test_bits = bytecode >> 6;
            if (test_bits == 2){
                  /*
                   * 10nnnnnn nnnnnnnn               memory[2 * N]       0 - 65535
                   */
                  temp_data = buff[operand_address] & 0x3f;
                  operand = temp_data << 8;
                  temp_data = buff[operand_address + 1];
                  operand = operand | temp_data;
                  operand = (operand * 2);
                  *result_dest = operand;
                  temp_data16 = buff[operand] << 8;
                  temp_data16 = temp_data16 | buff[operand+1];
                  *value = temp_data16;
                  offset = offset + 2;

            }else{
                  /*
                   * 11000000 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
                   */
                  operand_address++;
                  operand = buff[operand_address] << 8;
                  operand = operand | buff[operand_address + 1];
                  *result_dest = operand;
                  temp_data16 = buff[operand] << 8;
                  temp_data16 = temp_data16 | buff[operand+1];
                  *value = temp_data16;
                  offset = offset + 3;

            }
      }else{
            /*
             * 0nnnnnnn                        memory[2 * N]       0 - 65535
             */
            operand = ( bytecode & 0x7f);
            operand = (operand * 2);
            *result_dest = operand;
            temp_data16 = buff[operand] << 8;
            temp_data16 = temp_data16 | buff[operand+1];
            *value = temp_data16;
            offset ++;
      }

      if (offset >= UDVM_MEMORY_SIZE || *result_dest >= UDVM_MEMORY_SIZE - 1 )
            THROW(ReportedBoundsError);

      return offset;
}

      /* RFC3320
       * Figure 10: Bytecode for a multitype (%) operand
       * Bytecode:                       Operand value:      Range:               HEX val
       * 00nnnnnn                        N                   0 - 63                       0x00
       * 01nnnnnn                        memory[2 * N]       0 - 65535              0x40
       * 1000011n                        2 ^ (N + 6)        64 , 128                      0x86
       * 10001nnn                        2 ^ (N + 8)    256 , ... , 32768                 0x88
       * 111nnnnn                        N + 65504       65504 - 65535              0xe0
       * 1001nnnn nnnnnnnn               N + 61440       61440 - 65535              0x90
       * 101nnnnn nnnnnnnn               N                   0 - 8191                     0xa0
       * 110nnnnn nnnnnnnn               memory[N]           0 - 65535              0xc0
       * 10000000 nnnnnnnn nnnnnnnn      N                   0 - 65535              0x80
       * 10000001 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535              0x81
       */
static int
decode_udvm_multitype_operand(guint8 *buff,guint operand_address, guint16 *value)
{
      guint test_bits;
      guint bytecode;
      guint offset = operand_address;
      guint16 operand;
      guint32 result;
      guint8 temp_data;
      guint16 temp_data16;
      guint16 memmory_addr = 0;

      bytecode = buff[operand_address];
      test_bits = ( bytecode & 0xc0 ) >> 6;
      switch (test_bits ){
      case 0:
            /*
             * 00nnnnnn                        N                   0 - 63
             */
            operand =  buff[operand_address];
            /* debug
             *g_warning("Reading 0x%x From address %u",operand,offset);
             */
            *value = operand;
            offset ++;
            break;
      case 1:
            /*
             * 01nnnnnn                        memory[2 * N]       0 - 65535
             */
            memmory_addr = ( bytecode & 0x3f) * 2;
            temp_data16 = buff[memmory_addr] << 8;
            temp_data16 = temp_data16 | buff[memmory_addr+1];
            *value = temp_data16;
            offset ++;
            break;
      case 2:
            /* Check tree most significant bits */
            test_bits = ( bytecode & 0xe0 ) >> 5;
            if ( test_bits == 5 ){
            /*
             * 101nnnnn nnnnnnnn               N                   0 - 8191
             */
                  temp_data = buff[operand_address] & 0x1f;
                  operand = temp_data << 8;
                  temp_data = buff[operand_address + 1];
                  operand = operand | temp_data;
                  *value = operand;
                  offset = offset + 2;
            }else{
                  test_bits = ( bytecode & 0xf0 ) >> 4;
                  if ( test_bits == 9 ){
            /*
             * 1001nnnn nnnnnnnn               N + 61440       61440 - 65535
             */
                        temp_data = buff[operand_address] & 0x0f;
                        operand = temp_data << 8;
                        temp_data = buff[operand_address + 1];
                        operand = operand | temp_data;
                        operand = operand + 61440;
                        *value = operand;
                        offset = offset + 2;
                  }else{
                        test_bits = ( bytecode & 0x08 ) >> 3;
                        if ( test_bits == 1){
            /*
             * 10001nnn                        2 ^ (N + 8)    256 , ... , 32768
             */

                              result = 1 << ((buff[operand_address] & 0x07) + 8);
                              operand = result & 0xffff;
                              *value = operand;
                              offset ++;
                        }else{
                              test_bits = ( bytecode & 0x0e ) >> 1;
                              if ( test_bits == 3 ){
                                    /*
                                     * 1000 011n                        2 ^ (N + 6)        64 , 128
                                     */
                                    result = 1 << ((buff[operand_address] & 0x01) + 6);
                                    operand = result & 0xffff;
                                    *value = operand;
                                    offset ++;
                              }else{
                              /*
                               * 1000 0000 nnnnnnnn nnnnnnnn      N                   0 - 65535
                               * 1000 0001 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
                               */
                                    offset ++;
                                    temp_data16 = buff[operand_address + 1] << 8;
                                    temp_data16 = temp_data16 | buff[operand_address + 2];
                                    /*  debug
                                     * g_warning("Reading 0x%x From address %u",temp_data16,operand_address);
                                     */
                                    if ( (bytecode & 0x01) == 1 ){
                                          memmory_addr = temp_data16;
                                          temp_data16 = buff[memmory_addr] << 8;
                                          temp_data16 = temp_data16 | buff[memmory_addr+1];
                                    }
                                    *value = temp_data16;
                                    offset = offset +2;
                              }


                        }
                  }
            }
            break;

      case 3:
            test_bits = ( bytecode & 0x20 ) >> 5;
            if ( test_bits == 1 ){
            /*
             * 111nnnnn                        N + 65504       65504 - 65535
             */
                  operand = ( buff[operand_address] & 0x1f) + 65504;
                  *value = operand;
                  offset ++;
            }else{
            /*
             * 110nnnnn nnnnnnnn               memory[N]           0 - 65535
             */
                  memmory_addr = buff[operand_address] & 0x1f;
                  memmory_addr = memmory_addr << 8;
                  memmory_addr = memmory_addr | buff[operand_address + 1];
                  temp_data16 = buff[memmory_addr] << 8;
                  temp_data16 = temp_data16 | buff[memmory_addr+1];
                  *value = temp_data16;
                  /*  debug
                   * g_warning("Reading 0x%x From address %u",temp_data16,memmory_addr);
                   */
                  offset = offset +2;
            }

      default :
            break;
      }
      return offset;
}
      /*
       *
       * The fourth operand type is the address (@).  This operand is decoded
       * as a multitype operand followed by a further step: the memory address
       * of the UDVM instruction containing the address operand is added to
       * obtain the correct operand value.  So if the operand value from
       * Figure 10 is D then the actual operand value of an address is
       * calculated as follows:
       *
       * operand_value = (memory_address_of_instruction + D) modulo 2^16
       *
       * Address operands are always used in instructions that control program
       * flow, because they ensure that the UDVM bytecode is position-
       * independent code (i.e., it will run independently of where it is
       * placed in the UDVM memory).
       */
static int
decode_udvm_address_operand(guint8 *buff,guint operand_address, guint16 *value,guint current_address)
{
      guint32 result;
      guint16 value1;
      guint next_opreand_address;

      next_opreand_address = decode_udvm_multitype_operand(buff, operand_address, &value1);
      result = value1 & 0xffff;
      result = result + current_address;
      *value = result & 0xffff;
      return next_opreand_address;
}


/*
 * This is a lookup table used to reverse the bits in a byte.
 */
static guint8 reverse [] = {
    0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
    0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
    0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
    0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
    0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
    0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
    0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
    0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
    0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
    0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
    0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
    0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
    0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
    0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
    0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
    0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
    0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
    0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
    0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
    0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
    0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
    0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
    0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
    0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
    0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
    0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
    0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
    0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
    0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
    0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
    0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};


static int
decomp_dispatch_get_bits(
            tvbuff_t *message_tvb,
            proto_tree *udvm_tree,
            guint8 bit_order,
            guint8 *buff,
            guint16 *old_input_bit_order,
            guint16 *remaining_bits,
            guint16     *input_bits,
            guint *input_address,
            guint16 length,
            guint16 *result_code,
            guint msg_end)
{
      guint16 input_bit_order;
      guint16 bits_still_required = length;
      guint16 value = 0;
      guint8  octet;
      gint    extra_bytes_available = msg_end - *input_address;
      gint    p_bit;
      gint    prev_p_bit = *old_input_bit_order & 0x0001;
      gint    bits_to_use = 0;


      input_bit_order = buff[68] << 8;
      input_bit_order = input_bit_order | buff[69];
      *result_code = 0;
      p_bit = (input_bit_order & 0x0001) != 0;

      /*
       * Discard any spare bits.
       * Note: We take care to avoid remaining_bits having the value of 8.
       */
      if (prev_p_bit != p_bit)
      {
            *remaining_bits = 0;
            *old_input_bit_order = input_bit_order;
      }

      /*
       * Check we can suppy the required number of bits now, before we alter
       * the input buffer's state.
       */
      if (*remaining_bits + extra_bytes_available * 8 < length)
      {
            *result_code = 11;
            return 0xfbad;
      }

      /* Note: This is never called with length > 16, so the following loop
      *       never loops more than three time. */
      while (bits_still_required > 0)
      {
            /*
             * We only put anything into input_bits if we know we will remove
             * at least one bit. That ensures we can simply discard the spare
             * bits if the P-bit changes.
             */
            if (*remaining_bits == 0)
            {
                  octet = tvb_get_guint8(message_tvb, *input_address);
                  if (print_level_1 ){
                        proto_tree_add_text(udvm_tree, message_tvb, *input_address , 1,
                                    "               Geting value: %u (0x%x) From Addr: %u", octet, octet, *input_address);
                  }
                  *input_address = *input_address + 1;

                  if (p_bit != 0)
                  {
                        octet = reverse[octet];
                  }
                  *input_bits = octet;
                  *remaining_bits = 8;
            }

            /* Add some more bits to the accumulated value. */
            bits_to_use = bits_still_required < *remaining_bits ? bits_still_required : *remaining_bits;
            bits_still_required -= bits_to_use;

            *input_bits <<= bits_to_use;           /* Shift bits into MSByte */
            value = (value << bits_to_use)         /* Then add to the accumulated value */
                  | ((*input_bits >> 8) & 0xFF);
            *remaining_bits -= bits_to_use;
            *input_bits &= 0x00FF;                 /* Leave just the remaining bits */
      }

      if (bit_order != 0)
      {
            /* Bit reverse the entire word. */
            guint16 lsb = reverse[(value >> 8) & 0xFF];
            guint16 msb = reverse[value & 0xFF];

            value = ((msb << 8) | lsb) >> (16 - length);
      }

      return value;
}


/* end udvm */


Generated by  Doxygen 1.6.0   Back to index