From Pavel Moravec via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9612
[metze/wireshark/wip.git] / epan / sigcomp-udvm.c
index bdabb3ace749f89132649faffb07fd36245fc106..9e39d348f862cb99e947288daccb3427318a811a 100644 (file)
@@ -3,52 +3,52 @@
  * Signaling Compression (SigComp) dissection.
  * Copyright 2004, Anders Broman <anders.broman@ericsson.com>
  *
- * $Id: udvm.c 11445 2004-07-20 19:04:48Z etxrab $
+ * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-03.txt
+ * 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 "config.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <math.h>
 #include <glib.h>
 
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
+#include <epan/emem.h>
 
-#include "packet.h"\r
+#include <wsutil/sha1.h>
+#include <wsutil/crc16.h>
+
+#include "packet.h"
+#include "exceptions.h"
 #include "strutil.h"
+#include "to_str.h"
 #include "sigcomp-udvm.h"
 #include "sigcomp_state_hdlr.h"
-#include "sha1.h"
+#include "except.h"
 
 #define        SIGCOMP_INSTR_DECOMPRESSION_FAILURE     0
 #define SIGCOMP_INSTR_AND                       1
 #define SIGCOMP_INSTR_OUTPUT                    34
 #define SIGCOMP_INSTR_END_MESSAGE               35
 
-#define UDVM_MEMORY_SIZE                                               65536
 
 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 decomprssion failure" },
+       { 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" },
+       { 6,    "Attempt to jump outside of UDVM memory" },
        { 7,    "L in input-bits > 16" },
        { 8,    "input_bit_order > 7" },
-       { 9,    "Instruction Decompression failure encounterd" },
+       { 9,    "Instruction Decompression failure encountered" },
        {10,    "Input huffman failed j > n" },
-       {11,    "Input bits requested beond end of message" },
+       {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" },
+       {14,    "Input bytes requested beyond 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,
+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)
+                                                  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];
+       /* UDVM memory must be initialised to zero */
+       guint8          *buff = (guint8 *)ep_alloc0(UDVM_MEMORY_SIZE);
        char            string[2];
-       guint8          out_buff[65536];                /* Largest allowed size for a message is 65535  */
+       guint8          *out_buff;              /* Largest allowed size for a message is UDVM_MEMORY_SIZE = 65536 */
        guint32         i = 0;
        guint16         n = 0;
        guint16         m = 0;
@@ -154,9 +160,11 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
        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;
+       guint16         result_code = 0;
        guint16         old_input_bit_order = 0;
        guint16         remaining_bits = 0;
        guint16         input_bits = 0;
@@ -169,12 +177,12 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
        guint16         state_address_buff[5];
        guint16         state_instruction_buff[5];
        guint16         state_minimum_access_length_buff[5];
-       guint16         state_state_retention_priority_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[20];
+       unsigned char sha1_digest_buf[STATE_BUFFER_SIZE];
        sha1_context ctx;
 
 
@@ -182,7 +190,7 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
        guint16 length;
        guint16 at_address;
        guint16 destination;
-       guint16 address;
+       guint16 addr;
        guint16 value;
        guint16 p_id_start;
        guint16 p_id_length;
@@ -213,10 +221,13 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
        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 ) {
@@ -225,32 +236,26 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
 
                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 */
-       while ( i < UDVM_MEMORY_SIZE ) {
-               buff[i] = 0;
-               i++;
-       }
-       /* Set initial UDVM data 
+       /* Set initial UDVM data
         *  The first 32 bytes of UDVM memory are then initialized to special
         *  values as illustrated in Figure 5.
         *
@@ -274,8 +279,8 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
         *            Figure 5: Initializing Useful Values in UDVM memory
         */
        /* UDVM_memory_size  */
-       buff[0] = 0;
-       buff[1] = 0;
+       buff[0] = (UDVM_MEMORY_SIZE >> 8) & 0x00FF;
+       buff[1] = UDVM_MEMORY_SIZE & 0x00FF;
        /* cycles_per_bit */
        buff[2] = 0;
        buff[3] = 16;
@@ -283,29 +288,30 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
        buff[4] = 0;
        buff[5] = 1;
        /* partial_state_ID_length */
-       buff[6] = 0;
-       buff[7] = 0;
+       buff[6] = (byte_code_id_len >> 8) & 0x00FF;
+       buff[7] = byte_code_id_len & 0x00FF;
        /* state_length  */
-       buff[8] = 0;
-       buff[9] = 0;
-       code_length = tvb_reported_length_remaining(bytecode_tvb, 0);\r
-\r
-       cycles_per_bit = buff[2] << 8;\r
-       cycles_per_bit = cycles_per_bit | buff[3];\r
-       /* \r
-        * maximum_UDVM_cycles = (8 * n + 1000) * cycles_per_bit\r
-        */\r
-       maximum_UDVM_cycles = (( 8 * msg_end ) + 1000) * cycles_per_bit;\r
-\r
-       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);\r
+       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;\r
-       if ( print_level_3 )\r
+       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 ) {
-               buff[i] = tvb_get_guint8(bytecode_tvb, offset);\r
+       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]);
@@ -314,13 +320,14 @@ decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet
                offset++;
 
        }
+       /* Largest allowed size for a message is UDVM_MEMORY_SIZE = 65536  */
+       out_buff = (guint8 *)g_malloc(UDVM_MEMORY_SIZE);
        /* Start executing code */
-       current_address = udvm_mem_dest;
+       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",
-               udvm_mem_dest,msg_end);
+               current_address, msg_end);
 
 execute_next_instruction:
 
@@ -328,33 +335,39 @@ execute_next_instruction:
                result_code = 15;
                goto decompression_failure;
        }
-       current_instruction = buff[current_address];
+       used_udvm_cycles++;
+       current_instruction = buff[current_address & 0xffff];
 
        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,"Ethereal UDVM diagnostic: %s.",
+               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);
-                       tvb_set_child_real_data_tvbuff(message_tvb,decomp_tvb);
+                       decomp_tvb = tvb_new_child_real_data(message_tvb, 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.
+                        */
                        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 (print_level_1 ){
+               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);
@@ -362,35 +375,40 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
 
                break;
 
        case SIGCOMP_INSTR_OR: /* 2 OR ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               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);
@@ -398,35 +416,40 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
 
                break;
 
        case SIGCOMP_INSTR_NOT: /* 3 NOT ($operand_1) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                                "Addr: %u ## NOT(3) ($operand_1)",
                                current_address);
@@ -434,27 +457,32 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
 
        case SIGCOMP_INSTR_LSHIFT: /* 4 LSHIFT ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               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);
@@ -462,34 +490,39 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
 
                break;
-               case SIGCOMP_INSTR_RSHIFT: /* 5 RSHIFT ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+       case SIGCOMP_INSTR_RSHIFT: /* 5 RSHIFT ($operand_1, %operand_2) */
+               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);
@@ -497,33 +530,38 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
-               case SIGCOMP_INSTR_ADD: /* 6 ADD ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+       case SIGCOMP_INSTR_ADD: /* 6 ADD ($operand_1, %operand_2) */
+               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);
@@ -531,33 +569,38 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
 
-               case SIGCOMP_INSTR_SUBTRACT: /* 7 SUBTRACT ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+       case SIGCOMP_INSTR_SUBTRACT: /* 7 SUBTRACT ($operand_1, %operand_2) */
+               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);
@@ -565,34 +608,39 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
 
        case SIGCOMP_INSTR_MULTIPLY: /* 8 MULTIPLY ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               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);
@@ -600,18 +648,24 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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)
                 */
@@ -621,20 +675,19 @@ execute_next_instruction:
                }
                result = operand_1 * operand_2;
                lsb = result & 0xff;
-               msb = result >> 8;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
 
        case SIGCOMP_INSTR_DIVIDE: /* 9 DIVIDE ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               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);
@@ -642,18 +695,24 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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
@@ -663,22 +722,21 @@ execute_next_instruction:
                        result_code = 4;
                        goto decompression_failure;
                }
-               result = (guint16)floor(operand_1/operand_2);
+               result = operand_1 / operand_2;
                lsb = result & 0xff;
-               msb = result >> 8;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
 
        case SIGCOMP_INSTR_REMAINDER: /* 10 REMAINDER ($operand_1, %operand_2) */
-               used_udvm_cycles++;
-               if (print_level_1 ){
+               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);
@@ -686,18 +744,24 @@ execute_next_instruction:
                /* $operand_1*/
                operand_address = current_address + 1;
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
-               if (print_level_1 ){
+               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_address = next_operand_address;
                /* %operand_2*/
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
-               if (print_level_1 ){
+               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
@@ -707,16 +771,16 @@ execute_next_instruction:
                        result_code = 4;
                        goto decompression_failure;
                }
-               result = operand_1 - operand_2 * (guint16)floor(operand_1/operand_2);
+               result = operand_1 - operand_2 * (operand_1 / operand_2);
                lsb = result & 0xff;
-               msb = result >> 8;              
+               msb = result >> 8;
                buff[result_dest] = msb;
-               buff[result_dest+1] = lsb;
+               buff[(result_dest+1) & 0xffff] = 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; 
+               current_address = next_operand_address;
                goto execute_next_instruction;
                break;
        case SIGCOMP_INSTR_SORT_ASCENDING: /* 11 SORT-ASCENDING (%start, %n, %k) */
@@ -728,7 +792,6 @@ execute_next_instruction:
                                "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)
@@ -741,7 +804,6 @@ execute_next_instruction:
                                "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)
@@ -760,7 +822,7 @@ execute_next_instruction:
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
                                operand_address, position);
                }
-               operand_address = next_operand_address; 
+               operand_address = next_operand_address;
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
@@ -776,40 +838,101 @@ execute_next_instruction:
                        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;
-               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
+               used_udvm_cycles = used_udvm_cycles + 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_ep_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 (print_level_1 ){
+               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 (print_level_1 ){
+               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
+               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, addr);
                }
-               operand_address = next_operand_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, addr, value);
+               }
                lsb = value & 0xff;
                msb = value >> 8;
 
-               buff[address] = msb;
-               buff[address + 1] = lsb;
+               buff[addr] = msb;
+               buff[(addr + 1) & 0xffff] = 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);
+                                       addr, value, value);
                }
-               used_udvm_cycles++;
                current_address = next_operand_address;
                goto execute_next_instruction;
                break;
@@ -820,27 +943,33 @@ execute_next_instruction:
                 * the UDVM memory to specified values.
                 * Hmm what if the value to load only takes one byte ? Chose to always load two bytes.
                 */
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
+               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, addr);
                }
-               operand_address = next_operand_address; 
+               operand_address = next_operand_address;
 
                /* #n */
                next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
-               if (print_level_1 ){
+               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 ## MULTILOAD (%%address=%u, #n=%u, value_0, ..., value_%d)",
+                               current_address, addr, n, n-1);
+               }
+               operand_address = next_operand_address;
                used_udvm_cycles = used_udvm_cycles + n;
                while ( n > 0) {
                        n = n - 1;
@@ -849,26 +978,29 @@ execute_next_instruction:
                        lsb = value & 0xff;
                        msb = value >> 8;
 
-                       buff[address] = msb;
-                       buff[address + 1] = lsb;
+                       if (addr >= UDVM_MEMORY_SIZE - 1)
+                               goto decompression_failure;
+
+                       buff[addr] = msb;
+                       buff[(addr + 1) & 0xffff] = lsb;
                        /* debug
                        */
                        length = next_operand_address - operand_address;
 
                        if (print_level_1 ){
-                               proto_tree_add_text(udvm_tree, bytecode_tvb, operand_address - 128, length,"Addr: %u      Value %5u      - Loading bytes at %5u Value %5u 0x%x",
-                                       operand_address, value, address, value, value);
+                               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, addr, value, value);
                        }
-                       address = address + 2;
-                       operand_address = next_operand_address; 
+                       addr = addr + 2;
+                       operand_address = next_operand_address;
                }
                current_address = next_operand_address;
                goto execute_next_instruction;
 
                break;
-                        
+
        case SIGCOMP_INSTR_PUSH: /* 16 PUSH (%value) */
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                                "Addr: %u ## PUSH(16) (value)",
                                current_address);
@@ -876,34 +1008,99 @@ execute_next_instruction:
                operand_address = current_address + 1;
                /* %value */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                                operand_address, value);
                }
-               used_udvm_cycles++;
-               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
+               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];
+               addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
+
+               if (addr >= UDVM_MEMORY_SIZE - 1)
+                       goto decompression_failure;
+
+               buff[addr] = (value >> 8) & 0x00FF;
+               buff[(addr+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;
+
+               goto execute_next_instruction;
+
                break;
 
        case SIGCOMP_INSTR_POP: /* 17 POP (%address) */
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
-                               "Addr: %u ## POP(17) (address)",
+                               "Addr: %u ## POP(16) (value)",
                                current_address);
                }
                operand_address = current_address + 1;
-               /* %address */
-               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &address);
-               if (print_level_1 ){
-                       proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Address %u",
-                               operand_address, address);
+               /* %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);
                }
-               operand_address = next_operand_address; 
-               used_udvm_cycles++;
-               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
+               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;
+
+               addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
+
+               if (addr >= UDVM_MEMORY_SIZE - 1)
+                       goto decompression_failure;
+
+               value = (buff[addr] << 8)
+                          | buff[(addr+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;
+
+               goto execute_next_instruction;
+
                break;
 
        case SIGCOMP_INSTR_COPY: /* 18 COPY (%position, %length, %destination) */
-               if (print_level_1 ){
+               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);
@@ -911,15 +1108,15 @@ execute_next_instruction:
                operand_address = current_address + 1;
                /* %position */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
-               if (print_level_1 ){
+               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; 
+               operand_address = next_operand_address;
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                                operand_address, length);
                }
@@ -927,10 +1124,16 @@ execute_next_instruction:
 
                /* %destination */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
-               if (print_level_1 ){
+               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
@@ -943,42 +1146,48 @@ execute_next_instruction:
                 * 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; 
+               k = destination;
                byte_copy_right = buff[66] << 8;
                byte_copy_right = byte_copy_right | buff[67];
-               if (print_level_1 ){
+               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 ){
-
-                       if (print_level_1 ){
+                       buff[k] = buff[position];
+                       if (print_level_2 ){
                                proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                               "               byte_copy_right = %u", byte_copy_right);
+                                       "               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 ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
                        }
-                       buff[k] = buff[position + n];
-                       if (print_level_1 ){
-                               proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                       "               Copying value: %u (0x%x) to Addr: %u", buff[position + n], buff[position + n], k);
+                       if ( position == byte_copy_right ){
+                               position = byte_copy_left;
                        }
-                       k = ( k + 1 ) & 0xffff;
-                       n++;
                }
-               used_udvm_cycles = used_udvm_cycles + 1 + length;
+               used_udvm_cycles = used_udvm_cycles + length;
                goto execute_next_instruction;
                break;
 
        case SIGCOMP_INSTR_COPY_LITERAL: /* 19 COPY-LITERAL (%position, %length, $destination) */
-               if (print_level_1 ){
+               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);
@@ -986,15 +1195,15 @@ execute_next_instruction:
                operand_address = current_address + 1;
                /* %position */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      position %u",
-                               operand_address, address);
+                               operand_address, position);
                }
-               operand_address = next_operand_address; 
+               operand_address = next_operand_address;
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                                operand_address, length);
                }
@@ -1003,11 +1212,17 @@ execute_next_instruction:
 
                /* $destination */
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      destination %u",
                                operand_address, ref_destination);
                }
-               current_address = next_operand_address; 
+               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, ref_destination);
+               }
+               current_address = next_operand_address;
 
 
                /*
@@ -1021,40 +1236,52 @@ execute_next_instruction:
                 * 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; 
+               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 ){
 
-                       if (print_level_1 ){
+                       buff[k] = buff[position];
+                       if (print_level_2 ){
                                proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                               "               byte_copy_right = %u", byte_copy_right);
+                                       "               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 ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
                        }
-                       buff[k] = buff[position + n];
-                       if (print_level_1 ){
-                               proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                       "               Copying value: %u (0x%x) to Addr: %u", buff[position + n], buff[position + n], k);
+                       if ( position == byte_copy_right ){
+                               position = byte_copy_left;
                        }
-                       k = ( k + 1 ) & 0xffff;
-                       n++;
                }
                buff[result_dest] = k >> 8;
-               buff[result_dest + 1] = k & 0x00ff;
+               buff[(result_dest + 1) & 0xffff] = k & 0x00ff;
 
-               used_udvm_cycles = used_udvm_cycles + 1 + length;
+               used_udvm_cycles = used_udvm_cycles + length;
                goto execute_next_instruction;
                break;
+
        case SIGCOMP_INSTR_COPY_OFFSET: /* 20 COPY-OFFSET (%offset, %length, $destination) */
-               if (print_level_1 ){
+               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);
@@ -1062,15 +1289,15 @@ execute_next_instruction:
                operand_address = current_address + 1;
                /* %offset */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
-               if (print_level_1 ){
+               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; 
+               operand_address = next_operand_address;
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                                operand_address, length);
                }
@@ -1079,17 +1306,24 @@ execute_next_instruction:
 
                /* $destination */
                next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      $destination %u",
                                operand_address, ref_destination);
                }
-               current_address = next_operand_address; 
+
+               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.
                 */
@@ -1098,14 +1332,26 @@ execute_next_instruction:
                byte_copy_right = buff[66] << 8;
                byte_copy_right = byte_copy_right | buff[67];
 
-               if ( (byte_copy_left + multy_offset) > ( ref_destination )){
-                       /* wrap around */
-                       position = byte_copy_right - ( multy_offset - ( ref_destination - byte_copy_left )); 
-               }else{
-                       position = ref_destination - multy_offset;
+               /*
+                * 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_1 ){
+               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);
@@ -1126,49 +1372,46 @@ execute_next_instruction:
                 * 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];
+               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 ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
-                               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);
-                               }
                        }
                        if ( position == byte_copy_right ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                position = byte_copy_left;
-                               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);
-                               }
-                       }
-                       buff[k] = buff[position];
-                       if (print_level_1 ){
-                               proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                       "               Copying value: %5u (0x%x) from Addr: %u to Addr: %u",
-                                       buff[position + n], buff[position + n],(position + n), k);
                        }
-                       k = ( k + 1 ) & 0xffff;
-                       n++;
-                       position++;
                }
                buff[result_dest] = k >> 8;
                buff[result_dest + 1] = k & 0x00ff;
-               used_udvm_cycles = used_udvm_cycles + 1 + length;
+               used_udvm_cycles = used_udvm_cycles + length;
                goto execute_next_instruction;
 
                break;
        case SIGCOMP_INSTR_MEMSET: /* 21 MEMSET (%address, %length, %start_value, %offset) */
-               if (print_level_1 ){
+               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);
@@ -1176,54 +1419,60 @@ execute_next_instruction:
                operand_address = current_address + 1;
 
                /* %address */
-               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &address);
-               if (print_level_1 ){
+               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
+               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, addr);
                }
-               operand_address = next_operand_address; 
+               operand_address = next_operand_address;
 
                /*  %length, */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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; 
+               operand_address = next_operand_address;
 
                /* %offset */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      offset %u",
                                operand_address, multy_offset);
                }
-               current_address = next_operand_address; 
+               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, addr, 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; 
+               k = addr;
                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 ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
-                               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);
-                               }
                        }
                        buff[k] = (start_value + ( n * multy_offset)) & 0xff;
                        if (print_level_2 ){
@@ -1234,13 +1483,13 @@ execute_next_instruction:
                        k = ( k + 1 ) & 0xffff;
                        n++;
                }/* end while */
-               used_udvm_cycles = used_udvm_cycles + 1 + length;
+               used_udvm_cycles = used_udvm_cycles + length;
                goto execute_next_instruction;
                break;
 
 
        case SIGCOMP_INSTR_JUMP: /* 22 JUMP (@address) */
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
                                "Addr: %u ## JUMP(22) (@address)",
                                current_address);
@@ -1248,20 +1497,25 @@ execute_next_instruction:
                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 (print_level_1 ){
+               /*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 (print_level_1 ){
+               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);
@@ -1270,7 +1524,7 @@ execute_next_instruction:
 
                /* %value_1 */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_1);
-               if (print_level_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);
                }
@@ -1278,7 +1532,7 @@ execute_next_instruction:
 
                /* %value_2 */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_2);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Value %u",
                                        operand_address, value_2);
                }
@@ -1288,7 +1542,7 @@ execute_next_instruction:
                 /* 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 (print_level_1 ){
+               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);
                }
@@ -1299,7 +1553,7 @@ execute_next_instruction:
                 /* 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 (print_level_1 ){
+               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);
                }
@@ -1307,12 +1561,18 @@ execute_next_instruction:
 
                /* @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);
+               /*next_operand_address = */decode_udvm_multitype_operand(buff, operand_address, &at_address_3);
                at_address_3 = ( current_address + at_address_3) & 0xffff;
-               if (print_level_1 ){
+               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
@@ -1325,38 +1585,85 @@ execute_next_instruction:
                        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 (print_level_1 ){
+               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_multitype_operand(buff, operand_address, &at_address);
-               at_address = ( current_address + at_address) & 0xffff;
-               if (print_level_1 ){
+               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_value = (memory_address_of_instruction + D) modulo 2^16 */
                }
-               used_udvm_cycles++;
-               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
+               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];
+               addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
+               if (addr >= UDVM_MEMORY_SIZE - 1)
+                       goto decompression_failure;
+               buff[addr] = (current_address >> 8) & 0x00FF;
+               buff[(addr+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;
+
+               goto execute_next_instruction;
+
                break;
 
        case SIGCOMP_INSTR_RETURN: /* 25 POP and return */
-               if (print_level_1 ){
+               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);
                }
-               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++;
+
+               /* 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;
+
+               addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
+               at_address = (buff[addr] << 8)
+                          | buff[(addr+1) & 0xFFFF];
+
+               /* ... and set the PC to the popped value */
+               current_address = at_address;
+
+               goto execute_next_instruction;
+
                break;
 
        case SIGCOMP_INSTR_SWITCH: /* 26 SWITCH (#n, %j, @address_0, @address_1, ... , @address_n-1) */
@@ -1364,7 +1671,7 @@ execute_next_instruction:
                 * 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.
                 */
@@ -1375,7 +1682,7 @@ execute_next_instruction:
                                current_address);
                }
                operand_address = current_address + 1;
-               /* #n 
+               /* #n
                 * Number of addresses in the instruction
                 */
                next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
@@ -1383,7 +1690,7 @@ execute_next_instruction:
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      n %u",
                                operand_address, n);
                }
-               operand_address = next_operand_address; 
+               operand_address = next_operand_address;
                /* %j */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &j);
                if (print_level_1 ){
@@ -1416,8 +1723,8 @@ execute_next_instruction:
                        result_code = 6;
                        goto decompression_failure;
                }
-               used_udvm_cycles = used_udvm_cycles + 1 + n;
-;
+               used_udvm_cycles = used_udvm_cycles + n;
+
                goto execute_next_instruction;
 
                break;
@@ -1427,19 +1734,24 @@ execute_next_instruction:
                                "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; 
+               operand_address = next_operand_address;
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
@@ -1456,22 +1768,67 @@ execute_next_instruction:
                        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;
-
-               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
+                /* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
+               used_udvm_cycles = used_udvm_cycles + 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 (print_level_1 ){
-                       proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u ## INPUT-BYTES(28) 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 (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Length %u",
                                operand_address, length);
                }
@@ -1479,7 +1836,7 @@ execute_next_instruction:
 
                /* %destination */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                                operand_address, destination);
                }
@@ -1489,24 +1846,30 @@ execute_next_instruction:
                 /* 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 (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                                operand_address, at_address);
                }
-               /* execute the instruction TODO insert checks 
+               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
-         *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-                * 
+                *    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
@@ -1519,12 +1882,18 @@ execute_next_instruction:
                 * 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; 
+               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;
@@ -1536,13 +1905,7 @@ execute_next_instruction:
                                goto execute_next_instruction;
                        }
 
-                       if (print_level_1 ){
-                               proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
-                                               "               byte_copy_right = %u", byte_copy_right);
-                       }
                        if ( k == byte_copy_right ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
                        }
                        octet = tvb_get_guint8(message_tvb, input_address);
@@ -1558,11 +1921,11 @@ execute_next_instruction:
                         * execution to the address specified by the address operand.
                         */
 
-                       
+
                        k = ( k + 1 ) & 0xffff;
                        n++;
                }
-               used_udvm_cycles = used_udvm_cycles + 1 + length;
+               used_udvm_cycles = used_udvm_cycles + length;
                current_address = next_operand_address;
                goto execute_next_instruction;
                break;
@@ -1571,7 +1934,7 @@ execute_next_instruction:
                 * 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
@@ -1582,7 +1945,7 @@ execute_next_instruction:
                 * execution to the address specified by the address operand.
                 */
 
-               if (print_level_1 ){
+               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);
@@ -1591,14 +1954,14 @@ execute_next_instruction:
 
                /* %length */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                                operand_address, destination);
                }
@@ -1607,16 +1970,22 @@ execute_next_instruction:
                /* @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 (print_level_1 ){
+               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
@@ -1630,12 +1999,6 @@ execute_next_instruction:
                 * execution to the address specified by the address operand.
                 */
 
-               if ((input_address > ( msg_end -1)) && (remaining_bits == 0 )){
-                       result_code = 11;
-                       current_address = at_address;
-                       goto execute_next_instruction;
-               }
-
                if ( length > 16 ){
                        result_code = 7;
                        goto decompression_failure;
@@ -1644,9 +2007,12 @@ execute_next_instruction:
                        result_code = 8;
                        goto decompression_failure;
                }
-               /* Transfer F bit to bit_order to tell decomp dispatcher which bit order to use */
+
+               /*
+                * 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, 
+               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 ){
@@ -1655,14 +2021,15 @@ 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;
+               buff[(destination + 1) & 0xffff]=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 + length;
                goto execute_next_instruction;
                break;
        case SIGCOMP_INSTR_INPUT_HUFFMAN: /* 30 */
@@ -1671,7 +2038,7 @@ execute_next_instruction:
                 *  %upper_bound_1, %uncompressed_1, ... , %bits_n, %lower_bound_n,
                 *  %upper_bound_n, %uncompressed_n)
                 */
-               if (print_level_1 ){
+               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);
@@ -1680,7 +2047,7 @@ execute_next_instruction:
 
                /* %destination */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
-               if (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      Destination %u",
                                operand_address, destination);
                }
@@ -1689,7 +2056,7 @@ execute_next_instruction:
                /* @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 (print_level_1 ){
+               if (show_instr_detail_level == 2 ){
                        proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      @Address %u",
                                operand_address, at_address);
                }
@@ -1697,47 +2064,56 @@ execute_next_instruction:
 
                /* #n */
                next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
-               if (print_level_1 ){
+               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; 
+               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 + 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 
+                * 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];
@@ -1747,7 +2123,7 @@ execute_next_instruction:
                H = 0;
                m = n;
                outside_huffman_boundaries = TRUE;
-               print_in_loop = print_level_1;
+               print_in_loop = print_level_3;
                while ( m > 0 ){
                        /* %bits_n */
                        next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &bits_n);
@@ -1755,7 +2131,7 @@ execute_next_instruction:
                                proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u      bits_n %u",
                                        operand_address, bits_n);
                        }
-                       operand_address = next_operand_address; 
+                       operand_address = next_operand_address;
 
                        /* %lower_bound_n */
                        next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &lower_bound_n);
@@ -1763,14 +2139,14 @@ execute_next_instruction:
                                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; 
+                       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; 
+                       operand_address = next_operand_address;
                        /* %uncompressed_n */
                        next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &uncompressed_n);
                        if (print_in_loop ){
@@ -1781,34 +2157,33 @@ execute_next_instruction:
                        /* execute instruction */
                        if ( outside_huffman_boundaries ) {
                                /*
-                                * 3. Set H := H * 2^bits_j + k.
+                                * 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, 
+                               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;
                                }
-                               /* ldexp Returns x multiplied by 2 raised to the power of exponent.
-                                * x*2^exponent
+
+                               /*
+                                * 3. Set H := H * 2^bits_j + k.
+                                * [In practice is a shift+OR operation.]
                                 */
                                oldH = H;
-                               H = ( (guint16)ldexp( H, bits_n) + k );
+                               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,((guint16)pow(2,bits_n)),k);
+                                                H ,oldH, 1<<bits_n,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.
-                                */
-                               if ( input_address > msg_end ){
-                                       current_address = at_address;
-                                       goto execute_next_instruction;
-                               }
                                /*
                                 * 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
@@ -1831,14 +2206,16 @@ execute_next_instruction:
                                        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;
+                                       buff[(destination + 1) & 0xffff]=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", 
+                                       "               Loading H: %u (0x%x) at Addr: %u,j = %u remaining_bits: %u",
                                                H, H, destination,( n - m + 1 ), remaining_bits);
                                        }
-                                       
+
                                }
 
 
@@ -1851,7 +2228,6 @@ execute_next_instruction:
                }
 
                current_address = next_operand_address;
-               used_udvm_cycles = used_udvm_cycles + 1 + n;
                goto execute_next_instruction;
                break;
 
@@ -1859,29 +2235,28 @@ execute_next_instruction:
                /*   STATE-ACCESS (%partial_identifier_start, %partial_identifier_length,
                 * %state_begin, %state_length, %state_address, %state_instruction)
                 */
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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 (print_level_1 ){
+               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);
                }
@@ -1890,7 +2265,7 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_begin);
-               if (print_level_1 ){
+               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);
                }
@@ -1898,7 +2273,8 @@ execute_next_instruction:
                 * %state_length
                 */
                operand_address = next_operand_address;
-               next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);             if (print_level_1 ){
+               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);
                }
@@ -1907,7 +2283,7 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
-               if (print_level_1 ){
+               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);
                }
@@ -1916,10 +2292,16 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
-               if (print_level_1 ){
+               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];
@@ -1930,12 +2312,12 @@ execute_next_instruction:
                                        "               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, TRUE);
+               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; 
+                       goto decompression_failure;
                }
-               used_udvm_cycles = used_udvm_cycles + 1 + state_length;
+               used_udvm_cycles = used_udvm_cycles + state_length;
                goto execute_next_instruction;
                break;
        case SIGCOMP_INSTR_STATE_CREATE: /* 32 */
@@ -1943,7 +2325,7 @@ execute_next_instruction:
                 * STATE-CREATE (%state_length, %state_address, %state_instruction,
                 * %minimum_access_length, %state_retention_priority)
                 */
-               if (print_level_1 ){
+               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);
@@ -1954,7 +2336,7 @@ execute_next_instruction:
                 * %state_length
                 */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
-               if (print_level_1 ){
+               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);
                }
@@ -1963,7 +2345,7 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
-               if (print_level_1 ){
+               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);
                }
@@ -1972,30 +2354,34 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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 (print_level_1 ){
+               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
@@ -2016,31 +2402,31 @@ execute_next_instruction:
                no_of_state_create++;
                if ( no_of_state_create > 4 ){
                        result_code = 12;
-                       goto decompression_failure; 
+                       goto decompression_failure;
                }
-               if (( minimum_access_length < 6 ) || ( minimum_access_length > 20 )){
+               if (( minimum_access_length < 6 ) || ( minimum_access_length > STATE_BUFFER_SIZE )){
                        result_code = 1;
-                       goto decompression_failure; 
+                       goto decompression_failure;
                }
                if ( state_retention_priority == 65535 ){
                        result_code = 13;
-                       goto decompression_failure; 
+                       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;
+               /* state_state_retention_priority_buff[no_of_state_create] = state_retention_priority; */
+               used_udvm_cycles = used_udvm_cycles + 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 ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
                        }
                        string[0]= buff[k];
@@ -2048,7 +2434,7 @@ execute_next_instruction:
                        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],string);
+                                       k,buff[k],buff[k],format_text(string, 1));
                        }
                        k = ( k + 1 ) & 0xffff;
                        n++;
@@ -2061,17 +2447,17 @@ execute_next_instruction:
                /*
                 * STATE-FREE (%partial_identifier_start, %partial_identifier_length)
                 */
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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);
                }
@@ -2080,50 +2466,60 @@ execute_next_instruction:
                /*
                 * %partial_identifier_length
                 */
-               operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_length);
-               if (print_level_1 ){
+               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);
-               }\r
-               current_address = next_operand_address;\r
+               }
+               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
-                */\r
-               udvm_state_free(buff,p_id_start,p_id_length);\r
-               used_udvm_cycles++;\r
+                */
+               udvm_state_free(buff,p_id_start,p_id_length);
 
-               goto execute_next_instruction;\r
+               goto execute_next_instruction;
                break;
        case SIGCOMP_INSTR_OUTPUT: /* 34 OUTPUT (%output_start, %output_length) */
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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 (print_level_1 ){
+               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 
+               /*
+                * Execute instruction
                 * 8.4.  Byte copying
                 * :
                 * The string of bytes is copied in ascending order of memory address,
@@ -2134,12 +2530,14 @@ execute_next_instruction:
                 * 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; 
+               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);
@@ -2147,13 +2545,7 @@ execute_next_instruction:
                while ( n < output_length ){
 
                        if ( k == byte_copy_right ){
-                               byte_copy_left = buff[64] << 8;
-                               byte_copy_left = byte_copy_left | buff[65];
                                k = byte_copy_left;
-                               if (print_level_3 ){
-                                       proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
-                                                       "               byte_copy_right = %u", byte_copy_right);
-                               }
                        }
                        out_buff[output_address] = buff[k];
                        string[0]= buff[k];
@@ -2161,13 +2553,13 @@ execute_next_instruction:
                        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],string, k,output_address);
+                                       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;
+               used_udvm_cycles = used_udvm_cycles + output_length;
                goto execute_next_instruction;
                break;
        case SIGCOMP_INSTR_END_MESSAGE: /* 35 */
@@ -2177,7 +2569,7 @@ execute_next_instruction:
                 * %state_instruction, %minimum_access_length,
                 * %state_retention_priority)
                 */
-               if (print_level_1 ){
+               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);
@@ -2186,24 +2578,23 @@ execute_next_instruction:
 
                /* %requested_feedback_location */
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &requested_feedback_location);
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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 (print_level_1 ){
+               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);
                }
@@ -2212,7 +2603,7 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
-               if (print_level_1 ){
+               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);
                }
@@ -2221,63 +2612,67 @@ execute_next_instruction:
                 */
                operand_address = next_operand_address;
                next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
-               if (print_level_1 ){
+               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 (print_level_1 ){
+               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 (print_level_1 ){
+               /*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);
                }
-               current_address = next_operand_address;
+               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);
+               }
                /* 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; 
+                       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;
-               
+               /* 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 ){
-                       for( x=0; x < 20; x++){
-                               sha1_digest_buf[x]=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 = (guint8 *)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[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 ){
@@ -2290,8 +2685,6 @@ execute_next_instruction:
                                for( x=0; x < state_length_buff[n]; x++)
                                        {
                                        if ( k == byte_copy_right ){
-                                               byte_copy_left = buff[64] << 8;
-                                               byte_copy_left = byte_copy_left | buff[65];
                                                k = byte_copy_left;
                                        }
                                        sha1buff[8+x] = buff[k];
@@ -2302,12 +2695,18 @@ execute_next_instruction:
                                sha1_update( &ctx, (guint8 *) sha1buff, state_length_buff[n] + 8);
                                sha1_finish( &ctx, sha1_digest_buf );
                                if (print_level_3 ){
-                               for( x=0; x < 20; x++){
-                                               proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"SHA1 digest byte %u 0x%x",
-                                                       x,sha1_digest_buf[x]);
-                                       }
+                                       proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"SHA1 digest %s",bytes_to_ep_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_ep_str(sha1_digest_buf, state_minimum_access_length_buff[n]));
+
                                n++;
 
                        }
@@ -2316,13 +2715,17 @@ execute_next_instruction:
 
 
                /* At least something got decompressed, show it */
-               decomp_tvb = tvb_new_real_data(out_buff,output_address,output_address);
-               tvb_set_child_real_data_tvbuff(message_tvb,decomp_tvb);
+               decomp_tvb = tvb_new_child_real_data(message_tvb, 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_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;
+               */
+               used_udvm_cycles = used_udvm_cycles + 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;
@@ -2333,17 +2736,18 @@ execute_next_instruction:
                        current_address,current_instruction,current_instruction);
                break;
                }
-       return NULL;
+               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)"));
-       return NULL;
-
 
+               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.
@@ -2356,7 +2760,7 @@ decompression_failure:
   *
   */
 static int
-decode_udvm_literal_operand(guint8 buff[],guint operand_address, guint16 *value) 
+decode_udvm_literal_operand(guint8 *buff,guint operand_address, guint16 *value)
 {
        guint   bytecode;
        guint16 operand;
@@ -2374,7 +2778,7 @@ decode_udvm_literal_operand(guint8 buff[],guint operand_address, guint16 *value)
                         */
                        temp_data = buff[operand_address] & 0x1f;
                        operand = temp_data << 8;
-                       temp_data = buff[operand_address + 1];
+                       temp_data = buff[(operand_address + 1) & 0xffff];
                        operand = operand | temp_data;
                        *value = operand;
                        offset = offset + 2;
@@ -2386,7 +2790,7 @@ decode_udvm_literal_operand(guint8 buff[],guint operand_address, guint16 *value)
                        offset ++;
                        temp_data = buff[operand_address] & 0x1f;
                        operand = temp_data << 8;
-                       temp_data = buff[operand_address + 1];
+                       temp_data = buff[(operand_address + 1) & 0xffff];
                        operand = operand | temp_data;
                        *value = operand;
                        offset = offset + 2;
@@ -2420,7 +2824,7 @@ decode_udvm_literal_operand(guint8 buff[],guint operand_address, guint16 *value)
  *            Figure 9: Bytecode for a reference ($) operand
  */
 static int
-dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *value,guint *result_dest) 
+dissect_udvm_reference_operand(guint8 *buff,guint operand_address, guint16 *value,guint *result_dest)
 {
        guint bytecode;
        guint16 operand;
@@ -2439,12 +2843,12 @@ dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *val
                         */
                        temp_data = buff[operand_address] & 0x3f;
                        operand = temp_data << 8;
-                       temp_data = buff[operand_address + 1];
+                       temp_data = buff[(operand_address + 1) & 0xffff];
                        operand = operand | temp_data;
                        operand = (operand * 2);
                        *result_dest = operand;
                        temp_data16 = buff[operand] << 8;
-                       temp_data16 = temp_data16 | buff[operand+1];
+                       temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
                        *value = temp_data16;
                        offset = offset + 2;
 
@@ -2454,10 +2858,10 @@ dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *val
                         */
                        operand_address++;
                        operand = buff[operand_address] << 8;
-                       operand = operand | buff[operand_address + 1];
+                       operand = operand | buff[(operand_address + 1) & 0xffff];
                        *result_dest = operand;
                        temp_data16 = buff[operand] << 8;
-                       temp_data16 = temp_data16 | buff[operand+1];
+                       temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
                        *value = temp_data16;
                        offset = offset + 3;
 
@@ -2470,11 +2874,14 @@ dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *val
                operand = (operand * 2);
                *result_dest = operand;
                temp_data16 = buff[operand] << 8;
-               temp_data16 = temp_data16 | buff[operand+1];
+               temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
                *value = temp_data16;
                offset ++;
        }
 
+       if (offset >= UDVM_MEMORY_SIZE || *result_dest >= UDVM_MEMORY_SIZE - 1 )
+               THROW(ReportedBoundsError);
+
        return offset;
 }
 
@@ -2483,7 +2890,7 @@ dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *val
         * 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    
+        * 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
@@ -2493,7 +2900,7 @@ dissect_udvm_reference_operand(guint8 buff[],guint operand_address, guint16 *val
         * 10000001 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535                        0x81
         */
 static int
-decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *value)
+decode_udvm_multitype_operand(guint8 *buff,guint operand_address, guint16 *value)
 {
        guint test_bits;
        guint bytecode;
@@ -2504,11 +2911,13 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
        guint16 temp_data16;
        guint16 memmory_addr = 0;
 
+*value = 0;
+
        bytecode = buff[operand_address];
        test_bits = ( bytecode & 0xc0 ) >> 6;
        switch (test_bits ){
        case 0:
-               /*  
+               /*
                 * 00nnnnnn                        N                   0 - 63
                 */
                operand =  buff[operand_address];
@@ -2519,12 +2928,12 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                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];
+               temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
                *value = temp_data16;
                offset ++;
                break;
@@ -2537,7 +2946,7 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                 */
                        temp_data = buff[operand_address] & 0x1f;
                        operand = temp_data << 8;
-                       temp_data = buff[operand_address + 1];
+                       temp_data = buff[(operand_address + 1) & 0xffff];
                        operand = operand | temp_data;
                        *value = operand;
                        offset = offset + 2;
@@ -2549,7 +2958,7 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                 */
                                temp_data = buff[operand_address] & 0x0f;
                                operand = temp_data << 8;
-                               temp_data = buff[operand_address + 1];
+                               temp_data = buff[(operand_address + 1) & 0xffff];
                                operand = operand | temp_data;
                                operand = operand + 61440;
                                *value = operand;
@@ -2561,7 +2970,7 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                 * 10001nnn                        2 ^ (N + 8)    256 , ... , 32768
                 */
 
-                                       result = (guint32)pow(2,( buff[operand_address] & 0x07) + 8);
+                                       result = 1 << ((buff[operand_address] & 0x07) + 8);
                                        operand = result & 0xffff;
                                        *value = operand;
                                        offset ++;
@@ -2571,7 +2980,7 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                                                /*
                                                 * 1000 011n                        2 ^ (N + 6)        64 , 128
                                                 */
-                                               result = (guint32)pow(2,( buff[operand_address] & 0x01) + 6);
+                                               result = 1 << ((buff[operand_address] & 0x01) + 6);
                                                operand = result & 0xffff;
                                                *value = operand;
                                                offset ++;
@@ -2581,15 +2990,15 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                                         * 1000 0001 nnnnnnnn nnnnnnnn      memory[N]           0 - 65535
                                         */
                                                offset ++;
-                                               temp_data16 = buff[operand_address + 1] << 8;
-                                               temp_data16 = temp_data16 | buff[operand_address + 2];
+                                               temp_data16 = buff[(operand_address + 1) & 0xffff] << 8;
+                                               temp_data16 = temp_data16 | buff[(operand_address + 2) & 0xffff];
                                                /*  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];
+                                                       temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
                                                }
                                                *value = temp_data16;
                                                offset = offset +2;
@@ -2616,16 +3025,16 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
                 */
                        memmory_addr = buff[operand_address] & 0x1f;
                        memmory_addr = memmory_addr << 8;
-                       memmory_addr = memmory_addr | buff[operand_address + 1];
+                       memmory_addr = memmory_addr | buff[(operand_address + 1) & 0xffff];
                        temp_data16 = buff[memmory_addr] << 8;
-                       temp_data16 = temp_data16 | buff[memmory_addr+1];
+                       temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
                        *value = temp_data16;
-                       /*  debug 
+                       /*  debug
                         * g_warning("Reading 0x%x From address %u",temp_data16,memmory_addr);
                         */
                        offset = offset +2;
                }
-                       
+
        default :
                break;
        }
@@ -2648,7 +3057,7 @@ decode_udvm_multitype_operand(guint8 buff[],guint operand_address, guint16 *valu
         * placed in the UDVM memory).
         */
 static int
-decode_udvm_address_operand(guint8 buff[],guint operand_address, guint16 *value,guint current_address)
+decode_udvm_address_operand(guint8 *buff,guint operand_address, guint16 *value,guint current_address)
 {
        guint32 result;
        guint16 value1;
@@ -2661,302 +3070,144 @@ decode_udvm_address_operand(guint8 buff[],guint operand_address, guint16 *value,
        return next_opreand_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){
-
-guint16 input_bit_order;
-guint16 value;
-guint16 mask;
-guint8 octet;
-guint8 n;
-guint8 i;
-
-
 
-               input_bit_order = buff[68] << 8;
-               input_bit_order = input_bit_order | buff[69];
-               *result_code = 0;
+/*
+ * 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
+};
 
-               /*
-                * Note that after one or more INPUT instructions the dispatcher may
-                * hold a fraction of a byte (what used to be the LSBs if P = 0, or, the
-                * MSBs, if P = 1).  If an INPUT instruction is encountered and the P-
-                * bit has changed since the last INPUT instruction, any fraction of a
-                * byte still held by the dispatcher MUST be discarded (even if the
-                * INPUT instruction requests zero bits).  The first bit passed to the
-                * INPUT instruction is taken from the subsequent byte.
-                */
-               if (print_level_1 ){
-                       if ( *input_address > ( msg_end - 1)){
-                               proto_tree_add_text(udvm_tree, message_tvb, (msg_end - 1), 1,
-                                       "               input_bit_order = 0x%x, old_input_bit_order = 0x%x MSG BUFFER END", input_bit_order, *old_input_bit_order);
-                       }else{
-                               proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               input_bit_order = 0x%x, old_input_bit_order = 0x%x", input_bit_order,*old_input_bit_order);
-                       }
-               }
 
-               if ( (*old_input_bit_order & 0x0001 ) != ( input_bit_order & 0x0001 )){
-                       /* clear out remaining bits TODO check this further */
-                       *remaining_bits = 0;
-                       *old_input_bit_order = input_bit_order;
-               }
+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;
 
-               /*
-                * Do we hold a fraction of a byte ?
-                */
-               if ( *remaining_bits != 0 ){
-                       if ( *remaining_bits < length ){
-                               if (*remaining_bits > 8 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               Yikes!! haven't coded this case yet!!remaining_bits %u > 8 ", *remaining_bits);
-                                       return 0xfbad;
-                               }
-                               if ( *input_address > ( msg_end -1 ) ){
-                                       *result_code = 11;
-                                       return 0xfbad;
-                               }
 
-                               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;
+       input_bit_order = buff[68] << 8;
+       input_bit_order = input_bit_order | buff[69];
+       *result_code = 0;
+       p_bit = (input_bit_order & 0x0001) != 0;
 
-                               if ( ( bit_order ) == 0 ){
-                                       /* 
-                                        * F/H bit = 0
-                                        */
-                                       /* borrow value */
-                                       value = octet & 0x00ff;
-                                       value = value << ( 8 - (*remaining_bits));
-                                       *remaining_bits = *remaining_bits + 8;
-                               }else{
-                                       /*
-                                        * F/H bit = 1
-                                        */
-                                       /* borrow value */
-                                       value =  ( octet << 7) & 0x80;
-                                       value = value | (( octet << 5) & 0x40 ); 
-                                       value = value | (( octet << 3) & 0x20 ); 
-                                       value = value | (( octet << 1) & 0x10 ); 
-
-                                       value = value | (( octet >> 1) & 0x08 ); 
-                                       value = value | (( octet >> 3) & 0x04 ); 
-                                       value = value | (( octet >> 5) & 0x02 ); 
-                                       value = value | (( octet >> 7) & 0x01 );
-
-                                       value = value << ( 8 - (*remaining_bits));
-                                       *remaining_bits = *remaining_bits + 8;
-                               }
+       /*
+        * 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;
+       }
 
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address - 1 , 1,
-                                       "               Or value 0x%x with 0x%x remaining bits %u, Result 0x%x",
-                                       value, *input_bits, *remaining_bits, (*input_bits | value));
-                               }
-                               *input_bits = *input_bits | value;
-                       }/* Bits remain */
-                       if ( ( bit_order ) == 0 ){
-                               /* 
-                                * F/H bit = 0
-                                */
-                               mask = (0xffff >> length)^0xffff;
-                               value = *input_bits & mask;
-                               value = value >> ( 16 - length);
-                               *input_bits = *input_bits << length;
-                               *remaining_bits = *remaining_bits - length;
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               Remaining input_bits 0x%x remaining_bits %u", *input_bits, *remaining_bits);
-                               }
-                               return value;
-                       }
-                       else{
-                               /* 
-                                * F/H bit = 1
-                                */
-                               n = 15;
-                               i = 0;
-                               value = 0;
-                               while ( i < length ){
-                                       value =  value | (( *input_bits & 0x8000 ) >> n) ;
-                                       *input_bits = *input_bits << 1;
-                                       n--;
-                                       i++;
-                               }
-                               *remaining_bits = *remaining_bits - length;
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               Remaining input_bits 0x%x", *input_bits);
-                               }
-                               return value;
-                       }
+       /*
+        * 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;
+       }
 
-               }
-               else
+       /* 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)
                {
-                       /*
-                        * Do we need one or two bytes ?
-                        */
-                       if ( *input_address > ( msg_end -1 ) ){
-                               *result_code = 11;
-                               return 0xfbad;
+                       octet = tvb_get_guint8(message_tvb, *input_address);
+                       if (print_level_1 ){
+                               proto_tree_add_text(udvm_tree, message_tvb, *input_address , 1,
+                                               "               Getting value: %u (0x%x) From Addr: %u", octet, octet, *input_address);
                        }
+                       *input_address = *input_address + 1;
 
-                       if ( length < 9 ){
-                               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 (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address , 1,
-                                       "               Next input from Addr: %u", *input_address);
-                               }
-
-                               if ( ( input_bit_order & 0x0001 ) == 0 ){
-                                       /*
-                                        * P bit = Zero
-                                        */
-                                       *input_bits = octet & 0xff;
-                                       *input_bits = *input_bits << 8;
-                                       *remaining_bits = 8;
-                               }else{
-                                       /*
-                                        * P bit = One
-                                        */
-                                       *input_bits =  ( octet << 7) & 0x80;
-                                       *input_bits = *input_bits | (( octet << 5) & 0x40 ); 
-                                       *input_bits = *input_bits | (( octet << 3) & 0x20 ); 
-                                       *input_bits = *input_bits | (( octet << 1) & 0x10 ); 
-
-                                       *input_bits = *input_bits | (( octet >> 1) & 0x08 ); 
-                                       *input_bits = *input_bits | (( octet >> 3) & 0x04 ); 
-                                       *input_bits = *input_bits | (( octet >> 5) & 0x02 ); 
-                                       *input_bits = *input_bits | (( octet >> 7) & 0x01 ); 
-
-                                       *input_bits = *input_bits << 8;
-                                       *remaining_bits = 8;
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address -1, 1,
-                                       "               P bit = 1, input_bits = 0x%x",*input_bits);
-
-                               }
-
+                       if (p_bit != 0)
+                       {
+                               octet = reverse[octet];
                        }
-                       else{
-                               /* Length > 9, we need two bytes */
-                               octet = tvb_get_guint8(message_tvb, *input_address);
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "              Geting first value: %u (0x%x) From Addr: %u", octet, octet, *input_address);
-                               }
-                               if ( ( input_bit_order & 0x0001 ) == 0 ){
-                                       *input_bits = octet & 0xff;
-                                       *input_bits = *input_bits << 8;
-                                       *input_address = *input_address + 1;
-                               }else{
-                                       /*
-                                        * P bit = One
-                                        */
-                                       *input_bits =  ( octet << 7) & 0x80;
-                                       *input_bits = *input_bits | (( octet << 5) & 0x40 ); 
-                                       *input_bits = *input_bits | (( octet << 3) & 0x20 ); 
-                                       *input_bits = *input_bits | (( octet << 1) & 0x10 ); 
+                       *input_bits = octet;
+                       *remaining_bits = 8;
+               }
 
-                                       *input_bits = *input_bits | (( octet >> 1) & 0x08 ); 
-                                       *input_bits = *input_bits | (( octet >> 3) & 0x04 ); 
-                                       *input_bits = *input_bits | (( octet >> 5) & 0x02 ); 
-                                       *input_bits = *input_bits | (( octet >> 7) & 0x01 ); 
+               /* 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 = *input_bits << 8;
-                                       *input_address = *input_address + 1;
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address -1, 1,
-                                       "               P bit = 1, input_bits = 0x%x",*input_bits);
+               *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];
 
-                               if ( *input_address > ( msg_end - 1)){
-                                       *result_code = 11;
-                                       return 0xfbad;
-                               }
+               value = ((msb << 8) | lsb) >> (16 - length);
+       }
 
-                               octet = tvb_get_guint8(message_tvb, *input_address);
-                               *input_address = *input_address + 1;
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address - 2, 2,
-                                       "               Geting second value: %u (0x%x) From Addr: %u", octet, octet, *input_address);
-                               }
-                               if ( ( input_bit_order & 0x0001 ) == 0 ){
-                               /*
-                                * P bit = zero
-                                */
-                               *input_bits = *input_bits | octet;
-                               *remaining_bits = 16;
-                               }else{
-                                       /*
-                                        * P bit = One
-                                        */
-                                       *input_bits =  ( octet << 7) & 0x80;
-                                       *input_bits = *input_bits | (( octet << 5) & 0x40 ); 
-                                       *input_bits = *input_bits | (( octet << 3) & 0x20 ); 
-                                       *input_bits = *input_bits | (( octet << 1) & 0x10 ); 
-
-                                       *input_bits = *input_bits | (( octet >> 1) & 0x08 ); 
-                                       *input_bits = *input_bits | (( octet >> 3) & 0x04 ); 
-                                       *input_bits = *input_bits | (( octet >> 5) & 0x02 ); 
-                                       *input_bits = *input_bits | (( octet >> 7) & 0x01 ); 
-
-                                       *input_bits = *input_bits << 8;
-                                       *input_address = *input_address + 1;
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address -1, 1,
-                                       "               P bit = 1, input_bits = 0x%x",*input_bits);
-
-                               *remaining_bits = 16;
-                               }
+       return value;
+}
 
-                       }
-                       if ( ( bit_order ) == 0 ){
-                               /* 
-                                * F/H bit = 0
-                                */
-                               mask = (0xffff >> length)^0xffff;
-                               value = *input_bits & mask;
-                               value = value >> ( 16 - length);
-                               *input_bits = *input_bits << length;
-                               *remaining_bits = *remaining_bits - length;
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               Remaining input_bits 0x%x", *input_bits);
-                               }
-                               return value;
-                       }
-                       else{
-                               /* 
-                                * F/H bit = 1
-                                */
-                               n = 15;
-                               i = 0;
-                               value = 0;
-                               while ( i < length ){
-                                       value =  value | ( *input_bits & 0x8000 ) >> n ;
-                                       *input_bits = *input_bits << 1;
-                                       n--;
-                                       i++;
-                               }
-                               *remaining_bits = *remaining_bits - length;
-                               if (print_level_1 ){
-                                       proto_tree_add_text(udvm_tree, message_tvb, *input_address, 1,
-                                       "               Remaining input_bits 0x%x", *input_bits);
-                               }
-                               return value;
-                       }
 
-               }
-}
 /* end udvm */
+